- Master 15 essential ROS2 CLI commands for inspecting topics, services, and nodes in real time.
- Learn how to debug publish rates, QoS mismatches, and connection failures using terminal tools.
- Discover why CLI tools beat GUIs for scripting, remote debugging, and scalable inspection.
The First Thing You Need After ros2 run
You just launched your first ROS2 node. It’s running. Great. Now what?
Most tutorials stop here, leaving you staring at a terminal with no idea what your node is actually doing. Is it publishing? At what rate? What’s the message structure? This is where the ROS2 command-line tools become essential — not just for debugging, but for understanding what’s happening in your system at all.
I’m going to show you 15 commands that turn ROS2 from a black box into something you can actually inspect and control. These aren’t just reference material — they’re the tools I reach for every single time something doesn’t work the way I expect.

ros2 topic list: See Every Active Topic
Start here:
ros2 topic list
This dumps every active topic in your ROS2 network. On a fresh turtlesim node (install with sudo apt install ros-humble-turtlesim if you’re following along), you’ll see:
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
The /rosout and /parameter_events topics are system-level — every node publishes to these. The interesting ones are the turtle1/* topics: velocity commands, color sensor data, and pose (position/orientation).
Add -t to see message types:
ros2 topic list -t
Output:
/turtle1/cmd_vel [geometry_msgs/msg/Twist]
/turtle1/pose [turtlesim/msg/Pose]
Now you know /turtle1/cmd_vel expects a Twist message (linear and angular velocity vectors). This is critical when you’re about to publish to a topic manually — the message type tells you what fields you need.
ros2 topic echo: Watch Messages in Real Time
Want to see what’s flowing through a topic?
ros2 topic echo /turtle1/pose
This streams every message published to /turtle1/pose:
x: 5.544444561004639
y: 5.544444561004639
theta: 0.0
linear_velocity: 0.0
angular_velocity: 0.0
---
The turtle starts at with zero velocity. If you drive it around (using arrow keys in the turtlesim window), you’ll see these values update in real time.
Limit output with --once (print one message and exit) or --no-arr (hide array brackets for cleaner output). I use --once constantly when I just need to confirm a topic is alive:
ros2 topic echo /turtle1/pose --once
One message, then the command exits. Perfect for quick checks.
ros2 topic hz: Measure Publishing Rate
You think your node is publishing at 10 Hz. Is it actually?
ros2 topic hz /turtle1/pose
Output:
average rate: 62.496
min: 0.015s max: 0.017s std dev: 0.00041s window: 64
The turtle’s pose updates at ~62 Hz. The min and max fields show jitter — the time between consecutive messages. A standard deviation of 0.4ms means the timing is pretty stable.
This command catches performance issues you wouldn’t see otherwise. If your control loop is supposed to run at 100 Hz but ros2 topic hz shows 23 Hz, you’ve found your bottleneck. I’ve debugged memory leaks that killed our Jetson nodes after 48 hours — the first symptom was always a dropping publish rate.
ros2 topic info: Check Publishers and Subscribers
Who’s talking to this topic?
ros2 topic info /turtle1/cmd_vel
Output:
Topic: /turtle1/cmd_vel
Publisher count: 0
Subscription count: 1
One subscriber (the turtlesim node itself), zero publishers. That’s why the turtle isn’t moving — nothing is sending velocity commands yet.
Add --verbose for full details:
ros2 topic info /turtle1/cmd_vel --verbose
You’ll see QoS (Quality of Service) settings: reliability (reliable vs best-effort), durability (volatile vs transient), history depth. QoS mismatches are a common reason topics don’t connect — if a publisher uses best_effort and a subscriber requires reliable, they won’t communicate. This command surfaces those mismatches immediately.
ros2 topic pub: Manually Publish Messages
Want to drive the turtle without writing a node?
ros2 topic pub /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 1.8}}"
The turtle spins in a circle. You just published a Twist message with linear velocity m/s and angular velocity rad/s.
The YAML syntax is finicky — note the double quotes around the entire message and single quotes (or no quotes) for field names. If you get field 'x' must be set, check your braces and commas.
By default, ros2 topic pub publishes at 1 Hz. Add --rate 10 for 10 Hz, or --once to publish one message and exit:
ros2 topic pub --once /turtle1/cmd_vel geometry_msgs/msg/Twist "{linear: {x: 1.0}}"
One forward jolt, then silence.
ros2 topic bw: Measure Bandwidth Usage
How much data is flowing through a topic?
ros2 topic bw /turtle1/pose
Output:
Subscribed to [/turtle1/pose]
2.93 KB/s from 62 messages
The pose topic uses ~3 KB/s. For a single float32 pose message, that’s 40 bytes per message × 62 Hz = 2.48 KB/s, plus DDS overhead. This matches.
I use this when network bandwidth becomes a bottleneck — compressing image topics or reducing publish rates. On embedded systems (Raspberry Pi, Jetson Nano), high-bandwidth topics can saturate the network interface. This command tells you which topics to optimize first.
ros2 interface show: Inspect Message Definitions
What fields does a Twist message have?
ros2 interface show geometry_msgs/msg/Twist
Output:
Vector3 linear
float64 x
float64 y
float64 z
Vector3 angular
float64 x
float64 y
float64 z
Now you know the exact structure. linear and angular are both Vector3 types with x, y, z float64 fields. This is essential when you’re writing publishers — you need to match this structure exactly.
For custom messages, this shows you field types, default values, and comments from the .msg definition file.
ros2 service list: Find Available Services
Services are request-response interactions (unlike topics, which are continuous streams).
ros2 service list
Turtlesim exposes several services:
/clear
/kill
/reset
/spawn
/turtle1/set_pen
/turtle1/teleport_absolute
/turtle1/teleport_relative
The /spawn service creates a new turtle. /teleport_absolute moves the turtle to an exact position. These are operations you trigger once, not continuously — perfect for services.
Add -t for service types:
ros2 service list -t
Output:
/spawn [turtlesim/srv/Spawn]
/turtle1/teleport_absolute [turtlesim/srv/TeleportAbsolute]

ros2 service type: Get Service Message Type
What does the /spawn service expect?
ros2 service type /spawn
Output:
turtlesim/srv/Spawn
Now check the request/response structure:
ros2 interface show turtlesim/srv/Spawn
Output:
float32 x
float32 y
float32 theta
string name
---
string name
The --- separates request (top) from response (bottom). You send coordinates and a name; the service returns the spawned turtle’s name. If you leave name empty, it auto-generates one.
ros2 service call: Trigger a Service Manually
Spawn a second turtle at :
ros2 service call /spawn turtlesim/srv/Spawn "{x: 2.0, y: 2.0, theta: 0.0, name: 'turtle2'}"
Response:
waiting for service to become available...
requester: making request: turtlesim.srv.Spawn_Request(x=2.0, y=2.0, theta=0.0, name='turtle2')
response:
turtlesim.srv.Spawn_Response(name='turtle2')
A second turtle appears in the window. Now you have two independent turtles, each with their own /turtleX/cmd_vel topic.
If the service call hangs with “waiting for service to become available”, the service node isn’t running. This is a common gotcha when nodes crash or you forget to launch a service provider.
ros2 node list: See All Running Nodes
ros2 node list
Output:
/turtlesim
One node running. If you launch a second terminal and run ros2 run turtlesim turtle_teleop_key, you’ll see:
/turtlesim
/teleop_turtle
The teleop node publishes to /turtle1/cmd_vel based on your keyboard input. This is why ros2 node list is the first command I run when debugging multi-node systems — it confirms every expected node is alive.
ros2 node info: Inspect Node Connections
What topics and services does a node provide?
ros2 node info /turtlesim
Output:
/turtlesim
Subscribers:
/turtle1/cmd_vel: geometry_msgs/msg/Twist
Publishers:
/turtle1/color_sensor: turtlesim/msg/Color
/turtle1/pose: turtlesim/msg/Pose
Service Servers:
/spawn: turtlesim/srv/Spawn
/turtle1/teleport_absolute: turtlesim/srv/TeleportAbsolute
Service Clients:
Action Servers:
/turtle1/rotate_absolute: turtlesim/action/RotateAbsolute
Action Clients:
The turtlesim node subscribes to velocity commands, publishes pose and color sensor data, and provides several services. This is a complete map of the node’s interface.
Action servers (like /turtle1/rotate_absolute) are long-running tasks with feedback — you send a goal angle, and the node periodically reports progress until the rotation completes. Actions are beyond basic topics/services but show up in node info.
ros2 param list: See Node Parameters
Parameters are runtime configuration values (background color, robot mass, PID gains).
ros2 param list
Output:
/turtlesim:
background_b
background_g
background_r
use_sim_time
RGB values for the window background. Get the current value:
ros2 param get /turtlesim background_r
Output:
Integer value is: 69
Change it:
ros2 param set /turtlesim background_r 255
The background instantly shifts to red. No need to restart the node. This is how you tune parameters in real time — I’ve adjusted Nav2 DWA planner gains mid-mission to avoid obstacles more aggressively.
ros2 bag record: Capture Live Data
You need to replay a test scenario later. Record all topics:
ros2 bag record -a
This writes every active topic to a .db3 SQLite file in the current directory. Stop with Ctrl+C.
Record specific topics:
ros2 bag record /turtle1/pose /turtle1/cmd_vel
Playback:
ros2 bag play rosbag2_2026_05_19-12_34_56/
The bag replays every message with original timestamps. This is essential for debugging non-deterministic bugs — record the failure, replay it 100 times until you isolate the cause. I’ve used bag files to benchmark sensor fusion algorithms offline without needing the physical robot.
ros2 run: Launch a Node (The One You Already Know)
You’ve seen this:
ros2 run turtlesim turtlesim_node
But combine it with remapping to override topic names:
ros2 run turtlesim turtlesim_node --ros-args --remap /turtle1/cmd_vel:=/my_custom_topic
Now the turtle listens on /my_custom_topic instead of /turtle1/cmd_vel. This is how you integrate nodes with conflicting default names — remap topics on launch rather than editing source code.
When Commands Fail: QoS Mismatches and Timing Issues
You run ros2 topic echo /my_topic and see nothing, even though ros2 topic list confirms the topic exists.
Common causes:
- QoS mismatch: The publisher uses
best_effortreliability, but your subscriber (theechocommand) defaults toreliable. Add--qos-reliability best_effortto match. - Latched topics: Some topics only publish once (e.g., a static map). By the time you run
echo, the message already passed. Useros2 topic echo --qos-durability transient_localto receive the last published message. - No publishers yet: The node publishing to this topic hasn’t started. Check
ros2 topic info /my_topic— if “Publisher count: 0”, that’s your issue.
I spent an embarrassing amount of time debugging a camera node that “wasn’t publishing” before realizing the QoS was set to sensor_data (best-effort, volatile) while my subscriber expected reliable delivery. ros2 topic info --verbose would have caught it immediately.
Why CLI Tools Matter More Than GUI Tools
ROS2 has GUIs like rqt_graph and plotjuggler. I rarely use them.
CLI tools are scriptable. I have a shell function that checks if critical topics are alive before launching a mission:
check_topics() {
ros2 topic hz /camera/image_raw --timeout 2.0 --window 10
ros2 topic hz /lidar/scan --timeout 2.0 --window 10
}
If either topic isn’t publishing at the expected rate, the script aborts. You can’t do that with a GUI.
CLI tools also work over SSH. When your robot is running in the field and you’re debugging remotely, you need commands that work in a terminal. GUIs require X forwarding or VNC — brittle and slow over cellular links.
And CLI tools scale. If you need to inspect 50 topics, you write a bash loop. With a GUI, you’re clicking through menus for 10 minutes.
One More Thing: ros2 doctor
This one’s a lifesaver for mysterious connection issues:
ros2 doctor --report
It checks your ROS2 installation, network configuration, middleware settings, and active nodes. Output includes warnings like “multiple ROS_DOMAIN_IDs detected” or “DDS middleware version mismatch” — issues that silently break topic discovery.
I run ros2 doctor first whenever topics aren’t connecting between machines. Nine times out of ten, it’s a firewall rule or mismatched domain ID.
FAQ
Q: Why do some commands show “waiting for service” forever?
The service node isn’t running, or the service name is wrong (typo, wrong namespace). Run ros2 service list to confirm the exact name. If the service is listed but still unreachable, check QoS settings with ros2 service info --verbose.
Q: How do I echo a topic that publishes images?
ros2 topic echo works, but dumps raw binary pixel data (unreadable). Use ros2 run rqt_image_view rqt_image_view instead, or save to disk: ros2 run image_view image_saver --ros-args --remap /image:=/your_camera_topic.
Q: Can I change multiple parameters at once without typing 10 commands?
Yes. Dump current params to a YAML file: ros2 param dump /node_name > params.yaml. Edit the file, then load it: ros2 param load /node_name params.yaml. You can also pass --params-file params.yaml when launching nodes.
My Advice: Memorize 5, Reference the Rest
You don’t need all 15 commands in muscle memory. Learn these five cold:
ros2 topic list -t— see what’s aliveros2 topic echo --once— quick message checkros2 topic hz— catch rate issuesros2 node info— map node interfacesros2 doctor— fix connection mysteries
The rest (bw, interface show, bag record) you’ll reach for as needed. Bookmark this post if you want — I still look up the exact --qos-reliability flag syntax half the time.
One pattern I’ve found useful: chain commands in scripts. Before launching a navigation stack, I run ros2 topic hz checks on sensor topics, ros2 param get to verify controller gains, and ros2 service call to clear costmaps. The CLI tools compose well — that’s their real power.
If you’re working on an embedded system like a Jetson or Raspberry Pi, grab a USB-powered cooling fan — thermal throttling kills your publish rates before you realize what’s happening.
I’m still figuring out the best way to monitor QoS compatibility across a large system (50+ nodes). The --verbose flags help, but there’s no single command that validates “will these 10 nodes actually communicate?” before you launch them. If you’ve solved this, I’d love to hear how.
Did you find this helpful?
Your support keeps this blog running and ad-free content coming.
☕ Buy me a coffeeMost Popular Posts
- Custom Metaclass in Python: 43% Faster Validation (12,863 views)
- Python match-case: 7 Patterns That Beat if-elif Chains (963 views)
- yfinance Alternatives 2026: 7 Free APIs Compared (828 views)
- YOLOv8 INT8 Quantization: 4x Faster on Jetson Orin (813 views)
- PaddleOCR vs EasyOCR vs Tesseract: Why PaddleOCR Is Slower (606 views)