fastdds_transport_viz¶
Shows which Fast DDS transport each ROS 2 topic is communicated over — UDPv4, UDPv6, TCP, shared memory (SHM) or zero-copy data-sharing — and why.
All distros below use rmw_fastrtps_cpp (rmw_fastrtps_dynamic_cpp works the same):
| ROS 2 distro | Fast DDS | Notes |
|---|---|---|
| Humble | 2.6 | Prediction only — the binary has no statistics module |
| Jazzy | 2.14 | Prediction + --stats measurement |
| Lyrical | 3.6 | Prediction + --stats measurement |
| Rolling | 3.x (head) | Tracks Fast DDS main; best-effort in CI, not a required check |
Source and issues: github.com/atinfinity/fastdds_transport_viz.
$ ros2 transport list -v --stats --topic '^/(chatter|bounded)$'
TOPIC TYPE PUBS SUBS TRANSPORT LATENCY HZ LOSS REASON
/bounded std_msgs/msg/Int32 1 1 DATA_SHARING x1 108 µs 0 same-host-guid,datasharing-qos-enabled-both,datasharing-domain-ids-match,datasharing-confirmed-no-data-submessages
/bounded_pub@ba8b86aa803d(688) -> /bounded_sub@ba8b86aa803d(690) DATA_SHARING 108 µs (max 155 µs) 10.0 0 measured=SHM (unmeasured, delivered) same-host-guid,datasharing-qos-enabled-both,datasharing-domain-ids-match,datasharing-confirmed-no-data-submessages
/chatter std_msgs/msg/String 1 2 UDPv4 x1, SHM x1 217 µs 0 same-host-guid,datasharing-disabled-writer,reader-no-shm-locator,common-udpv4-locator,measured-udpv4-traffic,both-shm-locators,measured-shm-traffic
/talker@ba8b86aa803d(691) -> /listener_udp@ba8b86aa803d(689) UDPv4 185 µs (max 239 µs) 1.0 0 measured=UDPv4 9pkt 1.19 kB same-host-guid,datasharing-disabled-writer,reader-no-shm-locator,common-udpv4-locator,measured-udpv4-traffic
/talker@ba8b86aa803d(691) -> /listener@ba8b86aa803d(692) SHM 217 µs (max 254 µs) 1.0 0 measured=SHM 10pkt 1.31 kB same-host-guid,datasharing-disabled-writer,both-shm-locators,measured-shm-traffic
statistics: 448 samples from 5 participant(s)
shared memory: /dev/shm 37.4 MB used of 16.7 GB (16.6 GB free) | Fast DDS 3.90 MB in 6 segment(s), 11 port(s), 1 data-sharing history, 1 data-sharing notification(s)
The same capture on a terminal (--color auto, default when stdout is a terminal):
The same run opened in the web viewer (table view):

- The prediction comes from Fast DDS discovery data (announced locators and QoS) and needs nothing from the observed nodes.
- With
--stats, the measurement comes from the Fast DDS statistics module and shows the transport that actually carried packets. - Every verdict carries reason codes;
--explaindescribes them.
Features¶
- Transport per pair, from discovery alone. Every writer → reader pair gets a
predicted transport (
UDPv4,UDPv6,TCPv4/TCPv6,SHM,DATA_SHARING) with machine-readable reason codes; the observed nodes need no change. Pairs whose QoS do not match (reliability, durability, deadline, liveliness, ownership, partition) are shown asNONEwith the policy that breaks them. - Measurement with
--stats. The Fast DDS statistics module supplies the packets and bytes that actually flowed per locator, the write-to-notification latency (LATENCY), the delivered samples per second of each pair (HZ), lost and resent packets (LOSS), host names and process ids, and the proof of zero-copy data-sharing; a measurement that contradicts the prediction is flagged. - Several front-ends. A table with colors,
--watch(live terminal view that marks what changed),--jsonwith a published schema, theros2 transportcommand, and a web viewer (graph and table, live updates throughtransport_viz_webwith a timeline of the frames received so far, and recordings made withtransport_viz_web --recordreplayed on the same timeline).transport_viz_webalso serves the latest document as Prometheus metrics on/metrics. - Focus.
--topic/--noderegex filters,--explainfor the codes in use,--advisefor what to change to get past them,ros2 transport codesfor all of them. - Shared memory of the environment. Capacity of
/dev/shm, the Fast DDS segments, ports and data-sharing histories in it, stale leftovers, and whether the observed nodes share it at all. - Verified on Jazzy (Fast DDS 2.14) and Lyrical / Rolling (Fast DDS 3.x), x86_64 and
arm64, with Discovery Server,
LARGE_DATA(TCP),UDPv6,LOCALHOSTdiscovery range, large SHM samples, zero-copy data-sharing, and two physical hosts (x86_64 ↔ Jetson Orin NX over Wi-Fi, prediction and measurement in both directions).
Quick start¶
docker compose build
docker compose run --rm dev bash
colcon build --symlink-install && source build/$ROS_DISTRO/install/setup.bash
ros2 run demo_nodes_cpp talker &
ros2 run demo_nodes_cpp listener &
ros2 transport list -v --explain
Run the tool in the same environment (env vars, XML profile, network/IPC namespace) as the nodes you observe.
On a Linux host, releases from 2.1.0 on also run without a build, from the image on GHCR
(:humble, :jazzy, :lyrical; see Getting started):
docker run --rm --net host --ipc host ghcr.io/atinfinity/fastdds_transport_viz:jazzy ros2 transport list -v.
Usage¶
ros2 transport list [--domain N] [--timeout S] [--quiet S] [--topic REGEX] [--node REGEX]
[--all] [-v] [--explain] [--locators] [--advise] [--stats] [--json | --csv]
[--color auto|always|never] [--watch [--interval S]]
ros2 transport diff BEFORE.json AFTER.json [--key node|guid] [--changes-only] [--json]
[--topic REGEX] [--node REGEX] [--all] [-v] [--explain] [--locators]
[--advise] [--color auto|always|never]
ros2 transport codes
ros2 transport is a thin ros2cli extension (package ros2transport) that runs the
transport_viz binary of fastdds_transport_viz; the binary can also be run directly as
ros2 run fastdds_transport_viz transport_viz, with the same options plus --list-codes
(and transport_viz diff for ros2 transport diff).
| Option | Effect |
|---|---|
-v |
expand writer → reader pairs under each topic |
--explain |
append a legend for the reason codes used |
--locators |
add a line under each pair with the locator the tool selected and the locators that actually carried packets (implies -v; ignored with --json, which always carries them) |
--advise |
add a fix <code>: … line under each pair for its reason codes that have a remedy, and the remedy under each code of the legend (implies -v and --explain; ignored with --json, which always carries them as reason_code_remedies) |
--stats |
also show measured transports, latency and loss; observed nodes need FASTDDS_STATISTICS, see Measured transports |
--json |
machine-readable output (schema_version: 1); open it in the web viewer |
--csv |
one CSV row per writer → reader pair (RFC 4180 quoting, LF line ends, a header line first; an empty cell where the JSON value is null, lists joined with ;), for a spreadsheet or pandas; exclusive with --json, not accepted by diff. With --watch the header is printed once and each frame adds its rows, observed_at telling the frames apart |
--topic REGEX |
only topics whose name matches |
--node REGEX |
only pairs involving a node whose full name matches (its unpaired endpoints stay visible) |
--all |
include services/actions and non-ROS DDS topics; each service or action is one SERVICE / ACTION row per client-server pair rather than its raw rq/ / rr/ topics |
--watch |
re-render every --interval seconds, highlighting added/changed/removed pairs; keys q p v e a l f (with --json: JSON Lines with a changes object) |
--color |
ANSI colors for transports and warnings (auto = only on a terminal) |
ros2 transport diff BEFORE.json AFTER.json compares two saved --json documents (change
a profile or an environment variable, run again, see what moved) without observing
anything: the after snapshot is printed with the pairs that were added (+), changed (~)
or removed (-) marked as in --watch, or with --json as the after document plus a
changes object. Pairs are matched by node names (--key node, the default, so a restart
of the nodes is not a change) or by GUIDs (--key guid, what --watch does);
--changes-only keeps only the topics that moved. The exit status is 0 without changes, 1
with, 2 on an error, so it works in scripts. The web viewer compares two documents the same
way and highlights the result. Details in
How it works.
Documentation¶
- Getting started — build (native or Docker), first run,
--stats, watch mode, web viewer, first checks - How it works — decision rules, reason codes, hosts and addresses, where to run it, watch mode
- Measured transports (
--stats) — statistics topics, enabling them, the 10-instance pitfall - Data-sharing (zero-copy) — why ROS 2 topics show
SHMby default and how to enable data-sharing - Web viewer — graph view and a topic-grouped table of
--jsonoutput in the browser, live mode (transport_viz_web) and its history, recording and replay (--record), Prometheus/metrics, JSON schema - Architecture — components, the flow of one run, data model, Fast DDS 2.14/3.x layer, extension points
- Development, verification and tests — Docker environment, packages, verification nodes, multi-container scenarios, tests, scale harness, release procedure, roadmap
- Verification log — dated scale results and verification runs
Limitations¶
- Fast DDS RMWs only.
rmw_fastrtps_cppandrmw_fastrtps_dynamic_cppare supported (the launch test suite passes on both, see CI); nodes on CycloneDDS or Connext are not covered, and Fast DDS participants that are not ROS nodes appear only with--all(Discovery Servers, which have no endpoints, only in theparticipantssection of--json, the-vfooter and the web viewer). The tool refuses to start on another RMW (exit 1, naming it). - Linux only. macOS has no
/dev/shm, and Docker Desktop cannot observe nodes on the host. - Run it where the nodes run. Same domain, same environment variables and XML profile,
same network and IPC namespace.
ROS_AUTOMATIC_DISCOVERY_RANGE=OFFhides everything. - Type hashes need ROS 2 Jazzy or later. A writer and a reader whose type names
differ are shown as
NONEwithtype-name-mismatch, except on Fast DDS 3.x (Lyrical and later) when both announce an XTypesTypeInformationthat agrees: Fast DDS then matches them regardless of the names, and the pair carriestype-names-differ-same-type(#213). Two versions of the same message definition are told apart by the ROS 2 type hash (REP-2011), which only the rmw of Jazzy and later announces: on Humble such a pair looks healthy, and the subscription still receives nothing. Fast DDS's own, older type description cannot stand in for it — measured on 2026-09-21, no Humble endpoint announces aTypeIdentifier, aTypeObjector aTypeInformationeither, becausermw_fastrtpsregisters no type in theTypeObjectFactorythose are filled from (Fast DDS 2.14, and so Jazzy, announces them just as little; seedocs/verification-log.md). On Humble, rebuild and reinstall every node against the same version of the message package, and, if a machine with Jazzy or later is available, run the same graph there, where the tool does report the mismatch. - A prediction is a model. The verdicts encode Fast DDS's selection rules; some
situations stay
likely(marked?) until--statsconfirms them. Measuring requiresFASTDDS_STATISTICSon the observed nodes before they start, and the shipped profile when a node talks to more than 10 locators. - Statistics are per participant (one per ROS node), so several topics between the same two nodes share one measurement.
- Not a benchmark.
LATENCYis Fast DDS's ownHISTORY_LATENCYstatistic (write-to-notification between the two histories), sampled during a short observation; it does not replace a load test or an end-to-end measurement, and across hosts it includes the clock offset.HZcounts the samples that reached each reader (#143); there is no writer-side publish rate:PUBLICATION_THROUGHPUTlooked like one but is not (#137). - DDS Security (SROS2) is not supported and untested: the tool's participants carry no security configuration, so participants inside a secure enclave are not discovered.
- Footprint. The tool adds two participants of its own to the domain, three on Humble
(
fastdds_transport_viz_names, a participant without SHM that reads the node names); all are filtered from the output. - Split shared memory. Nodes with the same host id in different IPC namespaces
(
network_mode: hostwithoutipc: host) still select SHM or data-sharing between each other and lose every message. The pair isNONEwithshm-ipc-namespace-splitwhen the tool can tell: the two announce the same SHM port number (shm-port-collision, the usual case with one node per container), or the tool shares the IPC namespace of one of them (their SHM ports or data-sharing segments are only half there). Otherwise the pair staysSHMorDATA_SHARINGand onlyshm-not-visiblein the shared-memory line hints at it (#101, #110). - Native-buffer companions. On Lyrical and later
rmw_fastrtps_cppsends the samples of types with an unboundeduint8[]field over a companion topic<topic>/_buf_cpu. The tool adds the companion's counters to the parent pair (buffer-companion-folded) and shows the companion topic only with--all; a companion it cannot link to its parent stays visible withbuffer-companion-unmatched, and its parent pair then shows no traffic of its own (#119).
Quality declaration¶
Both packages claim REP 2004 Quality Level 3,
with one exception: Linux only, so Windows 10 (a tier 1 platform of REP 2000) is not
supported. See the quality declarations of
fastdds_transport_viz and
ros2transport for the version policy and
public API, change control, testing, dependencies and platforms, and
SECURITY.md to report a vulnerability.
License¶
Apache-2.0