forked from tangger/lerobot
Fixes on robot integration tutorial (#1290)
This commit is contained in:
@@ -20,7 +20,7 @@ If you're using Feetech or Dynamixel motors, LeRobot provides built-in bus inter
|
|||||||
Please refer to the [`MotorsBus`](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/motors_bus.py) abstract class to learn about its API.
|
Please refer to the [`MotorsBus`](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/motors_bus.py) abstract class to learn about its API.
|
||||||
For a good example of how it can be used, you can have a look at our own [SO101 follower implementation](https://github.com/huggingface/lerobot/blob/main/lerobot/common/robots/so101_follower/so101_follower.py)
|
For a good example of how it can be used, you can have a look at our own [SO101 follower implementation](https://github.com/huggingface/lerobot/blob/main/lerobot/common/robots/so101_follower/so101_follower.py)
|
||||||
|
|
||||||
Use these if compatible! Otherwise, you'll need to find or write a Python interface (not covered in this tutorial):
|
Use these if compatible. Otherwise, you'll need to find or write a Python interface (not covered in this tutorial):
|
||||||
- Find an existing SDK in Python (or use bindings to C/C++)
|
- Find an existing SDK in Python (or use bindings to C/C++)
|
||||||
- Or implement a basic communication wrapper (e.g., via pyserial, socket, or CANopen)
|
- Or implement a basic communication wrapper (e.g., via pyserial, socket, or CANopen)
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ For Feetech and Dynamixel, we currently support these servos:
|
|||||||
- SCS series (protocol 1): `scs0009`
|
- SCS series (protocol 1): `scs0009`
|
||||||
- Dynamixel (protocol 2.0 only): `xl330-m077`, `xl330-m288`, `xl430-w250`, `xm430-w350`, `xm540-w270`, `xc430-w150`
|
- Dynamixel (protocol 2.0 only): `xl330-m077`, `xl330-m288`, `xl430-w250`, `xm430-w350`, `xm540-w270`, `xc430-w150`
|
||||||
|
|
||||||
If you are using Feetech or Dynamixel servos that are not in this list, you can add those in the [Feetech table](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/feetech/tables.py) or [Dynamixel table](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/dynamixel/tables.py). Depending on the model, this will require you to add model-specific information. In most cases though, there should be a lot of additions to do.
|
If you are using Feetech or Dynamixel servos that are not in this list, you can add those in the [Feetech table](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/feetech/tables.py) or [Dynamixel table](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/dynamixel/tables.py). Depending on the model, this will require you to add model-specific information. In most cases though, there shouldn't be a lot of additions to do.
|
||||||
|
|
||||||
In the next sections, we'll use a `FeetechMotorsBus` as the motors interface for the examples. Replace it and adapt to your motors if necessary.
|
In the next sections, we'll use a `FeetechMotorsBus` as the motors interface for the examples. Replace it and adapt to your motors if necessary.
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ def is_connected(self) -> bool:
|
|||||||
|
|
||||||
### `connect()`
|
### `connect()`
|
||||||
|
|
||||||
This method should establish communication with the hardware. Moreover, if your robot needs calibration is not calibrated, it should start a calibration procedure by default. If your robot needs some specific configuration, this should also be called here.
|
This method should establish communication with the hardware. Moreover, if your robot needs calibration and is not calibrated, it should start a calibration procedure by default. If your robot needs some specific configuration, this should also be called here.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def connect(self, calibrate: bool = True) -> None:
|
def connect(self, calibrate: bool = True) -> None:
|
||||||
@@ -272,30 +272,31 @@ Returns a dictionary of sensor values from the robot. These typically include mo
|
|||||||
```python
|
```python
|
||||||
def get_observation(self) -> dict[str, Any]:
|
def get_observation(self) -> dict[str, Any]:
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("Robot is not connected")
|
raise ConnectionError(f"{self} is not connected.")
|
||||||
|
|
||||||
joint_pos = self.motor_interface.read_joint_positions()
|
# Read arm position
|
||||||
gripper = self.motor_interface.read_gripper_state()
|
obs_dict = self.bus.sync_read("Present_Position")
|
||||||
image = self.camera.get_frame()
|
obs_dict = {f"{motor}.pos": val for motor, val in obs_dict.items()}
|
||||||
|
|
||||||
return {
|
# Capture images from cameras
|
||||||
"joint_positions": joint_pos,
|
for cam_key, cam in self.cameras.items():
|
||||||
"gripper_open": gripper,
|
obs_dict[cam_key] = cam.async_read()
|
||||||
"camera_image": image,
|
|
||||||
}
|
return obs_dict
|
||||||
```
|
```
|
||||||
|
|
||||||
### `send_action()`
|
### `send_action()`
|
||||||
|
|
||||||
Takes a dictionary that matches `action_features`, and sends it to your hardware. You can add safety limits (clipping, smoothing) and return what was actually sent.
|
Takes a dictionary that matches `action_features`, and sends it to your hardware. You can add safety limits (clipping, smoothing) and return what was actually sent.
|
||||||
|
|
||||||
|
For simplicity, we won't be adding any modification of the actions in our example here.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def send_action(self, action: dict[str, Any]) -> dict[str, Any]:
|
def send_action(self, action: dict[str, Any]) -> dict[str, Any]:
|
||||||
if not self.is_connected:
|
goal_pos = {key.removesuffix(".pos"): val for key, val in action.items()}
|
||||||
raise RuntimeError("Robot is not connected")
|
|
||||||
|
|
||||||
self.motor_interface.set_joint_positions(action["joint_position_goals"])
|
# Send goal position to the arm
|
||||||
self.motor_interface.set_gripper(action["gripper_command"])
|
self.bus.sync_write("Goal_Position", goal_pos)
|
||||||
|
|
||||||
return action
|
return action
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user