2026-08-05 15:43:04 +00:00
|
|
|
|
# usb-camera-webui
|
|
|
|
|
|
|
2026-08-06 00:44:19 +09:00
|
|
|
|
A live video feed from a USB webcam, served through a small web UI, running on a Raspberry Pi 5.
|
|
|
|
|
|
|
|
|
|
|
|
## Why this is its own repo
|
|
|
|
|
|
|
|
|
|
|
|
There is a sibling project, **`camera-webui`**, doing the same job on a Jetson Orin Nano with a CSI
|
|
|
|
|
|
IMX219. This is deliberately *not* that repo, for two reasons:
|
|
|
|
|
|
|
|
|
|
|
|
1. **Two agents, two repos.** A Codex agent is working in `camera-webui` on the Orin. A second agent
|
|
|
|
|
|
editing the same files from another machine would collide for reasons that have nothing to do with
|
|
|
|
|
|
either one's ability.
|
|
|
|
|
|
2. **The point is measuring the agent.** Both projects exist to see how far Codex + qwen3.6 gets on
|
|
|
|
|
|
real hardware. Two independent runs are readable; one shared repo with merge conflicts is not.
|
|
|
|
|
|
|
|
|
|
|
|
Merging them later behind a source-selector — one UI, switchable backends — is a reasonable end
|
|
|
|
|
|
state. It is just not the starting point.
|
|
|
|
|
|
|
|
|
|
|
|
## Hardware, verified
|
|
|
|
|
|
|
|
|
|
|
|
| | |
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
| Board | Raspberry Pi 5, Debian 12 (bookworm), aarch64 |
|
|
|
|
|
|
| Camera | **Logitech C505 HD Webcam** (`046d:08e3`), USB/UVC |
|
|
|
|
|
|
| Node | `/dev/video0` |
|
|
|
|
|
|
| Formats | `MJPG` (Motion-JPEG) and `YUYV` (4:2:2) |
|
|
|
|
|
|
| Confirmed | 1280x720 MJPG frame captured, a genuine 33 KB JPEG |
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
v4l2-ctl -d /dev/video0 --list-formats
|
|
|
|
|
|
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=MJPG \
|
|
|
|
|
|
--stream-mmap --stream-count=1 --stream-to=/tmp/frame.jpg
|
|
|
|
|
|
file /tmp/frame.jpg # must say "JPEG image data", not just exist
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
⚠ **`/dev/video*` is crowded here.** The Pi 5 exposes many nodes (`/dev/video19`–`35`) belonging to
|
|
|
|
|
|
its ISP and codec blocks, present with no camera attached. The webcam is `/dev/video0`; a second node
|
|
|
|
|
|
(`/dev/video1`) is the UVC metadata interface, not a capture device. **Never pick a node by index —
|
|
|
|
|
|
confirm with `v4l2-ctl --list-devices`.**
|
|
|
|
|
|
|
|
|
|
|
|
## UVC is the portable path
|
|
|
|
|
|
|
|
|
|
|
|
This is plain **V4L2**. No libcamera, no `picamera2`, no Argus. That matters beyond this repo: UVC is
|
|
|
|
|
|
the one capture path that works identically on the Pi and the Jetson, so a backend written here is
|
|
|
|
|
|
the piece most likely to survive being moved.
|
|
|
|
|
|
|
|
|
|
|
|
**Prefer `MJPG` over `YUYV` for streaming.** The camera compresses in hardware, so MJPG frames come
|
|
|
|
|
|
off the wire ready to serve; `YUYV` is uncompressed and will spend Pi CPU on encoding you did not
|
|
|
|
|
|
need to do.
|
|
|
|
|
|
|
|
|
|
|
|
## ⚠ Power is a real constraint here
|
|
|
|
|
|
|
|
|
|
|
|
The Pi is running on a **3 A supply, not the 5 A one it wants**:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
max_current = 3000 mA
|
|
|
|
|
|
usb_max_current_enable = 0 # restricted USB budget
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The C505 fits within that, and the board has been stable with it attached — but the headroom is thin.
|
|
|
|
|
|
**Do not assume a second USB device will fit**, and do not add powered peripherals casually. If the
|
|
|
|
|
|
board drops out, check these after it returns:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
vcgencmd get_throttled # undervoltage bits
|
|
|
|
|
|
cat /sys/firmware/devicetree/base/chosen/power/usb_over_current_detected
|
|
|
|
|
|
journalctl -b -1 -e # clean shutdown, or abrupt cut?
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
That last one is the useful one: this machine keeps **persistent logs**, so a previous boot ending in
|
|
|
|
|
|
an orderly shutdown sequence means something different from one that stops mid-line.
|
|
|
|
|
|
|
|
|
|
|
|
## Planned stages
|
|
|
|
|
|
|
|
|
|
|
|
1. **Capture** — open `/dev/video0`, pull frames, confirm format and rate. *(Hardware already
|
|
|
|
|
|
verified; the code is not written.)*
|
|
|
|
|
|
2. **Live feed** — MJPEG over HTTP first. It works in any browser with no negotiation, and the camera
|
|
|
|
|
|
already produces the frames.
|
|
|
|
|
|
3. **Web UI** — one page: the feed, plus basic controls.
|
|
|
|
|
|
4. **Later** — resolution/format switching, snapshots, and only then anything heavier.
|
|
|
|
|
|
|
|
|
|
|
|
Each stage should be usable on its own before the next begins.
|
|
|
|
|
|
|
|
|
|
|
|
## Development
|
|
|
|
|
|
|
|
|
|
|
|
Codex runs on this Pi, so development happens on the target — no cross-compiling, no deploy step. The
|
|
|
|
|
|
model endpoint and MCP gateway are on `halogen` and reachable from here by name. See
|
|
|
|
|
|
[AGENTS.md](AGENTS.md).
|