Example: TurtleBot 4 (Jazzy)

Runs the full TurtleBot 4 simulator (iRobot Create 3 base + RPLIDAR + OAK-D camera) in Gazebo Harmonic with all the ROS 2 nodes that ship for the real robot.

Source: examples/turtlebot4/. Jazzy only — TB4’s simulator stack on Humble uses Ignition Fortress and different package names; this example doesn’t cover it.


1. Build the extended image

From the repo root (with ROS_DISTRO=jazzy in .env):

docker compose -f docker-compose.yml -f examples/turtlebot4/docker-compose.yml up -d --build

Add -f docker-compose.nvidia.yml before up if you have an NVIDIA GPU — the TB4 sim is heavy, you want it.

The build installs turtlebot4-desktop, turtlebot4-simulator, turtlebot4-navigation, plus slam-toolbox and nav2-bringup on top of the base image. First build takes several minutes; afterwards it’s cached.


2. Launch the simulator

docker compose exec ros-gazebo zsh
ros2 launch turtlebot4_gz_bringup turtlebot4_gz.launch.py

Gazebo opens with a TurtleBot 4 on the depot world. The Create 3 bringup, RPLIDAR, camera, and EKF nodes all spin up automatically.

If that launch file isn’t found, check which launch your installed version ships: ros2 pkg prefix turtlebot4_gz_bringup && ls $(ros2 pkg prefix turtlebot4_gz_bringup)/share/turtlebot4_gz_bringup/launch. The package was renamed from turtlebot4_ignition_bringup when TB4 moved to gz-sim.


3. Verify topics

Second shell:

docker compose exec ros-gazebo zsh
ros2 topic list

Expected (abridged):

/cmd_vel
/odom
/scan
/oakd/rgb/preview/image_raw
/tf
/battery_state
ros2 topic echo /scan --once
ros2 topic hz /odom

4. Drive it from the CLI

On Jazzy, TurtleBot 4’s /cmd_vel is geometry_msgs/msg/TwistStamped, not the plain Twist you may be used to. Check first:

ros2 topic info /cmd_vel

Drive forward continuously (Ctrl-C to stop — Create 3 safety-stops within ~0.5s after the publish stream ends):

ros2 topic pub -r 20 /cmd_vel geometry_msgs/msg/TwistStamped \
  '{header: {frame_id: "base_link"}, twist: {linear: {x: 0.2}, angular: {z: 0.0}}}'

Spin in place:

ros2 topic pub -r 20 /cmd_vel geometry_msgs/msg/TwistStamped \
  '{twist: {angular: {z: 0.5}}}'

One-shot (robot moves briefly, then safety-stops):

ros2 topic pub --once /cmd_vel geometry_msgs/msg/TwistStamped \
  '{twist: {linear: {x: 0.2}}}'

Zsh quoting gotcha: keep the whole command on one line. Zsh mangles backslash-newlines mid-YAML, which splits the message into multiple shell words and produces an unhelpful unrecognized arguments error. Single-quote the YAML so {, }, and : aren’t interpreted by the shell.

Why teleop_twist_keyboard doesn’t move the robot

teleop_twist_keyboard publishes plain geometry_msgs/msg/Twist. TB4 on Jazzy subscribes to TwistStamped. The topic name matches, so ros2 topic list looks fine, but no message gets through. Either use ros2 topic pub as above, or run a twist-to-twist-stamped relay, or use turtlebot4_teleop if available.


5. Optional: Nav2 + SLAM

With the sim still running:

ros2 launch turtlebot4_navigation slam.launch.py
ros2 launch turtlebot4_navigation nav2.launch.py
ros2 launch turtlebot4_viz view_robot.launch.py

RViz opens with the live map and Nav2 goal tools.


Shut down

docker compose -f docker-compose.yml -f examples/turtlebot4/docker-compose.yml down

This site uses Just the Docs, a documentation theme for Jekyll.