fwt_software/docs/known-issues.md

7.8 KiB
Raw Blame History

Known Issues — Status

This tracks the reproduction blockers and robustness issues identified in the original code and what the refactor did about them.

Resolved

# Original issue Resolution
1 Hardcoded config path (/home/ggs/...) Config search order: --config$FGC_CONFIG./config.ini → exe dir → XDG (src/core/Paths.cpp)
2 Hardcoded image output path [Paths] output_dir with ~/$ENV expansion + sensible default
3 Startup scripts with ~/projects/... Replaced by path-independent scripts/run.sh + systemd unit
4 Vimba X required to build WITH_VIMBA CMake option (default ON); OFF builds a mock-only binary
5 No hardware path; exits if MQTT down Mock implementations + runtime toggles; MQTT failure now logs and continues
8 Plaintext MQTT credentials $FGC_MQTT_USER/$FGC_MQTT_PW env override; config.ini gitignored
9 MQTT busy-wait (while(running);) Gone — Paho async client + set_automatic_reconnect; no spin thread
10 parser() missing return Old parser removed; parseTelemetryLine returns std::optional cleanly
11 Fragile Boost.Spirit command grammar Replaced by parseCommand whitespace tokenizer (src/core/CommandParser.cpp)
12 Two divergent config.ini files Single committed config/config.example.ini; real configs gitignored
6 Telemetry field order: humidity before temperature Obsolete — migrated to the current firmware's ST protocol (encoder counts, no environmental fields); humidity/temp/fan are gone
7 Trigger fires while is_moving == 1 (not when stopped) Fixed by the protocol migration — capture is now move → settle → trigger; the camera fires only once both axes report standstill at the target (CaptureScheduler.cpp)

Also added along the way: a leveled logger, typed/validated config, an SDK-independent core library, and a doctest unit-test suite (ctest).

Open / needs hardware confirmation

# Issue Status
13 [Motor] degrees↔counts calibration The config.example.ini values are placeholders. Calibrate *_counts_per_deg / *_zero_count against real xenc readings after homing on the rig.
14 Capture sweep untested on hardware Homing was verified live (see below), but the MOVE → settle → trigger sweep was not run with --start. kSettleTolCounts (600) and the per-interval timing in CaptureScheduler.cpp still need tuning against observed ST behaviour, alongside #13.

Camera acquisition (USB3) — root cause + approach

Real-camera capture (Alvium 1800 U-2040c, Sony IMX541, 20.4 MP) was brought up on the LattePanda this session. Two problems were root-caused (both host/USB3-side, reproduced in Allied Vision's own vmbpy — the camera keeps acquiring while the host stops receiving; no kernel errors):

  1. Camera shipped in hardware-trigger mode (TriggerSource=Line0) → produced no frames. Fixed by configuring software trigger explicitly in-session in VimbaCameraSource.cpp (relying on the camera's persisted user set alone did not work).
  2. Acquisition stall — frame delivery stops after a few frames:
    • USB3 hardware LPM (U1/U2) was enabled on the camera's link (the camera logs Enable of device-initiated U2 failed) → silent bulk-transfer stalls under load. Disable per-port: write 0 to /sys/devices/.../usb2/2-0:1.0/usb2-port<N>/usb3_lpm_permit, then re-enumerate (the per-device power/usb3_hardware_lpm_u* files are read-only). Make persistent via a udev rule matched on idVendor 1ab2.
    • The host xHCI cannot reliably move large single frames. Measured (LPM off, paced ~1 fps): RGB8 full-res 61 MB stalls in 35 frames; ≤ ~20 MB frames sustain when paced (BayerRG8 full-res 20 MB → 21 frames/20 s; 3.8 MB → 41/20 s). Freerun at max rate stalls even for medium frames.
    • Also raise usbcore.usbfs_memory_mb to 1000 (persist via kernel cmdline; resets to 16 on reboot).

Approach (config-driven, see [Camera] in configuration.md): RGB8 + 2×2 binning (~5 MP, ~15 MB) keeps de-Bayering and white balance on-camera (the on-camera pipeline applies white balance before de-Bayering); a paced low-rate stream keeps on-camera auto-exposure/gain/white-balance converged to the changing outdoor light, and the scheduler saves one frame per waypoint. DeviceLinkThroughputLimit is kept conservative (~250 MB/s; ≥450 caused incomplete frames). Full 20 MP is possible via BayerRG8 (20 MB) + a host de-Bayer step if reduced resolution proves insufficient.

Status: the [Camera] config schema, near-lossless JPEG XL, and unit tests are in place. Still to do on the rig: wire the in-session imaging config + paced acquisition in VimbaCameraSource, add the udev/boot persistence for LPM + usbfs, and verify a full sweep captures white-balanced frames with no stall.

Verification caveats

  • Full build verified on the LattePanda: a WITH_VIMBA=ON WITH_MQTT=ON build compiles and links on the device (real Vimba X SDK + Paho fetched). The MQTT wrapper also builds on the dev box (GCC 16 / CMake 4 — see cmake/Paho.cmake for the toolchain-compat shims).
  • Serial protocol verified live against real firmware (LattePanda, this session): ENABLE/HOME/SPEED reach the firmware, the ST telemetry parses with zero unparsed lines across a full session, and a live --init drove a clean re-home of both axes to READY. Still unverified on hardware: the capture sweep (#14) and real-camera (Vimba) frame capture — earlier tests used --mock-camera.
  • Makefile parity is moot: the Makefile was removed in favour of CMake, and the full WITH_VIMBA=ON WITH_MQTT=ON CMake build now runs on the device.
  • Demo mode copies bin/x64/Release/test_smoke.jxl, resolved relative to the working directory. Run from a directory where that path exists, or extend ImagePipeline::Params::demo_image.

Possible follow-ups (not done)

  • Graceful shutdown on SIGINT (currently exit via exit/Ctrl-D; a pending getline can delay shutdown).
  • Make the camera index→label map fully config-driven. (JPEG XL distance/effort and the on-camera imaging settings are now config-driven under [Camera] — see configuration.md.)
  • Reintroduce optional image upload to the ground station, config-driven (the old hardcoded NFS/SMB upload was removed).
  • gimbal calib persistence: the fitted counts_per_deg/zero_count are always applied to the live session (display, manual moves, MQTT heading, and the capture scheduler) and written to logs/calib_*.log. In the TUI, the activity strip then prompts Save … as the new default? (y/n)y writes the full per-axis [Motor] map (*_counts_per_deg, *_zero_count, *_min_deg/*_max_deg) into config.ini (persists across restarts), n keeps them session-only. In the headless console there is no prompt, so calibration stays session-only there; copy the logged values into [Motor] by hand to keep them.
  • gimbal nudge moves a fixed fraction of the homed endstop-to-endstop travel (from the firmware dump), so it is independent of the degrees↔counts calibration. If no dump has been captured yet (not homed / no gimbal dump), nudge requests one and does nothing that press — it never falls back to the configured degree clamps (which, if *_min_deg/*_max_deg were unset, produced absurd ±100000° steps).
  • DHT11 temperature/humidity is still a Sensors-panel placeholder (the IMU half is integrated).