Populate design, architecture and repo layout docs
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 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,37 @@
|
|||||||
# Project Yukart
|
# Project Yukart
|
||||||
|
|
||||||
Mostly passive probing and info extraction and GUI on a Z27AG Colt Ralliart.
|
Making a 2008 Mitsubishi Colt Ralliart (Z27AG) a bit smarter with modern technologies.
|
||||||
Overview available at [OVERVIEW.md](OVERVIEW.md).
|
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
|
- [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).
|
||||||
|
|||||||
@@ -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/<signal> decoded signals (rpm, speed, coolant, …), retained
|
||||||
|
yukart/gnss/fix position/speed/time, retained
|
||||||
|
yukart/system/<service> 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 |
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user