Introduction: RC Arduino Car - Speed Racers

The world of electronics and programming can be a fascinating place, especially when it comes to building your own projects. One such project that can be both exciting and educational is the creation of an Arduino RC transmitter, RC car, and race timer that can be combined to create a thrilling time attack racing game--Speed Racers.

To begin this project, we will first focus on building the RC car. The car will consist of a 3D printed chassis that will hold most of the components for the car. The chassis will provide a sturdy base for the motors, servos, and Arduino board, which will control the movements of the car. A body will also be 3D printed to cover the electronics, which will also feature little windows to add a touch of style. The car will have both motors to accelerate the car and servos to control the front wheels, which will be managed using an Arduino and a DC motor controller.

The next component to be built is the RC transmitter. The transmitter will use a NRF24L01 Transceiver Module to communicate with the vehicle. To keep everything tidy and compact, while also allowing us to create a smaller, more comfortable controller, we'll make the controller box out of acrylic. This also adds some durability This will require some design work and cutting but it will be a great opportunity to make the car and joystick your style.

Once the RC car and transmitter are completed, we can move on to building the race timer. The timer will be based around the Arduino Nano, LCD screen, and Gikfun IR LED emitter and receiver. The timer will start as soon as the race gate switch is triggered, and it will stop as soon as the car crosses the finish line. From there, we will calculate the elapsed time to determine the winner. We will also build a casing for the gate, allowing the car to pass through it smoothly.

Building each component of this project can be a challenging but ultimately fulfilling experience. The process of designing and 3D printing the chassis and body of the car, as well as designing and assembling the transmitter, can teach valuable skills such as 3D modeling and soldering. The race timer can teach skills such as programming and working with electronic components. Integrating all of the components into a cohesive system will require careful planning and attention to detail.

Once the project is complete, we can combine all of the components into a time attack racing game.

In conclusion, this project can be an exciting and rewarding way to learn about programming, electronics, and 3D printing. It provides ample opportunities to develop new skills, explore new ideas, and have fun in the process. Whether you are a beginner or an experienced hobbyist, this project is a great way to challenge yourself and create something truly unique.

Code links:

car: https://gist.github.com/emhe3766/0ff75577614b6173cb56227205cdecd5

joystick: https://gist.github.com/emhe3766/b6030957cec9bd9f44902b9c1b3d2ff6  

time gate: https://gist.github.com/alci1167/f2712e60a9b2e4270bb787a5bc79b51a 

Supplies

  • Battery holder for 4
  • Batteries x4
  • Arduino Uno x3
  • Joystick/Remote
  • Acrylic sheet (5"x6")
  • 4 wheels
  • 4 motors
  • nRF24L01 Module x2
  • Laser sensor
  • LCD 1602 Module
  • Wires
  • Capacitors x2
  • Cardboard
  • Optional: car shell

Step 1: Cut Acrylic Sheet

Cut the acrylic sheet to be 5"x6".

Step 2: 3D Print Wheels and Car Shell

Model and 3D print your wheels and if you want, your car shell. You can also buy these.

Step 3: Acrylic Sheet Attachments

Use acrylic safe glue to attach motors onto the acrylic sheet. Arrange it how a car would be. We attached the motor shield to the uno and then glued the uno motor shield piece to the acrylic sheet. Attach the uno and the battery holder to the acrylic sheet, as well.

Step 4: Wiring to Motor Shield

Then screw the wires from the motor onto the motor shield.

Step 5: Attach the Wheels

Securely put wheels in motor.

Step 6: Attach a Power Switch

Attach the on/off switch to the battery holder that connects motor shield.

Step 7: Transmitter

Solder the transmitter module to the motor shield.

Step 8: Car Shell

Attach the car shell to the base to cover the top.

CAR

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Show hidden characters
/ libray for motors
#include
// librays for the transmitter/receiver
#include
#include
#include
// declares all the motors
AF_DCMotor motor1(1);
AF_DCMotor motor2(2);
AF_DCMotor motor3(3);
AF_DCMotor motor4(4);
// int Xpot;
// int Ypot;
// sets the pins for the radio
RF24 radio(8, 9); // CE, CSN
const byte Address[6] = "00001";
// sets the max speed and the joystick values
int speed = 255;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
radio.begin();
radio.openReadingPipe(1, Address);
// the motors will be stopped
motor1.setSpeed(0);
motor2.setSpeed(0);
motor3.setSpeed(0);
motor4.setSpeed(0);
}
// might need an update function for joystick, example can be found in Lab 4 Part 5
void loop() {
// put your main code here, to run repeatedly:
radio.startListening();
// when the radio is range4
if (radio.available()) {
while (radio.available()) {
// radio.read(Xpot, sizeof(Xpot));
// radio.read(Ypot, sizeof(Ypot));
int values[2];
radio.read(values, sizeof(values));
int Xpot = values[0];
int Ypot = values[1];
int XPOS = map(Xpot, 2, 1018, 0, 2 );
int YPOS = map(Ypot, 2, 1018, 0, 2 );
// Serial.print(Xpot);
// Serial.println(Ypot);
Serial.print(XPOS);
Serial.print (YPOS);
// forward
if (XPOS == 1 && YPOS == 0){
motor1.setSpeed(speed);
motor1.run(FORWARD);
motor2.setSpeed(speed);
motor2.run(FORWARD);
motor3.setSpeed(speed);
motor3.run(FORWARD);
motor4.setSpeed(speed);
motor4.run(FORWARD);
Serial.println("forward");
}
// backwards
if (XPOS == 1 && YPOS == 2){
motor1.setSpeed(speed);
motor1.run(BACKWARD);
motor2.setSpeed(speed);
motor2.run(BACKWARD);
motor3.setSpeed(speed);
motor3.run(BACKWARD);
motor4.setSpeed(speed);
motor4.run(BACKWARD);
Serial.println("backwards");
}
//right
if (XPOS == 2 && YPOS == 1){
motor1.setSpeed(speed);
motor1.run(BACKWARD);
motor2.setSpeed(speed);
motor2.run(BACKWARD);
motor3.setSpeed(speed);
motor3.run(FORWARD);
motor4.setSpeed(speed);
motor4.run(FORWARD);
Serial.println("right");
}
//left
if (XPOS == 0 && YPOS == 1){
motor1.setSpeed(speed);
motor1.run(FORWARD);
motor2.setSpeed(speed);
motor2.run(FORWARD);
motor3.setSpeed(speed);
motor3.run(BACKWARD);
motor4.setSpeed(speed);
motor4.run(BACKWARD);
Serial.println("left");
}
//topleft
if (XPOS == 0 && YPOS == 0){
motor1.setSpeed(speed);
motor1.run(FORWARD);
motor2.setSpeed(speed);
motor2.run(FORWARD);
motor3.setSpeed(speed/3);
motor3.run(FORWARD);
motor4.setSpeed(speed/3);
motor4.run(FORWARD);
Serial.println("topleft");
}
//topright
if (XPOS == 2 && YPOS == 0){
motor1.setSpeed(speed/3);
motor1.run(FORWARD);
motor2.setSpeed(speed/3);
motor2.run(FORWARD);
motor3.setSpeed(speed);
motor3.run(FORWARD);
motor4.setSpeed(speed);
motor4.run(FORWARD);
Serial.println("topright");
}
//bottomleft
if (XPOS == 0 && YPOS == 2){
motor1.setSpeed(speed);
motor1.run(BACKWARD);
motor2.setSpeed(speed);
motor2.run(BACKWARD);
motor3.setSpeed(speed/3);
motor3.run(BACKWARD);
motor4.setSpeed(speed/3);
motor4.run(BACKWARD);
Serial.println("bottomleft");
}
//bottomright
if (XPOS == 2 && YPOS == 2){
motor1.setSpeed(speed/3);
motor1.run(BACKWARD);
motor2.setSpeed(speed/3);
motor2.run(BACKWARD);
motor3.setSpeed(speed);
motor3.run(BACKWARD);
motor4.setSpeed(speed);
motor4.run(BACKWARD);
Serial.println("bottomright");
}
// stop
if (XPOS == 1 && YPOS == 1){
motor1.setSpeed(0);
motor1.run(RELEASE);
motor2.setSpeed(0);
motor1.run(RELEASE);
motor3.setSpeed(0);
motor1.run(RELEASE);
motor4.setSpeed(0);
motor1.run(RELEASE);
Serial.println("stop");
}
}
}
}
view raw CAR hosted with ❤ by GitHub

Step 9: Joystick

Attach the joystick module to the uno. (Place the joystick pieces in a casing for easy handle when everything is done.)

Step 10: Transmitter

Attach the transmitter to the uno.

JOYSTICK

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Show hidden characters
#include
#include
#include
RF24 radio(8, 9); // CE, CSN
const byte Address[6] = "00001";
int X_pin = A0;
int Y_pin = A1;
// int x_pos;
// int Ypot;
void setup() {
radio.begin();
radio.openWritingPipe(Address);
radio.setPALevel(RF24_PA_MIN);
radio.stopListening();
Serial.begin(9600);
pinMode(X_pin, INPUT);
pinMode(Y_pin, INPUT);
}
void loop() {
int Xpot = analogRead(X_pin);
// Serial.print("X Analog value: " + String(Xpot));
int Ypot = analogRead(Y_pin);
// Serial.println(" Y Analog value: " + String(Ypot));
int values[2];
values[0] = Xpot;
values[1] = Ypot;
Serial.println(values[0]);
Serial.println(values[1]);
delay(200);
radio.write(values, sizeof(values));
}
view raw JOYSTICK hosted with ❤ by GitHub

Step 11: Power

Attach a 9 volt battery to the uno.

Step 12: Wire

Wire the LCD screen the arduino. Wire the LCD display to the arduino using this as a reference. The LCD display also needs a 220 ohm resistor and a 10k potentiometer. The potentiometer helps control the brightness of the display.



Step 13: Laser Gate

Add to circuit with the arduino and LCD.

These are the laser transmitter and the laser receiver. These are added to the arduino and LCD display. The laser is connected to pin 13 and ground. The receiver is connected to power, ground, and pin 8. 



Step 14: Battery

This is the completed circuit including a battery for the power source. The laser and receiver have long wires so we can sit across from each other in the gate



Step 15: Program the Laser Gate

Put the outputs on the serial monitor.

Step 16: Output LCD

Output to the LCD.

Step 17: Make the Gate

These are the cutouts for the laser gate enclosure. This is made out of chipboard and put together using some craft glue. 



Step 18: Make the Gate Pt 2

Make a gate for the timer out of cardboard.

Timer

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Show hidden characters
#include
#define DETECT 8
#define LASER 13
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
double lap_time = 0;
double fastest_lap = 9999;
double previous_lap = 0;
double lap_start_time = 0;
bool laser_detected = true;
void setup() {
lcd.begin(16, 2);
Serial.begin(9600);
pinMode(LASER, OUTPUT);
digitalWrite(LASER, HIGH);
pinMode(DETECT, INPUT);
lcd.print("Ready to Race!");
}
void loop() {
lcd.setCursor(0, 1);
bool val = digitalRead(DETECT);
if (val == 0 && laser_detected) {
// Laser not detected, start lap timer
laser_detected = false;
lap_start_time = millis();
} else if (val == 1 && !laser_detected) {
// Laser detected again, stop lap timer
laser_detected = true;
lap_time = (millis() - lap_start_time) / 1000.0;
if (lap_time < fastest_lap) {
fastest_lap = lap_time;
}
previous_lap = lap_time;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Lap Time: ");
lcd.print(lap_time);
lcd.setCursor(0, 1);
lcd.print("Previous Lap: ");
lcd.print(previous_lap);
delay(500);
}
}
view raw Timer hosted with ❤ by GitHub

Step 19: Full Circuit for Reference

This is the circuit in its enclosure. The laser and receiver are placed across from each other to ensure they make contact. The LCD display is placed in the center to make sure it can be seen when in use.