
Here’s a completed version with your missing parts filled in, keeping your tone and not overexplaining:
The goal was to design and build a small, autonomously controlled differential drive robot car from the ground up. This project served as an introduction to integrating microcontrollers with physical hardware and power systems.
The entire chassis was designed for 3D printing, allowing for rapid prototyping and custom internal mounting points.
The design followed a clamshell approach, with the goal of packaging all electronics, including the Raspberry Pi, motor controller, and wiring, securely within the chassis for a clean, professional look.
This was the initial sketch for the chassis, I wanted to make the robot as compact as possible, so the robot dimensions are on the smaller side


I measured the components that the robot would use and packaged it in the CAD, ensuring that the assembly process would go smoothly. During this stage, I also added screws to secure all the electronics.



Some smaller details, like the marble at the front of the robot and the top cover with custom slots to snap together with the bottom section.
The final chassis design, with center struts to elevate the battery, and small standoffs to mount the motor controller and Raspberry Pi.
The assembly process revealed several critical engineering challenges that required on-the-fly modifications.
GPIO Clearance: Forgot to account for the height of the GPIO pins and cables when designing the top cover, requiring chassis adjustments as the original design was too short


The old design compared to the new design, notice how the top section is raised higher to account for the extra height.
Voltage Management: Initially overlooked the necessity of managing 12V for motors vs 5V for the RPi, leading to a more complex power distribution system.
The full power distribution system can be seen here: the 11.1V LiPo feeds directly into the motor controller for the motors, while also stepping down through a buck converter to 5V to power the Raspberry Pi through a USB-C breakout. All grounds are tied together through a central node to maintain a common reference between the Pi and the motor driver.







To control the robot, I developed a Python-based drivetrain controller that handles motor PWM signals and implements basic trapezoidal velocity profiling for smooth movement.
drivetrain.pyimport RPi.GPIO as GPIO
import time
from typing import NamedTuple
class MotorPins(NamedTuple):
enable: int
in1: int
in2: int
class Drivetrain:
def __init__(self, leftPins: MotorPins, rightPins: MotorPins, ldir: int, rdir: int) -> None:
self.left: MotorPins = leftPins
self.right: MotorPins = rightPins
self.pwmA: GPIO.PWM = GPIO.PWM(self.left.enable, 1000)
self.pwmB: GPIO.PWM = GPIO.PWM(self.right.enable, 1000)
self.ldir: int = ldir
self.rdir: int = rdir
self.pwmA.start(0)
self.pwmB.start(0)
def spin(self, speeds: tuple[float, float]) -> None:
ldir = bool((1 if speeds[0] > 0 else 0) * self.ldir)
rdir = bool((1 if speeds[1] > 0 else 0) * self.rdir)
GPIO.output(self.left.in1, ldir)
GPIO.output(self.left.in2, ldir)
GPIO.output(self.right.in1, rdir)
GPIO.output(self.right.in2, rdir)
self.pwmA.ChangeDutyCycle(speeds[0])
self.pwmB.ChangeDutyCycle(speeds[1])
#drive train controller truncatedmain.pyfrom drivetrain import *
import time
ENA = 17
IN1 = 27
IN2 = 22
ENB = 23
IN3 = 24
IN4 = 25
BUTTON_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_PIN, GPIO.IN)
dt = Drivetrain(
MotorPins(ENA, IN1, IN2),
MotorPins(ENB,IN3,IN4),
1,
1
)
dtc = DrivetrainController(dt)
def run(channel):
dtc.profiled_drive(1000)
try:
GPIO.add_event_detect(
BUTTON_PIN,
GPIO.FALLING,
callback = run,
bouncetime = 200
)
while True:
time.sleep(0.01)
finally:
dt.spin((0,0))
GPIO.cleanup()