Repository navigation
v1.4.0
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_HANDLEandGRIPPER_TEACHING_HANDLE_PATHstill resolve to v1. ButGripperType.YAM_TEACHING_HANDLE.valueis now"yam_teaching_handle_v1". Anything that loadsrobots/config/yam_teaching_handle.ymlorgripper/yam_teaching_handle/yam_teaching_handle.xmlby path must move to thev1/files, because the old files are removed. enter_zero_torque_idlenow 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_idleturns 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_4310andno_gripperproduce 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 documenta30d2ef2655863e671c75240.- 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 ownArmType, model directory, config andlast_joint_mountblocks, so nothing in the API takes aside. 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.directionsis mixed-sign. The left arm'sdirectionshas not been verified on the bench.- The gripper uses CAN
0x08, because the arm's joints take0x01–0x07. The config declares it asgripper_can_id. Every other arm keeps the default0x07. - 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 optionalgripper_pos/gripper_quatfor 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 asyamv1. 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 undertransmissions:in both arm configs.i2rt/robots/motor_chain_robot.py:MotorChainRobotconverts 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.SimRobotis 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 anymotor_registersthe arm config declares. The 7-DOF arms declareKT_Value/GREFon 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-runpreviews 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}.ymlreplaceyam_teaching_handle.yml.i2rt/robots/teaching_handle_robot.py(new):TeachingHandleRobotandMotorlessCanChain, a read-only 0-DOF robot over the passive trigger encoder. It publishes the trigger asgripper_posand has the samerobot.motor_chainshape as other robots, so the control interfaces need no special case. It is used with--arm no_armand either handle.
Composition and robot API
i2rt/robots/utils.py: newArmTypeandGripperTypemembers.combine_arm_and_gripper_xmlhandles the off-axisgripper_pos/gripper_quat. It also renumbers the gripper's finger joints to follow the arm's joint count (joint8/joint9on 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_offsetnow accounts for motor polarity.i2rt/robot_models/__init__.py: newGRIPPER_TEACHING_HANDLE_V1_PATH/_V2_PATH.GRIPPER_TEACHING_HANDLE_PATHremains 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 exposesenter_zero_torque_idle.i2rt/robots/sim_robot.py: implementsenter_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 atyroCLI, 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, the0x08gripper id, mount offsets, gravity ceiling, self-collision sweep),test_teaching_handle_robot.py,test_torque_modes.py,test_encoder_convention.pyandtest_set_7dof_motor_registers.py. test_urdf_mjcf_alignment.py, its posed twin, andtest_robot_variants.pynow cover arms with any number of joints, so both 7-DOF sides run through the generic suites.
Verification
ruff_CIandunit_tests_CIpass on this commit.