--- type: report date: 2026-10-15 --- # Z27AG CAN: third pass, the drive back Sessions `000011-20261015T212904` and `000013-20261015T214544` (the drive back, about 13 minutes, no marks) together with pass 2's `000008` and `000009`: 20 km of driving with GNSS and the calibrated IMU, no OBD-II. Nothing was marked, so this pass uses what any drive has: corners and distance. ## Confirmed | Signal | Where | Evidence | Registered as | |---|---|---|---| | Wheel speeds | `235` four words, little-endian (pass 2): bytes 0–1 **front right**, 2–3 **front left**, 4–5 **rear right**, 6–7 **rear left** | from corners, below | `wheel_speed_fr_kph`, `_fl_`, `_rr_`, `_rl_` | | Odometer | `570` bytes 4–6, little-endian, **1 km** | steps once per kilometre: 12 steps over 11.9 km (`000009`), 3 over 3.0 km (`000011`); 167966 on the 13th, 167988 at the end of the drive back; valid with the engine off too. Agrees with the cluster's (digital) odometer | `odometer_km` (the layout format gained 24-bit fields) | | Distance counter | `14D` bytes 6–7, little-endian, **about 0.40 m** per count | tracks distance from the wheel speeds with correlation 1.0000 in both drives (103.2 and 103.6 m per step of byte 7); wraps every ~26 km | not registered. The cluster's two trip meters count 0.1 km and may run from this; it is also the finest distance on the bus (slow creeping, short manoeuvres) | ### Which word is which wheel In a corner the outer wheels run faster than the inner ones, by about half the track width times the curvature; and the fronts run on a wider arc than the rears, by about half the wheelbase squared times the curvature squared. Fitting each word's share of the four (its speed ÷ their mean) against the curvature from the steering angle (`steering_angle_deg` + 2.7° for the straight-ahead offset, ÷ 16.3, over a 2.5 m wheelbase), 74 476 frames above 15 km/h: | Word | Linear term (track) | Square term (wheelbase) | So | |---|---|---|---| | 0 | +0.72 m | +1.4 m² | right, front | | 1 | −0.72 m | +1.4 m² | left, front | | 2 | +0.75 m | −0.9 m² | right, rear | | 3 | −0.75 m | −1.9 m² | left, rear | Curvature is positive turning left, so a positive linear term is a wheel on the right (outside in a left turn). The size, ±0.72–0.75 m, is half the Colt's track (1.45–1.46 m). The square terms split the words into a pair above the mean and a pair below it, ±1.5 m² against an expected ±1.6 m² (2.5² ÷ 4). Medians by curvature agree: in left turns tighter than 20 m (`κ > 0.05`) the words read 1.068, 0.956, 1.044, 0.932 of their mean. Straight ahead the fronts read 0.6 % more counts than the rears, matching pass 2's per-word scales (0.0578 against 0.0581 km/h per count). Driven wheels or tyre sizes, either is ordinary; each pair is registered with its own scale, so all four read GNSS speed when cruising. Jack stands (checklist 23–26) would still confirm this, but are no longer needed to find it. ## Candidates - **`570` bytes 2 and 3: fuel, most likely.** Both fall slowly: byte 2 read 87 on the 13th and 76 at the end of the drive back, 22 km later. Both read `7F` with the engine off. Outside temperature was the other reading, but the car shows it nowhere, and the bytes **slosh**. Take away their own 60 s average, and what is left follows the car's motion in all three drives: | Byte | Lateral g | Longitudinal g | Lag | |---|---|---|---| | 3 | +0.70 to +0.81 | −0.42 to −0.48 | none | | 2 | +0.64 to +0.75 | −0.48 to −0.50 | about 3 s | Lateral g here is from the wheel speeds and the steering angle, longitudinal from the change in wheel speed. A temperature would not do this; liquid in a tank would. Byte 3 looks like the sender as it is, and byte 2 a damped copy (a gauge needle is damped the same way). The "rise while parked" (78 → 81) was the same thing: the drive before ended at 80, parked in the same spot (the same IMU tilt to three decimals). It read 76 a minute earlier, while still moving. The reading moves about ±4 with tilt and motion, so it needs averaging over minutes. Scale unknown: full is unlikely to be 100 or 255. A refuel gives two points (before and after, parked level, with the litres put in). Not registered until then. - **`449` bytes 0, 1, 3: climate-control temperatures, most likely raw sensor readings.** Pass 2 looked for a byte that equals OBD-II intake air temperature less 40 and found none. Read the other way, bytes 1 and 3 run *against* it (correlation −0.96 and −0.98 in `000007`), the way a thermistor's raw reading falls as it warms. They follow it over tens of minutes, not second to second, so they are other sensors that warm and cool with the air around the engine and car: - **Byte 3: the A/C evaporator.** At each first switch-on of the compressor (`ac_compressor`) it climbs from 115–145 to about 185 within 30–60 s, then stays there while the compressor cycles on and off every 10–20 s. That is the evaporator being held just above freezing, the job its sensor exists for. It keeps climbing a few counts after each switch-off, as an evaporator does while the last refrigerant boils off. With the A/C off it drifts with the air (the `000007` correlation above). Higher count, colder. - **Byte 1: outside air, probably.** Slow; 89–91 on the afternoon of the 13th, 99–117 in the evening of the 15th (higher count, colder, as byte 3). It fell from 114 to 99 over 30 minutes parked and idling, and rose from 112 to 117 over 8 minutes of driving. A sensor behind the grille does this: radiator heat soaks it while standing, and the airflow cools it once moving. That is why climate controls filter it. - **Byte 0: unclear.** 119–134, slow, unmoved by the engine starting or stopping (so not the charging voltage), and its sign against the other two is not consistent. A cabin sensor is one guess. An auto climate control has these three: evaporator, outside air, cabin. The way to scale them is an overnight soak: a cold start after the car has stood all night gives one reading of each with everything at the outside temperature (OBD-II intake and coolant say what that is). With a thermometer and the A/C steps (12, 17), it gives a second. A mid-session frame with byte 6 = 24 instead of 51 (end of `000009`, engine stopping) has every byte halved or changed; left out of the above. ## Notes on the recording - `000012` is a 25-second parked session in between; `000013` ends with the PEAK unplugged. - The recorder kept IMU samples as JSON lines (34 MB for `000009`). From this pass on it packs them (`imu.bin`, svc-core `imu/packed.rs`): the same samples are 8.5 MB, and all of `000009`'s samples fit the packed form exactly.