From dd974529cf6cc885fa7197d90acf65041b823e28 Mon Sep 17 00:00:00 2001 From: Pepijn <138571049+pkooij@users.noreply.github.com> Date: Mon, 3 Feb 2025 18:27:55 +0100 Subject: [PATCH] User/pepijn/2025 01 31 improved tutorial so100 (#666) --- examples/10_use_so100.md | 127 +++++++++++++----- .../common/robot_devices/motors/feetech.py | 4 + tests/mock_scservo_sdk.py | 9 ++ 3 files changed, 108 insertions(+), 32 deletions(-) diff --git a/examples/10_use_so100.md b/examples/10_use_so100.md index 293212f24..7912884c1 100644 --- a/examples/10_use_so100.md +++ b/examples/10_use_so100.md @@ -1,63 +1,91 @@ # Using the [SO-100](https://github.com/TheRobotStudio/SO-ARM100) with LeRobot +## Table of Contents + + - [A. Source the parts](#a-source-the-parts) + - [B. Install LeRobot](#b-install-lerobot) + - [C. Configure the motors](#c-configure-the-motors) + - [D. Assemble the arms](#d-assemble-the-arms) + - [E. Calibrate](#e-calibrate) + - [F. Teleoperate](#f-teleoperate) + - [G. Record a dataset](#g-record-a-dataset) + - [H. Visualize a dataset](#h-visualize-a-dataset) + - [I. Replay an episode](#i-replay-an-episode) + - [J. Train a policy](#j-train-a-policy) + - [K. Evaluate your policy](#k-evaluate-your-policy) + - [L. More Information](#l-more-information) ## A. Source the parts -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. +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, +and advice if it's your first time printing or if you don't own a 3D printer. -**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. +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. ## B. Install LeRobot +> [!TIP] +> 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) + On your computer: -1. [Install Miniconda](https://docs.anaconda.com/miniconda/#quick-command-line-install): +#### 1. [Install Miniconda](https://docs.anaconda.com/miniconda/install/#quick-command-line-install): + +#### 2. Restart shell +Copy paste in your shell: `source ~/.bashrc` or for Mac: `source ~/.bash_profile` or `source ~/.zshrc` if you're using zshell + +#### 3. Create and activate a fresh conda environment for lerobot + +
+Video install instructions + + + +
+ ```bash -mkdir -p ~/miniconda3 -# Linux: -wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh -# Mac M-series: -# curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o ~/miniconda3/miniconda.sh -# Mac Intel: -# curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -o ~/miniconda3/miniconda.sh -bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3 -rm ~/miniconda3/miniconda.sh -~/miniconda3/bin/conda init bash +conda create -y -n lerobot python=3.10 ``` -2. Restart shell or `source ~/.bashrc` (*Mac*: `source ~/.bash_profile`) or `source ~/.zshrc` if you're using zshell - -3. Create and activate a fresh conda environment for lerobot +Then activate your conda environment (do this each time you open a shell to use lerobot!): ```bash -conda create -y -n lerobot python=3.10 && conda activate lerobot +conda activate lerobot ``` -4. Clone LeRobot: +#### 4. Clone LeRobot: ```bash git clone https://github.com/huggingface/lerobot.git ~/lerobot ``` -5. Install LeRobot with dependencies for the feetech motors: +#### 5. Install LeRobot with dependencies for the feetech motors: ```bash cd ~/lerobot && pip install -e ".[feetech]" ``` -*For Linux only (not Mac)*: install extra dependencies for recording datasets: +*EXTRA: For Linux only (not Mac)*: install extra dependencies for recording datasets: ```bash conda install -y -c conda-forge ffmpeg pip uninstall -y opencv-python conda install -y -c conda-forge "opencv>=4.10.0" ``` - +Great :hugs:! You are now done installing LeRobot and we can begin assembling the SO100 arms :robot:. +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. ## C. Configure the motors +> [!NOTE] +> 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). + ### 1. Find the USB ports associated to each arm -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. +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). -#### a. Run the script to find ports +#### a. Run the script to find port -Follow Step 1 of the [assembly video](https://www.youtube.com/watch?v=FioA2oeFZ5I), which illustrates the use of our scripts below. +
+Video finding port + + +
To find the port for each bus servo adapter, run the utility script: ```bash @@ -144,10 +172,18 @@ class So100RobotConfig(ManipulatorRobotConfig): ) ``` -### 2. Configure the motors +### 2. Assembling the Base +Let's begin with assembling the follower arm base #### a. Set IDs for all 12 motors -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: + +
+Video configuring motor + + +
+ +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: ```bash python lerobot/scripts/configure_motor.py \ --port /dev/tty.usbmodem58760432961 \ @@ -157,7 +193,8 @@ python lerobot/scripts/configure_motor.py \ --ID 1 ``` -*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).* +> [!NOTE] +> 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). Then unplug your motor and plug the second motor and set its ID to 2. ```bash @@ -174,22 +211,47 @@ Redo the process for all your motors until ID 6. Do the same for the 6 motors of #### b. Remove the gears of the 6 leader motors -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. +
+Video removing gears + + + +
+ + +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. #### c. Add motor horn to all 12 motors -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. + +
+Video adding motor horn + + + +
+ +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. 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. ## D. Assemble the arms -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. +
+Video assembling arms + + + +
+ +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. ## E. Calibrate 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. #### a. Manual calibration of follower arm -/!\ 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. + +> [!IMPORTANT] +> 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. You will need to move the follower arm to these positions sequentially: @@ -353,4 +415,5 @@ As you can see, it's almost the same command as previously used to record your t 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. -If you have any question or need help, please reach out on Discord in the channel [`#so100-arm`](https://discord.com/channels/1216765309076115607/1237741463832363039). +> [!TIP] +> If you have any questions or need help, please reach out on Discord in the channel [`#so100-arm`](https://discord.com/channels/1216765309076115607/1237741463832363039). diff --git a/lerobot/common/robot_devices/motors/feetech.py b/lerobot/common/robot_devices/motors/feetech.py index fd5e877bf..a59db7df8 100644 --- a/lerobot/common/robot_devices/motors/feetech.py +++ b/lerobot/common/robot_devices/motors/feetech.py @@ -717,6 +717,10 @@ def read(self, data_name, motor_names: str | list[str] | None = None): group_key = get_group_sync_key(data_name, motor_names) if data_name not in self.group_readers: + # Very Important to flush the buffer! + self.port_handler.ser.reset_output_buffer() + self.port_handler.ser.reset_input_buffer() + # create new group reader self.group_readers[group_key] = scs.GroupSyncRead( self.port_handler, self.packet_handler, addr, bytes diff --git a/tests/mock_scservo_sdk.py b/tests/mock_scservo_sdk.py index 596978c00..ca9233b03 100644 --- a/tests/mock_scservo_sdk.py +++ b/tests/mock_scservo_sdk.py @@ -46,6 +46,7 @@ def __init__(self, port): self.port = port # factory default baudrate self.baudrate = DEFAULT_BAUDRATE + self.ser = SerialMock() def openPort(self): # noqa: N802 return True @@ -101,3 +102,11 @@ def txPacket(self): # noqa: N802 def changeParam(self, index, data): # noqa: N802 self.packet_handler.data[index][self.address] = data + + +class SerialMock: + def reset_output_buffer(self): + pass + + def reset_input_buffer(self): + pass