lerobot_robot_piper
LeRobot plugin for the Agilex Piper 7-DOF robotic arm. Provides follower (robot) and leader (teleoperator) interfaces that integrate directly with the LeRobot framework for teleoperation, dataset recording, and autonomous policy deployment.
# The whole setup, start to finish:
git clone https://github.com/WeGo-Robotics/lerobot_robot_piper.git
cd lerobot_robot_piper && pip install -e .
piper-doctor # verify install & hardware
piper-setup # name your arms (once)
sudo bash scripts/install_can_persist.sh # survive reboots (once)
piper-teleop # go
Features
- Leader-Follower Teleoperation: Mirror a leader arm's movements onto a follower arm in real time
- Dataset Recording: Collect episodes (joint positions + camera frames) for imitation learning
- CAN Bus Communication: Direct hardware control via
piper_sdk - Safety Limits: Configurable
max_relative_targetto cap per-step joint movement - Camera Integration: Attach multiple USB cameras as observations on the follower
- GUI Tools: Tkinter-based UIs for setup (
piper-setup), direct control (piper-ui), teleoperation monitoring (piper-teleop), and zero-point calibration (piper-calibrate) - Boot-persistent CAN setup: One-time install script keeps canonical CAN names across reboots and hotplugs
Installation
From PyPI:
pip install lerobot_robot_wego_piper
The PyPI name is
lerobot_robot_wego_piper— the package namedlerobot_robot_piperon PyPI is an unrelated third-party project. The import name stayslerobot_robot_pipereither way.
From source — needed for the scripts/ (CAN persistence) and development:
git clone https://github.com/WeGo-Robotics/lerobot_robot_piper.git
cd lerobot_robot_piper
pip install -e .
Wheels are also attached to each GitHub Release. All dependencies, including piper_sdk, resolve automatically from PyPI.
Verify the installation (and later, the hardware) with:
piper-doctor
Requirements: Python >= 3.10, LeRobot >= 0.3.0, Linux with SocketCAN (iproute2, ethtool, can-utils), CAN-USB interface (gs_usb) connected to the Piper arm.
sudo apt update && sudo apt install iproute2 ethtool can-utils
Hardware Setup
First-time setup (recommended path)
# 1. Assign canonical names to your arms (GUI wizard, see below)
piper-setup
# 2. Make the CAN setup persistent across reboots, hotplugs, and port swaps
# (keep the arms plugged in — adapter serials are read live)
sudo bash scripts/install_can_persist.sh
After this, can_leader1, can_follower1, … come back up automatically on every boot and every re-plug.
Why serial pinning matters: plain can0/can1 are kernel enumeration order — swap two adapters between USB ports and the arms silently swap names, so a leader can receive follower commands. The installer generates udev rules pinned to each adapter's USB serial, so the name follows the arm no matter which port it's plugged into. Re-run piper-setup + the installer only when an arm is rewired to a different adapter.
To see which adapter is which (e.g. before rewiring):
python3 scripts/list_can_adapters.py # serial <-> interface table
python3 scripts/list_can_adapters.py --watch # move an arm by hand to identify it
piper-doctor — When something doesn't work
piper-doctor
Checks the whole chain in dependency order and prints a fix for every failure:
- Python packages & LeRobot plugin registration (
piper_follower/piper_leadertypes) - CAN adapter hardware on the USB bus
- CAN interface state vs
~/piper_config.json(names, UP, bitrate) - Arm response — passive RX counters, then an active firmware query
- Boot persistence (udev rules +
piper-can-up.service)
Read-only — never changes interface state or sends arm commands. Exit code 0 = healthy, 1 = problems found.
Manual CAN activation (single arm, no wizard)
# Activate the only plugged-in CAN module as can0 at 1 Mbps
bash scripts/can_activate.sh can0 1000000
# Multiple modules plugged in: disambiguate by USB address
sudo ethtool -i can0 | grep bus-info
bash scripts/can_activate.sh can0 1000000 1-2:1.0
Or fully by hand:
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
The piper-ui and piper-teleop GUIs can also detect and initialize CAN interfaces.
Scripts
| Script | Purpose |
|---|---|
scripts/can_activate.sh |
Activate a single CAN interface (name, bitrate, optional USB address) |
scripts/can_restore.sh |
Bring up all arms from ~/piper_config.json (rename if needed, bitrate, link up) |
scripts/install_can_persist.sh |
Generate serial-pinned udev NAME= rules + install boot/hotplug bring-up service; uninstall to remove |
scripts/list_can_adapters.py |
Show adapter serial ↔ interface table; --watch identifies an arm by moving it |
Wiring
| Arm | Interface |
|---|---|
| Follower (robot) | e.g., can_follower1 (or can0) |
| Leader (human input) | e.g., can_leader1 (or can1) |
GUI Tools
piper-setup — Multi-Arm Setup Wizard
Run this first when setting up multiple arms.
piper-setup
4-step wizard for configuring up to 4 arms:
- Scan — detect all CAN ports, initialize, connect, and read firmware version from each arm
- Config — select arm configuration (1 Leader/1 Follower, 2 Followers, 2 Leaders, 2 Leaders/2 Followers)
- Identify — click
Findfor each slot, then physically move the target arm more than 45° to assign it; useSet Roleto apply leader/follower mode andTorque Offto release the arm - Finalize — rename CAN ports to canonical names (
can_leader1,can_follower1, etc.) and save~/piper_config.json
piper-ui — Direct Control
piper-ui
- CAN Setup: detect interfaces, view firmware version and USB port per interface, select role (leader/follower), initialize bitrate
- Connect: select a port via radio button, then click Connect — sliders automatically sync to the arm's current joint positions
- Torque: toggle torque on/off; sliders and Parking are disabled while torque is off
- Set Leader / Set Follower: apply
MasterSlaveConfigto switch the arm between teaching input mode and motion output mode - Parking: move the arm to the home position (joint values: 0, −100, 100, 0, 35, 0, 0)
- Joints: drag sliders to move joints in real time (only active when torque is on); live position readout next to each slider
piper-teleop — Teleoperation Monitor
piper-teleop
- Detect and initialize CAN interfaces
- Launch pre-configured teleoperation/recording commands
- Real-time joint position bars for both arms (leader & follower)
- Follower arm status (enable state, motion status, error codes)
piper-calibrate — Joint Zero-Point Calibration
piper-calibrate
- Connect to a Piper arm via CAN
- Manually move each joint to its zero (home) position
- Click Set Zero — writes the zero-point to the motor's flash (persists across power cycles)
- Real-time joint monitor shows raw positions for verification
camera_check.py — Camera Grid Viewer
python camera_check.py
Probes /dev/video0 … /dev/video17, opens every working camera, and shows all streams in one grid — useful for finding camera indices before recording.
Quick Start
1. Python API
from lerobot_robot_piper import PiperFollowerConfig, PiperLeaderConfig, PiperFollower, PiperLeader
follower_cfg = PiperFollowerConfig(port="can_follower1")
leader_cfg = PiperLeaderConfig(port="can_leader1")
follower = PiperFollower(follower_cfg)
leader = PiperLeader(leader_cfg)
follower.connect()
leader.connect()
try:
while True:
action = leader.get_action() # read leader joint positions
follower.send_action(action) # mirror to follower
obs = follower.get_observation() # read follower state + cameras
finally:
follower.disconnect()
leader.disconnect()
2. LeRobot CLI
# Teleoperate
python -m lerobot.teleoperate \
--robot.type=piper_follower \
--robot.port=can_follower1 \
--teleop.type=piper_leader \
--teleop.port=can_leader1
# Record a dataset
python -m lerobot.record \
--robot.type=piper_follower \
--robot.port=can_follower1 \
--teleop.type=piper_leader \
--teleop.port=can_leader1 \
--dataset-id=my_piper_dataset
Configuration
PiperFollowerConfig
| Parameter | Type | Default | Description |
|---|---|---|---|
port |
str |
"can0" |
CAN port for the follower arm |
disable_torque_on_disconnect |
bool |
True |
Disable motors when disconnecting |
cameras |
dict[str, CameraConfig] |
{} |
Named cameras for observation |
max_relative_target |
float | dict | None |
None |
Max per-step joint movement (safety limit) |
PiperLeaderConfig
| Parameter | Type | Default | Description |
|---|---|---|---|
port |
str |
"can1" |
CAN port for the leader arm |
gripper_open_pos |
float |
50.0 |
Position value representing gripper fully open |
Motor Configuration
The Piper arm has 7 joints. Normalization maps raw encoder counts to the ranges shown below.
| Joint | Model | Normalized Range | Physical Range |
|---|---|---|---|
| Joint 1 | AGILEX-M | −100 to +100 | ±150° |
| Joint 2 | AGILEX-M | −100 to +100 | 0–180° |
| Joint 3 | AGILEX-M | −100 to +100 | −170–0° |
| Joint 4 | AGILEX-S | −100 to +100 | ±100° |
| Joint 5 | AGILEX-S | −100 to +100 | ±65° |
| Joint 6 | AGILEX-S | −100 to +100 | ±100–130° |
| Gripper | AGILEX-S | 0 to 100 | 0–68° |
The parking (home) position in normalized values: 0, −100, 100, 0, 35, 0, 0.
Project Structure
lerobot_robot_piper/
├── config_piper.py # PiperFollowerConfig
├── config_piper_leader.py # PiperLeaderConfig
├── piper_follower.py # PiperFollower (Robot)
├── piper_leader.py # PiperLeader (Teleoperator)
├── ui.py # piper-ui entrypoint
├── teleop_ui.py # piper-teleop entrypoint
├── arm_setup_ui.py # piper-setup entrypoint (multi-arm wizard)
├── calibration_ui.py # piper-calibrate entrypoint
├── doctor.py # piper-doctor entrypoint (installation checkup)
└── motors/
├── piper_motors_bus.py # CAN bus abstraction
├── port_handler.py # CAN port lifecycle (absorbed from wego_piper)
└── tables.py # Motor model tables
lerobot_robot_wego_piper/ # PyPI-name discovery shim (re-exports the package above)
scripts/
├── can_activate.sh # single-CAN activation
├── can_restore.sh # bring up arms from ~/piper_config.json
├── install_can_persist.sh # serial-pinned udev rules + bring-up service
└── list_can_adapters.py # adapter serial <-> interface, --watch to identify
camera_check.py # camera grid viewer
License
Apache-2.0
Metadata
Release files for lerobot-robot-wego-piper 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lerobot_robot_wego_piper-0.3.0.tar.gz | 43.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lerobot_robot_wego_piper-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 89.9 kB
Release files / lerobot_robot_wego_piper-0.3.0.tar.gz
| Download URL | lerobot_robot_wego_piper-0.3.0.tar.gz |
|---|---|
| Size | 43.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d0a279a543c4a6e9d772b59010d47dcbebf895bd29411e1a416a8b09fbb7ff21
|
|
BLAKE2b-256 checksum How to use checksums |
773f91fa41a428fc864c6d51b260e46e0ebf5df48ef0ffcbe81a3f3ddb91f1ab
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.
Transparency logRelease files / lerobot_robot_wego_piper-0.3.0-py3-none-any.whl
| Download URL | lerobot_robot_wego_piper-0.3.0-py3-none-any.whl |
|---|---|
| Size | 46.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6308e04e4ba7dc6aae9004720f283d13034c36a96339df560e918a23fbd0bc00
|
|
BLAKE2b-256 checksum How to use checksums |
5d5fba9c7882407088ea0951d3ca5d0cdf7b76c7bba27545910aa934d6ae8265
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.
Transparency log