In the first part of my story I have told how my son and I had become acquainted with Arduino and also I have told about first steps (or rather meters) of the robot composed on Arduino Uno 3 board. Now it’s a time to tell more about our construction job.
On the way we had become acquainted with Arduino and about first steps (or rather meters) of the robot composed on Arduino Uno R3, can be read here:
Для тех, кто не в танке или мое знакомство с Ардуино (про Ардуино вообще и про робота в частности). Часть 1.+116
17 янв. 2016 г., 12:58:20 | Александр Шаргаев Химки
Статья http://www.parkflyer.ru/blogs/view_entry/13158/


Now it’s a time to tell about our further work. I will start from disaster: once in attempt to upload the sketch the screen has showed incomprehensible message and… The board has stopped operation. The first suspicion was about ATMEGA 348 microcontroller, the heart of board. In this case the buying of new chip will not resolve the issue because “clear” microcontrollers will not working in Arduino board “as is” – it needs to be provided with particular firmware in advance. To be able to upload this firmware we need to use special programming device (of course, we haven’t it!) or another Arduino board with “right” microcontroller. We’ve taken second option as preferable – sure the redundancy board will be useful and it may be used for various modeling and “desktop” debugging for new fragments of program code. So we’ve ordered new board although the waiting was slowed down our activity.

While the board was on the way, we’ve tried to understand the cause of incident. The following idea was looking like this: the control shield for electrical motor has the button; this button cuts the motor power off. During the sketch uploading we’ve switched motor shield off by this button. But, as we were observed, wheels were twitched and high-frequency tone was coming from the bowels of robot. It looks like the microcontroller outputs were extremely overloaded and finally it has kill the chip. Probably we were wrong but anyway we didn’t found any other reason to explain the issue… At the same time we were thinking about further project development – we were composing the behavior algorithms of robot, we were drawing flowcharts, and we were learning books about C++ programming language and so on.

At last the new board had arrived and our ward had come back to life. The diagnostics by chip swapping between boards had confirmed our suspicions – the microcontroller was broken. We had buy new chip and had program it with correct firmware. Thus now we have two boards and we are happy. Also just in case, on motor shield board we’ve cut the printed wire going to pin connected to “5 V” female connector on Arduino board. When the shield is switched on, 5V voltage appears on this pin, and this voltage makes collision with 5V from Arduino board; anyway it is not well, I suppose.

Training processes for both son and robot were going forward. The first what we done is teaching the robot to select the route after stopping due to obstacle. How does it work: after stopping the “head” turns itself to left and the distance is measured; then the robot turns “head” to right and the distance is measured again; the distance ahead is already measured before the stopping. After that these three values are compared each to other. The robot will be turning to – left or right – where the distance is greater. If the distance ahead is greatest the robot will be performing reversal turn. Everything is simple and understandable. However the sketch with implementation of described algorithm had increased dramatically in size. Finally we had written the code, and even everything was working. But it was clear for us that further moving forward will produce a lot of difficulties – it will be too complicate to find errors and to make corrections when new features will be included to project.

So it’s time to learn subroutines which are normally named as functions in C language. What is the function? It is the code fragment, once written for any particular action, and then may be called many times from any code point with necessary parameters. We had written two functions at once – for turning and for distance measurement by ultrasonic sensor. The sketch had “slim” and became comfortable in reading immediately.

What is the next step? Son likes any light bulbs and other LEDs than the robot had been obliged to acquire “external lights”. Two bright white LEDs were installed in front as well as two usual red LEDs were fixed on backside. All LEDs are controlled by photo sensor; we’ve successfully used the photodiode from our ambry. The microcontroller must be able to receive the luminance level on its analog input pin therefore the resistor is necessary to build so-called voltage divider circuit. We had considered as unpractical the solution where the resistor is soldered directly over the photo diode; and it was only one implementation issue. We are using four LEDs so 5 volts powering from microcontroller board is not appropriate solution at all; clearly we need 12 V and transistor in the case. Where the transistor may be installed? Is it correct option to hang it on wires? Not so. Moreover the transistor needs, at least, one resistor at base circuit! Finally we had implemented the crucial solution. The extension board at the top of “sandwich” above motor shield was removed. We had decided to make our own shield on the bread board with appropriate dimensions – the connection board as we called it (of course, we could come up with any modern name, like “interface and matching module”… But we didn’t like it somehow).

Using of this board is profitable in several reasons. At first, on this board we had assembled the power supply based on IC КР142ЕН5А (translator’s note: IC L7805 is the functional analog). IC provides stabilized 5V power for all connected units; therefore powering circuit on Arduino board itself is unloaded. What is most important for the project like this – this IC is sustained to short-circuits and overloads.

Secondly, with this board we have enough space for comfortable placing of any necessary resistors, transistors, connectors and so on, what the soul of robot would wish. Besides, we may rebuild the content of board, if necessary, at any time, according to changing in tasks or equipments.

And thirdly, and it is most important, during continuous working process with the board young robot maker and I draw and discuss sketches, working principles for electronic components and circuits. Soldering experience is the best fun on the way, of course!

So, we had made the board for our current targets, we had installed the photo diode using the cover from relay board of Chinese car reverse camera:




Arduino has extremely comfortable feature for debugging – it is serial port monitor. It allows to display the value of any variable on screen and to watch what is happen during program execution. It was very interesting to watch how the voltage on analog input pin was varying with differ illumination of photo diode. Finally “outdoor light” is switched automatically. This is our Apollo:


What is the next step? Now we feared to switch motor shield and robot off in sketch uploading process. We were obliged to keep it or to underlay something; otherwise the robot could escape. To resolve the issue, we had installed the jumper on connection board (by the way, we were sure that idea with connection board is absolutely correct). The jumper was connected to one of Arduino’s input, the sketch was modified and – voila! While the jumper is in one position, you can program the robot or debug the code comfortably; the robot is patient. It’s enough to set the jumper to opposite position and to press Reset – yep! We are going!


With an eye to “increase intelligence” of robot we had introduced procedures for starting and for side watching in the movement. Now after switching on the robot “awakes”, it turns by “head” and blinks by LEDs (this is the point for further upgrading for us). In movement the robot “looks around” on both sides and watches the distances permanently. This is a short movie:



Also we had idea to sound our pupil, and this thing was ordered: WTV020-SD-16P U-Disk Audio Player SD Card MP3 Voice Module
Product http://www.rcfair.com/en/product/1685751/


But it was unworkable in testing; probably we had killed it successfully thanks to incorrect technical description we had. So now this feature is temporary postponed.

What’s next step? We will resolve the serious disadvantage of ultra-sonic distance sensor – it is absolutely blind in front of soft obstacles. Also the ultra-sonic signal is reflected aside when the robot comes near to obstacle with angle. Here we are hoping on infrared LEDs and TSOP photo sensors, at least we have got positive results in preliminary tests. It must work well: ultra-sonic sensor is effective on far distance as well as infrared will be useful on shorter one. Ok, we will tell about this issue next time.

One more issue: the velocity of robot movement goes down in battery discharge because the motor shield doesn’t manage the voltage. Of course, it’s possible to provide stabilized power for motor shield, but first of all we will try to resolve the issue by software.

And, it’s all at the moment. To be continued…

Good luck for everybody!!
This is working sketch for case which is running on video:
/* Control program for wheel robot. Author – Dmitry Shargaev, Khimki */
#include <Servo.h> // include the library for servos
#define servoPin 3 // output pin for servo
#define servoMinImp 800 // pulse duration for 0 degree position of servo
#define servoSeredImp 1250 // pulse duration for 90 degree position of servo
#define servoMaxImp 1700 // pulse duration for 180 degree position of servo

/*Digital inputs/outputs*/
byte outlightPin = 0; // pin for outdoor lightning
byte trigPin = 1; // pin for US sensor - trig
byte echoPin = 2; // pin for US sensor - echo
byte motlnPin = 4; // pin for left motor - direction
byte motlsPin = 5; // pin for left motor - speed
byte motrsPin = 6; // pin for right motor - speed
byte motrnPin = 7; // pin for right motor - direction

/*Analog inputs*/
byte stopPin = 0; // pin for motor stop jumper
byte fotoPin = 5; // pin for photo sensor input

/*Variables*/
long dist,distN,distL,distR; // distances measured by US sensor
int fotodat = 0; // photo sensor value
int mstop; // motor stop jumper value
int ugol; // angle of turn

/*Parameters*/
int lightlevel = 1010; // illumination threshold for outdoor lightning control (in 0 - 1023)
int mindist = 3500; // minimal distance of US sensor for reversal turn
int mindistD = 1500; // minimal distance of US sensor for head turn
byte v1 = 100; // gear 1 (max.allowed.value 255)100/150
byte v2 = 200; // gear 2 – reversal turn 200/250
byte z = 0; // counter of program cycles
byte kolz = 10; // the number of cycles between head turns in movement
Servo myServo;

void setup()
{
myServo.attach(servoPin, servoMinImp, servoMaxImp);
pinMode(outlightPin, OUTPUT); // set the mode of outer light control pin
pinMode(trigPin, OUTPUT); // set the mode of US sensor – trig pin
pinMode(echoPin, INPUT); // set he mode of US sensor – echo pin
pinMode(motlnPin, OUTPUT); // set the mode of left motor direction pin
pinMode(motlsPin, OUTPUT); // set the mode of left motor speed pin
pinMode(motrsPin, OUTPUT); // set the mode of right motor speed pin
pinMode(motrnPin, OUTPUT); // set the mode of right motor direction pin
}

//---------------------------------------------- SUBROUTINES -------------------------------------
//-------------------------------------------------------------------------------------------------

byte start() // start procedure
{
delay (3000);
myServo.writeMicroseconds(servoSeredImp); // head in forward
stp();
mstop = analogRead(stopPin); // checking the jumper presence
if (mstop>500)
{
v1 = 0; v2 = 0; // if the jumper found, speed = 0
}

digitalWrite(outlightPin, HIGH); // blinking by outer light
delay (100);
digitalWrite(outlightPin, LOW);
delay (100);
digitalWrite(outlightPin, HIGH);
delay (100);
digitalWrite(outlightPin, LOW);
delay (100);
digitalWrite(outlightPin, HIGH);
delay (100);
digitalWrite(outlightPin, LOW);
delay (100);
digitalWrite(outlightPin, HIGH);
delay (100);
digitalWrite(outlightPin, LOW);
delay (100); // ----------------------

myServo.writeMicroseconds(servoMinImp); // turn head to left
delay(200);
myServo.writeMicroseconds(servoMaxImp); // turn head to right
delay(200);
myServo.writeMicroseconds(servoMinImp); // turn head to left
delay(200);
myServo.writeMicroseconds(servoMaxImp); // turn head to right
delay(200);
myServo.writeMicroseconds(servoSeredImp); // head in forward
delay(2000);
z=1; // incrementing the program cycle counter
return z;
}

//----------------------------------------------------------------------------------------
void go()// movement ahead
{
digitalWrite(motlnPin, HIGH); analogWrite(motlsPin, v1);
digitalWrite(motrnPin, HIGH); analogWrite(motrsPin, v1);
}

//----------------------------------------------------------------------------------------
void stp() // stop
{
digitalWrite(motlnPin, HIGH); analogWrite(motlsPin, 0);
digitalWrite(motrnPin, HIGH); analogWrite(motrsPin, 0);
}

//----------------------------------------------------------------------------------------
void pov(int ugol) // turn
{
if (ugol<0)
{
digitalWrite(motlnPin, LOW); analogWrite(motlsPin, v2);
digitalWrite(motrnPin, HIGH); analogWrite(motrsPin, v2);
ugol=ugol*-1;
delay(ugol*5);
}
else
{
digitalWrite(motlnPin, HIGH); analogWrite(motlsPin, v2);
digitalWrite(motrnPin, LOW); analogWrite(motrsPin, v2);
delay(ugol*5);
}
}

//----------------------------------------------------------------------------------------
int izmdist() // distance measurement by US sensor
{
digitalWrite(trigPin, LOW); delay(10); // pause before measurement
digitalWrite(trigPin, HIGH); delay(10); digitalWrite(trigPin, LOW); // 10ms pulse on импульс trig pin
dist = pulseIn(echoPin, HIGH); // reading the distance from US sensor
delay(50);
return dist;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------

void loop()
{
if (z==0) // call start subroutine
{
start();
}

//----------- Switching off the outer light
fotodat = analogRead(fotoPin); // reading the luminance
if (fotodat>lightlevel) // checking
{
digitalWrite(outlightPin, HIGH); // switch light on
}
else
{
digitalWrite(outlightPin, LOW); // switch light off
}

//----------- Distance measurement
myServo.writeMicroseconds(servoSeredImp);
izmdist();
if (dist>mindist) // if the measureв distance is greater that minimal, we are going
{
go();
goto m10;
}

stp();
digitalWrite(outlightPin, HIGH);
delay (100);
digitalWrite(outlightPin, LOW);
delay (100);
digitalWrite(outlightPin, HIGH);
delay (100);
digitalWrite(outlightPin, LOW);
delay (100);
digitalWrite(outlightPin, HIGH);
delay (100);
digitalWrite(outlightPin, LOW);
delay (100);
digitalWrite(outlightPin, HIGH);
delay (100);
digitalWrite(outlightPin, LOW);
delay (100);

distN=dist;
myServo.writeMicroseconds(servoMinImp); // turn head to left than distance measurement
delay(500);
izmdist();
distL=dist;
myServo.writeMicroseconds(servoMaxImp); // turn head to right than distance measurement
delay(500);
izmdist();
distR=dist;

if (distN>distL) //1 searching the route after stop
if (distN>distR) //2
if (distL>distR) //3
pov(-180);
else
{
pov(180);
}
else
{
pov(90);
}
else
if (distL>distR)
pov(-90);
else
{
pov(90);
}
z = 1;
m10:; //----------------------------

if (z==kolz) //-------------------Turning the head in movement
{
myServo.writeMicroseconds(servoMinImp); // turn the head to left
delay (250);
izmdist();
myServo.writeMicroseconds(servoSeredImp); // head in forward
if (dist<mindistD)
{
pov(45);
}
}
if (z==kolz*2)
{
myServo.writeMicroseconds(servoMaxImp); // turn the head to right
delay (250);
izmdist();
myServo.writeMicroseconds(servoSeredImp); // head in forward
if (dist<mindistD)
{
pov(-45);
}
z = 1;
}
z++; //-----------------------------------------------

}
This is the translated version. You can read the original Russian article here.