Compare commits

..

6 Commits

Author SHA1 Message Date
mikkeli b52a7dcedb Checklist v3: IMU calibration (level twice, straight pull-aways and stops); yukart/raw/imu
/ crosscheck (push) Successful in 1s
Rust consumers (L4T) / Clippy, test, build, glibc for every service that compiles contracts in (push) Successful in 19s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
2026-10-14 13:28:40 +09:00
mikkeli 4cbac36fbe IMU signals in the car's frame (attitude, gravity-free g, yaw rate) on yukart/imu/<signal>
/ crosscheck (push) Successful in 0s
Rust consumers (L4T) / Clippy, test, build, glibc for every service that compiles contracts in (push) Successful in 17s
The WT61's publisher owns mounting and gravity; displays get car-frame values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
2026-10-13 23:23:31 +09:00
mikkeli 5d186bfd5d Captures plan: OBD-II through the ELM on the K-line, obd_* names, what each poller state means
/ crosscheck (push) Successful in 1s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
2026-10-13 22:57:31 +09:00
mikkeli 229d796cfd OBD-II signals renamed obd_*, plus timing, trims, O2; GNSS signals; elm_connected; reboot command
/ crosscheck (push) Successful in 1s
Rust consumers (L4T) / Clippy, test, build, glibc for every service that compiles contracts in (push) Failing after 6s
Decision 30: CAN feeds displays, OBD-II (K-line via the ELM) calibrates, so every
obd2 signal carries the obd_ prefix and the plain names are left for decoded ones.
yukart/gnss/<signal> gives displays the fix as single values; gnss/fix stays for
navigation. Boundary: reboot beside poweroff, same guards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
2026-10-13 22:50:03 +09:00
mikkeli 5feba8b354 Decode report: clutch and transmission not on CAN, stated once; no camera trigger plan
/ crosscheck (push) Successful in 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
2026-10-13 21:48:07 +09:00
mikkeli 0eab0e660e Decode report: reverse rechecked, gear inference dropped for a recommended gear
/ crosscheck (push) Successful in 0s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDwfd6Ki8UfG4hK6W5YpJz
2026-10-13 21:44:52 +09:00
7 changed files with 386 additions and 110 deletions
+54 -1
View File
@@ -1,6 +1,6 @@
{ {
"id": "z27ag-captures", "id": "z27ag-captures",
"version": 2, "version": 3,
"title": "Z27AG decoding captures", "title": "Z27AG decoding captures",
"about": "docs/impl/plans/Z27AG-CAPTURES.md", "about": "docs/impl/plans/Z27AG-CAPTURES.md",
"mark_format": "<step> <action>[ #<n>] start|end for a span, <step> <action>[ #<n>] for a point", "mark_format": "<step> <action>[ #<n>] start|end for a span, <step> <action>[ #<n>] for a point",
@@ -447,6 +447,59 @@
] ]
} }
] ]
},
{
"title": "IMU calibration (module fixed in its final place)",
"steps": [
{
"id": "27",
"title": "IMU level, facing one way",
"do": "Parked on the flattest ground at hand, engine off or idling, nobody moving inside. Start, keep still 15 s, end.",
"finds": "which way is down for the IMU (with step 28, cancelling the ground's slope)",
"actions": [
{
"label": "imu level A",
"hold_s": 15
}
]
},
{
"id": "28",
"title": "IMU level, turned round",
"do": "The same spot, nose the other way: a rough 180° will do. Still again, 15 s.",
"finds": "the second half of the level: the slope's tilt reverses, the mounting's does not",
"actions": [
{
"label": "imu level B",
"hold_s": 15
}
]
},
{
"id": "29",
"title": "IMU pull-away, straight",
"do": "A straight, flat section. From standstill, a firm pull-away in 1st to about 30. Start as the clutch bites, end as you lift.",
"finds": "which way is forward for the IMU",
"actions": [
{
"label": "imu pull away",
"repeat": 3
}
]
},
{
"id": "30",
"title": "IMU braking, straight",
"do": "The same section. From about 40, a firm (not emergency) stop. Start as you brake, end when stopped.",
"finds": "forward again, from the other side; also braking g",
"actions": [
{
"label": "imu brake",
"repeat": 3
}
]
}
]
} }
] ]
} }
+9 -7
View File
@@ -37,7 +37,7 @@ The two channels from decision 24 share the socket but keep different guarantees
| `ack` | reply to a `cmd` | `id`, `ok`, `detail`, `dup` (true when answered from the cache) | | `ack` | reply to a `cmd` | `id`, `ok`, `detail`, `dup` (true when answered from the cache) |
With `source: bus`, `signals` is the newest envelope of every signal svc-gw has With `source: bus`, `signals` is the newest envelope of every signal svc-gw has
seen on `yukart/vehicle/+` and `yukart/host/+`. svc-gw marks one seen on `yukart/vehicle/+`, `yukart/host/+`, `yukart/gnss/+` and `yukart/imu/+`. svc-gw marks one
`quality: "stale"` when it has not been refreshed for 5 s, or is known only from `quality: "stale"` when it has not been refreshed for 5 s, or is known only from
the broker's retained copy (which may predate a reboot). A signal once seen is the broker's retained copy (which may predate a reboot). A signal once seen is
never removed. never removed.
@@ -66,18 +66,20 @@ tablet, or an Orin behind a replugged hub, looks connected at the link layer.
|---|---|---| |---|---|---|
| `ping` | — | `ack` with `detail: "pong"` | | `ping` | — | `ack` with `detail: "pong"` |
| `mark` | `text`, `delay_ms` (optional: how long the command waited before this send) | stamped into the open recording; fails with no session open | | `mark` | `text`, `delay_ms` (optional: how long the command waited before this send) | stamped into the open recording; fails with no session open |
| `poweroff` | `confirm: "poweroff"`, `boot_id` (from this connection's `hello`) | acks, then shuts the host down cleanly (`systemctl poweroff`) about 2 s later. Refused unless svc-gw runs with `--allow-poweroff` (the Orin's unit only), and when `boot_id` is not the current boot's | | `poweroff` | `confirm: "poweroff"`, `boot_id` (from this connection's `hello`) | acks, then shuts the host down cleanly (`systemctl poweroff`) about 2 s later. Refused unless svc-gw runs with `--allow-power` (the Orin's unit only), and when `boot_id` is not the current boot's |
| `reboot` | `confirm: "reboot"`, `boot_id` | the same, with `systemctl reboot`; the same flag and refusals |
A repeated `id` returns the original `ack` (last 256 kept, shared across A repeated `id` returns the original `ack` (last 256 kept, shared across
connections) and never re-runs the command. connections) and never re-runs the command.
`poweroff` is the exception to retry-until-acked: the ack cache does not survive `poweroff` and `reboot` are the exception to retry-until-acked: the ack cache does
the reboot it causes, so a resend could shut the next boot down too. The client not survive the restart they cause, so a resend could shut the next boot down (or
sends it once and does not resend it; `boot_id` makes svc-gw refuse one from a reboot it again). The client sends them once and does not resend; `boot_id` makes
previous boot regardless. svc-gw refuse one from a previous boot regardless.
## Not yet ## Not yet
- TTS utterances (id, chunk sequence, terminator, expiry) — when there is a TTS. - TTS utterances (id, chunk sequence, terminator, expiry) — when there is a TTS.
- `gnss`: its fix is an object, which the envelope's `value` does not allow yet. - `gnss/fix` as one object (navigation's input): the envelope's `value` does not allow
one yet. Displays get the fix as single values on `yukart/gnss/<signal>` instead.
- Any version beyond `proto: 0`. A breaking change bumps it; the client checks it. - Any version beyond `proto: 0`. A breaking change bumps it; the client checks it.
+1 -1
View File
@@ -9,7 +9,7 @@ type: guidelines
- ⚠ **The unit appears in both the topic name and the payload, so they can - ⚠ **The unit appears in both the topic name and the payload, so they can
contradict each other.** Generating both from one entry is what stops that; a contradict each other.** Generating both from one entry is what stops that; a
hand-written `"unit"` reintroduces the failure it was meant to prevent. hand-written `"unit"` reintroduces the failure it was meant to prevent.
- Signal names carry their unit (`vehicle_speed_kph`, `coolant_temp_c`), so a unit - Signal names carry their unit (`gnss_speed_kph`, `obd_coolant_temp_c`), so a unit
mismatch is visible at the call site rather than one registry lookup away. mismatch is visible at the call site rather than one registry lookup away.
## 2. Two clocks, and they answer different questions ## 2. Two clocks, and they answer different questions
+38 -15
View File
@@ -1,7 +1,7 @@
--- ---
type: plan type: plan
status: ready status: ready
updated: 2026-10-13 updated: 2026-10-14
--- ---
# Z27AG decoding captures: what to do in the car # Z27AG decoding captures: what to do in the car
@@ -13,10 +13,11 @@ ground truth. Prior art and first candidates: [the prior-art report](../reports/
| In the session directory | From | Use | | In the session directory | From | Use |
|---|---|---| |---|---|---|
| `can-*.log(.zst)` | the PEAK, every frame, kernel timestamps | what gets decoded; also holds every OBD request (`7DF`) and reply (`7E8`) | | `can-*.log(.zst)` | the PEAK, every frame, kernel timestamps | what gets decoded (nothing transmits on CAN: OBD-II is on the K-line) |
| `vehicle.ndjson` | `obd-poller` via the bus | the same OBD replies as values (rpm, speed, throttle, load, MAP, MAF ~10 Hz; coolant, intake air, fuel 1 Hz); `env.timestamp` equals the reply frame's timestamp | | `vehicle.ndjson` | `decoder` and `obd-poller` via the bus | decoded CAN signals, and the `obd_*` references from the K-line through the ELM327 (rpm, speed, throttle, load, MAF, timing, O2 every round; coolant, intake air, trims every 5 s); `env.timestamp` is the reply's arrival at the Orin |
| `events.ndjson` | marks from the app | when each step happened | | `events.ndjson` | marks from the app | when each step happened |
| `gnss.ndjson` | gpsd (SIM7600) | speed and position for the drive | | `gnss.ndjson` | gpsd (SIM7600) | speed and position for the drive |
| `imu.ndjson` | `imu` via the bus (`yukart/raw/imu`) | every IMU sample, raw module axes, Orin receive time: calibration (27–30) and, once calibrated, motion for the drive |
## Operating it from the app ## Operating it from the app
@@ -33,8 +34,9 @@ ground truth. Prior art and first candidates: [the prior-art report](../reports/
session` when there is no traffic yet (ignition on, PEAK plugged). A mark sent with session` when there is no traffic yet (ignition on, PEAK plugged). A mark sent with
the link down waits (`unacked`) and goes when it is back, with its delay noted. the link down waits (`unacked`) and goes when it is back, with its delay noted.
- The **Mark** button on the main screen is still there for anything off-plan. - The **Mark** button on the main screen is still there for anything off-plan.
- **OBD is working** when `engine_rpm`, `vehicle_speed_kph` and the rest appear in - **OBD is working** when `obd_engine_rpm`, `obd_coolant_temp_c` and the rest appear
the signal list and move. If they never appear, see *If OBD stays silent*. in the signal list and move (the ELM on the OBD port, through the Y harness beside
the PEAK). If they never appear, see *If OBD stays silent*.
## The steps ## The steps
@@ -52,14 +54,20 @@ recorder refuses marks with "no session" otherwise); engine off, doors shut.
- **Engine running, parked** (14–18): start and idle, held revs in neutral (no OBD - **Engine running, parked** (14–18): start and idle, held revs in neutral (no OBD
on this car's CAN: the revs are approximate, read off the tacho), blips, A/C load, radiator fan. on this car's CAN: the revs are approximate, read off the tacho), blips, A/C load, radiator fan.
- **Driving** (19–22): steady speeds, stops, corners, each gear. A passenger presses, - **Driving** (19–22): steady speeds, stops, corners, each gear. A passenger presses,
or skip the marks: GNSS speed is recorded continuously, and gear comes from or skip the marks: GNSS speed is recorded continuously. The gear is not on CAN and
rpm ÷ speed. is not inferred (decode report).
- **On jack stands** (23–26, since v2): front wheels up, rears chocked, handbrake - **On jack stands** (23–26, since v2): front wheels up, rears chocked, handbrake
off. Unpowered steering; speedometer readings held in 2nd and 3rd (fronts turn, off. Unpowered steering; speedometer readings held in 2nd and 3rd (fronts turn,
rears stay still, which tells the wheels apart); braking from speed with vacuum rears stay still, which tells the wheels apart); braking from speed with vacuum
assist; reverse. Stands replace the driving speeds where a drive is not practical. assist; reverse. Stands replace the driving speeds where a drive is not practical.
- **IMU calibration** (27–30, since v3): once the IMU is fixed in its final place. Level
twice on the same spot, facing one way and then turned round (a rough 180° is fine:
the ground's slope reverses and cancels, the mounting's tilt does not); then three
firm pull-aways and three firm stops on a straight, flat section (forward, signed by
which kind of stretch it is). Any session holds raw IMU samples (`imu.ndjson`), so
these can go in their own short session or with anything else.
Version 2 (2026-10-13) adds the stands section and writes down the conditions the Version 3 (2026-10-14) adds the IMU calibration section. Version 2 (2026-10-13) adds the stands section and writes down the conditions the
first run showed matter: engine off and handbrake on for 1–13, foot brake held for first run showed matter: engine off and handbrake on for 1–13, foot brake held for
the handbrake step, neutral with the clutch up for the revs. the handbrake step, neutral with the clutch up for the revs.
@@ -80,18 +88,33 @@ The parked steps can be split over several sessions; the drive is the important
## If OBD stays silent ## If OBD stays silent
`yukart/system/obd-poller` says why (visible in `mosquitto_sub -v -t 'yukart/system/#'` `yukart/system/obd-poller` says why (visible in `mosquitto_sub -v -t 'yukart/system/#'`
on the Orin): on the Orin), and the signal list's `elm_connected` shows the Bluetooth link:
- `bus idle: not polling`: no traffic: ignition off or PEAK unplugged. - `ELM …: … (unplugged, asleep or out of range)`: no Bluetooth link. The ELM in the
- `no ECU answers 01 00`: the engine ECU does not do standard mode 01 on this bus. port? Its light on? A phone app holding it (it takes one connection)? Retried
Then OBDb's MUT-III (`21 xx`) requests are the next thing to try. every minute.
- `ECU not answering (…): ignition off?`: the ELM is there, the car is not. The
adapter's own words are in the brackets (`BUS INIT: ...ERROR`, `NO DATA`).
- `ECU silent for 60 s: adapter released`: ignition off for a minute; the poller let
go so the ELM can sleep, and tries again every minute.
- To see what answers, on the Orin: `sudo systemctl stop yukart-obd-poller`, - To see what answers, on the Orin: `sudo systemctl stop yukart-obd-poller`,
`yukart-obd-poller --once` (supported PIDs and one value each, with reply times), `yukart-obd-poller --elm $(. /etc/default/yukart-elm; echo $ELM_ADDR) --once`
`sudo systemctl start yukart-obd-poller`. Never two pollers at once: their (adapter, protocol, supported PIDs and one value each, with reply times), then
replies would cross. `sudo systemctl start yukart-obd-poller`.
## Afterwards ## Afterwards
**IMU calibration**, on the car Orin, from the session that holds steps 27–30:
```bash
yukart-imu --calibrate /var/lib/yukart/recordings/<session> # print: down, forward, slope, spread
yukart-imu --calibrate /var/lib/yukart/recordings/<session> --write # and save /var/lib/yukart/imu/mount.json
```
The service picks the new mounting up within seconds; roll and pitch should then read
about 0 parked on level ground. Steps 27–28 alone also work: forward then stays the
`--forward` axis, laid flat, until a session with 29–30 is calibrated.
Sessions are in `/var/lib/yukart/recordings/` on the car Orin. Copy one off with Sessions are in `/var/lib/yukart/recordings/` on the car Orin. Copy one off with
`rsync -a mikkeli-orin-nano:/var/lib/yukart/recordings/<session>/ …` into `rsync -a mikkeli-orin-nano:/var/lib/yukart/recordings/<session>/ …` into
`yukart-data`, with a line in its README of what was done. `yukart-data`, with a line in its README of what was done.
+9 -4
View File
@@ -46,10 +46,15 @@ jack-stands session and a GNSS-matched drive settle both the byte order and the
## Not on this bus (or not seen) ## Not on this bus (or not seen)
- **Clutch pedal:** nothing changed in 3 presses, engine off. - **Clutch and transmission are not on this bus.** Nothing changed for the clutch
- **Gear position:** nothing in 5 gears, reverse or neutral. Expected for a manual. The (3 presses), any of the 5 gears, neutral or reverse: nothing on the car consumes
gear can be computed from rpm ÷ wheel speed once the scale is known. them, so no frame carries them. Reverse was rechecked against both reverse
- **Reverse:** no reverse bit found. The reverse lamp is probably wired directly. stretches (engine off and engine on) versus every other position: no bit
separates them.
- **Gear is not inferred from rpm ÷ wheel speed** (owner's call, 2026-10-13): the
clutch is invisible, so the ratio lies whenever it is down or slipping, and the
gear matters most at a standstill, where the ratio says nothing. A *recommended*
gear from speed and rpm is the useful form, if any.
- **Steering angle:** not analysed yet (step 5 was done with the engine on, at the end). - **Steering angle:** not analysed yet (step 5 was done with the engine on, at the end).
## Not analysed yet ## Not analysed yet
+253 -81
View File
@@ -1,6 +1,136 @@
{ {
"$comment": "Single source for signal identity. Topic name and envelope unit are both derived from these entries and are never authored separately. source=obd2 is standardised; source=host is the Orin itself (orin-status), not the car. source=z27ag is reverse-engineered from the car's own broadcast frames, and its 'can' block is the only place its layout is written down: id (11-bit, hex string), byte (first data byte, 0-7), length in bits (1, 8 or 16), bit (length 1 only: 0 = LSB of that byte), order (length 16: big = byte first is most significant, little = the reverse), scale and offset (value = raw * scale + offset; booleans are raw != 0). 'evidence' names the contracts report that found it.", "$comment": "Single source for signal identity. Topic name and envelope unit are both derived from these entries and are never authored separately. source=obd2 is standardised (OBD-II mode 01 over the K-line, through the ELM327): calibration references, every name prefixed obd_ (project-yukart decision 30); source=host is the Orin itself (orin-status), not the car. source=gnss is the receiver (svc-core gnss), on yukart/gnss/<signal>. source=imu is the WT61 IMU, already turned into the car's frame (mounting and gravity handled by its publisher), on yukart/imu/<signal>. source=z27ag is reverse-engineered from the car's own broadcast frames, and its 'can' block is the only place its layout is written down: id (11-bit, hex string), byte (first data byte, 0-7), length in bits (1, 8 or 16), bit (length 1 only: 0 = LSB of that byte), order (length 16: big = byte first is most significant, little = the reverse), scale and offset (value = raw * scale + offset; booleans are raw != 0). 'evidence' names the contracts report that found it.",
"signals": { "signals": {
"obd_vehicle_speed_kph": {
"unit": "kph",
"type": "number",
"source": "obd2",
"description": "Road speed",
"range": [
0,
255
]
},
"obd_coolant_temp_c": {
"unit": "celsius",
"type": "number",
"source": "obd2",
"description": "Engine coolant temperature",
"range": [
-40,
215
]
},
"obd_intake_air_temp_c": {
"unit": "celsius",
"type": "number",
"source": "obd2",
"description": "Intake air temperature",
"range": [
-40,
215
]
},
"obd_throttle_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Throttle position",
"range": [
0,
100
]
},
"obd_engine_load_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Calculated engine load",
"range": [
0,
100
]
},
"obd_fuel_level_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Fuel tank level",
"range": [
0,
100
]
},
"obd_intake_pressure_kpa": {
"unit": "kpa",
"type": "number",
"source": "obd2",
"description": "Intake manifold absolute pressure",
"range": [
0,
255
]
},
"obd_maf_gps": {
"unit": "g/s",
"type": "number",
"source": "obd2",
"description": "Mass air flow rate",
"range": [
0,
656
]
},
"obd_engine_rpm": {
"unit": "rpm",
"type": "number",
"source": "obd2",
"description": "Engine speed (OBD-II 0C): the reference for the decoded engine_rpm",
"range": [
0,
8000
]
},
"obd_timing_advance_deg": {
"unit": "degree",
"type": "number",
"source": "obd2",
"description": "Ignition timing advance before TDC, cylinder 1",
"range": [
-64,
64
]
},
"obd_stft_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Short-term fuel trim, bank 1: positive adds fuel",
"range": [
-100,
100
]
},
"obd_ltft_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Long-term fuel trim, bank 1: positive adds fuel",
"range": [
-100,
100
]
},
"obd_o2_b1s1_v": {
"unit": "V",
"type": "number",
"source": "obd2",
"description": "Upstream oxygen sensor voltage (narrowband: ~0.1 lean … ~0.9 rich)",
"range": [
0,
1.275
]
},
"engine_rpm": { "engine_rpm": {
"unit": "rpm", "unit": "rpm",
"type": "number", "type": "number",
@@ -20,86 +150,6 @@
"evidence": "Z27AG-DECODE-1" "evidence": "Z27AG-DECODE-1"
} }
}, },
"vehicle_speed_kph": {
"unit": "kph",
"type": "number",
"source": "obd2",
"description": "Road speed",
"range": [
0,
255
]
},
"coolant_temp_c": {
"unit": "celsius",
"type": "number",
"source": "obd2",
"description": "Engine coolant temperature",
"range": [
-40,
215
]
},
"intake_air_temp_c": {
"unit": "celsius",
"type": "number",
"source": "obd2",
"description": "Intake air temperature",
"range": [
-40,
215
]
},
"throttle_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Throttle position",
"range": [
0,
100
]
},
"engine_load_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Calculated engine load",
"range": [
0,
100
]
},
"fuel_level_pct": {
"unit": "percent",
"type": "number",
"source": "obd2",
"description": "Fuel tank level",
"range": [
0,
100
]
},
"intake_pressure_kpa": {
"unit": "kpa",
"type": "number",
"source": "obd2",
"description": "Intake manifold absolute pressure",
"range": [
0,
255
]
},
"maf_gps": {
"unit": "g/s",
"type": "number",
"source": "obd2",
"description": "Mass air flow rate",
"range": [
0,
656
]
},
"accel_pedal_pct": { "accel_pedal_pct": {
"unit": "percent", "unit": "percent",
"type": "number", "type": "number",
@@ -477,6 +527,12 @@
10000 10000
] ]
}, },
"elm_connected": {
"unit": "",
"type": "boolean",
"source": "host",
"description": "Bluetooth link to the OBD-II adapter (the ELM327 on the K-line) is up: obd-poller holds it while the ECU answers"
},
"ups_battery_v": { "ups_battery_v": {
"unit": "V", "unit": "V",
"type": "number", "type": "number",
@@ -512,6 +568,122 @@
"type": "string", "type": "string",
"source": "host", "source": "host",
"description": "charging, discharging (running on battery) or idle (on input power, not charging)" "description": "charging, discharging (running on battery) or idle (on input power, not charging)"
},
"gnss_fix": {
"unit": "",
"type": "string",
"source": "gnss",
"description": "Fix quality: none, 2d or 3d (gpsd TPV mode)"
},
"gnss_speed_kph": {
"unit": "kph",
"type": "number",
"source": "gnss",
"description": "Speed over ground; null without a fix",
"range": [
0,
300
]
},
"gnss_heading_deg": {
"unit": "degree",
"type": "number",
"source": "gnss",
"description": "Course over ground, true north; null without a fix or at a standstill",
"range": [
0,
360
]
},
"gnss_lat": {
"unit": "degree",
"type": "number",
"source": "gnss",
"description": "Latitude, WGS84",
"range": [
-90,
90
]
},
"gnss_lon": {
"unit": "degree",
"type": "number",
"source": "gnss",
"description": "Longitude, WGS84",
"range": [
-180,
180
]
},
"gnss_alt_m": {
"unit": "m",
"type": "number",
"source": "gnss",
"description": "Altitude above mean sea level; null without a 3D fix",
"range": [
-500,
9000
]
},
"gnss_satellites": {
"unit": "",
"type": "number",
"source": "gnss",
"description": "Satellites used in the fix",
"range": [
0,
64
]
},
"imu_roll_deg": {
"unit": "degree",
"type": "number",
"source": "imu",
"description": "Body roll in the car's frame: positive leaning right (right side down)",
"range": [
-180,
180
]
},
"imu_pitch_deg": {
"unit": "degree",
"type": "number",
"source": "imu",
"description": "Body pitch in the car's frame: positive nose up",
"range": [
-90,
90
]
},
"imu_accel_lon_g": {
"unit": "g",
"type": "number",
"source": "imu",
"description": "Longitudinal acceleration in the car's frame, gravity removed: positive forward (speeding up), negative braking",
"range": [
-4,
4
]
},
"imu_accel_lat_g": {
"unit": "g",
"type": "number",
"source": "imu",
"description": "Lateral acceleration in the car's frame, gravity removed: positive to the right (a right turn reads positive)",
"range": [
-4,
4
]
},
"imu_yaw_rate_dps": {
"unit": "degree/s",
"type": "number",
"source": "imu",
"description": "Yaw rate: positive turning left (counter-clockwise from above)",
"range": [
-500,
500
]
} }
} }
} }
+22 -1
View File
@@ -12,7 +12,7 @@
"payload": "envelope", "payload": "envelope",
"retained": true, "retained": true,
"rate": "1-50/s", "rate": "1-50/s",
"publisher": "decoder, obd-poller", "publisher": "decoder (source z27ag), obd-poller (source obd2)",
"description": "One topic per signal, named exactly as in signals.json." "description": "One topic per signal, named exactly as in signals.json."
}, },
"yukart/gnss/fix": { "yukart/gnss/fix": {
@@ -22,6 +22,27 @@
"publisher": "gnss", "publisher": "gnss",
"description": "value is an object: lat, lon, alt_m, speed_kph, heading_deg, fix, satellites." "description": "value is an object: lat, lon, alt_m, speed_kph, heading_deg, fix, satellites."
}, },
"yukart/gnss/<signal>": {
"payload": "envelope",
"retained": true,
"rate": "1-10/s",
"publisher": "gnss",
"description": "The receiver's fix as single values, one topic per signal, named exactly as in signals.json (source=gnss). For displays; yukart/gnss/fix stays the composite for navigation."
},
"yukart/imu/<signal>": {
"payload": "envelope",
"retained": true,
"rate": "10-50/s",
"publisher": "imu",
"description": "The IMU (WT61) in the car's frame: attitude, gravity-free acceleration, yaw rate; one topic per signal, named exactly as in signals.json (source=imu)."
},
"yukart/raw/imu": {
"payload": "json",
"retained": false,
"rate": "10-100/s",
"publisher": "imu",
"description": "Every IMU sample, raw: module axes, not calibrated. {mono (ns, CLOCK_MONOTONIC), t (µs, realtime), accel [x,y,z] g, gyro [x,y,z] deg/s, angle [roll,pitch,yaw] deg (the module's own)}. Not an envelope; for the recorder (imu.ndjson), so a later calibration can reprocess a session. Displays use yukart/imu/<signal>."
},
"yukart/host/<signal>": { "yukart/host/<signal>": {
"payload": "envelope", "payload": "envelope",
"retained": true, "retained": true,