增加只读启动和可调用采集 API,保留单路数据协议。通过 28 项模拟回归测试、Ruff 和文档检查;实机限制见 docs/uart.md。
6.7 KiB
UART finger service
serial/example_uart.py processes 1–4 finger cameras or recorded videos and
publishes the SDK's normal and shear values over a separate data UART. Python
3.10+, the board's installed orisys SDK and pyserial are required. Run inside
the board environment prepared by setup/sdk_setup.sh; install pyserial there
with python -m pip install pyserial if needed.
Launch from the login console
The TTL login console and data UART must use different device ports. Start
the script in the login shell; connect the data receiver to the port selected
by --port. A shell/getty or another serial program must not own that data port.
The default is /dev/ttyHS1, 115200 baud, 8N1, with no flow control. This service
does not configure pin multiplexing or enable the board's UART hardware.
From the board's dragon-q6a checkout:
# Host commands control connection and streaming (default: one camera).
python serial/example_uart.py --port /dev/ttyHS1 --config finger
# Four configured sources; use 1, 2, 3 or 4 entries as required.
python serial/example_uart.py --port /dev/ttyHS1 --sources 0 2 4 6
# A passive receiver needs only to read: connection and streaming start automatically.
python serial/example_uart.py --port /dev/ttyHS1 --sources 0 2 --read-only
# Start streaming immediately, while still accepting UART commands.
python serial/example_uart.py --port /dev/ttyHS1 --sources 0 2 --autostart
Use actual camera indices/device paths discovered on the board; 0 2 4 6 is
only an example. Slot IDs are fixed by --sources order, not camera index.
Repeat --config once per source for different sensor configurations, or supply
one shared configuration. Existing --camera-id and --video remain available
for a single source. --sources replaces those options. --show requires a local
GUI and is off by default. Logs go to the login console, replies to the data UART.
In --read-only mode, all incoming UART commands are ignored. End the process
with Ctrl-C in the login shell. Startup still emits OK/ERR records; the receiver
should select force, lines. Without --autostart or --read-only, a passive
reader receives only OK ready until a host sends connect and run.
Command protocol
Commands are UTF-8, case-insensitive, terminated by LF, CR or CRLF. Incomplete
lines remain buffered across serial timeouts. Lines exceeding 1024 bytes are
discarded through their terminator and produce ERR command ... in control mode.
Quote file paths containing spaces. Linux device paths are recommended on Q6A.
| Command | Behavior |
|---|---|
search |
List cameras, then OK search N; use before connecting. Rejected while streaming. |
connect |
Connect slot 1 using its configured source; in single-source mode, prefer the latest search result for a camera. |
connect SOURCE |
Legacy form: connect slot 1 to this camera index, device path or file. |
connect ID SOURCE |
Connect/replace one slot; stop streaming that slot. Other slots keep their connections. |
connect all |
Connect all configured slots; report each success/failure independently. |
run [ID|all] |
Stream the selected slot, or all connected slots when omitted. Requires a connection. |
read [ID|all] |
Publish one newly processed measurement per selected slot; defaults to all configured slots. Does not start streaming. |
stop [ID|all] |
Stop selected streaming, or all when omitted; keep cameras connected. |
quit / exit |
Exit and release all camera and UART resources. |
connect 2 means camera index 2 on slot 1, preserving the old protocol.
To connect slot 2, send connect 2 /dev/video2 or use connect all.
There are no motor-control commands; these commands control acquisition only.
Single-source measurements retain the original format:
force,1.250000,-2.500000,3.750000
When configured with multiple sources, measurements include the slot ID even if only one source connected successfully:
OK connect 2 /dev/video2 (camera)
OK run 1 2
force,1,1.250000,-2.500000,3.750000
force,2,0.500000,0.100000,-0.200000
ERR run 2 processing failed
OK eof 1
Force fields are FNORMAL, FSHEARX, FSHEARY in SDK axes. They may be raw
or calibrated; do not assume Newtons. The Python API exposes SDK units per
reading, using unknown if an older SDK does not expose them. CSV preserves
the original fields and carries no units, timestamps or cross-sensor synchronization.
Each processing failure or EOF stops only the affected slot. Processing exceptions
produce ERR, never fabricated zero force. --no-loop-video stops files at EOF;
the default tries one rewind, resets the tracker and retries one frame. Failed
preparation releases the newly opened runtime; replacing a connection releases
the old one before opening the replacement. A failed replacement requires retrying
connect. Startup continues with any successfully connected slots and fails if
none connect. Reconnect and run explicitly after a camera failure.
Callable acquisition API
serial/finger_api.py owns acquisition and runtime cleanup; importing it opens
no UART or camera. Place that directory on the caller's module search path:
from finger_api import FingerSensorBank
bank = FingerSensorBank([0, 2], configs=["finger"])
try:
bank.connect(1)
bank.connect(2)
reading = bank.read(1)
if reading is not None:
print(reading.normal, reading.shear_x, reading.shear_y, reading.units)
finally:
bank.close()
The caller owns one thread and must close the bank. read() returns None on
capture failure/EOF and raises on processing failure. It returns an image and
three scalar forces from the same processed frame. One file or camera is read
at a time; the API introduces no workers beyond those owned by the SDK.
Verification and limits
Hardware-free regression tests cover command fragmentation, CR/LF, legacy output, 1–4 slot identities, selective control, failure isolation, read-only startup and cleanup. They use in-memory serial and runtime fakes, not physical devices:
python -m unittest discover -s tests -v
Q6A UART wiring, installed ARM SDK compatibility, camera bandwidth, sustained
frame rates and latency remain unverified. The shipped ARM wheel is compiled
orisys 0.5.0; local tests do not execute it. SDK capture and processing remain
synchronous from this service's perspective. Commands are checked before each
round; a slow grab, processing call, connection or camera scan can delay them.
Serial writes have a finite timeout (default 1 second), and transport failure
terminates the service with cleanup. At 115200 baud/8N1, the data budget is
11,520 bytes/s, shared by all measurements and replies. Measure actual frame
rates and stop latency on the board before choosing a higher baud rate.