Hand-Controlled Robot Arm

Hackathon build · 24 hours · solo

Hand-Controlled Robot Arm

Move your hand in front of a camera and the robot arm moves with you. Make a fist and the gripper closes. No gloves, no controller: just a webcam, hand tracking and an Arduino.

5 servos 21 hand landmarks per frame 30 commands / s 115200 baud 1.5 cm floor clearance

Hand: -- Arm: not connected

Directions

Sample motion. Start the camera or use your mouse to take control.

Move left / rightBase90°
Move up / downShoulder90°
Closer / fartherElbow90°
Tilt your handWrist90°
Make a fist to grabGripperOPEN
Arm model (3D)

Drag to rotate. Double-click to reset the view.

Serial packet<90,95,89,90,30>

Sample motion

Your webcam stays in your browser. Frames are never uploaded.

Hand tracking runs on your device with Google MediaPipe. The arm connection uses Web Serial, available in Chrome and Edge on desktop.

Signal path

From your hand to a servo

Every camera frame goes through the same six steps. The Python app and the demo above share the same numbers, so what you see in the browser is how the real arm behaves.

  1. 1

    Camera

    A webcam or Raspberry Pi camera at 640×480 (320×240 on a Pi). The image is mirrored so it feels like a reflection.

  2. 2

    Hand landmarks

    MediaPipe finds 21 points on one hand: the wrist, each knuckle and each fingertip.

  3. 3

    Measurements

    Palm position, palm size (how close you are), knuckle-line tilt, and how far the fingertips reach from the wrist.

  4. 4

    Joint angles

    Each measurement maps onto one servo's range, then a moving average smooths out jitter.

  5. 5

    Floor limit

    The pose is checked against the arm's real dimensions and raised if any part would touch the floor.

  6. 6

    Arduino

    Angles go over USB as <b,s,e,w,g>. The Arduino eases each servo toward its target at 2° per 15 ms.

Your handArm jointHow it's measuredServo range
Move left / rightBase turnsPalm x across the frame20°–160°
Move up / downShoulder liftsPalm y down the frame40°–140°
Move closer / fartherElbow reachesPalm size, wrist to middle knuckle40°–140°
Tilt your handWrist rotatesAngle of the knuckle line, ±60°30°–150°
Make a fistGripper closesFingertip reach ÷ palm size, below 1.15 to close, above 1.40 to open30° / 100°

If your hand leaves the frame, nothing is sent and the arm holds its last position.

Safety

The arm never touches the floor

Before any command is sent, the software works out where the elbow, wrist and gripper tips would be, using the arm's measured lengths. If any of them would come within 1.5 cm of the floor, the pose is raised just enough to clear it.

Stop and slide

The elbow bends up first. If the elbow joint itself would hit the floor, the shoulder lifts and then the elbow is corrected. Each correction is the smallest one that works, so pushing your hand down makes the arm stop at the floor and slide along it instead of jumping.

Tested, not assumed

  • 11,025 poses checked: none below the floor, none outside a servo limit.
  • About 0.2 ms per check, fast enough for every frame.
  • The Arduino also clamps every angle to hard limits, as a second layer.

Try it above: in mouse mode, move to the bottom of the pad and set the distance to “farther”. The badge turns on and the model shows where the arm is closest to the floor.

Hardware & software

What it's built from

Hardware

  • Pre-built 5-servo robot arm (base, shoulder, elbow, wrist, gripper)
  • Arduino, receiving packets over USB serial
  • Laptop, or a Raspberry Pi running headless
  • Webcam or Raspberry Pi Camera Module
  • Separate 5–6 V supply for the servos, sharing ground with the Arduino

Software

  • Python, MediaPipe Hand Landmarker, OpenCV
  • Tkinter desktop app with a hand-drawn 3D arm view
  • pyserial and an Arduino sketch with per-servo limits and easing
  • This page: MediaPipe for the web, Canvas 2D, Web Serial
Run it

Set up in three steps

# 1. Upload arm_receiver/arm_receiver.ino to the Arduino
pip install mediapipe opencv-python pyserial pillow   # 2. install
python3 arm_gui.py                                    # 3. run (add --headless on a Pi)

Source code: [GITHUB LINK]