This is a tutorial to help you build and assemble Smart Robotic Car which is built using Arduino Board, Motors and various sensors which will be explained in this story.
Robotic Car Features
Control using IR Remote
Control via Bluetooth
Autonomous Mode
Line following Mode
Require Components
1x Arduino UNO
4 x DC Motors (3 — 6 VDC)
1x Servo Motor
1x Motor Driver Module (L298N)
1x Bluetooth Modules (HC-06)
1x Ultrasonic Sensor
3x IR Sensors
1x IR Receiver
1x Remote Control
Jumper Wires
2x Car Chassis
4x Wheels
Assembling Components
Step 1: Fixing DC Motors & L298N Motor Driver
First step is to assemble DC Motors on the lower chassis making sure to align right and left motors with each other and then wire each motor to the L298N Motor Driver as shown below.
The L298N Motor Driver Module will control 4 Motors while distributing balanced current to each motor to maintain the car speed at all time.
Just make sure the wiring of each motor is connected so that the front and back motors moves in the same direction or opposite to each other depending on how motor being fixed on the car chassis.
L298N Motors Technical Specifications
Motor output voltage: 5 - 35V
Motor output voltage (Recommended): 7 - 12V
Logic input voltage: 5 - 7V
Continuous current per channel: 2A
Max Power Dissipation: 25W
L298N will receive Pulse Width Modulation (PWM) signal from Arduino to control motors speed. Wiring between Arduino and L298N Motors Driver is shown below. The module need to be fixed on the car chassis as well.
Upon wiring DC Motors as explained above and fixing the Motor Driver Module we will have the lower part of the car as shown below, thus we could proceed to the next step.
Step 2: Microcontroller (Arduino UNO)
This project utilizes Arduino UNO to interface between Motor Driver Module, Motors and Sensors. It will receive input from various connected sensors and then control motors accordingly.
As we’ve mentioned above in order to control motor’s speed we need to connect PWM pins of Arduino to the L298N input pins.
In Arduino UNO we have 13 Digital Pins 6 of which are with PWM capability which are represented with the symbol (~) as shown on Arduino UNO figure above (Pins 3, 5, 6, 9, 10, 11).
We need 2 PWM pins to control motor’s speed which will be used for Enable Pins ENA,ENB. ENA will control speed of right (front and back) motors and ENB will control the left side motors.
Those 2 pins will receive trigger signal from Arduino Pins 11, 6 subsequently with a voltage range between 0–5 Volt, where 5V corresponds to maximum motor speed, 2.5V Mid Speed and 0V to will Stop Motors.
Step 3: Connecting Sensors
1- Line Following (IR Sensors)
To use the Robotic car as a line following robot, 3 IR Sensor are required to move the car along a black line surface (Black tape in our case) while detecting turns and curves along a path.
Those Sensors should be placed on the car lower chassis facing down towards the surface and leaving a distance of no more 20mm.
We need to make sure to align the three sensors with the chassis front side so that the middle sensor facing forward, left sensor about 45 degree to the left and right sensor about 45 to the right.
IR sensor has an LED that emits infrared lights and as you may know that black color absorbs lights, thus there is a phototransistor on the IR sensor module that receives the reflected light and sends signals to the microcontroller, but in case of the black light there will be no reflection of light from surface.
By placing a black thin tape on the surface and using the light’s reflection concept, we could find out if the car is aligned on the black line, and if not than the car should correct its position either to the right or to the left.
2- Autonomous Mode (Ultrasonic Sensor)
In autonomous mode, Ultrasonic sensor used to enable the car to move autonomously by scanning the surrounding and deciding which route should the car head to. Which is obviously the route with no obstacles then moving the car in that direction.
The Ultrasonic sensor should be fixed on a servo motor to swing the sensor back and forth while the sensor emits signals to measure distance in all directions.
The next step would be handled by the microcontroller (Arduino UNO) which will compute the distance in every direction and find the longest distance, and then moves the car towards that direction.
In other words, the movement sequence will be as follows:
Align the sensor to front direction by moving the servo motor to 90 degree
Move forward
Detect Obstacles and if detected, then
Stop the Car
Scan Surrounding
Compute the direction with longest distance reading
Rotate the car in the computed direction
Align the sensor to front direction by moving the servo motor to 90 degree
Move forward
3- IR Remote Control (IR Sensor)
Other way to control the car is using an IR receiver module and remote control with an IR Transmitter.
Basically, each button in the remote control will send a unique code to the receiver, then the receiver will send that code to the microcontroller (Arduino UNO).
For each code sent, Arduino will decide to the corresponding action to be taken, either to move the car in a certain direction, move servo motor, read distance, or any other possible action could be taken.
4- Bluetooth Control Mode (Bluetooth Module)
In Bluetooth Mode, we will pair the Bluetooth module on board with a mobile app, and through that app we’ll send codes that could be translated by the microcontroller and move the car accordingly.
Video
Design
Code
/* This code is written by Eng. Mohammed AlMehaiza (Go Invent)
This code was uploaded and tested on the Robotic Car kit as per the following
video link: https://www.youtube.com/watch?v=-wUMs36Cf2M
This code should enable user to communicate with the car using the IR Remote control, bluetooth via mobile apps
And it should enabel the car to move autonomously.
Any comments or inquiry please send via the contact form at (https://diylab.io)
Thank you, have fun!
*/
#include<SoftwareSerial.h> // Including softSerial header file
#include <IRremote.h> // Including infrared remote header file
#include <Servo.h> // Including servo motor header file
// ------------------------- Pins Definition ------------------------------
// Pins assigned for the L298N motor driver control pins
#define IN1 10
#define IN2 9
#define IN3 8
#define IN4 7
#define EN1 11 // Should be PWM pin
#define EN2 6 // Should be PWM pin
#define echoPin 4 // pin number to Echo of the Ultrasonic Sensor
#define trigPin 3 // pin number to Trig of the Ultrasonic Sensor
#define servoPin 5 // Define servo control pin
int RECV_PIN = 2; // IR Receiver pin
// ------------------------- Configurable Variables ------------------------------
int time_to_stop = 150;
String Forward_Bluetooth = "F";
String Reverse_Bluetooth = "B";
String Right_Bluetooth = "R";
String Left_Bluetooth = "L";
String Stop_Bluetooth = "S";
long Forward_IR = 16718055;
long Reverse_IR = 16726215;
long Left_IR = 16716015;
long Right_IR = 16734885;
long Autonomous_IR = 16761405;
long Bluetooth_IR = 16769565;
long Action_IR = 4294967295; // This code is sent by the IR Remote after pressing and holding a button on the remote
long Move_Servo_Left_IR = 16754775;
long Move_Servo_Right_IR = 16769055;
long Move_Servo_90_IR = 16748655;
// ------------------------------------------------------------------------------
// Enumeration of differnt car movement actions
enum motion {
Forward, // 1
Reverse, // 2
Left, // 3
Right, // 4
Stop // 5
};
//Defining a softserial object to communication with the bluetooth module
SoftwareSerial mySerial(12, 13); // RX, TX (Bluetooth module Rx to 13 and Tx to 12)
IRrecv irrecv(RECV_PIN); // Define IR receiver object using the predefined pin (2)
decode_results results; // Object to store the received code sent by the IR remote control
Servo myservo; // Define Servo object
motion dir; // Define a variable of the enumerated type (motion)
String data = "n"; // String variable to store the data sent via the bluetooth module
int pos = 90; // Variable to store the position of the servo (default is 90) to face the ultrasonic sensor front of the car
int old_pos = 0; // Variable to store the old positon of the servo
int heading_direction = 90;; // Variable to decide in which direction and angle the car has to turn
float saved_pos = 90; // Variable to store the heading servo postion
float ful_cycle = 1000; // How long it will take the car to rotate 180 degree (Assumption is 1 second)
// using this variable we try to predict the angle of rotation by -> (full_cycle*heading_angle)/180
// This equation should convert the angle to interval so that the car will turn the correct angle
// to avoid collision with other obstacles.
int rotation = 1; // Variable to change the servo motor rotation direction (1 = clockwise, -1 = counterclockwise)
boolean autonomous = false; // Boolean variable to enable/disable autonomous mode
boolean bluetooth = false; // Boolean variable to enable/disable bluetooth control mode
boolean move_servo = false; // Boolean variable to enable/disable servo motor movement
long duration; // Duration of sound wave travel
float distance; // Distance from the obstacle
float max_distance = 0; // Variable to store the maximum distance from obstacles
float safeDistance = 20.00; // Safe distance to stop car before collision
long currentmillis = 0; // Store current millis()
void setup()
{
// Serial.begin(9600); ------> Enable this line to check the code sent by the IR Remote
// Set the defined pins to OUTPUT/INPUT
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(EN1, OUTPUT);
pinMode(EN2, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// Initialize Motor control pins to LOW
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
// Change the motors speed (1023 = Maximum speed, 0 = stop)
analogWrite(EN1, 1023);
analogWrite(EN2, 1023);
// Begin serial communication with the bluetooth module
mySerial.begin(9600);
// Attach the servo motor on the defined pin and move to initial position
myservo.attach(servoPin);
myservo.write(pos);
// Enable IR receiver data communication
irrecv.enableIRIn();
}
void loop()
{
// For Autonomous mode
if (autonomous) {
delay(50);
// Check if distance from objects ahead is less than the safe distance
if (check() <= safeDistance) {
dir = Stop;
movement(Stop); // Stop the car
movement(search()); // Search for the best and safe direction to turn car to then turn the car to that direction
if (saved_pos > 90) saved_pos = saved_pos - 90; // Return the corrsponding position between 0 to 90 if the position is more than 90
// So that the car could turn to the correct direction in relation with time delay.
delay((ful_cycle * saved_pos) / 180); // Calculate the correct delay in relation with the time required for 180 rotation
distance = 200; // Reset the distance to 200 to clear the Ultrasonic sensor readings
dir = Forward;
movement(dir); // After the car turned to the correct position move the car forward
delay(500);
pos = 90;
myservo.write(pos); // Return the servo position again to 90 to let the Ultrasonic sensor face forward again
}
else
dir = Forward;
movement(dir);
}
// For Bluetooth mode
else if (bluetooth) {
// If the bluetooth module received data
if (mySerial.available())
{
data = mySerial.readStringUntil('\n'); // Check the received data
data.trim(); // Trim the string received to remove any spaces and unnecessary characters
// Check the character recevied and set the (dir) variable the corresponding direction
if (data == Forward_Bluetooth) dir = Forward;
else if (data == Reverse_Bluetooth) dir = Reverse;
else if (data == Right_Bluetooth) dir = Right;
else if (data == Left_Bluetooth) dir = Left;
else if (data == Stop_Bluetooth) {
dir = Stop;
data = "n";
}
movement(dir);
}
}
// For IR Remote mode
while (irrecv.decode(&results) && data == "n") {
//Serial.println(results.value); ------> Enable this line to check the code sent by the IR Remote
if (results.value == Forward_IR) dir = Forward;
else if (results.value == Reverse_IR && !autonomous) dir = Reverse;
else if (results.value == Left_IR && !autonomous) dir = Left;
else if (results.value == Right_IR && !autonomous) dir = Right;
else if (results.value == Autonomous_IR) { // TO enable/disable autonomous mode
autonomous = !autonomous;
myservo.write(90);
}
else if (results.value == Bluetooth_IR) { // TO enable/disable bluetooth mode
dir = Stop;
movement(dir);
bluetooth = !bluetooth;
myservo.write(90);
}
// Most of the actions are done by this if statement
else if (results.value == Action_IR && !autonomous && !bluetooth) {
movement(dir);
if (pos != old_pos && pos < 180 && pos > 0 && move_servo) {
move_servo = false;
myservo.write(pos);
pos = pos + (rotation * 5);
}
}
// Move servo left manually
else if (results.value == Move_Servo_Left_IR && !autonomous) {
if (pos <= 175) {
pos = pos + 5;
rotation = 1;
move_servo = true;
}
}
// Move servo right manually
else if (results.value == Move_Servo_Right_IR && !autonomous) {
if (pos >= 5) {
pos = pos - 5;
rotation = -1;
move_servo = true;
}
}
// Center the servo to the middle
else if (results.value == Move_Servo_90_IR && !autonomous) {
pos = 90;
old_pos = 0;
rotation = 0;
}
// Clear the remaining codes from the IR Receiver data buffer
irrecv.resume();
currentmillis = millis();
}
// After certain time of no IR code is received stop the motors
if ( (millis() - currentmillis) > time_to_stop && dir != Stop && !autonomous && data == "n") {
dir = Stop;
movement(dir);
old_pos = pos;
}
}
// Function to check the distance of objects from the Ultrasonic sensor
float check() {
// Ultrasonic
// Clears the trigPin condition
digitalWrite(trigPin, HIGH);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 2 microseconds
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)
// Serial.println(distance);
return distance;
}
// Function to search for the maximum distance from the Ultrasonic sensor by moving
// the servo to the right and left and testing the Distance from objects
int search() {
max_distance = 0;
saved_pos = 90;
for (pos; pos >= 0; pos--) {
myservo.write(pos);
delay(15);
if (check() > max_distance) {
max_distance = distance;
saved_pos = pos;
}
}
delay(500);
for (pos = 0; pos <= 180; pos++) {
myservo.write(pos);
delay(15);
if (check() > max_distance) {
max_distance = distance;
saved_pos = pos; // Saved position of the maximum distance
}
}
if (saved_pos > 90) dir = Left;
else if (saved_pos < 90) dir = Right;
for (pos; pos >= saved_pos; pos--) {
myservo.write(pos);
delay(15);
}
return dir; // Return the direction of the maximum distance
}
// Function to move the motors in certain direction which a receiving a control parameter (1 -5)
void movement(int direction) {
switch (direction)
{
case Forward:
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
break;
case Reverse:
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
break;
case Left:
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
break;
case Right:
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
break;
default:
// Will stop the car;
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
break;
}
}
Comments