Skip to content

daniellowell/handpose-robotics

Repository files navigation

uHand Controller Workflows

Two end-to-end paths let you drive the uHand from MediaPipe hand tracking:

  • USB workflow (usb/) – Plug the Arduino UNO into your computer and stream percentage commands (P:…) over the virtual serial port.
  • Serial-pin workflow (serial/) – Talk to the controller's UART header using the binary packet protocol defined in serial/uhand_protocol.py.

The guides usb/PROJECT_GUIDE.md and serial/PROJECT_GUIDE.md walk through wiring, firmware expectations, and quick checks.

Recent Improvements (October 2025)

Session 3 Updates (Latest):

  • Fixed angle threshold defaults - Restored correct values (180°→90° for fingers, 165°→95° for thumb) that were accidentally changed
  • Fixed Arduino EMA smoothing - Re-enabled proper exponential moving average that was disabled, eliminating jerky motion
  • Fixed Python smoothing - Changed from 0.3 to 0.6 alpha for faster, more responsive tracking
  • Fixed send rate - Reduced from 100Hz to 20Hz to prevent serial buffer overflow
  • Calibration drift prevention - Added automatic keep-alive mechanism that prevents servos from detaching during calibration, solving position drift issues
  • Improved GET command - Better serial buffer handling and error messages when reading EEPROM calibration
  • Diagnostic tools added - Created test scripts for power, servo response, real-time tracking, and individual servo testing

Session 2 Updates:

  • Calibration GET command fixed - Now properly loads EEPROM values during calibration
  • Performance optimizations - No-op logging functions, eliminated unnecessary dict construction when logging disabled
  • Code cleanup - Removed debug spam, direct global access for threshold values
  • Arduino config restored - Fixed swivel defaults and invert flags

Session 1 Updates:

  • 3D joint-angle detection - Uses MediaPipe's full x,y,z coordinates (CRITICAL: was using only 2D x,y which failed when fingers bent toward/away from camera)
  • PIP/DIP angle-based flexion instead of TIP-MCP distance for more stable detection
  • Configurable thresholds via CLI (--finger-open, --finger-close, --thumb-open, --thumb-close, --dip-blend)
  • Servo feedback logging - Arduino reports actual positions for diagnostics
  • Comprehensive analyzer (usb/analyze_log.py) with automatic issue detection and recommendations
  • Optimized loops - Non-blocking STATUS queries, char arrays instead of String on Arduino (2-3x faster)

⚠️ IMPORTANT:

  • The angle calculation uses 3D vectors and works regardless of hand orientation
  • For inverted servos (Middle, Ring, Pinky), calibration must have MIN > MAX in EEPROM
  • Arduino auto-detaches servos after 2 seconds of no commands (saves power, prevents buzzing)

⚠️ KNOWN ISSUES:

  • Some Arduino pins (D6, D7) may not respond - check wiring or remap pins if needed
  • Swivel remains at neutral 50% (wrist rotation not implemented yet)

1. Prerequisites

  1. Use a virtual environment if possible:
    python -m venv .venv
    source .venv/bin/activate
  2. Install Python dependencies:
    pip install -r requirements.txt
  3. Download the MediaPipe model (place in repo root as hand_landmarker.task):
    curl -o hand_landmarker.task \
      https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task

2. USB Workflow (MediaPipe → P: packets)

Main controller:

python usb/pose2hand.py [--port SERIAL_PORT] [--cam INDEX] [--log-json session.json]

Recommended with joint-angle tuning:

python usb/pose2hand.py --log-json session.log \
  --finger-open 175 --finger-close 85 \
  --thumb-open 175 --thumb-close 70 \
  --dip-blend 0.35

Key options:

  • --calibrate – interactive per-finger limits (sends CAL/SAVE). Now uses single-servo S: commands to prevent jitter on inactive fingers.
  • --smooth – EMA coefficient for percent smoothing (default 0.6).
  • --send-hz – command rate (default 20).
  • --finger-open/--finger-close – angle thresholds for fingers in degrees (default: 180°→90°)
  • --thumb-open/--thumb-close – angle thresholds for thumb in degrees (default: 165°→95°)
  • --dip-blend – DIP joint blend factor 0-1 (default: 0.35; higher = smoother)
  • --log-json PATH – append structured diagnostics including joint angles and servo feedback
  • --no-print-tx – silence the human-readable P:… lines.

Analyze session logs:

python usb/analyze_log.py session.log

Provides comprehensive diagnostics: performance metrics, joint angle analysis, servo feedback, jitter detection, and actionable recommendations.

Helpful scripts:

  • python usb/directusbtest.py – send a scripted degree sequence to verify wiring/firmware without MediaPipe.

3. Serial-Pin Workflow (Binary Protocol)

Use when you have direct access to the UART header or a custom firmware responding to the 0xAA 0x77 packet format.

Common utilities:

python serial/test_serial.py      # send SET_ANGLES + read-back
python serial/writetest.py        # single SET_ANGLES packet
python serial/readtest.py         # issue READ_ANGLE and decode reply
python serial/loopbacktest.py     # sanity check adapter wiring

All scripts read connection details from serial/config.json (PORT, BAUD, etc.).

4. Calibration Tips

  • Launch python usb/pose2hand.py --calibrate to capture per-finger open/closed angles. Use the j/J/l/L keys for fine/coarse adjustments; press m to mark MIN (open) and n to mark MAX (closed).
  • The dialog now logs every adjustment when --log-json is active, making it easier to debug twitchy servos or reversed ranges.
  • CAL_SETTLE_REPEATS (top-level constant) controls how many times each degree command is resent to overcome firmware EMA smoothing. CALIB_CLAMP_MIN/CALIB_CLAMP_MAX and CALIB_START_DEG expose the servo bounds without digging through the loop, while SERIAL_LIVE_TIMEOUT, SERIAL_CAL_TIMEOUT, and SERIAL_COMMAND_DELAY tune responsiveness.

5. Tests & Diagnostics

  • python test_camera_preview.py – confirm camera feed.
  • python test_mp_handpose.py – confirm MediaPipe landmarks.
  • USB serial smoke test: python usb/directusbtest.py.
  • UART smoke test: python serial/test_serial.py.

6. Logging & Diagnostics

With --log-json PATH, both live and calibration modes emit newline-delimited JSON. Example entry:

{"ts": 1720000000.123, "event": "serial_send", "frame": 42,
 "raw_percentages": [12.5, 18.7, 33.3, 27.4, 41.2, 50.0],
 "smoothed_percentages": [10, 18, 32, 26, 40, 50],
 "angles": {"thumb_ip": 145.2, "index_pip": 175.8, "index_dip": 172.3, ...},
 "elapsed_since_last": 0.052, "send_period": 0.05, "fps": 19.6}

Additional logged events:

  • live_start – session parameters including angle thresholds
  • servo_status – actual servo positions and calibration limits from Arduino (every 2 seconds)
  • hand_presence – when hand enters/leaves frame

Analyze logs with:

python usb/analyze_log.py session.log        # Full diagnostic report
python usb/analyze_log.py session.log --stats       # JSON statistics
python usb/analyze_log.py session.log --jitter index  # Per-finger jitter
python usb/analyze_log.py session.log --angles thumb_ip  # Plot angles

7. Key Constants & Helpers

  • FLEXION_OPEN_THRESHOLD / FLEXION_CLOSE_THRESHOLD – tweak these if MediaPipe percentages hover near 50 %. Lowering the open value or raising the close value amplifies finger travel.
  • SERIAL_LIVE_TIMEOUT, SERIAL_CAL_TIMEOUT, SERIAL_COMMAND_DELAY – govern serial responsiveness in live and calibration modes.
  • CALIB_CLAMP_MIN, CALIB_CLAMP_MAX, CALIB_START_DEG, CAL_SETTLE_REPEATS – adjust servo bounds and smoothing without digging into the calibration loop.
  • MP_MIN_HAND_DETECTION_CONF, MP_MIN_HAND_PRESENCE_CONF, MP_MIN_TRACKING_CONF – expose MediaPipe confidence thresholds.
  • Logging helpers (module_version, build_env_snapshot, send_line) were designed so future LLMs can follow the data flow; events such as env_snapshot, model_loaded, serial_send, and shutdown provide breadcrumbs when reviewing logs.

8. Repository Map (selected)

usb/
  pose2hand.py              # MediaPipe → serial with joint-angle detection
  analyze_log.py            # Comprehensive log analyzer with diagnostics
  directusbtest.py          # Simple scripted motions
serial/
  config.json               # UART adapter configuration
  uhand_protocol.py         # Packet helpers
  test_serial.py            # Binary protocol exerciser
hand_driver_sketch/         # Arduino firmware with STATUS feedback (optimized)

Key improvements in current version:

  • Joint-angle detection (PIP/DIP) replaces TIP-MCP for reduced jitter
  • Configurable angle thresholds via CLI flags
  • Servo feedback logging with STATUS command
  • Non-blocking log queries (no loop interference)
  • Optimized Arduino parsing (char arrays, 2-3x faster)
  • Calibration keep-alive prevents servo drift

9. Troubleshooting

Servos Not Moving

Run diagnostic tests in order:

  1. Basic connection test:

    python usb/test_basic_connection.py

    Checks if Arduino is responding to serial commands.

  2. Direct servo test:

    python usb/test_arduino_direct.py

    Bypasses Python angle detection, sends simple P: commands.

  3. Individual servo test:

    python usb/test_each_servo.py

    Interactive control of each servo separately (use keys 0-5, o/c/m).

  4. Real-time tracking test:

    python usb/test_realtime.py

    Shows detected angles and sent commands in real-time.

Common Issues

Fingers moving erratically or slowly:

  • Check Python smoothing (--smooth 0.6 is default)
  • Check send rate (--send-hz 20 is default)
  • Check Arduino EMA smoothing (alpha should be 0.95 in firmware)
  • Verify angle thresholds are correct (180°→90° for fingers, 165°→95° for thumb)

Fingers stuck or barely moving:

  • Check EEPROM calibration ranges (should be 90°+ range for most servos)
  • For inverted servos (Middle/Ring/Pinky), MIN must be > MAX in EEPROM
  • Run reset_calibration.py to clear bad EEPROM data
  • Recalibrate with python usb/pose2hand.py --calibrate

Calibration positions drift between calibrate and live mode:

  • Servos auto-detach after 2s of no commands and can drift
  • Latest version has automatic keep-alive to prevent this
  • Make sure you're using updated pose2hand.py

Specific servos don't respond:

  • Check wiring - servos must be on correct pins (D2-D7)
  • Test Arduino pins with test_each_servo.py
  • Some pins may be damaged - remap in Arduino code if needed
  • Check servo power supply (6 servos need 2A+ at 5V)

Power issues (multiple servos slow):

  • USB typically provides 0.5-0.9A, insufficient for 6 servos
  • Use external 5V 2A+ power supply for servo power rail
  • Connect GND between power supply and Arduino
  • Use powered USB hub, or try different USB port

Diagnostic Tools

All diagnostic tools are in usb/ directory:

  • test_basic_connection.py - Verify Arduino communication
  • test_arduino_direct.py - Test servos with simple commands
  • test_each_servo.py - Interactive individual servo control
  • test_realtime.py - Real-time angle detection display
  • test_power.py - Test if power is limiting servo speed
  • diagnose_slow.py - Analyze calibration ranges and response
  • diagnose_pinky.py - Specific pinky servo drift diagnostic
  • reset_calibration.py - Reset EEPROM to safe defaults

Refer to the project guides for wiring diagrams and safety tips before driving the servos.

About

Handpose model controlling uHand robot

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors