Issue with VIO Fusion in EKF2 After Landing (PX4 v1.16, ROS2 px4-ros2-interface)

Hi all,

We’re running an indoor drone using VIO, feeding it into the EKF over ROS2 via the px4-ros2-interface (PX4 v1.16).

We’re seeing an interesting behavior:

  • During an autonomous mission (using ModeExecutors), the drone flies fine with VIO fused.
  • After landing and disarming, the mag calibration triggers, which causes VIO position fusion to stop.
  • On the next attempted takeoff, the EKF will not start fusing VIO again, even though VIO measurements are still available.

Here’s the relevant EKF2 control state progression we observe:

  1. Power up
  2. cs_tilt_align = true
  3. cs_yaw_align = true
  4. cs_ev_yaw = true → this becomes true once VIO measurements are received and stays true throughout the flight
  5. cs_in_air = true (during mission)
  6. Land → cs_in_air = false
			if (!_control_status.flags.in_air) {
				// Assume that a reset on the ground is caused by a change in mag calibration
				// Clear alignment to force a clean reset
				_control_status.flags.yaw_align = false;
			}
  1. After landing:
  • cs_yaw_align = false
  • cs_mag = false
  • cs_ev_yaw remains true

From what I can tell, the problem lies in this section of EKF2:

// determine if we should use mag fusion

bool continuing_conditions_passing =
    ((_params.mag_fusion_type == MagFuseType::INIT)
  || (_params.mag_fusion_type == MagFuseType::AUTO)
  || (_params.mag_fusion_type == MagFuseType::HEADING))
  && _control_status.flags.tilt_align
  && (_control_status.flags.yaw_align || (!_control_status.flags.ev_yaw && !_control_status.flags.yaw_align))
  && mag_sample.mag.longerThan(0.f)
  && mag_sample.mag.isAllFinite();

Specifically, this part seems problematic:

|| (!_control_status.flags.ev_yaw && !_control_status.flags.yaw_align)

After landing, we end up with:

  • _control_status.flags.ev_yaw = true
  • _control_status.flags.yaw_align = false

…which means the condition fails, preventing mag fusion from continuing.

Could someone provide some background on the logic behind this conditional? Or explain the intended reasoning here?

also to note, this does not occur in simulation

Thanks in advance!