NT-X integration
Status: catalog, simulation and the serial transport are verified inside the NT-X harness environment (
make ntx-smoke). Opening the physical robot from an NT-X session needs one NT-X core change (below).
packages/strido-ntx is an NT-X extension. Installed into the NT-X environment it contributes:
| Entry point | Contributes |
|---|---|
ntx.assets → strido_ntx | robots/strido.yaml (RobotSpec), robots/models/strido.xml + meshes (MJCF), skills/strido-stand.yaml |
ntx.adapters → strido_ntx.plugin:register | robot adapter strido-serial → StridoSerialPort |
ntx-extension.yaml | manifest for ntx ext info/doctor strido |
Install into NT-X
cd ../../ntx-harness
uv pip install -e ../workspace/robot/packages/strido-core -e ../workspace/robot/packages/strido-ntx
uv run ntx ext doctor strido
uv run ntx robots show stridomake ntx-smoke runs the same checks without touching the NT-X virtualenv (uv run --project ntx-harness --with-editable …): the robot loads from the catalog, compiles into an NT-X MuJoCo world and stands for 2 s, the adapter is registered, and the serial port drives a protocol-level fake MCU (command → state → protective stop → close).
Robot spec
Generated by python -m strido_ntx.build_assets from the CAD-derived MJCF (make models runs it; make drift checks it):
- joints in MCU order FL, FR, RL, RR × (hip, thigh, calf), limits from the collision sweep, defaults = 170 mm stand pose;
- SPT5435LV limits: 3.43 N·m effort, 7.48 rad/s velocity; PD gains from the MuJoCo servo model;
- feet
FL_foot… bodies at the foot centres;hardware_status: unverifieduntil a robot is qualified.
RobotPort semantics (StridoSerialPort)
| NT-X expects | Strido provides |
|---|---|
read_state().q, dq, tau | q = the angle the MCU applies after its clamps (hobby servos report nothing); dq zeros; tau empty |
| base pose / velocity | orientation + body rates from the IMU; position and linear velocity not measured → has_odometry = False. A state with imu_ok cleared latches the protective stop and raises ImuUnavailableError (fail closed) |
apply(JointCommand) | position target only. Positive kp/kd run as the servo's fixed stiffness and tau_ff (the gravity feed-forward of pd-pose) is dropped; a non-zero dq or kp <= 0 is rejected; non-finite targets latch a protective stop |
hold() | re-sends the last target (MCU watchdog holds 200 ms, relaxes after 2 s) |
protective_stop() | latched MCU e-stop: PCA9685 OE high, every servo pulse off. Servos go limp (no damping) |
release(), close() | clear the e-stop; stop and free the serial device |
| freshness | the input buffer is flushed on open and drained on every poll (newest frame wins); TimeoutError when no state frame arrives within 0.2 s |
Odometry gate. NT-X sessions refuse non-gantry skills on a port without odometry (ntx.runtime.session._check_port_support). strido-stand is a free-standing skill, so on hardware it runs only after a base estimator exists, or as a gantry variant with the body on a stand and the legs free. Simulation sessions are unaffected (the MuJoCo port measures the base).
What NT-X needs to change for hardware sessions
NT-X opens hardware through ntx.deploy.open_robot_port, which always builds the Unitree SDK2 port, and TargetSpec.transport.kind only accepts unitree-sdk2. To run Strido live from a session, NT-X should dispatch hardware through its adapter registry:
- allow
transport.kindvalues that name a registeredrobotadapter (e.g.strido-serial); - in
open_robot_port,registry.create("robot", target.transport.kind, spec=robot, device=…); - add a target
config/targets/strido-desk.yamlwith the qualification gates (identity, e-stop, shadow) for a built robot; - provide a base pose estimate (IMU + leg kinematics) or a gantry variant of
strido-standfor the first hardware sessions.
This change belongs to the NT-X repository and is tracked in TODO; nothing in this repository edits NT-X.
Training in NT-X
The NT-X locomotion-velocity template trains any catalog quadruped: uv run ntx train run --template locomotion-velocity --set spec.robot_id=strido. Policies trained there use NT-X's observation layout; the Strido ROS 2 policy_node runs policies from strido_sim.rl.train (feedback-free observation). Bridging the two runtimes is open work.