openpilot: A Software Engineer's Deep Dive into Open-Source ADAS and Robotics
Here's a friendly breakdown of how openpilot can be useful to you as a software engineer, along with implementation insights and code examples.
openpilot isn't just a product; it's a living, breathing robotics operating system you can study, modify, and contribute to.
The project is a polyglot system, meaning you'll get hands-on experience with several languages and technologies critical to high-performance, embedded, and safety-critical systems
Python (High-Level Logic)
You'll primarily see Python used for the main control loop processes (like controlsd, plannerd), sensor fusion logic, and the overall system orchestration. This is where the "brains" of the driving agent live.
C++ (Performance-Critical Components)
For real-time tasks like running the neural network models (in modeld) for perception and interfacing with cameras (camerad), C++ is used for maximum speed and efficiency.
C (Embedded and Safety)
The panda firmware, which acts as a safety-critical interface to the car's CAN bus, is written in C. This gives you exposure to low-level hardware communication and functional safety principles.
Cap'n Proto & Messaging
The entire system relies on a fast, inter-process communication (IPC) layer using Cap'n Proto (a data interchange format) for passing messages between services (like sensor data, control commands, and vehicle state).
You get to tackle core challenges in robotics and ADAS
Perception
Working with camera data, running neural network inference, and interpreting the world (lanes, lead vehicles).
Planning
Creating a safe and smooth trajectory for the vehicle based on the perceived environment.
Controls
Implementing robust control algorithms (like Model Predictive Control, or MPC) to execute the planned trajectory via the car's steering, braking, and acceleration systems.
openpilot provides a unique, structured way to understand and interact with the CAN bus, the car's internal network. You learn how to reverse engineer and implement interfaces for new car models, which is an invaluable skill in the automotive domain.
openpilot follows a client-server/microservice architecture, where different services (or "daemons") run concurrently, communicating via the high-speed messaging system.
| Service Name | Primary Function | Language |
modeld | Runs the neural network for lane and lead car prediction (Perception). | C++ |
plannerd | Determines the desired path and acceleration/braking profile (Planning). | Python |
controlsd | Calculates the low-level steering and pedal commands (Control). | Python |
boardd | Interfaces with the panda device to read/write CAN messages. | C++ |
ui | Manages the on-screen user interface. | C++ / Python |
The panda is a custom hardware device that connects the openpilot computer (like the comma 3X) to the car's CAN bus. Its firmware, written in C, is the safety guardian.
controlsd (Python) sends a desired command (e.g., steer by 5 Nm) to boardd (C++).
boardd relays this command to the panda via USB.
The panda firmware (C) translates the command into a car-specific CAN message and sends it to the car. Crucially, the C firmware enforces safety rules—it will only allow commands within safe limits, ensuring the driver can always take over.
Since openpilot is a massive project, a full runnable example is complex. Instead, let's look at illustrative snippets that demonstrate its core concepts
the use of Cap'n Proto for IPC and the logic in the control loop.
In a real openpilot project, you'd have a .capnp file to define the data structures for IPC. This ensures fast, strongly-typed communication.
# cereal/log.capnp (simplified)
@0x...; # Schema ID
struct CarControl {
# Desired control values calculated by controlsd
accel @0: Float32; # Target longitudinal acceleration (m/s^2)
steerTorque @1: Int16; # Target lateral steering torque (unitless)
enabled @2: Bool; # Is the system currently active?
}
This snippet shows how a service like controlsd uses openpilot's messaging library (which wraps Cap'n Proto) to publish its calculated command to the network.
# From selfdrive/controls/controlsd.py (conceptual snippet)
import cereal.messaging as messaging
# Set up the publisher for the 'sendCarControl' topic
pm = messaging.PubMaster(['sendCarControl'])
def control_loop(desired_accel, desired_torque, is_active):
# 1. Create a new Cap'n Proto message container
msg = messaging.new_message('carControl')
# 2. Access the CarControl struct within the message
car_control = msg.carControl
# 3. Populate the fields with the calculated values
car_control.accel = desired_accel
car_control.steerTorque = desired_torque
car_control.enabled = is_active
# 4. Publish the message so other services (like boardd) can read it
pm.send('carControl', msg)
# Example Usage:
# Run at 100 Hz
# (Imagine these are calculated via MPC and plannerd output)
current_accel = 0.5 # gently accelerating
current_torque = 50 # light steering to the left
control_loop(current_accel, current_torque, True)
print(f"Published CarControl: Accel={current_accel}, Torque={current_torque}")
This is a conceptual C snippet, representing the low-level safety check that happens inside the panda firmware before a CAN message is physically sent to the car.
// From selfdrive/board/safety/safety_honda.h (conceptual snippet)
// Max allowed steering torque (a safety limit)
#define HONDA_MAX_STEER_TORQUE 3840
// Checks a received command before allowing it on the CAN bus
bool honda_safety_check(int desired_steer_torque, int car_speed_kph) {
// Rule 1: Always enforce maximum torque limit
if (abs(desired_steer_torque) > HONDA_MAX_STEER_TORQUE) {
// Command is unsafe, reject it!
return false;
}
// Rule 2: Do not allow steering at very low speeds (car must be moving)
if (car_speed_kph < 10 && desired_steer_torque != 0) {
// Disengage or return false, depending on the specific safety model
return false;
}
// All checks passed
return true;
}
This C code is a critical safety barrier, ensuring that even if the high-level Python code has a bug, the physical actuators of the car are protected by hard-coded, verifiable limits.