diff --git a/src/lerobot/motors/motors_bus.py b/src/lerobot/motors/motors_bus.py index 4688eaa7f..f4a747b44 100644 --- a/src/lerobot/motors/motors_bus.py +++ b/src/lerobot/motors/motors_bus.py @@ -23,6 +23,7 @@ from __future__ import annotations import abc import logging +import time from collections.abc import Sequence from contextlib import contextmanager from dataclasses import dataclass @@ -818,13 +819,13 @@ class SerialMotorsBus(MotorsBusBase): """ motor_names = self._get_motors_list(motors) - start_positions = self.sync_read("Present_Position", motor_names, normalize=False) + start_positions = self.sync_read("Present_Position", motor_names, normalize=False, num_retry=5) mins = start_positions.copy() maxes = start_positions.copy() user_pressed_enter = False while not user_pressed_enter: - positions = self.sync_read("Present_Position", motor_names, normalize=False) + positions = self.sync_read("Present_Position", motor_names, normalize=False, num_retry=5) mins = {motor: min(positions[motor], min_) for motor, min_ in mins.items()} maxes = {motor: max(positions[motor], max_) for motor, max_ in maxes.items()} @@ -837,9 +838,12 @@ class SerialMotorsBus(MotorsBusBase): if enter_pressed(): user_pressed_enter = True - if display_values and not user_pressed_enter: - # Move cursor up to overwrite the previous output - move_cursor_up(len(motor_names) + 3) + if not user_pressed_enter: + if display_values: + # Move cursor up to overwrite the previous output + move_cursor_up(len(motor_names) + 3) + # Throttle reads even when the live table is disabled. + time.sleep(0.02) same_min_max = [motor for motor in motor_names if mins[motor] == maxes[motor]] if same_min_max: diff --git a/tests/motors/test_dynamixel.py b/tests/motors/test_dynamixel.py index 8b02d4330..9e58ef5e0 100644 --- a/tests/motors/test_dynamixel.py +++ b/tests/motors/test_dynamixel.py @@ -405,12 +405,18 @@ def test_record_ranges_of_motion(mock_motors, dummy_motors): read_pos_stub = mock_motors.build_sequential_sync_read_stub( *X_SERIES_CONTROL_TABLE["Present_Position"], positions ) - with patch("lerobot.motors.motors_bus.enter_pressed", side_effect=[False, True]): - bus = DynamixelMotorsBus(port=mock_motors.port, motors=dummy_motors) - bus.connect(handshake=False) + bus = DynamixelMotorsBus(port=mock_motors.port, motors=dummy_motors) + bus.connect(handshake=False) + with ( + patch("lerobot.motors.motors_bus.enter_pressed", side_effect=[False, True]), + patch("lerobot.motors.motors_bus.time.sleep") as mock_sleep, + patch.object(bus, "sync_read", wraps=bus.sync_read) as mock_sync_read, + ): mins, maxes = bus.record_ranges_of_motion(display_values=False) assert mock_motors.stubs[read_pos_stub].calls == 3 + assert all(call.kwargs["num_retry"] == 5 for call in mock_sync_read.call_args_list) + mock_sleep.assert_called_once_with(0.02) assert mins == expected_mins assert maxes == expected_maxes diff --git a/tests/motors/test_feetech.py b/tests/motors/test_feetech.py index e8cdddbbd..6fc9d684e 100644 --- a/tests/motors/test_feetech.py +++ b/tests/motors/test_feetech.py @@ -509,12 +509,18 @@ def test_record_ranges_of_motion(mock_motors, dummy_motors): stub = mock_motors.build_sequential_sync_read_stub( *STS_SMS_SERIES_CONTROL_TABLE["Present_Position"], positions ) - with patch("lerobot.motors.motors_bus.enter_pressed", side_effect=[False, True]): - bus = FeetechMotorsBus(port=mock_motors.port, motors=dummy_motors) - bus.connect(handshake=False) + bus = FeetechMotorsBus(port=mock_motors.port, motors=dummy_motors) + bus.connect(handshake=False) + with ( + patch("lerobot.motors.motors_bus.enter_pressed", side_effect=[False, True]), + patch("lerobot.motors.motors_bus.time.sleep") as mock_sleep, + patch.object(bus, "sync_read", wraps=bus.sync_read) as mock_sync_read, + ): mins, maxes = bus.record_ranges_of_motion(display_values=False) assert mock_motors.stubs[stub].calls == 3 + assert all(call.kwargs["num_retry"] == 5 for call in mock_sync_read.call_args_list) + mock_sleep.assert_called_once_with(0.02) assert mins == expected_mins assert maxes == expected_maxes