diff --git a/lerobot/common/robot_devices/robots/configs.py b/lerobot/common/robot_devices/robots/configs.py index fec5da16..4ead591a 100644 --- a/lerobot/common/robot_devices/robots/configs.py +++ b/lerobot/common/robot_devices/robots/configs.py @@ -685,3 +685,61 @@ class TrossenAIBimanualRobotConfig(ManipulatorRobotConfig): ) mock: bool = False + + +@RobotConfig.register_subclass("trossen_ai_solo") +@dataclass +class TrossenAISoloRobotConfig(ManipulatorRobotConfig): + + # /!\ FOR SAFETY, READ THIS /!\ + # `max_relative_target` limits the magnitude of the relative positional target vector for safety purposes. + # Set this to a positive scalar to have the same value for all motors, or a list that is the same length as + # the number of motors in your follower arms. + # For Trossen AI Arms, for every goal position request, motor rotations are capped at 5 degrees by default. + # When you feel more confident with teleoperation or running the policy, you can extend + # this safety limit and even removing it by setting it to `null`. + # Also, everything is expected to work safely out-of-the-box, but we highly advise to + # first try to teleoperate the grippers only (by commenting out the rest of the motors in this yaml), + # then to gradually add more motors (by uncommenting), until you can teleoperate both arms fully + max_relative_target: int | None = 5 + + leader_arms: dict[str, MotorsBusConfig] = field( + default_factory=lambda: { + "main": TrossenArmDriverConfig( + # wxai + ip="192.168.1.2", + model="V0_LEADER", + ), + } + ) + + follower_arms: dict[str, MotorsBusConfig] = field( + default_factory=lambda: { + "main": TrossenArmDriverConfig( + ip="192.168.1.3", + model="V0_FOLLOWER", + ), + } + ) + + # Troubleshooting: If one of your IntelRealSense cameras freeze during + # data recording due to bandwidth limit, you might need to plug the camera + # on another USB hub or PCIe card. + cameras: dict[str, CameraConfig] = field( + default_factory=lambda: { + "cam_high": IntelRealSenseCameraConfig( + serial_number=130322270184, + fps=30, + width=640, + height=480, + ), + "cam_left_wrist": IntelRealSenseCameraConfig( + serial_number=218622274938, + fps=30, + width=640, + height=480, + ), + } + ) + + mock: bool = False diff --git a/lerobot/common/robot_devices/robots/manipulator.py b/lerobot/common/robot_devices/robots/manipulator.py index 4d7da54e..fa949965 100644 --- a/lerobot/common/robot_devices/robots/manipulator.py +++ b/lerobot/common/robot_devices/robots/manipulator.py @@ -160,7 +160,7 @@ class ManipulatorRobot: ): self.config = config self.robot_type = self.config.type - if not self.robot_type =="trossen_ai_bimanual": + if not self.robot_type in ["trossen_ai_bimanual", "trosssen_ai_solo"]: self.calibration_dir = Path(self.config.calibration_dir) self.leader_arms = make_motors_buses_from_configs(self.config.leader_arms) self.follower_arms = make_motors_buses_from_configs(self.config.follower_arms) @@ -224,7 +224,7 @@ class ManipulatorRobot: return available_arms def teleop_safety_stop(self): - if self.robot_type in ["trossen_ai_bimanual"]: + if self.robot_type in ["trossen_ai_bimanual", "trossen_ai_solo"]: for arms in self.follower_arms: self.follower_arms[arms].write("Reset", 1) self.follower_arms[arms].write("Torque_Enable", 1) @@ -251,7 +251,7 @@ class ManipulatorRobot: print(f"Connecting {name} leader arm.") self.leader_arms[name].connect() - if self.robot_type in ["koch", "koch_bimanual", "aloha", "trossen_ai_bimanual"]: + if self.robot_type in ["koch", "koch_bimanual", "aloha", "trossen_ai_bimanual", "trossen_ai_solo"]: from lerobot.common.robot_devices.motors.dynamixel import TorqueMode elif self.robot_type in ["so100", "moss", "lekiwi"]: from lerobot.common.robot_devices.motors.feetech import TorqueMode @@ -263,7 +263,7 @@ class ManipulatorRobot: for name in self.leader_arms: self.leader_arms[name].write("Torque_Enable", TorqueMode.DISABLED.value) - if not self.robot_type == "trossen_ai_bimanual": + if not self.robot_type in ["trossen_ai_bimanual", "trossen_ai_solo"]: print("Checking if calibration is needed.") self.activate_calibration() diff --git a/lerobot/common/robot_devices/robots/utils.py b/lerobot/common/robot_devices/robots/utils.py index c27f85a1..f5e537e4 100644 --- a/lerobot/common/robot_devices/robots/utils.py +++ b/lerobot/common/robot_devices/robots/utils.py @@ -25,6 +25,7 @@ from lerobot.common.robot_devices.robots.configs import ( So100RobotConfig, StretchRobotConfig, TrossenAIBimanualRobotConfig, + TrossenAISoloRobotConfig, ) @@ -65,6 +66,8 @@ def make_robot_config(robot_type: str, **kwargs) -> RobotConfig: return LeKiwiRobotConfig(**kwargs) elif robot_type == "trossen_ai_bimanual": return TrossenAIBimanualRobotConfig(**kwargs) + elif robot_type == "trossen_ai_solo": + return TrossenAISoloRobotConfig(**kwargs) else: raise ValueError(f"Robot type '{robot_type}' is not available.")