longer95479@home:~$

[Paper Reading] A Tutorial on Quantitative Trajectory Evaluation for Visual(-Inertial) Odometry


Quantitatively comparing the estimated trajectory with the groundtruth, however, is not an easy task. There are two major difficulties.

  • First, the estimated trajectory and the groundtruth are usually expressed in different reference frames, and, therefore, cannot be compared directly.

  • Second, a trajectory consists of the states at many different times and, therefore, is high-dimensional data.

Thus, how to summarize the information of the whole trajectory into concise accuracy metrics is not trivial.

  • To address the first problem, the estimated trajectory requires to be properly transformed into the same reference frame as the groundtruth, which is often called trajectory alignment.

  • To address the second problem, meaningful error metrics need to be used and their properties well understood.

Roughly speaking, we integrate the raw IMU measurements to get the relative rotation ∆ R̃ ik , velocity ∆ṽ ik and position ∆p̃ ik between two states x i and x k , and the integration is formulated to be independent of the states (except for the biases) so that re-integration is not needed when the states change (e.g., during optimization iterations). The corresponding measurement model is

(6) has infinite solutions that have the same minimum cost. The reason is that the predicted measurements f (X) are invariant to certain transformations g(·) of the parameter, namely $f (X) = f (X’ )$ with $X’ = g(X)$. Since the measure- ments z̃ are constant, the cost function (7) is also invariant to



Quaternion Conventions


Quaternion type Hamilton $JPL$
1 Components s order $( q_w$ , $\mathbf{q} _v)$ $\left(\mathbf{q}_v\:,\:\right.$ $q_w)$
2 $\operatorname{Algebra}$ Handedness $ij=k$ Right- handed $ij=$ $=-k$ Left- handed
3 Function Passive $\mathrm{P}_{\xi}$ assive
Right- to- left products mean Local- to- Global Global-to-Local
4 Default operation $\mathbf{X}_{G}$ $\mathbf{X}_{\mathcal{L}}$ 水 = $\mathbf{q}$ $\mathbf{q}$ $\mathbf{X}_{C}$ 三 T $\mathbf{X}_{G}$


px4ctrl understanding and tunning


状态机

Px4ctrl的状态机对象如下:

class PX4CtrlFSM
{
public:

    // somedata

private:
	State_t state; // Should only be changed in PX4CtrlFSM::process() function!
	AutoTakeoffLand_t takeoff_land;

	// ---- control related ----
	Desired_State_t get_hover_des();
	Desired_State_t get_cmd_des();

	// ---- auto takeoff/land ----
	void motors_idling(const Imu_Data_t &imu, Controller_Output_t &u);
	void land_detector(const State_t state, const Desired_State_t &des, const Odom_Data_t &odom); // Detect landing 
	void set_start_pose_for_takeoff_land(const Odom_Data_t &odom);
	Desired_State_t get_rotor_speed_up_des(const ros::Time now);
	Desired_State_t get_takeoff_land_des(const double speed);

	// ---- tools ----
	void set_hov_with_odom();
	void set_hov_with_rc();

	bool toggle_offboard_mode(bool on_off); // It will only try to toggle once, so not blocked.
	bool toggle_arm_disarm(bool arm); // It will only try to toggle once, so not blocked.
	void reboot_FCU();

	void publish_bodyrate_ctrl(const Controller_Output_t &u, const ros::Time &stamp);
	void publish_attitude_ctrl(const Controller_Output_t &u, const ros::Time &stamp);
	void publish_trigger(const nav_msgs::Odometry &odom_msg);
};

Input.cpp 里的 rc_data 的回调函数 feed()包含了通道的含义,涉及各通道切换的功能:

  • enter_hover_mode, is_hover_mode
  • enter_command_mode, is_command_mode

类成员函数 feed() 是如何被绑定为 ros subscriber 的回调函数的?使用 std::bind,例子如下,bind有三个参数,第一个参数指明哪一个类成员函数,第二个参数指明类的实例,第三个参数指明将接收到的 mavros_msgs::State 消息传递给 feed 函数的第一个参数。

ros::Subscriber state_sub =
        nh.subscribe<mavros_msgs::State>("/mavros/state",
                                         10,
                                         boost::bind(&State_Data_t::feed, &fsm.state_data, _1));

起飞流程

接下来梳理一下自动起飞的状态切换流程。首先要保证遥控器 5、6 通道已拨,分别表示进入 offboard 模式(也称 hover mode)和 command 模式,只有 两个条件 均满足,且 起飞使能(在yaml文件里配置)起飞信号触发 才会从 MANUAL_CTRL 切换到 AUTO_TAKEOFF 状态,当然中间还有很多检查。在进入 AUTO_TAKEOFF 前会重置 thr2acc_ 和设置起飞的起始点(已当前的里程计的值作为起点,四自由度),然后px4发送消息使其切换为 offboard 模式并自动解锁,记录当前时间戳 takeoff_land.toggle_takeoff_land_time = now_time;

void PX4CtrlFSM::set_start_pose_for_takeoff_land(const Odom_Data_t &odom)
{
	takeoff_land.start_pose.head<3>() = odom_data.p;
	takeoff_land.start_pose(3) = get_yaw_from_quaternion(odom_data.q);

	takeoff_land.toggle_takeoff_land_time = ros::Time::now();
}
struct AutoTakeoffLand_t
{
	bool landed{true};
	ros::Time toggle_takeoff_land_time;
	std::pair<bool, ros::Time> delay_trigger{std::pair<bool, ros::Time>(false, ros::Time(0))};
	Eigen::Vector4d start_pose;
	
	static constexpr double MOTORS_SPEEDUP_TIME = 3.0; // motors idle running for 3 seconds before takeoff
	static constexpr double TAKEOFF_SPEEDUP_TIME = 0.5; // Time to speed up during takeoff font stage
	static constexpr double DELAY_TRIGGER_TIME = 2.0;  // Time to be delayed when reach at target height
};

进入 AUTO_TAKEOFF 模式后,电机需要先怠速旋转一段时间,其速度指数增长,但提供很小的推力,用于警告周围的人。怠速旋转时长到了之后,则执行起飞,具体的控制可看下文的控制器章节,简单来说即目标位置是斜坡函数,目标速度是阶跃函数,也就是期望飞行器匀速上升。当到达指定高度后,状态将会在下一时间片切到 AUTO_HOVER,在切换之前执行 set_hov_with_odom(),将当前的里程计赋值给 hov_pose(4DoF)。

进入 AUTO_HOVER 后:

  • 如果没有里程计 或者 不是 hover mode,切回 MANUAL_CTRL
  • 如果是 command mode 且 收到了 cmd 且 没进入 emergency hover,则进一步判断是否是 offboard 模式,是的话则切换到 CMD_CTRL
  • 如果收到降落信号 或 emergency_hover,则进入 AUTO_LAND 状态
  • 最后才是 执行悬停控制
      set_hov_with_rc();
      des = get_hover_des();
      if ((rc_data.enter_command_mode) ||
          (takeoff_land.delay_trigger.first && now_time > takeoff_land.delay_trigger.second))
      {
          takeoff_land.delay_trigger.first = false;
          publish_trigger(odom_data.msg);
          ROS_INFO("\033[32m[px4ctrl] TRIGGER sent, allow user command.\033[32m");
      }
    

控制器

其位置速度P控制器是并联的,其实和串联的等价。(闭环传函推导、参数选择详见 onenote)

但如果速度环增加 I D,则串联和并联不再等价,目前的速度环增加了 I D,因此将控制器结构改成了串联形式。

改进 1:增加起飞的加速度前馈

起飞阶段的前期设置期望加速度,因为速度不可能突变,因此非零的期望加速度相当于前馈,符合系统的变化,提高相应速度。 \(a_{des} = 0.02||g||\sin(\frac{\pi}{t_{speedup}}\Delta t)\)

Desired_State_t PX4CtrlFSM::get_takeoff_land_des(const double speed)
{
	ros::Time now = ros::Time::now();
	double delta_t = (now - takeoff_land.toggle_takeoff_land_time).toSec() - (speed > 0 ? AutoTakeoffLand_t::MOTORS_SPEEDUP_TIME : 0); // speed > 0 means takeoff
	// takeoff_land.last_set_cmd_time = now;
	// takeoff_land.start_pose(2) += speed * delta_t;
	Desired_State_t des;
	des.p = takeoff_land.start_pose.head<3>() + Eigen::Vector3d(0, 0, speed * delta_t);
	des.v = Eigen::Vector3d(0, 0, speed);
	if (speed > 0) {
		double des_a_z = (delta_t < AutoTakeoffLand_t::TAKEOFF_SPEEDUP_TIME) ? (0.02 * param_.gra * sin(M_PI/AutoTakeoffLand_t::TAKEOFF_SPEEDUP_TIME * delta_t)) : 0;
		des.a = Eigen::Vector3d(0, 0, des_a_z);
	}
	else {
		des.a = Eigen::Vector3d::Zero();
	}
	des.j = Eigen::Vector3d::Zero();
	des.yaw = takeoff_land.start_pose(3);
	des.yaw_rate = 0.0;
	return des;
}

实验测试结果表明,确实能够提高起飞离开地面的速度,响应更快,xy偏离更少。

改进 2:在起飞阶段也进行油门估计

油门估计的原理是带记忆消逝的迭代最小二乘,利用一系列的油门值和加速度测量值,来估计二者对应直线的斜率(假设二者是线性关系)。

px4ctrl 里的油门估计存在一个假设,即无人机只受重力和油门推力,因此当无人机还受地面支持力时,是不能够使用油门估计的。

当电机怠速转动结束的一段时间后,此时推力大概率已经等于或大于重力,也就是此时不存在地面支撑力了,经验选择为怠速转动结束后的0.2s,运行油门估计函数。

实验表明,在起飞阶段使用油门估计,无论电池电压高低,四旋翼均能稳定地起飞和悬停,并且起飞到悬停的切换也不会带来跟之前一样的震荡。

改进 3:最大化相位裕度原则,简化调参

可将速度环的 P I 两个参数,转换为为阻尼因子 $\delta$ 的选择

\[P = \frac{1}{\tau \delta}\] \[I = \frac{1}{\tau^2\delta^3}\]

如果是离散化,I 还需要乘上控制时间间隔 $\Delta t_{ctrl}$,或者除以控制频率。



Total views. cowboys. Hits