Repository navigation
feat(ui): add a 0-X mode timing a standing start to a target speed - #208
Merged
Merged
Conversation
Counts up from 0.00, stops the instant the target is reached, turns green. Coming back to rest re-arms it; a tap resets it sooner. The target is chosen in SETUP -> 0-X TARGET. This is an instrument rather than a readout, and two things follow from that. **Zero is not zero.** A stationary receiver reports a few centimetres per second of noise, so the instant the car began moving cannot be read off a sample. The start is estimated by extrapolating back along the acceleration between the first two moving fixes to where speed would have been zero; the finish is interpolated between the two fixes that straddle the target. At 25 Hz a fix lands every 40 ms, so without both ends interpolated every reading would be quantised to 40 ms and the second decimal would be decoration. The test drives a 4 m/s^2 run and measures 6.71 s against a true 6.7056. **A run that stopped being measured must not look like one that finished.** When the fixes dry up the number stops climbing, which is exactly what arriving at the target looks like. So that is its own state: LOST FIX, never green. Green belongs to a completed run alone, and is applied to the decimal point as well, because a green number with a white point reads as a glitch rather than a result. The armed state shows a literal 0.00. That is the one place on this device where a zero is the right answer rather than a placeholder - the car genuinely has not moved - and it is what the request asked for. X is configurable, and that cost more than a mode does. Appending an OperatingMode changes no stored value's meaning; adding a field changes the length of a fixed-width record, so the settings format goes to version 8 with a migration. A v7 device keeps every setting it had and takes the default target, because it never had an opinion about one and a migrated record should not be read as a device that chose zero. Setup's entry opens the target's choices directly rather than descending through twelve fields to reach the one it is named after. Its index into the picker array is static_assert ed rather than trusted: a hand-written count that stopped matching its array is what made DIAGNOSTICS unreachable in #158. Closes #207. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #207.
Counts up from
0.00, stops the instant the target is reached, turns green. Coming back torest re-arms it; a tap resets it sooner. Target chosen in
SETUP→0-X TARGET.Zero is not zero
A stationary receiver reports a few centimetres per second of noise, not
0.000— so theinstant the car began moving cannot be read off a sample.
The start is estimated by extrapolating back along the acceleration between the first
two moving fixes to where speed would have been zero:
The finish is interpolated between the two fixes straddling the target. At 25 Hz a fix
lands every 40 ms, so without both ends every reading is quantised to 40 ms and the second
decimal is decoration.
The test drives a synthetic 4 m/s² run: 6.71 s measured against a true 6.7056 — well
inside one fix interval, which is the whole point.
A stalled run must not look like a finished one
When the fixes dry up the number stops climbing, which is exactly what arriving at the
target looks like. So it is its own state:
LOST FIX, never green.Green belongs to a completed run alone, and is applied to the decimal point too — a green
number with a white point reads as a glitch rather than a result.
--.--with which--.--, "NO SPEED" — the fix is fine, the receiver just isn't sure enough of its speed0.00, "READY"armedshowing a literal0.00is the one place on this device a zero is the right answerrather than a placeholder: the car genuinely has not moved.
X configurable cost a format bump
Appending an
OperatingModechanges no stored value's meaning. Adding a field changesthe length of a fixed-width record, so the settings format goes to version 8 with a
migration.
A v7 device keeps every setting it had and takes the default target — it never had an
opinion about one, and a migrated record should not be read as a device that chose zero.
There is a test for exactly that.
Setup's entry opens the target's choices directly rather than descending through twelve
fields to reach the one it is named after. Its index into the picker array is
static_asserted rather than trusted: a hand-written index that stopped matching its arrayis what made DIAGNOSTICS unreachable in #158.
Layout
12.34is four digits and a point, and the numeral face carries.among its fourteenglyphs — so the whole reading is in the large face, at metrics identical to Clock's
HH:MM: 536 px of 540 at 170 px, the countdown's cached size. Two leading digits coversevery real measurement and no unreal one.
The point never moves, which keeps the reading stable as it crosses ten seconds.
Verification
12 host cases in
test_acceleration.cpp: both interpolations against hand-worked numbers,a full run, the time holding once passed, re-arm on returning to rest, tap reset, a slower
target finishing sooner, the speed-accuracy gate, and that an abandoned run never renders
as a finished one. Plus v8 round-trip and v7 migration coverage in
test_settings.cpp.make checkpasses. Simulator 76/76. Firmware builds at0xfda30.Not verified: an actual run. That needs a car and a straight, and the acceptance
criterion — checked against an independent timing source — can only be met there.
Not in scope
its own conventions, and it should not be silently mixed in
than GNSS can, and the device already has a launch threshold — but it is a second sensor
and a fusion problem, better once the GNSS-only error is known rather than guessed
🤖 Generated with Claude Code