This document is based on stock PX4 Autopilot v1.11.2
ECL EKF Initialisation
Software Architecture Overview#
Multi-EKF and Sensor Voting#
The EKF logic is wrapped around by class EKF2, which is implemented as a ScheduledWorkItem. It is initialised by the static method task_spawn.
The reason for this wrapper architecture is that, the EKF2 class can turn on a mode called multi mode, which enables multi-EKF support. This essentially runs one EKF instance per physical IMU detected on the hardware platform. With the multi mode enabled, the ekf selector is also run to perform the selection logic.

note
ScheduledWorkItem inherits WorkItem which contains private object WorkQueue. Given the wq_config_t struct in the constructor of WorkItem, it will find or create the relevant Work Queue by WorkQueueFindOrCreate(config), then attach the current work item class object this to the target work queue by Attach(this).
Here each work queue is identified by name, in struct wq_config_t.name. For more info refer to here.
Mode Selection#
The multi-EKF mode is enabled when SENS_IMU_MODE is set to 0 (disabled), reference. Setting the value to 0 disable Sensors hub IMU, hence to expose all IMU data out. Otherwise, setting SENS_IMU_MODE to 1, enables sensor voting, in which disable multi-EKF support.
The sensor voting result is published as the uORB sensor_combined message (VotedSensorsUpdate::sensorsPoll). It is received by _sensor_combined_sub in EKF2 class (non multi-EKF mode).
tip
Currently, we are using the default value of SENS_IMU_MODE which is 1. We are not using multi-EKF mode now.
Bootstraping Process (Non Multi-EKF)#
ekf2_mainC method, which handleshelp,start,stopparameters.EKF2::task_spawn(), checkingSENS_IMU_MODE. If it is 1 (default), enter normal non multi-EKF mode. A newEKF2instance is allocated.- Inside the spawning, it schedule the
EKF2::Run()as well
- Inside the spawning, it schedule the
EKF2has a member variable of classEkf, which is the actuall ECL library (external to PX4 firmware itself)EKF2::Run()- On the first run, it will register itself to the callback of sensor_combined message:
_sensor_combined_sub.registerCallback(). Hence theRun()function will be called everytime a new combined IMU message is available.
- On the first run, it will register itself to the callback of sensor_combined message:
IMU Update Routine#
As we have discussed the EKF2::Run() function is called whenever a new IMU data is available (callback). For each run:
- update status like
_armed,_standby - maintain
_preflt_checker, which is updated during stand by mode_preflt_checkeris responsible for thexy_valid,z_valid,v_xy_valid,v_z_validentries invehicle_local_positionuORB message.
void PreFlightChecker::update(const float dt, const estimator_innovations_s &innov){ const float alpha = InnovationLpf::computeAlphaFromDtAndTauInv(dt, _innov_lpf_tau_inv);
_has_heading_failed = preFlightCheckHeadingFailed(innov, alpha); _has_horiz_vel_failed = preFlightCheckHorizVelFailed(innov, alpha); _has_vert_vel_failed = preFlightCheckVertVelFailed(innov, alpha); _has_height_failed = preFlightCheckHeightFailed(innov, alpha);}- call
_ekf.setIMUData(imu_sample_new)and then_ekf.update() - Among other things, update sensors sample too
UpdateAirspeedSample(ekf2_timestamps); UpdateAuxVelSample(ekf2_timestamps); UpdateBaroSample(ekf2_timestamps); UpdateGpsSample(ekf2_timestamps); UpdateMagSample(ekf2_timestamps); UpdateRangeSample(ekf2_timestamps);
vehicle_odometry_s ev_odom; const bool new_ev_odom = UpdateExtVisionSample(ekf2_timestamps, ev_odom);
optical_flow_s optical_flow; const bool new_optical_flow = UpdateFlowSample(ekf2_timestamps, optical_flow);Yaw Alignment#
Inside bool Ekf::initialiseFilter(), yaw alignment is attempted:
// calculate the initial magnetic field and yaw alignment _control_status.flags.yaw_align = resetMagHeading(_mag_lpf.getState(), false, false);If the type is MAG_FUSE_TYPE_NONE, then the yawalign will return false. If the type is MAG_FUSE_TYPE_INDOOR (`is_yaw_fusion_inhibited would be false at initialisation)