New Feetech calibration (#859)

Co-authored-by: Pepijn <pepijn@huggingface.co>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Simon Alibert
2025-03-14 11:31:23 +01:00
committed by GitHub
parent ce63cfdb25
commit 1f7ddc1d76
25 changed files with 529 additions and 795 deletions
+22 -23
View File
@@ -26,37 +26,37 @@ from lerobot.common.errors import DeviceAlreadyConnectedError, DeviceNotConnecte
from lerobot.common.motors.feetech import (
FeetechMotorsBus,
TorqueMode,
run_arm_manual_calibration,
apply_feetech_offsets_from_calibration,
run_full_arm_calibration,
)
from ..robot import Robot
from ..utils import ensure_safe_goal_position
from .configuration_so100 import So100RobotConfig
from .configuration_so100 import SO100RobotConfig
class So100Robot(Robot):
class SO100Robot(Robot):
"""
[SO-100 Arm](https://github.com/TheRobotStudio/SO-ARM100) designed by TheRobotStudio
[SO-100 Follower Arm](https://github.com/TheRobotStudio/SO-ARM100) designed by TheRobotStudio
"""
config_class = So100RobotConfig
name = "koch"
config_class = SO100RobotConfig
name = "so100"
def __init__(self, config: So100RobotConfig):
def __init__(self, config: SO100RobotConfig):
super().__init__(config)
self.config = config
self.robot_type = config.type
self.id = config.id
self.arm = FeetechMotorsBus(
port=self.config.port,
motors={
"shoulder_pan": config.shoulder_pan,
"shoulder_lift": config.shoulder_lift,
"elbow_flex": config.elbow_flex,
"wrist_flex": config.wrist_flex,
"wrist_roll": config.wrist_roll,
"gripper": config.gripper,
"shoulder_pan": (1, "sts3215"),
"shoulder_lift": (2, "sts3215"),
"elbow_flex": (3, "sts3215"),
"wrist_flex": (4, "sts3215"),
"wrist_roll": (5, "sts3215"),
"gripper": (6, "sts3215"),
},
)
self.cameras = make_cameras_from_configs(config.cameras)
@@ -133,22 +133,21 @@ class So100Robot(Robot):
Rotations are expressed in degrees in nominal range of [-180, 180],
and linear motions (like gripper of Aloha) in nominal range of [0, 100].
"""
arm_calib_path = self.calibration_dir / f"{self.config.id}.json"
if arm_calib_path.exists():
with open(arm_calib_path) as f:
if self.calibration_fpath.exists():
with open(self.calibration_fpath) as f:
calibration = json.load(f)
else:
# TODO(rcadene): display a warning in __init__ if calibration file not available
logging.info(f"Missing calibration file '{arm_calib_path}'")
calibration = run_arm_manual_calibration(self.arm, self.robot_type, self.name, "follower")
logging.info(f"Missing calibration file '{self.calibration_fpath}'")
calibration = run_full_arm_calibration(self.arm, self.robot_type, self.name, "follower")
logging.info(f"Calibration is done! Saving calibration file '{arm_calib_path}'")
arm_calib_path.parent.mkdir(parents=True, exist_ok=True)
with open(arm_calib_path, "w") as f:
logging.info(f"Calibration is done! Saving calibration file '{self.calibration_fpath}'")
self.calibration_fpath.parent.mkdir(parents=True, exist_ok=True)
with open(self.calibration_fpath, "w") as f:
json.dump(calibration, f)
self.arm.set_calibration(calibration)
apply_feetech_offsets_from_calibration(self.arm, calibration)
def get_observation(self) -> dict[str, np.ndarray]:
"""The returned observations do not have a batch dimension."""