A full ROS 2-based differential drive robot project for simulation, localization, mapping, and autonomous navigation, entirely containerized with Docker Compose.
This repository demonstrates a complete robotics pipeline — from URDF description and ROS2 control to SLAM and navigation — all reproducible and modular.
- Project Overview
- Requirements
- Docker Setup
- Running the Simulation
- Localization, Mapping & Navigation
- Common Issues
The DiffRobot-ROS2-Navigation project is a modular ROS 2 workspace that includes:
| Package | Purpose |
|---|---|
| 🛠️ diff_robot_controllers | Implements ros2_control for differential drive movement and velocity control. |
| 🧱 diff_robot_description | Defines the robot in URDF/Xacro, including sensors, joints, and geometry. |
| 🛰️ diff_robot_localization | Uses robot_localization (EKF) for state estimation by fusing IMU and odometry. |
| 🗺️ diff_robot_nav | Provides SLAM and Nav2 configuration for mapping and path planning. |
| 🎮 diff_robot_simulation | Sets up Gazebo worlds and plugins for simulation and testing. |
Everything runs inside a Docker container for an easy, dependency-free setup.
- Docker
Without docker container, you need:
- ROS 2 Jazzy
- Ubuntu 24.04 (recommended)
- X11 display support for GUI tools (RViz, Gazebo)
- Gazebo Harmonic
The Volume has to be changed according to the workspace path device: path/to/ws
version: "3.9"
services:
ros2-control-1:
build:
context: .
dockerfile: Dockerfile
command: /bin/bash
environment:
- DISPLAY=$DISPLAY
- QT_X11_NO_MITSHM=1
image: ros2-control-image:1.0
container_name: ros2-control-container
restart: unless-stopped
volumes:
- ws-volume:/root/ros_ws
- /tmp/.X11-unix:/tmp/.X11-unix
ports:
- "15001:11313"
tty: true
stdin_open: true
volumes:
ws-volume:
driver: local
driver_opts:
type: none
device: /home/andi/DockerDev/diff_robot/dev_ws
o: bind1️⃣ Build the Docker image
docker-compose build2️⃣ Start the container
xhost +local:root # Allow GUI for Gazebo/RViz
docker-compose up -d3️⃣ Access the running container
docker exec -it ros2-control-container bash4️⃣ Build and source your ROS 2 workspace
cd ~/ros_ws
colcon build
source install/setup.bashNow your environment is ready to launch the simulation, localization, and navigation stacks.
3.1 Launch Gazebo Simulation
To visualize the differential drive robot model in a simulated world (default custom maze world from diff_robot_simulation/worlds/maze.sdf):
ros2 launch diff_robot_simulation gazebo.launch.pyExample: Differential drive robot in Gazebo.
Example: Maze world in Gazebo.
3.2 Run the Controllers
Load the ros2_control controllers for the differential drive robot:
ros2 launch diff_robot_controllers gz_controllers.launch.pyThis will automatically lunch RViz2 as well. You can control this with the launch argument:
ros2 launch diff_robot_controllers gz_controllers.launch.py launch_rviz:=falseYou can verify available controllers:
ros2 control list_controllers🎮 3.3 Teleoperate the Robot (Optional)
Install teleop if not already included:
sudo apt install ros-humble-teleop-twist-keyboardThen run the teleop by remapping the /cmd_vel topic to /diff_drive_controller/cmd_vel one and ensuring the message is stamped:
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/diff_drive_controller/cmd_vel -p stamped:=trueUse your keyboard to move the robot inside Gazebo.
This section explains the main stages of making your robot autonomous: Localization → Mapping → Navigation.
4.1 Localization (EKF)
Run the Extended Kalman Filter to fuse odometry and IMU:
ros2 launch diff_robot_localization ekf.launch.pyThis improves pose accuracy and stability by filtering noisy data.
4.2 Mapping (SLAM)
To build a map of the environment, launch the RViz2 and Gazebo simulation with:
ros2 launch diff_robot_nav diff_robot_slam.launch.pyThen, drive the robot via teleop to explore the environment.
When you’re done mapping, save the map useing the slam_toolbox pkg service:
ros2 service call /slam_toolbox/save_map slam_toolbox/srv/SaveMap "name: data: '/path/to/maps_folder/map_name'"Example: Real-time SLAM map generation in RViz..
4.3 Autonomous Navigation (Nav2)
Once a map is available, start Nav2 for autonomous navigation by taking care of modifying the map path in the launch file or by using the map launch argument:
ros2 launch diff_robot_nav diff_robot_navigation.launch.py map:=/path/to/map/to/loadThen open RViz, set the initial pose with SetInitialPose, reset the nav2 components on the left tab and click 2D Goal Pose to send a target.
Example: Set the initial pose.
Example: Reset the NAV2 components.
Example: Robot planning and navigating to a goal using Nav2.
| Issue | Description | Fix |
|---|---|---|
| GUI not showing | X11 permission error | Run xhost +local:root before docker-compose up |
| controller_manager not running | Missing ros2_control startup |
Start controller manually or check launch file |
| Slow simulation | CPU overload | Use smaller Gazebo world or enable GPU rendering |
| No navigation | Localization not running | Ensure EKF and map topics are publishing correctly |





