MHS device¶
Every Robot is a Model Hardware Standard device:
it publishes a manifest, serves procedures over a broker, joins the fleet e-stop, and drives
estop to 1 when the broker goes away. Any MHS client discovers and invokes it; no strands
code is needed on that side.
Terminal one:
python3 -m pip install "strands-robots[sim]"
python3 -m pip install mhs # until the release lands on PyPI: pip install "mhs[nats,zenoh] @ git+https://github.com/modelhardwarestandard/python-sdk"
export MHS_SECURITY_MODE=shadow # every decision logged, none blocked; commission before enforce
strands-robots serve so101 --mode sim --mhs zenoh:// # mesh peer + MHS device, no server
Terminal two:
export MHS_SECURITY_MODE=shadow
strands-robots mhs fleet --broker zenoh://
strands-robots mhs invoke so101 act '{"action": {"shoulder_pan": 0.3}}' --broker zenoh:// --confirm
strands-robots[mhs] is an empty extra until the SDK is on PyPI; the refusal
MISSING_EXTRA names both install lines.
Four lines¶
from strands_robots import Robot
from strands_robots.app.mhs import mount_robot
robot = Robot("so101", mode="sim")
device = mount_robot(robot, "inproc://strands-robots") # default broker: MHS_BROKER
robot.close() # drives estop to 1, unmounts, closes the client
mount_robot(robot, broker, mesh=...) ties the device to a running Mesh so one e-stop
serves both wires. Sim and real robots mount the same way.
The manifest¶
Derived from the registry row, never typed by hand.
| entry | derived from |
|---|---|
| one sensor per joint (unit = the action frame, range = the row's limits) | RobotSpec.joints |
task_status step_count instruction |
the running PolicyRunner |
estop control: range (0, 1), safe 1, on_disconnect APPLY 1 |
fixed |
getState act preflight getFeatures getStatus stop |
the RobotLike surface |
execute_op with op_status and op_cancel |
PolicyRunner + the policy registry |
getFrame(camera) -> JPEG |
present only when the row has cameras |
events taskStarted taskStopped taskError emergencyStop |
the runner and the latch |
act with an unknown joint, a non-finite or out-of-range value, and any motion while the
e-stop is latched are refused on the wire (-32000) with the same code an agent sees locally.
Nothing is clamped on the wire; Robot.act stays the one place that clamps.
E-stop¶
stop, or writing estop=1, halts the robot, latches, and publishes emergencyStop (and the
mesh safety envelope when a mesh is attached). Any peer's emergencyStop latches this device;
stopping needs no identity, resume does (STRANDS_MESH_OVERRIDE_CODE). Broker loss applies
estop=1.
Brokers¶
| broker | callers | gate |
|---|---|---|
inproc:// |
same process | off |
zenoh:// |
LAN peers | SDK enforce (needs MHS_TRUST_BUNDLE) or MHS_SECURITY_MODE=shadow |
nats:// mqtt:// zenoh://host |
NATS_CREDENTIALS_FILE, MESSAGING_USERNAME/PASSWORD, MESSAGING_TLS_* |
as above |
A networked broker with no credentials and no TLS is refused CONNECT_FAILED unless
STRANDS_MHS_ALLOW_INSECURE=1. STRANDS_MESH_BACKEND=mhs carries the strands mesh over the
same broker. Knobs: configuration.