Arduino Smart Car - Obstacle Avoiding Robot

Step by step build instructions and the needed code to construct and program the Bang-good smart car or similar project. This is an intermediate to advanced build. It is assumed you know what Arduino sketches and libraries are and how to use them. It is also assumed you have basic electronics knowledge, circuit building, and soldering skills.

Smart Car Assembly

Because of the low quality of the Banggood kit and needed component upgrades several modifications to the basic kit are required to make this build successful.

  1. Drill (4) four additional holes in the chassis to mount the L298N Driver board.
    Also chamfer the four holes as shown on the right side in the image below.
    We recommend using masking tape on the bottom of the part to help avoid scratching the surface.


Download this PDF and print at full scale to create a drill template.
NOTE: The holes with centerlines are the additional or chamfered holes.

  1. Fabricate the component mount plate that will go over the battery pack.
    Any thin material will work. We cut and drilled 1/8 inch Plexiglas from the local hardware.


Download this PDF and print at full scale to create a part pattern.

  1. Fabricate the rear skid mount plate that will hold the carriage bolt.
    This part should be at least 1/4 inch thick. Again we fabricated ours from 1/4 inch Plexiglas from the local hardware.


Download this PDF and print at full scale to create a part pattern.

  1. Assemble the rear skid as shown using the 4-40 x 5/16 flat head screws.
    We used a 5/8-16 x 1 1/2 inch carriage bolt for the rear skid.

 

  1. Assemble the Upper Mount Plate, Arduino Board, and Mini Breadboard.
    NOTE: Chamfer the holes and use flat head screws to mount the 1 inch standoff spacers.
    Protruding screw heads will interfere with the  installation of the motors.

 

  1. Attach the gear motors and wheels to the chassis.

 

  1. Install the L298N motor driver and servo using the 1/2 inch standoffs.
    NOTE: Use hot melt glue or double sided tape to secure the servo motor.


Before installing the ultrasonic sensor calibration of the servo is required.

  1. Build the following circuit using a 10K pot:


Click picture for larger image.

  1. Copy, paste, and upload the following code to the Arduino IDE.

/*
Controlling a servo position using a potentiometer (variable resistor)
by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>

modified on 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Knob

modified on 21 March 2018
by David A Smith
*/

#include <Servo.h>

Servo myservo; // create servo object to control a servo

int potpin = A0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin

void setup(){
Serial.begin(9600);
myservo.attach(10); // attaches the servo on pin 10 to the servo object
}

void loop() {
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180)
myservo.write(val); // sets the servo position according to the scaled value
Serial.println(val); // Displays the current angle position on the Serial Monitor
delay(15); // waits for the servo to get there
}

  1. Open the serial monitor and turn the potentiometer to zero.
  2. Attach a horn to the servo and align it as close as possible to the pointing forward position.
  3. Turn the pot and note the right, forward and left positions. We will use these numbers later in the code.
    For Example: Right = 6, Forward = 95, Left = 168
  4. Return the servo to the centered position before disassembling this circuit.
  5. Install the servo horn and ultra-sonic sensor.

Electrical Connections

-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------

Bring the T-1000 On-Line

When building complex robotic systems it is best to test each component and function along the way. This makes it easier to identify and trouble shoot problems should they arise.

!!! WARNING !!!
Do not power the Arduino Robot from both the battery pack and the USB cable at the same time.

  1. Testing the Ultra-Sonic Sensor

    • Copy, paste, and upload the following code to the Arduino IDE.

    /*
      HC-SR04 NewPing Duration Demonstration
      HC-SR04-NewPing-Duration.ino
      Demonstrates using Duration function of NewPing Library for HC-SR04 Ultrasonic Range Finder
      Displays results on Serial Monitor

      DroneBot Workshop 2017
      http://dronebotworkshop.com

      modified on 25 March 2018
      by David Smith
    */
    // This uses Serial Monitor to display Range Finder distance readings

    // Edit this variable to change how close something comes to the sensor before tripping the LED
    // Also try different materials at different angles to see how the sensor behaves.

    float stopDist=3;     //Declare the stop distance variable and set it to a number in inches

    #include "NewPing.h" // Include NewPing Library
    #define TRIGGER_PIN A1 // Hook up Trig to Arduino Pin A1
    #define ECHO_PIN A0 // Hook up Trig to Arduino Pin A0
    #define MAX_DISTANCE 400 // Maximum Distance is 400 cm
    NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
    float duration, distance;
    int indicatorLED=13; //Declare indicatorLED an int, and set to pin 13

    void setup() {
      pinMode(indicatorLED, OUTPUT); // Tell Arduino that indicatorLED is an output pin
      Serial.begin (9600);
    }

    void loop() {
        duration = sonar.ping(); // Determine distance from duration
        distance = (duration / 2) * 0.0343; // Use 343 metres per second as speed of sound

        Serial.print("Distance = "); // Send results to Serial Monitor
      if (distance >= 400 || distance <= 2) {
        Serial.println("Out of range");
      }

      else {
        Serial.print(distance);
        Serial.print(" cm - ");
        Serial.print(distance*.3937); // Convert cm to inches
        Serial.println(" in");
        delay(500); // Pause the program for 1/2 second
      }

      if ((distance*.3937)<= stopDist) {
        digitalWrite(indicatorLED,HIGH); //Turn the indictor LED on
      }

      else {
        digitalWrite(indicatorLED,LOW); //Turn the indictor LED off
      }

      delay(500);
    }

    • Launch the serial monitor and notice that the pin 13 LED turns on when the stop distance is reached.

    • Change the value of the stopDist variable in the code and experiment with the set up to see the results.

    • Try different materials at different angles to see how the sensor behaves and to understand its limitations.
  1. Setup and Testing of the Motors and Motor Driver


  2. NOTE:
    The 6 volt battery pack that comes with the kit is insufficient to drive the required loads.
    Testing has also shown that anything over 12 volts causes the robot to behave erratically.

!!! WARNING !!!
Do not power the Arduino Robot from both the battery pack and the USB cable at the same time.

  • Copy paste and upload the following code to the Arduino then disconnect the USB cable.

    // connect motor controller pins to Arduino digital pins
    // motor one (LH Wheels)
    int enA = 3;
    int in1 = 9;
    int in2 = 8;
    // motor two (RH Wheels)
    int enB = 5;
    int in3 = 7;
    int in4 = 6;
    int spd = 255; // set speed from 0 (stop) to 255 (max)

    void setup()
    {
      // set all the motor control pins to outputs
      pinMode(enA, OUTPUT);
      pinMode(enB, OUTPUT);
      pinMode(in1, OUTPUT);
      pinMode(in2, OUTPUT);
      pinMode(in3, OUTPUT);
      pinMode(in4, OUTPUT);
    }

    void demoOne()
    {
      // this function will run the motors in both directions at a fixed speed

      // turn on motor one (LH Wheels) and Drive Forward
      digitalWrite(in1, LOW);
      digitalWrite(in2, HIGH);
      analogWrite(enA, spd);

      // turn on motor two (RH Wheels) and Drive Forward
      digitalWrite(in3, LOW);
      digitalWrite(in4, HIGH);
      analogWrite(enB, spd);
      delay(2000);

      // now reverse motor directions
      digitalWrite(in1, HIGH);
      digitalWrite(in2, LOW);
      digitalWrite(in3, HIGH);
      digitalWrite(in4, LOW);
      delay(2000);

      // now turn off motors
      digitalWrite(in1, LOW);
      digitalWrite(in2, LOW);
      digitalWrite(in3, LOW);
      digitalWrite(in4, LOW);
    }

    void demoTwo()
    {
      // this function will run the motors across the range of possible speeds
      // note that maximum speed is determined by the motor itself and the operating voltage
      // the PWM values sent by analogWrite() are fractions of the maximum speed possible
      // by your hardware

      // turn on motors
      digitalWrite(in1, LOW);
      digitalWrite(in2, HIGH);
      digitalWrite(in3, LOW);
      digitalWrite(in4, HIGH);

      // accelerate from zero to maximum speed
      for (int i = 0; i < 256; i++)
      {
        analogWrite(enA, i);
        analogWrite(enB, i);
        delay(20);
      }

      // decelerate from maximum speed to zero
      for (int i = 255; i >= 0; --i)
     {
      analogWrite(enA, i);
      analogWrite(enB, i);
      delay(20);
      }

      // now turn off motors
      digitalWrite(in1, LOW);
      digitalWrite(in2, LOW);
      digitalWrite(in3, LOW);
      digitalWrite(in4, LOW);
    }

    void loop()
    {
      demoOne();
      delay(1000);
      demoTwo();
      delay(1000);
    }

    • After disconnecting the USB cable prop the robot up so that the wheels can spin freely.
      Turn the battery power switch on and observe the wheel movement.
      The wheels should:
      - Spin Forward
      - Spin Backward
      - Slowly ramp up to full speed and then slow down and stop.
      The cycle will then repeat.

    • Observe that the wheels are spinning correctly. If one is spinning in reverse simply switch the wires connected to the motor driver board.
  1. Load the Final Code


  2. Be sure to turn the battery pack off before connecting the USB cable for programming.

Copy, paste, and upload the following code to the Arduino IDE.

// Arduino Obstacle Avoiding Robot
// Code adapted from http://www.educ8s.tv
// Modified by David A Smith on 4/8/2018
// First Include the NewPing and Servo Libraries
#include <NewPing.h>
#include <Servo.h>

#define TRIG_PIN A1 // Arduino pin tied to trigger pin on ping sensor.
#define ECHO_PIN A0 // Arduino pin tied to echo pin on ping sensor.
#define MAX_DISTANCE 200 // Maximum distance we want to ping for (in centimeters).
// Maximum sensor distance is rated at 400-500cm.

NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
Servo myservo;

boolean goesForward=false;
int distance = 100;

// connect motor controller pins to Arduino digital pins
// motor one (LH Wheels)
int enA = 3;
int in1 = 9;
int in2 = 8;
// motor two (RH Wheels)
int enB = 5;
int in3 = 7;
int in4 = 6;
int spd = 230; // set speed from 0 (stop) to 255 (max)
int timeRight = 380; // Number of milliseconds to turn right 90 degrees (adjust as necessary)
int timeLeft = 370; // Number of milliseconds to turn left 90 degrees (adjust as necessary)
int stpDist = 20; // Distance to stop from objects (adjust as necessary)
int sloR = 10; // If bot consistentaly drifts in one direction while moving "straight"
int sloL = 0; // adjust the sloR & sloL to slow down the appropriate wheel.

void setup() {
// set all the motor control pins to outputs
pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);

myservo.attach(11);
myservo.write(90); //#90 Sets the servo to center of travel (tweak as necessary)
delay(2000);
distance = readPing();
delay(100);
}

void loop() {
int distanceR = 0;
int distanceL = 0;
delay(40);

if(distance<=stpDist)
{
moveStop();
delay(100);
// moveBackward();
// delay(300);
// moveStop();
// delay(200);
distanceR = lookRight();
delay(200);
distanceL = lookLeft();
delay(200);

if(distanceR>=distanceL)
{
turnRight();
moveStop();
}
else
{
turnLeft();
moveStop();
}
} // End if < Stop Distance
else
{
moveForward();
}
distance = readPing();
}

int lookRight()
{
myservo.write(0);
delay(500);
int distance = readPing();
delay(100);
myservo.write(90);
return distance;
delay(100);
}

int lookLeft()
{
myservo.write(180);
delay(500);
int distance = readPing();
delay(100);
myservo.write(90);
return distance;
delay(100);
}

int readPing() {
delay(70);
int cm = sonar.ping_cm();
if(cm==0)
{
cm = 250;
}
return cm;
}

void moveStop()
{
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
}

void moveForward()
{
// turn on motor A
analogWrite(enA, spd-sloR);
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
// turn on motor B
analogWrite(enB, spd-sloL);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
}

void moveBackward()     // The move backward void is not used but has been left in for refrence
{
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
}

void turnRight()
{
analogWrite(enA, 255);
analogWrite(enB, 255);
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, HIGH);
delay(timeRight);
moveForward();
}

void turnLeft()
{
analogWrite(enA, 255);
analogWrite(enB, 255);
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
digitalWrite(in3, HIGH);
digitalWrite(in4, LOW);
delay(timeLeft);
moveForward();
}

  • Once the code is loaded disconnect the USB and power the car from the battery pack

  • The code that is posted here is exactly as is it is on the functioning demo build. Your car can and probably will behave differently.

  • Things that affect performance:
    • Orientation of the Ultra-Sonic sensor.
    • Humidity
    • Battery pack voltage
    • The type of surface it is running on

  • Tweak the parameters of the code as necessary to fine tune how your bot behaves.

Design Notes

Out of the box the Bangood Smart Car Kit is on the poor side.

Power:
The included battery pack is too small for the power requirements of the car. Once the motors engage the voltage drop is significant enough make the 5 volt regulator drop out causing the Arduino to reset. As a result we went with the 9 volt AA battery pack. It fit perfectly under the upper mount plate and was easily held in place with a Velcro strap.

Mounting:
None of the holes in the chassis plate matched the various components that were to be mounted. There was also not enough space to effectively mount all the components. Hence it was necessary to developed the upper mount plate and drill additional holes in the chassis.

Hardware:
None of the hardware (screws) that came with the kit were useful. Aside from the fasteners in the servo bag all hardware used was either on hand or purchased seperatly.

The Caster:
Do not even bother mounting the caster. With the light weight of the car and the low quality of the caster it simply would not swivel smoothly. This would cause the car to drive in big archs if not outright cause it to sit and spin. A higher quality caster was purchased. Although it did somewhat improve performance it still caused the bot to not function correctly. Ultimately a carriage bolt used as a skid plate proved to be the best / cheapest solution.

What You See:
Is not what you get.
Most notably the chassis plate is not the CNC'd acrylic as shown but rather a cheap molded part.

If your PC is a tower the USB cable is not long enough to reach the desk let alone be useful for anything. Probably OK for laptop use.
 
Conclusion:
In all it is a fun project. Just be ready to wait for the slow boat from China and to completely rework the kit once you have it. For the price of a real Arduino you can get this kit, pretty good bang for the buck.

 


Some variations on what could be built with the same kit and some additional parts.