Rename Lekiwi files & classes
This commit is contained in:
parent
6b4931b4f0
commit
7dedbeb457
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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 wheel’s angular speed (deg/s) to a raw integer.
|
# Convert each wheel’s 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 wheel’s linear speed (m/s) from its angular speed.
|
# Compute each wheel’s 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 = {}
|
||||||
|
|
|
@ -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__":
|
|
@ -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__":
|
|
@ -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)
|
||||||
|
|
|
@ -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__":
|
||||||
|
|
Loading…
Reference in New Issue