Obstacle Avoidance and AMCL Localization
Overview
Combine reactive obstacle avoidance with probabilistic localization. You will implement a simple lidar-based avoidance loop and then initialize Adaptive Monte Carlo Localization (AMCL) on a pre-built map to maintain pose estimates while navigating.
Prerequisites
- Completed IMU Processing with a 1D Kalman Filter
- 2D occupancy grid map (PGM/YAML pair) for your test track
- Lidar publishing
/scanat ≥10 Hz - The roboracer publishing velocity on the topic
/cmd_vel
Learning Objectives
- Students can implement a complete autonomous behavior and use a standard algorithm to know where their car is.
- Generate steering commands that keep the vehicle clear of nearby obstacles
- Configure
move_base-free AMCL for lightweight localization - Validate particle filter convergence against ground truth markers
1. Implement Reactive Obstacle Avoidance
- Create a ROS 2 node
obstacle_avoidance_node.py:import math import rclpy from rclpy.node import Node from sensor_msgs.msg import LaserScan from geometry_msgs.msg import Twist class ObstacleAvoid(Node): def __init__(self): super().__init__('obstacle_avoid') self.declare_parameter('min_range', 0.5) self.declare_parameter('forward_speed', 0.5) self.declare_parameter('turn_gain', 1.5) self.pub = self.create_publisher(Twist, '/cmd_vel', 10) self.sub = self.create_subscription(LaserScan, '/scan', self.scan_cb, 10) def scan_cb(self, scan: LaserScan): min_r = self.get_parameter('min_range').value forward = self.get_parameter('forward_speed').value turn_gain = self.get_parameter('turn_gain').value ranges = scan.ranges left = min(ranges[len(ranges)//2:]) right = min(ranges[:len(ranges)//2]) cmd = Twist() cmd.linear.x = forward if min(left, right) > min_r else 0.0 cmd.angular.z = turn_gain * (right - left) self.pub.publish(cmd) rclpy.init() node = ObstacleAvoid() rclpy.spin(node) - Adjust
min_rangeto maintain a comfortable buffer. - Test in simulation first (
ros2 launch fri_sim simple_world.launch.py).
2. Prepare the Map and TF Tree
- Copy your map files into
fri_navigation/maps/track.yamlandtrack.pgm. - Ensure TF broadcasts exist for
map → odom → base_link. Confirm withros2 run tf2_tools view_frames. - Set the initial pose guess in
map_serverlaunch file.
3. Launch AMCL
- Configure
amcl.yaml:use_map_topic: false min_particles: 200 max_particles: 2000 laser_z_hit: 0.5 laser_z_rand: 0.2 update_min_a: 0.2 update_min_d: 0.1 - Launch stack:
ros2 launch fri_navigation localization.launch.py map:=track.yaml - Monitor
/amcl_poseand/particlecloudin Foxglove.
4. Integrate Avoidance with Localization
- Run
obstacle_avoidance_node.pyconcurrently with AMCL. - Watch the vehicle maintain pose while reacting to obstacles.
- Log
/cmd_vel,/amcl_pose, and/scanfor tuning.
5. Evaluate Performance
- Drive a loop and compare
/amcl_poseto ground truth markers usingrviz2or manual measurements. - Check localization covariance; it should shrink once particles converge.
- Increase particle counts if the map has dense obstacles; reduce if CPU is constrained.
6. Troubleshooting
- Divergence suggests TF mismatches or inaccurate sensor model; re-check frame IDs.
- If the robot stalls, widen
min_rangeor add smoothing via a PID controller. - Use
ros2 topic hzto ensure/scanrates stay consistent.
Wrap-Up
Commit the avoidance node and AMCL configuration files. Record localization errors for baseline metrics.