Skip to content

ECU Design

Mason Jones edited this page Aug 22, 2026 · 1 revision

The ECU code is split into a couple files:

Entry points

Entry points are the root file that gets compiled per microcontroller. We currently have two:

  • Electronic Control Unit (ECU): This is responsible for reading throttle and brake values, and deciding how much torque to command the motor with. The entry point is at src/ecu.cpp. Note that the entry point handles all IO, while the Ecu class is the one that actually handles the logic. This is intentional, so switching microcontrollers in the future isn't hard, and so it's easy to test.
  • Data Collector Forward (DCF): This reads the throttle, brake sensor, and start switch values, and sends them to the ECU along the CAN bus. It's such simple logic that we keep it contained in a single file.

ECU Logic

Currently at lib/ecu/ecu_logic.cpp and lib/ecu/ecu_logic.hpp. This is the logic for the ECU. It's written intentionally simple, and heavily documented, since this is where all the decisions around safety and car control happen. For now, I've decided against using a RTOS, since then we'd have to deal with the headache that is scheduling, priority inversion, hitting deadlines, etc. Polling based is stupid simple, so I'd rather that the polling be stupid simple so we can handle the quite complex rules around safety. Perhaps in the future it'll be relatively simpler to use an RTOS, at which point it makes sense to switch over. For now though, poll based is easier to follow.

Shared code

All shared code is in lib/shared/*. This has a couple things:

  • lib/shared/assert.hpp - This is our safety assert logic. This allows doing something like SAFETY_ASSERT(somethingThatShouldAlwaysBeTrue, AssertCode::BadMessage). If that thing becomes false, the ECU will safely shut down, and start sending out debugging info over serial and CAN. This info will include the AssertCode, so we can quickly see what was violated.
  • lib/shared/can_serde.hpp - This has our custom CAN message serialization and deserialization (converting CAN messages from raw bytes to structured data and vice versa). This has functions like create_motor_control_command and create_motor_control_command, that allow us to convert from and to CAN.
  • lib/shared/util.hpp - A grab bag of random utilities, such as a PID controller, integer mapping, Timer, and Trigger (used for timing).

Documentation

Clone this wiki locally