Chris Shi Robotics

Robot Jousting

The Tilt of Tiltford. Two real robot arms with 3D-printed swords fence each other on stepper rails while a crowd plays from their phones.

Two real SO-100/SO-101 robot arms, each holding a 3D-printed sword, fence each other on stepper rails at a medieval festival. Players fight from their phones. A crowd watches. It is an HRI experiment in whether a machine can make a room of people cheer. We built it at HackCMU 2026, on 12 September 2026.

  • HackCMU 2026
  • SO-100 and SO-101 arms
  • Stepper rails
  • MuJoCo
  • 3D-printed fencing gripper
  • Team of three

Every move was designed in MuJoCo, then tuned on the real arms, and the moves are chained together by a transition library so one motion can run into the next. The game waits on the real motions — the screen does not resolve an exchange until the arms have actually fought it.

Plays each step in order.

The real arms

  1. 1 Overhead chop, high bar blocked

    Overhead chop meets the high bar. Blocked.

    Engineering

    The screen beat is stretched to the real motion — an overhead chop is 4.5 s of arm time, not the 1.4 s the screen would take on its own.

  2. 2 Overhead chop, low guard the hit lands

    Overhead chop against a low guard. The hit lands.

    Engineering

    It drives the carriages together for the charge and apart for the return, plays each beat on both arms, and waits on the arms' own busy flags rather than on timers.

  3. 3 Low slash, right-hand guard blocked

    A low slash from the left meets the right-hand guard. Blocked.

    Engineering

    Rules used everywhere: hand no more than 0.27 m forward of its own base (hands never cross the centre line), nothing below the base plane, servo speed ~300 deg/s, the real wrist roll must not cross +/-180.

  4. 4 A whole bout 3x speed

    A whole bout, played from the laptop (3x speed)

    Engineering

    A mock daemon carrying the real motion timings lets the whole thing be rehearsed with no hardware attached. In rehearsal the screen never released before the arms, with a worst margin of +23 ms.

Code Write-up Trailer Demo

Driving the arms live

At the start of a match the game prepares the hardware: home the rails, move apart, both arms to rest. It drives the carriages together for the charge and apart for the return, plays each beat on both arms, and waits on the arms’ own busy flags rather than on timers. The screen beat is stretched to the real motion — an overhead chop is 4.5 s of arm time, not the 1.4 s the screen would take on its own.

A mock daemon carrying the real motion timings lets the whole thing be rehearsed with no hardware attached. In rehearsal the screen never released before the arms, with a worst margin of +23 ms.

Players choose their own openers and finishing flourishes. The En garde opener runs before the first beat; the Samurai finish runs after the knockout, with the winner raining blows while the loser collapses. Both stream the rail carriages in time with the arm motions.

The arms sit on stepper rails and charge in to 19.5 inches of each other.

Calibration, by hand

The arms’ servo calibrations live in the repo, in calib/. We calibrated the SO-100 by holding it at the zero pose and sweeping every joint to its stops, then checked the zero points against physical references — the arm leaning fully back on its board, the upright square pose, the blade sitting on top of the gripper — before we trusted the taught moves on the real arm.

The hardware

We printed a fencing gripper for the arms: a sword holder that takes swappable 6 and 8 inch blades in five styles — fang, katana, rapier, falchion and crystal — plus a shield, a gauntlet and a sword-breaker talon for the wrist. For the tilt itself we printed a plate with one of each 8 inch blade, plus the gauntlet and talon wrists.

The demo