10. QoS — the most common trap
Important
This is not an advanced topic. It is a leading cause of beginners losing a whole day with perfectly correct code.
The classic symptom: ros2 topic list shows the topic, ros2 node list shows
every node, there is not a single error — and no data reaches anything.
What QoS is
An agreement about how data is delivered. The publisher offers terms; the subscriber requests terms. If they are incompatible the two never connect, and nothing reports it.
The three that break things most often:
Setting |
Options |
Meaning |
|---|---|---|
Reliability |
|
Retry until delivered — nothing may be lost |
|
Send and move on, loss is acceptable — faster |
|
Durability |
|
Late joiners get nothing |
|
The last value is kept for late joiners |
|
History |
|
How many recent messages to hold |
The compatibility rule — remember only this
Warning
🔴 The publisher must offer at least as much as the subscriber requests.
Publisher offers |
Subscriber requests |
Result |
|---|---|---|
|
|
✅ connects |
|
|
✅ connects (offering more than asked) |
|
|
🔴 no connection, complete silence |
|
|
✅ connects |
The red row is the one that actually happens, almost every time, because:
Most sensors publish
BEST_EFFORT(LiDAR, camera, IMU) — data arrives constantly, and a dropped frame is replaced 0.1 s laterThe default for
create_subscriptionisRELIABLE
So a straightforward subscriber listening to /scan receives nothing at all.
How to diagnose — one command
ros2 topic info -v /scan
Type: sensor_msgs/msg/LaserScan
Publisher count: 1
Node name: lidar_node
QoS profile:
Reliability: BEST_EFFORT ← all the publisher offers
Durability: VOLATILE
Subscription count: 1
Node name: my_node
QoS profile:
Reliability: RELIABLE ← subscriber wants more → no connection
Durability: VOLATILE
Tip
-v is the whole point. Without it you see only the publisher and subscriber
counts, which both read 1 — everything looks fine while nothing is connected.
Memorise this command. It saves more time than anything else in this guide.
The fix
Use the profile that matches the kind of data:
from rclpy.qos import qos_profile_sensor_data
self.sub = self.create_subscription(
LaserScan, '/scan', self.on_scan,
qos_profile_sensor_data) # instead of the plain 10
qos_profile_sensor_data is BEST_EFFORT with depth 5 — what sensors publish.
To set it explicitly:
from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy
qos = QoSProfile(
depth=5,
reliability=ReliabilityPolicy.BEST_EFFORT,
durability=DurabilityPolicy.VOLATILE,
)
The nested trap — ros2 topic echo follows the same rule
ros2 topic echo is itself a subscriber, so it can hit the same mismatch.
If echo is silent but RViz shows data, try:
ros2 topic echo /scan --qos-profile sensor_data
Danger
🔴 Never conclude “there is no data” from a silent echo alone.
People have gone as far as replacing a LiDAR cable while the data was flowing perfectly the whole time — their inspection tool simply could not connect.
Always check ros2 topic info -v before concluding anything about the hardware.
TRANSIENT_LOCAL — data sent once
Some topics publish once and then go quiet:
Topic |
Why |
|---|---|
|
The map is sent once when loaded |
|
Sensor positions never change |
With VOLATILE, a node that starts later never receives the map — it missed
the one transmission.
from rclpy.qos import QoSProfile, DurabilityPolicy
qos = QoSProfile(depth=1, durability=DurabilityPolicy.TRANSIENT_LOCAL)
self.sub = self.create_subscription(OccupancyGrid, '/map', self.on_map, qos)
Note
The symptom is “it works if I start things in one order but not the other”, which looks like a timing problem but is really QoS.
What to remember
"Everything looks fine but no data" → ros2 topic info -v first, always
Sensors (LiDAR, camera, IMU) → qos_profile_sensor_data
Map, tf_static → TRANSIENT_LOCAL
Control commands (/cmd_vel) → the default (RELIABLE) is correct
Important
That is the end of Part 1. You should now be able to:
Read a system — what nodes exist, and which topics they use to talk
Write your own nodes that publish and subscribe
Diagnose why data is not arriving, which is what matters most once real hardware is involved
Part 2 starts connecting real hardware, beginning with making the wheels turn.
Previous: 9. RViz · Back to: ROS 2 for Mobile Robots