Chisle
The coding-agent plugin that bills 52% of a bare model across 20 live tasks. Terse persona + tool-output compressor + context diet.
Autonomous motion-tracking sentry for ESP32-CAM. Features real-time CV blob detection, WebSocket telemetry, and a custom futuristic Web HUD for kinetic manual override.
Developer toolsC++ · PythonGitHub @KoganTheDevOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗An ESP32-CAM pan/tilt turret that tracks motion on-device and serves a live web HUD
Void Sentry watches a room through an OV3660 camera on an ESP32, finds the moving object by frame differencing, and points a stepper-plus-servo turret at it. Everything runs on the board: no PC or cloud is involved. A browser HUD streams the live video over a WebSocket and shows tracking telemetry. The camera is fixed on the base and the turret aims absolutely: image position is mapped to pan/tilt angles through a two-point calibration you do with the joystick or from the HUD. The firmware is written in C++20 on the Arduino core, with the pure logic split into libraries that are unit-tested on the host.
flowchart LR
CAM["OV3660 camera"] --> CT["camera task (core 1)"]
CT --> FS["FrameStore<br/>4 x 32 KB PSRAM slots"]
FS --> DT["detect task (core 1)<br/>JPEG decode, MotionDetector, Tracker"]
DT --> SNAP["track snapshot"]
SNAP --> CTRL["Controller<br/>AimPolicy, AimMap"]
JOY["Joystick"] --> CTRL
CTRL --> MT["motor task (core 0)"]
MT --> STEP["Stepper (yaw)"]
MT --> SERVO["Servo (pitch)"]
FS --> ST["stream task (core 1)"]
ST -->|"/stream WebSocket"| HUD["Browser HUD"]
HUD <-->|"/commands WebSocket"| CTRL
Frames flow one way: camera, slots, detection, snapshot, controller, motors. The stream task reads the same slots for the HUD. Controller depends only on interfaces (BaseDetectionModule, BaseTurret), and objects are wired by reference in src/main.cpp.
httpd is pinned to core 0 so network bursts cannot preempt detection. The full task table (cores, priorities, stack sizes) is in CLAUDE.md, and the reasoning in the engineering notes.
Measured on the board (QVGA JPEG, quality 18, camera clock 12 MHz, about 16.6 fps capture).
| Measurement | Result |
|---|---|
| Decode, 1/8 scale DC-only vs 1/4 scale | about 7 ms vs about 71 ms |
| Per-frame decode + track, empty scene | 7.7-9.1 ms + 0.49-0.59 ms |
| Per-frame decode + track, person close, turret following (worst 5 s window) | 11.4 ms (Stage 3: 25-30 ms) |
| Frames analysed per 5 s | 83-84 (every captured frame) |
| 20 min soak | no reboots, heap about 147 KB free (min 137 KB) |
| Camera clock 20 MHz vs 12 MHz: ping | 265 ms vs 19 ms (capture 27.8 vs 16.6 fps) |
A higher camera clock degrades WiFi on this board, so 12 MHz is the best frame rate that keeps the network healthy. The full sweep is in the engineering notes.
Parts: Freenove ESP32-WROVER CAM (OV3660, PSRAM required) on the Freenove GPIO Extension Board; 28BYJ-48 stepper with a ULN2003 driver (yaw); SG90 servo (pitch); 2-axis joystick with push button.
| Function | GPIO |
|---|---|
| Joystick X / Y (ADC1, works with WiFi on) | 32 / 33 |
| Joystick button | 0 |
| Servo (pitch) | 14 |
| Stepper IN1-IN4 (yaw) | 13, 12, 15, 2 |
With the camera attached exactly 8 GPIOs are free, and the turret uses all 8. ESP32/include/pins.h is the only place pins are defined, and its static_asserts reject flash/PSRAM pins, camera collisions and duplicates. GPIO12 high at reset selects 1.8 V flash and causes a boot loop, so check the ULN2003 polarity before powering on.
This is the beginning of the README. Read the rest at the original. Read the full README ↗