Tune Mobile Base Localization
MoveIt Pro localizes a mobile base in two stages:
- A state estimator, Fuse, combines wheel odometry and IMU data into a smooth odometry estimate.
- beluga_amcl matches lidar scans against a map and publishes the
map→odomcorrection on top of that estimate.
This guide shows how to get that stack working on your robot, how to check that it is working, and what to change when it is not. Mobile Navigation (Nav2) describes how the stack is wired together.
The hangar_sim robot configuration package in the example workspace is a working reference. Its settings are in two files:
params/nav2_params.yaml: theamclblock.config/fuse/fuse.yaml: the Fuse state estimator.
1. Check odometry first
AMCL corrects odometry; it cannot make up for odometry that is wrong. Before tuning AMCL, drive the base a known distance and rotate it a known angle, and compare with the wheel odometry your drive controller publishes. In hangar_sim, that is /platform_velocity_controller_nav2/odom during navigation; /odom there is the simulator's ground truth, so it cannot show a wheel calibration error. If they differ, fix the drive controller's kinematic parameters, such as wheel radius and wheel separation.
2. Set the basic AMCL parameters
Start from the hangar_sim amcl block and change these to match your robot:
| Parameter | What to set |
|---|---|
robot_model_type | nav2_amcl::OmniMotionModel for a holonomic base such as a mecanum drive; nav2_amcl::DifferentialMotionModel for a differential drive. |
scan_topic | The lidar scan topic. |
base_frame_id, odom_frame_id, global_frame_id | Your robot's base, odometry, and map frames. |
max_beams | Close to the number of rays in one scan. beluga picks evenly spaced rays before it discards invalid returns, so a low value can leave very few usable measurements. |
laser_max_range, laser_min_range | Your lidar's usable range. |
laser_model_type | Start with likelihood_field. It is the cheapest model and copes well with many small or moving objects, such as chair legs. Switch to beam, which traces each ray along its whole path, only if likelihood_field cannot hold the estimate and you have CPU to spare. Do not use likelihood_field_prob: the beluga authors recommend it only together with beam skipping, which beluga does not implement. |
Leave the other parameters at the hangar_sim values until you see a problem.
3. Check that localization is working
- In the MoveIt Pro Desktop App, open the View menu and enable Particle Filter - topic under Navigation, for example Particle Filter - /particle_cloud. The particles appear as magenta arrows. See Particle filter overlay.
- Drive the robot around. The particles should stay in a tight group around the robot, and the lidar scan should line up with the walls in the map.
- Watch the robot, not the
odomframe. A small heading correction moves theodomorigin a long way when the robot is far from it, even though the robot itself barely moves. Judge localization by how well the robot and its scan line up with the map.
4. Fix common problems
| Symptom | What to change |
|---|---|
| The robot's pose jumps when people, carts, or other objects that are not in the map are nearby. | Increase sigma_hit in small steps. Also increase z_rand and decrease z_hit by the same amount. |
| The pose drifts between corrections, then snaps back. | Decrease update_min_d and update_min_a so AMCL corrects more often. Try this before changing the alpha values. If the particles then thin out or collapse, increase resample_interval. Check that odometry is accurate (step 1). |
| The robot loses its position in long corridors or open areas. | Increase the alpha1 … alpha5 motion noise values in small steps. This keeps the particles spread out until the robot sees distinctive features again. |
| The heading flips to a wrong direction during turns in place. | Increase alpha1, the rotation noise caused by rotation, in small steps. |
| The robot loses its position near walls or obstacles on a hand-drawn map. | Check that beluga's only_obstacle_boundaries option is true, its default; it reduces filled obstacles in the map to thin outlines. If it is disabled, redraw filled walls as thin outlines. Maps from SLAM already have thin outlines. |
| The map lags behind the robot during turns. | Lower the velocity smoother's angular limit, max_velocity[2]. Changing MPPI's wz_max has no effect if it is above that limit. |
| The particles spread out and never come back together. | Check odometry (step 1), then check that max_beams is close to the scan's ray count. |
| The robot is completely lost. | Publish the robot's correct pose on /initialpose, for example with the 2D Pose Estimate tool in RViz. Keep recovery_alpha_slow and recovery_alpha_fast enabled, as in hangar_sim, so AMCL can recover on its own. Both default to 0.0, which disables recovery. |
| Localization is worse in simulation or when the computer is busy. | Close other heavy programs, such as builds. In simulation, keep the real-time factor close to 1.0. |
Change one parameter at a time, and drive the same route before and after each change so you can compare.
beluga does not implement beam skipping. You can remove do_beamskip, beam_skip_distance, beam_skip_error_threshold, and beam_skip_threshold from your configuration.
5. Tune Fuse
These are the Fuse settings most robots need to change from the hangar_sim example:
throttle_periodon each sensor. If an input arrives much faster thanoptimization_frequency, the optimizer falls behind, logsOptimization exceeded the configured duration, and keeps publishing an old estimate. Check each input's rate withros2 topic hzand setthrottle_periodto bring it close to the optimizer's rate. If the optimizer still falls behind, shortenlag_duration, the smoother's time window, so each optimization has less to solve.- Which sensor provides heading. If your IMU heading is more accurate than wheel odometry, remove
orientation_dimensionsandangular_velocity_dimensionsfrom the wheel odometry sensors so the IMU provides yaw.
To stop a sensor from providing a measurement, delete the key entirely, such as orientation_dimensions. Do not set it to an empty list ([]): Fuse fails to start with the error parameter_value_from failed ... No parameter value set.
Compare settings systematically
Driving the robot and watching is enough to get started. When you need to compare several settings reliably:
- Record a representative route once as a ROS bag, then replay the same bag through AMCL with each setting, so every run sees the same data.
- Compare the result with a reference: ground truth in simulation, or motion capture or surveyed markers on hardware.
- Look at the error while the robot is stopped and the error while it is moving separately. They have different causes, so a change can improve one and not the other. Error while stopped decides whether the robot reaches its goals.
- Repeat each setting several times, because results vary from run to run.
LAMBKIN, from the authors of beluga, automates this: it runs parameter sweeps over repeated iterations, manages the ROS processes, and collects the results for analysis.