ROS2 Topic & Service Commands: 15 CLI Tools Tested

Disclosure: As an Amazon Associate, I earn from qualifying purchases. Some links in this post are affiliate links — they cost you nothing extra.
⚡ Key Takeaways
  • 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.

A futuristic robot in a studio setting, striking a powerful pose with raised arms.
Photo by Pavel Danilyuk on Pexels

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.

Enjoying this article? Get more like it delivered to your inbox. Subscribe to the newsletter

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 (5.544,5.544)(5.544, 5.544) 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 vx=2.0v_x = 2.0 m/s and angular velocity ωz=1.8\omega_z = 1.8 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 (x,y)(x, y) 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]
Close-up studio shot of a white robot toy with LED eyes raised in victory on a gray background.
Photo by Pavel Danilyuk on Pexels

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 (x,y,θ)(x, y, \theta) 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 (2.0,2.0)(2.0, 2.0):

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:

  1. QoS mismatch: The publisher uses best_effort reliability, but your subscriber (the echo command) defaults to reliable. Add --qos-reliability best_effort to match.
  2. Latched topics: Some topics only publish once (e.g., a static map). By the time you run echo, the message already passed. Use ros2 topic echo --qos-durability transient_local to receive the last published message.
  3. 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 alive
  • ros2 topic echo --once — quick message check
  • ros2 topic hz — catch rate issues
  • ros2 node info — map node interfaces
  • ros2 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 coffee
TODAY 746 | TOTAL 128,955