From 62ac7bd09df40d9696bf72a7c4e96ae29f54581f Mon Sep 17 00:00:00 2001 From: Mikkeli Date: Fri, 14 Aug 2026 09:21:10 +0900 Subject: [PATCH] Populate design, architecture and repo layout docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit project-yukart becomes the code-free hub: overview, roadmap and cross-cutting design only. Each app or app cluster gets its own repo, indexed from here. - ARCHITECTURE.md: separate services over a message bus, with displays as bus subscribers so the directly-driven screen, Android client and ESP32 panel share one contract. Records CAN scope (listen-only + OBD-II as sole writer) and a decisions table for choices still in flux. - REPOS.md: repo splitting rule, planned repos, naming, and Gitea template-repo policy (scaffolding only — no upstream link after instantiation). - ROADMAP.md: phases 0-5, capture and decode before displays. Bus choice (MQTT) is marked proposed pending a check against real CAN rates; implementation language is still open. Co-Authored-By: Claude Opus 5 --- README.md | 37 ++++++++++++-- docs/ARCHITECTURE.md | 119 +++++++++++++++++++++++++++++++++++++++++++ docs/REPOS.md | 86 +++++++++++++++++++++++++++++++ docs/ROADMAP.md | 67 ++++++++++++++++++++++++ 4 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 docs/ARCHITECTURE.md create mode 100644 docs/REPOS.md create mode 100644 docs/ROADMAP.md diff --git a/README.md b/README.md index 8cb84a5..d5967f9 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,37 @@ # Project Yukart -Mostly passive probing and info extraction and GUI on a Z27AG Colt Ralliart. -Overview available at [OVERVIEW.md](OVERVIEW.md). +Making a 2008 Mitsubishi Colt Ralliart (Z27AG) a bit smarter with modern technologies. +What the system is meant to do is described in [OVERVIEW.md](OVERVIEW.md). -## Other repositories +This repository is the **overview and roadmap only — it holds no code.** +Every application or application cluster lives in its own repository and is +indexed here. -- [Environment setup](gitea:yukart/orin-nano-env-setup) +## Documents -## Roadmap \ No newline at end of file +- [Overview](OVERVIEW.md) — what the system is meant to do +- [Architecture](docs/ARCHITECTURE.md) — system shape, services, message bus, display contract +- [Repositories](docs/REPOS.md) — repo layout, naming, template-repo policy +- [Roadmap](docs/ROADMAP.md) — phases and current status + +## Repository index + +| Repository | Role | Status | +|---|---|---| +| [project-yukart](gitea:yukart/project-yukart) | This hub — overview, roadmap, cross-cutting design | Active | +| [orin-nano-env-setup](gitea:yukart/orin-nano-env-setup) | Jetson host bring-up: drivers, kernel modules, OS-level setup | Active | + +Planned repositories and the reasoning behind the split are described in +[docs/REPOS.md](docs/REPOS.md). + +## Hardware at a glance + +| Part | Role | +|---|---| +| NVIDIA Jetson Orin Nano Super (`mikkeli-orin-nano-2`) | Main compute, JetPack r36.4 / Ubuntu 22.04 | +| PEAK PCAN-USB | Car CAN bus access (`can1`, 500 kbps) | +| Onboard MTTCan | Second CAN interface (`can0`) | +| Waveshare SIM7600G-H-M.2 | LTE Cat 4 + GNSS | + +Details and rationale live in the environment repo's +[bill of materials](gitea:yukart/orin-nano-env-setup). diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..8eb8408 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,119 @@ +# Architecture + +## The one rule + +**Everything is a bus participant.** Acquisition services publish; displays, +loggers and analysis tools subscribe. No service knows which display exists, and +no display talks to hardware. + +This is what lets the three display options coexist without forking the system, +and what lets a service be restarted or replaced mid-drive without taking the +rest down. + +## Shape + +``` + CAN (can1) ──▶ can-bridge ──┐ + OBD-II ──▶ obd-poller ─┤ + GNSS ──▶ gnss ├──▶ message bus ──┬──▶ recorder (disk) + camera ──▶ vision* ─┘ ├──▶ hud (local video out) + └──▶ telemetry-gw ──▶ remote displays + * later phase, separate task +``` + +## Services + +| Service | Responsibility | Transmits on CAN | +|---|---|---| +| `can-bridge` | Read SocketCAN frames, timestamp, publish raw | No | +| `obd-poller` | Active OBD-II PID request/response | **Yes** | +| `gnss` | gpsd client → position, speed, time fix | No | +| `decoder` | Raw frames → named signals via DBC | No | +| `recorder` | Persist raw + decoded sessions to disk | No | +| `telemetry-gw` | Serve external display clients | No | +| `vision` | Camera capture and on-device inference (later) | No | + +Each ships as a systemd unit. The host-level prerequisites they depend on +(kernel modules, device permissions, gpsd) are the environment repo's job, not +theirs. + +## CAN bus scope + +Passive sniffing **plus** active OBD-II queries. OBD-II is a request/response +protocol, so it necessarily transmits onto a 2008 car's bus. Constraints that +follow: + +- `can-bridge` runs listen-only and must never transmit. +- `obd-poller` is the **single writer**. No other service opens a TX-capable socket. +- Transmission is rate-limited and restricted to standard OBD-II diagnostic IDs. +- TX is a distinct, explicitly enabled mode — not the default state on boot. + +Reverse-engineering of Z27AG-specific frame IDs proceeds purely from observed +traffic; discovered signals are recorded as a DBC rather than as code. + +## Message bus + +**Proposed: MQTT (mosquitto) on the Jetson.** Rationale: + +- First-class client libraries on every display target — ESP32 (Arduino + `PubSubClient` / ESP-IDF) and Android (Paho) — which is the deciding factor. +- Broker handles fan-out and retained "last known value", so a display that + connects mid-drive immediately has state to render. +- Trivially inspectable with `mosquitto_sub` while debugging in a car. + +Rejected: NNG/ZeroMQ (lower latency, no broker, but a poor ESP32 story and no +retained values); DDS (capable, disproportionate). + +### Topics + +``` +yukart/can/raw high-rate raw frames, not retained +yukart/vehicle/ decoded signals (rpm, speed, coolant, …), retained +yukart/gnss/fix position/speed/time, retained +yukart/system/ health and status, retained +``` + +Payloads: JSON for low-rate signals (readable, debuggable); compact binary or +CBOR for `can/raw`, since a 500 kbps bus produces far more traffic than JSON +should carry. + +Topic names and payload schemas are a **contract shared across repos** — Android +and ESP32 clients depend on them — so they are versioned in their own repo +rather than duplicated per client. + +## Display contract + +Three display paths, in two classes: + +**Class A — video out.** A screen driven directly by the Orin over SPI/DP/HDMI. +The renderer is a local process subscribing to the bus over loopback. + +**Class B — data only.** The Orin sends no video, only data; the device renders +itself. + +| Path | Transport | Notes | +|---|---|---| +| Android app | WiFi, or USB (RNDIS) | Full-featured client, richest UI | +| ESP32 + RLCD/e-ink | WiFi, or USB/BT serial | Low-rate, glanceable subset of signals | + +Class B devices reaching the bus over IP connect to the broker directly. For +transports without IP (BT SPP, plain USB serial), `telemetry-gw` bridges +serial ↔ bus rather than each device inventing its own protocol. + +Because both classes are bus subscribers, adding, removing or swapping a display +touches no acquisition code. + +## Decisions + +Recorded here so fast-moving choices stay visible. Flip a row rather than +rewriting the document. + +| # | Decision | Status | Date | +|---|---|---|---| +| 1 | Separate services over a message bus, not one process | Accepted | 2026-08-14 | +| 2 | Displays are bus subscribers; no display-specific logic upstream | Accepted | 2026-08-14 | +| 3 | Listen-only sniffing + active OBD-II, single writer | Accepted | 2026-08-14 | +| 4 | MQTT as the bus | **Proposed** | 2026-08-14 | +| 5 | Implementation language(s) per service | **Open** | — | +| 6 | Local logging first; off-board LTE telemetry deferred | Accepted | 2026-08-14 | +| 7 | Camera/AI inference is a later, separate task | Accepted | 2026-08-14 | diff --git a/docs/REPOS.md b/docs/REPOS.md new file mode 100644 index 0000000..aa23cad --- /dev/null +++ b/docs/REPOS.md @@ -0,0 +1,86 @@ +# Repositories + +## Splitting rule + +- **`project-yukart`** — overview, roadmap, cross-cutting design. No code, ever. +- **`orin-nano-env-setup`** — the host: kernel modules, drivers, OS packages, + device permissions, systemd plumbing. Anything that must be true *before* an + application starts. +- **One repo per application or application cluster.** A cluster is a set of + services that are developed, versioned and deployed together. +- **Helper/deployment repos** stand alone when they are reusable outside Yukart. + +Anything cross-repo — topic names, payload schemas, the DBC — belongs in the +contracts repo, not copied into each consumer. + +## Current + +| Repository | Role | +|---|---| +| [project-yukart](gitea:yukart/project-yukart) | Hub: overview, roadmap, architecture | +| [orin-nano-env-setup](gitea:yukart/orin-nano-env-setup) | Jetson host bring-up | + +## Planned + +| Repository | Role | Why separate | +|---|---|---| +| `yukart-contracts` | Topic namespace, payload schemas, Z27AG DBC | Consumed by every other repo, including non-Jetson clients; must not be duplicated | +| `yukart-core` | Acquisition + processing cluster: `can-bridge`, `obd-poller`, `gnss`, `decoder`, `recorder` | Developed and deployed as one unit on the Orin | +| `yukart-gw` | `telemetry-gw` — serves external display clients | Independent release cycle from acquisition; the network-facing surface | +| `yukart-hud` | Local renderer for the directly-driven screen (Class A) | Its own toolchain and graphics stack | +| `yukart-android` | Android display client (Class B) | Entirely separate toolchain and release process | +| `yukart-esp32-display` | ESP32 RLCD/e-ink display firmware (Class B) | Embedded toolchain, flashed not deployed | +| `yukart-analysis` | Offline session analysis, reverse-engineering notebooks | Runs off-car, no runtime coupling | + +Create these lazily — when there is something to put in them, not before. + +## Naming + +- `yukart-*` for project-specific repositories. +- **No prefix** for reusable helpers, since the prefix would be a lie the first + time one is used in another project. + +## Helper and deployment repos + +Arduino and ESP32 work implies flashing, build and deployment scaffolding that +is likely to be reused. Keep those unprefixed and generic — e.g. an ESP32 +project skeleton with the toolchain, flashing scripts and CI already wired up. + +### Gitea template repositories + +Gitea supports these: repo **Settings → Repository → Template**, after which the +repo offers **"Use this template"** to create new repos from it. + +Use a template repo for **scaffolding** — a new ESP32 or Arduino project that +should start with the toolchain, directory layout and flashing scripts in place. + +Do **not** use one for code you intend to keep updating in one place. Template +instantiation is a fork-at-create: the copy has no link back, so improvements to +the template never reach repos already created from it. For genuinely shared +code, use a git submodule or publish a package instead. + +Rule of thumb: *template for the starting shape, submodule/package for living +code.* + +## Linking convention + +Cross-repo links use the `gitea:owner/repo` scheme, as established in the hub +README — e.g. `[Environment setup](gitea:yukart/orin-nano-env-setup)`. + +## Per-repo document layout + +Following the convention already set by `orin-nano-env-setup`: + +``` +README.md minimal portal, points everywhere else +docs/ + GUIDELINES.md implementation practice for this repo + BOM.md hardware, where the repo owns hardware + impl/ + plans/ what is intended + reports/ what actually happened, and why +``` + +The `impl/plans` ÷ `impl/reports` split is worth keeping: plans go stale, +reports do not. A report like `PCAN-SETUP.md` stays valuable precisely because +it records the investigation and the dead ends, not just the final commands. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..84dc0d1 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,67 @@ +# Roadmap + +Phases are ordered by dependency, not by date. Each phase should end with +something demonstrable in the car. + +## Phase 0 — Host bring-up · *in progress* + +Getting the Jetson to see the hardware at all. + +- [x] PCAN-USB working as SocketCAN `can1` (out-of-tree `pcan.ko`, netdev build) +- [x] SIM7600G-H-M.2 specified and documented +- [ ] SIM7600 brought up: LTE data path and GNSS via gpsd +- [ ] Kernel-update procedure for the out-of-tree PCAN module — it does not + survive kernel upgrades and will break silently +- [ ] Power and mounting in the car: clean shutdown on ignition off + +Tracked in [orin-nano-env-setup](gitea:yukart/orin-nano-env-setup). + +## Phase 1 — Capture + +Get real Z27AG traffic onto disk before designing anything around it. + +- [ ] `can-bridge` — listen-only, timestamped frames onto the bus +- [ ] `recorder` — persist raw sessions +- [ ] Capture drive sessions across varied conditions (idle, cold start, moving, + lights/indicators/windows actuated) with a written log of what was done when + +The manual event log matters more than it sounds: it is what makes the raw +capture decodable later. + +## Phase 2 — Decode + +- [ ] Correlate captures against the event log; identify recurring frame IDs +- [ ] Build the Z27AG DBC incrementally in `yukart-contracts` +- [ ] `decoder` — raw frames to named signals +- [ ] `obd-poller` — active OBD-II PIDs, single writer, rate-limited +- [ ] `gnss` — position/speed, useful as ground truth for validating decoded speed + +OBD-II gives standardised signals quickly and is worth doing early; it also +provides a cross-check for reverse-engineered ones. + +## Phase 3 — Bus and contracts + +- [ ] Stand up the broker; confirm MQTT holds up at real CAN rates (decision 4 + in [ARCHITECTURE.md](ARCHITECTURE.md) is still *proposed*) +- [ ] Freeze v1 of topic names and payload schemas +- [ ] `telemetry-gw` — external client access, including the serial bridge + +## Phase 4 — Displays + +Order chosen by feedback speed, not ambition. + +- [ ] One display end-to-end first, proving the contract — Android client is the + quickest to iterate on +- [ ] `yukart-hud` — directly-driven screen (Class A) +- [ ] `yukart-esp32-display` — RLCD/e-ink glanceable subset (Class B) + +## Phase 5 — Camera and inference · *separate task* + +Deliberately deferred. It is the reason the compute is a Jetson rather than a +Pi, but it shares nothing with the CAN work beyond the bus. + +## Deferred + +- Live off-board telemetry over LTE — hardware is present, but local logging + covers the current need +- Any CAN transmission beyond OBD-II diagnostics