diff --git a/CMakeLists.txt b/CMakeLists.txt index e8f4e91..fd70ee0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ endif() # Always-required dependencies # --------------------------------------------------------------------------- find_package(Threads REQUIRED) -find_package(OpenCV REQUIRED COMPONENTS core highgui imgproc) +find_package(OpenCV REQUIRED COMPONENTS core imgproc) # Boost.Asio is header-only (Boost >= 1.69); only program_options is a compiled lib. if(POLICY CMP0167) cmake_policy(SET CMP0167 NEW) diff --git a/README.md b/README.md index 335cf4a..f92e381 100644 --- a/README.md +++ b/README.md @@ -221,12 +221,13 @@ press a key that acts. | `a` / `p` / `m` | auto mode (sweep the scan grid) / pan 30° around where the gimbal points now / manual mode (stop, take it by hand) | | `h` | home the gimbal | | `g` `s` `c` `n` | open the full-screen gimbal, sensors, cameras or connectivity view; press it again to close | -| `?` | the built-in help: every command, with examples (`j`/`k` change section) | +| `?` | the built-in help: every command on one page (`:help ` for examples) | | `:` | type a command, exactly as in the [command list](#everyday-commands) | | `f` | freeze the display, to select and copy text or to page back through the log (the program keeps running) | | `PgUp` `PgDn` | scroll the log, or the open view - the only scroll keys | | arrows | nudge the gimbal by hand, from any view - manual mode only | -| `Space` | take one picture now - manual mode only | +| `Space` | take one picture now (`snapshot`) - manual mode only | +| `r` | continuous capture on/off (`capture on` / `capture off`) - manual mode only | | `Esc` | close a view; with no view open, **cancel** whatever is running (a test, a homing, a calibration, a heading setup) | | `q` | quit or background the program - it asks which | | `Ctrl-b d` | leave the dashboard and keep the program running (a `tmux` key) | @@ -317,10 +318,10 @@ job. Details, payloads and safety rules: [docs/mqtt-api.md](docs/mqtt-api.md). | `gimbal move ,` | point at a **true bearing** (0 = north) and an elevation, in degrees | | `gimbal nudge <+/-percent>` | a small move by hand | | `snapshot` | take one picture now (manual mode) | +| `capture on` / `capture off` | keep taking pictures where the gimbal is aimed, at the sweep's pace (manual mode; the gimbal can still be nudged) | | `test [ []]` | run self-tests - see [below](#is-the-tower-healthy) | | `gimbal heading setup` | tie the yaw axis to true north by sighting landmarks | | `set camera profile ` | switch the camera profile, e.g. `night` | -| `set fps ` | how many pictures per second the sweep aims for | | `camera reset` | reboot the camera and put it back on its profile - for a camera that has stopped sending pictures | | `gimbal dump` | show everything the firmware is holding | | `debug` | more detail in the log, or back to normal | @@ -479,7 +480,6 @@ settings the way the real firmware does. | `--mock-serial`, `--mock-camera`, `--mock-env` | stand-ins instead of the motor board, camera, ambient sensor | | `--no-mqtt` | no broker | | `--degraded` | start even though `hardware.ini` declares a part that is missing (field triage) | -| `-d, --demo` | save a placeholder picture instead of encoding live frames | | `--log-level ` | `trace`, `debug`, `info`, `warn`, `error`, `off` - for the screen | | `--log-file-level `, `--no-log-file` | the log file's level / no log file this run | | `--trace ` | log every message to and from `serial`, `mqtt`, `camera`, `control`, `all` | diff --git a/bin/x64/Release/test_smoke.jxl b/bin/x64/Release/test_smoke.jxl deleted file mode 100644 index 3d3604d..0000000 Binary files a/bin/x64/Release/test_smoke.jxl and /dev/null differ diff --git a/docs/architecture.md b/docs/architecture.md index 0aa82a6..e675e03 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -55,7 +55,7 @@ thread so all geometry/state mutation stays single-threaded. | MQTT client | Paho (internal) | delivers callbacks; auto-reconnects (no busy-wait loop) | | Camera acquisition | Vimba X (internal) | free-runs at the mode's frame rate and delivers frames via the observer, which keeps the latest complete one | -Shared state is mutex-guarded: latest `MotorTelemetry` (serial), `ControlCommand` (channel), the frame queue +Shared state is mutex-guarded: latest `MotorTelemetry` (serial), `RemoteCommand` queue (channel), the frame queue (pipeline), the console command queue, and the latest `UiSnapshot`. The `CaptureScheduler` runs only on the main thread; the UI is a pure observer + command source (it copies a snapshot to render and pushes command strings back through the same queue the console uses, so it never touches live logic objects). In TUI mode @@ -76,16 +76,17 @@ corrupted. - auto: `MOVE ,` to the next `ScanGrid` waypoint (front to back, then wrap). - pan: `MOVE` to the next of `panHeadings()` (left to right, then back to the left edge) at the pan's pitch, converted to counts via `Geometry`. - - manual: nothing, bar a requested snapshot. + - manual: nothing, bar a requested snapshot or continuous capture (`capture on`), which skip the + move and wait only for standstill. - Once **both axes report standstill at the target**, wait `settle_wait_ms`, then keep the newest frame and advance the grid or pan position. -5. **Acquisition** — the camera free-runs at the active mode's `AcquisitionFrameRate` with its own +5. **Acquisition** — the camera free-runs at the active profile's `AcquisitionFrameRate` with its own auto-exposure tracking the light; `trigger()` hands over the freshest complete frame. See *Image capture* below. 6. **Frame handling** — the kept `Frame` goes to the callback, which `submit()`s it to the `ImagePipeline`. `submit()` samples the gimbal pose there and then — yaw from the encoder, pitch from the IMU — and the pose travels through the queue with the frame, so encode latency cannot attribute a later pose to earlier - pixels. The worker rotates it by `Camera.rotation_deg`, encodes JPEG XL (or copies the demo image), writes + pixels. The worker rotates it by `Camera.rotation_deg`, encodes JPEG XL, writes `/