mirror of
https://github.com/huggingface/lerobot.git
synced 2026-07-30 21:19:40 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d788abd85 | |||
| 7b78e751a6 |
@@ -142,11 +142,25 @@ class SOFollower(Robot):
|
|||||||
range_mins[full_turn_motor] = 0
|
range_mins[full_turn_motor] = 0
|
||||||
range_maxes[full_turn_motor] = 4095
|
range_maxes[full_turn_motor] = 4095
|
||||||
|
|
||||||
|
drive_modes = dict.fromkeys(self.bus.motors, 0)
|
||||||
|
input(f"Fully close the gripper of {self} and press ENTER....")
|
||||||
|
gripper_closed_pos = self.bus.read(
|
||||||
|
"Present_Position", "gripper", normalize=False, num_retry=self.config.num_read_retries
|
||||||
|
)
|
||||||
|
distance_to_min = abs(gripper_closed_pos - range_mins["gripper"])
|
||||||
|
distance_to_max = abs(gripper_closed_pos - range_maxes["gripper"])
|
||||||
|
if min(distance_to_min, distance_to_max) > (range_maxes["gripper"] - range_mins["gripper"]) * 0.2:
|
||||||
|
raise ValueError("Gripper is not fully closed. Run calibration again.")
|
||||||
|
|
||||||
|
drive_modes["gripper"] = int(distance_to_max < distance_to_min)
|
||||||
|
if drive_modes["gripper"]:
|
||||||
|
logger.info("Gripper motor is inverted, setting drive_mode=1 to compensate.")
|
||||||
|
|
||||||
self.calibration = {}
|
self.calibration = {}
|
||||||
for motor, m in self.bus.motors.items():
|
for motor, m in self.bus.motors.items():
|
||||||
self.calibration[motor] = MotorCalibration(
|
self.calibration[motor] = MotorCalibration(
|
||||||
id=m.id,
|
id=m.id,
|
||||||
drive_mode=0,
|
drive_mode=drive_modes[motor],
|
||||||
homing_offset=homing_offsets[motor],
|
homing_offset=homing_offsets[motor],
|
||||||
range_min=range_mins[motor],
|
range_min=range_mins[motor],
|
||||||
range_max=range_maxes[motor],
|
range_max=range_maxes[motor],
|
||||||
|
|||||||
@@ -110,11 +110,25 @@ class SOLeader(Teleoperator):
|
|||||||
range_mins[full_turn_motor] = 0
|
range_mins[full_turn_motor] = 0
|
||||||
range_maxes[full_turn_motor] = 4095
|
range_maxes[full_turn_motor] = 4095
|
||||||
|
|
||||||
|
drive_modes = dict.fromkeys(self.bus.motors, 0)
|
||||||
|
input(f"Fully close the gripper of {self} and press ENTER....")
|
||||||
|
gripper_closed_pos = self.bus.read(
|
||||||
|
"Present_Position", "gripper", normalize=False, num_retry=self.config.num_read_retries
|
||||||
|
)
|
||||||
|
distance_to_min = abs(gripper_closed_pos - range_mins["gripper"])
|
||||||
|
distance_to_max = abs(gripper_closed_pos - range_maxes["gripper"])
|
||||||
|
if min(distance_to_min, distance_to_max) > (range_maxes["gripper"] - range_mins["gripper"]) * 0.2:
|
||||||
|
raise ValueError("Gripper is not fully closed. Run calibration again.")
|
||||||
|
|
||||||
|
drive_modes["gripper"] = int(distance_to_max < distance_to_min)
|
||||||
|
if drive_modes["gripper"]:
|
||||||
|
logger.info("Gripper motor is inverted, setting drive_mode=1 to compensate.")
|
||||||
|
|
||||||
self.calibration = {}
|
self.calibration = {}
|
||||||
for motor, m in self.bus.motors.items():
|
for motor, m in self.bus.motors.items():
|
||||||
self.calibration[motor] = MotorCalibration(
|
self.calibration[motor] = MotorCalibration(
|
||||||
id=m.id,
|
id=m.id,
|
||||||
drive_mode=0,
|
drive_mode=drive_modes[motor],
|
||||||
homing_offset=homing_offsets[motor],
|
homing_offset=homing_offsets[motor],
|
||||||
range_min=range_mins[motor],
|
range_min=range_mins[motor],
|
||||||
range_max=range_maxes[motor],
|
range_max=range_maxes[motor],
|
||||||
|
|||||||
@@ -149,3 +149,51 @@ def test_configure_writes_position_pid_coefficients():
|
|||||||
bus_mock.write.assert_any_call("P_Coefficient", "shoulder_pan", 32)
|
bus_mock.write.assert_any_call("P_Coefficient", "shoulder_pan", 32)
|
||||||
bus_mock.write.assert_any_call("I_Coefficient", "shoulder_pan", 1)
|
bus_mock.write.assert_any_call("I_Coefficient", "shoulder_pan", 1)
|
||||||
bus_mock.write.assert_any_call("D_Coefficient", "shoulder_pan", 16)
|
bus_mock.write.assert_any_call("D_Coefficient", "shoulder_pan", 16)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"gripper_closed_pos, expected_drive_mode",
|
||||||
|
[
|
||||||
|
(2035, 0), # closed position at range_min -> raw increases when opening -> not inverted
|
||||||
|
(3528, 1), # closed position at range_max -> raw increases when closing -> inverted
|
||||||
|
(2781, None), # not near either end stop -> unsafe to infer
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_calibrate_detects_gripper_drive_mode(follower, gripper_closed_pos, expected_drive_mode):
|
||||||
|
"""Regression test for #3942: the follower gripper can be mounted mirrored with respect to the
|
||||||
|
leader's, in which case its raw position increases when closing. Calibration must detect this
|
||||||
|
and set drive_mode=1 so that normalized values follow the 0=closed/100=open convention."""
|
||||||
|
follower.connect()
|
||||||
|
|
||||||
|
motors = list(follower.bus.motors)
|
||||||
|
follower.bus.set_half_turn_homings.return_value = dict.fromkeys(motors, 0)
|
||||||
|
follower.bus.record_ranges_of_motion.return_value = (
|
||||||
|
dict.fromkeys(motors, 2035),
|
||||||
|
dict.fromkeys(motors, 3528),
|
||||||
|
)
|
||||||
|
follower.bus.read.return_value = gripper_closed_pos
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch("builtins.input", return_value=""),
|
||||||
|
patch.object(type(follower), "_save_calibration", lambda self: None),
|
||||||
|
):
|
||||||
|
follower.calibration = {}
|
||||||
|
if expected_drive_mode is None:
|
||||||
|
with pytest.raises(ValueError, match="Gripper is not fully closed"):
|
||||||
|
follower.calibrate()
|
||||||
|
else:
|
||||||
|
follower.calibrate()
|
||||||
|
|
||||||
|
follower.bus.read.assert_called_with(
|
||||||
|
"Present_Position",
|
||||||
|
"gripper",
|
||||||
|
normalize=False,
|
||||||
|
num_retry=follower.config.num_read_retries,
|
||||||
|
)
|
||||||
|
if expected_drive_mode is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
assert follower.calibration["gripper"].drive_mode == expected_drive_mode
|
||||||
|
for motor in motors:
|
||||||
|
if motor != "gripper":
|
||||||
|
assert follower.calibration[motor].drive_mode == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user