Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions docs/concepts/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ build against which:

![Module dependency graph](/img/diagrams/concepts__architecture__03_module_deps.svg)

Notice that `humanoid_controllers` does **not** `find_package(humanoid_control_robstride)`.
Notice that `humanoid_controllers` does **not** `find_package(humanoid_devices_robstride)`.
The plugin is loaded by `controller_manager` at launch via `pluginlib` — a
runtime dep that doesn't appear in the static graph but is just as binding.
The same applies to every `<plugin>` entry in a controller-manager YAML.
Expand All @@ -36,7 +36,7 @@ MuJoCo — it performs three steps:
| `update()` | read state_interfaces_, write command_interfaces_, lock-free trylock for diag publishers | allocations, blocking, exceptions across the RT boundary |
| `write()` | stage frames into the bus library's outgoing queue | the actual CAN/EtherCAT syscall (that's the I/O thread's job) |

The I/O thread in each hardware plugin (`humanoid_control_socketcan::SocketCanBus`,
The I/O thread in each hardware plugin (`humanoid_drivers_socketcan::SocketCanBus`,
`ethercat_driver_ros2`'s EtherLAB master thread) is **separate** from the
controller-manager thread. RT-safety is preserved by making `read()` /
`write()` allocation-free buffer swaps.
Expand Down Expand Up @@ -229,8 +229,8 @@ system:

Concrete examples:

- A Robstride bus-off → `humanoid_control_robstride` publishes `SafetyStatus{level=FAULT,
source="humanoid_control_robstride/can0", flags=BUS_OFF}` → `mode_manager` requests a
- A Robstride bus-off → `humanoid_devices_robstride` publishes `SafetyStatus{level=FAULT,
source="humanoid_devices_robstride/can0", flags=BUS_OFF}` → `mode_manager` requests a
STRICT switch to DAMPING. If DAMPING fails (e.g. command interfaces
unavailable), `mode_manager` falls back to ZERO_TORQUE.
- A `RemotePolicyController` whose Python publisher stalls for >100 ms
Expand All @@ -249,8 +249,8 @@ The shipping configuration is a **two-machine tethered split**. The
same colcon workspace is installed (and built from the same pixi lock
file) on both machines; each launch boots only the subset of nodes
that belongs on its side. Single-machine sim/dev paths
(`humanoid_control_bringup_lite/mujoco.launch.py`, `humanoid_control_bringup_lite/view_lite.launch.py`,
`humanoid_control_bringup_lite/calibrate.launch.py`) are unaffected — they
(`humanoid_bringup_lite/mujoco.launch.py`, `humanoid_bringup_lite/view_lite.launch.py`,
`humanoid_bringup_lite/calibrate.launch.py`) are unaffected — they
collapse both sides into one process tree.

Launches come from two sibling repos: `humanoid_control` ships every
Expand All @@ -259,8 +259,8 @@ ships the piano-task-specific launches.

| Side | Machine | Launch | What lives here |
|---|---|---|---|
| **Robot** | Onboard computer (RT kernel, wired tether) | `humanoid_control_bringup_lite/launch/real.launch.py` (humanoid_control) | `ros2_control_node`, `humanoid_control_robstride` / `humanoid_control_sito` hardware plugins, `joint_state_broadcaster`, the five FSM controllers (`zero_torque` / `damping` / `standby` / `rl_policy` / `remote_policy`), `mode_manager`, `joy_node`, `robot_state_publisher`, IMU driver |
| **Host** | Operator workstation | `humanoid_control_bringup_lite/launch/viz.launch.py` (humanoid_control) | `viser_viz` *or* `rerun_viz` (selected by `viewer:=`) |
| **Robot** | Onboard computer (RT kernel, wired tether) | `humanoid_bringup_lite/launch/real.launch.py` (humanoid_control) | `ros2_control_node`, `humanoid_devices_robstride` / `humanoid_devices_sito` hardware plugins, `joint_state_broadcaster`, the five FSM controllers (`zero_torque` / `damping` / `standby` / `rl_policy` / `remote_policy`), `mode_manager`, `joy_node`, `robot_state_publisher`, IMU driver |
| **Host** | Operator workstation | `humanoid_bringup_lite/launch/viz.launch.py` (humanoid_control) | `viser_viz` *or* `rerun_viz` (selected by `viewer:=`) |
| **Robot** | Onboard computer | `humanoid_control_policy/launch/lite_policy.launch.py` (humanoid_control) / `pianist_policy/launch/piano_policy.launch.py` (pianist_ros2) | Runs `prepare` (resolve ONNX, convert motion → `.mcap` + overlay) then loads `rl_policy_controller` into the local CM. Inference is in-process, so the `.onnx` / `.mcap` artifacts **and** the W&B / HF Hub / `onnxruntime` *prepare-time* deps live here. The RT path itself pulls none of them. |
| **Robot** | Onboard computer | `pianist_policy/launch/midi_keyboard_driver.launch.py` (pianist_ros2) | USB-MIDI keyboard driver → `/piano/key_state` (`std_msgs/Float32MultiArray`); feeds the on-robot controller's `key_pressed` extern term locally (loopback, does **not** cross the tether). |

Expand Down
10 changes: 5 additions & 5 deletions docs/concepts/calibration_math.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: Calibration math

# Calibration math

How `humanoid_control_robstride` maps between the raw encoder reading and the
How `humanoid_devices_robstride` maps between the raw encoder reading and the
URDF joint frame, where the per-joint constants live, and why the
calibration is split across two files.

Expand Down Expand Up @@ -37,7 +37,7 @@ is in the joint frame — controllers never see the raw encoder.
| Parameter | Per | Where it lives | What it captures |
|---|---|---|---|
| `direction` | joint | URDF `<param>` inside the `<ros2_control>` block | Wiring sign — does the motor's positive direction match the URDF's positive joint direction? |
| `homing_offset` | joint | `humanoid_control_bringup_lite/config/calibration.yaml` | Per-physical-robot encoder zero offset (motor frame, rad). |
| `homing_offset` | joint | `humanoid_bringup_lite/config/calibration.yaml` | Per-physical-robot encoder zero offset (motor frame, rad). |

The split is deliberate:

Expand All @@ -53,7 +53,7 @@ The split is deliberate:

## Deriving the offset

The calibration tool (`humanoid_control_bringup_lite/scripts/calibrate_robot.py`)
The calibration tool (`humanoid_bringup_lite/scripts/calibrate_robot.py`)
runs the plugin with `calibration_file:=''` — identity calibration —
so `/lite/joint_states` reports `direction · raw_motor_pos` (the
direction-applied-but-not-offset frame). The operator hand-sweeps each
Expand Down Expand Up @@ -141,6 +141,6 @@ URDF. The cost is that hand-edits to `id` / `direction` in
## See also

- [How-to → Calibrate the zero pose](../how_to/calibrate_zero_pose.md) — the recipe.
- [`RobstrideSystem` source](https://github.com/Berkeley-Humanoids/humanoid_control/blob/main/humanoid_control_devices/humanoid_control_robstride/src/robstride_system.cpp#:~:text=load_calibration)
- [`RobstrideSystem` source](https://github.com/Berkeley-Humanoids/humanoid_control/blob/main/humanoid_devices/humanoid_devices_robstride/src/robstride_system.cpp#:~:text=load_calibration)
— the loader + apply.
- `humanoid_control_bringup_lite/scripts/calibrate_robot.py` — the formula in code.
- `humanoid_bringup_lite/scripts/calibrate_robot.py` — the formula in code.
8 changes: 4 additions & 4 deletions docs/concepts/mit_command_surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ projects. Three properties make it the right primitive:
1. **One formula across silicon and sim.** Robstride firmware computes
it on the motor MCU; `mujoco_ros2_control::MujocoSystem` computes
the same expression and applies it via `qfrc_applied`; our
`humanoid_control_robstride/RobstrideSystem` encodes the five fields straight
`humanoid_devices_robstride/RobstrideSystem` encodes the five fields straight
into a wire frame. A controller written against this surface runs
unchanged on silicon, MuJoCo, and `mock_components`.
2. **No mode-switching at the actuator.** "Switch from position control
Expand Down Expand Up @@ -120,8 +120,8 @@ kd : 16 bits, unsigned, scaled to [0, kd_max]
```

Limits are model-specific (rs-00..rs-06); see
`humanoid_control_devices/humanoid_control_robstride/include/humanoid_control_robstride/robstride_protocol.hpp`.
`humanoid_control_robstride/RobstrideSystem::write` does the scale-and-pack;
`humanoid_devices/humanoid_devices_robstride/include/humanoid_devices_robstride/robstride_protocol.hpp`.
`humanoid_devices_robstride/RobstrideSystem::write` does the scale-and-pack;
`read` reverses it.

## See also
Expand All @@ -131,5 +131,5 @@ Limits are model-specific (rs-00..rs-06); see
- [Reference → Hardware specs → MIT-mode command convention](../reference/hardware_specs.md#mit-mode-command-convention)
— short-form repeat of the formula.
- The protocol header in
[`humanoid_control_robstride/robstride_protocol.hpp`](https://github.com/Berkeley-Humanoids/humanoid_control/blob/main/humanoid_control_devices/humanoid_control_robstride/include/humanoid_control_robstride/robstride_protocol.hpp)
[`humanoid_devices_robstride/robstride_protocol.hpp`](https://github.com/Berkeley-Humanoids/humanoid_control/blob/main/humanoid_devices/humanoid_devices_robstride/include/humanoid_devices_robstride/robstride_protocol.hpp)
is the source-of-truth for the wire encoding.
12 changes: 6 additions & 6 deletions docs/concepts/prime_hybrid_actuation.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ EtherCAT, through the IgH master); two — the distal wrist roll/pitch — are
So the EtherCAT ring carries **10 eRob** (positions 0-9, left arm 0-4, right
arm 5-9) and the CAN bus carries **4 Sito** wrists (ids `0x16/0x17/0x26/0x27`).
All Prime eRob are **50:1** gear. The single source of truth for this mapping
is `humanoid_control_bringup_prime/config/prime_hardware.yaml` (`buses`, `joints.all_joints`,
is `humanoid_bringup_prime/config/prime_hardware.yaml` (`buses`, `joints.all_joints`,
`joints.erob_slaves`, `joints.mit_joints`); the per-joint bus assignment is
emitted by `prime_description` (`robots/prime_dummy/xacro/prime_dummy.ros2_control.xacro`).

Expand All @@ -54,7 +54,7 @@ constant (read each joint's model off its label; see the eRob manual §25.2):

The 1.5% `Kt` difference is negligible in practice; the **gear ratio** would
be the real lever, but every Prime eRob is 50:1, so a single conversion
serves all of them. `humanoid_control_bringup_prime/config/prime_hardware.yaml` can still
serves all of them. `humanoid_bringup_prime/config/prime_hardware.yaml` can still
override `Kt`/gear per joint (`joints.erob_kt` / `joints.erob_gear`) if a model
ever differs.

Expand All @@ -63,7 +63,7 @@ ever differs.
`real.launch.py` expands the xacro with `use_fake_hardware:=false use_sim:=false`,
which emits **two concurrent `ros2_control` blocks** — `PrimeEtherCATSide`
(`ethercat_driver/EthercatDriver`, the 10 eRob) and `PrimeSitoCAN`
(`humanoid_control_sito/SitoSystem`, the 4 Sito wrists). One `controller_manager` runs them
(`humanoid_devices_sito/SitoSystem`, the 4 Sito wrists). One `controller_manager` runs them
together and exposes a flat 14-joint list to the mode controllers. The sim path
(`mujoco.launch.py`) collapses both into one `MujocoSystem` block but presents
the identical 14 joints, so the shared controllers run unchanged.
Expand Down Expand Up @@ -96,7 +96,7 @@ differently — and that difference is the heart of the Prime control story.
The Sito firmware runs the MIT law directly. The host sends the desired
position, velocity, and feedforward torque in a command frame, and `Kp`/`Kd`
in a separate gains frame. Conversions (in
`humanoid_control_devices/humanoid_control_sito/include/humanoid_control_sito/sito_protocol.hpp`, TA40-50):
`humanoid_devices/humanoid_devices_sito/include/humanoid_devices_sito/sito_protocol.hpp`, TA40-50):

```
position_counts = q_cmd · 65536 / (2π) # 16-bit encoder, MOTOR side
Expand Down Expand Up @@ -132,7 +132,7 @@ are not PDO-mappable, so they cannot be a per-tick command interface):
| `0x2381:02` | velocity loop integral (held at 0 for clean impedance) |
| `0x2383` | "Bus Regulation of PID" gate — `1` = use bus-written gains, `0` = factory |

The SI-to-register conversion (`humanoid_control_bringup_prime/scripts/erob_impedance_manager.py`,
The SI-to-register conversion (`humanoid_bringup_prime/scripts/erob_impedance_manager.py`,
`erob_gains()`), validated exactly against the ZeroErr derivation:

```
Expand Down Expand Up @@ -186,7 +186,7 @@ fixed mode impedance and track position in CSP.

## The eRob impedance manager

`humanoid_control_bringup_prime/scripts/erob_impedance_manager.py` is the bridge between the
`humanoid_bringup_prime/scripts/erob_impedance_manager.py` is the bridge between the
mode FSM and the eRob loop gains. It subscribes to `/control_mode` and, on each
transition, converts that mode's `(kp, kd)` to loop-gain registers and writes
them over the EtherLab `ethercat download` CLI. (It uses the CLI, not the
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/safety_pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The plugin publishes `humanoid_control_msgs/SafetyStatus` on `/safety_status`
TRANSIENT_LOCAL durability so late-joining subscribers (like rqt or a
freshly-started `mode_manager`) immediately see the most recent
value. The `source` field carries the bus interface name
(`humanoid_control_robstride/can0`, etc.), so an operator can tell which bus
(`humanoid_devices_robstride/can0`, etc.), so an operator can tell which bus
flagged.

Each tick, the plugin rebuilds `flags` from **currently observed**
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/workspace_and_environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ or topic:
| | **Tier 1 — ROS native** | **Tier 2 — workspace tooling** | **Tier 3 — separate project** |
|---|---|---|---|
| Location | `src/<pkg>/` | per-package `scripts/`, the `hc` CLI, a future top-level `scripts/` | its own git repo, outside the workspace |
| Examples | `humanoid_controllers`, `humanoid_control_robstride`, `humanoid_control_socketcan` | `robstride_probe`, calibration helpers, `hc bus ping` | `Lite-SDK2`, `Lite-Gravity-Compensation` |
| Examples | `humanoid_controllers`, `humanoid_devices_robstride`, `humanoid_drivers_socketcan` | `robstride_probe`, calibration helpers, `hc bus ping` | `Lite-SDK2`, `Lite-Gravity-Compensation` |
| Build / run | `colcon` + `ros2 run` | `pixi run …` | own toolchain (`uv run …`) |
| Imports `rclpy`? | **yes** | no | **no** |
| Talks to ROS via | native pub / sub / service / action | doesn't talk to running nodes | **DDS (CycloneDDS)** + file handoff |
Expand Down
20 changes: 10 additions & 10 deletions docs/getting_started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ platforms = ["linux-64", "linux-aarch64"]
# `view` / `viz` launches.
ros-jazzy-ros-base = "*"
# The whole Lite bringup: humanoid_controllers (ONNX-enabled), humanoid_control_msgs,
# lite_description, humanoid_control_robstride, humanoid_control_socketcan, humanoid_control_common, humanoid_control_policy.
# lite_description, humanoid_devices_robstride, humanoid_drivers_socketcan, humanoid_control_common, humanoid_control_policy.
ros-jazzy-humanoid-control-bringup-lite = "*"
# Optional: the `hc` diagnostic CLI (run via `ros2 run humanoid_control_cli hc ...`).
ros-jazzy-humanoid-control-cli = "*"
Expand All @@ -106,7 +106,7 @@ fails with `invalid choice: 'launch'`. The from-source workspace gets this from

```sh
pixi install
pixi run ros2 launch humanoid_control_bringup_lite real.launch.py
pixi run ros2 launch humanoid_bringup_lite real.launch.py
```

`pixi install` downloads the prebuilt `ros-jazzy-humanoid-control-*` binaries plus the
Expand All @@ -119,7 +119,7 @@ so `ros2 launch …` / `ros2 run …` work inside `pixi shell` (or via
```sh
pixi shell
ros2 pkg list | grep '^humanoid_control_' # the humanoid_control_* packages you pulled in
ros2 launch humanoid_control_bringup_lite real.launch.py --show-args # dry-parse the launch (no hardware)
ros2 launch humanoid_bringup_lite real.launch.py --show-args # dry-parse the launch (no hardware)
ros2 run humanoid_control_cli hc bus discover --iface can0 --scan-to 32 # read-only CAN scan, e.g.
```

Expand Down Expand Up @@ -198,7 +198,7 @@ colcon build fails with a clear CMake error — add the dep to `pixi.toml`'s

:::warning[Optional: skip the EtherCAT path]
`ethercat_driver_ros2` links `libethercat`, which has no conda recipe. The
default build below skips `ethercat.*` and `humanoid_control_bringup_prime` so Lite bringup
default build below skips `ethercat.*` and `humanoid_bringup_prime` so Lite bringup
works on any host. To enable Prime, install the IgH EtherLAB master from source
on the host, then drop the `--packages-skip-regex` filter.
:::
Expand All @@ -207,7 +207,7 @@ on the host, then drop the `--packages-skip-regex` filter.

```sh
pixi shell
colcon build --symlink-install --packages-skip-regex 'ethercat.*|humanoid_control_bringup_prime'
colcon build --symlink-install --packages-skip-regex 'ethercat.*|humanoid_bringup_prime'
```

`pixi shell` sources the conda env and `humanoid_control_ws/install/setup.bash` once it
Expand All @@ -230,14 +230,14 @@ ros2 control list_hardware_interfaces 2>/dev/null \
The 11 `humanoid_control` packages (Lite's `lite_description` comes separately, via `bar.repos`):

```
humanoid_control_bringup_lite
humanoid_control_bringup_prime
humanoid_bringup_lite
humanoid_bringup_prime
humanoid_control_cli
humanoid_control_common
humanoid_controllers
humanoid_control_robstride
humanoid_control_sito
humanoid_control_socketcan
humanoid_devices_robstride
humanoid_devices_sito
humanoid_drivers_socketcan
humanoid_control_msgs
humanoid_control_policy
```
Expand Down
6 changes: 3 additions & 3 deletions docs/getting_started/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ A single git repo at `Berkeley-Humanoids/humanoid_control`, a flat collection of

Notice that **`humanoid_controllers`, `humanoid_control_msgs`, and `humanoid_control_policy` have no
robot-specific code** — everything robot-specific lives in `humanoid_control_description_*`
or `humanoid_control_bringup_*`.
or `humanoid_bringup_*`.

## Design rationale (one-paragraph version)

Expand Down Expand Up @@ -97,15 +97,15 @@ list; the most influential are:
decomposition pattern and `industrial_ci` workflow.
- **[legged_control2](https://qiayuanl.github.io/legged_control2_doc/overview.html)**
— two-tier hardware factoring (bus library / per-actuator-family plugin)
that we mirror for `humanoid_control_socketcan` / `humanoid_control_robstride` / `humanoid_control_sito`.
that we mirror for `humanoid_drivers_socketcan` / `humanoid_devices_robstride` / `humanoid_devices_sito`.
- **[mujoco_ros2_control](https://github.com/qiayuanl/mujoco_ros2_control)** —
the MuJoCo ↔ ros2_control bridge whose `MujocoSystem` plugin we consume.
- **[franka_ros2](https://github.com/frankarobotics/franka_ros2)** — the flat
package-collection layout this repo follows.
- **[Universal_Robots_ROS2_Driver](https://github.com/UniversalRobots/Universal_Robots_ROS2_Driver)**
— gold-standard `ros2_control` hardware integration. The
`Universal_Robots_Client_Library` / `ur_robot_driver` split mirrors our
`humanoid_control_socketcan` / `humanoid_control_robstride` split.
`humanoid_drivers_socketcan` / `humanoid_devices_robstride` split.

## Next

Expand Down
14 changes: 7 additions & 7 deletions docs/getting_started/lite_101.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The simplest possible launch: `robot_state_publisher` + a
the kinematic chain.

```sh
ros2 launch humanoid_control_bringup_lite view_lite.launch.py
ros2 launch humanoid_bringup_lite view_lite.launch.py
```

What you'll see:
Expand Down Expand Up @@ -66,7 +66,7 @@ hosted inside `mujoco_sim`, all five mode-FSM controllers loaded, the
the Robstride firmware computes on silicon.

```sh
ros2 launch humanoid_control_bringup_lite mujoco.launch.py
ros2 launch humanoid_bringup_lite mujoco.launch.py
```

A **MuJoCo viewer window** opens with the Lite humanoid at zero pose.
Expand Down Expand Up @@ -142,22 +142,22 @@ ros2 topic echo --once /control_mode

:::tip["See it move"]
Two interchangeable live visualizers ride on `/lite/joint_states` +
`/robot_description`, both shipped by `humanoid_control_bringup_lite`. On the
`/robot_description`, both shipped by `humanoid_bringup_lite`. On the
tethered deployment they live on the **operator workstation** (host
side of the tether), spawned by `viz.launch.py`:

```sh
ros2 launch humanoid_control_bringup_lite viz.launch.py # viser, http://localhost:8080
ros2 launch humanoid_control_bringup_lite viz.launch.py viewer:=rerun # native rerun window
ros2 launch humanoid_bringup_lite viz.launch.py # viser, http://localhost:8080
ros2 launch humanoid_bringup_lite viz.launch.py viewer:=rerun # native rerun window
```

For a single-machine MuJoCo run, the standalone shortcuts work too —
they auto-discover `/robot_description` and the joint-state topic on
the local domain:

```sh
ros2 run humanoid_control_bringup_lite viser_viz
ros2 run humanoid_control_bringup_lite rerun_viz
ros2 run humanoid_bringup_lite viser_viz
ros2 run humanoid_bringup_lite rerun_viz
```

Visualiser dependencies (`rerun-sdk`, `viser`, `yourdfpy`, `scipy`)
Expand Down
Loading
Loading