Today I made my first autonomous robot car which is a modification of the my first Arduino RC Car. Until now, I used bluetooth for control navigation of the diy Arduino robomaster. Now, I wanted to add autonomous driving feature to the robot car because I thought it would be great experience to test code, test servo motors and HC-SR04 ultrasonic sensor and get hand on experience. Maybe I will incorporate both bluetooth and autonomous self driving or self aware robotic feature into the final Arduino Robomaster.
This autonomous robot car is a Obstacle Avoidance Robot car. It uses ultrasonic senor to detect distances and servo motor is used the sensor around to look for obstacles and objects.
I told in my previous blog post Adding and Checking Ultrasonic Sensor and Servo Motor how I made assembled the servo and the sensor onto the robot car chassis.
Robot Car Circuit Diagram
Following is the circuit diagram for the sensor based robot car using Arduino.
I have already explained how I built and added the lithium ion recharging circuit to the Arduino robot car. In that blog post I said that this recharging circuit is not yet confirmed. But I checked for 1 day and the recharging circuit seems to work. To learn the basic of servo motor control see controlling a hobby servo motor with L293D motor shield and Arduino. To learn the basic of ultrasonic sensor look at my previous tutorial intruder sensor with ultrasonic sensor. For bluetooth and other aspects you can read the references links.
Ultrasonic sensor robot car code
After I had built the sensor and actuator onto it, I uploaded a obstacle avoiding program code for the robot. Below is the ultrasonic Arduino robot car code that I used.
#include <AFMotor.h>
#include <NewPing.h>
#include <Servo.h>
#define TRIG_PIN A0
#define ECHO_PIN A1
#define MAX_DISTANCE 200
#define MAX_SPEED 200 // sets speed of DC motors
#define MAX_SPEED_OFFSET 20
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
AF_DCMotor motor1(1, MOTOR12_1KHZ);
AF_DCMotor motor2(2, MOTOR12_1KHZ);
AF_DCMotor motor3(3, MOTOR34_1KHZ);
AF_DCMotor motor4(4, MOTOR34_1KHZ);
Servo myservo;
boolean goesForward=false;
int distance = 100;
int speedSet = 0;
void setup() {
Serial.begin(9600);
myservo.attach(10);
myservo.write(50); //115
delay(2000);
distance = readPing();
delay(100);
distance = readPing();
delay(100);
distance = readPing();
delay(100);
distance = readPing();
delay(100);
myservo.write(100);
delay(500);
myservo.write(54);
delay(500);
myservo.write(142);
delay(500);
myservo.write(100);
delay(500);
Serial.print(distance);
Serial.println(" cm");
}
void loop() {
int distanceR = 0;
int distanceL = 0;
delay(40);
Serial.print(distance);
Serial.println(" cm");
if(distance<=15) {
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();
}
}
else{
moveForward();
}
distance = readPing();
}
int lookRight(){
myservo.write(54);
delay(500);
int distance = readPing();
delay(100);
myservo.write(100);
return distance;
}
int lookLeft(){
myservo.write(142);
delay(500);
int distance = readPing();
delay(100);
myservo.write(100);
return distance;
delay(100);
}
int readPing(){
delay(70);
int cm = sonar.ping_cm();
if(cm==0){
cm = 250;
}
return cm;
}
void moveStop(){
motor1.run(RELEASE);
motor2.run(RELEASE);
motor3.run(RELEASE);
motor4.run(RELEASE);
}
void moveForward(){
if(!goesForward){
goesForward=true;
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
for (speedSet = 0; speedSet < MAX_SPEED; speedSet +=2){
motor1.setSpeed(speedSet);
motor2.setSpeed(speedSet);
motor3.setSpeed(speedSet);
motor4.setSpeed(speedSet);
delay(5);
}
}
}
void moveBackward() {
goesForward=false;
motor1.run(BACKWARD);
motor2.run(BACKWARD);
motor3.run(BACKWARD);
motor4.run(BACKWARD);
for (speedSet = 0; speedSet < MAX_SPEED; speedSet +=2){
motor1.setSpeed(speedSet);
motor2.setSpeed(speedSet);
motor3.setSpeed(speedSet);
motor4.setSpeed(speedSet);
delay(5);
}
}
void turnRight() {
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(BACKWARD);
motor4.run(BACKWARD);
delay(500);
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
}
void turnLeft() {
motor1.run(BACKWARD);
motor2.run(BACKWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
delay(500);
motor1.run(FORWARD);
motor2.run(FORWARD);
motor3.run(FORWARD);
motor4.run(FORWARD);
}
Let's break down the code section by section to understand its functionality:
1. Libraries and Definitions
#include <AFMotor.h>
#include <NewPing.h>
#include <Servo.h>
#define TRIG_PIN A0
#define ECHO_PIN A1
#define MAX_DISTANCE 200
#define MAX_SPEED 200 // sets speed of DC motors
#define MAX_SPEED_OFFSET 20
In this section, the code includes three libraries: AFMotor
for controlling DC motors, NewPing
for interfacing with ultrasonic distance sensors, and Servo
for controlling a servo motor. It also defines some constants like TRIG_PIN
, ECHO_PIN
, MAX_DISTANCE
, MAX_SPEED
, and MAX_SPEED_OFFSET
, which are used throughout the code.
2. Object Initialization
NewPing sonar(TRIG_PIN, ECHO_PIN, MAX_DISTANCE);
AF_DCMotor motor1(1, MOTOR12_1KHZ);
AF_DCMotor motor2(2, MOTOR12_1KHZ);
AF_DCMotor motor3(3, MOTOR34_1KHZ);
AF_DCMotor motor4(4, MOTOR34_1KHZ);
Servo myservo;
This part of the code initializes objects for the NewPing sensor (sonar
) and four DC motors (motor1
, motor2
, motor3
, motor4
) using the AFMotor
library. It also initializes a servo motor object (myservo
) to control a servo.
3. Global Variables
boolean goesForward=false;
int distance = 100;
int speedSet = 0;
Here, some global variables are declared. goesForward
is a boolean flag indicating the direction of movement, distance
stores the distance measured by the sensor, and speedSet
keeps track of the motor speed.
4. setup()
Function
void setup() {
Serial.begin(9600);
myservo.attach(10);
// ...
}
The setup()
function initializes the serial communication
and attaches the servo motor to pin 10. It also performs some
initializations involving the servo and ultrasonic sensor, reading the
sensor's value after each delay.
5. loop()
Function
void loop() {
// ...
}
The loop()
function is the core of the code, where the main
actions take place. It reads the distance from the sensor, and
depending on the distance value, it decides whether to move forward,
stop, or take evasive actions (move backward, turn right, or turn left)
to avoid obstacles.
6. Sensor Reading Functions
lookRight()
andlookLeft()
: These functions turn the servo to specific angles to scan for obstacles and return the distance measured at those angles.readPing()
: Reads the distance from the ultrasonic sensor and returns it. If the sensor returns 0 (indicating no valid distance measurement), it assigns a value of 250 tocm
(centimeters) as a placeholder.
7. Motor Control Functions
moveStop()
: Stops all four motors.moveForward()
: Moves the vehicle forward by gradually increasing the speed of the motors.moveBackward()
: Moves the vehicle backward by gradually increasing the speed of the motors in the opposite direction.turnRight()
: Turns the vehicle to the right.turnLeft()
: Turns the vehicle to the left.
These functions control the direction and speed of the motors based on the situation determined by the distance readings from the sensor.
After uploading the code I tested it. In the robot car code, the angle for the servo to turn left and right has to be adjusted according to your requirement. For me, on the right side the angle needed was 54 degree and for the left was 142 degree, 100 degree being the center. To find the angle values to set in the above program code, you can use a joystick to move the servo arm around and take note of the angles.
Video demonstration
Following is video demonstration of testing the autonomous Arduino robot car.
# Arduino RoboMaster Modifications with Crane Part - Arduino RoboMaster Part 9