Skip to content

qb-creates/rc-car

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RC Car Project

This project is a custom-built remote-controlled (RC) car, designed from the ground up with custom electronics, PCB design, and embedded firmware for both the car and its remote.

Completed RC Car Side Profile

Table of Contents

  1. Software Used
  2. Drive and Steering Control Circuit
  3. Remote Control Circuit
  4. Pin Mapping
  5. STL Viewer

1. Software Used

2. Drive and Steering Control Circuit

This board is the car's real-time control core. It receives wireless throttle/steering commands from the handheld transmitter, converts steering targets into stable hardware PWM for the MG90S servo, and drives the rear motor through a protected H-bridge path with direction dead-time and command deadbands for smoother behavior. The result is a compact control system designed for responsive handling, predictable failsafe behavior, and reliable power delivery under changing load.

Car Side Profile Car Top Profile
Car Angled Profile Car Side Profile Complete

RF Receiver

The car uses an nRF24L01+ module with the RF24 library over SPI to receive drive and steering commands from the handheld controller. In firmware, the radio object is created as RF24 radio(CE_PIN, CSN_PIN) with CE on PB0 and CSN on PB1.

The RF stack is configured in configureRFRadio() with:

  • radio.begin() hardware check (halts if radio is not detected)
  • radio.setPALevel(RF24_PA_LOW) to reduce TX power/current
  • radio.enableDynamicPayloads()
  • radio.setAutoAck(false)
  • Pipe/address setup using "jag-1" and "jag-2"
  • radio.startListening() so this node stays in RX mode

An important part of the RF path is Timer0 timing configuration. Because this firmware includes #include <RF24.h>, the RF24 stack depends on millis()/micros() timing for operations such as CE pulse timing, transmit timing windows, retry timing, and transaction spacing.

The RF24 library itself does not directly configure Timer0. Instead, those timing primitives are provided by the Arduino core (millis()/micros()), and the project sets Timer0 for a 50 us timing base:

TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << WGM02) | (1 << CS01); // prescaler = 8
OCR0A = 49;

At 8 MHz CPU clock with prescaler 8:

  • Timer clock = 8 MHz / 8 = 1 MHz
  • Timer tick = 1 us
  • Period = (49 + 1) x 1 us = 50 us

So the Timer0 event period is 50 us (20 kHz). Timer0 is intentionally kept running at this rate so the millis()/micros() time base used by RF24 remains available and stable.

The receiver expects a MotorControlPayload packet with two fields:

  • int16_t ocrMotor for signed throttle/drive command
  • uint16_t ocrSteering for servo pulse width command in microseconds

This payload is 4 bytes total (2 + 2), and after reception the car firmware applies it directly:

  • OCR1B = payload.ocrSteering for steering position
  • payload.ocrMotor drives H-bridge direction/speed logic with a deadband of -15 to +15

Reliability/safety behavior tied to RF reception:

  • On first valid packet, watchdog is enabled (WDTO_2S)
  • Each additional valid packet resets the watchdog
  • If RF packets stop arriving, watchdog timeout forces a reset/failsafe

Steering Servo Control

Steering is driven by an MG90S servo using Timer1 hardware PWM on OC1B (PD4). The car firmware configures Timer1 in Fast PWM mode 14 with ICR1 as TOP, prescaler = 8, and ICR1 = 20000. With an 8 MHz clock, that gives a 1 us timer tick and about a 50 Hz control period (20 ms), which matches standard hobby servo timing.

The commanded steering pulse is written directly to OCR1B. Steering values are transmitted as absolute pulse widths in microseconds. Instead of assuming a fixed joystick center, the controller now supports calibration by entering measured joystick potentiometer voltages for minimum, maximum, and center. Those measured values are used to map ADC input to the steering pulse range and produce a more accurate neutral point (typically near 1900 us). On the car side, OCR1B is updated from the payload each loop:

  • Neutral: calibrated from measured joystick center voltage (typically ~1900 us)
  • Left/Right command range: ~1520 us to ~2280 us
  • PWM period: ~20 ms (50 Hz)
  • Steering deadzone: +/-90 us around calibrated center snaps to neutral to reduce twitch

This keeps steering response deterministic because the servo waveform is generated in hardware (Timer1), not by software toggling.

Drive Motor Control

The drive motor uses a discrete H-bridge driven by a hybrid approach: latch lines select direction, while PWM is generated in software via Timer2 interrupts.

H-bridge signal assignment:

  • PC0: Forward latch
  • PC1: Forward PWM
  • PC2: Reverse latch
  • PC3: Reverse PWM

Timer2 is configured for Fast PWM with OCR2A as TOP. With OCR2A = 199 and prescaler = 8 at 8 MHz, PWM frequency is about 5 kHz. Instead of using OC2A/OC2B output pins directly, compare interrupts are used:

  • TIMER2_COMPA_vect sets the active direction PWM pin high (PC1 for forward or PC3 for reverse)
  • TIMER2_COMPB_vect clears that same active pin low

This effectively creates direction-dependent PWM on one of two output pins while the opposite side remains off.

Direction changes are intentionally staged to protect the bridge and drivetrain:

  1. Disable Timer2 PWM (stop switching)
  2. Force all H-bridge outputs low
  3. Wait 150 ms dead-time
  4. Assert new direction latch (PC0 forward or PC2 reverse)
  5. Re-enable Timer2 PWM

That delay prevents hard instant reversals and helps ensure MOSFETs on the same side of the H-bridge are not on at the same time during direction transitions, reducing shoot-through/braking stress.

Additional control logic from the car firmware:

  • Speed deadband: commands between -15 and +15 stop the motor to avoid joystick/noise creep
  • Steering deadzone: commands within +/-90 us of the calibrated center are snapped to neutral
  • Direction is only changed when needed (or from stopped state)
  • A watchdog is enabled after first RF packet and reset on each valid packet; if RF traffic is lost, the MCU resets after the watchdog timeout (2 s)

Why RF reception is harder with this PWM approach

Using Timer2 compare interrupts for every PWM cycle means the MCU is servicing frequent interrupts continuously while also polling and reading nRF24 payloads over SPI. That interrupt load can steal time from RF handling and make robust payload reception harder than a pure hardware-PWM motor path.

In practice, the current tuning (about 5 kHz PWM, deadband around zero, staged direction changes) was a workable sweet spot between motor smoothness and reliable radio updates. A strictly hardware PWM implementation for both drive channels would reduce ISR overhead and leave more CPU time for RF processing.

Power Consumption

This power system was sized around worst-case drive events (motor stall plus active steering), not just average cruising current.

Estimated load envelope:

  • 9V drive motor stall current at 7.2V: ~600 mA
  • MG90S steering servo working current: ~600-700 mA
  • Control circuitry (MCU, RF, logic, support electronics): ~20 mA

Worst-case instantaneous estimate:

  • Total peak demand: $0.60 + 0.70 + 0.02 \approx 1.32,A$

Battery capability:

  • 2S 200 mAh pack, 20C rating
  • Maximum continuous supply: $0.2,Ah \times 20 = 4,A$

Power-stage device headroom:

  • IRLML6244 continuous drain current: 6.3 A (comfortably above motor stall current)
  • IRLML2246 continuous source current: -1.3 A (above the ~600 mA motor stall requirement in this bridge path)

Conclusion: the battery and MOSFET current limits provide practical headroom over the expected peak load, so the system can supply drive, steering, and control electronics simultaneously under normal and transient operation.

Charging Notes

For safe charging practice on the car side, do not charge the car while it is powered on. Turn the car off first, then connect the charger.


Parts List

Schematics

Drive and Steering Circuit

PCB Images

Car Front PCB Car Back PCB
Car 3D PCB Front Car 3D PCB Back

3. Remote Control Circuit

The handheld controller samples two joystick axes, converts them into throttle and steering commands, and transmits those values over 2.4 GHz to the car at a steady update rate. The design goal is low-latency control with stable center behavior so the car tracks driver input without twitching or drift.

Radio Controller Front Radio Controller Back
Radio Controller Mounted Radio Controller Complete

RF Transmitter

The remote uses an nRF24L01+ module with RF24 over SPI to transmit MotorControlPayload packets containing ocrMotor and ocrSteering. During initialization, firmware performs a radio hardware check, configures dynamic payload mode, and sets TX/RX addresses for the paired node. Timer0 is also configured with a 50 us base so the millis()/micros() timing used by RF24 remains stable while packets are sent continuously.

Control Input Processing

Joystick values are read through the ADC and mapped into the exact command domains expected by the vehicle firmware. This preprocessing keeps control semantics consistent across the RF link: signed throttle around zero and steering in absolute pulse-width units centered at a calibrated neutral.

Throttle Input (Left Analog Stick)

Throttle is sampled on ADC channel 0, inverted to match intuitive stick direction, scaled into a signed drive command, and centered around zero. Positive values represent forward demand, negative values represent reverse demand, and near-zero commands cooperate with the car-side deadband to prevent idle creep.

Steering Input (Right Analog Stick)

Steering is sampled on ADC channel 1 and converted using a calibration profile where measured joystick potentiometer minimum, maximum, and center voltages are entered in firmware. The mapping uses those measured endpoints and center value to generate steering pulses, then clamps to the valid steering window before transmission. This makes neutral alignment and left/right travel more accurate than a fixed center assumption. A center deadzone is applied so small stick jitter and ADC noise snap back to neutral, reducing servo chatter and improving straight-line stability.

To measure and enter steering calibration voltages:

  1. Power the controller on.
  2. Connect the multimeter to ground and to the X-axis test point by the left controller.
  3. Measure the voltage with the analog stick in its center position (center voltage).
  4. Measure the voltage with the stick moved all the way to the right (minimum voltage for this mapping).
  5. Measure the voltage with the stick moved all the way to the left (maximum voltage for this mapping).

Charging Notes

The remote has a built-in LiPo charging circuit. When a charger is connected, the controller may automatically power on while charging. You can place the power switch in the OFF position before charging if you prefer it to stay off.


Parts List

Schematics

Controller Circuit

PCB Images

RC Car Remote Front PCB RC Car Remote Back PCB
RC Car Remote 3D PCB Front RC Car Remote 3D PCB Back

4. Pin Mapping

ATmega164A/P pin information is from the Microchip datasheet: https://ww1.microchip.com/downloads/en/devicedoc/atmel-8272-8-bit-avr-microcontroller-atmega164a_pa-324a_pa-644a_pa-1284_p_datasheet.pdf

Car Controller (ATmega164A)

Signal MCU Pin Notes
nRF24 CE PB0 Defined as CE_PIN 0 in car RF firmware
nRF24 CSN PB1 Defined as CSN_PIN 1 in car RF firmware
nRF24 SPI SCK PB7 Hardware SPI clock
nRF24 SPI MISO PB6 Hardware SPI MISO
nRF24 SPI MOSI PB5 Hardware SPI MOSI
nRF24 SPI SS PB4 Hardware SPI SS
Steering PWM (OC1B) PD4 Servo output (Timer1 OC1B)
Motor Forward Latch PC0 H-bridge control
Motor Forward PWM PC1 H-bridge control
Motor Reverse Latch PC2 H-bridge control
Motor Reverse PWM PC3 H-bridge control
Status LED PD5 Set during startup/status

Remote Controller (ATmega164A)

Signal MCU Pin Notes
nRF24 CE PB0 Defined as CE_PIN 0 in remote RF firmware
nRF24 CSN PB1 Defined as CSN_PIN 1 in remote RF firmware
nRF24 SPI SCK PB7 Hardware SPI clock
nRF24 SPI MISO PB6 Hardware SPI MISO
nRF24 SPI MOSI PB5 Hardware SPI MOSI
nRF24 SPI SS PB4 Hardware SPI SS
Throttle Joystick (Y) ADC PA0 / ADC0 Read with readADC(0)
Steering Joystick (X) ADC PA1 / ADC1 Read with readADC(1)

5. STL Viewer

Car Mechanical Mounts STL

Controller Housing STL


License

See LICENSE for details.

About

Custom DIY RC car featuring in-house PCB design, 3D-printed components, and dual ATmega164A firmware for wireless drive and steering control.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors