K-LD7 Timing and PRF Probe¶
ARCHIVED DOCUMENT
This is a historical design or implementation note, kept as a record of why the code is shaped the way it is. It describes the project as of the date in its filename and is not a guide to follow — commands, paths, and constants may no longer match the code. See the Archive index for current alternatives.
Date: 2026-06-09 Status: Approved Scope: Build a guarded hardware exploration path for diagnosing unreliable K-LD7 launch-angle frames, measuring actual RADC frame cadence, and optionally probing explicitly listed undocumented serial commands.
Problem¶
OpenFlight is not always getting enough reliable K-LD7 frames around impact to extract launch angle. The current production path streams RADC frames at 3 Mbaud and anchors angle extraction to the OPS243 impact timestamp, but a golf ball can cross the useful detection zone in only a few tens of milliseconds. More frames near impact would improve the odds of a clean launch-angle estimate.
The hypothesis is that a higher PRF and slightly lower pulse width could improve frame capture. The K-LD7 public documentation, however, does not expose PRF or pulse width directly. The module is documented as an FSK Doppler radar. The exposed controls are maximum speed (RSPI), maximum range (RRAI), base frequency (RBFR), threshold/tracking settings, and data-frame request commands. That means the first question is whether the bottleneck is true RF acquisition cadence, serial readout/request strategy, or undocumented firmware capability.
Approach¶
Create a standalone hardware-test probe that talks to the K-LD7 binary serial protocol directly, but defaults to non-destructive measurement.
The exploration has two phases:
- Safe measurement: use documented commands only. Measure actual frame cadence, dropped
DONEframe numbers, RADC payload read time, and serial errors under current and swept documented settings. - Unsafe probing: only with an explicit opt-in flag, send explicitly listed candidate undocumented command packets and record response codes plus before/after parameter diffs.
This is not a broad brute-force scanner. The unsafe phase must only send command names and payloads deliberately supplied on the CLI or in a small allowlisted fixture. The goal is to discover whether a plausible engineering command exists, not to fuzz the firmware.
Evidence From Current Code And Docs¶
src/openflight/kld7/tracker.pyconfiguresRRAI,RSPI,RBFR,DEDI,THOF,TRFT,MIAN,MAAN,MIRA,MARA,MISP,MASP, andVISU.src/openflight/kld7/serial_io.pyconnects through the existingkld7.KLD7package at 3 Mbaud and patches packet reads for robust RADC streaming.- The installed
kld7package is a thin wrapper around binary packets: 4-byte command, 4-byte length, optional payload, thenRESPplus data packets. docs/K-LD7_Datasheet.pdflists documented commands:INIT,GNFD,GRPS,SRPS,RFSE,GBYE, and individual parameter setters includingRBFR,RSPI,RRAI,THOF,TRFT,VISU, detection bounds, output routing, hold time, and micro-detection settings.- The datasheet notes RADC is 3072 bytes and recommends the highest baud rate. It also states real-time readout is not possible if requested data readout time exceeds the typical frame duration.
Architecture¶
File: scripts/hardware-test/probe_kld7_timing.py
Entry point: uv run python scripts/hardware-test/probe_kld7_timing.py
The script should not depend on the production KLD7Tracker. It should use pyserial directly or a small local protocol helper so we can observe raw packet timings without tracker-side buffering or selection logic.
Components¶
KLD7Protocol
Low-level serial protocol wrapper:
- Opens the port at 115200 even parity.
- Sends
INITto negotiate the requested baud rate, usually 3 Mbaud. - If
INITfails, optionally sendsGBYEat 3 Mbaud and retries, matching the production recovery path for radars left streaming by a crashed process. - Sends binary packets with
struct.pack("<4sI", cmd, length) + payload. - Reads exact packet headers and payloads with the same short-read tolerance used by
src/openflight/kld7/serial_io.py. - Exposes
send_command(cmd, payload=b""),read_packet(),get_response(),read_params(),set_param(),request_frame(frame_mask), andclose().
TimingRecorder
Records one row per packet/frame:
- Host monotonic timestamp at command send.
- First-byte arrival timestamp.
- Header complete timestamp.
- Payload complete timestamp.
- Packet code.
- Payload length.
- Response code, if applicable.
DONEframe number, if requested.- Short-read or timeout errors.
ProbeResult
Aggregates each run:
- Effective RADC Hz.
- Effective
DONEHz. - Mean/p50/p95 RADC payload read duration.
- Missing
DONEframe numbers. - Number of timeouts, short reads, invalid headers, and sensor-busy responses.
- Parameter snapshot before and after the run.
CLI¶
uv run python scripts/hardware-test/probe_kld7_timing.py \
--port /dev/kld7_vertical \
--duration 10 \
--frame-mask RADC,DONE
Safe Flags¶
--port PATH: serial port or udev alias. Required unless auto-detection finds exactly one K-LD7.--baud 3000000: target post-INITbaud rate.--duration SECONDS: measurement duration for each configuration.--frame-mask LIST: comma-separated frame types. DefaultRADC,DONE.--rspi-sweep: run all documentedRSPIvalues.--rrai VALUE: documented range code or meters.--rbfr VALUE: documented base frequency code.--output PATH: write JSONL packet log plus summary JSON.--restore-params: restore the initialGRPSparameter snapshot before exit. Default on. Restore should use individual documented parameter setters, not an opaqueSRPSwrite that includes the software-version bytes.
Unsafe Flags¶
--unsafe-probe: enables undocumented command probing.--probe-command CMD[:HEX_PAYLOAD]: one explicitly listed 4-byte uppercase command packet to send. Repeatable. Hex payload must have an even number of characters.--allow-factory-reset: permitsRFSE. Default refusesRFSEeven in unsafe mode.--no-restore-params: leaves changed parameters in place, but only after printing a warning and requiring--unsafe-probe.
Unsafe mode is unavailable unless --output is set, so every probe leaves an audit trail.
Safe Measurement Flow¶
- Resolve the serial port.
- Connect at 115200, send
INIT, switch to target baud. - Send
GRPSand store the initial parameter snapshot. - Apply documented settings for the current run.
- Re-read
GRPSand record the active settings. - Loop until duration expires:
- Send
GNFDwith the requested frame mask. - Read
RESP. - Read expected data packets, including
DONEwhen requested. - Record exact timing and packet sizes.
- Summarize effective frame cadence and gaps.
- Restore the initial parameter snapshot unless disabled.
- Send
GBYEand close the port.
Unsafe Probe Flow¶
- Run the safe connection and initial
GRPSsnapshot. - For each explicit
--probe-command: - Refuse known destructive commands unless separately allowed.
- Validate the command is exactly four ASCII uppercase bytes.
- Send the command with its exact payload.
- Read and record
RESP. - Drain and record any follow-up packets.
- Re-read
GRPS. - Emit a before/after parameter diff.
- If the command returns
OKor changes parameters, run a shortRADC,DONEcadence sample. - Restore the original parameter snapshot before exit by default.
Safety Rules¶
- No random command generation.
- No wildcard payload sweeps.
- No persistent production integration until a command is understood and reproducible.
- Refuse
RFSEby default. - Always snapshot parameters before writes.
- Restore parameters by default.
- Always send
GBYEon exit. - Treat any command that appears to alter RF timing as lab-only until RFbeam confirms regulatory implications. The K-LD7 has modular RF approvals; changing waveform timing or duty cycle outside documented settings could invalidate those assumptions.
Data Products¶
JSONL packet log: one row per command/packet with timing and raw metadata.
Summary JSON: one object per run:
{
"port": "/dev/kld7_vertical",
"baud": 3000000,
"frame_mask": ["RADC", "DONE"],
"params_before": {"RSPI": 3, "RRAI": 0, "RBFR": 0},
"params_active": {"RSPI": 3, "RRAI": 0, "RBFR": 0},
"duration_s": 10.0,
"radc_frames": 340,
"done_frames": 340,
"effective_radc_hz": 34.0,
"done_frame_gaps": 0,
"read_duration_ms_p95": 12.4,
"errors": {}
}
Interpretation¶
The first decision point is whether the measured RADC stream is close to the documented RSPI=3 cadence.
- If RADC is near 34 Hz with low gaps, the launch-angle issue is probably frame selection, timing alignment, geometry, SNR, or target ambiguity rather than serial acquisition.
- If RADC is well below 34 Hz or has large
DONEgaps, the next target is readout/request strategy, USB scheduling, or reducing requested packet volume. - If a documented
RSPIsweep changes effective cadence as expected,RSPI=3remains the highest documented cadence and true higher PRF is not exposed. - If an undocumented command returns
OKand changes cadence, it must stay experimental until validated against RF behavior, data quality, and module stability.
Testing¶
Unit tests should cover protocol and summarization without hardware:
- Packet builder creates correct command headers and payload lengths.
- Packet reader handles split headers and split payloads.
DONEframe gap detection works across wrap-free monotonically increasing frame numbers.- Summary statistics are correct for synthetic packet logs.
- Unsafe mode refuses undocumented probes unless
--unsafe-probeis present. RFSEis refused unless--allow-factory-resetis present.- Parameter restore runs in
finallywhen initial parameters were captured.
Hardware verification is manual and explicit:
uv run python scripts/hardware-test/probe_kld7_timing.py \
--port /dev/kld7_vertical \
--duration 10 \
--frame-mask RADC,DONE \
--output /tmp/kld7_vertical_timing.jsonl
Out Of Scope¶
- Production use of undocumented commands.
- Automatic fuzzing of the K-LD7 firmware.
- Firmware extraction or binary reverse engineering.
- RF lab measurement of actual waveform timing.
- Changes to live launch-angle selection.
- UI changes.
- Replacing the
kld7Python package in production.
Files Created Or Modified¶
| File | Change |
|---|---|
scripts/hardware-test/probe_kld7_timing.py |
New guarded timing/protocol probe |
tests/test_probe_kld7_timing.py |
New protocol, summary, and safety tests |
docs/kld7-troubleshooting.md |
Add a short section linking the probe and explaining interpretation |