Many of us have some toy at home that we have kept without knowing what to do with it. Maybe because we don't know how to use it, or it has very simple functions (as in my case) and thus has become a bit too boring. I wanted to expand the functions. So we can put together a bit of ingenuity, a bit of our favorite hobby and the toy and make changes with these elements. With that, we have a good time and a toy almost made by us. Since you probably don't have the same toy car, this blog post serves as inspiration. I'm also applying the controls to the Smart Robot Car Kit. More on that below.
In this case, the toy chosen is a toy store car that has only a DC motor on the rear wheels with a two-position switch for forward or reverse. To be able to steer, it has a wheel on the roof that manually drives a gear mechanism.
The modification we will make will be to install four DC motors (one per wheel). We will make a new steering mechanism that will be driven by a servo motor. For autonomous driving, we will install ultrasonic sensors. They will determine the distance to obstacles. The control system will react accordingly by driving the car forward or backward, or turning right or left.
We will also use the same features for the Smart Robot Car 2WD from AZ-Delivery use. Since this car has no steering mechanism, the conversion is very simple. We will only need to install the side ultrasonic sensors.
Once we have selected the car that we want to convert, we prepare a cup of coffee or tea and start planning. The first thing we need to know is what components we need for each case.
Hardware and components needed
1 |
|
1 |
|
2 |
SG90 Micro Servo Motor 9G (alternatively here) or MG90S Micro Servo Motor |
1 |
|
3 |
HC-SR04 Ultrasonic Module Rangefinder (alternatively here) |
1 |
|
4 |
|
1 |
|
4 |
AA batteries |
When you use the Smart Robot Car Kit:
1 |
|
2 |
HC-SR04 Ultrasonic Module Range Finder (alternatively here) |
Software used
- Arduino IDE
- Ultrasonic Sensor Library (Elegoo, h)
- Adafruit Motorshield Library v1 (via Library Manager h)
- Servomotor library (integrated h)
- ino sketch
If you are using the Smart Robot Car Kit:
- Arduino IDE
- Ultrasonic Sensor Library (via Library Manager h)
- Servo motor library (integrated h)
- ino sketch
First we will develop and explain the modification of the toy car and then we will do the same with the Smart Robot Car.
Circuit and description of the components used
According to the component plan, to move the four DC motors we will use the module "4-channel L293D motor driver shield". It simplifies the programming of the motors and eliminates many cables. Also, we only need one object in the sketch for each motor with which we can select the motor speed and work with the forward, reverse and stop commands. Since this is a shield module, we only need to connect it to the ATmega328 microcontroller and they form one unit.
We will use two SG90 microservo motors one of which will drive the steering of the vehicle and the other will perform a small 40-degree slew with the front ultrasonic sensor. The HC-SR04 ultrasonic sensors inform us about the distance to objects or obstacles. The 4 DC motorsI used are the usual motors for robotcar kits. For the power supply of the whole kit I used two external 5V DC batteries with 1A, but you can use any battery set that provides a minimum voltage of 5V DC.
Pay close attention to the maximum power consumption of the different modules.
Modification of the steering system of the vehicle
I will briefly explain how I changed the steering system of the car.
The car's manual system had a wheel on the roof that moved gears. These gears moved a shaft that went to the front of the car to move the steering. As you can see from the picture, the system is very cumbersome and is also manually operated. |
|
The new steering system is operated by the respective servo motor acting on the associated front wheel and via the rigid front crossbar. The entire assembly is attached to the chassis by two axles that correspond to the green dots in the picture. In this way, when the servo motor is actuated, the entire assembly moves and pivots at these two points. On the left side of the picture you can also see the servo motor to which we will attach the front ultrasonic sensor. |
Description of the operation of the vehicle and the sketch
The three ultrasonic sensors are the "eyes" of the car. The microcontroller sends signals to the ultrasonic sensors so that they continuously emit pulses. When they bounce off an object, the sensor receives the signal and transmits it to the microcontroller. The elapsed time is divided by two because the signal must go back and forth. With the information about the time taken and the data about the speed of sound, the distance to the object is calculated. The information of each sensor is stored in variables and compared with the distance limits permanently in a multiple loop with if-else conditions. Distances to objects are measured, which can be on the right, left and in front of the car. If the distance is larger, the car continues, if one of the distances is smaller, it compares the distance between the right and the left side. If the right side is greater and the distance to an object is greater than the limit, it turns to the right. If the distance between the right side is smaller than the left side, it checks if the left distance to an object is larger than the limit value. If so, it would turn to the left. If the three distances happen to be less than the limits we programmed, the car will stop and reverse for 2 seconds, then start the distance checking process again. Depending on the condition, the microcontroller performs some actions to activate the H-bridges of the L293D chips of the motor shield module to turn the motors in one direction or another.
Let's start with the development of our sketch. In order to use the servo motors, the ultrasonic sensors and the motor control board, we need to include their libraries at the beginning of the sketch. I have chosen these SR04-library because I have been using it for a long time and never had any problems with it. You have to download and unpack it. In the subfolder you will find the ZIP file HC-SR04.zip, which you can install in the Arduino IDE via the menu Sketch->Integrate library->Add.ZIP library.
#include "SR04.h" #include <AFMotor.h> #include <Servo.h>
After adding the libraries, we need to proceed with the implementation and configuration of all installed components. We will start with the implementation of the ultrasonic sensors. We need to tell the microcontroller which pins we have connected the pins of each sensor to. One that sends the signal (ECHO) and one that receives the signal (TRIG) after hitting the object. Next, we need to create a name for each sensor with some parameters. This is done by implementing an object from the SR04 library that contains the name of the sensor and, as parameters, the names of the pins to send and receive the signal. Now we need to store the distance data, for which we define a variable for each sensor.
#define TRIG_PIN_RIGHT 15 #define ECHO_PIN_RIGHT 14 SR04 ultrasonics_sensor_right = SR04(ECHO_PIN_RIGHT,TRIG_PIN_RIGHT); long right_distance; #define TRIG_PIN_LEFT 17 #define ECHO_PIN_LEFT 16 SR04 ultrasonics_sensor_left = SR04(ECHO_PIN_LEFT,TRIG_PIN_LEFT); long left_distance; #define TRIG_PIN_FRONT 19 #define ECHO_PIN_FRONT 18 SR04 ultrasonics_sensor_front = SR04(ECHO_PIN_FRONT,TRIG_PIN_FRONT); long front_distance;
Now follows the implementation of the two servo motors. We create an object for each servo motor. The pins to which we connect the signals of the servo motor will be defined later in the setup()-method of the sketch.
Servo servo_steering; Servo servo_ultrasonic_front;
The "4-channel L293D Motor driver Shield" is the last component we need to configure and implement so we can manage the control of the motors. We need to create a library object for each output channel of the motor control. In our case it will be the 4 channels. As parameters we have to specify the port number and the frequency of the working signal. According to the microcontroller's datasheet, ports 3 and 4 work only with a frequency of 1KHz, so we configure all ports with this frequency. Besides, at this update rate the power consumption is lower, so we can save the battery.
It is very important to remove the corresponding jumper on the shield, because we will supply the board with external voltage and not from the microcontroller.
AF_DCMotor right_front_motor(1, MOTOR12_1KHZ); AF_DCMotor left_front_motor(2, MOTOR12_1KHZ); AF_DCMotor left_rear_motor(3, MOTOR12_1KHZ); AF_DCMotor right_rear_motor(4, MOTOR12_1KHZ);
Now we have to setup()-method. In it we define the pins to which we connect the lines of the servo motors. Here we use the PWM output of the digital pins. Fortunately, since we are working with a shield module and its library, we only need to specify a number between 0 and 255, which is the minimum and maximum value, respectively.
The first two lines of the setup()-method are very simple: we initialize the Serial Monitor and output a message on it.
Serial.begin (9600); Serial.println ("Motors test");
Now we define here the pins to which we send the signals for the two servo motors.
servo_steering.attach(9); servo_ultrasonic_front.attach(10);
Now we configure the rotation speed of the motors and the initial state of them when the microcontroller is initialized or reset. The rotation speed is set with the instruction motor_name.setSpeed(120) to half the maximum speed and the motors must be stopped, the latter is done with the instruction motor_name.run(RELEASE) configured.
left_front_motor.setSpeed(120); left_front_motor.run(RELEASE); right_front_engine.setSpeed(120); right_front_motor.run(RELEASE); left_rear_motor.setSpeed(120); left_rear_motor.run(RELEASE); right_rear_motor.setSpeed(120); right_rear_motor.run(RELEASE);
At the end of the setup()-method, we call two methods to check the servo motors before our car starts moving. We will explain these methods later.
servo_ultrasonic_front_check(); servo_steering_check();
The loop() method is very short because the actions have been outsourced to methods. This makes the code cleaner and clearer. The only line of this loop()-method is the call to the method for executing the swivel movement of the servo motor of the front ultrasonic sensor.
servo_ultrasonic_scan();
The method performs a pan by positioning the servo motor at three angles (70, 90, and 110 degrees). Once positioned at each of these angles, the three methods are called to measure the distance of possible objects or obstacles to the right, left, and front. After the measurement of the front distance, the method object_distance_compare() is called to compare the three measurements and perform a specific action with respect to the direction of the vehicle.
void servo_ultrasonic_scan() servo_ultrasonic_front.write(90); right_distance_object(); left_distance_object(); front_distance_object(); object_distance_compare(); servo_ultrasonic_front.write(70); right_distance_object(); left_distance_object(); front_distance_object(); object_distance_compare(); servo_ultrasonic_front.write(90); right_distance_object(); left_distance_object(); front_distance_object(); object_distance_compare(); servo_ultrasonic_front.write(110); right_distance_object(); left_distance_object(); front_distance_object(); object_distance_compare(); servo_ultrasonic_front.write(90); }
I explain the methods mentioned above. The first three after positioning measure the distances to objects or obstacles the car encounters on its way. The ultrasonic sensor measures the distance to the nearest object or obstacle and stores this distance in the variable we defined at the beginning. We display the distance data through the serial monitor. There is a separate method for each sensor.
void right_distance_object() { right_distance = ultrasonics_sensor_right.Distance(); Serial.print("Distance to obstacles on the right "); Serial.print(right_distance); Serial.println(" cm"); delay(100); } void left_distance_object() { left_distance = ultrasonics_sensor_leftt.Distance(); Serial.print("Distance to obstacles on the left "); Serial.print(left_distance); Serial.println(" cm"); delay(100); } void front_distance_object() { front_distance = ultrasonics_sensor_front.Distance(); Serial.print("Distance to front obstacles "); Serial.print(front_distance); Serial.println(" cm"); delay(100); }
The following method compares the measurements taken by the previous sensors with nested if-else conditions. Depending on the result, a specific method is called if the respective condition is met. The first line compares the values measured by the three ultrasonic sensors. If all three values match, the method car_advances() is called. If, on the other hand, one of the three measured values is lower, the second line is executed, which checks whether the existing objects are further away on the right than on the left and whether they are also further away than 30 cm. If so, the method turn_right() is called. If the distance to the left is greater than to the right and the objects are also more than 30 cm away, the method turn_left() is called. The last line calls the method go_back() if the three distances to be checked are smaller than the one we configured.
void object_distance_compare () { if (front_distance >= 100 && right_distance >= 30 && left_distance >= 30) { car_advances(); } else { if (right_distance > left_distance && right_distance >= 30) { turn_right(); } else { if (left_distance > right_distance && left_distance >= 30) { turn_left(); } else { if (front_distance < 100 && right_distance < 30 && left_distance < 30) { go_back();} } } } }
The method that makes our car go forward in a straight line positions the servo motor for the steering at an angle of 100 degrees and activates it with the instruction motor_name.run(FORWARD) to activate the pins of the microcontroller that allow the L293D Motor Shield module to supply the correct voltage to the correct motors to make the wheels turn forward. As a reminder, this method will run as long as the ultrasonic sensors measure distances to objects greater than or equal to the distances we set.
void car_advances() { servo_steering.write(100); left_front_motor.run (FORWARD); right_front_motor.run (FORWARD); left_rear_motor.run (FORWARD); right_rear_motor.run (FORWARD); }
If a measurement result of the ultrasonic sensors to an object is less than the specified measurement, the measurements of the lateral sensors are compared. if there is a greater distance on the right side than on the left side and this distance is also greater than the one we specified, the block of conditional commands calls the method turn_right() which causes the servo motor to position the direction of our car at 184 degrees. The motors then execute the set of commands to move forward. This way our car will turn right and then drive forward.
void turn_right() { servo_steering.write(184); left_front_motor.run (FORWARD); right_front_motor.run (FORWARD); left_rear_motor.run (FORWARD); right_rear_motor.run (FORWARD); }
Conversely, the method turn_left() is executed if the distance to the left determined by the side sensors is greater than to the right and also greater than the distance we set. This causes the servo motor to adjust the steering by 20 degrees so that the vehicle turns in that direction without stopping.
void turn_left() { servo_steering.write(20); left_front_motor.run (FORWARD); right_front_motor.run (FORWARD); left_rear_motor.run (FORWARD); right_rear_motor.run (FORWARD); }
The last method to call is go_back()which is executed if none of the previous three conditions are met. When the vehicle enters an area where the frontal obstacles are less than 1 meter and the side obstacles are less than 20 centimeters, the following commands are executed: Positioning the vehicle at an angle of 100 degrees, stopping the engines with the command. motor_name.run(RELEASE), pausing for 500 milliseconds and then stopping with the command motor_name.run(BACKWARD) for 2 seconds, which is the same as in the last line of the method delay(2000) corresponds to the time set.
void go_back() { servo_steering.write(100); left_front_motor.run(RELEASE); right_front_engine.run (RELEASE); left_rear_motor.run (RELEASE); right_rear_motor.run (RELEASE); delay(500); left_front_motor.run(BACKWARD); right_front_engine.run (BACKWARD); left_rear_motor.run (BACKWARD); right_rear_motor.run (BACKWARD); delay(2000); }
The last two methods receive the call from the setup()-method, so they are executed only once to check if the servo motors are working properly. The first one checks the servo motor of the front ultrasonic sensor. The positioning degrees are the same as in the method servo_ultrasonic_scan()but we program a delay of 500 milliseconds between positions.
void servo_ultrasonic_front_check() { servo_ultrasonic_front.write(90); delay (500); servo_ultrasonic_front.write(70); delay (500); servo_ultrasonic_front.write(90); delay (500); servo_ultrasonic_front.write(110); delay (500); servo_ultrasonic_front.write(90); }
The next and last method of the sketch checks the movement of the servo motor that drives the steering system of the vehicle. The servo motor is positioned at the working angles of the steering to check if it works properly. The center position of this servo motor in this car is 100 degrees, the position for the right turn of the car must be 184 degrees, for the left turn 20 degrees. The pause between the positions is 1 second.
void servo_steering_check() { servo_steering.write(100); delay (1000); servo_steering.write(20); servo_steering.write(100); delay (1000); servo_steering.write(184); delay (1000); servo_steering.write(100); }
Download toy_car_modification.ino sketch
Wf you do not see video at this point, clear your browser cookies, refresh the page and allow cookies.
AZ-Delivery Smart Robot Car Modification
The modification of the Smart Robot Car is a little different. We don't need the "4-channel L293D Motor driver Shield" module because it only has two motors. In this case, we use the "L298N Motor Driver Board" module, which also contains an H-bridge that provides the power needed to drive the two DC motors. Since we don't have a steering system, the change in direction is done by changing the direction of rotation of the motors. The "V5 Expansion Board Shield" module is used to connect all the components.
The process of obstacle detection and the actions to be taken are similar to those explained previously. The ultrasonic sensors measure the distance in a similar way, i.e. if the front and side obstacles are further away than the set distance, the car moves forward. When one of the sensors detects an obstacle at a distance less than the set distance, the distance to the side objects is compared and it turns in the direction that has a greater distance to an obstacle. If the three sensors detect that the distance to the obstacles is less than the set distance, the car moves backwards.
The difference between the two cars lies in the way the motors work and how they are programmed. In this case, with the "L298N Motor Driver Board" module, we do not have FORWARD, REVERSE and RELEASE commands. In order to get a motor to turn, we must first enable it and apply voltage across one of the two contacts on the motors. Depending on which contact is used to supply the voltage, it will turn in one direction or the other. In the "L298N Motor Driver Board" module, the EN A pin activates the IN1 and IN2 lines for one motor and the EN B pin activates the IN3 and IN4 lines for the second motor, so the programming of the motors is as follows: A motor is activated by setting the EN pin to HIGH and to turn the corresponding motor, one must set one of the two IN connections of the motor to HIGH and the other to LOW. If you change the state of the two connections, the motor will rotate in the opposite direction. In this sense we will use the AZ-Delivery Modify the Smart Robot Car.
To add the sensors and servos on the sides, some tinkering is necessary.
Description of the sketch
The first thing to do, as always, is to add the necessary libraries. In this case we only need the ones for the ultrasonic sensors and for the servo motor.
#include "SR04.h" #include <Servo.h>
In the following lines we declare 6 constants to name the pins of the microcontroller used to control the motors.
#define enable_right_motor 3 #define connection_1_motor_right 2 #define connection_2_motor_right 4 #define enable_left_motor 6 #define connection_1_motor_left 7 #define connection_2_motor_left 8
Next, the ultrasonic sensors and the servo motor of the front ultrasonic module have to be implemented. Both the connection pins and the designation of the sensors are the same as in the modification of the previous vehicle. The designation of the servomotor is also the same.
#define TRIG_PIN_RIGHT 15 #define ECHO_PIN_RIGHT 14 SR04 ultrasonics_sensor_right = SR04(ECHO_PIN_RIGHT,TRIG_PIN_RIGHT); long right_distance; #define TRIG_PIN_LEFT 17 SR04 ultrasonics_sensor_left = SR04(ECHO_PIN_LEFT,TRIG_PIN_LEFT); long left_distance; #define TRIG_PIN_FRONT 19 #define ECHO_PIN_FRONT 18 SR04 ultrasonics_sensor_front = SR04(ECHO_PIN_FRONT,TRIG_PIN_FRONT); long front_distance; Servo servo_ultrasonic_front;
In the setup()-method, the only differences are the missing steering servo motor and the way we configure the motors. We have to configure the pins of the microcontroller to which the "L298N Motor Driver Board" module is connected as OUTPUT. We will change their state between HIGH and LOW to enable the motors and supply voltage to their contacts depending on the desired direction of rotation. Connecting the servo motor signal and calling the method servo_ultrasonic_front_check() are identical.
pinMode(enable_right_motor,OUTPUT); pinMode(connection_1_motor_right, OUTPUT); pinMode(connection_2_motor_right, OUTPUT); pinMode(enable_left_motor,OUTPUT); pinMode(connection_1_motor_left, OUTPUT); pinMode(connection_2_motor_left, OUTPUT);
The methods loop(), servo_ultrasonic_scan(), right_distance_object(), left_distance_object(), front_distance_object(), object_distance_compare() and servo_ultrasonic_front_check() are exactly the same as in the previous chapter and perform the same functions as explained above.
The methods car_advances(), turn_right(), turn_left() and go_back() are responsible for supplying power to the two motor terminals to make the Smart Robot Car move forward, turn right or left, or go back. The first method I will explain is car_advances(). The first line of the comment shows us through the Serial Monitor that our car is moving forward. In the next line we set the right motor enable pin to HIGH. The next two lines are the two motor contacts. We set one pin to HIGH-level (supplies voltage) and the other to LOW-level, the motor will rotate in forward direction (if the motor rotates in the opposite direction, we just need to change the motor connections in the "L298N Motor Driver Board" module). The last 3 lines of the method are exactly the same as described above and are also valid for the other motor.
void car_advances() { Serial.println("Car advance"); digitalWrite(enable_right_motor,HIGH); digitalWrite(connection_1_motor_right,HIGH); digitalWrite(connection_2_motor_right,LOW); digitalWrite(enable_left_motor,HIGH); digitalWrite(connection_1_motor_left,HIGH); digitalWrite(connection_2_motor_left,LOW); }
The turn_right()-method causes the car to turn to the right. We can observe that the state of the pins to the right motor is opposite. This causes this motor to rotate in the opposite direction. So if the left motor is turning forward and the right motor is turning backward, our Smart Robot Car will turn quickly to the right around its imaginary center axis.
void turn_right() { Serial.println("Car turn right"); digitalWrite(enable_right_motor,HIGH); digitalWrite(connection_1_motor_right,LOW); digitalWrite(connection_2_motor_right,HIGH); digitalWrite(enable_left_motor,HIGH); digitalWrite(connection_1_motor_left,HIGH); digitalWrite(connection_2_motor_left,LOW); }
In the following two methods, only the states of the pins to the motors are swapped to make them turn one way or the other. This way the Smart Robot Car can move to the left or backwards.
If we don't want the rotation to be so abrupt, when we call to activate the motor we have to use digitalWrite(enable_name_motor,state) we have to set the parameter state to LOW set. This will allow us to disable the motor and regardless of the state of the motor contacts, it will not rotate in any direction and will stop while the other motor continues to rotate, so the rotation will be on the stopped wheel.
As you can see, the Smart Robot Car is very versatile. We could modify it to install two ultrasonic sensors to make it somewhat autonomous. It could also be modified to become a Smart Robot Car line follower, for example.
We hope you enjoy modifying your vehicle.
3 comments
Andreas Wolter
@Peter: danke für den Hinweis. Ich habe die Bibliothek bei Elegoo gefunden.
https://www.elegoo.com/blogs/arduino-projects/elegoo-hc-sr04-ultrasonic-sensor-module-tutorial?srsltid=AfmBOopaCMm85Id4_BEY0nQgkHdRq5842rVuoL-D8nexIS6iSioxxUe-
Der Sensor kann auch mit anderen Bibliotheken verwendet werden (wie z.B. die von Ihnen verlinkte). Es kann sein, dass man dann einiges am Code verändern muss. Wir werden das im Beitrag ändern.
https://www.arduinolibraries.info/libraries/hcsr04
oder über den Bibliotheksverwalter in der Arduino IDE
oder ohne Bibliothek, das geht auch
Grüße,
Andreas Wolter
AZ-Delivery Blog
Peter
Ich habe eine passende gefunden:
https://github.com/mrRobot62/Arduino-ultrasonic-SR04-library
Peter
Hallo Miguel,
der Link zur SR04-Bibliothek funktioniert leider nicht. :-)