Table of Contents
This is the third and final installment of my series on constructing and programming the Elegoo Smart Robot Car Kit. If you haven’t read part 1 and part 2 you might want to take a look at them first.
Introduction
The Elegoo Smart Robot Car Kit is a very capable yet inexpensive Arduino-based robotics car that boasts some very impressive features. It is an ideal kit for first-time Arduino builders and is also a very practical kit for advanced users who want a robot car base for code development.
In the first part of this series, I assembled the car and gave it a quick test. The second installment covered both the Bluetooth and Infrared remote control functions.
In this, the final installment of the series, I will be examining both the Collision Avoidance and Line Following features of the robot car. We will start with the collision avoidance system.
Collision Avoidance Components
The collision avoidance system in the Elegoo Smart Robot Car employs an HC-SR04 ultrasonic sensor which is mounted on an SG90 servo motor at the front of the car. The motor is set to sweep the sensor 180°, permitting it to examine for obstacles on the left, right and straight ahead of the vehicle.
In the image above you can see that I am pointing to the location of the ultrasonic sensor on the robot car.
HC-SR04 Ultrasonic Sensor
The HC-SR04 is a very popular ultrasonic sensor, I have already covered the operation of this device in a separate article “Using the HC-SR04 Ultrasonic Distance Sensor with Arduino”.
The operation of this device is quite simple. It consists of two ultrasonic transducers, one transmitter, and one receiver. The transmitter sends out a pulse of ultrasonic sound which will be reflected off of any solid object in front of it. The receiver listens for the reflected pulse and, if it detects it, measures the time delay between transmission and reception. This time delay can be used to calculate the distance to the solid object.
On the Elegoo Smart Robot Car, the ultrasonic sensor is mounted on a bracket that allows it to be positioned on the shaft of a servo motor. It is connected to the custom Arduino Shield using a 4-conductor cable.
If you plan to modify your car you will want to be sure not to obstruct the sensor or it won’t be able to do its job.
The ultrasonic sensor has four connections:
- VCC – This is the 5-volt positive power connection.
- TRIG – This is the “Trigger”, an input for the pulse we will be sending from the ultrasonic transmitter.
- ECHO – This is an output that sends back the received pulse.
- GND – The Ground connection.
The Arduino Uno on the robot car is used to control the ultrasonic distance sensor.
SG90 Servo Motor
The servo motor that positions the ultrasonic sensor is a very common type, the SG90. We have used these servo motors in many projects before. If you need an update on the operation of servo motors you can check out my article “Using Servo Motors with the Arduino” for a complete guide to using them.
Essentially a servo motor is a DC motor that has an internal “servomechanism”, a method of controlling the position of the motor shaft with an internal feedback mechanism. Most servo motors, including the SG90 used in the robot car, are restricted to turning just 180° (some can turn 270°).
In order to control the servo motor, a pulse is sent to it. The width of the pulse determines the desired position of the servo. The servo motors internal controller receives the pulse and positions the motor shaft in the appropriate position.
There are only three connections on the SG90 servo motor:
- GND – The ground connection.
- POWER – A voltage that both drives the internal motor and the internal controller. The SG90 requires 5 to 6 volts.
- CONTROL – The control input, a logic-level input for the pulse to determine the shaft position.
Once again the Arduino Uno is used to control the servo motor.
The SG90 is not a particularly powerful servo, it’s rated at only 1kg/cm (17.5oz /in), but it has more than enough torque to spin the ultrasonic sensor and its bracket.
Aligning the Sensor Assembly
In order for the collision avoidance system to function properly, the ultrasonic sensor assembly must be positioned correctly on the servo motor shaft.
The servo is capable of rotating 180°, so at the 90° position the ultrasonic sensor needs to be facing directly forward.
When we first assembled the robot car we just mounted the sensor bracket onto the servo motor in the position that the servo happened to be resting in at the time. The bracket is held onto the servo shaft with a small Phillips head screw.
In order to align the sensor correctly, we need to remove it from the servo, set the shaft to the 90° position, and then remount the assembly with the sensor facing directly forward.
I would recommend powering down the car and disconnecting the cable from the ultrasonic sensor assembly first, it will make removing and reinstalling the sensor a lot easier.
Once you have the sensor assembly removed you’ll need to position the servo motor shaft in the correct 90° position. Elegoo has provided a very simple sketch that does exactly that. It’s available on the CD ROM that is included with the kit as well as in the download from the Elegoo website.
Servo Test Sketch
Here is the “Servo Debug” sketch that Elegoo has provided:
1 2 3 4 5 6 7 8 9 10 11 |
//www.elegoo.com #include <Servo.h> Servo myservo; void setup(){ myservo.attach(3); myservo.write(90);// move servos to center position -> 90° } void loop(){ } |
The sketch is simplicity itself!
The sketch begins by including the Servo library, this library is usually already installed in your Arduino IDE but if it isn’t Elegoo has provided instructions for installing it.
Next, an object named myservo is created to represent the servo motor we are controlling.
In the Setup we attach the servo control line on Arduino pin 3 to the myservo object. We then position that servo at 90°.
And that’s all there is to it! There is no code in the loop, the sketch just positions the servo and then stops. If you want to run it again you’ll need to press the Reset button on the Arduino or on the shield.
Once the sketch has run you can put the ultrasonic sensor assembly back onto the servo motor shaft, making sure to position it facing directly forward. After that, you can secure it with its mounting screw.
When you have the sensor in place you can power down the car and reconnect the cable to the ultrasonic sensor. You are now ready to load the collision avoidance sketch.
Collision Avoidance Sketch
As with all other aspects of the car, a very basic collision avoidance sketch has been provided by Elegoo. I’ll get to it in a moment but first, we should discuss how it actually works. Knowing this will assist you in creating a much better sketch should you wish to improve the car’s performance.
Collision Avoidance – Principle of Operation
The principle of collision avoidance is really quite simple, as follows:
- Stop the car.
- Measure the distance to the nearest object in multiple directions.
- Turn the car in the direction that you measure the longest distance.
- Start the car, then repeat when you encounter another object.
There are many variations among collision avoidance sketches, the Elegoo one is pretty simple.
- It begins by stopping the car.
- It measures the distance to the object directly in front of it.
- If the distance is more than 20 centimeters it proceeds ahead and tests again in half a second.
- If the distance is less than 20 centimeters it stops and checks the far left and far right. Whatever distance is greater determines which way it turns. It then proceeds in that direction for half a second.
- If none of the distances are greater than 20 centimeters it reverses for half a second.
- It then repeats itself.
This works but it is subject to errors, especially if an object enters its path during the half-second driving period. It also only measures in three directions (left, right and ahead).
Nonetheless, it is a good beginning, a basis for writing a more advanced sketch. Let’s take a look at it.
Collision Avoidance Sketch – Elegoo
Here is the collision avoidance sketch provided by Elegoo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
//www.elegoo.com #include <Servo.h> //servo library Servo myservo; // create servo object to control servo int Echo = A4; int Trig = A5; #define ENA 5 #define ENB 6 #define IN1 7 #define IN2 8 #define IN3 9 #define IN4 11 #define carSpeed 150 int rightDistance = 0, leftDistance = 0, middleDistance = 0; void forward(){ analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); Serial.println("Forward"); } void back() { analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); Serial.println("Back"); } void left() { analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); Serial.println("Left"); } void right() { analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); Serial.println("Right"); } void stop() { digitalWrite(ENA, LOW); digitalWrite(ENB, LOW); Serial.println("Stop!"); } //Ultrasonic distance measurement Sub function int Distance_test() { digitalWrite(Trig, LOW); delayMicroseconds(2); digitalWrite(Trig, HIGH); delayMicroseconds(20); digitalWrite(Trig, LOW); float Fdistance = pulseIn(Echo, HIGH); Fdistance= Fdistance / 58; return (int)Fdistance; } void setup() { myservo.attach(3); // attach servo on pin 3 to servo object Serial.begin(9600); pinMode(Echo, INPUT); pinMode(Trig, OUTPUT); pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(IN3, OUTPUT); pinMode(IN4, OUTPUT); pinMode(ENA, OUTPUT); pinMode(ENB, OUTPUT); stop(); } void loop() { myservo.write(90); //setservo position according to scaled value delay(500); middleDistance = Distance_test(); if(middleDistance <= 20) { stop(); delay(500); myservo.write(10); delay(1000); rightDistance = Distance_test(); delay(500); myservo.write(90); delay(1000); myservo.write(180); delay(1000); leftDistance = Distance_test(); delay(500); myservo.write(90); delay(1000); if(rightDistance > leftDistance) { right(); delay(360); } else if(rightDistance < leftDistance) { left(); delay(360); } else if((rightDistance <= 20) || (leftDistance <= 20)) { back(); delay(180); } else { forward(); } } else { forward(); } } |
The Sketch begins by including the Servo library and then creating a myservo object to represent our servo motor, exactly as we did with the servo debug sketch.
Next, a couple of integer variables are defined to represent the pins for the HC-SR04 ultrasonic sensor. Note that a couple of the Analog pins are used, in this sketch these pins are being used as digital I/O pins instead of as analog inputs.
After that, we define some constants to use for controlling the L298N H-Bridge motor controller. Another constant named carSpeed is also defined and given a value of 150 (which I ended up changing on my robot car, more on that later).
Finally, there are three integers defined to represent the right, left and middle(forward) distance. They are set to a value of 0 to begin with.
The forward, back, left and right functions should look pretty familiar by now if you have been folowing this series, they are almost identical to the equivalently named functions in previous sketches with one exception – the carSpeed variable is used in each of them to lower the speed of the car.
To understand these four functions you need to know how the L298N H-Bridge motor controller works, if you need a refresher course please see my article “Controlling DC Motors with the L298N Dual H-Bridge and an Arduino”.
The stop function just disables all of the motors.
The Distance_test function is used to drive the HC-SR04 ultrasonic sensor and measure the distance. It works by producing a pulse that goes low for 2 microseconds and then high for 20 microseconds. This pulse is used to drive the trig (trigger) input on the HC-SR04. Then the Arduino pulseIn function is used to measure the received pulse from the echo pin on the ultrasonic sensor. The result is divided by 58 to get the distance in centimeters, this result is returned by the function as an integer.
In the setup we attach the servo control lead on digital I/O pin 3 to the myservo object. We then set up the serial port, which can be used to monitor the motor control functions if you have a very long USB cable. After that, the Arduino pinMode function sets all of the pins except the echo pin as inputs. Finally, we call the stop function to ensure that the robot car isn’t moving when we first switch it on.
Now on to the loop.
We start the loop by positioning the servo motor at the 90° position, in other words facing straight forward. We then delay for half a second, after which we do a distance test and set the value of the middleDistance variable.
If the value of middleDistance is less than 20 centimeters then we evaluate the right and left distances. We do this by moving the servo motor in each direction and then doing a distance test.
If we find a distance that is more than 20 centimeters then we turn the car in that direction. If we don’t then we go backward.
Modifications to Sketch
When I tested the sketch I found that the carSpeed value was too little to allow the robot car to move left or right. So I set the value to 220. I did this in the previous tests with the remote controls as well.
By doing this I was able to move left and right properly, however since I was now driving the car faster I needed to increase the distance it was looking for to 40 centimeters.
In retrospect, I should actually have used a separate variable for the forward and backward car speed. I also should have fine-tuned the delay times for each directional move as I don’t think the robot car was really turning a full 90 degrees.
I would advise you play with the values to get everything working to your satisfaction. Remember, the code that Elegoo has provided is just meant to get you started. The real fun is in developing your own code.
Line Following Principle & Components
Now that we have covered the collision avoidance feature of the Elegoo Smart Robot Car it’s time to focus on the line tracking (or line following) capabilities.
Line folowing is a very common robotics application and it can be done in several ways. The most common method, and the one employed with the Elegoo Smart Robot Car, is to have a dark line on a light background and use optical sensors to determine its position.
Line folowing can also be done with ultraviolet sensors and fluorescent paint, this method can be used to track lines on surfaces that vary in color. It also has the advantage of being invisible if you use the correct type of fluorescent paint.
Another, more esoteric method is to use a wire that has an audio or radio signal and have a sensor to pick up the signal with a small antenna. This usually is done in a more permanent installation with the wire embedded in the floor or placed under a carpet.
Line Following Operation
With any line following method the same basic principles are applied.
Line followers use a sensing device that consists of at least three sensors, many actually use several sensors. These sensors are aimed down at the floor to sense the line they are to follow.
Sensors like the one in the Elegoo Smart Robot Car use LEDs and light sensors. The light is beamed down at the floor and is reflected back.
A dark surface will reflect very little light while a light surface will reflect the light fairly efficiently. The sensors are tuned to a threshold so that a dark surface can be distinguished from a light one.
The object of the sensor and the code that drives it is to keep the detected line directly under the middle sensor. So if the sensor on the right or left detects the line then the software (the Arduino sketch in this case) will instruct the robot car to move in the appropriate direction to reposition itself correctly.
Line Following Sensor on Robot Car
The Elegoo Smart Robot Car uses a line tracking device with three IR source/sensor elements. The sensor array is mounted at the bottom of the car and is connected to the Arduino shield using a 5-conductor cable that carries the sensor outputs and power supply.
The line tracking unit also has a sensitivity adjustment, this sets the threshold between dark and light objects. If you find your car is unable to track the line accurately you can adjust this to correct the situation.
Line Following Sketch
Let’s take a look at the Line Tracking Car sketch provided by Elegoo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
//www.elegoo.com //Line Tracking IO define #define LT_R !digitalRead(10) #define LT_M !digitalRead(4) #define LT_L !digitalRead(2) #define ENA 5 #define ENB 6 #define IN1 7 #define IN2 8 #define IN3 9 #define IN4 11 #define carSpeed 150 void forward(){ analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); Serial.println("go forward!"); } void back(){ analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); Serial.println("go back!"); } void left(){ analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); digitalWrite(IN3, LOW); digitalWrite(IN4, HIGH); Serial.println("go left!"); } void right(){ analogWrite(ENA, carSpeed); analogWrite(ENB, carSpeed); digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); digitalWrite(IN3, HIGH); digitalWrite(IN4, LOW); Serial.println("go right!"); } void stop(){ digitalWrite(ENA, LOW); digitalWrite(ENB, LOW); Serial.println("Stop!"); } void setup(){ Serial.begin(9600); pinMode(LT_R,INPUT); pinMode(LT_M,INPUT); pinMode(LT_L,INPUT); } void loop() { if(LT_M){ forward(); } else if(LT_R) { right(); while(LT_R); } else if(LT_L) { left(); while(LT_L); } } |
The sketch starts by defining the readings from the three sensors on the line tracking device. It takes the readings using the Arduino digitalRead command and inverts them.
Next, we define the inputs to the L298N motor driver and we also set the carSpeed variable. As with the previous sketches, I found it necessary to increase the value of this variable to execute left and right turns correctly.
The forward, back, left and right functions are identical to the ones we looked at in the previous sketch, as is the stop function.
In the Setup, we simply set up the serial monitor speed and define the three connections to the line tracking sensors as inputs.
And finally the loop, which is surprisingly simple.
In the loop we check the values (HIGH or LOW) of the inverted outputs from each sensor. If the middle sensor is high then we simply move forward. If it isn’t then we check the right and then left sensors, depending upon which one is HIGH (indicating it is positioned over the line) we turn the car until it goes LOW. And then we repeat the loop.
The result is that the car follows the line perfectly!
You can give the line folowing sketch a test by using the small roll of electrical tape that Elegoo has provided to make your own test track. If you find it isn’t tracking correctly try adjusting the sensitivity potentiometer on the line tracking sensor assembly.
Conclusion
The Elegoo Smart Robot Car is a great value when you consider all of the parts that you get, it even comes supplied with the tools required to put it together. It can be used as the basis for several different robot car experiments for Arduino enthusiasts of all skill levels.
Have fun and try and modify the sketches to suit your own needs. Try combining them to make a collision avoiding robot that can be controlled by Bluetooth. You can also add a few LED’s, a piezo buzzer or other components to customized your car.
Now get you driving gloves on and give it a test drive!
Parts List
Here are some components that you might need to complete the experiments in this article. Please note that some of these links may be affiliate links, and the DroneBot Workshop may receive a commission on your purchases. This does not increase the cost to you and is a method of supporting this ad-free website.
COMING SOON!
Resources
Elegoo Smart Robot Car – The car on the Elegoo website, it is also available at Amazon.
Elegoo Download – The contents of the CD ROM included with the car. Contains all the code samples as well as instructions for bu8ilding and using the robot car.
information about “#define LT_R !digitalRead(10)”……….
Combining line tracking and obstacle avoidance My son is doing a grade 5 science fair project – he was hit by a car 2 years ago, so now is very interested in learning how cars could be made to follow tracks and stops if it encounters an obstacle with sensor technology. His experiment is not to learn how to write all of the code, but just to understand how you build it and the components involved and their functions. He has built the smart robot car on his own and is wanting to have the code to do both line… Read more »
Hello,
I have a Question, how can I combine line tracking with ultrasonic sensor?
Is there any chance you could do an article on how to add optical encoders to this kit? I just ordered and received one based on your recommendation and would love to enable it with the ability to calculate distance and speed but am unsure of what parts best to order and how to fit them (or indeed even if it is possible given the physical limitations of the kit).
Finally I would like to thank you for providing such a wonderful resource. I don’t think I’ve come across anything else of the standard you provide with such wonderful clarity.
For example, would these be suitable? I have no idea!
https://tronixlabs.com.au/robotics/encoders/wheel-encoders-for-dfrobot-3pa-and-4wd-rovers-australia/
Hi Bill, Sometime ago, I built a bluetooth controlled robot based on a 4 wheel drive chassis that I purdhased from Hobby King. After watching you video on the Elegoo car, I decided I’d add an UltraSonic sensor mounted on a servo to mine. After some initial issues with power supply, and my loop timing, I got it working fairly well. My one remaining problem area is that the sensor doesn’t detect round table/chair legs, and when it approaches a wall at about 45 degree angle. Is this a drawback with this type of sensor? Do you have any comments… Read more »
Great informative video, thanks again
By the way, what sensor do you use so the car doesn’t fall off a platform, and just stops and turns around?
thanks again
Do you ever get a reply on here?
Angelo, I use IR sensors. The same used in a line follower.
Check the example below:
void checkDropOff() {
// IR threshold indicating drop-off (table edge, hole, etc.)
int dropOff = 950; // adjust value if necessary
// get IR sensor readings
int leftSensor = leftLine.read();
int centerSensor = centerLine.read();
int rightSensor = rightLine.read();
// see if any IR sensors detect drop-off
if (leftSensor > dropOff || centerSensor > dropOff || rightSensor > dropOff) {
// add code to perform (brake, reverse, change direction, etc.)
motors.brake();
}
}
I will try that, thanks for answering
Hi, thanks for answering
I purchased a pixy and your video was very important
I also purchased the tilt – works great – tracks everything I teach it to
Are there any sketches to connect the pixy cam with the robot car you demonstrated?
I also have the car. That would be a great connection.
I keep watching your teaching videos, thanks for all your work
Excellent video! Thank you.
A few question:
1) I’m assuming this is C++. can we add our own classes in separate files?
2) Can we programatically get input from the remote?
3) Can we add components more relatively easily to the robot and access them programatically?
Great website and tutorials. My 8y.o. and I are building this car now. Do you know what pins are available to add additional sensors or outputs like lights or an LCD?
Great series of videos.
The setup() for the line following “sketch” doesn’t look right, and I’m a bit surprised the car behaved correctly. Is it likely that pins are setup as “INPUT” by default anyway if not explicitly specified?
line 65: pinMode(LT_R,INPUT);
will compile as
line 65: pinMode(!digitalRead(10),INPUT);
So, it’s really just setting up pin 1 or 0 based on returned value of the digitalRead().
pinMode(1 ,INPUT);
or
pinMode(0 ,INPUT);
Correctly, they’d need to setup pins 10, 4 and 2 for the 3 IR sensors
pinMode(10,INPUT);
I found this little robot car video series quite interesting! I remember as a young man (1984) having a robot that I could program (Omnibot 2000 by TOMY(C) ) that would use a cassette tape for program storage! It was quite the feat for the 80s but it was short lived! What I would like to do is use this robot car to remake the Omnibot using today’s electronics! No more tape memory but using a micro SD like a data logger to save programs on to be played back. I have an Omnibot 5402 robot and he functions quite… Read more »
Sir can I use same thing for doing my industry level project