Automated multi-axis foot scanner
A two-axis robotic arm swings a phone camera around a resting foot, then rebuilds it as a measured 3D model. Built for spotting diabetic foot ulcers early.
The problem
Diabetic foot ulcers often start on the bottom of the foot, where neither the patient nor a quick clinical glance catches them. Standard foot scanners have the patient stand on a glass plate, which flattens the very tissue you want to inspect.
3D-Me scans the foot non-weight-bearing. The patient sits with the foot resting, and the arm moves the camera around it on a sphere. The result is a full-colour 3D surface of the foot in its natural shape, sole included, that can be measured and compared over time.
System
Heavy computation stays off the device. The arm only moves, the phone only shoots and coordinates, and a GPU machine does the thinking.
01 · Motion
XIAO ESP32-C3 driving two TMC2209 steppers over UART, with a PCF8574 expander for endstops and LEDs. Deliberately minimal.
02 · Capture
A Pixel 9 runs the scan: it asks the server for a path, commands the arm to each waypoint, takes the photo and uploads it.
03 · Reconstruction
FastAPI service that plans the scan, finds the leg, and turns photos into a textured mesh.
Scan workflow
The arm must never hit the patient's leg, so every scan runs in two phases.
A short, safe pass of photos from positions known to be clear of the leg.
The server detects the leg in the sweep images and builds a no-go zone map.
Camera positions are spread evenly over a Fibonacci sphere, then anything inside the no-go zone is dropped. The quality setting picks the count, e.g. Scan 312.
The phone walks the arm through every safe waypoint and photographs the foot at each one.
COLMAP solves geometry using the known arm angles as pose priors, then OpenMVS densifies, meshes and textures it.
A single GLB file with a UV texture atlas, viewable in a browser or on Android.
Reconstruction
Off-the-shelf photogrammetry guesses each camera position by matching features between photos. Skin is smooth and low-texture, which makes those guesses fragile. But the scanner already knows where the camera is: it put it there.
reconstruct.py is a pose-seeding layer on top of COLMAP. It converts stepper angles into camera poses and injects them as priors, so COLMAP refines known positions instead of solving blind. It also runs in plain unposed mode for hand-shot test sets, and exposes run_pipeline() so the FastAPI server can call it directly.
Finding from testing
Flat test targets fail no matter how much texture they have. A plane gives no parallax, so structure-from-motion has nothing to triangulate new views against. Validation now uses real 3D objects.
Arm protocol
Newline-terminated ASCII over TCP port 23 or USB serial at 115200 baud. Every reply starts with OK or ERR, and any command sent mid-move gets ERR BUSY.
Hardware
A custom KiCad PCB carries the controller, both drivers and power. The first schematic review turned up a list of fixes for the next revision.
| Part | Role | Note |
|---|---|---|
| XIAO ESP32-C3 | Controller, WiFi | Runs the motion firmware |
| TMC2209 ×2 | Stepper drivers | UART addresses 0 and 2 |
| PCF8574 | I²C GPIO expander | Endstops and LEDs |
| Buck converter | 24 V → 5 V | Logic supply |
| Next-revision fix | Status |
|---|---|
| U2 MS1 tied to 3.3 V, giving the wrong microstep setting | to fix |
| LED net mismatches; dead UART_RX net | to fix |
| Floating SPRD and INT pins | to fix |
| R1 on UART line set to 1 kΩ; add C9/C10 bulk caps | to fix |
| Schematic review complete | done |