An open-source hardware and software platform for vehicle embedded systems, built with Elixir, Nerves, Phoenix, and Flutter.
OVCS tackles vendor parts lock-in in transportation by redesigning the embedded systems in a vehicle. It allows parts from different brands to seamlessly communicate and creates an abstraction layer on top of them that can be standardized, extended, and monitored.
OVCS was started in early 2024 by Marc Lainez, Loïc Vigneron, and Thibault Poncelet at Spin42. The project was born from a desire to make vehicle embedded computing accessible using simple, off-the-shelf components and high-level programming languages.
The first full-size platform, OVCS1, is a 2007 Volkswagen Polo converted to an electric vehicle using a Nissan Leaf AZE0 drivetrain, a Bosch iBooster Gen2 brake system, an Orion BMS2 battery management system, and custom Arduino-based controllers -- all orchestrated by Elixir running on Raspberry Pis via the Nerves framework.
A smaller-scale platform, OVCS Mini, replicates the same software and hardware stack on a Traxxas 4WD RC car, enabling safe development and testing of remote control and ROS2 features before deploying to the full-size vehicle.
- CAN bus abstraction -- The Cantastic library provides a YAML-driven CAN bus communication layer that handles frame encoding/decoding, signal extraction, and multi-bus routing via Linux SocketCAN.
- Multi-vendor component integration -- Seamlessly makes parts from Nissan, Volkswagen, Bosch, Orion, and custom OVCS components work together by isolating and bridging their CAN buses.
- Vehicle Management System (VMS) -- The central brain of the vehicle, running on a Raspberry Pi 4, that translates and orchestrates all vehicle components.
- Infotainment system -- An in-car touchscreen UI built with Flutter running on a Raspberry Pi 5, providing gear selection, vehicle status, and diagnostics.
- Remote control -- Drive the vehicle using a MAVLink-compatible RC transmitter via a dedicated bridge on a Raspberry Pi 3A.
- ROS2 integration -- A bridge for Robot Operating System 2 communication, enabling autonomous driving research with IMU data publishing and joystick interpretation.
- Generic controllers -- Arduino R4 Minima-based controllers that interface with specific vehicle components via CAN bus, receiving their configuration from the VMS through an over-the-air adoption process.
- OBD2 diagnostics -- A diagnostic mode for reading standard OBD2 data from any vehicle.
- Debug dashboard -- A real-time Vue.js web dashboard for monitoring vehicle metrics, CAN bus traffic, and component status during development.
OVCS is built around two ideas:
- Bus isolation. Components from different manufacturers use overlapping CAN IDs, so each manufacturer's bus is kept separate. The VMS is the only node that touches all of them and bridges traffic where needed.
- Pluggable vehicle packages. The cores (
vms_core,infotainment_core) and firmware shells contain zero vehicle-specific code. Each vehicle is a standalone Mix package undervehicles/<name>/that bundles its supervision tree, CAN topology, and Nerves targets. Selecting a vehicle at boot is one env var (VEHICLE).
flowchart LR
classDef firmware fill:#dde5ff,stroke:#3344aa,color:#111
classDef arduino fill:#fff1d6,stroke:#a07000,color:#111
classDef bus fill:#f5f5f5,stroke:#666,color:#333,stroke-dasharray:3 3
classDef external fill:#e7f6ec,stroke:#2a7a3a,color:#111
subgraph CLUSTER["Erlang-distribution mesh (OvcsBus)"]
direction TB
VMS["VMS<br/>vms_firmware"]:::firmware
INFO["Infotainment<br/>infotainment_firmware<br/>(optional)"]:::firmware
BRIDGES["Bridges (0..N)<br/>bridge_firmware"]:::firmware
end
CTRL["Generic controllers (0..N)<br/>Arduino R4 Minima"]:::arduino
OVCS_BUS(["OVCS internal CAN"]):::bus
VEH_BUSES(["Vehicle CAN buses (0..N)<br/>(isolated, per manufacturer)"]):::bus
MFG["Manufacturer components<br/>(drivetrain, BMS, brakes, body, …)"]
HEAD["In-car head-unit UI"]:::external
DEBUG["Developer dashboard"]:::external
OUTSIDE["External worlds<br/>(RC link, ROS 2 graph, …)"]:::external
VMS --- OVCS_BUS
INFO --- OVCS_BUS
BRIDGES --- OVCS_BUS
OVCS_BUS --- CTRL
VMS --- VEH_BUSES --- MFG
INFO -. HTTP + WS .- HEAD
VMS -. HTTP + WS .- DEBUG
BRIDGES -. per-bridge transport .- OUTSIDE
- VMS is the only firmware that touches the vehicle CAN buses, so all message-ID isolation between manufacturers happens there.
- Infotainment and bridges are optional per vehicle — a vehicle package declares which it ships through its
OvcsVehiclecallbacks. - Generic controllers are reconfigurable Arduino I/O boards. They get their pinout from the VMS at runtime via an adoption frame, so the same firmware runs on every board.
- Every BEAM in a running vehicle (VMS + optional infotainment + each bridge firmware) joins one Erlang-distribution mesh via
OvcsBus.Cluster.OvcsBus.broadcast/2fans messages out cluster-wide with no broker. Same transport in./ovcs run <vehicle>on a developer laptop and on the deployed vehicle LAN.
See Hardware Architecture for a concrete instance (OVCS1: five CAN buses, three Arduino controllers, Leaf / Polo / Bosch / Orion components) and Vehicle Parameterisation for the boot flow.
This is a monorepo containing multiple independent applications:
ovcs/
+-- vms/ Vehicle Management System
| +-- core/ Elixir library - VMS platform + component drivers (no vehicle code)
| +-- api/ Phoenix JSON API + WebSocket server for the debug dashboard
| +-- dashboard/ Vue.js real-time debug dashboard (Vite + ECharts + TailwindCSS)
| +-- firmware/ Nerves firmware targeting Raspberry Pi 4
|
+-- infotainment/ Infotainment System
| +-- core/ Elixir library - infotainment platform (no vehicle code)
| +-- api/ Phoenix JSON API + WebSocket server for the Flutter dashboard
| +-- dashboard/ Flutter/Dart in-car touchscreen application
| +-- firmware/ Nerves firmware targeting Raspberry Pi 5
|
+-- vehicles/ Vehicle Packages (pluggable)
| +-- ovcs1/ Full-size Polo EV conversion
| +-- ovcs_mini/ Traxxas RC car platform
| +-- obd2/ OBD-II diagnostic mode
| Each bundles its VMS + infotainment composers and CAN topology.
|
+-- bridges/ Communication Bridges
| +-- firmware/ Shared Nerves image hosting one or more bridges per build
| +-- radio_control_bridge/ MAVLink RC transmitter bridge library
| +-- ros_bridge/ Native rmw_zenoh ROS2 bridge library
|
+-- controllers/ Arduino Controllers
| +-- generic_controller/ PlatformIO C++ project for Arduino R4 Minima
|
+-- libraries/ Shared Libraries
| +-- cantastic/ CAN bus communication library (Elixir, SocketCAN)
| +-- ovcs_can/ Shared CAN component frame/signal YAMLs
| +-- ovcs_vehicle/ OvcsVehicle top-level behaviour + scaffold
| +-- ovcs_bus/ Cluster-wide pub/sub over Erlang distribution
| +-- ovcs_bridge/ Behaviour + supervisor for bridge libraries
| +-- ovcs_drivers/ Hardware chip drivers, grouped by kind (Elixir; currently BNO085 IMU)
| +-- ovcs_control/ PID controller + input filters
| +-- express_lrs/ MAVLink v2 telemetry reader (ExpressLRS)
| +-- msp_osd/ MSP / DisplayPort OSD stack for MSP-compatible VTXs
|
+-- compose/ Container stacks: compute/ (the vehicle's compute node, balenaOS) and local/ (operator + simulation)
+-- cli/ Rust source for the `ovcs` CLI (binary at cli/ovcs)
+-- scripts/ Utility scripts (setup_can.sh, bind_remote_can.rb, ...)
+-- candumps/ CAN bus capture logs for offline testing and replay
+-- docs/ Project documentation
+-- ovcs Symlink to cli/ovcs (built via `mise run cli`; gitignored)
| Vehicle | Description | Status |
|---|---|---|
| OVCS1 | 2007 VW Polo converted to EV with Nissan Leaf AZE0 motor, Bosch iBooster Gen2, Orion BMS2, VW Polo 9N original systems | Drivable (manual + remote) |
| OVCS Mini | Traxxas 4WD RC car with the same OVCS software/hardware stack for development and testing | Operational |
| OBD2 | Diagnostic mode for reading OBD2 data from any vehicle via a standard OBD plug | Operational |
| Layer | Technology |
|---|---|
| Vehicle control logic | Elixir |
| Embedded firmware | Nerves (Linux + Erlang/OTP on Raspberry Pi) |
| Web APIs | Phoenix Framework 1.7 |
| In-car UI | Flutter / Dart |
| Debug dashboard | Vue.js 3 + Vite + ECharts |
| CAN bus communication | Cantastic (Elixir + Linux SocketCAN) |
| Controllers | C++ / PlatformIO on Arduino R4 Minima |
| Database | SQLite via Ecto |
| Real-time communication | Phoenix Channels (WebSocket) |
| ROS2 integration | Native Zenoh via zenohex (rmw_zenoh wire format), Foxglove Studio |
See the Getting Started guide for full prerequisites and setup (Linux / VM, mise, system packages, fwup, bootstrap, verification).
Once the setup is done:
# Provision vcan interfaces and spawn one BEAM per firmware
./ovcs run ovcs1 # VMS + infotainment + bridges
# Attach a split-pane log + IEx TUI (in another terminal)
./ovcs attach ovcs1The VMS API at http://localhost:4000/ already serves a prebuilt copy
of the dashboard (from vms/api/priv/static/), so just open that URL.
Only run the Vite dev server if you're actively editing the dashboard
Vue source and want hot reload:
cd vms/dashboard && npm install && npm run devovcs run spawns one BEAM per declared firmware: VMS API on :4000,
infotainment API on :4001 (when the vehicle has an infotainment side),
and one BEAM per entry in bridge_firmwares/0. They join a single
Erlang-distribution cluster — the same topology as deployed Nerves
devices on the vehicle LAN. See Applications
for the per-side breakdown if you prefer running pieces separately.
Build, burn, or OTA-upload firmware via the ovcs CLI:
./ovcs vehicles # list discovered vehicles and their Nerves targets
./ovcs build ovcs1 vms # also: infotainment | <bridge-firmware-id>
./ovcs burn ovcs1 vms
./ovcs upload ovcs1 vms [--host HOST] [--file FILE]| Event | Date | Links |
|---|---|---|
| ElixirConf EU 2024 | April 2024 | Video: Retrofitting a Car and Running it with Elixir -- Slides |
| Makilab | November 2024 | Slides |
| FOSDEM 2025 | February 2025 | Video: Converting an '07 car to an RC EV using open source software -- Video: Building a robot from a Traxxas RC car -- Slides |
| OVCS Teaser | 2025 | Video: Open Vehicle Control System teaser |
Subscribe to the Spin42 Engineering YouTube channel for video updates, demos, and build logs.
Full documentation is in the docs/ directory:
- Getting Started — environment setup and installation
- Simulation — drive a simulated OVCS Mini in Gazebo, no hardware needed
- Applications — what each app and library is, plus local-dev
- Vehicle Parameterisation — how
VEHICLEselects a composer and what each firmware boots - Hardware Architecture — physical topology, CAN networks, controllers
- Running on Hardware — firmware build/burn/upload + runtime debugging via the
ovcsCLI - Testing CAN Messages — simulating CAN traffic
- Testing Generic Controllers — adopting + verifying generic Arduino controllers
OVCS is provided as-is without any warranty. Use it at your own risk. It is not road-certified and therefore does not meet all required criteria to be so. We decline any responsibility for any incident resulting from the usage of OVCS. OVCS is a hobby research project.
MIT License -- Copyright (c) 2026 Spin42 SRL