Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/lerobot/scripts/lerobot_teleoperate.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
from lerobot.teleoperators import ( # noqa: F401
Teleoperator,
TeleoperatorConfig,
alicia_d_leader,
bi_so100_leader,
gamepad,
homunculus,
Expand Down Expand Up @@ -160,8 +161,11 @@ def teleop_loop(
# Process action for robot through pipeline
robot_action_to_send = robot_action_processor((teleop_action, obs))

# Send processed action to robot (robot_action_processor.to_output should return dict[str, Any])
_ = robot.send_action(robot_action_to_send)
# When the teleoperator controls the robot through a direct hardware
# connection, sending the action again from the computer would duplicate
# the command. Keep processing it for visualization, but skip transmission.
if not teleop.directly_controls_robot:
_ = robot.send_action(robot_action_to_send)

if display_data:
# Process robot observation through pipeline
Expand Down
22 changes: 20 additions & 2 deletions tests/test_control_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from unittest.mock import patch
from unittest.mock import PropertyMock, patch

from lerobot.scripts.lerobot_calibrate import CalibrateConfig, calibrate
from lerobot.processor import make_default_processors
Expand All @@ -23,7 +23,7 @@
from lerobot.scripts.lerobot_teleoperate import TeleoperateConfig, teleoperate
from tests.fixtures.constants import DUMMY_REPO_ID
from tests.mocks.mock_robot import MockRobot, MockRobotConfig
from tests.mocks.mock_teleop import MockTeleopConfig
from tests.mocks.mock_teleop import MockTeleop, MockTeleopConfig


def test_calibrate():
Expand All @@ -43,6 +43,24 @@ def test_teleoperate():
teleoperate(cfg)


def test_teleoperate_skips_send_action_when_teleop_directly_controls_robot():
robot_cfg = MockRobotConfig()
teleop_cfg = MockTeleopConfig()
cfg = TeleoperateConfig(
robot=robot_cfg,
teleop=teleop_cfg,
teleop_time_s=0.1,
)

with (
patch.object(MockTeleop, "directly_controls_robot", new_callable=PropertyMock, return_value=True),
patch.object(MockRobot, "send_action", autospec=True) as mock_send_action,
):
teleoperate(cfg)

mock_send_action.assert_not_called()


def test_record_and_resume(tmp_path):
robot_cfg = MockRobotConfig()
teleop_cfg = MockTeleopConfig()
Expand Down