primitive-linkerbot-linker_hand_o6-hand-rbnx
robonix.primitive.linkerbot.linker_hand_o6.hand — Robonix primitive for the LinkerBot
LinkerHand O6 five-finger dexterous hand (six axes). Drives the hand over
SocketCAN directly, with no ROS backend.
The LinkerHand CAN backend is vendored into this package
(linkerhand_o6/vendor/, from the official
linkerhand-python-sdk), so
the package is self-contained — no PyPI package exists for that SDK, and
rbnx build needs no network access to fetch it. See
linkerhand_o6/vendor/README.md for what was
copied, what was changed, and how to refresh it.
Capabilities
| Contract | Transport | What it does |
|---|---|---|
robonix/primitive/hand/driver |
gRPC | lifecycle (CMD_INIT / ACTIVATE / DEACTIVATE / SHUTDOWN) |
robonix/primitive/hand/info |
gRPC | each axis's finger and type, so consumers can map fingers |
robonix/primitive/hand/move_joint |
gRPC | axis-level position control |
robonix/primitive/hand/set_joint_speed_limits |
gRPC | per-axis speed ceilings |
robonix/primitive/hand/set_joint_torque_limits |
gRPC | per-axis torque ceilings |
robonix/primitive/hand/get_state |
gRPC | read the current axis positions |
The finger-level contracts (move_finger / set_finger_*) and the state_joint /
state_finger streams (topic_out, which would need a ROS backend this deployment
does not run) are intentionally not provided. Consumers read the axis↔finger
mapping from info and then drive move_joint.
Axis layout
Six axes, in firmware order (which is also info's order and the order any
6-vector is interpreted in):
| # | Name | Finger | Type |
|---|---|---|---|
| 0 | thumb_cmc_pitch |
thumb | bend |
| 1 | thumb_cmc_yaw |
thumb | oppose |
| 2 | index_mcp_pitch |
index | bend |
| 3 | middle_mcp_pitch |
middle | bend |
| 4 | ring_mcp_pitch |
ring | bend |
| 5 | pinky_mcp_pitch |
pinky | bend |
Units
Every value crossing the gRPC surface is normalized to [0, 1], per the robonix hand contracts:
- position —
0= open (extended),1= closed (flexed); forthumb_cmc_yaw,0= neutral and1= full opposition. - speed / torque limits —
0= min,1= max.
The O6 firmware itself speaks raw 0–255 per axis, and for position its
polarity is inverted (255 = fully open). linkerhand_o6/hand.py is the only
place that conversion happens; it is unit-checked against the upstream SDK's own
preset poses (its "张开" / open pose is all-255).
Configuration
Fields, units and defaults are in config.spec. The essentials:
hand_type(right|left, defaultright) — selects the hand's CAN arbitration id (0x27right /0x28left). A wrong value means the hand never answers, and init fails on the state readback.can_iface(defaultcan0) — the SocketCAN interface the hand is wired to.baudrate(default1000000) — CAN bitrate; the O6 firmware runs at 1 Mbps.
Every field also falls back to a matching O6_HAND_* env var.
Dependencies and permissions
- Python 3.8+ with
python-can,numpy, androbonix_api. - CAN permissions. The primitive runs
ip link set …at init to bring the interface up. Either bring it up beforehand —
sudo ip link set can0 up type can bitrate 1000000
— or export PREFLIGHT_SUDO_PASS so the internal sudo -S works. Bringing it
up beforehand is preferred: then nothing here needs elevated rights.
Note that unlike the upstream SDK, this package does not read a sudo
password from a committed yaml file.
- scripts/start.sh defaults to $HOME/miniconda3/envs/bb_d1_robonix/bin/python3;
override with LINKERHAND_O6_PYTHON.
Build and run
bash scripts/build.sh # rbnx codegen, generating the gRPC stubs
bash scripts/start.sh # or let rbnx boot start it from a deployment manifest
rbnx caps -v | grep hand # check all 6 capabilities registered and the provider is ACTIVE
Shutdown is handled by the Driver's CMD_SHUTDOWN (on_shutdown opens the hand
and releases the CAN handle). There is no cleanup beyond that, so no
scripts/stop.sh is provided. The CAN interface is deliberately left up on
shutdown — it may be shared with other devices on the bus.
Safety
- Do the read-only checks first (
info/get_state) before commandingmove_joint. - For the first open/close, lower the ceiling with
set_joint_torque_limitsto avoid pinching a finger or damaging a knuckle. - Shut down any other controller (the LinkerHand ROS/ROS2 SDK, a mocap glove, the vendor GUI) before starting this primitive — two writers on one CAN bus fight over the hand.
- Providers stop hardware output on input timeout, process exit, or
CMD_SHUTDOWN.
Layout
package_manifest.yaml config.spec README.md README_CN.md
scripts/{build.sh, start.sh}
linkerhand_o6/
__init__.py main.py # robonix contract surface
hand.py # normalized [0,1] wrapper
vendor/ # vendored LinkerHand SDK — see its README
linker_hand_o6_can.py color_msg.py can_iface.py UPSTREAM_COMMIT
License
MulanPSL-2.0. The vendored files retain their upstream licensing — see
linkerhand_o6/vendor/README.md.