robot-linkerbot-linker_hand_o6
Robonix deployment for a standalone LinkerHand O6 five-finger dexterous hand (six axes, CAN bus) — no arm, no mobile base, no camera. The hand performs a finger "dance" on voice or text command through pilot.
This repository is the assembly, and holds no actual package source —
the primitive and the skill each live in their own repository and are fetched by
url: at build time into rbnx-boot/cache/. What lives here is:
robonix_manifest.yaml— the deployment manifest listing every package to bring up, with its runtime config.soma.yaml+urdf/linkerhand_o6_right.urdf— the body description and URDF served byrobonix-soma(see urdf/README.md)..env.example— the LLM endpoint credential template (copy to.env).

1. What it can do
| Capability | Tool | Example request |
|---|---|---|
| Finger dance | gesture_dance |
"跳个舞" / "wiggle your fingers for 5 seconds" |
| Per-axis position / speed / torque | the hand primitive's contracts | (programmatic) |
It cannot reach, lift, move or see anything: there is no arm and no camera in
this deployment. soma.yaml's cannot_do states this explicitly so pilot does
not attempt object manipulation.
2. Package roster
Manifest order is boot order. The names below match - name: in
robonix_manifest.yaml, which is also what rbnx caps displays.
| Section | Name | Repository |
|---|---|---|
primitive |
o6_hand |
primitive-linkerbot-linker_hand_o6-hand-rbnx |
skill |
hand_gesture |
skill-hand-gesture-rbnx |
The primitive owns the CAN bus and serves the six robonix/primitive/hand/*
contracts. The LinkerHand SDK — which is not on PyPI — is vendored inside it, so
a build needs no extra network access beyond fetching the two packages.
The skill is a standalone, generic package, reused verbatim rather than
forked. Nothing in it is tied to a particular robot: it is a pure consumer that
discovers the primitive through atlas, reads the axis order from hand/info at
activation, and drives a 6-axis dance vector — exactly the O6 layout.
3. Prerequisites
- Hardware: a LinkerHand O6 hand and a USB-CAN adapter, wired and powered.
robonix-cli(rbnx) onPATH, with the robonix source tree registered (rbnx setupin that tree).- Python env with
python-can,numpy,grpcio,grpcio-tools,mcp,fastmcp. Each package'sscripts/start.shcarries a default interpreter path; override per package withLINKERHAND_O6_PYTHON/HAND_GESTURE_PYTHON. - An LLM endpoint for pilot. Copy
.env.example→.envand fillVLM_BASE_URL/VLM_API_KEY/VLM_MODEL. No image input is needed — this deployment has no camera, so the model is only a text planner.
4. Configuration — what to check before running
4.1 CAN bus
Bring the bus up before booting, at 1 Mbps:
sudo ip link set can0 up type can bitrate 1000000
ip -br link show can0 # confirm it exists and is up
The primitive will raise the interface itself if it is down, but that needs
elevated rights (PREFLIGHT_SUDO_PASS, see .env.example). Bringing it up
beforehand is preferred: then nothing in the deployment needs privileges.
Shut down any other controller on the bus first — the LinkerHand ROS/ROS2 SDK, a mocap glove, the vendor GUI. Two writers on one CAN bus fight over the hand.
4.2 Manifest knobs
Everything tunable is in robonix_manifest.yaml:
hand_type—right(CAN id0x27) orleft(0x28). A wrong value means the hand never answers and init fails on the state readback.can_iface/baudrate— defaultcan0at 1 Mbps.
The skill takes no config (config: {}) — the dance duration is a per-call
argument.
5. Build and run
5.1 Per-session bring-up
rbnx build -f robonix_manifest.yaml # fetch both packages + run their codegen
rbnx boot -f robonix_manifest.yaml # bring up the stack, until Ctrl-C
Then, in another shell:
rbnx caps -v # every capability and its provider state
rbnx tools # the MCP tools pilot can call
rbnx chat # talk to the robot
rbnx shutdown tears down a stack brought up by rbnx boot.
5.2 After changing a package
After changing code in one of the package repos, drop the cached checkout or the old copy keeps booting:
rbnx clean -f robonix_manifest.yaml --cache
rbnx build -f robonix_manifest.yaml
6. Body model
soma.yaml describes a single body part — the hand — rooted at
hand_base_link, with the six actuated axes and the contracts serving them. It
is served verbatim to pilot as LLM body context.
urdf/linkerhand_o6_right.urdf is a standalone right-hand model: the arm, head
and base links of the whole-body URDF it came from were dropped and
hand_base_link promoted to the root. Joint names match the axis names the
primitive reports through hand/info. The distal joints are mimic — six
actuators, with each distal link following its proximal one mechanically. The
vendor ships no O6 URDF in either its Python or ROS2 SDK, which is why this is
derived rather than imported.
The footprint in soma.yaml is the hand base's own static hull, not a drivable
base; soma validates that a footprint encloses the origin, and this deployment
has no chassis.
7. Repository layout
robot-linkerbot-linker_hand_o6/
├── robonix_manifest.yaml # what to deploy, and with what config
├── soma.yaml # body model served to pilot
├── .env.example # LLM endpoint + optional sudo password for CAN
├── assets/robot.jpg # catalog preview image
└── urdf/
├── README.md # URDF provenance, joint tree, frame conventions
├── linkerhand_o6_right.urdf # standalone right hand, root link = hand_base_link
└── meshes/right_hand/*.STL # meshes referenced by the URDF
rbnx-boot/ (fetched packages and runtime logs) is git-ignored.
8. Units
Every hand value is normalized to [0, 1] per axis: position 0 = open and
1 = closed; speed and torque limits 0 = min and 1 = max. The O6 firmware's
raw 0–255 units — and the inverted polarity of its position values — are
converted inside the primitive package.
9. Safety
- Secure the hand before the first run; a dance moves all five fingers at once.
- Lower the ceiling with
set_joint_torque_limitsbefore the first open/close to avoid pinching a finger or damaging a knuckle. - The hand is commanded fully open at the end of every dance, on any error, and on shutdown — it is never left mid-clench.
- Keep hands and objects clear of the fingers while the stack is running.
10. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Init fails on the state readback; the hand never answers | Wrong hand_type — right is CAN id 0x27, left 0x28 |
Fix hand_type in robonix_manifest.yaml (§4.2) |
| The primitive won't start, reporting a missing interface | can0 is down |
Run the ip link set from §4.1; confirm with ip -br link show can0 |
| Twitchy motion, or commands landing intermittently | Another writer on the bus (ROS/ROS2 SDK, mocap glove, vendor GUI) | Shut the other controllers down — one writer per CAN bus |
| Package code changed but behaviour didn't | The old checkout in rbnx-boot/cache/ is what booted |
Run the rbnx clean --cache from §5.2, then build |
| Pilot tries to grasp or carry something | soma.yaml's cannot_do was edited or isn't taking effect |
There is no arm and no camera here; confirm cannot_do is intact |
For deeper digging, every package leaves stdout/stderr in
rbnx-boot/logs/<name>.log.
11. Reference
- Joint tree and frame conventions: urdf/README.md
- Hand primitive: https://github.com/syswonder/primitive-linkerbot-linker_hand_o6-hand-rbnx
- Gesture skill: https://github.com/syswonder/skill-hand-gesture-rbnx
- robonix framework: https://github.com/syswonder/robonix
Each package's own README covers its contracts and failure modes in detail. When a package misbehaves, start there.
12. License
MulanPSL-2.0