Meet "Barbara", the six-DOF arm
The rover's six-degree-of-freedom manipulator — how it is driven, how it finds its own zero with a camera, and how it avoids tying itself in knots.
Most of what wins points at the European Rover Challenge beyond driving comes down to one subsystem: the arm. Flipping switches, measuring voltages, powering an electromagnetic lock, seating an RJ-45 plug in a socket — the maintenance and probing tasks are all fine motor work, done remotely, on a rover the operator cannot see directly. That work belongs to Barbara, our six-degree-of-freedom manipulator.
Six joints, two brands of muscle
Barbara is built on Dynamixel smart servos — a mix of XH-series and the larger P-series motors, the beefier ones carrying the load closer to the base. They all speak Dynamixel Protocol 2.0 over a single bus, through a U2D2 adapter on /dev/ttyUSB0.
The whole arm runs on ros2_control. Two libraries do the heavy lifting: FZI’s cartesian_controllers for Cartesian motion, and ROBOTIS’ dynamixel_hardware_interface for talking to the servos. At start-up the joint-state broadcaster, the Cartesian motion controller and a pose broadcaster come up active, with a joint-trajectory controller held in reserve.
Mixing two servo families on one bus has a catch worth mentioning: the “goal position” register lives at a different address on the XH and P motors. We paper over that with Dynamixel indirect address pointers, configured once so a single bulk write reaches every joint at the same register — which is what keeps the control loop fast enough to be useful.
Two ways to drive it
An operator can command Barbara in one of two modes, toggled live from the controller:
- Cartesian (IK) mode is the default and the intuitive one. You push the end-effector — forward, left, up — and inverse kinematics works out what all six joints must do to move the tip that way. This is how you line a gripper up with a switch without thinking about shoulder and elbow angles.
- Direct joint mode hands you one joint at a time — base rotation, shoulder, elbow, wrist yaw, pitch and roll. Slower, but it is the mode you want when you need to unwind a joint from an awkward pose or work in a tight corner where the IK solution is not the one you had in mind.
For input we use a SpaceMouse — its six-axis puck maps naturally onto the arm’s six Cartesian degrees of freedom, publishing a Twist that the controller turns into pose targets — and, more recently, an ordinary PlayStation controller, which publishes to the very same topic for compatibility. Both offer a scalable speed setting with haptic feedback: the pad rumbles when you change speed, and rumbles differently when you hit the limit. The gripper follows a simple, deliberately paranoid protocol — 1.0 to open, -1.0 to close, 0.0 to stop — and the hardware halts on its own if it hears nothing for more than a second, so a dropped link can never leave it clamping.
Finding zero with a camera
A servo arm only knows where it is relative to where it thinks “zero” is. Get that wrong and every Cartesian command is off by the same error. Barbara can re-zero her wrist roll axis — the fifth axis — automatically, using a camera.
The trick is a small ring of coloured segments (white, green, blue, red) on the wrist. A dedicated node watches the wrist camera and jogs the axis until the blue segment is centred in the frame, at roughly 326 px. It runs in two phases: a search phase that sweeps toward blue when it can only see its neighbours, and a centring phase that closes in with proportional feedback on the blue segment’s centroid.
A few details make it robust rather than fragile:
- Timestamp-filtered frames. After each jog it grabs the image with the matching completion timestamp and throws away the stale frames still sitting in the queue, so the loop only ever acts on a settled view.
- Self-calibrating direction. A test jog tells it which way blue lies; if that jog moves blue away, it reverses and sweeps the other way.
- Safety aborts. If cumulative roll passes 360° (±4000 pulses), or it can only see the white segment — which sits directly opposite zero, so the direction is ambiguous — it stops rather than guess.
There is also a mechanical fallback: a homing routine that drives each joint gently into its hard-stops to establish an accurate zero, after which the offsets are written to a YAML file and simply reloaded on the next launch.
Not tying itself in knots
A six-DOF arm on top of a rover has plenty of ways to hit itself, the chassis, or a rear-mounted sensor. Static joint limits would keep it safe by keeping it useless — you would have to clip the whole workspace to the worst case.
Instead Barbara uses dynamic joint limits. A joint’s allowed range can depend on where the other joints are, written as an expression right in the URDF and evaluated synchronously inside the real-time hardware loop at 120 Hz. So the shoulder can swing freely most of the time, but its limit tightens automatically the moment the base rotates the arm back over the rover; the elbow’s range shrinks when the shoulder is at an extreme angle to avoid cable strain and segments colliding. To keep the expressions readable we provide helper functions — ifelse, gt, and and friends — instead of drowning the XML in escaped < and &&.
The result is an arm that gives the operator its full reach where it is safe to have it, and quietly pulls those limits in exactly where and when it would otherwise fold into itself — which, when you are threading an RJ-45 plug into a socket from a couple of hundred metres away, is precisely the safety net you want.