Skip to content

Commit dd97452

Browse files
authored
User/pepijn/2025 01 31 improved tutorial so100 (#666)
1 parent 43e079f commit dd97452

File tree

3 files changed

+108
-32
lines changed

3 files changed

+108
-32
lines changed

examples/10_use_so100.md

Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,91 @@
11
# Using the [SO-100](https://github.com/TheRobotStudio/SO-ARM100) with LeRobot
22

3+
## Table of Contents
4+
5+
- [A. Source the parts](#a-source-the-parts)
6+
- [B. Install LeRobot](#b-install-lerobot)
7+
- [C. Configure the motors](#c-configure-the-motors)
8+
- [D. Assemble the arms](#d-assemble-the-arms)
9+
- [E. Calibrate](#e-calibrate)
10+
- [F. Teleoperate](#f-teleoperate)
11+
- [G. Record a dataset](#g-record-a-dataset)
12+
- [H. Visualize a dataset](#h-visualize-a-dataset)
13+
- [I. Replay an episode](#i-replay-an-episode)
14+
- [J. Train a policy](#j-train-a-policy)
15+
- [K. Evaluate your policy](#k-evaluate-your-policy)
16+
- [L. More Information](#l-more-information)
317

418
## A. Source the parts
519

6-
Follow this [README](https://github.com/TheRobotStudio/SO-ARM100). It contains the bill of materials, with link to source the parts, as well as the instructions to 3D print the parts, and advices if it's your first time printing or if you don't own a 3D printer already.
20+
Follow this [README](https://github.com/TheRobotStudio/SO-ARM100). It contains the bill of materials, with a link to source the parts, as well as the instructions to 3D print the parts,
21+
and advice if it's your first time printing or if you don't own a 3D printer.
722

8-
**Important**: Before assembling, you will first need to configure your motors. To this end, we provide a nice script, so let's first install LeRobot. After configuration, we will also guide you through assembly.
23+
Before assembling, you will first need to configure your motors. To this end, we provide a nice script, so let's first install LeRobot. After configuration, we will also guide you through assembly.
924

1025
## B. Install LeRobot
1126

27+
> [!TIP]
28+
> We use the Command Prompt (cmd) quite a lot. If you are not comfortable using the cmd or want to brush up using the command line you can have a look here: [Command line crash course](https://developer.mozilla.org/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line)
29+
1230
On your computer:
1331

14-
1. [Install Miniconda](https://docs.anaconda.com/miniconda/#quick-command-line-install):
32+
#### 1. [Install Miniconda](https://docs.anaconda.com/miniconda/install/#quick-command-line-install):
33+
34+
#### 2. Restart shell
35+
Copy paste in your shell: `source ~/.bashrc` or for Mac: `source ~/.bash_profile` or `source ~/.zshrc` if you're using zshell
36+
37+
#### 3. Create and activate a fresh conda environment for lerobot
38+
39+
<details>
40+
<summary><strong>Video install instructions</strong></summary>
41+
42+
<video src="https://github.com/user-attachments/assets/17172d3b-3b64-4b80-9cf1-b2b7c5cbd236"></video>
43+
44+
</details>
45+
1546
```bash
16-
mkdir -p ~/miniconda3
17-
# Linux:
18-
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
19-
# Mac M-series:
20-
# curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o ~/miniconda3/miniconda.sh
21-
# Mac Intel:
22-
# curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -o ~/miniconda3/miniconda.sh
23-
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
24-
rm ~/miniconda3/miniconda.sh
25-
~/miniconda3/bin/conda init bash
47+
conda create -y -n lerobot python=3.10
2648
```
2749

28-
2. Restart shell or `source ~/.bashrc` (*Mac*: `source ~/.bash_profile`) or `source ~/.zshrc` if you're using zshell
29-
30-
3. Create and activate a fresh conda environment for lerobot
50+
Then activate your conda environment (do this each time you open a shell to use lerobot!):
3151
```bash
32-
conda create -y -n lerobot python=3.10 && conda activate lerobot
52+
conda activate lerobot
3353
```
3454

35-
4. Clone LeRobot:
55+
#### 4. Clone LeRobot:
3656
```bash
3757
git clone https://github.com/huggingface/lerobot.git ~/lerobot
3858
```
3959

40-
5. Install LeRobot with dependencies for the feetech motors:
60+
#### 5. Install LeRobot with dependencies for the feetech motors:
4161
```bash
4262
cd ~/lerobot && pip install -e ".[feetech]"
4363
```
4464

45-
*For Linux only (not Mac)*: install extra dependencies for recording datasets:
65+
*EXTRA: For Linux only (not Mac)*: install extra dependencies for recording datasets:
4666
```bash
4767
conda install -y -c conda-forge ffmpeg
4868
pip uninstall -y opencv-python
4969
conda install -y -c conda-forge "opencv>=4.10.0"
5070
```
51-
71+
Great :hugs:! You are now done installing LeRobot and we can begin assembling the SO100 arms :robot:.
72+
Every time you now want to use LeRobot you can go to the `~/lerobot` folder where we installed LeRobot and run one of the commands.
5273
## C. Configure the motors
5374

75+
> [!NOTE]
76+
> Throughout this tutorial you will find videos on how to do the steps, the full video tutorial can be found here: [assembly video](https://www.youtube.com/watch?v=FioA2oeFZ5I).
77+
5478
### 1. Find the USB ports associated to each arm
5579

56-
Designate one bus servo adapter and 6 motors for your leader arm, and similarly the other bus servo adapter and 6 motors for the follower arm.
80+
Designate one bus servo adapter and 6 motors for your leader arm, and similarly the other bus servo adapter and 6 motors for the follower arm. It's convenient to label them and write on each motor if it's for the follower `F` or for the leader `L` and it's ID from 1 to 6 (F1...F6 and L1...L6).
5781

58-
#### a. Run the script to find ports
82+
#### a. Run the script to find port
5983

60-
Follow Step 1 of the [assembly video](https://www.youtube.com/watch?v=FioA2oeFZ5I), which illustrates the use of our scripts below.
84+
<details>
85+
<summary><strong>Video finding port</strong></summary>
86+
<video src="https://github.com/user-attachments/assets/4a21a14d-2046-4805-93c4-ee97a30ba33f"></video>
87+
<video src="https://github.com/user-attachments/assets/1cc3aecf-c16d-4ff9-aec7-8c175afbbce2"></video>
88+
</details>
6189

6290
To find the port for each bus servo adapter, run the utility script:
6391
```bash
@@ -144,10 +172,18 @@ class So100RobotConfig(ManipulatorRobotConfig):
144172
)
145173
```
146174

147-
### 2. Configure the motors
175+
### 2. Assembling the Base
176+
Let's begin with assembling the follower arm base
148177

149178
#### a. Set IDs for all 12 motors
150-
Plug your first motor and run this script to set its ID to 1. It will also set its present position to 2048, so expect your motor to rotate:
179+
180+
<details>
181+
<summary><strong>Video configuring motor</strong></summary>
182+
<video src="https://github.com/user-attachments/assets/ef9b3317-2e11-4858-b9d3-f0a02fb48ecf"></video>
183+
<video src="https://github.com/user-attachments/assets/f36b5ed5-c803-4ebe-8947-b39278776a0d"></video>
184+
</details>
185+
186+
Plug your first motor F1 and run this script to set its ID to 1. It will also set its present position to 2048, so expect your motor to rotate. Replace the text after --port to the corresponding follower control board port and run this command in cmd:
151187
```bash
152188
python lerobot/scripts/configure_motor.py \
153189
--port /dev/tty.usbmodem58760432961 \
@@ -157,7 +193,8 @@ python lerobot/scripts/configure_motor.py \
157193
--ID 1
158194
```
159195

160-
*Note: These motors are currently limitated. They can take values between 0 and 4096 only, which corresponds to a full turn. They can't turn more than that. 2048 is at the middle of this range, so we can take -2048 steps (180 degrees anticlockwise) and reach the maximum range, or take +2048 steps (180 degrees clockwise) and reach the maximum range. The configuration step also sets the homing offset to 0, so that if you misassembled the arm, you can always update the homing offset to account for a shift up to ± 2048 steps (± 180 degrees).*
196+
> [!NOTE]
197+
> These motors are currently limited. They can take values between 0 and 4096 only, which corresponds to a full turn. They can't turn more than that. 2048 is at the middle of this range, so we can take -2048 steps (180 degrees anticlockwise) and reach the maximum range, or take +2048 steps (180 degrees clockwise) and reach the maximum range. The configuration step also sets the homing offset to 0, so that if you misassembled the arm, you can always update the homing offset to account for a shift up to ± 2048 steps (± 180 degrees).
161198
162199
Then unplug your motor and plug the second motor and set its ID to 2.
163200
```bash
@@ -174,22 +211,47 @@ Redo the process for all your motors until ID 6. Do the same for the 6 motors of
174211

175212
#### b. Remove the gears of the 6 leader motors
176213

177-
Follow step 2 of the [assembly video](https://youtu.be/FioA2oeFZ5I?t=248). You need to remove the gear for the motors of the leader arm. As a result, you will only use the position encoding of the motor and reduce friction to more easily operate the leader arm.
214+
<details>
215+
<summary><strong>Video removing gears</strong></summary>
216+
217+
<video src="https://github.com/user-attachments/assets/0c95b88c-5b85-413d-ba19-aee2f864f2a7"></video>
218+
219+
</details>
220+
221+
222+
Follow the video for removing gears. You need to remove the gear for the motors of the leader arm. As a result, you will only use the position encoding of the motor and reduce friction to more easily operate the leader arm.
178223

179224
#### c. Add motor horn to all 12 motors
180-
Follow step 3 of the [assembly video](https://youtu.be/FioA2oeFZ5I?t=569). For SO-100, you need to align the holes on the motor horn to the motor spline to be approximately 1:30, 4:30, 7:30 and 10:30.
225+
226+
<details>
227+
<summary><strong>Video adding motor horn</strong></summary>
228+
229+
<video src="https://github.com/user-attachments/assets/ef3391a4-ad05-4100-b2bd-1699bf86c969"></video>
230+
231+
</details>
232+
233+
Follow the video for adding the motor horn. For SO-100, you need to align the holes on the motor horn to the motor spline to be approximately 1:30, 4:30, 7:30 and 10:30.
181234
Try to avoid rotating the motor while doing so to keep position 2048 set during configuration. It is especially tricky for the leader motors as it is more sensible without the gears, but it's ok if it's a bit rotated.
182235

183236
## D. Assemble the arms
184237

185-
Follow step 4 of the [assembly video](https://youtu.be/FioA2oeFZ5I?t=610). The first arm should take a bit more than 1 hour to assemble, but once you get use to it, you can do it under 1 hour for the second arm.
238+
<details>
239+
<summary><strong>Video assembling arms</strong></summary>
240+
241+
<video src="https://github.com/user-attachments/assets/488a39de-0189-4461-9de3-05b015f90cca"></video>
242+
243+
</details>
244+
245+
Follow the video for assembling the arms. It is important to insert the cables into the motor that is being assembled before you assemble the motor into the arm! Inserting the cables beforehand is much easier than doing this afterward. The first arm should take a bit more than 1 hour to assemble, but once you get used to it, you can do it under 1 hour for the second arm.
186246

187247
## E. Calibrate
188248

189249
Next, you'll need to calibrate your SO-100 robot to ensure that the leader and follower arms have the same position values when they are in the same physical position. This calibration is essential because it allows a neural network trained on one SO-100 robot to work on another.
190250

191251
#### a. Manual calibration of follower arm
192-
/!\ Contrarily to step 6 of the [assembly video](https://youtu.be/FioA2oeFZ5I?t=724) which illustrates the auto calibration, we will actually do manual calibration of follower for now.
252+
253+
> [!IMPORTANT]
254+
> Contrarily to step 6 of the [assembly video](https://youtu.be/FioA2oeFZ5I?t=724) which illustrates the auto calibration, we will actually do manual calibration of follower for now.
193255
194256
You will need to move the follower arm to these positions sequentially:
195257

@@ -353,4 +415,5 @@ As you can see, it's almost the same command as previously used to record your t
353415

354416
Follow this [previous tutorial](https://github.com/huggingface/lerobot/blob/main/examples/7_get_started_with_real_robot.md#4-train-a-policy-on-your-data) for a more in-depth tutorial on controlling real robots with LeRobot.
355417

356-
If you have any question or need help, please reach out on Discord in the channel [`#so100-arm`](https://discord.com/channels/1216765309076115607/1237741463832363039).
418+
> [!TIP]
419+
> If you have any questions or need help, please reach out on Discord in the channel [`#so100-arm`](https://discord.com/channels/1216765309076115607/1237741463832363039).

lerobot/common/robot_devices/motors/feetech.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,10 @@ def read(self, data_name, motor_names: str | list[str] | None = None):
717717
group_key = get_group_sync_key(data_name, motor_names)
718718

719719
if data_name not in self.group_readers:
720+
# Very Important to flush the buffer!
721+
self.port_handler.ser.reset_output_buffer()
722+
self.port_handler.ser.reset_input_buffer()
723+
720724
# create new group reader
721725
self.group_readers[group_key] = scs.GroupSyncRead(
722726
self.port_handler, self.packet_handler, addr, bytes

tests/mock_scservo_sdk.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def __init__(self, port):
4646
self.port = port
4747
# factory default baudrate
4848
self.baudrate = DEFAULT_BAUDRATE
49+
self.ser = SerialMock()
4950

5051
def openPort(self): # noqa: N802
5152
return True
@@ -101,3 +102,11 @@ def txPacket(self): # noqa: N802
101102

102103
def changeParam(self, index, data): # noqa: N802
103104
self.packet_handler.data[index][self.address] = data
105+
106+
107+
class SerialMock:
108+
def reset_output_buffer(self):
109+
pass
110+
111+
def reset_input_buffer(self):
112+
pass

0 commit comments

Comments
 (0)