← Back to Software Setup

Outcome

Walk the gripper to a physical object on your desk using coordinates rather than joint angles, confirming that the whole command-to-servo pipeline works on your hardware.

What you will learn

  • Joint space vs. Cartesian space
  • What an inverse-kinematics solver is for
  • How to tell a software error from a mechanical one

Prerequisites

  • Software setup finished through step 9.
  • One arm's motors have unique IDs and the arm is calibrated.
  • Every motor answers diagnostics/check_bus.py.
  • The workspace in front of the arm is clear.
Estimated Time: 10–15 Minutes

What Inverse Kinematics Actually Does

Up to now you have moved the robot the way the motors think: shoulder to 30°, elbow to −45°. That is joint space. It works, but it is a terrible way to describe "touch that cup" — you would have to solve the geometry in your head.

Inverse kinematics flips the problem around. You name a point in space and the solver works backwards to the joint angles that put the gripper there. That is Cartesian space, and it is how every useful manipulation task is expressed.

This robot has two IK solvers, and they are for different jobs

SolverHow it worksUsed by
Closed-form 2-link
this tutorial
Law of cosines on the shoulder-lift and elbow pair. One equation, instant answer, no iteration. Only solves the arm's vertical plane. 1_so100_keyboard_ee_control.py
Pink (Pinocchio)
the autonomous demos
Differential IK over the full arm model — nudges all joints toward the target a step at a time, handling orientation and singularities. xlerobot_pro.IK_SO101, used across examples/vision/

You are starting with the simple one on purpose. It has almost nothing that can go wrong, so anything that does go wrong here is your hardware — which is exactly what this tutorial is for.

THE SOLVER TRUSTS YOUR CALIBRATION COMPLETELY. It has a model of the arm's link lengths and it assumes the joint angles it reads are true. If calibration is off, IK will confidently compute a perfect answer to the wrong question — and the arm will miss by exactly that much. This is why calibration gets verified before you reach this page.

Instructions

1. Set the terminal up

Activate the environment and move to the repository root.

Terminal
$ source ~/.venvs/xlerobot-pro/bin/activate
$ cd ~/xlerobot-pro
Serial permission errors? Permission denied: /dev/ttyACM0 means you are not in the dialout group — or you added yourself and never logged back out. Run sudo usermod -aG dialout $USER, then log out and in. sudo chmod 666 /dev/ttyACM* also works, but only until the next reboot.

2. Launch the script

Terminal
$ python examples/xlerobot_examples/1_so100_keyboard_ee_control.py

It asks you two questions before anything moves.

PromptWhat to answer
"Please enter the USB port…" Full 2-bus robot: /dev/xle_arms
Benchtop rig: /dev/ttyACM0, or just press Enter for that default
"Do you want to recalibrate the robot? (y/n)" n — you already calibrated in software setup. Answering y throws that away and starts over.
THIS SCRIPT DRIVES ONE ARM AT MOTOR IDs 1–6. On the full robot, those are the left arm. Pointing it at /dev/xle_arms moves the left arm and never the right — the right arm lives at IDs 7–12, which needs a different motor map, not just a different port. For two-armed work use the whole-robot teleop instead.
THE ARM MOVES UNDER POWER AS SOON AS IT CONNECTS. It first drives slowly to its zero position, then holds. Clear the workspace, keep your hands out of the swept volume, and keep a hand near the supply switch. Torque and acceleration are clamped by src/xlerobot_pro/firmware_limits.py, but a clamped arm still hits hard enough to hurt.

3. Learn the keys

Three of these pairs are Cartesian — they name a point and let IK find the angles. The rest are direct joint control, because a 2-link solver cannot express them.

KeysWhat movesKind
W / SEnd-effector X — reach in and outCartesian (drives joints 2+3)
E / DEnd-effector Y — height in the arm's vertical planeCartesian (drives joints 2+3)
Q / Ashoulder_pan — swings the whole arm left and rightDirect joint
R / FPitch adjustment — tilts wrist_flexDirect joint
T / Gwrist_rollDirect joint
Y / Hgripper — close and openDirect joint
XExit — returns to the start position first
EscExit immediately
PREFER X OVER Esc TO QUIT. X walks the arm back to where it started before releasing it. Esc stops where it stands, which is fine at rest and unpleasant if the arm is extended.
DO NOT GUESS THE SIGN CONVENTION — TAP AND READ. Press W once and watch the terminal print Update x coordinate: …. One tap tells you which way that key sends the gripper on your build, and each step is only 4 mm, so a wrong guess costs nothing. Holding a key queues a long move that is hard to stop cleanly.

4. Reach a physical target

Place a small object — a cup or a bottle — roughly 15–20 cm in front of the arm base. Then work in this order, which is easier than it sounds once you try it:

  1. Q / A to swing the arm until it is pointing at the object.
  2. E / D to set the height.
  3. W / S to reach out until the gripper is around it.
  4. Y / H to close the gripper.

Aiming with pan first and reaching last keeps the gripper away from the object while you are still finding the range.

Expected Output & Validation

Physical behaviour

The gripper tracks the coordinate you set, smoothly — the script runs a P-control loop toward the target rather than snapping. Accuracy within 1–2 cm is normal for a well-built arm.

Software feedback

Every keypress prints the updated coordinate or joint target. Those lines should appear on every press — even when the arm physically cannot get there.

THE SOLVER CLAMPS INSTEAD OF FAILING. Ask for a point beyond the arm's reach and it scales the request back to the workspace boundary rather than erroring. So an arm that stops following your keypresses is usually at the edge of its reach, not broken.

Troubleshooting

Arm jerks or moves wildly. Almost always a motor ID mismatch or a servo horn installed a tooth off. Recheck Motor Configuration.

Coordinates update but nothing moves. The solver is running and the bus is not. Most often the motors have logic power but no motor power — a 5 V rail instead of 12 V. Confirm with python diagnostics/check_bus.py --motors arm.

Straight-line motion, but it consistently misses in one direction. That is calibration, not IK. Re-run calibration and check the left/right symmetry table in the Build Guide.

It will not reach a point you are sure is reachable. A joint's calibrated range is probably narrower than its real travel, because it was not swept all the way to both end stops during calibration.

The arm drops when you quit. Torque was cut rather than bled off. Quit with X so it returns to start first, and never cut torque on a loaded arm.

The bus dies partway through a long move. A cable is being tugged at a joint's travel extreme. Add a service loop at that joint — it will otherwise recur mid-grasp, under power.

Reaching by hand works. Let the camera pick the target next.

Autonomous Cube Grasp ↗