TelemetrySign in

Chassis Lateral Load

Algorithm imu-1.0.0+mount-1.0.0 · source engine/src/dtta/engine/imu/{conventions,filters,mount,body,gyro}.py, engine/src/dtta/engine/pipeline/imu.py.

What an accelerometer measures

An accelerometer measures specific force f=agf = a - g: its own acceleration minus gravity. At rest it reads +g0+g_0 along the up direction (g0=9.80665g_0 = 9.80665 m/s²); in free fall it reads zero. GoPro's GRAV stream is the up unit vector in camera coordinates (verified on stationary data: RMS error 0.016–0.036 g after a fixed axis permutation). Raw accelerometer magnitude on a dirt car is dominated by vibration (99th percentile 46–59 m/s², occasional ±8 g sensor clipping) and is never shown as a G number.

Frames and rotation convention

frame axes
C — camera +ZC+Z_C = up at rest; XC,YCX_C, Y_C complete a right-handed frame (lens direction not assumed)
V — vehicle (ISO 8855) +XV+X_V forward, +YV+Y_V left, +ZV+Z_V up; yaw positive turning left
E — earth east, north, up
P — path along the horizontal velocity, left of travel, up

RVCR_{V\leftarrow C} maps vector components from the camera frame to the vehicle frame; its rows are the vehicle axes expressed in camera coordinates. Quaternions use the Hamilton convention. Closed-form cases S1–S5 (stationary level, parked on a slope, steady banked turn, straight-line acceleration with pitch, free fall) are unit tests with tolerance 1e-9.

The channel

fV=saRVCfC,filt,Chassis Lateral Load=fbody,yf_V = s_a\,R_{V\leftarrow C}\,f_{C,filt}, \qquad \text{Chassis Lateral Load} = f_{body,y}

  • fC,filtf_{C,filt}: camera-frame specific force after (1) replacing samples at the ±8 g rail by an imu_hampel_window (11)-sample rolling median (imu_replace_clipped), (2) a zero-phase Butterworth low-pass, order 4 in second-order sections, cutoff imu_cutoff_hz = 5 Hz, per contiguous run, and (3) decimation to imu_decimate_hz = 50 Hz. The statistical Hampel filter is disabled (imu_hampel_nsigma = None): Phase 8 showed it replaced 1–9 % of racing samples and injected up to 0.12 g RMS of low-band error.
  • sas_a = accel_sign: +1 on every fixture (GoPro reports ff, not f-f; the handedness test would flip it and warn otherwise).
  • Positive fbody,yf_{body,y} = load toward the left of the car.

In a steady turn with horizontal centripetal acceleration aca_c (= Cornering G) and lean λ\lambda (bank + body roll, positive leaning into a left turn):

fbody,y=accosλg0sinλ,fbody,z=acsinλ+g0cosλf_{body,y} = a_c\cos\lambda - g_0\sin\lambda, \qquad f_{body,z} = a_c\sin\lambda + g_0\cos\lambda

Banking reduces felt lateral load. Chassis Load ≠ Cornering G on a banked track is physics, not an error, and the difference is reported as a lean diagnostic:

λest=atan2(fbody,z,fbody,y)atan2(g0,alat,path)\lambda_{est} = \operatorname{atan2}(f_{body,z}, f_{body,y}) - \operatorname{atan2}(g_0, a_{lat,path})

(undefined below 8 m/s; low-passed at lean_lowpass_hz when used elsewhere). On the Hamilton County fixture the chassis leans out by ~7° relative to its parked attitude in the corners, and Chassis Load reads 0.08–0.14 g more than Cornering G — both instruments agree, so it is reported, not corrected.

Mount calibration RVCR_{V\leftarrow C}

Automatic, per session:

  1. z^V\hat z_V = mean up vector over stationary periods (speed < stationary_speed_max_ms, ≥ stationary_min_seconds = 30 s; else the low-passed f/ff/|f| over the session with confidence 0.6). When stationary runs disagree by more than stationary_up_spread_max_deg (3°) the pre-race run is used and a note is recorded.
  2. Lateral axis first (ovals have almost no straight-line braking windows): the horizontal specific force is fitted by least squares onto the GPS path accelerations (along,alat)(a_{long}, a_{lat}) on racing samples; y^V\hat y_V is the lateral direction, x^V=y^V×z^V\hat x_V = \hat y_V \times \hat z_V. corr_lat (0.90–0.96 on the fixtures) is the primary quality, corr_long (0.53–0.77) a diagnostic.
  3. GPS lag: the GPS-derived channels are shifted by gps_lag_s (cross-correlation of the low-passed fbody,xf_{body,x} with along,patha_{long,path}, ±2.5 s) before any comparison.
  4. Handedness: in left turns (alat,path>a_{lat,path} > handedness_min_lat_ms2) the lateral sign agreement must be ≥ handedness_agreement_min (95 %), the net rotation rVdt\int r_V\,dt over the racing samples must be positive with the GPS sign and exceed half a turn, and the yaw sign must agree in ≥ 60 % of corner samples.
  5. Confidence = min(stationary 1.0/0.6, correlation 1.0/0.7/0.4 at calib_corr_good 0.8 / calib_corr_ok 0.6, handedness 1.0/0.3/0.7); method auto at ≥ 0.8, else auto_low_confidence.

Manual override (engineer): lens facing forward/rearward/left/right, upside-down, roll, pitch → a deterministic RVCR_{V\leftarrow C} with method = manual, confidence 0.75, full provenance.

Priority (never silent): 1 automatic ≥ 0.8 → 2 automatic 0.5–0.8 (shown with a warning) → 3 manual → 4 hidden. Vehicle-frame channels (Chassis Load, body-yaw lateral, lean) are shown only at priority ≤ 3; Cornering G needs no IMU and is always available. The same rule gates the chassis columns of the segment table.

Mount drift: per lap, the angle between the gyro-propagated up vector (complementary filter, complementary_tau_s = 15 s) and the calibrated ZVZ_V is reported; laps above mount_drift_max_deg (10°) are flagged mount_moved and their vehicle-frame values are marked unreliable. This caught a camera whose mount rotated 38° during a heat.

Sustained value (per segment)

Same definition as Cornering G: maximum 1 s sliding mean of fbody,y|f_{body,y}| (sustained_window_s).

Limitations

  • Requires a rigid mount. A flexing pole mount (I-35 "facing out" HERO9) gives 0.21 g RMS disagreement with the driver camera and is classified auto_low_confidence (0.3) → hidden.
  • Only bank + roll relative to the parked attitude is observable; parking on a slope shifts λ\lambda by the slope (the I-35 camera showed 4.9° between two stationary runs for that reason).
  • The longitudinal axis fbody,xf_{body,x} carries g0sinθg_0\sin\theta from pitch and braking-in-corner content: it is an engineer diagnostic, never the driver's longitudinal number.

Verified

Phase 8 (docs/proofs/phase-08/REPORT.md): stationary fV=(0,0,g0)±0.05g0f_V = (0,0,g_0) \pm 0.05\,g_0 and $|f| = 1.00 \pm 0.02,g_0$; handedness pass on the three rigid cameras; R3 closed (GoPro GRAV tracks true vertical mid-corner to 1–3°); two same-car cameras agree on the gyro lateral to 0.08–0.10 g RMS. Tests: engine/tests/unit/test_imu_conventions.py, synthetic banked turn at 0/8/15° lean (Chassis Load within 0.02 g, lean within 0.5°), vibration + 5 g spike, mounted rearward/left/right/upside-down recovered within 2°.