Sensor-fusion polish: calibration badge, 3D replay, richer CSV, chart-label fixes#25
Open
lkasso wants to merge 8 commits into
Open
Sensor-fusion polish: calibration badge, 3D replay, richer CSV, chart-label fixes#25lkasso wants to merge 8 commits into
lkasso wants to merge 8 commits into
Conversation
Users who think in Euler angles had to do quaternion math in a spreadsheet. The exporter now appends host-computed Tait-Bryan angles (heading 0-360, pitch +/-90, roll +/-180) after the raw w/x/y/z columns, in both logged-session and live-buffer CSVs. Derivation happens at export via a new MWDataConvertible hook so stored samples stay raw. No derived yaw column on purpose: the firmware's yaw channel is gyro-INTEGRATED (unbounded, drifts) and cannot be reconstructed from a single orientation quaternion - it would just duplicate heading. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bosch fusion outputs (especially heading) are unreliable until the algorithm calibrates against real motion, and the app never said so - users had no way to know their orientation data was garbage. While any fusion channel streams, a badge now shows the chip's own 0-3 accuracy per sensor (A/G/M chips colored by level) with a rotate-to-calibrate hint until everything reads high. The read ([0x19, 0x8B]) is only valid while fusion is RUNNING, which is exactly when the badge shows: polling starts with the streams and ends with them (pause included). Any poll failure just stops the updates - a courtesy readout must never tear down the streams. Gated on sensor- fusion revision >= 1 (C++ CALIBRATION_REVISION). The demo transport answers all-high, so the badge is simulator-testable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two fixes for saved sessions: 1. The detail chart styled everything with generic x/y/z/w labels, which actively MISLABELED fusion sessions - a quaternion's first channel is w (rendered as "x"), and Euler channels are heading/pitch/ roll/yaw. Styles now resolve from the persisted kind (fusion types) or the capture-time label (units, colors, and the captured +/-range for everything else), falling back to generic only for legacy records. 2. Quaternion sessions gain a 3D replay: the same board view the live stream uses, driven by a playback clock instead of BLE, with play/ pause, a scrubber, and a 1x/2x/4x speed toggle. Timing comes from the board's own tick clock (normalized 0-based; clamped monotonic so a stray out-of-order tick can't break the scrub binary search). QuaternionRealityView is a pure function of "latest sample", so replay is just choosing which sample is latest - and it picks up the real MetaMotion.usdz automatically once that ships. Also deletes SessionHistoryViewModel, dead since the history screen went direct-to-store. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
55%/45% of the container height crowded out the chart and replay controls; 42%/35% (min 240pt) leaves the board plenty readable while keeping the rest of the screen above the fold. Applies to both the live view and session replay, which share this component. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field test: all-green is nearly unreachable at a desk and doesn't stick - the fusion algorithm continuously re-evaluates accuracy and demotes the magnetometer the moment it sees field distortion, which indoors is constant (laptop, monitor, chargers, metal). Nagging users toward permanent green was asking the impossible. Bosch's own guidance is that MEDIUM (2 of 3) is good enough to record, so the badge now has three states: Calibrating (any sensor below medium), Ready To Record (all at least medium - the blue state), and Fully Calibrated (all high). While calibrating, each sensor below the bar gets ITS OWN instruction - the three sensors calibrate with different motions (accel: rest on each face; gyro: hold still; mag: figure-8 away from electronics), so one generic "rotate the board" line couldn't get anyone to green. The ready state explains that a dipping M rating indoors is normal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Built from the owner's CAD STEP exports (100-050 bottom shell + 100-060 top-cover assembly with the button; 100-051 is the same top without the button and was skipped). Pipeline: OpenCascade (cadquery) tessellation at 0.05 mm -> SceneKit assembly with PBR materials (top shell brighter/smoother than bottom so the seam reads) -> USDZ. Both parts share one CAD frame so they align natively, and the case already sits long-axis-Y / face-toward-+Z - the exact orientation QuaternionRealityView expects, so no axis correction needed. The loader finds it by name and the synchronized project group bundles it - zero code change; the procedural board remains as the fallback. CAD meshes carry no textures, so the shells are tinted white in-material like the physical case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The top-cover STEP is an assembly of three solids (front cover, button, LED light pipe) that the first conversion flattened into one white mesh. Exploding the compound lets each part carry its own material: grey button, glossier lens-like LED window, white shells - matching the physical device. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hardware test: the model's rest pose was right but rotations came out about the wrong axes - physical yaw rolled the model, etc. The fusion quaternion lives in Bosch's Z-up world; RealityKit is Y-up with Z toward the camera. Applying the raw quaternion mixed the two frames. Fix is a change of basis: conjugate by the fixed -90-about-X rotation (q' = M q M^-1) that sends Earth-up to screen-up. Conjugation - not a pre-multiply - is the load-bearing choice: identity conjugates to identity, which is exactly the observed symptom pattern (rest pose correct, axes switched). Also guards against zero/malformed samples that would produce NaN orientations. Co-Authored-By: Claude Fable 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.
The fusion follow-up planned after the group-logging arc. Three pieces (the real
MetaMotion.usdzis deliberately NOT here — the loader already picks it up from the bundle the moment the file lands, so it ships separately whenever we have it):Calibration badge (Live Stream)
While any fusion channel streams, a badge shows the chip's own 0–3 calibration accuracy per sensor — A/G/M chips colored by level — with a rotate-to-calibrate hint until everything reads high. Heading is garbage before calibration and the app never said so.
[0x19, 0x8B], every 2 s) starts/stops with the streams — the read is only valid while fusion runs. Failures silently stop the badge; they never touch the streams.3D replay of saved quaternion sessions
Session detail for a quaternion session now replays the recorded motion in the same 3D board view the live stream uses: play/pause, scrubber, 1×/2×/4× speed. Timing comes from the board's own tick clock (normalized, clamped monotonic).
ReplayTimeline(the position→sample binary search) is unit-tested at the boundaries.Richer CSV + label fixes
heading,pitch,rollafterw,x,y,z. No derived yaw — the firmware's yaw is gyro-integrated and can't be reconstructed from one quaternion; it would just duplicate heading.wrendered as "x", Euler channels as "x/y/z/w". Styles now recover the real sensor (labels, units, captured ± range) from the persisted kind + capture-time label.SessionHistoryViewModel.Validation
ReplayTimelineTests,SessionAxisStyleTests).🤖 Generated with Claude Code