Drive ~2 min read
at the endThe Nicla Vision on your LAN: /health, /senses, /stream, /detect from one file.
Firmware¶
The Nicla Vision is the eyes, and a camera node on your LAN. No cloud relay, no account.
What runs on the board¶
firmware/arm_node.py (MicroPython, on OpenMV 5.0) joins Wi-Fi and serves on :8080.
| route | what you get |
|---|---|
GET /health |
{device, uptime_s, wifi_rssi, model, ip, fw} |
GET /senses |
IMU in g and °/s, ToF mm, RSSI, free memory, uptime |
GET /stream |
MJPEG, one client, 6 to 13 fps |
GET /detect |
SSE, one JSON event per FOMO face inference, largest box first, up to 10 Hz |
POST /ble/scan |
devices seen in a 5 s passive scan, with RSSI |
GET /audio |
PCM16 mono 16 kHz; 503 while the stream or detector is attached |
Detection runs on the STM32H7 with fomo_face_detection.tflite, person_detect as fallback. Boxes cross the Wi-Fi, not pixels, so watch and the dashboard hold their rate on any laptop. Box offsets are in pixels of a 320-wide frame; the 33 degree horizontal half-FOV watch uses for degrees-per-pixel is an assumption, not the lens datasheet, which is why the tracker corrects in steps and re-measures instead of trusting one conversion.
Wi-Fi comes from /flash/arm.json ({"wifi": {"ssid", "psk"}}) or a /flash/tiny.json with a networks list.
Boot¶
main.py → tiny_boot (crash guard: three fast boots in a row and the board parks at the REPL with a red blink) → a 3 s window where any byte on USB keeps the REPL → arm_node.run(). A crash prints its traceback and drops to the REPL, no reset loop. OpenMV runs main.py only after a hard reset (machine.reset() or replug).
Upload¶
Four files to /flash: arm_node.py, tiny_stream.py, tiny_boot.py, main.py. The port must be free; the dashboard talks to the node over the LAN and only opens USB when the node has been silent for 30 s, so stop the dash or wait for it to fall back before uploading. The exact one-liner and recovery steps are in firmware/README.md.
tiny_boot and tiny_stream are shared with strands-nicla. The pure helpers have CPython tests: pytest tests/test_firmware_*.py.
Power¶
Micro-USB from the arm's supply, cable along the servo bus. The JST in the open top takes a battery later, outside the head. Never both at once.
The other side of the wire: Dashboard, Tools.