In the previous article, I briefly explained what VLA is, what LeRobot is, and what makes it useful, and then introduced the products I purchased.
https://dev.to/takeofuture/getting-started-with-lerobot-and-so-101-building-a-low-cost-physical-ai-robot-arm-part-0-6j1
Now that all the parts have arrived, it is finally time to start assembling the robot.
However, before jumping straight into the assembly, there is one important step we need to complete first. You should have received six motors, and each of them needs to be assigned its own ID. In this article, I will first explain how to do that.
We will connect the controller board to a PC and assign the IDs from there. You can also install Ubuntu on Windows using WSL (Windows Subsystem for Linux), but if possible, I recommend using a native Ubuntu installation. As of August 30, 2026, the latest stable LTS version is Ubuntu 24.04.
Installing the setup tools
I will assume that Python 3 is already installed. If it is not, install it with the following command.
apt install python3 python3-venv python3-pip
Next, let's create a Python virtual environment. Here, I will name it lerobot, and then activate it.
$ python3 -m venv lerobot
$ source lerobot/bin/activate
(lerobot)$ pip install --upgrade pip
After that, install LeRobot.
Because the SO-101 uses STS3215 motors, the feetech option is important.
If this PC is only being used for configuration or teleoperation and does not have an NVIDIA GPU, it is better to install the CPU-only version of PyTorch first so that unnecessary NVIDIA GPU-related PyTorch packages are not downloaded.
(lerobot)$ pip install \
torch==2.11.0+cpu \
--index-url https://download.pytorch.org/whl/cpu
(lerobot)$ cd ~
(lerobot)$ git clone https://github.com/huggingface/lerobot.git
(lerobot)$ cd lerobot
(lerobot)$ pip install -e ".[feetech]"
Once the installation is complete, you should be able to use commands such as the following!
(lerobot)$ lerobot-find-port --help
(lerobot)$ lerobot-setup-motors --help
Setting the Waveshare board to USB mode
To communicate with the PC via USB-C, insert six jumpers arranged in two columns and three rows vertically into the appropriate pins.
Connect the Waveshare board to the PC via USB, and also connect the power cable.
The USB connection itself supplies power to the board, but it does not provide enough power to operate the motors, so you also need to connect the 12V power supply.
Run the following command from the terminal to identify the port.
(lerobot) $ lerobot-find-port
Finding all available ports for the MotorsBus.
Ports before disconnecting: ['/dev/ttyACM0', '/dev/ttyprintk', '/dev/ttyS31', '/dev/ttyS30', '/dev/ttyS29', '/dev/ttyS28', '/dev/ttyS27', '/dev/S20', '/dev/ttyS19', '/dev/ttyS18', '/dev/ttyS17', '/dev/ttyS16', '/dev/ttyS15', '/dev/ttyS14', '/dev/ttyS13', '/dev/ttyS12', '/dev/ttyS11', '/d', '/dev/ttyS3', '/dev/ttyS2', '/dev/ttyS1', '/dev/ttyS0', '/dev/tty63', '/dev/tty62', '/dev/tty61', '/dev/tty60', '/dev/tty59', '/dev/tty58', '1', '/dev/tty50', '/dev/tty49', '/dev/tty48', '/dev/tty47', '/dev/tty46', '/dev/tty45', '/dev/tty44', '/dev/tty43', '/dev/tty42', '/dev/tty41', 34', '/dev/tty33', '/dev/tty32', '/dev/tty31', '/dev/tty30', '/dev/tty29', '/dev/tty28', '/dev/tty27', '/dev/tty26', '/dev/tty25', '/dev/tty24',y17', '/dev/tty16', '/dev/tty15', '/dev/tty14', '/dev/tty13', '/dev/tty12', '/dev/tty11', '/dev/tty10', '/dev/tty9', '/dev/tty8', '/dev/tty7', 'ev/tty']
Remove the USB cable from your MotorsBus and press Enter when done.
As instructed by the command, disconnect the USB cable connecting the Waveshare device to the PC, and then press Enter.
The port of this MotorsBus is '/dev/ttyACM0'
Reconnect the USB cable.
Success! We can now confirm that this Waveshare device is associated with
/dev/ttyACM0
If you are not running these commands as root, give your user account permission to access serial devices with the following command.
(lerobot) $ sudo usermod -aG dialout yourusername
Reconnect the USB cable to the PC. Then disconnect the power supply temporarily and connect a motor.
Both the motors and the Waveshare board have two connectors, and either connector can be used. However, it is better to keep the connection pattern consistent. I will proceed using the following connection scheme.
Board left connector
↓
Motor 1 left connector
Motor 1 right connector
↓
Motor 2 left connector
Motor 2 right connector
↓
Motor 3 left connector
...
Once the motor is connected, run the following command.

(lerobot) $ lerobot-setup-motors \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0
Connect the controller board to the 'gripper' motor only and press enter.
After pressing Enter, you should see the following output.
'gripper' motor id set to 6
The motor ID is important because it determines which motor will be installed at which joint of the robot. In this case, the motor was assigned ID 6, so it is a good idea to physically label the motor.
Then repeat the same process for the remaining five motors.
- Disconnect the 12V power supply
- Disconnect the current motor
- Connect only one new motor to the board
- Reconnect the 12V power supply
- Press Enter
- Attach a label to the configured motor
Repeat this process until IDs have been assigned to all six motors.
(lerobot)$ lerobot-setup-motors \
--robot.type=so101_follower \
--robot.port=/dev/ttyACM0
Connect the controller board to the 'gripper' motor only and press enter.
'gripper' motor id set to 6
Connect the controller board to the 'wrist_roll' motor only and press enter.
'wrist_roll' motor id set to 5
Connect the controller board to the 'wrist_flex' motor only and press enter.
'wrist_flex' motor id set to 4
Connect the controller board to the 'elbow_flex' motor only and press enter.
'elbow_flex' motor id set to 3
Connect the controller board to the 'shoulder_lift' motor only and press enter.
'shoulder_lift' motor id set to 2
Connect the controller board to the 'shoulder_pan' motor only and press enter.
'shoulder_pan' motor id set to 1
To summarize, the motor IDs are assigned as follows. This mapping is very important, so make sure to record it carefully.
ID 1 = shoulder_pan
ID 2 = shoulder_lift
ID 3 = elbow_flex
ID 4 = wrist_flex
ID 5 = wrist_roll
ID 6 = gripper
Next, we’re finally ready to start assembling the robot arm.
https://dev.to/takeofuture/trying-vla-part-2-assembling-lerobot-joint-1-2npj





Top comments (0)