# Known issues requiring on-rig verification Questions that cannot be answered from the code alone. Check these the next time the hardware is available; each one gates a small code change. ## uC480 camera: gain/exposure during active capture The driver used to carry an (unused) `_capture_paused` context manager whose docstring claimed many IDS cameras return `IS_CANT_COMMUNICATE_WITH_DRIVER` (17) or `IS_NO_SUCCESS` (-1) when gain/exposure commands are issued during active capture. `set_exposure()` and `set_gain()` never used it, and the helper was deleted in the Phase-1 cleanup. **Bench check:** with live streaming running, move the exposure and gain sliders in `camera_test_app.py` and watch the log for those error codes. If they appear, the setters need a stop-live/apply/restart sequence (re-create the helper around the two call sites in [uc480_camera.py](hardware/uc480_camera.py)). ## Helios: no output-power query `docs/hardware/HELIOS_DRIVER_README.md` documents `driver.get_power_mw()`, but `HeliosLaser` has no such method and no output-power mnemonic appears anywhere in this repo's protocol notes. `helios_test_app.py` called it anyway and raised `AttributeError` into a popup; the button is now disabled and the handler reports the gap instead. **Answered (2026-09-08):** the mnemonic is `HMP` (Table 6-3, "Laser Power Monitor", read-only, 0-5000 mW) — but the table adds "not available on all models", and the operator confirms this rig's laser has no power meter. So the button stays disabled; what remains is to delete the Power Monitoring group from `helios_test_app.py` and drop the power-monitoring claims from `docs/hardware/HELIOS_DRIVER_README.md`. ## Genesis laser: forked protocol implementations disagree `hardware/genesis_core.py` and the reference implementation `tools/genesis_laser_gui.py` disagree on ADC command bytes, LDD enable polarity, shutter semantics, filtering, and scaling. Do not modify either until the checklist in [docs/genesis_verification.md](docs/genesis_verification.md) has been run on the bench. ## `lib/ueye_loader.so` — still needed? `lib/ueye_loader.c` is an `LD_PRELOAD` shim that dlopens `/usr/lib/libueye_api.so` — yet nothing in the repo references it, and the vendored SDK copy is `lib/libueye_api64.so.3.82` (a different file). On the rig, check whether the camera apps run without the shim; if they do, delete `lib/ueye_loader.{c,so}`. Either way, record in SETUP.md where `libueye_api64.so.3.82` came from (IDS SDK version) and how the loader is meant to be used. ## Per-angle background: trigger round trip mid-scan Every angle now captures its own background, so the scope switches from the scan-time logic-AND trigger back to the single-record edge trigger and returns to it once per angle (`core/scope_sras.py`: `configure_background_trigger` → `capture_background` → `configure_scan_trigger`). Before this, that transition happened once per scan, with the stage idle and nothing depending on how long it took. **Bench check:** run a multi-angle scan and watch the first row after each background. If frames go missing at the start of an angle, the 0.2 s settle in `configure_scan_trigger` is not enough for FastFrame to re-arm after an AVERAGE-mode sequence, and the row-packing warning ("N frames acquired, M expected") will say so in the log. Raise the settle rather than the ramp buffer — the stage geometry is not what changed. ## Auto-align: constants that are guesses until the rig confirms them `core/auto_align.py` closes a loop over hardware whose gain nobody has measured. Three numbers in `AlignSettings`/`TAxisSettings` are reasoned defaults, not readings: - `probe_steps = 200` — the first move of every search, made only to learn how many millivolts a microstep is worth. Too small and each search wastes iterations doubling it (the status line says so: "moved N microsteps and the DC difference did not change"); too large and the first move overshoots by more than the platform should be asked to travel in one go. - `max_excursion_steps = 20000` — the per-axis safety limit, measured from wherever the axis started. It exists to stop a runaway before the actuator reaches its end stop, so it has to be smaller than the real travel. - `hold_current_ma = 300` — the run current (600 mA) and microstepping (32) are specified; the standstill current is half the run current by analogy with the GR axis, and has not been checked against the platform's weight. **Bench check:** run one auto-align and read the log. The first search's iteration count is the probe verdict — 3 or 4 steps means the probe is about right, and a "did not change by 2 mV" line means it is too small. Convert the applied corrections into actuator travel and compare against the T-axis travel to set the excursion limit. Watch whether the platform holds its tilt between the two phases; if it sags, raise the hold current. ## Auto-align: does the X phase's piston matter, and where is the pivot? The X phase moves T1 alone, as specified. T1 is the only axis lying along X, so it does tilt the platform along X — but moving one leg of three also lifts the platform by a third of the move (`tilt_response(X_TILT)` returns a piston of 1/3 alongside the 2/3 tilt). The search nulls the split-detector difference, which a piston should not move, so the assumption is that the piston is harmless. The piston-free alternative is T1 +1 with T0 and T2 at −0.5 each. Separately, the procedure assumes the tilt pivot is under the beam: if it is not, applying the correction shifts the DC levels at the reference point itself, and the Y phase then chases levels that no longer describe the rig. The code reports this rather than compensating for it — `AxisResult`'s "back at the reference" reading after the X phase is exactly that measurement. **Bench check:** during an X search, watch DC1 + DC2 (the sum, not the difference) on the scope. If the sum moves as T1 moves, the piston is changing the amount of collected light and `X_TILT` should become the piston-free triple. Then read the X phase's reference residual out of the log: more than a few millivolts means the pivot is not under the beam, and the Y phase's reference should be re-measured after the X correction instead of reusing the operator's original numbers.