Bring up LeKiwi wheel servos on a partially assembled chassis by assigning Feetech STS3215 wheel IDs 7/8/9 one-at-a-time without requiring the arm to be installed.
Use this when:
/dev/ttyACM0)lerobot-setup-motors --robot.type=lekiwi is a bad fit because it expects arm motors too{} or wheels have never been assigned IDsDo NOT use the full interactive LeKiwi setup flow on a partially assembled robot with multiple wheel servos connected. That is how you scramble IDs and waste an evening.
base_left_wheel -> 7base_back_wheel -> 8base_right_wheel -> 96,5,4,3,2,19,8,7robot.bus.setup_motor('<wheel_name>') directly./dev/ttyACM0 existsQuick checks:
ls -l /dev/ttyACM* /dev/ttyUSB* 2>/dev/null || true
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
from lerobot.robots.lekiwi.lekiwi import LeKiwi
from lerobot.robots.lekiwi.config_lekiwi import LeKiwiConfig
LeKiwi(LeKiwiConfig(port='/dev/ttyACM0', cameras={}))
print('LeKiwi import/construct OK')
PY
Disconnect all wheel servos from the bus. Then repeat this process for each wheel.
Connect only the left wheel servo, then run:
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
from lerobot.robots.lekiwi.lekiwi import LeKiwi
from lerobot.robots.lekiwi.config_lekiwi import LeKiwiConfig
robot = LeKiwi(LeKiwiConfig(port='/dev/ttyACM0', cameras={}))
print('Setting up base_left_wheel -> target ID 7')
robot.bus.setup_motor('base_left_wheel')
print('DONE')
PY
Connect only the back wheel servo, then run:
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
from lerobot.robots.lekiwi.lekiwi import LeKiwi
from lerobot.robots.lekiwi.config_lekiwi import LeKiwiConfig
robot = LeKiwi(LeKiwiConfig(port='/dev/ttyACM0', cameras={}))
print('Setting up base_back_wheel -> target ID 8')
robot.bus.setup_motor('base_back_wheel')
print('DONE')
PY
Connect only the right wheel servo, then run:
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
from lerobot.robots.lekiwi.lekiwi import LeKiwi
from lerobot.robots.lekiwi.config_lekiwi import LeKiwiConfig
robot = LeKiwi(LeKiwiConfig(port='/dev/ttyACM0', cameras={}))
print('Setting up base_right_wheel -> target ID 9')
robot.bus.setup_motor('base_right_wheel')
print('DONE')
PY
After each individual setup, scan the port:
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
from lerobot.motors.feetech.feetech import FeetechMotorsBus
print(FeetechMotorsBus.scan_port('/dev/ttyACM0'))
PY
Expected outputs while only one wheel is connected:
{1000000: [7]}{1000000: [8]}{1000000: [9]}After assigning all IDs, connect all three wheel servos and rescan:
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
from lerobot.motors.feetech.feetech import FeetechMotorsBus
print(FeetechMotorsBus.scan_port('/dev/ttyACM0'))
PY
Expected result:
{1000000: [7, 8, 9]}
Order may vary, but the set should be 7/8/9.
setup_motor() call.lerobot-setup-motors --robot.type=lekiwi flow on a chassis without the arm installed.{} but /dev/ttyACM0 exists, USB-to-controller is alive but controller-to-servo bus is not.If you use the full LeKiwi object and later call disconnect while only a subset of motors exists, you may see errors like:
Failed to write 'Torque_Enable' on id_=1 ... There is no status packet!
That does not mean the wheel ID assignment failed. It happens because the LeKiwi bus object still contains the full expected motor map including missing arm motors. Ignore it in this wheel-only setup context.
/dev/ttyACM0 missing/dev/ttyACM0 exists but scan returns {}Do not use the full LeKiwi object for base-only verification on a chassis that does not have the arm yet. The full object expects IDs 1..9 and will complain about missing arm motors even when wheel setup is correct.
Instead, build a bus object containing only the wheel motors:
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
from lerobot.motors import Motor, MotorNormMode
from lerobot.motors.feetech.feetech import FeetechMotorsBus
bus = FeetechMotorsBus(
port='/dev/ttyACM0',
motors={
'base_left_wheel': Motor(7, 'sts3215', MotorNormMode.RANGE_M100_100),
'base_back_wheel': Motor(8, 'sts3215', MotorNormMode.RANGE_M100_100),
'base_right_wheel': Motor(9, 'sts3215', MotorNormMode.RANGE_M100_100),
}
)
bus.connect(handshake=True)
print('CONNECTED_BASE_ONLY')
print('present velocity', bus.sync_read('Present_Velocity'))
PY
Expected result:
Present_Velocity returns zeros or small near-zero values for all three wheelsOnce scan_port('/dev/ttyACM0') shows IDs 7,8,9 together, do a very small motion test with the robot on the floor, clear space around it, and hands away from the wheels.
cd ~/projects/lerobot
.venv/bin/python - <<'PY'
import time
from lerobot.robots.lekiwi.lekiwi import LeKiwi
from lerobot.robots.lekiwi.config_lekiwi import LeKiwiConfig
from lerobot.motors import Motor, MotorNormMode
from lerobot.motors.feetech.feetech import FeetechMotorsBus, OperatingMode
robot_model = LeKiwi(LeKiwiConfig(port='/dev/ttyACM0', cameras={}))
wheel_cmd = robot_model._body_to_wheel_raw(x=0.0, y=0.0, theta=45.0, max_raw=500)
print('wheel_cmd', wheel_cmd)
bus = FeetechMotorsBus(
port='/dev/ttyACM0',
motors={
'base_left_wheel': Motor(7, 'sts3215', MotorNormMode.RANGE_M100_100),
'base_back_wheel': Motor(8, 'sts3215', MotorNormMode.RANGE_M100_100),
'base_right_wheel': Motor(9, 'sts3215', MotorNormMode.RANGE_M100_100),
}
)
使用 Arthas 的 watch/trace 获取 EagleEye traceId / 获取请求的 traceId