ROS Ecosystem
Orchestrate ROS 2, Nav2, MoveIt 2 and ros2_control by delegating to the real
ros2 CLI of your installed distro. Caasi never imports rclpy and never
speaks DDS itself — it finds your distro, builds ros2 command lines, and turns every
long-lived launch into a tracked run.
Distro discovery
Every command on this page resolves the distro the same way:
ROS_DISTROenvironment variable →/opt/ros/$ROS_DISTRO;- otherwise, scan
/opt/rosfor a subdirectory containingsetup.bash; - the
ros2binary:<distro>/bin/ros2first, thenros2onPATH.
You do not need to source setup.bash before using Caasi — the
distro is located directly. When no ros2 binary can be found, commands fail with:
shellcaasi ros list topics
Error: No ROS 2 installation found (no ros2 CLI). Install ROS 2 or set ROS_DISTRO — see 'caasi setup ros2'.
caasi ros
caasi ros status
caasi ros status [--json]
The one-screen ROS overview: distro, root, binary, RMW implementation and how many topics are
currently live (a real ros2 topic list call — proves the graph works, not just that
files exist). Never fails: “not found” is reported as data.
shellcaasi ros status
ROS 2
Distro jazzy
Root /opt/ros/jazzy
Binary /opt/ros/jazzy/bin/ros2
RMW (default)
Topics 2
caasi ros status --json
{ "available": true, "distro": "jazzy", "root": "/opt/ros/jazzy",
"binary": "/opt/ros/jazzy/bin/ros2", "rmw": null, "topics": 2 }
caasi ros doctor
caasi ros doctor [--json]
Runs ros2 doctor (60 s timeout) and mirrors its output and exit code — the real
health check of your middleware, network and distro setup. JSON mode:
{"returncode": 0, "output": "…full report…"}.
caasi ros list
caasi ros list KIND [--json] # KIND: topics | nodes | services | actions
Thin, uniform wrapper over ros2 topic|node|service|action list:
shellcaasi ros list topics
Topics
/parameter_events
/rosout
/scan
/tf
caasi ros list nodes --json
["/talker", "/listener"]
caasi ros list topicz
Error: Unknown kind 'topicz'. Valid kinds: topics, nodes, services, actions.
JSON is the raw name array. Empty lists print a “no …” hint, exit 0; missing
ros2 exits 1.
caasi ros launch
caasi ros launch TARGET [--package|-p PKG] [--name NAME] [--dry-run] [--json] [-- LAUNCH_ARGS…]
| Parameter | Kind | Type | Default | Description |
|---|---|---|---|---|
TARGET | argument | str | required | Launch file path, or (with --package) the launch file name inside a package. |
--package | option (-p) | str | — | Launch from an installed package: ros2 launch <pkg> <target>. |
--name | option | str | target stem | Run name for the tracked run. |
--dry-run | option | flag | off | Show the command without starting. |
--json | option | flag | off | Print the run record. |
| trailing args | pass-through | Appended verbatim (e.g. use_sim_time:=true). |
The launch becomes a tracked run (backend: ros, kind: ros) — detached,
logged, stoppable, surviving your terminal. A path-like target that doesn't exist fails early:
Error: Launch file not found: <path>.
shellcaasi ros launch demo.launch.py -p demo_bringup --dry-run
Dry run — nothing was started:
command: /opt/ros/jazzy/bin/ros2 launch demo_bringup demo.launch.py
caasi ros launch demo.launch.py -p demo_bringup use_sim_time:=true
Run 20260905-190411-demo-launch started in the background.
Follow it with: caasi logs 20260905-190411-demo-launch -f
caasi run stop latest
caasi ros topic
caasi ros topic NAME [--echo] [--dry-run] [--json] [-- ECHO_ARGS…]
Two modes in one command:
- info (default): runs
ros2 topic info NAME— type, publisher and subscriber counts. Unknown topic →Error: Topic '/nope' not found (is the graph up?).exit 1. JSON:{"topic": "/scan", "info": "Type: sensor_msgs/msg/LaserScan\n…"}. - echo (
--echo): streaming would block forever, so it becomes a tracked run (kind: ros) namedecho-<topic>. Read the stream withcaasi logs, end it withcaasi run stop.
shellcaasi ros topic /scan
Type: sensor_msgs/msg/LaserScan
Publisher count: 1
Subscription count: 0
caasi ros topic /scan --echo
Run 20260905-191022-echo-scan started in the background.
caasi logs echo-scan -n 4
---
header:
stamp: {sec: 1757070622, nanosec: 412}
frame_id: laser_frame
range_min: 0.12
caasi run stop echo-scan
caasi ros node
caasi ros node NAME [--json]
Wraps ros2 node info NAME — subscribers, publishers, service clients/servers.
Unknown node → Error: Node '/nope' not found (is the graph up?). exit 1.
JSON: {"node": "/talker", "info": "…"}.
caasi ros graph
caasi ros graph [--json]
Quick whole-graph snapshot — all nodes and all topics in one view:
shellcaasi ros graph
ROS Graph
Nodes (2)
/listener
/talker
Topics (4)
/parameter_events
/rosout
/scan
/tf
caasi ros graph --json | jq '.nodes'
["/listener", "/talker"]
caasi nav — Nav2
Nav2 orchestration on top of the same delegation: Caasi checks that
nav2_bringup is installed (via ros2 pkg prefix nav2_bringup), starts the
standard bringup, and tells you whether the navigation stack is actually up — by looking for its
nodes in the live graph.
caasi nav status
caasi nav status [--json]
Reports the bringup install prefix and which Nav2 nodes are currently running. Recognized
nodes: bt_navigator, planner_server, controller_server,
behavior_server, recoveries_server, smoother_server,
waypoint_follower, amcl, velocity_smoother.
shellcaasi nav status
Nav2
Bringup /opt/ros/jazzy
Nodes /bt_navigator, /planner_server, /controller_server, /amcl
caasi nav status --json
{ "installed": true, "bringup": "/opt/ros/jazzy",
"nodes": ["/bt_navigator", "/planner_server", "/controller_server", "/amcl"] }
caasi nav launch
caasi nav launch [--params FILE] [--map FILE] [--dry-run] [--json] [-- LAUNCH_ARGS…]
| Option | Type | Default | Description |
|---|---|---|---|
--params | path | — | Params file → launch arg params_file:=<file>. |
--map | path | — | Map file → launch arg map:=<file>. |
--dry-run | flag | off | Show the command without starting. |
--json | flag | off | Print the run record. |
Starts ros2 launch nav2_bringup bringup_launch.py [map:=…] [params_file:=…] as a
tracked run named nav2-bringup (kind: nav). Requires
nav2_bringup to be installed:
shellcaasi nav launch --map maps/warehouse.yaml --dry-run
Dry run — nothing was started:
command: /opt/ros/jazzy/bin/ros2 launch nav2_bringup bringup_launch.py map:=maps/warehouse.yaml
caasi nav launch --map maps/warehouse.yaml --params my_nav2_params.yaml
Run 20260905-192233-nav2-bringup started in the background.
caasi logs nav2-bringup -f
# …wait for "[INFO] [bt_navigator]: bt_navigator started"…
Without Nav2: Error: Nav2 is not installed (no 'nav2_bringup' package). Install it
(e.g. sudo apt install ros-jazzy-navigation2 ros-jazzy-nav2-bringup) and try again.
caasi nav inspect
caasi nav inspect [PARAMS_FILE] [--json]
Lists the nodes configured in a Nav2 params file. With no argument, the distro default is
used: <bringup prefix>/share/nav2_bringup/params/nav2_params.yaml. Nav2 params
files are keyed by node name at the top level, so “which nodes will this bring up?” is one
yaml.safe_load away:
shellcaasi nav inspect
Nav2
Params /opt/ros/jazzy/share/nav2_bringup/params/nav2_params.yaml
Nodes 14
amcl
behavior_server
bt_navigator
controller_server
planner_server
…
caasi nav inspect my_params.yaml --json
{ "path": "my_params.yaml", "nodes": ["amcl", "bt_navigator", "planner_server"] }
Missing file → Error: Nav2 params file not found: <path> (exit 1).
caasi nav test
caasi nav test [--json]
Readiness gate with three checks — ros2 binary, nav2_bringup package,
running Nav2 nodes — and an exit code you can script against:
shellcaasi nav test
✓ ros2 /opt/ros/jazzy/bin/ros2
✓ nav2_bringup /opt/ros/jazzy
✓ nodes /bt_navigator, /planner_server, /controller_server, /amcl
Nav2 is ready.
caasi nav test --json | jq '.ok'
true
JSON: {"ok": bool, "checks": [{"check", "ok", "detail"}, …]}. Exit
0 when all checks pass, 1 otherwise.
caasi moveit — MoveIt 2
Same pattern for manipulation: locate moveit_ros_move_group, launch your MoveIt
config, and verify the move_group node is up. Planning always happens inside MoveIt 2.
caasi moveit status
caasi moveit status [--json]
shellcaasi moveit status
MoveIt 2
Package /opt/ros/jazzy
move_group /move_group
caasi moveit status --json
{ "installed": true, "package": "/opt/ros/jazzy",
"move_group_nodes": ["/move_group"] }
Node detection works even when the package prefix lookup is unavailable — status answers
“is move_group running right now?” from the live graph.
caasi moveit launch
caasi moveit launch TARGET [--package|-p PKG] [--name NAME] [--dry-run] [--json] [-- LAUNCH_ARGS…]
Identical semantics to ros launch (path check, pass-through args, tracked run —
kind: moveit), pointed at your MoveIt config's demo launch:
shellcaasi moveit launch demo.launch.py -p panda_moveit_config
Run 20260905-193312-demo-launch started in the background.
Follow it with: caasi logs 20260905-193312-demo-launch -f
caasi moveit plan
caasi moveit plan [--group|-g NAME] [--json]
Answers “can I plan right now?” — i.e. is a move_group node in the graph? The
optional --group records which planning group you care about. Exit 0
ready / 1 not ready:
shellcaasi moveit plan --group panda_arm
move_group is up — planning available (group: panda_arm)
caasi moveit plan --json
{ "ready": true, "group": null, "move_group_nodes": ["/move_group"] }
caasi moveit plan; echo $?
Error: move_group node is not running. Launch your MoveIt config first (caasi moveit launch …).
1
caasi moveit test
caasi moveit test [--json]
Three-check readiness gate like nav test: ros2 binary,
moveit_ros_move_group package, live move_group node.
JSON {"ok", "checks"}, exit 0/1.
caasi control — ros2_control
Controller management via ros2 control (the ros2controlcli package),
plus offline validation of controller YAML — the #1 source of “why won't my hardware interface
load”.
caasi control status
caasi control status [--json]
shellcaasi control status
ros2_control
Package /opt/ros/jazzy
Controller managers /controller_manager
caasi control status --json
{ "installed": true, "package": "/opt/ros/jazzy",
"managers": ["/controller_manager"] }
managers are the live graph nodes containing controller_manager —
i.e. the robots/hardware interfaces currently serving controllers.
caasi control list
caasi control list [--json]
Runs ros2 control list_controllers and passes the output through:
shellcaasi control list
joint_state_broadcaster joint_state_broadcaster/JointStateBroadcaster active
diff_drive_controller diff_drive_controller/DiffDriveController active
caasi control list --json
["joint_state_broadcaster joint_state_broadcaster/JointStateBroadcaster active", …]
Failure (typically ros2controlcli not installed, or no manager reachable) →
Error: ros2_control CLI is not available (is 'ros2controlcli' installed?). exit 1.
caasi control check
caasi control check PARAMS_FILE [--json]
Static validation of a controller params YAML, offline — no ROS needed. It verifies:
- the file parses and its top level is a mapping;
- a
controller_manager:node with aros__parameters:block exists; update_rateis set on the controller manager;- every controller entry (dict-valued key under
ros__parameters) declares atype.
controllers.yamlcontroller_manager:
ros__parameters:
update_rate: 100
joint_state_broadcaster:
type: joint_state_broadcaster/JointStateBroadcaster
diff_drive_controller:
type: diff_drive_controller/DiffDriveController
shellcaasi control check controllers.yaml
✓ joint_state_broadcaster
✓ diff_drive_controller
Controller config looks good (2 controller(s)).
caasi control check broken.yaml --json
{
"path": "broken.yaml",
"controllers": ["diff_drive_controller", "broken_controller"],
"issues": [
"controller_manager.ros__parameters has no 'update_rate'",
"controller 'broken_controller' has no 'type'"
],
"ok": false
}
exit code: 1
Missing argument → Error: Pass a controller params YAML file…; missing file →
params-not-found error; exit 0 clean / 1 any issue (both modes).
The shared pattern
| You want… | Use |
|---|---|
| “what's on the graph?” | ros status · ros graph · ros list … |
| “start something long-lived” | ros launch · nav launch · moveit launch · ros topic --echo → all become tracked runs |
| “is the stack ready?” (scriptable) | nav test · moveit test · moveit plan · control check → exit 0/1 + --json |
| “why is my config broken?” | nav inspect · control check · ros doctor |
| anything else ROS | caasi native ros … — raw ros2 pass-through |