stefanopineda.com / robot_setup

SO-ARM101 host PC — build spec & Ubuntu runbook

Minimal feasible host for a remote SO-ARM101 (BusLinker / Waveshare bus-servo adapter + STS3215) running Hugging Face LeRobot. The host computer is the brain; the servo board is only a USB power + serial bridge.

Updated 2026-07-21 SO-ARM101 + LeRobot Ubuntu 24.04 / JetPack

Bottom line

For SO-ARM101 + LeRobot you are not programming an Arduino-class MCU. You need a host PC next to the arm that runs Python/PyTorch, talks USB-serial to the BusLinker (or Waveshare) board, and streams camera frames into a policy.

1. What changes with SO-ARM101

Earlier generic “MCU + ROS” advice assumed a programmable real-time controller on the arm. SO-ARM101 does not work that way. Official LeRobot hardware docs treat the arm as Feetech bus servos behind a USB MotorBus adapter, with all algorithms on the host.

Topic Generic MCU robot SO-ARM101 + LeRobot
Brain Split: PC high-level, MCU low-level Host PC is the brain (Python / PyTorch / LeRobot)
Board on the arm Arduino / STM32 / etc. running firmware you write BusLinker V3 / Waveshare bus servo adapter — USB bridge + power
Motors Often pulse/dir or CAN drivers STS3215 daisy-chained bus servos (IDs + baudrate in EEPROM)
Software stack ROS 2 + custom serial often default Hugging Face LeRobot + Feetech extra (pip install -e ".[feetech]")
Typical tasks Scripted pick + classical CV / YOLO Leader teleop → dataset → imitation learning policy → replay on follower
USB ports 1 MCU + cameras Often 2 adapters (leader + follower) + 1–2 USB cameras
Fail-safe MCU watchdog can stop motors if PC dies Weaker by default — host process + servo timeouts; plan power kill + supervision
Does this change the PC build? Hardware tier stays in the same ballpark (modest NVIDIA GPU or Jetson), but software, I/O, and safety assumptions change. Prefer LeRobot’s path over a custom ROS/MCU stack unless you have a reason not to. Jetson is a first-class community target for this kit; ROS 2 is optional, not required.

2. What the host machine must do

For remote SO-ARM101 work (teleop, data collection, then learned policies), the host loop is roughly:

  1. Open USB serial to follower (and leader, if present) via BusLinker / Waveshare.
  2. Capture 1–2 RGB camera streams (wrist and/or scene).
  3. Teleop mode: map leader joint positions → follower commands and record a LeRobot dataset.
  4. Autonomy mode: run a policy (ACT, diffusion, SmolVLA, etc.) → joint targets → Feetech bus.
  5. Expose SSH / logs / optional camera preview over Tailscale for remote monitoring.
Design rule for this kit: treat the host as safety-critical software. Keep control loops local to the machine that owns the USB cable. Do not put the Feetech command path across the open internet. Provide a local way to cut 5 V/12 V servo power.

3. Architecture (host vs BusLinker)

You (laptop) ──Tailscale──▶ Ubuntu/Jetson host ──USB──▶ BusLinker/Waveshare ──bus──▶ STS3215×6 ▲ │ USB cameras (×1–2) │ ▼ SSH / monitoring LeRobot (PyTorch policy / teleop)

Host PC / Jetson (this build)

  • Ubuntu 24.04 LTS or JetPack (Jetson)
  • LeRobot + Feetech SDK
  • Camera capture + policy inference
  • Dataset recording & calibration files
  • Remote access gateway (Tailscale)

BusLinker / Waveshare adapter

  • USB device (typically /dev/ttyACM* or /dev/ttyUSB*)
  • Power rail for bus servos (use kit PSU)
  • Half-duplex serial to daisy-chained STS3215
  • Not a place to run YOLO or policies
  • Waveshare: jumpers on channel B (USB) when using PC control

4. Processing levels by LeRobot workload

Size the host for the heaviest job you will run at the robot site. Teleop recording and policy inference have very different GPU needs.

Tier Workload Typical hardware Good for
T0 — Teleop / record only Leader→follower streaming, USB cameras, write LeRobot episodes Laptop, N100/N305 mini-PC, Pi 5 8 GB — GPU optional Collecting demos; no onboard neural policy yet
T1 — Policy inference (recommended min) ACT / diffusion-style policies, 1–2 cams @ ~30 Hz class loops RTX 3050 6–8 GB or Jetson Orin Nano 8 GB, 16–32 GB RAM Autonomous tabletop tasks after training elsewhere or lightly on-box
T2 — Larger VLAs / multi-cam SmolVLA-class, heavier vision backbones, dual HD streams RTX 4060–4070 8–12 GB or Orin NX 16 GB, 32 GB RAM Richer policies without cloud round-trips
T3 — Training / foundation finetune Long policy training, GR00T-class finetunes RTX 4090 / A6000 / cloud (often 16–24 GB+ VRAM; some recipes ~25 GB) Train off-site; copy checkpoints to the robot host

Graphics / GPU requirements (plain English)

Training vs inference: collect data on the robot host; train on a bigger GPU or cloud; deploy the checkpoint back for inference. The remote SO-ARM101 box should optimize for USB reliability, cameras, uptime, and inference latency — not training throughput.

5. Recommended minimal feasible build

Two equal “minimum viable” hosts for SO-ARM101 autonomy. Teleop-only can go cheaper (Path C).

Path A — best general default

Used / SFF desktop + RTX 3050

  • CPU: Ryzen 5 5600 / Intel i5-12400 or better
  • GPU: NVIDIA RTX 3050 6 GB or 8 GB
  • RAM: 32 GB DDR4
  • SSD: 1 TB NVMe (datasets)
  • PSU: quality 450–550 W 80+ Bronze
  • USB: 4+ free USB-A/C ports after peripherals
  • OS: Ubuntu 24.04 LTS (LeRobot + CUDA 12.x friendly)

≈ $500–850 used · $750–1,100 new

Path B — ecosystem favorite

NVIDIA Jetson Orin Nano Super 8 GB

  • Dev kit / reComputer-class carrier + Orin Nano
  • NVMe 512 GB–1 TB
  • Active cooling (sustained policy load)
  • USB3 cameras + BusLinker adapters
  • JetPack 6.x (not a stock Ubuntu desktop ISO)
  • Strong community docs for SO-ARM + LeRobot

≈ $250–600 depending on kit + storage

Path C — teleop / data collection only

  • Any modern laptop (Windows for Feetech GUI debugging is fine; Ubuntu for LeRobot preferred)
  • or Raspberry Pi 5 8 GB / Intel N100 mini-PC for recording demos
  • Upgrade to Path A/B before running onboard policies at usable latency

≈ $0 (existing laptop) – $220 — not the long-term autonomy host

Recommendation for remote SO-ARM101 + object manipulation with LeRobot: buy Path A or Path B as the always-on machine next to the arm. Use a laptop only for initial bring-up if needed. Skip 24 GB+ GPUs until a specific policy (e.g. large VLA / GR00T finetune) demands them — and even then, train off-box when possible.

I/O you must plan for

6. Bill of materials (host + SO-ARM101 side)

Item Spec Notes
Host PC Path A or Path B above Lives next to the arm (USB tether)
GPU (Path A) RTX 3050 6/8 GB (or 4060) NVIDIA Linux drivers + CUDA for PyTorch
RAM / SSD 32 GB / 1 TB NVMe Datasets are video-heavy
Bus servo adapter(s) BusLinker V3 or Waveshare Bus Servo Adapter Usually included with kit; one per arm bus
Arm kit SO-ARM101 follower (± leader) STS3215 bus servos, kit PSU(s)
Cameras 1–2× USB3 720p/1080p UVC Scene + optional wrist view
USB cables Short, data-rated Avoid unpowered multi-hop hubs when possible
Network Gigabit Ethernet Tailscale remote access
Power kill Switched strip / E-stop on servo PSU Independent of host OS health

7. What you do not need (yet)

8. Ubuntu install runbook

Assume Ubuntu 24.04 LTS is already installed on the host next to the arm (Desktop or Server). Run as a user with sudo. Commands are copy-pasteable.

Jetson users: use NVIDIA JetPack / SDK Manager instead of the generic NVIDIA driver steps. Skip §8.3 GPU drivers; install LeRobot against JetPack’s PyTorch build (community guides often use JetPack 6.0/6.x). SSH/Tailscale/Feetech steps still apply.

8.1 System baseline

# Update OS
sudo apt update && sudo apt -y full-upgrade
sudo apt -y install curl wget git build-essential \
  ca-certificates gnupg lsb-release software-properties-common \
  htop tmux vim net-tools usbutils v4l-utils \
  python3-pip python3-venv python3-dev \
  openssh-server

# Optional: reboot after kernel upgrade
sudo reboot

8.2 Identity, locale, and unattended upgrades

# Set a clear hostname (shows up in Tailscale / mDNS)
sudo hostnamectl set-hostname robot-pc
echo "10.0.0.1 robot-pc" | sudo tee -a /etc/hosts  # adjust if needed

# Time sync (critical for logs + certs)
timedatectl
sudo timedatectl set-ntp true

# Security updates
sudo apt -y install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

8.3 NVIDIA GPU drivers (Path A)

# Recommended: Ubuntu’s proprietary driver meta-package
ubuntu-drivers devices
sudo ubuntu-drivers autoinstall
# or pin a known-good series, e.g.:
# sudo apt -y install nvidia-driver-550

sudo reboot

# Verify
nvidia-smi
# Expect GPU name, driver version, CUDA version listed
After nvidia-smi works, install CUDA toolkit only if you compile custom ops. Many vision stacks ship wheels that bundle CUDA runtime — prefer those first.

8.4 Docker (optional)

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker "$USER"
# log out/in for group membership

# NVIDIA Container Toolkit (GPU in containers)
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
  sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
  sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
sudo apt -y install nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker

# Smoke test
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi

8.5 Camera smoke test

sudo apt -y install v4l-utils python3-opencv
v4l2-ctl --list-devices
python3 - <<'PY'
import cv2
cap = cv2.VideoCapture(0)
ok, frame = cap.read()
print("camera_ok=", ok, "shape=", None if frame is None else frame.shape)
cap.release()
PY

8.6 USB permissions for BusLinker / cameras

# Serial access for Feetech MotorBus adapters
sudo usermod -aG dialout "$USER"
sudo usermod -aG video "$USER"
sudo usermod -aG plugdev "$USER"

# CRITICAL on many Ubuntu installs: brltty claims CH340/CH341 USB-serial IDs
# used by some bus servo boards and blocks /dev/ttyUSB* or ttyACM*
sudo apt -y remove brltty
# reboot or replug adapters after removal

# Temporary access (until groups apply / udev rules land)
# sudo chmod 666 /dev/ttyACM0 /dev/ttyACM1

# Stable symlinks — replace vendor/product from `lsusb` after plugging adapters
sudo tee /etc/udev/rules.d/99-so101-motorbus.rules <<'EOF'
# Example: adjust idVendor/idProduct per `lsusb` for each adapter
SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="so101_follower", MODE="0666"
# Second adapter example — different serial or physical port mapping as needed
# SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ATTRS{serial}=="XXXX", SYMLINK+="so101_leader", MODE="0666"
EOF
sudo udevadm control --reload-rules
sudo udevadm trigger

# Re-login, then: ls -l /dev/ttyACM* /dev/ttyUSB* /dev/video*

9. Remote access & security

You are not on site. The host owns USB to the arm — treat it as a hardened jump host. Remember: there is no independent MCU application brain to “fail safe” for you.

9.1 SSH hardening

sudo systemctl enable --now ssh

# On your laptop: ssh-copy-id user@robot-pc-local-ip
# Then on robot PC, prefer keys only:
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sudo systemctl restart ssh

9.2 Tailscale (recommended VPN)

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up --ssh
# authenticate via the printed URL from a browser on any device
tailscale status
tailscale ip -4
Why Tailscale: no port-forwarding on the site router, works behind CGNAT, and tailscale ssh can replace opening port 22 publicly. WireGuard self-host is fine if you prefer.

9.3 Firewall

sudo apt -y install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
# If Tailscale handles SSH, you can skip public 22 entirely.
# Allow SSH only if needed on LAN:
sudo ufw allow from 192.168.0.0/16 to any port 22 proto tcp
sudo ufw allow in on tailscale0
sudo ufw enable
sudo ufw status verbose

9.4 Fail-safe behavior (required for SO-ARM101)

9.5 Optional camera preview

# Simple low-latency path for debugging (LAN/VPN only):
# MediaMTX / go2rtc / WebRTC stacks are preferable to raw open RTSP on the internet.
# Example placeholder: use your chosen streamer bound to Tailscale IP only.
ip -4 addr show tailscale0

10. LeRobot + Feetech stack install

Follow the official guides for exact flags as versions move: LeRobot install, SO-101 assembly / motors / calibrate. Below is a practical host-side sequence after Ubuntu/JetPack basics.

10.1 Clone and install with Feetech extra

# Prefer a fresh conda/mamba or venv per LeRobot docs for your platform
cd ~
git clone https://github.com/huggingface/lerobot.git
cd lerobot

# Install package + Feetech motors support (required for SO-ARM101)
pip install -e ".[feetech]"

# On x86_64 Ubuntu with NVIDIA GPU, ensure torch sees CUDA:
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"
LeRobot’s Linux wheels track a specific CUDA/PyTorch index over time (recent docs mention CUDA 12.x driver floors). If torch.cuda.is_available() is false, fix drivers/torch before debugging the arm.

10.2 Find MotorBus ports

# Power the adapter(s) with the kit PSU, then:
lerobot-find-port

# On Linux you will often see /dev/ttyACM0, /dev/ttyACM1
# Use chmod or dialout group if permission denied:
# sudo chmod 666 /dev/ttyACM0

10.3 Motor IDs, calibration, first motion

# One motor at a time per official SO-101 guide — example shapes:
lerobot-setup-motors \
  --robot.type=so101_follower \
  --robot.port=/dev/ttyACM0

lerobot-calibrate \
  --robot.type=so101_follower \
  --robot.port=/dev/ttyACM0 \
  --robot.id=my_follower_arm

# Leader (if present) uses --teleop.type=so101_leader and its own port/id
# Then follow the imitation-learning real-robot tutorial for teleop + record + train + eval

10.4 Optional: YOLO still useful?

Classic YOLO pick-and-place is not the primary SO-ARM101 path. LeRobot policies usually consume raw camera frames + joint state end-to-end. You can still add OpenCV/YOLO for debugging or hybrid stacks, but size the GPU for the policy first.

11. BusLinker / Waveshare bring-up

  1. Power correctly. Connect kit PSU to the servo board; USB alone is not the motor supply. Standard vs Pro kits differ (e.g. 5 V vs 12 V follower) — match the listing.
  2. USB to host only. Plug BusLinker/Waveshare into the robot-site host (the machine that will run LeRobot). For Waveshare, set jumpers to channel B (USB) when controlling from PC.
  3. Identify ports. lsusb, dmesg -w, lerobot-find-port. Remove brltty if the device never appears.
  4. Program servo IDs once. Use lerobot-setup-motors one motor at a time (official sequence). Optional Windows Feetech GUI for debug only.
  5. Daisy-chain and calibrate. Full bus chain, then lerobot-calibrate for follower and leader so joint zeros match.
  6. Cameras last. Mount scene (± wrist) cameras, confirm indices, then record short teleop episodes before long datasets.
  7. Remote only after local success. Teleop and a recorded replay must work with you standing there before Tailscale-only operation.

12. Verification checklist

Check Command / action Pass criteria
GPU (if Path A/B autonomy) nvidia-smi / torch.cuda.is_available() True / GPU listed
Cameras v4l2-ctl --list-devices + OpenCV grab Stable frames
MotorBus lerobot-find-port Port found; survives replug
Motors setup-motors + calibrate IDs unique; calibration saved
Teleop Leader moves follower (if dual arm) Smooth tracking, no USB drops
Remote SSH tailscale ssh user@robot-pc Login without public port 22
Power kill Cut servo PSU while host stays up Arm loses actuation immediately
Reboot persistence sudo reboot Drivers, dialout, Tailscale, ports return

13. Day-2 operations

systemd (use carefully)

# Prefer manual start for motion-capable processes.
# If you must daemonize inference, gate on a
# hardware enable or explicit env flag.

[Service]
Type=simple
User=YOUR_USER
WorkingDirectory=/home/YOUR_USER/lerobot
# ExecStart=... only after dry-run validation
Restart=no

Useful habits

  • Version calibration files under ~/.cache/huggingface/lerobot/calibration/
  • Cap dataset disk use; rsync episodes off-box often
  • Pin LeRobot git commit + policy checkpoint hashes
  • Clone the NVMe image after a known-good bring-up
  • Re-check USB ports after any hub/cable change

Performance tuning notes

Decision guide (one paragraph)

SO-ARM101 makes the host PC the entire brain and the BusLinker a USB/power bridge to STS3215 servos under Hugging Face LeRobot. For remote object manipulation, place an RTX 3050-class or Jetson Orin Nano next to the arm, install Ubuntu/JetPack, Feetech-enabled LeRobot, cameras, and Tailscale. Use a light machine only for teleop/data collection. Train big models off-site. Compensate for the missing independent MCU with a physical servo power kill and local supervision on first remote runs.