# ros-physical-ai/demos architecture

> Architecture diagram of the GitHub repository ros-physical-ai/demos, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-29). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/ros-physical-ai/demos
- Repository: https://github.com/ros-physical-ai/demos

## Overview

ROS Physical AI Demos provides ROS 2 SO-ARM101 robot demos across Gazebo, MuJoCo, and physical hardware, plus a LeRobot-based Record → Train → Deploy workflow. An operator brings up a robot, chooses a teleoperation or inference input, and sends commands through ROS control to the arm. Demonstration collection feeds the learning workflow; visualization and optional MCP access support inspection and control. The README documents several capabilities whose implementations are external or not sampled here, so those are represented at subsystem level; edges reflect documented launch and topic relationships rather than inferred internal calls.

Main entry points: [`pai_bringup/config/control/ros2_controllers.yaml`](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/config/control/ros2_controllers.yaml) (ROS control), [`pai_bringup/launch/so_arm_gz_bringup.launch.py`](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/so_arm_gz_bringup.launch.py) (Robot bringup), [`pai_data_collection/config/rosetta`](https://github.com/ros-physical-ai/demos/tree/main/pai_data_collection/config/rosetta) (Rosetta bridge), [`pai_rerun_visualizer/pai_rerun_visualizer/visualizer_node.py`](https://github.com/ros-physical-ai/demos/blob/main/pai_rerun_visualizer/pai_rerun_visualizer/visualizer_node.py) (Rerun visualizer)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_robot_runtime["Robot runtime"]
  node_robot_bringup["Robot bringup"]
  node_common_bringup["Common bringup"]
  node_description_world["Robot and scene<br/>[so_arm_table.sdf]"]
  node_simulators["Gazebo / MuJoCo"]
  node_real_hardware["Physical arm"]
  node_ros_control["ROS control"]
  node_camera_stack["Camera stack<br/>[cameras.launch.py]"]
  node_assets["Scene assets"]
end

subgraph group_teleoperation["Teleoperation"]
  node_leader_teleop["Leader teleop"]
  node_leader_relay["Leader command relay"]
  node_phone_adapter["Phone adapter"]
  node_rviz_adapter["RViz marker adapter"]
  node_ik_servo["Cartesian IK servo<br/>[servo_node.py]"]
end

subgraph group_learning["Learning pipeline"]
  node_learning_bridge["Rosetta bridge"]
  node_dataset[("Demonstration dataset")]
  node_lerobot["LeRobot train / policy"]
  node_policy_runner["Policy inference<br/>[policy_runner.yaml]"]
end

subgraph group_inspection["Inspection and access"]
  node_rerun_visualizer["Rerun visualizer<br/>[visualizer_node.py]"]
  node_rosbridge["ROS bridge"]
end

node_operator(("Operator"))
node_phone_user(("Phone user"))
node_mcp_client(("MCP client"))
node_rerun["Rerun viewer"]
node_ros_mcp["ROS-MCP server"]

node_operator -->|"starts"| node_robot_bringup
node_robot_bringup -->|"includes"| node_common_bringup
node_robot_bringup -->|"starts Gazebo"| node_simulators
node_common_bringup -->|"loads description"| node_description_world
node_simulators -->|"loads scene"| node_description_world
node_description_world -->|"references models"| node_assets
node_common_bringup -->|"spawns controllers"| node_ros_control
node_robot_bringup -->|"includes cameras"| node_camera_stack
node_operator -->|"starts"| node_leader_teleop
node_leader_teleop -->|"launches"| node_leader_relay
node_leader_relay -->|"publishes commands"| node_ros_control
node_operator -->|"starts"| node_phone_adapter
node_phone_user -->|"sends WebXR pose"| node_phone_adapter
node_operator -->|"starts"| node_rviz_adapter
node_phone_adapter -->|"publishes target pose"| node_ik_servo
node_rviz_adapter -->|"publishes target pose"| node_ik_servo
node_ik_servo -->|"publishes joint commands"| node_ros_control
node_operator -->|"starts collection"| node_learning_bridge
node_leader_relay -.->|"provides demonstrations"| node_learning_bridge
node_camera_stack -.->|"provides observations"| node_learning_bridge
node_learning_bridge -->|"records episodes"| node_dataset
node_dataset -->|"trains policy"| node_lerobot
node_lerobot -->|"provides trained policy"| node_policy_runner
node_policy_runner -->|"sends actions"| node_ros_control
node_operator -.->|"enables visualization"| node_rerun_visualizer
node_ros_control -->|"publishes robot state"| node_rerun_visualizer
node_camera_stack -->|"publishes images"| node_rerun_visualizer
node_rerun_visualizer -->|"logs visualization"| node_rerun
node_operator -.->|"enables MCP access"| node_rosbridge
node_rosbridge -->|"exposes ROS WebSocket"| node_ros_mcp
node_mcp_client -->|"requests robot access"| node_ros_mcp
node_ros_mcp -->|"accesses ROS"| node_rosbridge

click node_robot_bringup "https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/so_arm_gz_bringup.launch.py"
click node_common_bringup "https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/include/so_arm_common.launch.py"
click node_description_world "https://github.com/ros-physical-ai/demos/blob/main/pai_description/world/so_arm_table.sdf"
click node_simulators "https://github.com/ros-physical-ai/demos/tree/main/pai_bringup/launch"
click node_real_hardware "https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/urdf/so_arm_real.urdf.xacro"
click node_ros_control "https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/config/control/ros2_controllers.yaml"
click node_camera_stack "https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/include/cameras.launch.py"
click node_assets "https://github.com/ros-physical-ai/demos/tree/main/pai_assets/models"
click node_leader_teleop "https://github.com/ros-physical-ai/demos/blob/main/pai_leader_teleop/launch/leader_bringup.launch.py"
click node_leader_relay "https://github.com/ros-physical-ai/demos/blob/main/pai_leader_teleop/scripts/leader_teleop_node"
click node_phone_adapter "https://github.com/ros-physical-ai/demos/blob/main/pai_phone_teleop/pai_phone_teleop/phone_teleop_node.py"
click node_rviz_adapter "https://github.com/ros-physical-ai/demos/blob/main/pai_rviz_teleop/launch/interactive_ik.launch.py"
click node_ik_servo "https://github.com/ros-physical-ai/demos/blob/main/pai_teleop_ik/pai_teleop_ik/servo_node.py"
click node_learning_bridge "https://github.com/ros-physical-ai/demos/tree/main/pai_data_collection/config/rosetta"
click node_policy_runner "https://github.com/ros-physical-ai/demos/blob/main/pai_data_collection/config/rosetta/policy_runner.yaml"
click node_rerun_visualizer "https://github.com/ros-physical-ai/demos/blob/main/pai_rerun_visualizer/pai_rerun_visualizer/visualizer_node.py"
click node_rosbridge "https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/include/so_arm_common.launch.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_robot_bringup,node_common_bringup,node_description_world,node_simulators,node_real_hardware,node_ros_control,node_camera_stack,node_assets,node_phone_user,node_mcp_client,node_rerun toneBlue
class node_leader_teleop,node_leader_relay,node_phone_adapter,node_rviz_adapter,node_ik_servo toneAmber
class node_learning_bridge,node_dataset,node_lerobot,node_policy_runner,node_ros_mcp toneMint
class node_rerun_visualizer,node_rosbridge toneRose
class node_operator toneIndigo
```

## Components

### Robot runtime

- [Robot bringup](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/so_arm_gz_bringup.launch.py): `pai_bringup/launch/so_arm_gz_bringup.launch.py`
- [Common bringup](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/include/so_arm_common.launch.py): `pai_bringup/launch/include/so_arm_common.launch.py`
- [Robot and scene](https://github.com/ros-physical-ai/demos/blob/main/pai_description/world/so_arm_table.sdf): `pai_description/world/so_arm_table.sdf`
- [Gazebo / MuJoCo](https://github.com/ros-physical-ai/demos/tree/main/pai_bringup/launch): `pai_bringup/launch`
- [Physical arm](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/urdf/so_arm_real.urdf.xacro): `pai_bringup/urdf/so_arm_real.urdf.xacro`
- [ROS control](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/config/control/ros2_controllers.yaml): `pai_bringup/config/control/ros2_controllers.yaml`
- [Camera stack](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/include/cameras.launch.py): `pai_bringup/launch/include/cameras.launch.py`
- [Scene assets](https://github.com/ros-physical-ai/demos/tree/main/pai_assets/models): `pai_assets/models`

### Teleoperation

- [Leader teleop](https://github.com/ros-physical-ai/demos/blob/main/pai_leader_teleop/launch/leader_bringup.launch.py): `pai_leader_teleop/launch/leader_bringup.launch.py`
- [Leader command relay](https://github.com/ros-physical-ai/demos/blob/main/pai_leader_teleop/scripts/leader_teleop_node): `pai_leader_teleop/scripts/leader_teleop_node`
- [Phone adapter](https://github.com/ros-physical-ai/demos/blob/main/pai_phone_teleop/pai_phone_teleop/phone_teleop_node.py): `pai_phone_teleop/pai_phone_teleop/phone_teleop_node.py`
- [RViz marker adapter](https://github.com/ros-physical-ai/demos/blob/main/pai_rviz_teleop/launch/interactive_ik.launch.py): `pai_rviz_teleop/launch/interactive_ik.launch.py`
- [Cartesian IK servo](https://github.com/ros-physical-ai/demos/blob/main/pai_teleop_ik/pai_teleop_ik/servo_node.py): `pai_teleop_ik/pai_teleop_ik/servo_node.py`

### Learning pipeline

- [Rosetta bridge](https://github.com/ros-physical-ai/demos/tree/main/pai_data_collection/config/rosetta): `pai_data_collection/config/rosetta`
- **Demonstration dataset**
- **LeRobot train / policy**
- [Policy inference](https://github.com/ros-physical-ai/demos/blob/main/pai_data_collection/config/rosetta/policy_runner.yaml): `pai_data_collection/config/rosetta/policy_runner.yaml`

### Inspection and access

- [Rerun visualizer](https://github.com/ros-physical-ai/demos/blob/main/pai_rerun_visualizer/pai_rerun_visualizer/visualizer_node.py): `pai_rerun_visualizer/pai_rerun_visualizer/visualizer_node.py`
- [ROS bridge](https://github.com/ros-physical-ai/demos/blob/main/pai_bringup/launch/include/so_arm_common.launch.py): `pai_bringup/launch/include/so_arm_common.launch.py`

### Other components

- **Operator**
- **Phone user**
- **MCP client**
- **Rerun viewer**
- **ROS-MCP server**

## Connections

- Operator → Robot bringup: starts
- Robot bringup → Common bringup: includes
- Robot bringup → Gazebo / MuJoCo: starts Gazebo
- Common bringup → Robot and scene: loads description
- Gazebo / MuJoCo → Robot and scene: loads scene
- Robot and scene → Scene assets: references models
- Common bringup → ROS control: spawns controllers
- Robot bringup → Camera stack: includes cameras
- Operator → Leader teleop: starts
- Leader teleop → Leader command relay: launches
- Leader command relay → ROS control: publishes commands
- Operator → Phone adapter: starts
- Phone user → Phone adapter: sends WebXR pose
- Operator → RViz marker adapter: starts
- Phone adapter → Cartesian IK servo: publishes target pose
- RViz marker adapter → Cartesian IK servo: publishes target pose
- Cartesian IK servo → ROS control: publishes joint commands
- Operator → Rosetta bridge: starts collection
- Leader command relay → Rosetta bridge: provides demonstrations
- Camera stack → Rosetta bridge: provides observations
- Rosetta bridge → Demonstration dataset: records episodes
- Demonstration dataset → LeRobot train / policy: trains policy
- LeRobot train / policy → Policy inference: provides trained policy
- Policy inference → ROS control: sends actions
- Operator → Rerun visualizer: enables visualization
- ROS control → Rerun visualizer: publishes robot state
- Camera stack → Rerun visualizer: publishes images
- Rerun visualizer → Rerun viewer: logs visualization
- Operator → ROS bridge: enables MCP access
- ROS bridge → ROS-MCP server: exposes ROS WebSocket
- MCP client → ROS-MCP server: requests robot access
- ROS-MCP server → ROS bridge: accesses ROS
