Building a 4WD Autonomous Car with Arduino

In this tutorial you will learn to make a 4WD robotic car with built-in obstacle avoidance. This project involves building a 4WD car with an ultrasonic sensor that can detect nearby objects and change its direction to avoid these objects. The ultrasonic sensor will be attached to a servo motor which is constantly scanning left and right looking for objects in its way.

4WD autonomous robotic car
4WD autonomous robotic car

You can extend this project by adding more sensors such as ultrasonic sensor to the rear so that the car doesn’t reverse into objects, speed detection sensors to determine speed, line following sensors, and LED brake lights. You could even add light sensors and LEDs to turn headlights on in low-light conditions or a Bluetooth connection to control the car through a mobile app.

Parts required

Here is what you will need:

  • 1x Arduino Uno board
  • 1x 4WD Robotic Car kit (4 wheels, 4 motors, chassis, AA battery enclosure, screws)
  • 6x AA batteries
  • 1x 9V battery
  • 1x 9V battery power cable barrel jack connector
  • 1x L298N Motor Module
  • 1x Arduino Sensor Shield v5.0
  • 1x HC-SR04 Ultrasonic Sensor
  • 1x Servo motor (any small servo motor will do but if you don’t have one you can leave it out)
  • Assorted colour wires:
    • 4x female-to-female wires for Ultrasonic Sensor
    • 8x female-to-female wires for the Motor Module to Sensor Shield
    • 8x bare-ended wires to go from the four motors to the Motor Module
    • 2x bare-ended wires to go from the Motor Module to Sensor Shield
    • 3x wires for the servo motor with female end attaching to Sensor Shield (should already be included with the servo motor)
    • 2x bare-ended wires to go from AA Battery enclosure to the motor Module (should already be included with the battery enclosure)
  • Arduino IDE software – free at http://www.arduino.cc
  • 1x USB cable (A male plug to B male plug)
  • A computer to program with

Note: Make sure you get a range of different colours for the wires (eg. red for voltage, black for ground, etc.). Some items such as the battery enclosure, motors and servo motor may come with wires so you may not need to purchase these separately. Some motor modules or sensor shields may use different pins (eg. male or female or just bare-ended wires).

Below are images of the main components you need (apart from the wiring and batteries) – the different robot parts, shields, modules and sensors.

Click for larger image
Click for larger image

Assembling the robotic car

The first thing to do is to assemble all the car chassis parts and attach the motors to the wheels. This is explained in detail in the video below.

Wiring it up

Now that the chassis is assembled and the wheels and motors are attached, you will need to wire up all of the components. You can watch the video below or scroll down for the step-by-step instructions and wiring diagram.

  1. Connect the red wire (voltage) from the battery enclosure to VCC on the L298N Motor Module.
  2. Connect the black wire (ground) from the battery enclosure to GND on the Motor Module.
  3. Connect the red wire from Motor A1 (rear left) and the red wire from Motor A2 (front left) to OUT1 on the Motor Module (both wires can be twisted together and will go into OUT1 – the wiring diagram further down this page shows how to do this).
  4. Connect the black wire from Motor A1 (rear left) and the black wire from Motor A2 (front left) to OUT2 on the Motor Module.
  5. Connect the red wire from Motor B1 (rear right) and the red wire from Motor B2 (front right) to OUT3 on the Motor Module.
  6. Connect the black wire from Motor B1 (rear right) and the black wire from Motor B2 (front right) to OUT4 on the Motor Module.
  7. Connect a female-to-female end wire from ENA (Engine A) on the Motor Module to signal pin 1 on the Sensor Shield (the #2 pin in the S row. There are three rows – S stands for Signal, V for Voltage and G for Ground).
  8. Connect a female-to-female end wire from 5V (next to ENA) on the Motor Module to voltage pin 1 on the Sensor Shield (it doesn’t really matter which pin for voltage as long as it is in the V row).
  9. Connect a female-to-female end wire from IN1 on the Motor Module to signal pin 2 on the Sensor Shield.
  10. Connect a female-to-female end wire from IN2 on the Motor Module to signal pin 3 on the Sensor Shield.
  11. Connect a female-to-female end wire from IN3 on the Motor Module to signal pin 4 on the Sensor Shield.
  12. Connect a female-to-female end wire from IN4 on the Motor Module to signal pin 5 on the Sensor Shield.
  13. Connect a female-to-female end wire from 5V (next to ENB) on the Motor Module to voltage pin 6 on the Sensor Shield (it doesn’t really matter which pin for voltage as long as it is in the V row).
  14. Connect a female-to-female end wire from ENB (Engine B) on the Motor Module to signal pin 6 on the Sensor Shield.
  15. Connect the signal wire from the servo motor to signal (S) pin 7 on the Sensor Shield, the voltage wire from the servo motor to the voltage (V) pin 7 on the Sensor Shield, and the ground wire from the servo motor to the GND (G) pin 7 on the Sensor Shield.
  16. Attach the Ultrasonic Sensor to the servo motor and then attach the servo motor to the front of the car so that it can scan left and right looking for objects in its path.
    You can use sticky tape, blu-tack, glue or a 3D printed/laser cut mount or whatever you like to attach everything, as long as everything is firmly mounted.
  17. Use female-to-female end plugs to connect the Ultrasonic sensor to the Sensor Shield. Firstly, attach the TRIG pin from the Ultrasonic sensor to signal (S) pin 8 on the Sensor Shield. Attach the ECHO pin from the ultrasonic sensor to signal (S) pin 9 on the Sensor Shield. Attach the VCC pin from the Ultrasonic Sensor to the voltage (V) pin 10 on the Sensor Shield. Lastly, attach the GND pin from the Ultrasonic Sensor to the GND (G) pin 11 on the Sensor Shield.
  18. Now attach the Sensor Shield on top of the Arduino Uno board making sure to not bend any pins. Connect a 9V Battery Barrel Jack Connector to a 9V battery and then plug this in to the Arduino’s barrel jack (see diagram below).
  19. That’s it! Now all you need is batteries and the code!

Please note: There are several variations of the sensors and modules and several different ways to wire this up. For example, you can add a charging component to charge batteries and you can also add different switches. There may be other better methods to use, but I have gone for the simplest way I know of to set this up.

Wiring diagram

Click for larger image
Click for larger image

Writing the code

Here is the code to get your robot moving. The code is written in C language and is written in the Arduino IDE software. The code for a robot with a servo motor and the code for a robot without a servo motor is shown below. If you don’t have an ultrasonic sensor and just want to use Bluetooth control via a phone app, then you can just extract the parts of the code that you need and then add the Bluetooth code.

Code to use with a servo motor

// Setup the servo motor
#include <Servo.h>
Servo myservo;
int servposnum = 0;
int servpos = 0;

// Setup Motor A (front and rear) pins
int enableA = 1;
int pinA1 = 3;
int pinA2 = 2;

// Setup Motor B (front and rear) pins
int enableB = 6;
int pinB1 = 5;
int pinB2 = 4;

// Setup Ultrasonic Sensor pins
#define trigPin 8
#define echoPin 9


void setup() {
  // The setup code goes here and runs once only
  // Configure the pin modes for each drive motor
   pinMode (enableA, OUTPUT);
   pinMode (pinA1, OUTPUT);
   pinMode (pinA2, OUTPUT);

   pinMode (enableB, OUTPUT);
   pinMode (pinB1, OUTPUT);
   pinMode (pinB2, OUTPUT); 

   // Configure the pin modes for the Ultrasonic Sensor
   pinMode(trigPin, OUTPUT);
   pinMode(echoPin, INPUT);

   // Turn pin into servo driver. Calls pinMode. Returns 0 on failure.
   myservo.attach(7);
}

void loop() {
  // Main code goes here and will run repeatedly:

     car(); // function keeps moving car forward while distance > 15cm
     avoid(); // function makes car go back, turn slightly right to move forward in new direction
     
}

// Create motor functions
void motorAforward() {
 digitalWrite (pinA1, HIGH);
 digitalWrite (pinA2, LOW);
}
void motorBforward() {
 digitalWrite (pinB1, LOW);
 digitalWrite (pinB2, HIGH);
}
void motorAbackward() {
 digitalWrite (pinA1, LOW);
 digitalWrite (pinA2, HIGH);
}
void motorBbackward() {
 digitalWrite (pinB1, HIGH);
 digitalWrite (pinB2, LOW);
}
void motorAstop() {
 digitalWrite (pinA1, HIGH);
 digitalWrite (pinA2, HIGH);
}
void motorBstop() {
 digitalWrite (pinB1, HIGH);
 digitalWrite (pinB2, HIGH);
}
void motorAcoast() {
 digitalWrite (pinA1, LOW);
 digitalWrite (pinA2, LOW);
}
void motorBcoast() {
 digitalWrite (pinB1, LOW);
 digitalWrite (pinB2, LOW);
}
void motorAon() {
 digitalWrite (enableA, HIGH);
}
void motorBon() {
 digitalWrite (enableB, HIGH);
}
void motorAoff() {
 digitalWrite (enableA, LOW);
}
void motorBoff() {
 digitalWrite (enableB, LOW);
}

// Setup movement functions
void forward (int duration) {
 motorAforward();
 motorBforward();
 delay (duration);
}
void backward (int duration) {
 motorAbackward();
 motorBbackward();
 delay (duration);
}
void right (int duration) {
 motorAbackward();
 motorBforward();
 delay (duration);
}
void left (int duration) {
 motorAforward();
 motorBbackward();
 delay (duration);
}
void coast (int duration) {
 motorAcoast();
 motorBcoast();
 delay (duration);
}
void breakRobot (int duration) {
 motorAstop();
 motorBstop();
 delay (duration);
}
void disableMotors() {
 motorAoff();
 motorBoff();
}
void enableMotors() {
 motorAon();
 motorBon();
}

// Setup Ultrasonic Sensor distance measuring
int distance() {
  int duration, distance;
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(1000);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  return distance;
}

// Setup the main car function
void car() {
int distance_0;
distance_0 = distance();
  // Keep moving forward in a straight line while distance of objects > 15cm
  while(distance_0 > 15)
  {
     // Keep moving servo motor back and forth to scan surroundings
     // This allows the ultrasonic sensor to see more to its left and right
     if(servposnum == 0)
     {
      myservo.writeMicroseconds (1900);
      servposnum = 1;
      delay(100);     
     }
     else if(servposnum == 1)
     {
      myservo.writeMicroseconds (2200);
      servposnum = 2;
     delay(100);
     }
     else if(servposnum  == 2)
     {
      myservo.writeMicroseconds (1900);
      servposnum = 3;
      delay(100);
     }
     else if(servposnum == 3)
     {
      myservo.writeMicroseconds (1600);
      servposnum = 1;
      delay(100);
     }
     motorAon();
     motorBon();
     forward(1);    
     distance_0 = distance();
     
  }
  breakRobot(0);

}
void avoid()
{
    // Go back and turn slightly right to move car in new direction if object detected < 15cm away
    backward(500);
    right(360);
}

Code to use without a servo motor

// Setup Motor A (front and rear) pins
int enableA = 1;
int pinA1 = 3;
int pinA2 = 2;

// Setup Motor B (front and rear) pins
int enableB = 6;
int pinB1 = 5;
int pinB2 = 4;

// Setup Ultrasonic Sensor pins
#define trigPin 8
#define echoPin 9

void setup() {
  // The setup code goes here and runs once only
  // Configure the pin modes for each drive motor
   pinMode (enableA, OUTPUT);
   pinMode (pinA1, OUTPUT);
   pinMode (pinA2, OUTPUT);

   pinMode (enableB, OUTPUT);
   pinMode (pinB1, OUTPUT);
   pinMode (pinB2, OUTPUT);

   // Configure the pin modes for the Ultrasonic Sensor
   pinMode(trigPin, OUTPUT);
   pinMode(echoPin, INPUT);
}

void loop() {
  // Main code goes here and will run repeatedly:
  car(); // function keeps moving car forward while distance of objects in front are > 15cm away
  avoid(); // function makes car go back, turn slightly right to move forward in new direction
}

// Create motor functions
void motorAforward() {
 digitalWrite (pinA1, HIGH);
 digitalWrite (pinA2, LOW);
}
void motorBforward() {
 digitalWrite (pinB1, LOW);
 digitalWrite (pinB2, HIGH);
}
void motorAbackward() {
 digitalWrite (pinA1, LOW);
 digitalWrite (pinA2, HIGH);
}
void motorBbackward() {
 digitalWrite (pinB1, HIGH);
 digitalWrite (pinB2, LOW);
}
void motorAstop() {
 digitalWrite (pinA1, HIGH);
 digitalWrite (pinA2, HIGH);
}
void motorBstop() {
 digitalWrite (pinB1, HIGH);
 digitalWrite (pinB2, HIGH);
}
void motorAcoast() {
 digitalWrite (pinA1, LOW);
 digitalWrite (pinA2, LOW);
}
void motorBcoast() {
 digitalWrite (pinB1, LOW);
 digitalWrite (pinB2, LOW);
}
void motorAon() {
 digitalWrite (enableA, HIGH);
}
void motorBon() {
 digitalWrite (enableB, HIGH);
}
void motorAoff() {
 digitalWrite (enableA, LOW);
}
void motorBoff() {
 digitalWrite (enableB, LOW);
}

// Setup movement functions
void forward (int duration) {
 motorAforward();
 motorBforward();
 delay (duration);
}
void backward (int duration) {
 motorAbackward();
 motorBbackward();
 delay (duration);
}
void right (int duration) {
 motorAbackward();
 motorBforward();
 delay (duration);
}
void left (int duration) {
 motorAforward();
 motorBbackward();
 delay (duration);
}
void coast (int duration) {
 motorAcoast();
 motorBcoast();
 delay (duration);
}
void breakRobot (int duration) {
 motorAstop();
 motorBstop();
 delay (duration);
}
void disableMotors() {
 motorAoff();
 motorBoff();
}
void enableMotors() {
 motorAon();
 motorBon();
}

// Setup Ultrasonic Sensor distance measuring
int distance() {
  int duration, distance;
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(1000);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration/2) / 29.1;
  return distance;
}

// Setup the main car function
void car() {
int distance_0;
distance_0 = distance();
  // Keep moving forward in a straight line while distance of objects in front > 15cm away
  while(distance_0 > 15)
  {
     motorAon();
     motorBon();
     forward(1);
     distance_0 = distance();
  }
  breakRobot(0);

}

// Go back and turn slightly right to move car in new direction
// This function only runs if an obstacle within 15cm is detected
void avoid()
{
    backward(500);
    right(360);
}

Finishing up

Once you have the code you will need to verify it and then upload it to your Arduino Uno board. Make sure you have either the Arduino disconnected from the Sensor Shield or all batteries disconnected when uploading the code to prevent any errors while uploading. Make sure to also arrange the different components carefully in the chassis to prevent any short circuits.

And that’s it! There is so much more that can be done with this project. Try extending your project by adding the following features:

  • Line following
  • Low-light activated headlights (using light sensors and LEDs)
  • Brake lights
  • Speed measuring
  • Bluetooth/mobile app control
  • More ultrasonic sensors to avoid reversing into objects or falling off edges

The video below shows a demo of the 4WD autonomous car using an Arduino and the ultrasonic sensor attache to a servo motor. Six AA batteries power the motors while the Arduino board is powered using a separate 9V battery.

More photos