mirror of
https://github.com/huggingface/lerobot.git
synced 2026-08-04 23:49:49 +00:00
fix(robots): retry LeKiwi bus reads on transient Feetech errors (#4283)
Same fix as #4207 (SO follower/leader), applied to LeKiwi, which reads its motors through the same Feetech bus and had the same gap: `sync_read` was called without `num_retry`, so a single corrupted status packet raised ConnectionError and took the control loop down. Adds `num_read_retries` (default 2, matching #4207) to LeKiwiConfig and forwards it at all three read sites. Two of them are Present_Position, as in #4207; the third is the Present_Velocity read of the omniwheel base, which is LeKiwi-specific and is where this was observed in the field: File "lerobot/robots/lekiwi/lekiwi.py", line 351, in get_observation base_wheel_vel = self.bus.sync_read("Present_Velocity", self.base_motors) ConnectionError: Failed to sync read 'Present_Velocity' on ids=[7, 8, 9] after 1 tries. [TxRxResult] There is no status packet! All nine servos pinged 20/20 with the bus idle immediately afterwards, so this is transient corruption under load rather than a wiring fault. Relates to #4207. Refs #3131.
This commit is contained in:
@@ -58,6 +58,12 @@ class LeKiwiConfig(RobotConfig):
|
||||
# Set to `True` for backward compatibility with previous policies/dataset
|
||||
use_degrees: bool = True
|
||||
|
||||
# Number of extra attempts when a `sync_read` of the motors fails. Feetech buses can occasionally
|
||||
# return a corrupted status packet ("Incorrect status packet!"), especially when several joints move
|
||||
# at once, which otherwise aborts the control loop. Retries are immediate (no sleep) and only happen on
|
||||
# failure, so the steady-state read cost is unchanged.
|
||||
num_read_retries: int = 2
|
||||
|
||||
|
||||
@dataclass
|
||||
class LeKiwiHostConfig:
|
||||
|
||||
@@ -347,8 +347,12 @@ class LeKiwi(Robot):
|
||||
def get_observation(self) -> RobotObservation:
|
||||
# Read actuators position for arm and vel for base
|
||||
start = time.perf_counter()
|
||||
arm_pos = self.bus.sync_read("Present_Position", self.arm_motors)
|
||||
base_wheel_vel = self.bus.sync_read("Present_Velocity", self.base_motors)
|
||||
arm_pos = self.bus.sync_read(
|
||||
"Present_Position", self.arm_motors, num_retry=self.config.num_read_retries
|
||||
)
|
||||
base_wheel_vel = self.bus.sync_read(
|
||||
"Present_Velocity", self.base_motors, num_retry=self.config.num_read_retries
|
||||
)
|
||||
|
||||
base_vel = self._wheel_raw_to_body(
|
||||
base_wheel_vel["base_left_wheel"],
|
||||
@@ -397,7 +401,9 @@ class LeKiwi(Robot):
|
||||
# Cap goal position when too far away from present position.
|
||||
# /!\ Slower fps expected due to reading from the follower.
|
||||
if self.config.max_relative_target is not None:
|
||||
present_pos = self.bus.sync_read("Present_Position", self.arm_motors)
|
||||
present_pos = self.bus.sync_read(
|
||||
"Present_Position", self.arm_motors, num_retry=self.config.num_read_retries
|
||||
)
|
||||
goal_present_pos = {key: (g_pos, present_pos[key]) for key, g_pos in arm_goal_pos.items()}
|
||||
arm_safe_goal_pos = ensure_safe_goal_position(goal_present_pos, self.config.max_relative_target)
|
||||
arm_goal_pos = arm_safe_goal_pos
|
||||
|
||||
Reference in New Issue
Block a user