Rename Lekiwi files & classes

This commit is contained in:
Simon Alibert 2025-04-04 11:44:35 +02:00 committed by Steven Palma
parent 6b4931b4f0
commit 7dedbeb457
No known key found for this signature in database
9 changed files with 45 additions and 47 deletions

View File

@ -196,11 +196,11 @@ sudo chmod 666 /dev/ttyACM1
#### d. Update config file #### d. Update config file
IMPORTANTLY: Now that you have your ports of leader and follower arm and ip address of the mobile-so100, update the **ip** in Network configuration, **port** in leader_arms and **port** in lekiwi. In the [`LeKiwiRobotConfig`](../lerobot/common/robot_devices/robots/configs.py) file. Where you will find something like: IMPORTANTLY: Now that you have your ports of leader and follower arm and ip address of the mobile-so100, update the **ip** in Network configuration, **port** in leader_arms and **port** in lekiwi. In the [`LeKiwiConfig`](../lerobot/common/robot_devices/robots/configs.py) file. Where you will find something like:
```python ```python
@RobotConfig.register_subclass("lekiwi") @RobotConfig.register_subclass("lekiwi")
@dataclass @dataclass
class LeKiwiRobotConfig(RobotConfig): class LeKiwiConfig(RobotConfig):
# `max_relative_target` limits the magnitude of the relative positional target vector for safety purposes. # `max_relative_target` limits the magnitude of the relative positional target vector for safety purposes.
# Set this to a positive scalar to have the same value for all motors, or a list that is the same length as # Set this to a positive scalar to have the same value for all motors, or a list that is the same length as
# the number of motors in your follower arms. # the number of motors in your follower arms.
@ -283,7 +283,7 @@ For the wired LeKiwi version your configured IP address should refer to your own
```python ```python
@RobotConfig.register_subclass("lekiwi") @RobotConfig.register_subclass("lekiwi")
@dataclass @dataclass
class LeKiwiRobotConfig(RobotConfig): class LeKiwiConfig(RobotConfig):
# `max_relative_target` limits the magnitude of the relative positional target vector for safety purposes. # `max_relative_target` limits the magnitude of the relative positional target vector for safety purposes.
# Set this to a positive scalar to have the same value for all motors, or a list that is the same length as # Set this to a positive scalar to have the same value for all motors, or a list that is the same length as
# the number of motors in your follower arms. # the number of motors in your follower arms.
@ -448,7 +448,7 @@ You should see on your laptop something like this: ```[INFO] Connected to remote
| F | Decrease speed | | F | Decrease speed |
> [!TIP] > [!TIP]
> If you use a different keyboard you can change the keys for each command in the [`LeKiwiRobotConfig`](../lerobot/common/robot_devices/robots/configs.py). > If you use a different keyboard you can change the keys for each command in the [`LeKiwiConfig`](../lerobot/common/robot_devices/robots/configs.py).
### Wired version ### Wired version
If you have the **wired** LeKiwi version please run all commands including both these teleoperation commands on your laptop. If you have the **wired** LeKiwi version please run all commands including both these teleoperation commands on your laptop.

View File

@ -21,7 +21,7 @@ from lerobot.common.robots.config import RobotConfig
@RobotConfig.register_subclass("lekiwi") @RobotConfig.register_subclass("lekiwi")
@dataclass @dataclass
class LeKiwiRobotConfig(RobotConfig): class LeKiwiConfig(RobotConfig):
port = "/dev/ttyACM0" # port to connect to the bus port = "/dev/ttyACM0" # port to connect to the bus
disable_torque_on_disconnect: bool = True disable_torque_on_disconnect: bool = True

View File

@ -17,9 +17,9 @@ from dataclasses import dataclass, field
from lerobot.common.robots.config import RobotConfig from lerobot.common.robots.config import RobotConfig
@RobotConfig.register_subclass("daemon_lekiwi") @RobotConfig.register_subclass("lekiwi_client")
@dataclass @dataclass
class DaemonLeKiwiRobotConfig(RobotConfig): class LeKiwiClientConfig(RobotConfig):
# Network Configuration # Network Configuration
remote_ip: str = "172.18.133.90" remote_ip: str = "172.18.133.90"
port_zmq_cmd: int = 5555 port_zmq_cmd: int = 5555

View File

@ -32,12 +32,12 @@ from lerobot.common.motors.feetech import (
from ..robot import Robot from ..robot import Robot
from ..utils import ensure_safe_goal_position from ..utils import ensure_safe_goal_position
from .configuration_lekiwi import LeKiwiRobotConfig from .config_lekiwi import LeKiwiConfig
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class LeKiwiRobot(Robot): class LeKiwi(Robot):
""" """
The robot includes a three omniwheel mobile base and a remote follower arm. The robot includes a three omniwheel mobile base and a remote follower arm.
The leader arm is connected locally (on the laptop) and its joint positions are recorded and then The leader arm is connected locally (on the laptop) and its joint positions are recorded and then
@ -45,10 +45,10 @@ class LeKiwiRobot(Robot):
In parallel, keyboard teleoperation is used to generate raw velocity commands for the wheels. In parallel, keyboard teleoperation is used to generate raw velocity commands for the wheels.
""" """
config_class = LeKiwiRobotConfig config_class = LeKiwiConfig
name = "lekiwi" name = "lekiwi"
def __init__(self, config: LeKiwiRobotConfig): def __init__(self, config: LeKiwiConfig):
super().__init__(config) super().__init__(config)
self.config = config self.config = config
self.id = config.id self.id = config.id

View File

@ -26,7 +26,7 @@ from lerobot.common.errors import DeviceAlreadyConnectedError, DeviceNotConnecte
from lerobot.common.robots.config import RobotMode from lerobot.common.robots.config import RobotMode
from ..robot import Robot from ..robot import Robot
from .configuration_daemon_lekiwi import DaemonLeKiwiRobotConfig from .configuration_daemon_lekiwi import LeKiwiClientConfig
# TODO(Steven): This doesn't need to inherit from Robot # TODO(Steven): This doesn't need to inherit from Robot
@ -40,11 +40,11 @@ from .configuration_daemon_lekiwi import DaemonLeKiwiRobotConfig
# 2. Adding it into the robot implementation # 2. Adding it into the robot implementation
# (meaning the policy might be needed to be train # (meaning the policy might be needed to be train
# over the teleop action space) # over the teleop action space)
class DaemonLeKiwiRobot(Robot): class LeKiwiClient(Robot):
config_class = DaemonLeKiwiRobotConfig config_class = LeKiwiClientConfig
name = "daemonlekiwi" name = "lekiwi_client"
def __init__(self, config: DaemonLeKiwiRobotConfig): def __init__(self, config: LeKiwiClientConfig):
super().__init__(config) super().__init__(config)
self.config = config self.config = config
self.id = config.id self.id = config.id
@ -150,7 +150,7 @@ class DaemonLeKiwiRobot(Robot):
# TODO(Steven): Nothing to calibrate. # TODO(Steven): Nothing to calibrate.
# Consider triggering calibrate() on the remote mobile robot? # Consider triggering calibrate() on the remote mobile robot?
# Although this would require a more complex comms schema # Although this would require a more complex comms schema
logging.warning("DaemonLeKiwiRobot has nothing to calibrate.") logging.warning("LeKiwiClient has nothing to calibrate.")
return return
# Consider moving these static functions out of the class # Consider moving these static functions out of the class
@ -235,7 +235,7 @@ class DaemonLeKiwiRobot(Robot):
wheel_degps = wheel_degps * scale wheel_degps = wheel_degps * scale
# Convert each wheels angular speed (deg/s) to a raw integer. # Convert each wheels angular speed (deg/s) to a raw integer.
wheel_raw = [DaemonLeKiwiRobot._degps_to_raw(deg) for deg in wheel_degps] wheel_raw = [LeKiwiClient._degps_to_raw(deg) for deg in wheel_degps]
return {"left_wheel": wheel_raw[0], "back_wheel": wheel_raw[1], "right_wheel": wheel_raw[2]} return {"left_wheel": wheel_raw[0], "back_wheel": wheel_raw[1], "right_wheel": wheel_raw[2]}
@ -259,7 +259,7 @@ class DaemonLeKiwiRobot(Robot):
""" """
# Convert each raw command back to an angular speed in deg/s. # Convert each raw command back to an angular speed in deg/s.
wheel_degps = np.array([DaemonLeKiwiRobot._raw_to_degps(int(r)) for r in wheel_raw]) wheel_degps = np.array([LeKiwiClient._raw_to_degps(int(r)) for r in wheel_raw])
# Convert from deg/s to rad/s. # Convert from deg/s to rad/s.
wheel_radps = wheel_degps * (np.pi / 180.0) wheel_radps = wheel_degps * (np.pi / 180.0)
# Compute each wheels linear speed (m/s) from its angular speed. # Compute each wheels linear speed (m/s) from its angular speed.
@ -352,7 +352,7 @@ class DaemonLeKiwiRobot(Robot):
return (self.last_frames, self.last_present_speed, self.last_remote_arm_state) return (self.last_frames, self.last_present_speed, self.last_remote_arm_state)
return frames, present_speed, remote_arm_state_tensor return frames, present_speed, remote_arm_state_tensor
# TODO(Steven): The returned space is different from the get_observation of LeKiwiRobot # TODO(Steven): The returned space is different from the get_observation of LeKiwi
# This returns body-frames velocities instead of wheel pos/speeds # This returns body-frames velocities instead of wheel pos/speeds
def get_observation(self) -> dict[str, np.ndarray]: def get_observation(self) -> dict[str, np.ndarray]:
""" """
@ -361,9 +361,7 @@ class DaemonLeKiwiRobot(Robot):
and a camera frame. Receives over ZMQ, translate to body-frame vel and a camera frame. Receives over ZMQ, translate to body-frame vel
""" """
if not self.is_connected: if not self.is_connected:
raise DeviceNotConnectedError( raise DeviceNotConnectedError("LeKiwiClient is not connected. You need to run `robot.connect()`.")
"DaemonLeKiwiRobot is not connected. You need to run `robot.connect()`."
)
obs_dict = {} obs_dict = {}

View File

@ -18,8 +18,8 @@ import numpy as np
from lerobot.common.datasets.lerobot_dataset import LeRobotDataset from lerobot.common.datasets.lerobot_dataset import LeRobotDataset
from lerobot.common.robots.config import RobotMode from lerobot.common.robots.config import RobotMode
from lerobot.common.robots.lekiwi.configuration_daemon_lekiwi import DaemonLeKiwiRobotConfig from lerobot.common.robots.lekiwi.configuration_daemon_lekiwi import LeKiwiClientConfig
from lerobot.common.robots.lekiwi.daemon_lekiwi import DaemonLeKiwiRobot from lerobot.common.robots.lekiwi.lekiwi_client import LeKiwiClient
from lerobot.common.teleoperators.keyboard import KeyboardTeleop, KeyboardTeleopConfig from lerobot.common.teleoperators.keyboard import KeyboardTeleop, KeyboardTeleopConfig
from lerobot.common.teleoperators.so100 import SO100Teleop, SO100TeleopConfig from lerobot.common.teleoperators.so100 import SO100Teleop, SO100TeleopConfig
@ -87,11 +87,11 @@ def main():
keyboard_config = KeyboardTeleopConfig() keyboard_config = KeyboardTeleopConfig()
keyboard = KeyboardTeleop(keyboard_config) keyboard = KeyboardTeleop(keyboard_config)
logging.info("Configuring LeKiwiRobot Daemon") logging.info("Configuring LeKiwi Client")
robot_config = DaemonLeKiwiRobotConfig( robot_config = LeKiwiClientConfig(
id="daemonlekiwi", calibration_dir=".cache/calibration/lekiwi", robot_mode=RobotMode.TELEOP id="daemonlekiwi", calibration_dir=".cache/calibration/lekiwi", robot_mode=RobotMode.TELEOP
) )
robot = DaemonLeKiwiRobot(robot_config) robot = LeKiwiClient(robot_config)
logging.info("Creating LeRobot Dataset") logging.info("Creating LeRobot Dataset")
@ -106,10 +106,10 @@ def main():
leader_arm.connect() leader_arm.connect()
keyboard.connect() keyboard.connect()
logging.info("Connecting remote LeKiwiRobot") logging.info("Connecting remote LeKiwi")
robot.connect() robot.connect()
logging.info("Starting LeKiwiRobot teleoperation") logging.info("Starting LeKiwi teleoperation")
i = 0 i = 0
while i < 1000: while i < 1000:
arm_action = leader_arm.get_action() arm_action = leader_arm.get_action()
@ -135,11 +135,11 @@ def main():
dataset.save_episode() dataset.save_episode()
# dataset.push_to_hub() # dataset.push_to_hub()
logging.info("Disconnecting Teleop Devices and LeKiwiRobot Daemon") logging.info("Disconnecting Teleop Devices and LeKiwi Client")
robot.disconnect() robot.disconnect()
leader_arm.disconnect() leader_arm.disconnect()
keyboard.disconnect() keyboard.disconnect()
logging.info("Finished LeKiwiRobot cleanly") logging.info("Finished LeKiwi cleanly")
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -22,15 +22,15 @@ import numpy as np
import zmq import zmq
from lerobot.common.constants import OBS_STATE from lerobot.common.constants import OBS_STATE
from lerobot.common.robots.lekiwi.configuration_lekiwi import LeKiwiRobotConfig from lerobot.common.robots.lekiwi.config_lekiwi import LeKiwiConfig
from lerobot.common.robots.lekiwi.lekiwi_robot import LeKiwiRobot from lerobot.common.robots.lekiwi.lekiwi import LeKiwi
# Network Configuration # Network Configuration
PORT_ZMQ_CMD: int = 5555 PORT_ZMQ_CMD: int = 5555
PORT_ZMQ_OBSERVATIONS: int = 5556 PORT_ZMQ_OBSERVATIONS: int = 5556
class RemoteAgent: class HostAgent:
def __init__(self): def __init__(self):
self.zmq_context = zmq.Context() self.zmq_context = zmq.Context()
self.zmq_cmd_socket = self.zmq_context.socket(zmq.PULL) self.zmq_cmd_socket = self.zmq_context.socket(zmq.PULL)
@ -48,15 +48,15 @@ class RemoteAgent:
def main(): def main():
logging.info("Configuring LeKiwiRobot") logging.info("Configuring LeKiwi")
robot_config = LeKiwiRobotConfig() robot_config = LeKiwiConfig()
robot = LeKiwiRobot(robot_config) robot = LeKiwi(robot_config)
logging.info("Connecting LeKiwiRobot") logging.info("Connecting LeKiwi")
robot.connect() robot.connect()
logging.info("Starting RemoteAgent") logging.info("Starting HostAgent")
remote_agent = RemoteAgent() remote_agent = HostAgent()
last_cmd_time = time.time() last_cmd_time = time.time()
logging.info("Waiting for commands...") logging.info("Waiting for commands...")
@ -101,7 +101,7 @@ def main():
robot.disconnect() robot.disconnect()
remote_agent.disconnect() remote_agent.disconnect()
logging.info("Finished LeKiwiRobot cleanly") logging.info("Finished LeKiwi cleanly")
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -49,22 +49,22 @@ def make_robot_config(robot_type: str, **kwargs) -> RobotConfig:
return Stretch3RobotConfig(**kwargs) return Stretch3RobotConfig(**kwargs)
elif robot_type == "lekiwi": elif robot_type == "lekiwi":
from .lekiwi.configuration_lekiwi import LeKiwiRobotConfig from .lekiwi.config_lekiwi import LeKiwiConfig
return LeKiwiRobotConfig(**kwargs) return LeKiwiConfig(**kwargs)
else: else:
raise ValueError(f"Robot type '{robot_type}' is not available.") raise ValueError(f"Robot type '{robot_type}' is not available.")
def make_robot_from_config(config: RobotConfig): def make_robot_from_config(config: RobotConfig):
from .lekiwi.configuration_lekiwi import LeKiwiRobotConfig from .lekiwi.config_lekiwi import LeKiwiConfig
from .manipulator import ManipulatorRobotConfig from .manipulator import ManipulatorRobotConfig
if isinstance(config, ManipulatorRobotConfig): if isinstance(config, ManipulatorRobotConfig):
from lerobot.common.robots.manipulator import ManipulatorRobot from lerobot.common.robots.manipulator import ManipulatorRobot
return ManipulatorRobot(config) return ManipulatorRobot(config)
elif isinstance(config, LeKiwiRobotConfig): elif isinstance(config, LeKiwiConfig):
from lerobot.common.robots.mobile_manipulator import MobileManipulator from lerobot.common.robots.mobile_manipulator import MobileManipulator
return MobileManipulator(config) return MobileManipulator(config)

View File

@ -21,7 +21,7 @@ def main():
i += 1 i += 1
keyboard.disconnect() keyboard.disconnect()
logging.info("Finished LeKiwiRobot cleanly") logging.info("Finished LeKiwi cleanly")
if __name__ == "__main__": if __name__ == "__main__":