diff --git a/src/lerobot/robots/bi_openarm_follower/bi_openarm_follower.py b/src/lerobot/robots/bi_openarm_follower/bi_openarm_follower.py index c27398278..b6f446d9c 100644 --- a/src/lerobot/robots/bi_openarm_follower/bi_openarm_follower.py +++ b/src/lerobot/robots/bi_openarm_follower/bi_openarm_follower.py @@ -54,6 +54,7 @@ class BiOpenArmFollower(Robot): calibration_dir=config.calibration_dir, port=config.left_arm_config.port, disable_torque_on_disconnect=config.left_arm_config.disable_torque_on_disconnect, + use_velocity_and_torque=config.left_arm_config.use_velocity_and_torque, max_relative_target=config.left_arm_config.max_relative_target, cameras=left_cameras, side=config.left_arm_config.side, @@ -72,6 +73,7 @@ class BiOpenArmFollower(Robot): calibration_dir=config.calibration_dir, port=config.right_arm_config.port, disable_torque_on_disconnect=config.right_arm_config.disable_torque_on_disconnect, + use_velocity_and_torque=config.right_arm_config.use_velocity_and_torque, max_relative_target=config.right_arm_config.max_relative_target, cameras=right_cameras, side=config.right_arm_config.side, diff --git a/src/lerobot/robots/openarm_follower/config_openarm_follower.py b/src/lerobot/robots/openarm_follower/config_openarm_follower.py index 88d81fd50..096ec320f 100644 --- a/src/lerobot/robots/openarm_follower/config_openarm_follower.py +++ b/src/lerobot/robots/openarm_follower/config_openarm_follower.py @@ -66,6 +66,10 @@ class OpenArmFollowerConfigBase: # Whether to disable torque when disconnecting disable_torque_on_disconnect: bool = True + # When True, expose `.vel` and `.torque` per motor in observation features. + # Default False for compatibility with the position-only openarm_mini teleoperator. + use_velocity_and_torque: bool = False + # Safety limit for relative target positions # Set to a positive scalar for all motors, or a dict mapping motor names to limits max_relative_target: float | dict[str, float] | None = None diff --git a/src/lerobot/robots/openarm_follower/openarm_follower.py b/src/lerobot/robots/openarm_follower/openarm_follower.py index 4d1765f07..020f24052 100644 --- a/src/lerobot/robots/openarm_follower/openarm_follower.py +++ b/src/lerobot/robots/openarm_follower/openarm_follower.py @@ -93,8 +93,9 @@ class OpenArmFollower(Robot): features: dict[str, type] = {} for motor in self.bus.motors: features[f"{motor}.pos"] = float - features[f"{motor}.vel"] = float # Add this - features[f"{motor}.torque"] = float # Add this + if self.config.use_velocity_and_torque: + features[f"{motor}.vel"] = float + features[f"{motor}.torque"] = float return features @property @@ -235,8 +236,9 @@ class OpenArmFollower(Robot): for motor in self.bus.motors: state = states.get(motor, {}) obs_dict[f"{motor}.pos"] = state.get("position", 0.0) - obs_dict[f"{motor}.vel"] = state.get("velocity", 0.0) - obs_dict[f"{motor}.torque"] = state.get("torque", 0.0) + if self.config.use_velocity_and_torque: + obs_dict[f"{motor}.vel"] = state.get("velocity", 0.0) + obs_dict[f"{motor}.torque"] = state.get("torque", 0.0) # Capture images from cameras for cam_key, cam in self.cameras.items(): diff --git a/src/lerobot/teleoperators/bi_openarm_leader/bi_openarm_leader.py b/src/lerobot/teleoperators/bi_openarm_leader/bi_openarm_leader.py index 624729c02..2d2c23f9c 100644 --- a/src/lerobot/teleoperators/bi_openarm_leader/bi_openarm_leader.py +++ b/src/lerobot/teleoperators/bi_openarm_leader/bi_openarm_leader.py @@ -49,6 +49,7 @@ class BiOpenArmLeader(Teleoperator): can_data_bitrate=config.left_arm_config.can_data_bitrate, motor_config=config.left_arm_config.motor_config, manual_control=config.left_arm_config.manual_control, + use_velocity_and_torque=config.left_arm_config.use_velocity_and_torque, position_kd=config.left_arm_config.position_kd, position_kp=config.left_arm_config.position_kp, ) @@ -63,6 +64,7 @@ class BiOpenArmLeader(Teleoperator): can_data_bitrate=config.right_arm_config.can_data_bitrate, motor_config=config.right_arm_config.motor_config, manual_control=config.right_arm_config.manual_control, + use_velocity_and_torque=config.right_arm_config.use_velocity_and_torque, position_kd=config.right_arm_config.position_kd, position_kp=config.right_arm_config.position_kp, ) diff --git a/src/lerobot/teleoperators/openarm_leader/config_openarm_leader.py b/src/lerobot/teleoperators/openarm_leader/config_openarm_leader.py index 4b12fe730..8e3d480f6 100644 --- a/src/lerobot/teleoperators/openarm_leader/config_openarm_leader.py +++ b/src/lerobot/teleoperators/openarm_leader/config_openarm_leader.py @@ -60,6 +60,10 @@ class OpenArmLeaderConfigBase: # When enabled, motors have torque disabled for manual movement manual_control: bool = True + # When True, expose `.vel` and `.torque` per motor in action features. + # Default False for compatibility with the position-only openarm_mini teleoperator. + use_velocity_and_torque: bool = False + # TODO(Steven, Pepijn): Not used ... ? # MIT control parameters (used when manual_control=False for torque control) # List of 8 values: [joint_1, joint_2, joint_3, joint_4, joint_5, joint_6, joint_7, gripper] diff --git a/src/lerobot/teleoperators/openarm_leader/openarm_leader.py b/src/lerobot/teleoperators/openarm_leader/openarm_leader.py index 65da7416a..a82ad26af 100644 --- a/src/lerobot/teleoperators/openarm_leader/openarm_leader.py +++ b/src/lerobot/teleoperators/openarm_leader/openarm_leader.py @@ -70,8 +70,9 @@ class OpenArmLeader(Teleoperator): features: dict[str, type] = {} for motor in self.bus.motors: features[f"{motor}.pos"] = float - features[f"{motor}.vel"] = float - features[f"{motor}.torque"] = float + if self.config.use_velocity_and_torque: + features[f"{motor}.vel"] = float + features[f"{motor}.torque"] = float return features @property @@ -201,8 +202,9 @@ class OpenArmLeader(Teleoperator): for motor in self.bus.motors: state = states.get(motor, {}) action_dict[f"{motor}.pos"] = state.get("position") - action_dict[f"{motor}.vel"] = state.get("velocity") - action_dict[f"{motor}.torque"] = state.get("torque") + if self.config.use_velocity_and_torque: + action_dict[f"{motor}.vel"] = state.get("velocity") + action_dict[f"{motor}.torque"] = state.get("torque") dt_ms = (time.perf_counter() - start) * 1e3 logger.debug(f"{self} read state: {dt_ms:.1f}ms")