Engineering Guides · Module 11
Configuring robot_localization
A minimal, correct starting configuration and the reasoning for each choice. Parameter names are checked against the package’s own example file.
Assumptions: ROS 2 Jazzy with the robot_localization package; planar robot (two_d_mode); wheel odometry and IMU as inputs. The YAML block is parsed by the site’s tests and every parameter name is checked against the names confirmed from the package’s ekf.yaml (ros2 branch, fetched 2026-11-04). The configuration has not been run on a robot by the site’s tests.
1. Engineering problem
Wheel odometry is smooth but drifts, the IMU gives a good yaw rate but no position. An EKF combines them into one continuous pose. Whether it works depends on which variables each sensor is allowed to influence and on the covariances those sensors report.
2. When is this needed?
- Producing a continuous
odom → base_linktransform for a wheeled robot. - Adding GNSS or visual/LiDAR odometry later (a second filter or more inputs).
- Replacing an ad-hoc complementary filter with a tunable estimator.
3. Selection and design decisions
Which variables should each sensor contribute?
Each *_config parameter is 15 booleans in this order (as documented for the package): x, y, z, roll, pitch, yaw, vx, vy, vz, vroll, vpitch, vyaw, ax, ay, az.
| Sensor | Good to fuse | Usually avoid | Why |
|---|---|---|---|
| Wheel odometry | vx, vyaw | Absolute x, y, yaw | Pose integrates slip and drifts; velocity is a direct measurement |
| IMU | vyaw (yaw rate) | Absolute yaw unless it comes from a calibrated magnetometer-aided unit; linear acceleration unless you need it | Gyro rate is reliable; absolute heading and double-integrated acceleration are not |
| GNSS (via a second filter) | x, y | Heading, velocity | Position bound, outputs low-rate and noisy |
| Visual/LiDAR odometry | vx, vy, vyaw or pose differences | Absolute pose if it resets | Check each system’s covariance and frame |
Per-sensor options (names confirmed from ekf.yaml)
*_differential: fuse the change between successive measurements instead of the absolute value (for sources with a drifting or arbitrary reference).*_relative: treat the first measurement as the origin.*_queue_size: how many messages to buffer; too small drops data from fast sensors.*_rejection_thresholdvariants (_pose_,_twist_,_linear_acceleration_): Mahalanobis-distance gates that reject outlying measurements.sensor_timeout: after this long without data the filter runs prediction only.
4. Advantages and disadvantages
- Fewer fused variables: more robust to a bad sensor, less information. Start minimal, add one variable at a time and test.
- EKF vs UKF (the package provides both): the EKF is simpler and faster; the UKF handles strong nonlinearity better at higher cost. For wheeled robots at ordinary speeds the EKF is the usual start.
- Higher filter frequency: smoother output, more CPU; set it at or above the fastest important sensor.
5. Requirements and constraints
- The measurement covariance comes from the message (odometry pose/twist covariance, IMU covariance). A driver that publishes zeros tells the filter the data is perfect: fix the driver or override the covariances.
- Frames:
world_frameisodomfor the local filter;base_link_framemust match your URDF; sensor frames must exist in TF. - All timestamps must be consistent with the ROS clock; see the timing guides.
6. Architecture
/wheel/odometry ──┐
├──▶ ekf_filter_node ──▶ /odometry/filtered
/imu/data ────────┘ │
└──▶ TF: odom → base_link7. Implementation
Starting configuration (parsed and name-checked by the site’s tests):
ekf_filter_node:
ros__parameters:
frequency: 30.0
sensor_timeout: 0.1
two_d_mode: true
publish_tf: true
map_frame: map
odom_frame: odom
base_link_frame: base_link
world_frame: odom
# wheel odometry: fuse forward speed (vx) and yaw rate (vyaw) only
odom0: /wheel/odometry
odom0_config: [false, false, false,
false, false, false,
true, false, false,
false, false, true,
false, false, false]
odom0_queue_size: 10
odom0_differential: false
odom0_relative: false
# IMU: fuse yaw rate only
imu0: /imu/data
imu0_config: [false, false, false,
false, false, false,
false, false, false,
false, false, true,
false, false, false]
imu0_queue_size: 10
imu0_differential: false
imu0_relative: falsetwo_d_mode: trueconstrains the filter to the plane: z, roll, pitch and their rates are ignored.- The two
*_configarrays select vx and vyaw from the wheels and vyaw from the IMU. - No
process_noise_covarianceis set: the package supplies a default. Override the 15×15 diagonal once you have data that shows lag (too small) or noise (too large); use the EKF Tuning Playground to see the effect.
Run and inspect
Not executed by the site’s automated tests (they need a ROS 2 installation).
ros2 run robot_localization ekf_node --ros-args --params-file ekf.yaml -r __node:=ekf_filter_node
ros2 topic echo /odometry/filtered --once # pose, twist and covariance
ros2 topic hz /odometry/filtered # should match "frequency"
ros2 run tf2_ros tf2_echo odom base_link # the transform the filter publishesThe node name must match the top-level key in the YAML (ekf_filter_node) for the parameters to apply.
8. Real examples
- Robot drifts in yaw while stationary: the IMU bias; check
imu0_configuses the rate, not absolute yaw, and that the IMU covariance is realistic. - Pose jumps when the wheels slip: add an
odom0_twist_rejection_thresholdgate and consider fusing only vx. - Output lags real motion: process noise too small for the dynamics, or too small a queue dropping measurements.
9. Failure scenarios
- Fusing absolute yaw from an uncalibrated magnetometer.
- Two nodes publishing
odom → base_link(the EKF and the wheel driver): turn one off (publish_tf). - Zero covariance in sensor messages: the filter ignores everything else.
- Using
*_differentialon sources that are already relative: values cancel. - Forgetting that the config array order is x, y, z, roll, pitch, yaw, then velocities, then accelerations.
10. Troubleshooting
ros2 topic hzon each input and on/odometry/filtered.- Compare covariance in the input messages against reality (zeros are wrong).
- Fuse one sensor at a time: wheels only, then add the IMU. Check each output for sanity against a hand-driven path.
- Set
print_diagnostics: trueand read/diagnosticsfor dropped or rejected measurements. - Adjust the rejection thresholds and process noise based on the recorded data, not guesses.
11. Validation
- Drive a closed square or circle: the pose ends within your tolerance of the start (and compare with wheel-only).
- Spin in place: yaw returns to the start within the IMU’s expected drift.
- Stationary for 10 minutes: no pose drift beyond the specified limit.
- No two publishers on
odom → base_link(ros2 run tf2_tools view_frames). - The YAML parses and every parameter name is one confirmed from
ekf.yaml(checked by the site’s tests).
12. Engineering checklist
13. Further references
- robot_localization example configuration (ros2 branch), parameter names confirmed on 2026-11-04: params/ekf.yaml.
- The 15-element configuration order and the behaviour of each option are documented in the robot_localization package documentation; that documentation could not be fetched in the build environment, so check it against your installed version.
Related on FixTheRobot
- EKF-SLAM SLAM · Lesson
- Simple Filtering and Kalman Filter Intuition Perception · Lesson