Quick Diagnostic Matrices

Motor Issues

SymptomQuick Fix
No motors moveCheck 12V DC cable from battery to motor board — 5 V USB will not drive them
Permission deniedsudo usermod -aG dialout $USER, then re-login
Whole bus silentDuplicate IDs — scan each motor in isolation
Motor count mismatchScan the bus; the missing ID names the culprit
Single unresponsiveRe-assign its ID with set_motor_id.py, one motor on the chain
Arm jerks / wrong dirVerify IDs match the motor map
Grinding noiseInspect servo horn alignment; replace if stripped
could not open /dev/xle_armsThe bus symlinks do not exist — run python diagnostics/detect_buses.py --write
Answers the bus, never movesLogic power without motor power — check Present_Voltage
Arm drops when a script endsTorque cut instead of bled off — step Torque_Limit down over seconds
Bus vanishes after drivingA cable was tugged loose — check dmesg, then strain-relieve it

Camera Issues

SymptomQuick Fix
Camera not detectedls /dev/video* to check path
Black frameCheck lens cap; test with cv2.VideoCapture
YOLO not trackingVerify camera index in script

Software Issues

SymptomQuick Fix
Import errorspip install -e ".[all]" from the repo root, inside the venv
CUDA unavailableCheck for a +cpu torch build; reinstall from the Jetson index
Module not foundUse the venv interpreter directly: ~/.venvs/xlerobot-pro/bin/python
Joy-Con not pairingsudo apt install joycond, enable Bluetooth

Assembly Issues

SymptomQuick Fix
Arm wobbles/playTighten servo horn screws; check bracket fit
Wheels not straightAdjust z-axis scale in slicer or use printed washers
Cart tips reachingMove battery to lowest shelf to lower CoG

Failure Signatures

Every one of these presents as something other than its cause. That is exactly why they cost people hours — and why they are worth reading once before you need them.

What you seeWhat it actually isFix
[TxRxResult] There is no status packet!
Whole bus dead, yet each motor works in isolation
Duplicate motor IDs. Feetech is half-duplex — two motors on the same ID transmit together and the collision corrupts every packet on the wire, not just theirs. Reads exactly like a power or cabling fault. Scan each motor in isolation and correct the duplicates. See Motor Configuration.
device descriptor read/64, error -110
unable to enumerate USB device
USB physical layer. The adapter is powered and looks connected but never enumerates, so its bus is invisible rather than faulty. New cable first, then plug directly into the Jetson bypassing any hub, then try a different port.
torch.cuda.is_available() → False Wrong PyTorch wheel or wrong environment. Either the CPU wheel won the resolve (check for a +cpu suffix) or torch was installed inside conda. Reinstall from the Jetson index by direct wheel URL, into a venv built on system Python 3.10.
Bus drops mid-calibration, always at the same joint Cable tugged at that joint's travel extreme. Range recording retries only once, so a single dropped packet aborts the run. Add a service loop at that joint. Do not raise the retry count to mask it — the same dropout will recur mid-grasp, under power.
Permission denied: /dev/ttyACM0 User not in the dialout group — or the group was added without logging back in. sudo usermod -aG dialout $USER, then log out and back in.
Motors answer every scan but never move
Load pinned at 1024 + Torque_Limit, current 0
Logic power without motor power. The servos have enough to talk and nothing to move with. A lit LED proves nothing here — the STS3215 has no external LED, so any light you see belongs to the adapter board and only means its barrel jack has voltage. Read Present_Voltage: ~120–135 means 12 V and is healthy; ~50 means the bus is on a 5 V rail. Take 12 V from a battery's car/DC socket, never a USB-to-barrel cable.
could not open port /dev/xle_arms The udev symlinks were never created, or a rules file from an older build has different serials in it. Delete any stale /etc/udev/rules.d/99-xlerobot.rules, then run python diagnostics/detect_buses.py --write — see software step 7.
Grasp lands confidently in the wrong place
Motion is smooth, the target is simply not there
The camera-to-base transform is wrong, not the IK. Head tilt and pan feed that transform, so swapping the two axes — or reading the wrong motors as "head" — produces a transform that looks entirely plausible. Confirm on your hardware that ID 1 moves up/down and ID 2 left/right. Then work through diagnostics/debug_transform_chain.py and diagnose_fk_vs_vision.py.
A script connects, but drives the wrong arm Single-arm scripts address motor IDs 1–6, which on this build is the left arm. The right arm is at 7–12, so a port change alone will never reach it. Use the whole-robot teleop for two-armed work — software step 11.
An arm falls the moment a script starts or ends Torque was cut in one write rather than bled off. Some read-only tools release torque deliberately so you can pose the arm by hand — diagnostics/read_motors.py is one — and bus.disconnect() disables torque by default. Lower the arms before running anything that releases torque. In your own code, pass disconnect(disable_torque=False) and step Torque_Limit down over several seconds instead of zeroing it.
UEFI Interactive Shell v2.2 — Shell> No bootable storage. Run map -r: if the only entries are MemoryMapped and Fv(...), both are internal (RAM and the QSPI firmware volume) and zero block devices are present. Seat a flashed microSD, or confirm firmware is 36.x for a JetPack 6 card.
Error: could not make network connection Not a network fault. UEFI exhausted its boot order and fell through to PXE as a last resort. It is the tail end of "nothing bootable found." Ignore it. Disappears once a bootable card is present.
EXT4-fs (mmcblk0p1): error count since last fsck Filesystem damage on the card, usually from power loss during a write. Accumulates silently. Schedule an fsck at next boot. Prefer clean shutdowns — SD cards tolerate abrupt power cuts poorly.

Diagnostic Order

When a bus misbehaves, this sequence separates causes fastest. Each step rules out an entire class of problem, so work them in order rather than jumping to the most interesting theory.

  1. Does the adapter enumerate?
    lsusb | grep 1a86 and ls /dev/ttyACM*. No device node means the problem is USB, not motors — stop looking at the robot.
  2. Does any motor answer?
    Run scan_port() across all baud rates. A single reply proves power, wiring, baud rate, and protocol all work.
  3. Does one motor answer but not the chain?
    That is duplicate IDs, essentially every time. Go to Motor Configuration.
  4. Does the chain answer but drop under motion?
    Cable routing at a rotating joint. Find the joint that reproduces it and add slack there.
RESIST CHANGING TWO THINGS AT ONCE. Most of the difficulty in bringing one of these robots up comes from a working subsystem being disturbed while chasing a broken one.

Deep Dive: Camera Not Detected

Hardware / USB

Symptoms

  • ls /dev/video* shows no entries or fewer cameras than expected.
  • cv2.VideoCapture() returns False for ret.
  • YOLO tracking script errors with “no camera found”.
  • Camera LED is off even though it’s plugged in.

Likely Causes

  • USB cable not seated: Loose connection or damaged cable.
  • USB hub not powered: Hub can’t supply enough current for multiple cameras.
  • Wrong device index: Camera is at a different path than the script expects.
  • Kernel driver issue: Camera module not loaded (rare on Ubuntu).

Diagnostic & Fix Steps

1. Check Physical Connection: Unplug and replug the camera. Try a different USB port. Try without the USB hub (direct to PC) to isolate the issue.

2. Check USB Power: If using a USB hub, make sure it’s powered. Low-power hubs may not supply enough current for multiple cameras.

3. Check Device Detection: You should see even-numbered entries (/dev/video0, /dev/video2) — one per camera.

List Video Devices
$ ls /dev/video*

# To see detailed device paths:
$ v4l2-ctl --list-devices

4. Test the Camera Directly: Use a one-line Python test to verify the OpenCV pipeline.

Quick Camera Feed Test
$ python -c "import cv2; cap = cv2.VideoCapture(0); ret, frame = cap.read(); print('OK' if ret else 'FAIL'); cap.release()"

Verification Checklist

  • ls /dev/video* shows the expected number of devices.
  • The Python camera test returns OK.
  • YOLO or teleoperation scripts run without camera errors.

Prevention Tips

  • Use a powered USB hub for multiple cameras.
  • Always use the same USB ports—paths change when swapped.
  • Label USB cables to avoid confusion during setup.