Files
usb-camera-webui/README.md
T
Mikkeli ceccdcc211 Document the USB webcam target, verified on the hardware
Its own repo rather than a source-selector inside camera-webui: a Codex agent is
already working in that repo on the Orin, and a second agent editing the same
files from another machine would collide for reasons unrelated to either one's
ability. Both projects exist to measure Codex + qwen3.6 on real hardware, and
two independent runs are readable where one repo full of merge conflicts is not.
Merging behind a switchable backend later is still a reasonable end state.

Hardware facts are measured, not assumed: a Logitech C505 (046d:08e3) on
/dev/video0 offering MJPG and YUYV, with a 1280x720 MJPG capture confirmed as a
genuine 33 KB JPEG by file(1) rather than by the write succeeding.

⚠ Records that /dev/video* is crowded on this board — video19 through video35
belong to the ISP and codec blocks with no camera attached, and video1 is the
webcam's metadata interface. Selecting a node by index is the obvious mistake
here, so AGENTS.md forbids it and names --list-devices and the USB ID instead.

Power is written in as a constraint rather than a footnote. The board runs on a
3 A supply with usb_max_current_enable=0, so the USB budget is the restricted
one. The C505 fits and the board is stable, but a second device may not, and the
post-mortem commands are recorded because this machine now keeps persistent
logs: a previous boot that ends in an orderly shutdown means something different
from one that stops mid-line.

AGENTS.md carries the rules earned elsewhere tonight: write files with
apply_patch and never write_stdin, stop after two identical failures instead of
incrementing an identifier, emit tool calls as JSON arguments, and read the
working tree with the shell because the gitea MCP tools see the server's copy
and cannot see anything uncommitted.
2026-08-06 00:44:19 +09:00

89 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# usb-camera-webui
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).