ACU v3
Autonomous Control Unit — STM32F412Rx / Formula Student T26
Introduction
The ACU (Autonomous Control Unit) is the safety unit that guarantees the safety of the car during autonomous mode. It is built around an STM32F412Rx microcontroller and is responsible for monitoring the autonomous system, communicating with other ECUs, and triggering the solenoid-based brake system, pressure sensors, and watchdog timer in case of a fault.
The ACU communicates with three external ECUs — JETSON (0x061), VCU (0x600), and DV/AQT (0x770/0x502) — over a CAN bus at 1 Mbps. It reads pressure via ADC, extracts event logs from EEPROM via BLE (emergencies, hardfaults, etc.), controls the ASSI visual LEDs via a MOSFET and a GPIO pin, drives the EBS brake solenoid, and manages the hardware watchdog timer. If the system detects a fault — such as a timeout, sensor mismatch, or ASMS deactivation — the ACU triggers an emergency shutdown.
This document describes the system architecture, the state machines that drive the firmware, the main loop execution flow, and detailed flowcharts for each module.
Architecture Overview
The ACU monitors the autonomous system and intervenes when a fault is detected. Three external ECUs communicate over the CAN bus: the JETSON (mission computer), the VCU (vehicle control unit), and the DV/AQT (data logger / aquisition). Onboard, the ACU controls the brake solenoid via the EBS driver, reads pressure via ADC, extracts event logs from EEPROM via BLE (emergencies, hardfaults, etc.), controls the ASSI visual LEDs via a MOSFET and a GPIO pin, and manages the hardware watchdog to ensure the car enters a safe state in case of failure.
System architecture — The ACU connects to JETSON, VCU, and DV/AQT via CAN bus, and drives ADC, UART, solenoid driver, and timer peripherals directly on board.
State Machines
The firmware is driven by four state machines that control different aspects of the vehicle's behavior. The Vehicle state machine manages the high-level operating mode (IDLE, AS_ON, EMERGENCY). The Autonomous state machine handles the mission phases (initialisation, monitoring, finish). The Startup state machine runs a six-phase power-on sequence with timeout checks. The BLE state machine manages Bluetooth communication to extract logged events from EEPROM (emergencies, hardfaults, etc.) for diagnostics.
Start → IDLE (WDT enabled) → AS_ON (when ASMS=1 and IGN=0) → EMERGENCY (on fault) → IDLE (when ASMS=0 and rpm < 10). AS_ON handles autonomous mission state; EMERGENCY runs the fault handler (disable WDT, clear ignition, open solenoids).
OFF → Initial_Sequence (pressure, SDC, correlation checks) → Monitor_Sequence (mission monitoring) → Finish (when ASMS=0 and rpm < 10) → IDLE. Timeout or sensor faults trigger AS_Emergency → EMERGENCY.
Six-phase startup executed in sequence: Watchdog check (SDC=1, 500ms) → Pressure check (6–10 bar, 2000ms) → HV activation (IGN=ON, 5000ms) → Correlation (Hyd > 10×Pneu, 2000ms) → MB1 check (S1=1, S2=0, 2000ms) → MB2 check (S1=0, S2=1, 2000ms) → READY. Any timeout jumps to Error_state → EMERGENCY.
BLE_IDLE → ENTER_CMD (send command, 1s timeout) → CONNECT (wait for connection, 8s timeout) → READ_EEPROM_DATA → PROCESS_EVENT (parse event type, timestamp, counter) → EXIT_CMD → BRIDGE. Extracts emergency and hardfault events logged in EEPROM for diagnostics. Transitions to EXIT_CMD on error or disconnect.
Main Loop — app()
The main loop runs continuously from main.c's while(1). Each iteration executes a fixed sequence of operations in approximately 1 ms. The order is: read all peripheral inputs → update the active state machine → service the watchdog → update the LED indicator → control the ASSI → actuate peripherals → transmit CAN messages → pop from the CAN buffer → decode the received CAN payload.
Peripheral_aquisition → Handle_state → toggle_wdt → LED_indicator → ASSI_control → Peripheral_actuation → handle_can_tx → can_buffer_pop → dbc_decode. This sequence repeats every tick.
Module Flowcharts
Detailed flowcharts for key firmware modules. Each module handles a specific subsystem: the startup initialisation sequence, emergency handling, peripheral input acquisition, BLE event extraction, CAN buffer management, pressure filtering, and EEPROM data logging.
initial_sequence
SDC check (500ms timeout) → pressure 6–10 bar (2s timeout) → correlation Hyd > 10×Pneu (2s timeout) → OK.
Handle_Emergency
Disable the watchdog → clear ignition signal → open solenoids (release brake).
Peripheral_aquisition
Read ASMS (autonomous state) → read SDC (shutdown circuit) → read IGN (ignition) → read ASSI (visual LED state).
BLE Handler
Idle → wait for command → connect to device → read event data from EEPROM → parse event type and timestamp → EXIT_CMD → BRIDGE (pass data to external logger).
can_buffer_pop
If counter is 0, return NULL. Otherwise check direction: TX → call CAN_AddTxMessage, RX → memcpy to buffer.
EMA Filter
Exponential moving average filter. If uninitialised, output = input. Otherwise y = alpha · x + (1 − alpha) · y_prev.
EEPROM Logger
Read header → validate magic (0xDEADBEEF) → if invalid, initialise EEPROM; if valid, write data at current tail position → advance tail → if count reaches MAX, increment head → done.