Welcome to ROSMASTER M1 PRO repository
7.Robot EKF State Estimation
Robot EKF State Estimation
Robot EKF State Estimation1. Course Content2. Preparation3. Case Demonstration3. Viewing the Node Graph4. Source Code Analysis
1. Course Content
Perform multi-sensor data fusion using IMU and wheel encoder data to obtain fused odometry data odom and estimate the robot's movement position
Observe in rviz the trajectory difference between the wheel odometry (blue arrow) and the odometry obtained after fusing IMU data (red arrow)
2. Preparation
Start the state estimation node
xxxxxxxxxxros2 launch yahboomcar_bringup state_estimation.launch.py

Start the keyboard or handle control node; here, keyboard control is used as an example
xxxxxxxxxxros2 run common_demo keyboard_control
3. Case Demonstration
By controlling the car's movement with the keyboard, you can observe that the odometry trajectories of odom (red arrow) and odom_raw (blue arrow) gradually diverge; EKF combines the wheel odometry and IMU data to obtain more stable odometry data

Important
In subsequent SLAM mapping and navigation-related functions, the odometry data used all comes from the EKF fused odometry as the data source
3. Viewing the Node Graph
xxxxxxxxxxrqt_graph
If no node graph is displayed, click Refresh in the upper-left corner
As can be seen, /odom_raw is the wheel odometry data calculated from the chassis motor encoder pulses, /imu/data_raw is the IMU data, and the ekf_filter_node node subscribes to them and publishes the fused odometry /odom

4. Source Code Analysis
state_estimation launch file
xxxxxxxxxx~/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_bringup/launch/state_estimation.launch.py
state_estimation.launch.py adds rviz visualization on top of car_base.launch.py, used to compare the trajectory difference between the raw wheel odometry and the fused odometry:
IncludeLaunchDescription: reusescar_base.launch.py, passing inuse_camera:=falseto turn off the camera to save resources, andlog_level:=infoto enable detailed logging.rviz2: loads thestate_estimation.rvizconfiguration file, simultaneously displaying the two odometry trajectoriesodom(red) andodom_raw(blue), making it easy to visually compare the EKF fusion effect.
xxxxxxxxxxdef generate_launch_description(): rviz_config = os.path.join(get_package_share_directory('yahboomcar_bringup'),'rviz','state_estimation.rviz') carbase=IncludeLaunchDescription( PythonLaunchDescriptionSource(os.path.join(get_package_share_directory('yahboomcar_bringup'),'launch','car_base.launch.py')), launch_arguments={'log_level': 'info', 'use_camera': 'false', 'use_lidar': 'false', 'odom_tf_source':'ekf' }.items())
rviz_node = Node( package = 'rviz2', executable = 'rviz2', name='rviz2', arguments=['-d', rviz_config, '--ros-args', '--log-level', 'info'], output='screen' )
return LaunchDescription([ carbase, rviz_node])
ekf parameter file
xxxxxxxxxx~/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_bringup/param/ekf_M1.yaml
ekf.yaml is the core configuration of the EKF fusion node; the key parameters are described as follows:
Global parameters:
frequency: 15.0means the EKF runs at a frequency of 15Hz;two_d_mode: truerestricts it to planar motion (ignoring z/roll/pitch);publish_tf: trueautomatically publishes theodom → base_footprinttransform.odom0: /odom_raw: wheel odometry input. The 15-bit boolean arrayodom0_configcorresponds to whether each of[x,y,z, roll,pitch,yaw, vx,vy,vz, vroll,vpitch,vyaw, ax,ay,az]participates in the fusion. Here onlyvx(forward velocity) andyaw(yaw angular velocity) are enabled, because a differential chassis can only reliably observe these two quantities.imu0: /imu: IMU input.imu0_configenables onlyyaw(yaw angle), using the IMU's magnetometer/gyroscope to correct the wheel odometry's heading drift;imu0_relative: truemeans using the first IMU data as the reference baseline, avoiding jumps caused by inconsistency between the absolute heading and the odometry's initial orientation.Fusion strategy: the odometry provides translational velocity, and the IMU provides heading angle; the two are complementary — the odometry is accurate in the short term but its heading accumulates drift, while the IMU's heading is stable but has short-term noise. The EKF combines the advantages of both to obtain a more stable
/odom.
xekf_filter_node ros__parameters use_sim_timefalse frequency15.0 sensor_timeout0.15 two_d_modetrue transform_time_offset0.0 transform_timeout0.05 print_diagnosticsfalse debugfalse publish_tftrue publish_accelerationfalse reset_on_time_jumptrue odom_frameodom # Defaults to "odom" if unspecified base_link_framebase_footprint # Defaults to "base_link" if unspecified world_frameodom # Defaults to the value of odom_frame if unspecified
odom0/odom_raw odom0_configfalse false false false false false true true false false false true false false false
# [x_pos , y_pos , z_pos, # roll , pitch , yaw, # x_vel , y_vel , z_vel, # roll_vel, pitch_vel, yaw_vel, # x_accel , y_accel , z_accel]
odom0_queue_size3 odom0_nodelaytrue odom0_differentialfalse odom0_relativefalse odom0_pose_rejection_threshold20.0 odom0_twist_rejection_threshold5.0
imu0/imu/data_raw imu0_configfalse false false false false true false false false false false false false false false
# [x_pos , y_pos , z_pos, # roll , pitch , yaw, # x_vel , y_vel , z_vel, # roll_vel, pitch_vel, yaw_vel, # x_accel , y_accel , z_accel] imu0_nodelaytrue imu0_differentialfalse imu0_relativetrue imu0_queue_size5 imu0_pose_rejection_threshold5.0 # Note the difference in parameter names # 0.8 imu0_twist_rejection_threshold5.0 # 0.8 imu0_linear_acceleration_rejection_threshold10.0 # imu0_remove_gravitational_accelerationtrue