Hardware ROS 2 Graph

Launch command:

ros2 launch bringup robot.launch.py use_sim:=false
# optional: controller_type:=force_feedback hardware_check:=true

Complete ROS 2 graph

        flowchart TB
    classDef node fill:#e8f4fc,stroke:#0b6e99,stroke-width:1.5px
    classDef hw fill:#fce4ec,stroke:#c62828,stroke-width:1.5px
    classDef ctrl fill:#e8f5e9,stroke:#2e7d32,stroke-width:1.5px
    classDef infra fill:#f3e5f5,stroke:#6a1b9a,stroke-width:1.5px
    classDef topic fill:#fafafa,stroke:#757575,stroke-width:1px,font-size:11px
    classDef absent fill:#f5f5f5,stroke:#bdbdbd,stroke-width:1px,stroke-dasharray:4 4

    subgraph lane1["Lane 1 · Arm control loop"]
        direction LR
        CTRL["admittance / force_feedback<br/><i>control</i>"]:::ctrl
        T_TRAJ["/position_trajectory_controller/joint_trajectory"]:::topic
        PTC["position_trajectory_controller"]:::ctrl
        CM["controller_manager<br/><i>dynamixel_hardware</i>"]:::hw
        DX["Dynamixel XL430<br/>Joint_1 · Joint_2"]:::hw
        JSB["joint_state_broadcaster"]:::infra
        T_JS["/joint_states"]:::topic
        CTRL --> T_TRAJ --> PTC --> CM <-->|pos / fbk| DX
        CM --> JSB --> T_JS --> CTRL
    end

    subgraph lane2["Lane 2 · Tension sensing"]
        direction LR
        HX["HX711 load cell"]:::hw
        LC["load_cell_node<br/><i>hardware</i>"]:::node
        T_TEN["/fishing_arm/tension"]:::topic
        HX -->|"ADC"| LC --> T_TEN --> CTRL
    end

    subgraph lane3["Lane 3 · TF & bring-up test"]
        direction LR
        RSP["robot_state_publisher"]:::infra
        T_TF["/tf · /tf_static"]:::topic
        HWC["hardware_check<br/><i>optional</i>"]:::node
        RSP --> T_TF
        HWC -.-> T_TRAJ
        T_JS -.-> HWC
        T_TEN -.-> HWC
    end

    subgraph lane4["Sim-only (absent on hardware)"]
        direction LR
        X1["fish_agent"]:::absent
        X2["fish_effort_controller"]:::absent
        X3["tension_sensor_broadcaster"]:::absent
        X4["MuJoCo / recorder"]:::absent
    end
    

Standalone source: diagrams/hardware_ros2_graph.mmd

What is absent on hardware

These sim-only components are not spawned and have no URDF entries when use_sim:=false:

Component

Why absent

mujoco_ros2_control node

Replaced by controller_manager

fish_swim joint

No virtual fish in URDF

fish_effort_controller

No fish joint to command

tension_sensor_broadcaster

No MuJoCo FTS sensor

fish_agent

Launch gated on use_sim

/tension_sensor_broadcaster/wrench

Topic never created

/fish_effort_controller/commands

Topic never created

fish_link TF frame

Not in HW URDF

The dashed “NOT present” region in the diagram above summarises this.

Node reference

Infrastructure

Node

Package

Role

robot_state_publisher

robot_state_publisher

TF + robot description

controller_manager (ros2_control_node)

controller_manager

Realtime loop + dynamixel_hardware plugin

ros2_control controllers

Controller

Joints

Notes

joint_state_broadcaster

Joint_1, Joint_2

Publishes /joint_states

position_trajectory_controller

Joint_1, Joint_2

Position commands only

No effort controllers, no sensor broadcasters.

Application nodes

Node

Package

Notes

admittance_controller or force_feedback_controller

control

Same as sim

load_cell_node

sensors

source:=hardware — HX711 path

hardware_check

diagnostics

Only when hardware_check:=true

Topic catalog (hardware)

Topic

Message

Publisher → Subscriber

Notes

/joint_states

sensor_msgs/JointState

joint_state_broadcastercontrol, hardware_check

Dynamixel feedback

/position_trajectory_controller/joint_trajectory

trajectory_msgs/JointTrajectory

controlposition_trajectory_controller

Same interface as sim

/fishing_arm/tension

interfaces/FishingTension

load_cell_nodecontrol, hardware_check

From HX711 (not FTS)

/tf, /tf_static

tf2_msgs/TFMessage

robot_state_publisher

No fish_link

/robot_description

std_msgs/String

robot_state_publisher

HW URDF (no fish)

Topics that exist in sim but NOT on hardware

Topic

Sim publisher

/fish_effort_controller/commands

fish_agent

/tension_sensor_broadcaster/wrench

tension_sensor_broadcaster

/clock (sim time)

MuJoCo sim

Physical layer (below ROS)

        flowchart LR
    classDef hw fill:#fce4ec,stroke:#c62828,stroke-width:1.5px
    classDef sensor fill:#e3f2fd,stroke:#1565c0,stroke-width:1.5px
    classDef ctrl fill:#e8f5e9,stroke:#2e7d32,stroke-width:1.5px

    LOAD["line load / fish"]:::hw
    HX["HX711"]:::sensor
    LC["load_cell_node"]:::sensor
    CTRL["tension controller"]:::ctrl
    PTC["position_traj_controller"]:::ctrl
    DX["Dynamixel J1·J2"]:::hw
    LINE["line tension"]:::hw

    LOAD --> LINE --> HX --> LC -->|FishingTension| CTRL
    CTRL -->|JointTrajectory| PTC --> DX
    DX -.->|rod angle| LINE
    

Dynamixel path

JointTrajectory → position_trajectory_controller → ros2_control → DynamixelHardware
  → USB /dev/ttyUSB0 → XL430 servos (ID 1, 2) → joint encoders → /joint_states

Load cell path

Line tension → HX711 ADC → load_cell_node.read_raw_adc()
  → calibration → moving average → /fishing_arm/tension

Warning

Implement real HX711 I/O in read_raw_adc() before deployment. The current stub generates a synthetic sine wave for development.

Controller differences on hardware

Concern

Simulation

Hardware

Jacobian for admittance

Can use TF tip/fish geometry

Falls back to `rod_length *

Disturbance

Deterministic sine from fish_agent

Unpredictable real load

Latency

Sim-step bound

USB serial + servo response

Safety

Physics clamp in MJCF

safety_tension_limit E-stop in controller

Pre-flight checklist

# 1. Validate pipeline in sim first
ros2 launch bringup robot.launch.py hardware_check:=true

# 2. Run same check on hardware (controller disabled)
ros2 launch bringup robot.launch.py use_sim:=false hardware_check:=true

# 3. Closed-loop on hardware
ros2 launch bringup robot.launch.py use_sim:=false