Real-Time Embedded Vehicle

An embedded car powered by a custom-built real-time operating system.

Embedded · 4 months · CMU

STM32 Cortex-M4RMS scheduler<10% average speed error
Role
Embedded systems engineer
Team
CMU embedded systems course project
My contribution
RTOS kernel, boot code, device drivers, carrier PCB, PID control, and system integration
In this build

Overview

I created a real-time embedded vehicle from the bare metal up, combining custom hardware design, low-level firmware, a custom operating system, and closed-loop motor control. A preemptive RTOS schedules the PID loop, UART telemetry, and LCD updates against their selected execution periods.

The system is built around an STM32 Cortex-M4 microcontroller on a custom two-layer PCB that routes power and signals to L298 H-bridge motor drivers, LM1084 voltage regulators, quadrature encoders, servos, and an I2C LCD.

PCB Design

I designed the board in Autodesk Fusion to interface the STM32 Nucleo with the vehicle's peripherals. The PCB handles 5V and 3.3V power distribution, motor-control routing, encoder inputs, and user I/O.

Carrier board: power distribution, motor drivers, encoders, and LCD connections.

Firmware

I wrote the system bootloader in ARMv7-M assembly to initialize the exception vector table and stack pointers, then built bare-metal C drivers using MMIO for PWM, ADC, I2C, and interrupt-driven UART.

Preemptive multitasking uses the ARM Cortex-M exception model with separate process and kernel stacks for each thread. Thread code runs on PSP; exception handlers use MSP. SysTick tracks thread budgets and pends PendSV. Its assembly wrapper saves PSP and the remaining registers, while the C handler records that kernel frame in the thread control block (TCB) and selects the next runnable thread. The same wrapper then restores the selected context before exception return.

Context switch flow from SysTick through the PendSV handler Thread A runs on the user stack until SysTick pends PendSV. The PendSV wrapper saves Thread A's registers on its kernel stack. Its C handler records the frame in the TCB and calls the scheduler. The scheduler selects Thread B, whose saved frame returns to the same wrapper for restoration before exception return to Thread B's process stack. USER MODE HANDLER MODE Thread A running on PSP Thread B resumes on PSP PendSV HANDLER 1. Save PSP, R4–R11 + LR 2. Record kernel frame in TCB 3. Select next runnable thread 4. Restore registers + PSP SysTick tick TCB list state + priority Context switch flow from SysTick through the PendSV handler Thread A runs on the user stack until SysTick pends PendSV. The PendSV wrapper saves Thread A's registers on its kernel stack. Its C handler records the frame in the TCB and calls the scheduler. The scheduler selects Thread B, whose saved frame returns to the same wrapper for restoration before exception return to Thread B's process stack. USER MODE Thread A running on PSP HANDLER MODE SysTick tick PendSV HANDLER 1. Save PSP, R4–R11 + LR 2. Record kernel frame in TCB 3. Select next runnable thread 4. Restore registers + PSP TCB list state + priority USER MODE Thread B resumes on PSP
SysTick requests PendSV. Selection and restoration happen within that one handler before Thread B resumes.

Task priorities are assigned by a rate-monotonic scheduler validated against the utilization bound, with an SVC path bridging user and kernel space, newlib support for printf and malloc, and priority-inheritance mutexes (HLP/IPCP) to bound priority inversion.

Motor Control

The vehicle decodes wheel position through EXTI quadrature encoders and drives the motors through hardware-timer PWM. I tuned a closed-loop PID controller to keep average wheel speed within 10% of its target, measured from encoder telemetry visualized over UART. UART and I2C LCD updates ran as concurrent real-time tasks under the same scheduler.

Results

The selected PID, UART, and LCD parameters produce 71.25% modeled utilization, below the 77.98% rate-monotonic utilization bound for three tasks. The simulator below reconstructs that task set so you can explore the analytical schedulability margin.

Wheel-speed error
<10% average error from the target, measured through encoder telemetry over UART
Task utilization
71.25% of CPU time across PID, UART, and LCD threads
UB schedulability bound
77.98% for 3 tasks, comfortably met
Scheduling result
Analytically schedulable under the selected RMS task parameters
Vehicle carrier board PCB layout
Vehicle carrier board PCB layoutAdjust the schedulerPointerClick the −/+ controls to change task timing.TouchTap the −/+ controls to change task timing.KeyboardTab to each control and press Enter or Space.

Keep exploring.

Back to the workshop
Trash collection robot chassis with robotic arm and electronics

Trash Collection Robot

Autonomous bottle-collection robot with Raspberry Pi vision, Arduino motor control, UART command protocol, custom power delivery, and arm actuation.

Explore the project