High-Performance Active Suspension Control for Autonomous Vehicles (Tegra SoC)
This project implements a real-time active suspension control system designed for high-speed autonomous operation. It targets NVIDIA Tegra platforms (e.g., Jetson AGX Orin) running Linux/RTOS. The system maintains a level chassis by ingesting high-frequency IMU data and adjusting active dampers in real-time.
Compatibility Note: This project is optimized for Bazel 9.0+. An included
.bazelrcautomatically handles the legacyWORKSPACEsupport by disabling Bzlmod (build --noenable_bzlmod).
Key Performance constraints:
- Loop Rate: 1000 Hz (1ms period)
- Jitter Tolerance: < 50us
- Latency: Zero-copy architecture
- C++20: Utilizing modern features like
std::spanand concepts. - Lock-Free Concurrency: SPSC (Single Producer Single Consumer) Ring Buffer for thread-safe, non-blocking sensor ingestion.
- Eigen: High-performance linear algebra for Kalman Filtering and geometric transformations.
- Real-Time Optimization: POSIX thread pinning (
pthread_setaffinity_np) to isolate Sensor and Control loops on dedicated CPU cores. - Build System: Google Bazel.
graph TD
subgraph Hardware
IMU["IMU Sensor<br/>(Accel/Gyro)"]
Dampers["Active Dampers<br/>(FL, FR, RL, RR)"]
end
subgraph Tegra_SoC [NVIDIA Tegra SoC]
subgraph Core_2 [Core 2: Sensor Thread]
Ingest["Data Ingestion<br/>@ 1kHz"]
end
subgraph Shared_Memory [Shared Memory]
RingBuffer["Lock-Free SPSC<br/>Ring Buffer"]
end
subgraph Core_3 [Core 3: Control Thread]
Kalman["Kalman Filter<br/>(Pitch/Roll Est)"]
PID["PID Controller<br/>(Gravity Comp)"]
Mixer["Force Mixer"]
end
end
IMU -- "Raw Data" --> Ingest
Ingest -- "Push(IMUData)" --> RingBuffer
RingBuffer -- "Pop()" --> Kalman
Kalman -- "Theta, Phi" --> PID
PID -- "Counter-Force" --> Mixer
Mixer -- "Target Newtons" --> Dampers
style RingBuffer fill:#f9f,stroke:#333,stroke-width:2px
style Core_2 fill:#e1f5fe,stroke:#01579b
style Core_3 fill:#e1f5fe,stroke:#01579b
The system consists of two primary real-time threads:
-
Sensor Thread (Core 2):
- Ingests Accelerometer and Gyroscope data at 1kHz.
- Pushes data into a lock-free circular buffer.
-
Control Thread (Core 3):
- Polls the ring buffer for new measurements.
- Step 1 (State Estimation): Updates a Kalman Filter to estimate Pitch and Roll.
- Step 2 (Control): Calculates counter-forces using a PID loop.
- Step 3 (Actuation): Outputs force commands for FL, FR, RL, RR dampers.
To minimize latency and noise, we fuse the high-frequency Gyroscope data (low latency, drifting) with Accelerometer data (stable, noisy).
State Vector
Prediction (Time Update): $$ \begin{aligned} \hat{x}{k}^- &= \begin{bmatrix} 1 & -\Delta t \ 0 & 1 \end{bmatrix} \hat{x}{k-1} + \begin{bmatrix} \Delta t \ 0 \end{bmatrix} \omega_{gyro} \ P_{k}^- &= A P_{k-1} A^T + Q \end{aligned} $$
Correction (Measurement Update):
Using the angle derived from the accelerometer
The system calculates the required counter-torque to level the chassis using a PID controller for both Pitch and Roll axes.
The scalar outputs
- Bazel
- C++20 compatible compiler (GCC 10+ / Clang 11+)
- Linux Environment (for thread pinning APIs)
bazel build -c opt //:active_dynamics_mainNote: Root privileges may be required to set thread affinity.
sudo ./bazel-bin/active_dynamics_mainactive_dynamics::ActiveSuspensionController: Main interface.active_dynamics::LockFreeRingBuffer: Atomic SPSC buffer implementation.active_dynamics::KalmanFilter: 2D orientation estimator (Gyro/Accel fusion).active_dynamics::PIDController: Standard PID implementation with clamping.