diff --git a/lerobot/common/robots/lekiwi/README.md b/lerobot/common/robots/lekiwi/README.md index 215419e1..0077d2d8 100644 --- a/lerobot/common/robots/lekiwi/README.md +++ b/lerobot/common/robots/lekiwi/README.md @@ -1,3 +1,5 @@ +# TODO(Steven): Update README + # Using the [LeKiwi](https://github.com/SIGRobotics-UIUC/LeKiwi) Robot with LeRobot ## Table of Contents diff --git a/lerobot/common/robots/lekiwi/configuration_daemon_lekiwi.py b/lerobot/common/robots/lekiwi/configuration_daemon_lekiwi.py index 42d77cd3..c25d8b35 100644 --- a/lerobot/common/robots/lekiwi/configuration_daemon_lekiwi.py +++ b/lerobot/common/robots/lekiwi/configuration_daemon_lekiwi.py @@ -1,3 +1,17 @@ +# Copyright 2024 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from dataclasses import dataclass, field from lerobot.common.robots.config import RobotConfig diff --git a/lerobot/common/robots/lekiwi/configuration_lekiwi.py b/lerobot/common/robots/lekiwi/configuration_lekiwi.py index 3b8fe5d4..a112ae8b 100644 --- a/lerobot/common/robots/lekiwi/configuration_lekiwi.py +++ b/lerobot/common/robots/lekiwi/configuration_lekiwi.py @@ -1,3 +1,17 @@ +# Copyright 2024 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from dataclasses import dataclass, field from lerobot.common.cameras.configs import CameraConfig diff --git a/lerobot/common/robots/lekiwi/daemon_lekiwi.py b/lerobot/common/robots/lekiwi/daemon_lekiwi.py index e89a41e6..5962018e 100644 --- a/lerobot/common/robots/lekiwi/daemon_lekiwi.py +++ b/lerobot/common/robots/lekiwi/daemon_lekiwi.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - # Copyright 2024 The HuggingFace Inc. team. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -66,7 +64,7 @@ class DaemonLeKiwiRobot(Robot): self.last_frames = {} self.last_present_speed = [0, 0, 0] - # TODO(Steven): Consider 32 instead + # TODO(Steven): Move everything to 32 instead self.last_remote_arm_state = torch.zeros(6, dtype=torch.float64) # Define three speed levels and a current index @@ -112,6 +110,7 @@ class DaemonLeKiwiRobot(Robot): # TODO(Steven): Get this from the data fetched? # TODO(Steven): Motor names are unknown for the Daemon # Or assume its size/metadata? + # TODO(Steven): Check consistency of image sizes cam_ft = { "front": { "shape": (480, 640, 3), @@ -384,7 +383,7 @@ class DaemonLeKiwiRobot(Robot): frame = np.zeros((480, 640, 3), dtype=np.uint8) obs_dict[cam_name] = torch.from_numpy(frame) - # TODO(Steven): Refactor this ugly thing + # TODO(Steven): Refactor this ugly thing (needed for when there are not comms at init) if OBS_IMAGES + ".wrist" not in obs_dict: obs_dict[OBS_IMAGES + ".wrist"] = np.zeros(shape=(480, 640, 3)) if OBS_IMAGES + ".front" not in obs_dict: @@ -455,7 +454,7 @@ class DaemonLeKiwiRobot(Robot): # TODO(Steven): Not yet implemented. The policy outputs might need a different conversion raise Exception - # TODO(Steven): This assumes teleop mode is always used with keyboard + # TODO(Steven): This assumes teleop mode is always used with keyboard. Tomorrow we could teleop with another device ... ? if self.robot_mode is RobotMode.TELEOP: if action.size < 6: logging.error("Action should include at least the 6 states of the leader arm") @@ -481,7 +480,7 @@ class DaemonLeKiwiRobot(Robot): raise DeviceNotConnectedError( "LeKiwi is not connected. You need to run `robot.connect()` before disconnecting." ) - # TODO(Steven): Consider sending a stop to the remote mobile robot + # TODO(Steven): Consider sending a stop to the remote mobile robot. Although this would need a moore complex comms schema self.zmq_observation_socket.close() self.zmq_cmd_socket.close() self.zmq_context.term() diff --git a/lerobot/common/robots/lekiwi/daemon_lekiwi_app.py b/lerobot/common/robots/lekiwi/daemon_lekiwi_app.py index 241f5b66..47eb2e10 100644 --- a/lerobot/common/robots/lekiwi/daemon_lekiwi_app.py +++ b/lerobot/common/robots/lekiwi/daemon_lekiwi_app.py @@ -1,3 +1,17 @@ +# Copyright 2024 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import logging import numpy as np diff --git a/lerobot/common/robots/lekiwi/lekiwi_app.py b/lerobot/common/robots/lekiwi/lekiwi_app.py index cec214ac..bc720494 100644 --- a/lerobot/common/robots/lekiwi/lekiwi_app.py +++ b/lerobot/common/robots/lekiwi/lekiwi_app.py @@ -1,3 +1,19 @@ +#!/usr/bin/env python + +# Copyright 2024 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import json import logging import time diff --git a/lerobot/common/robots/lekiwi/lekiwi_robot.py b/lerobot/common/robots/lekiwi/lekiwi_robot.py index 09234845..211cefc7 100644 --- a/lerobot/common/robots/lekiwi/lekiwi_robot.py +++ b/lerobot/common/robots/lekiwi/lekiwi_robot.py @@ -37,6 +37,9 @@ from ..utils import ensure_safe_goal_position from .configuration_lekiwi import LeKiwiRobotConfig +# TODO(Steven): Everything in here is pretty much single-threaded and synchronous. The assumption is that we can run the loop at a +# high enough frequency to not need to worry about threading. This is a good assumption for now, but we should consider +# making this more robust in the future. class LeKiwiRobot(Robot): """ The robot includes a three omniwheel mobile base and a remote follower arm. @@ -111,7 +114,7 @@ class LeKiwiRobot(Robot): # We assume that at connection time, arm is in a rest position, # and torque can be safely disabled to run calibration. self.actuators_bus.write("Torque_Enable", TorqueMode.DISABLED.value, self.arm_actuators) - self.calibrate() # TODO(Steven): This should be only for the arm + self.calibrate() # TODO(Steven): This should be only for the arm, but apparently it doesn't harm the base # Mode=0 for Position Control self.actuators_bus.write("Mode", 0, self.arm_actuators)