Skip to content

v1.4.0

Choose a tag to compare

@nu-jliu nu-jliu released this 28 Oct 02:42
· 3 commits to main since this release
fe78bae

v1.4.0 Release Notes

Date: 2026-10-28 · Tag: v1.4.0 · Compare: v1.3.6...v1.4.0

Highlights

The 7-DOF arm ships as two ordinary arm variants, yam_7dof_left and yam_7dof_right. They plug into the API like any other arm (ArmType.YAM_7DOF_LEFT, --arm yam_7dof_left) and compose with every gripper.

The YAM teaching handle is now versioned as yam_teaching_handle_v1 and yam_teaching_handle_v2. Each is a two-part model (shell plus a passive trigger that moves), with CAD mass and inertia. With --arm no_arm it runs as a new read-only 0-DOF TeachingHandleRobot.

Heads-up for consumers

  • Teaching handle renamed, with deprecated aliases. The gripper is now yam_teaching_handle_v1 / GripperType.YAM_TEACHING_HANDLE_V1. --gripper yam_teaching_handle (which logs a deprecation warning), GripperType.YAM_TEACHING_HANDLE and GRIPPER_TEACHING_HANDLE_PATH still resolve to v1. But GripperType.YAM_TEACHING_HANDLE.value is now "yam_teaching_handle_v1". Anything that loads robots/config/yam_teaching_handle.yml or gripper/yam_teaching_handle/yam_teaching_handle.xml by path must move to the v1/ files, because the old files are removed.
  • enter_zero_torque_idle now sends nothing at all: zero torque, zero PD gains, no gravity comp and no friction comp. The arm will sag or fall, so support it first. enter_gravity_comp_idle turns gravity comp and the configured Coulomb friction back on.
  • Existing arms are unchanged. All 25 compositions of the five YAM-family arms with crank_4310, linear_3507, linear_4310, flexible_4310 and no_gripper produce MJCF that is byte-identical to v1.3.6.

New arms: yam_7dof_left / yam_7dof_right

  • i2rt/robot_models/arm/yam_7dof_{left,right}/v1/: URDF (the source of truth), the arm-only MJCF generated from it, meshes, and a README with the mass, inertia, frame, DH and PoE tables. Provenance: ONShape document a30d2ef2655863e671c75240.
  • A mirrored pair, registered as two families. The left model is the right one reflected about the world x-z plane, generated bit-exact by the new mirror_arm_model.py. Each side has its own ArmType, model directory, config and last_joint_mount blocks, so nothing in the API takes a side.
  • i2rt/robots/config/yam_7dof_{left,right}_v1.yml: the standard arm schema at length 7. Gravity comp (gravity_comp_factor, grav_comp_kd, coulomb_friction) is shared by both sides. directions is mixed-sign. The left arm's directions has not been verified on the bench.
  • The gripper uses CAN 0x08, because the arm's joints take 0x01–0x07. The config declares it as gripper_can_id. Every other arm keeps the default 0x07.
  • The gripper mounts off the joint axis. The last joint is a wrist pitch, and the gripper bolts about 70 mm perpendicular to its axis. last_joint_mount.<arm>.v<N> gains an optional gripper_pos/gripper_quat for this. It is identity on every YAM arm.
  • The wrist mesh is split. The ONShape export fused a 0.103 kg wrist section into the gripper link. The arm-side part is now assets/wrist.stl, a geom on the mount body that carries the same gripper-mount spigot as yam v1. Its mass is not modelled.

joint6 four-bar transmission

  • i2rt/robots/four_bar.py: joint6 is driven through a four-bar linkage. Its gear ratio runs from about 0.81 down to 0.14 across the travel. The linkage, with its bench-fitted phase and measured motor travel, is declared under transmissions: in both arm configs.
  • i2rt/robots/motor_chain_robot.py: MotorChainRobot converts every read and write through the linkage and scales torque by the ratio. It rejects any motor reading more than 3° outside the linkage's travel. SimRobot is unaffected, since the model is already in joint coordinates.

Motor register checks

  • i2rt/motor_drivers/motor_check.py, dm_driver.py: the startup config check also compares any motor_registers the arm config declares. The 7-DOF arms declare KT_Value/GREF on joints 1–7. A mismatch refuses the launch and logs the command that fixes it. The check never writes these registers.
  • scripts/set_7dof_motor_registers.py (new): writes those registers. It verifies motor types first, writes and saves to Flash only the registers that differ, then re-runs the startup check read-only. --dry-run previews the changes.

Teaching handle v1 / v2

  • i2rt/robot_models/gripper/yam_teaching_handle/{v1,v2}/: two-part models (shell plus passive trigger hinge) with CAD mass and inertia, each with a README. v2 is the same grip with a shell 38.2 mm shorter.
  • i2rt/robots/config/yam_teaching_handle_{v1,v2}.yml replace yam_teaching_handle.yml.
  • i2rt/robots/teaching_handle_robot.py (new): TeachingHandleRobot and MotorlessCanChain, a read-only 0-DOF robot over the passive trigger encoder. It publishes the trigger as gripper_pos and has the same robot.motor_chain shape as other robots, so the control interfaces need no special case. It is used with --arm no_arm and either handle.

Composition and robot API

  • i2rt/robots/utils.py: new ArmType and GripperType members. combine_arm_and_gripper_xml handles the off-axis gripper_pos/gripper_quat. It also renumbers the gripper's finger joints to follow the arm's joint count (joint8/joint9 on a 7-DOF arm), which changes nothing on a six-joint arm.
  • i2rt/robots/get_robot.py: assembles the new arms, the transmission and the register expectations. wrap_around_offset now accounts for motor polarity.
  • i2rt/robot_models/__init__.py: new GRIPPER_TEACHING_HANDLE_V1_PATH / _V2_PATH. GRIPPER_TEACHING_HANDLE_PATH remains as a v1 alias.

Control interfaces and tools

  • i2rt/utils/viser_control_interface.py: the mirroring mode is split into VIZ (grav comp) and VIZ (no torque). The no-torque mode is offered only when the robot exposes enter_zero_torque_idle.
  • i2rt/robots/sim_robot.py: implements enter_zero_torque_idle, so sim previews what a real chain does when commanded zero torque.
  • i2rt/utils/mujoco_control_interface.py: seeds its model from the robot on real hardware too, not only in sim.
  • i2rt/motor_config_tool/set_zero.py: moved to a tyro CLI, and the zero read-back is retried, since the motor does not report the new zero on the very next read.
  • examples/*, scripts/run_yam_leader.py: updated for the new arms and handles.

Tests

  • New suites: test_arm_7dof.py (mirror relation, home-pose world axes, the 0x08 gripper id, mount offsets, gravity ceiling, self-collision sweep), test_teaching_handle_robot.py, test_torque_modes.py, test_encoder_convention.py and test_set_7dof_motor_registers.py.
  • test_urdf_mjcf_alignment.py, its posed twin, and test_robot_variants.py now cover arms with any number of joints, so both 7-DOF sides run through the generic suites.

Verification

  • ruff_CI and unit_tests_CI pass on this commit.