支持传感器独立校准文件与批量配置启动

保留逐台添加,并通过显式配置一次连接全组;失败时撤销本批新增连接。通过 35 项回归测试、真实 SDK 校准与 1–4 路验证、Ruff 和文档检查。
This commit is contained in:
ykcheungab
2026-10-14 16:11:15 +08:00
parent 133a98e418
commit a723e96dcc
7 changed files with 460 additions and 24 deletions
+76 -8
View File
@@ -1,8 +1,8 @@
# UART finger service
Start the service first, then manually add 1-4 camera sources through UART.
Each successful `add` opens and warms up one source. Send `start` when the set
is ready. There is no camera discovery, hot-plug monitoring or automatic connection.
Connect 1-4 sources individually through UART, or load an explicit setup file
with their configurations and calibration paths. There is no camera discovery
or hot-plug monitoring; every source is selected by the user.
## Start the service and add cameras
@@ -40,17 +40,80 @@ No sensor count is declared in advance. A failed addition replies `ERR add ...`,
closes its newly opened runtime if one exists, and leaves existing cameras and
IDs unchanged. It does not consume an ID. The service remains available for retry.
To select this sensor's force calibration, append `--calibration`:
```text
add /dev/video0 --calibration "/home/radxa/calibrations/finger/DD02-14.json"
```
An optional config still works: `add SOURCE CONFIG --calibration PATH`.
Explicit calibration paths are passed to SDK `FingerRuntime.open(cal_path=...)`.
A missing or invalid file fails the addition, without falling back to raw values.
Without the option, normal SDK calibration selection applies. This does not
replace calibration on a camera already added; restart to change that mapping.
The Windows example `D:\orisys_ws\data\calibrations\finger\DD02-14.json` refers
to a file on that computer. Copy it to the Q6A before using a board-local path.
Quote Windows paths in UART commands, or use forward slashes. The user must
match each camera to its physical sensor's calibration; no serial-number discovery
is performed.
The TTL login console and data UART must use **different ports**. Data defaults
to `/dev/ttyHS1`, 115200 baud, 8N1 without flow control. It must not be occupied
by getty or another serial program. The script does not configure UART pins.
Logs stay in the login console; protocol records go to the data UART.
`--show` is optional local desktop debugging.
## Batch setup and one-command startup
Copy [sensors.example.json](../serial/sensors.example.json), then replace its
camera paths and calibration filenames with the real mappings. `SENSOR-2` through
`SENSOR-4` are placeholders. The JSON format is:
```json
{
"sensors": [
{"source": "/dev/video0", "config": "finger", "calibration": "calibrations/finger/DD02-14.json"},
{"source": "/dev/video2", "calibration": "calibrations/finger/SENSOR-2.json"}
]
}
```
List 1-4 entries. `source` is required; `config` defaults to startup `--config`.
An omitted/null `calibration` uses normal SDK selection. Relative file paths
resolve from the setup file's directory, independently of the working directory.
Named configs such as `finger` remain names. Unknown fields are rejected.
Once saved as `sensors.json`, one terminal command connects the whole set and
starts continuous UART output:
```bash
python serial/example_uart.py --port /dev/ttyHS1 --setup sensors.json --start
```
Omit `--start` to connect and wait for UART commands. With neither option, empty
manual startup is unchanged. `--start` requires `--setup`. Preparation failure
rolls back the entire startup set and exits before opening the UART.
An already-running service can also load the file:
```text
load "/home/radxa/sensors.json"
OK loaded 1 2
start
```
`load` only connects; it does not start output. It can extend manually added
sensors, up to four total. Batch failure removes only that batch's new sensors
and leaves previously added cameras unchanged. `add` and `load` require stopped
output. Wait for each reply before proceeding.
## Commands and output
| Command | Behavior |
|---|---|
| `add SOURCE [CONFIG]` | Open and prepare one source while output is stopped; reply `OK added ID`. Optional config overrides the startup `--config` for this sensor only. |
| `add SOURCE [CONFIG] [--calibration PATH]` | Prepare one source while output is stopped; reply `OK added ID`. Config/calibration apply only to this sensor. |
| `load SETUP.json` | Add the sources and calibration mappings in a setup file while stopped; reply `OK loaded ID ...`. |
| `start` | Begin continuous output for all added sensors; requires at least one sensor. Reply `OK start`. |
| `stop` | Pause continuous output for the whole set; keep all cameras open. Reply `OK stop`. |
| `read` | Publish one complete processing round; requires a sensor and preserves streaming state on success. |
@@ -70,8 +133,7 @@ OK start
`add` while streaming replies `ERR add stop streaming first` and opens no source.
A fifth source or duplicate source is rejected. Removing/replacing cameras requires
quitting and starting a fresh service. `start`, `stop`, `read` and `quit` take no
arguments and always act on the full set. The older commands and automatic
startup options are removed.
arguments and always act on the full set. The older protocol commands remain removed.
Commands are case-insensitive UTF-8 lines terminated by LF, CR or CRLF. Partial
lines survive read timeouts. Lines exceeding 1024 bytes are discarded through
@@ -109,7 +171,7 @@ from finger_api import FingerSensorBank
bank = FingerSensorBank(config="finger")
try:
first_id = bank.add(0)
first_id = bank.add(0, cal_path="/home/radxa/calibrations/finger/DD02-14.json")
second_id = bank.add(2, config="finger")
for reading in bank.read_all():
print(reading.sensor_id, reading.normal, reading.shear_x, reading.shear_y, reading.units)
@@ -125,6 +187,8 @@ sources succeed. File EOF raises `EOFError`; capture/processing failure raises
and SDK units; older SDKs without a units property report `unknown`. `close()`
attempts every runtime and clears the camera set. The API caller must pause its
own processing loop before adding; the UART service enforces this for commands.
`bank.add_setup("sensors.json")` uses the same transactional batch loader as the
CLI and UART. `bank.calibration_paths` records explicit calibration paths by ID.
## Backend evidence and remaining limits
@@ -135,12 +199,16 @@ recorded sources were added incrementally, with complete readings after each
addition and three final rounds for each count. Existing runtime identities were
preserved; capture handles and sensor objects were distinct, and optical-flow
arrays did not share memory. Resources were released after each case.
The explicit `DD02-14.json` calibration was also tested on 1-4 recorded sources:
each instance loaded its assigned file and reported three calibrated `N` axes.
Four-source JSON loading passed, and invalid explicit calibration was rejected
without altering an existing sensor. This validates software binding, not physical accuracy.
To rerun with a recording containing at least 12 frames, put generated clips and
caches in an isolated task scratch directory:
```bash
python tests/check_backend.py --recording /path/to/recording.avi --scratch .scratch/uart-manual-add/backend-run
python tests/check_backend.py --recording /path/to/recording.avi --calibration /path/to/DD02-14.json --scratch .scratch/uart-calibration-setup/backend-run
python -m unittest discover -s tests -v
```