Skip to content

Commit 8ea9f68

Browse files
Add per-robot joint offset calibration to actions (#100)
## Notes This PR adds `--robot.joint-offsets-deg` parameter for per-robot motor calibration offsets applied to `lowcmd` (action space) without affecting observations, matching the approach done by Unitree with their built-in locomotion policy and the offsets Unitree Explore App. The new option defaults to None (zero offsets), so existing behavior is unchanged. ## Example usage ``` python -m holosoma_inference.run_policy inference:g1-29dof-loco (...) --robot.joint-offsets-deg '[1.5, 0.0, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]' ```
1 parent 9ca129e commit 8ea9f68

2 files changed

Lines changed: 18 additions & 1 deletion

File tree

  • src/holosoma_inference/holosoma_inference

src/holosoma_inference/holosoma_inference/config/config_types/robot.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,15 @@ class RobotConfig:
222222

223223
num_upper_body_joints: int = 14
224224
"""Number of upper body degrees of freedom."""
225+
226+
# =========================================================================
227+
# Per-Robot Calibration
228+
# =========================================================================
229+
230+
joint_offsets_deg: tuple[float, ...] | None = None
231+
"""Per-joint offsets in degrees applied to lowcmd (action-space only).
232+
233+
These offsets correct for per-robot motor calibration differences without
234+
affecting the observation/state space. Converted to radians at init time.
235+
Length must equal num_joints when provided.
236+
"""

src/holosoma_inference/holosoma_inference/policies/base.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ def _init_robot_config(self, robot_config: RobotConfig):
7373
self.num_dofs = self.robot_config.num_joints
7474
self.default_dof_angles = np.array(self.robot_config.default_dof_angles)
7575
self.num_upper_dofs = robot_config.num_upper_body_joints
76+
77+
# Per-robot joint offsets (action-space calibration, does not affect observations)
78+
offsets_deg = robot_config.joint_offsets_deg
79+
self.joint_offsets = np.deg2rad(offsets_deg) if offsets_deg is not None else np.zeros(self.num_dofs)
80+
7681
# Setup dof names and indices
7782
self._setup_dof_mappings()
7883

@@ -690,7 +695,7 @@ def policy_action(self):
690695
q_target = scaled_policy_action + self.default_dof_angles
691696

692697
# Prepare command (reuse pre-allocated arrays)
693-
self.cmd_q[:] = q_target
698+
self.cmd_q[:] = q_target[0] + self.joint_offsets
694699

695700
# Stage 5: Action Pub
696701
with self.latency_tracker.measure("action_pub"):

0 commit comments

Comments
 (0)