The ROS 2 command line tools on a TurtleBot 4
The official ROS 2 beginner tutorials teach the ros2 command line with turtlesim, a 2D turtle.
Here you take the same steps on a simulated TurtleBot 4: a real robot with a LiDAR, a camera,
odometry, bumpers and a dock. You use nodes, topics, services, parameters and actions, then
rqt_console, ros2 launch and ros2 bag.
Everything runs in your browser. You don't need Ubuntu, Docker or a VPS.
This tutorial follows the structure of the ROS 2 Humble “Beginner: CLI tools” tutorials (Open Robotics, CC BY 4.0). The examples have been adapted to the TurtleBot 4. The commands are the same as on a real robot. What you learn here also works on a real TurtleBot 4 and in a real ROS 2 installation.
0The terminal
Open the simulator with the terminal already visible:
Open the TurtleBot 4 with the terminal →
You can also click Terminal on any TurtleBot 4 page. Some things to know about this terminal:
- + opens another terminal as a tab. Many steps need two or three terminals at once, for example one node that keeps running in terminal 1 and the commands that inspect it in terminal 2. Click a tab to switch.
- Ctrl+C stops whatever is running in that tab, just like in a real terminal. ↑ / ↓ go through your history, and Tab completes commands, topic names and node names.
- Type
helpto see everything this terminal knows. There are also the shell commandsls,cd,cat,nano,mkdir,cp,rm, and&&to chain commands. - Your files (parameter files, launch files, bags) are saved in your browser. They are still there tomorrow.
- The – button minimizes the terminal. Watch the robot and the LiDAR in the 3D view while you type.
The TurtleBot 4 is “switched on” when the page opens. Its nodes are already running, just like on the real robot after boot. In the steps below you add your own nodes to them.
1Understanding nodes
A node is one program with one job: read the LiDAR, drive the motors, watch the battery. Nodes talk to each other through topics, services, actions and parameters. A robot is a graph of nodes.
ros2 run
ros2 run <package> <executable> starts a node. In turtlesim you would start turtlesim_node.
Here you start a node that drives the robot in a square:
ros2 run botopia_demos square_driver
[INFO] [1792932782.704000000] [square_driver]: Driving a square: 4 sides of 0.5 m at 0.2 m/s
[INFO] [1792932782.807000000] [square_driver]: Side 1: driving 0.5 m
[INFO] [1792932785.433000000] [square_driver]: Corner 1: turning 90° left
…
The robot starts driving. Leave it running and open a second terminal with +.
To see which programs a package contains, run ros2 pkg executables botopia_demos.
ros2 node list
ros2 node list
/motion_control
/oakd
/robot_state
/robot_state_publisher
/rplidar_composition
/square_driver
/static_transform
/system_health
/turtlebot4_node
/ui_mgr
Your /square_driver sits between the nodes of the robot itself.
/rplidar_composition is the LiDAR driver, /oakd the camera, /motion_control
drives the wheels of the Create 3 base, and /robot_state publishes the battery, dock and bumper states.
Remapping
With --ros-args you change a node's name, topics or parameters when you start it, without changing the code.
Stop the square driver in terminal 1 with Ctrl+C and start it under a different name:
ros2 run botopia_demos square_driver --ros-args --remap __node:=my_square
In terminal 2, ros2 node list now shows /my_square instead of /square_driver.
You can remap topics the same way. --remap cmd_vel:=/robot2/cmd_vel would send the commands to another robot.
ros2 node info
ros2 node info /my_square
/my_square
Subscribers:
/odom: nav_msgs/msg/Odometry
/parameter_events: rcl_interfaces/msg/ParameterEvent
Publishers:
/cmd_vel: geometry_msgs/msg/Twist
/parameter_events: rcl_interfaces/msg/ParameterEvent
/rosout: rcl_interfaces/msg/Log
Service Servers:
/my_square/describe_parameters: rcl_interfaces/srv/DescribeParameters
/my_square/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
/my_square/get_parameters: rcl_interfaces/srv/GetParameters
/my_square/list_parameters: rcl_interfaces/srv/ListParameters
/my_square/set_parameters: rcl_interfaces/srv/SetParameters
/my_square/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
Service Clients:
Action Servers:
Action Clients:
This shows everything the node does: it reads /odom (how far the robot has driven),
writes /cmd_vel (the speed command), and logs on /rosout. Every node also gets
six parameter services. You will use them in step 4.
Now try ros2 node info /motion_control. That node has services and seven action servers.
Try it: stop my_square with Ctrl+C and run ros2 node list again.
The node is gone from the graph.
2Understanding topics
A topic is a named channel for messages. Any number of nodes can publish on it, and any number can subscribe. The publisher does not know who is listening. This is how sensor data and drive commands move through a robot.
Setup: drive with the keyboard
In terminal 1, start the keyboard teleop. It is the same program as on a real robot:
ros2 run teleop_twist_keyboard teleop_twist_keyboard
Click in that terminal and drive with i (forward), j / l (turn),
, (back) and k (stop). Each key publishes a geometry_msgs/msg/Twist on /cmd_vel.
rqt_graph
Open a second terminal and run:
rqt_graph
A window shows the graph: the ellipses are nodes, the rectangles are topics, and the arrows show who publishes and
who subscribes. You see /teleop_twist_keyboard → /cmd_vel → /motion_control and
/motion_control → /odom. With the drop-down you can show only the nodes, or all topics, including the
ones nobody is listening to. Drive with the keys while the window is open. Leave it open in a corner of the screen for the rest of the tutorial.
ros2 topic list
ros2 topic list -t
/battery_state [sensor_msgs/msg/BatteryState]
/cmd_audio [irobot_create_msgs/msg/AudioNoteVector]
/cmd_lightring [irobot_create_msgs/msg/LightringLeds]
/cmd_vel [geometry_msgs/msg/Twist]
/dock_status [irobot_create_msgs/msg/DockStatus]
/hazard_detection [irobot_create_msgs/msg/HazardDetectionVector]
/hmi/display/message [std_msgs/msg/String]
/imu [sensor_msgs/msg/Imu]
/ir_intensity [irobot_create_msgs/msg/IrIntensityVector]
/oakd/rgb/preview/image_raw [sensor_msgs/msg/Image]
/odom [nav_msgs/msg/Odometry]
/parameter_events [rcl_interfaces/msg/ParameterEvent]
/rosout [rcl_interfaces/msg/Log]
/scan [sensor_msgs/msg/LaserScan]
/wheel_vels [irobot_create_msgs/msg/WheelVels]
Without -t you only get the names. With -t you also see the message type of each topic.
ros2 topic echo
Show what is being published on a topic. Drive a bit in terminal 1 while this runs:
ros2 topic echo /cmd_vel
linear:
x: 0.5
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
---
Stop it with Ctrl+C and look at what the robot measures itself. --once prints one message and stops:
ros2 topic echo /odom --once
header:
stamp:
sec: 1792932786
nanosec: 891000000
frame_id: odom
child_frame_id: base_link
pose:
pose:
position:
x: 0.5003
y: 0.0123
z: 0.0
orientation:
…
---
Also try ros2 topic echo /scan --once (360 distances from the LiDAR, in metres) and
ros2 topic echo /hazard_detection. Drive into a wall and the bumper appears.
ros2 topic info
ros2 topic info /cmd_vel
Type: geometry_msgs/msg/Twist
Publisher count: 1
Subscription count: 1
With -v you also see which nodes publish and subscribe, with their QoS settings.
ros2 interface show
To publish a message yourself, you need to know its fields:
ros2 interface show geometry_msgs/msg/Twist
Vector3 linear
float64 x
float64 y
float64 z
Vector3 angular
float64 x
float64 y
float64 z
On a differential drive robot like the TurtleBot 4, only linear.x (forward, m/s) and
angular.z (turning, rad/s) do something.
ros2 topic pub
Stop the teleop with Ctrl+C, so only you are commanding the robot, and publish a command once. The message is written in YAML:
ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.0}}"
publisher: beginning loop
publishing #1: geometry_msgs.msg.Twist(linear=(x=0.2, y=0.0, z=0.0), angular=(x=0.0, y=0.0, z=1.0))
The robot makes a short arc and then stops. The Create 3 stops on its own when no new /cmd_vel arrives.
That is a safety feature. To keep it driving, publish at a fixed rate. --rate 1 means once per second:
ros2 topic pub --rate 1 /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2}, angular: {z: 1.0}}"
Now the robot drives in a circle until you press Ctrl+C. Fields you leave out are 0. Look at rqt_graph:
a /_ros2cli_… node now publishes on /cmd_vel. Untick “Hide debug” and press ⟳ to see it.
The CLI's own nodes are hidden by default, just like in the real rqt_graph.
ros2 topic hz
How often does the LiDAR send a scan?
ros2 topic hz /scan
average rate: 5.483
min: 0.177s max: 0.190s std dev: 0.00488s window: 6
average rate: 5.478
min: 0.177s max: 0.190s std dev: 0.00546s window: 11
About 5.5 Hz, like the RPLIDAR A1 on the real robot. Compare it with /odom (20 Hz) and /battery_state.
ros2 topic find
ros2 topic find geometry_msgs/msg/Twist
/cmd_vel
Try it: make the light ring red with
ros2 topic pub --once /cmd_lightring irobot_create_msgs/msg/LightringLeds "{override_system: true, leds: [{red: 255}, {red: 255}, {red: 255}, {red: 255}, {red: 255}, {red: 255}]}".
First look up the fields with ros2 interface show irobot_create_msgs/msg/LightringLeds.
3Understanding services
A service is a question and an answer: a client sends a request, and exactly one server sends back a response. Use a service for something short that you do once, such as switching on the emergency stop. Use a topic for a continuous stream of data.
ros2 service list
ros2 service list
/e_stop
/motion_control/describe_parameters
/motion_control/get_parameter_types
/motion_control/get_parameters
…
/reset_pose
/robot_state/describe_parameters
…
Most services are the six parameter services of each node. The two TurtleBot services are /e_stop (switch the
motors on or off) and /reset_pose (set the odometry back to zero). ros2 service list -t adds the types.
ros2 service type and find
ros2 service type /e_stop
irobot_create_msgs/srv/EStop
ros2 service find irobot_create_msgs/srv/EStop
/e_stop
ros2 interface show
ros2 interface show irobot_create_msgs/srv/EStop
bool e_stop_on
---
bool success
string message
Above the --- is the request, below it the response.
ros2 service call
Start the teleop again in terminal 1 and keep the robot driving. In terminal 2, switch on the emergency stop:
ros2 service call /e_stop irobot_create_msgs/srv/EStop "{e_stop_on: true}"
requester: making request: irobot_create_msgs.srv.EStop_Request(e_stop_on=True)
response:
irobot_create_msgs.srv.EStop_Response(success=True, message='E-stop on: the motors are off')
The robot stops and no longer reacts to the keys. Switch it off again with "{e_stop_on: false}".
Drive somewhere, watch ros2 topic echo /odom --once, and then set the odometry back to zero.
The robot does not move: only its idea of where it is changes.
ros2 service call /reset_pose irobot_create_msgs/srv/ResetPose "{}"
4Understanding parameters
A parameter is a setting of a node, such as a speed, a distance or a frame name. Each node has its own parameters. You can read and change them while the node is running.
Stop everything in terminal 1 and start the square driver again:
ros2 run botopia_demos square_driver
ros2 param list
ros2 param list
/motion_control:
safety_override
use_sim_time
/oakd:
use_sim_time
…
/rplidar_composition:
angle_compensate
frame_id
scan_mode
serial_port
use_sim_time
/square_driver:
angular_speed
linear_speed
side_length
sides
turn_left
use_sim_time
…
ros2 param get
ros2 param get /square_driver side_length
Double value is: 0.5
ros2 param get /motion_control safety_override
String value is: none
ros2 param set
Make the square bigger and faster while the robot drives it:
ros2 param set /square_driver side_length 1.0
Set parameter successful
ros2 param set /square_driver linear_speed 0.3
The next side is 1 m long. A node checks its parameters. Try a value it does not accept:
ros2 param set /square_driver linear_speed 2.0
Setting parameter failed: linear_speed must be between 0 and 0.46 m/s
ros2 param set /square_driver sides five
Setting parameter failed: Wrong parameter type, parameter {sides} is of type {integer}, setting it to {string} is not allowed.
Some parameters are read-only. For example, /rplidar_composition reads its serial_port only once, at start-up.
ros2 param dump
Write all parameters of a node to the screen, or to a file with >:
ros2 param dump /square_driver > square.yaml
cat square.yaml
/square_driver:
ros__parameters:
angular_speed: 0.8
linear_speed: 0.3
side_length: 1.0
sides: 4
turn_left: true
use_sim_time: false
ros2 param load
Change the file with nano square.yaml. For example, set turn_left: false and sides: 3
(that gives three sides of a square, not a triangle). Ctrl+S saves and Ctrl+X closes. Then load the file into the running node:
ros2 param load /square_driver square.yaml
Set parameter angular_speed successful
Set parameter linear_speed successful
Set parameter side_length successful
Set parameter sides successful
Set parameter turn_left successful
Set parameter use_sim_time successful
Load parameters at start-up
Stop the node with Ctrl+C and start it with the file. It begins with your settings right away:
ros2 run botopia_demos square_driver --ros-args --params-file square.yaml
A single parameter can also be set with -p:
ros2 run botopia_demos square_driver --ros-args -p side_length:=0.3 -p turn_left:=false.
The package also has a ready-made file: cat /opt/ros/humble/share/botopia_demos/config/square.yaml.
5Understanding actions
An action is for a task that takes time: “drive 1 m”, “turn 90°”, “dock”. It is built from services and topics. The client sends a goal, the server sends feedback while it works, and in the end a result. The client can also cancel the goal halfway. The Create 3 base of the TurtleBot 4 has seven actions.
ros2 action list
ros2 action list -t
/dock [irobot_create_msgs/action/Dock]
/drive_arc [irobot_create_msgs/action/DriveArc]
/drive_distance [irobot_create_msgs/action/DriveDistance]
/navigate_to_position [irobot_create_msgs/action/NavigateToPosition]
/rotate_angle [irobot_create_msgs/action/RotateAngle]
/undock [irobot_create_msgs/action/Undock]
/wall_follow [irobot_create_msgs/action/WallFollow]
ros2 action info
ros2 action info /rotate_angle
Action: /rotate_angle
Action clients: 0
Action servers: 1
/motion_control
ros2 interface show
ros2 interface show irobot_create_msgs/action/RotateAngle
float32 angle
float32 max_rotation_speed 1.9
---
geometry_msgs/PoseStamped pose
---
float32 remaining_angle_travel
There are three parts: the goal (angle in radians, plus a maximum speed with the default 1.9), the result (the pose at the end) and the feedback (how much is left to turn).
ros2 action send_goal
Turn a quarter turn to the left (π/2 rad):
ros2 action send_goal /rotate_angle irobot_create_msgs/action/RotateAngle "{angle: 1.57, max_rotation_speed: 0.5}"
Waiting for an action server to become available...
Sending goal:
angle: 1.57
max_rotation_speed: 0.5
Goal accepted with ID: 2d83c23da9a6e4cefb434937f1248010
Result:
pose:
header:
frame_id: odom
pose:
…
Goal finished with status: SUCCEEDED
Add --feedback to see the feedback while the robot works:
ros2 action send_goal /drive_distance irobot_create_msgs/action/DriveDistance "{distance: 1.0, max_translation_speed: 0.15}" --feedback
Feedback:
remaining_travel_distance: 0.8412
Feedback:
remaining_travel_distance: 0.7663
…
Press Ctrl+C halfway. The goal is cancelled and the robot stops:
Goal finished with status: CANCELED. A goal can also end in ABORTED, for example when the
robot bumps into something, or when you switch on the e-stop of step 3 during the goal.
Try it: the dock is behind the start square. Drive the robot half a metre to a metre
in front of it, then run ros2 action send_goal /dock irobot_create_msgs/action/Dock "{}" and watch it line up and drive onto it.
Just like on the real robot, the goal is rejected when the dock is not in sight (further than about 1.5 m), when the
e-stop is on, or when another action needs the robot to undock first. /undock does the reverse. Then try /navigate_to_position
("{goal_pose: {pose: {position: {x: 1.0, y: 0.5}}}}").
6rqt_console and logging
Every node writes log messages. You have already seen the [INFO] lines. Each message is also published
on the /rosout topic, and rqt_console collects them all in one window, from every node.
Open a simulator page with the corridor lane, so there are walls nearby:
TurtleBot 4 in the corridor, with the terminal →
rqt_console
The window already shows the start-up messages of the robot nodes (LiDAR health, camera ready, battery). In terminal 2, start a node that watches the LiDAR:
ros2 run botopia_demos scan_monitor
Then, in terminal 3, drive towards a wall with ros2 run teleop_twist_keyboard teleop_twist_keyboard:
[INFO] [1792932901.120000000] [scan_monitor]: Watching /scan: warning below 0.5 m
[WARN] [1792932905.620000000] [scan_monitor]: Obstacle 0.42 m away at 3° (closer than min_distance 0.5 m)
[ERROR] [1792932907.120000000] [scan_monitor]: Obstacle only 0.21 m away at 0°: stop!
[INFO] [1792932909.620000000] [scan_monitor]: Clear again: nearest obstacle 0.78 m
In rqt_console, each message has a severity, a node, a time and a text. Untick severities to hide them, or type a node name
in the filter. When you drive into the wall, /motion_control logs the bumper as a WARN.
Logger levels
There are five levels, from least to most severe:
| Level | Used for | Example on the TurtleBot 4 |
|---|---|---|
DEBUG | details for the developer | scan_monitor: the nearest point at every scan |
INFO | what the node is doing | square_driver: “Corner 2: turning 90° left” |
WARN | something unexpected, but not wrong | bumper pressed, battery low, obstacle close |
ERROR | something went wrong | obstacle closer than danger_distance |
FATAL | the node cannot go on | – |
By default a node shows INFO and higher. Change this at start-up with --log-level:
ros2 run botopia_demos scan_monitor --ros-args --log-level WARN
Now the node is quiet until something is close. With --log-level DEBUG you see every measurement.
ros2 run botopia_demos square_driver --ros-args --log-level DEBUG shows how far each side is.
The log messages are a normal topic. Look at them raw with ros2 topic echo /rosout.
7Launching nodes
A real robot quickly needs ten nodes or more. Starting them one by one in separate terminals gets tedious. A launch file starts many nodes at once, with their parameters and remaps.
ros2 launch
The classic example, a talker and a listener on /chatter:
ros2 launch demo_nodes_cpp talker_listener.launch.py
[INFO] [launch]: All log files can be found below /home/ubuntu/.ros/log/2026-10-25-13-52-25-turtlebot4-4692
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [talker-1]: process started with pid [4693]
[INFO] [listener-2]: process started with pid [4695]
[talker-1] [INFO] [1792932746.953000000] [talker]: Publishing: 'Hello World: 1'
[listener-2] [INFO] [1792932746.954000000] [listener]: I heard: [Hello World: 1]
…
Each line starts with the process it comes from: [talker-1] or [listener-2]. Ctrl+C stops all of them at once.
Launch arguments
A launch file can declare arguments. See them with --show-args:
ros2 launch botopia_demos square.launch.py --show-args
Arguments (pass arguments as '<name>:=<value>'):
'side_length':
Length of one side of the square (m)
(default: '0.5')
'linear_speed':
Driving speed (m/s)
(default: '0.2')
ros2 launch botopia_demos square.launch.py side_length:=0.8
Two nodes at once, a square driver and a LiDAR monitor:
ros2 launch botopia_demos patrol.launch.py min_distance:=0.6
Run rqt_graph while it runs to see both nodes.
Write your own launch file
A launch file is a Python file. Look at how square.launch.py is made:
cat /opt/ros/humble/share/botopia_demos/launch/square.launch.py
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
DeclareLaunchArgument('side_length', default_value='0.5',
description='Length of one side of the square (m)'),
DeclareLaunchArgument('linear_speed', default_value='0.2',
description='Driving speed (m/s)'),
Node(
package='botopia_demos',
executable='square_driver',
name='square_driver',
parameters=[{
'side_length': LaunchConfiguration('side_length'),
'linear_speed': LaunchConfiguration('linear_speed'),
}],
output='screen',
),
])
Copy it to your own folder and change it:
mkdir launch && cp /opt/ros/humble/share/botopia_demos/launch/square.launch.py launch/my_robot.launch.py
nano launch/my_robot.launch.py
For example, add a second Node(…) for scan_monitor, add 'sides': 6 to the parameters, or give the node
a different name=. You can add remaps with remappings=[('cmd_vel', 'other_cmd_vel')].
Save with Ctrl+S, close with Ctrl+X, and start your file by its path:
ros2 launch launch/my_robot.launch.py side_length:=0.3
The terminal reads the Node(…) and DeclareLaunchArgument(…) entries of
your file, with their package, executable, name, namespace,
parameters and remappings. It does not run other Python code: no if,
no loops, no included launch files.
8Recording and playing back data
ros2 bag records the messages on topics into a file, a bag, and plays them back later
with the same timing. This is useful for testing an algorithm again and again on the same data, or for showing
what the robot did.
Setup
mkdir bag_files && cd bag_files
In terminal 2, start the square driver: ros2 run botopia_demos square_driver.
Choose a topic
ros2 topic echo /cmd_vel
You see the commands that the square driver sends. Those are the commands you want to record. Stop the echo with Ctrl+C.
ros2 bag record
Stop the square driver in terminal 2 for a moment. Start the recorder in terminal 1. With -o you choose
the name, and you can record several topics at once:
ros2 bag record -o square /cmd_vel /odom
[INFO] [1792932851.704000000] [rosbag2_storage]: Opened database 'square/square_0.db3' for READ_WRITE.
[INFO] [1792932851.715000000] [rosbag2_recorder]: Press SPACE for pausing/resuming
[INFO] [1792932851.716000000] [rosbag2_recorder]: Listening for topics...
[INFO] [1792932851.716000000] [rosbag2_recorder]: Subscribed to topic '/cmd_vel'
[INFO] [1792932851.716000000] [rosbag2_recorder]: Subscribed to topic '/odom'
[INFO] [1792932851.716000000] [rosbag2_recorder]: Recording...
Now start the square driver in terminal 2 and let it drive the whole square. Then press Ctrl+C in terminal 1:
[INFO] [1792932875.460000000] [rosbag2_cpp]: Writing remaining messages from cache to the bag. It may take a while
[INFO] [1792932875.460000000] [rosbag2_recorder]: Recording stopped
Use ros2 bag record -a to record all topics. That can grow large on a real robot, because the camera images are big.
The actions of step 5 do not appear in /cmd_vel. On the Create 3,
/motion_control drives the wheels itself. So record a node that publishes on /cmd_vel
(square driver, teleop, ros2 topic pub), or record /odom to see where the robot went.
ros2 bag info
ros2 bag info square
Files: square_0.db3
Bag size: 61.4 KiB
Storage id: sqlite3
Duration: 21.6s
Start: Oct 25 2026 13:54:11.70 (1792932851.70)
End: Oct 25 2026 13:54:33.30 (1792932873.30)
Messages: 638
Topic information: Topic: /cmd_vel | Type: geometry_msgs/msg/Twist | Count: 206 | Serialization Format: cdr
Topic: /odom | Type: nav_msgs/msg/Odometry | Count: 432 | Serialization Format: cdr
ros2 bag play
Put the robot back on the start square with Reset on the page, and play the bag:
ros2 bag play square --topics /cmd_vel
The robot drives the square again, without the square driver running. The bag sends the same /cmd_vel
commands with the same timing. Compare the end pose with the recorded one. It is never exactly the same,
because the wheels slip a little differently each time. That is why robots use feedback, like the square driver does with /odom.
While playing, space pauses, and ↑ / ↓ make it faster or slower.
-r 2.0 plays at double speed, -l loops, and --remap /cmd_vel:=/other sends it somewhere else.
Why --topics /cmd_vel? Without it, the recorded /odom is also published again, alongside the
live /odom of the robot. Run ros2 topic echo /odom while playing without --topics and see both mixed together.
9What is simulated, and what not
The terminal is a simulation of a ROS 2 system, written in JavaScript. It is not a real Linux machine. It does exactly what the tutorial needs, with the same commands and almost the same output as real ROS 2 Humble. The differences:
- You cannot install packages with apt. The available programs are the TurtleBot 4 nodes,
teleop_twist_keyboard,demo_nodes_cpp(talker, listener),botopia_demos(square_driver, scan_monitor),rqt_console,rqt_graph, and the Python nodes you write yourself in tutorial 8. C++ nodes do not run. - Launch files are read, not executed (see the note in step 7).
- A bag is a JSON file named
.db3, not a real SQLite database. You cannot open it in a real ROS 2. - There is no DDS network and no
ROS_DOMAIN_ID. Every terminal tab sees the same robot.
Next: tutorial 8 shows how to write your own ROS 2 nodes in Python, in the same terminal: workspaces, packages, colcon, publishers, subscribers, services, custom messages and parameters. After that, the next step is a real ROS 2 Humble on Ubuntu 22.04, or a real TurtleBot 4. All commands of this page work there in the same way. To control the simulated robots from Python without ROS, see the API documentation.
10Cheat sheet
| Goal | Command |
|---|---|
| Start a node | ros2 run PKG EXE [--ros-args -r __node:=NAME -p P:=V --params-file F --log-level L] |
| Nodes | ros2 node list · ros2 node info /NODE |
| Topics | ros2 topic list -t · echo · info -v · hz · find TYPE |
| Publish | ros2 topic pub [--once | --rate N] /TOPIC TYPE "{yaml}" |
| Message fields | ros2 interface show TYPE |
| Services | ros2 service list -t · type · find · call /SRV TYPE "{yaml}" |
| Parameters | ros2 param list · get · set · dump /NODE > f.yaml · load /NODE f.yaml |
| Actions | ros2 action list -t · info · send_goal /ACT TYPE "{yaml}" --feedback |
| Logs | rqt_console · ros2 topic echo /rosout |
| Graph | rqt_graph |
| Launch | ros2 launch PKG FILE.launch.py [arg:=value] [--show-args] · ros2 launch path/to/file.launch.py |
| Bags | ros2 bag record [-o NAME] [-a | TOPICS…] · info NAME · play NAME [-r 2] [-l] [--topics …] |