WendyOS Docs
Robotics

Wendy for ROS 2

Inspect and debug live ROS 2 systems on a WendyOS device from the CLI, with no SSH. Nodes, topics, services, parameters, actions, lifecycle nodes, components, and rosbags.

wendy device ros2 brings the full ros2 command-line experience to a remote device. List nodes and topics, echo messages, watch publish rates, render the connectivity graph, read and set parameters, drive actions and lifecycle nodes, and record rosbags, all from your machine, over the same secure connection the CLI already uses.

Standard, upstream ROS 2. WendyOS runs real ROS 2 from stock containers, Humble by default, configurable per app. Choose your middleware with frameworks.ros2.rmw: CycloneDDS (default), Fast DDS, RTI Connext, or GurumDDS.

How it works

The agent discovers ROS 2 app containers (those deployed with a frameworks.ros2 config in wendy.json) and starts a CLI sidecar in the same DDS domain. Your ros2 commands run inside that sidecar over gRPC.

ROS 2 discovery is app-local by default: Wendy injects ROS_LOCALHOST_ONLY=1 so unrelated apps and robots do not discover each other. A bridge or inspection tool that intentionally needs the device's wider ROS 2 graph can opt in with "discoveryScope": "host" in frameworks.ros2; pair it with a host-network entitlement so DDS can reach the device interfaces.

No SSH, no source /opt/ros/<distro>/setup.bash, and no extra ports. If a device runs apps across multiple RMW implementations (for example CycloneDDS and Fast DDS), results are tagged with the RMW they came from, such as [cyclonedds].

Scaffold a ROS 2 app

wendy init writes the frameworks.ros2 block for you. Pass --framework ros2, plus any of the --ros2-* flags to override the defaults:

wendy init \
  --app-id my-ros2-app \
  --target wendyos \
  --language swift \
  --framework ros2 \
  --ros2-rmw cyclonedds \
  --ros2-discovery-scope host \
  --assistant skip

Any --ros2-* flag on its own implies --framework ros2, and values are validated up front, so a mistyped RMW or distro fails at init rather than at deploy time. Run wendy init interactively on a WendyOS target and it asks whether the app uses ROS 2, then walks through middleware, discovery scope, and domain ID.

Existing projects need no scaffolding — add the frameworks.ros2 key to wendy.json by hand and wendy run picks it up on the next deploy. See wendy.json for every field.

Prerequisites

  • A ROS 2 app running on the device. See Multi-app deployments for a complete talker/listener stack and the host-networking entitlement DDS discovery needs.
  • A device selected as your default (or pass --device). See Discovering devices.

Every subcommand accepts --domain to override the ROS_DOMAIN_ID. By default it is read from the app's ROS 2 config, so you rarely need to set it. That includes auto-derived domains: an app whose frameworks.ros2 omits domainId gets a stable domain hashed from its appId (in the 0 to 232 range), and the CLI follows it automatically. Every subcommand also honors the global --json flag for machine-readable output.

Explore the graph

List what's running and how it's connected:

# Running nodes
wendy device ros2 nodes

# Topics (add --all for publisher/subscriber counts)
wendy device ros2 topics
wendy device ros2 topics --all

# Type, endpoints, and QoS for a single topic
wendy device ros2 topic info /chatter

# Services
wendy device ros2 services

Render the node/topic connectivity graph as ASCII, or as Graphviz dot to pipe into your own tooling:

wendy device ros2 graph
wendy device ros2 graph --format dot

Watch live data

Stream deserialized messages from a topic, optionally stopping after a fixed count:

# Stream until ctrl-c
wendy device ros2 echo /chatter

# Stop after 10 messages
wendy device ros2 echo /chatter --count 10

Monitor a topic's publish rate:

wendy device ros2 hz /chatter

Parameters

Read parameters across the whole system or a single node, and change them live, no restart required:

# List all parameters (or just one node's)
wendy device ros2 params
wendy device ros2 params --node /talker

# Get and set a single parameter
wendy device ros2 param get /talker use_sim_time
wendy device ros2 param set /talker use_sim_time true

Call a service

wendy device ros2 call /reset std_srvs/srv/Empty

Pass a request payload as the optional third argument when the service type needs one.

Actions

List action servers, inspect one, and send goals with live feedback:

wendy device ros2 action list
wendy device ros2 action info /navigate

# Send a goal; add --feedback to stream feedback while it runs
wendy device ros2 action send_goal /navigate nav2_msgs/action/NavigateToPose "{pose: ...}" --feedback

Cancel all in-flight goals on an action server (a Wendy extension; the upstream ros2 action CLI has no cancel verb):

wendy device ros2 action cancel /navigate

Lifecycle nodes

Inspect and drive managed (lifecycle) nodes through their state machine:

# Lifecycle nodes on the system
wendy device ros2 lifecycle nodes

# Current state and available transitions for one node
wendy device ros2 lifecycle get /lifecycle_talker
wendy device ros2 lifecycle list /lifecycle_talker

# Trigger a transition (configure, activate, deactivate, cleanup, shutdown)
wendy device ros2 lifecycle set /lifecycle_talker configure

Components

Manage composable nodes in a running component container:

wendy device ros2 component list
wendy device ros2 component load /ComponentManager composition composition::Talker
wendy device ros2 component unload /ComponentManager 1

Record rosbags

Record topics to a bag on the device, list what's been recorded, and pull a bag back to your machine:

# Record specific topics (ctrl-c to stop and finalize)
wendy device ros2 bag record /camera/image_raw /imu

# Optionally name the bag (defaults to an auto-named, timestamped bag)
wendy device ros2 bag record /scan --output drive-test

# List bags on the device
wendy device ros2 bag list

# Download a bag to a local directory
wendy device ros2 bag download drive-test ./local-bags

Run bag download with no arguments to pick from the device's bags interactively. On a device running apps across multiple RMW implementations, recording all topics captures one RMW's graph and warns about the others; record explicit topic lists per RMW if you need both.

Health checks

Run ros2 doctor against the device's ROS 2 environment:

wendy device ros2 doctor

Anything else

For any ros2 subcommand not wrapped above, use the raw passthrough. Flags meant for Wendy (like --domain) go before the ros2 command word; everything after is handed straight to ros2:

wendy device ros2 exec topic echo /chatter --once
wendy device ros2 --domain 42 exec node info /talker

Visualize in Foxglove

To see this data in real time on plots and panels, bridge the device's topics into Foxglove Studio with Wendy for Foxglove.

On this page