Professional Documents
Culture Documents
Avoidance
Book 4 of the Arduino Short Reads Series
Gary Hallberg
The idea underpinning the Arduino short reads series is to provide a comprehensive, easy to follow
tutorial set and reference guide for anybody wanting to learn about Arduino and basic electronics.
Having a short reads series means that students and hobbyists can select key topics of interest in the
field with minimal outlay. The series aims to provide an easy introduction to all topics of interest and
expand on these topics to provide a broader and deeper understanding of that focus area. The books
are currently only available in Kindle format to provide a very inexpensive package backed up by video
content and interactive social media.
The series is aimed at youngsters and adults interested in getting into electronics and it takes a modern
approach combining the use of the inexpensive software driven Arduino controller board with a
multitude of sensors and discreet electronic components. The experiments in this series of books are
easy to follow, inexpensive to implement and compelling for all interested in STEM education. I hope
to inspire anybody looking for a future career in technology or to simply to have fun.
The first book of this series looks at the Arduino microcontroller and explains its operation and purpose.
Experiments look to show you how to set up the programming environment and drive LEDs as well as
read input from switches, thermistors and photocells. Book 1 will give you a solid foundation of how
some basic electronic components work and how to use them to make simple designs.
Books 5 to 8 in this Arduino short reads series are still being written but the series focuses on the
following:
• Book 1 – First Steps with Arduino (published)
• Book 2 – Working with Displays (published)
• Book 3 – Controlling Motors (published)
• Book 5 – Building a Simple Rover
• Book 6 – Arduino Special Functions
• Book 7 – Communications with Arduino
• Book 8 – The Arduino Leonardo
If you find this series of books useful then please leave your review and rating on
Amazon.
Follow North Border Tech Training on Facebook and Twitter for the latest news and
insights as to how this series will develop.
Foreword
Book 1 of this series sets out to provide a basic understanding of the Arduino platform, how to program
it and how to interface simple electronics. In this book we build on those skills in the focus area of range
finding, object detection and object avoidance. We also introduce the use of sounds on the Arduino as
it is natural that we should want to sound an alarm if an object is detected.
For the hobbyist, they may want to use object detection and avoidance within an automated rover, and
we will look at that application. We must also think about the many industrial applications such a
counting objects, moving machinery within a specified distance and security. We will look at some
experiments in those fields too. We could make this subject complex and look at some more
sophisticated applications that may use Artificial Intelligence. However, I will keep to the premise of
these books and aim the content at those looking to get started in the field of Arduino and electronics
and keep the experiments low cost, easy to follow and easy to implement. However, I will close the book
with a ‘Take it to the Next Level’ chapter to make you aware of the some of the more sophisticated
sensors with basic AI that are more complex to drive, but still within reach of the hobbyist and student
engineer.
I have no doubt the skills learnt here will allow you to develop more engaging and useful projects.
Without further delay let us get into the content.
Prerequisites for this Book
This book assumes you have read Book 1 of the series (‘First Steps with Arduino’) or you already have
some experience of the Arduino platform, how to set up the IDE and undertake some basic Arduino
programming tasks. Basic functions such as ‘digitalRead’ and ‘digitalWrite’ are not covered here
but are explained in Book 1. We will call on some of the material covered in Books 2 and 3 as I plan to
use displays and motors for some of the experiments, and so I will touch on some key aspects of these
subjects so that anybody starting with this book of the series, and does not have the relevant knowledge,
can still follow the experiments.
Download the Code
You can download the Arduino Code for the experiments in this book from GitHub using the link below.
https://github.com/ghallberg-nbtt/scaling-train
I recommend that you do this as I have removed some of the comments from the code in the book
listings to aid readability in print form. I strongly recommend that you comment your code heavily to
facilitate understanding and to become familiar with best engineering practice.
Chapter 1: The Passive Infrared Sensor
Passive Infrared (PIR) sensors have been around for a long time and are common in security systems
as they are ideal for detecting warm moving objects such a people and animals. They are relatively
complex compared to some of the sensors used in this series of books since they do have several
variables that come into play. That said, they are easy to program and so make an ideal starting point
for us to look at the subject of object detection.
Table 1-1: The Controls and Pinouts for the HC-S501 PIR Sensor
The HC-SR501 will detect changes in infrared and if interpreted as motion, it will trigger the output to
be ‘HIGH’. What is not interpreted as motion largely depends on the configured settings. The sensor
requires nearly 1 minute to initialize and during this time it can falsely trigger. You could map this
period out in code, but for simplicity we will not do this in our experiment.
The device has a 1100 view field and will detect motion in a cone from 3m to 7m. The view area can be
adjusted using the trim potentiometer. Fully clockwise will set the range to 3m and fully counter-
clockwise to 7m. A second trim potentiometer adjusts the delay. Fully clockwise is 5 minutes and full
counter-clockwise is 5 seconds. Bear in mind that if the sensor triggers, and the delay period expires,
the sensor will not detect motion for another 3 seconds.
The final control is the Trigger Mode jumper. If set to Single Trigger Mode, the time delay is started on
motion detection and continued detection is blocked until the delay period expires. If set to Repeatable
Trigger Mode, the delay timer is re-started every time motion is detected.
void setup() {
// put your setup code here, to run once:
pinMode(ledPin, OUTPUT);
pinMode(pirPin, INPUT);
digitalWrite(ledPin, LOW); //Turn off LED
}
void loop() {
// put your main code here, to run repeatedly:
pirState = digitalRead(pirPin); //read the PIR State
digitalWrite(ledPin, pirState); //turn on LED if sensor triggered
}
Summary
In this chapter you learnt about PIR sensors and how they can be easily interfaced to an Arduino and
controlled using a simple Sketch.
Chapter 2: The GP2Y0A41SK0F Infrared
Proximity Sensor
The GP2Y0A41SK0F is a common infrared range finding sensor also called a proximity sensor. It has
many industrial applications and is one of the sensors commonly used for educational purposes due its
ease of use and low cost.
void setup() {
Serial.begin (9600); //initialize serial monitor
}
void loop() {
value = analogRead (SENSOR_PIN); //read sensor
Serial.println(value);
delay (1000);
}
Listing 2-1: The Sketch to Work Out the Minimum and Maximum Arduino ADC Values for the Sensor
Listing source: The author
Place an object at 4cm from the sensor and note the ADC value and then place the object at 30cm and
do the same. I took extra readings as shown in Table 2-1.
Distance (cm) Voltage Output (V) ADC Value
4 2.70 540
8 1.53 301
12 1.05 203
16 0.86 163
20 0.75 141
24 0.69 130
28 0.68 127
30 0.68 127
void setup() {
pinMode (GREEN_LED, OUTPUT);
pinMode (CLEAR_LED1, OUTPUT);
pinMode (CLEAR_LED2, OUTPUT);
pinMode (CLEAR_LED3, OUTPUT);
pinMode (RED_LED, OUTPUT);
Serial.begin (9600); //initialize serial monitor
}
void loop() {
value = analogRead (SENSOR_PIN); //read sensor
Serial.println(value);
if (value < 141) { //ADC value for 20cm
digitalWrite (GREEN_LED, HIGH); //Turn on green LED
digitalWrite (CLEAR_LED1, LOW); //Turn off 1st clear LED
digitalWrite (CLEAR_LED2, LOW); //Turn off 2nd clear LED
digitalWrite (CLEAR_LED3, LOW); //Turn off 3rd clear LED
digitalWrite (RED_LED, LOW); //Turn off red LED
delay (1000);
//no sound
noTone(BUZZER);
} else if (value < 163 && value >= 141) { //>16cm and <=20cm
digitalWrite (GREEN_LED, LOW); //Turn off green LED
digitalWrite (CLEAR_LED1, HIGH); //Turn on 1st clear LED
digitalWrite (CLEAR_LED2, LOW); //Turn off 2nd clear LED
digitalWrite (CLEAR_LED3, LOW); //Turn off 3rd clear LED
digitalWrite (RED_LED, LOW); //Turn off red LED
//1 short beep every second
tone (BUZZER, 880, 150); // 880Hz for 0.15s
delay (1000); //wait for 0.85 second after tone finishes
} else if (value < 203 && value >= 163) { //>12cm and <=16cm
digitalWrite (GREEN_LED, LOW); //Turn of green LED
digitalWrite (CLEAR_LED1, LOW); //Turn off 1st clear LED
digitalWrite (CLEAR_LED2, HIGH); //Turn on 2nd clear LED
digitalWrite (CLEAR_LED3, LOW); //Turn off 3rd clear LED
digitalWrite (RED_LED, LOW); //Turn off red LED
//1 short beep every second
tone (BUZZER, 880, 150); // 880Hz for 0.15s
delay (1000); //wait for 0.85 second after tone finishes
} else if (value < 301 && value >= 203) { //>8cm and <=12cm
digitalWrite (GREEN_LED, LOW); //Turn off green LED
digitalWrite (CLEAR_LED1, LOW); //Turn off 1st clear LED
digitalWrite (CLEAR_LED2, LOW); //Turn off 2nd clear LED
digitalWrite (CLEAR_LED3, HIGH); //Turn on 3rd clear LED
digitalWrite (RED_LED, LOW); //Turn off red LED
//2 short beeps every second
tone (BUZZER, 988, 150); // 880Hz for 0.15s
delay (300);
tone (BUZZER, 988, 150); // 880Hz for 0.15s
delay (700); //wait for 0.25 second
} else if (value < 540 && value >= 301)//>4cm and <=8cm
{
digitalWrite (GREEN_LED, LOW); //Turn off green LED
digitalWrite (CLEAR_LED1, LOW); //Turn off 1st clear LED
digitalWrite (CLEAR_LED2, LOW); //Turn off 2nd clear LED
digitalWrite (CLEAR_LED3, LOW); //Turn off 3rd clear LED
digitalWrite (RED_LED, HIGH); //Turn on red LED
//continuous beep
tone (BUZZER, 988);
delay (1000);
}
}
A tone without a duration argument will continue until the ‘noTone’ function is initiated. With both
‘tone’ and ‘noTone’ we must always pass the pin number to which the sound device is connected. The
only other argument is the frequency of the sound. We are however, restricted to simple square wave
tones, so the capability of the Arduino to natively create sounds is limited. Knowing that the ‘tone’
function is non-blocking will help you understand why the delays are added as in the Sketch.
You can see a video demonstration of this project here (https://youtu.be/Km7e73YqhG0).
void setup() {
Serial.begin (9600); //Initialize serial monitor
pinMode (SWITCH, INPUT); //Set pin 2 as input
}
void loop() {
//Read unit switch
currentButton = digitalRead(SWITCH); //Read the switch state
if (previousButton != currentButton)
{
delay(5); // Wait 5ms - switch debounce
currentButton = digitalRead(SWITCH);// Read switch again
}
//Detect a button press
if (previousButton == HIGH && currentButton == LOW)
{
unit = !unit; //Toggle between cm and inches
}
previousButton = currentButton; //Reset button value
Listing 2-3: The Sketch to Register Distance Measurements using the GP2Y0A41SK0F.
Listing source: The author
Let us take a closer look at the Sketch.
First, we scan the switch to see to detect a button press. By default, centimeters are selected, and the
units are changed to inches if the switch is pressed. We toggle between the two units on each button
press. We should debounce the switch. A switch is a mechanical device and so the contacts will bounce,
making and breaking the contacts before it settles. The program loop is scanning so fast it can detect
the bounce conditions and so will switch the units on each bounce leading to a random unit selection.
We want to read the switch reliably. The process is simple. We read the switch and if the current state
is not equal to the previous it means that the switch has been depressed. In that situation we simply
wait 5ms for the contacts to settle and then read the switch state again. 5ms is enough time to eliminate
the bounce. We must set the previous button state to the current button state otherwise the code will
constantly toggle between centimeters and inches on each pass. The code for reading the switch and
debouncing is shown below and there is a video with more on the subject here
(https://youtu.be/cF8lq5sEV48).
currentButton = digitalRead(SWITCH); //Read the switch state
if (previousButton != currentButton)
{
delay(5); // Wait 5ms - switch debounce
currentButton = digitalRead(SWITCH);// Read switch again
}
We will hold the output readings from the sensor in an array. Arrays were covered in Book 2 of this
series and provide a convenient way of holding data sets. We use a ‘for’ loop to take 6 readings and
allow a small delay to ensure the sensor has time to settle if a spurious reading occurs.
for (int i = 0; i < 6; i++) {
ADC_Values [i] = analogRead (SENSOR_PIN); //Read sensor 6 times
delay (5); //Small delay to allow sensor to settle
}
We then use another ‘for’ loop to calculate the sum of the readings.
int ADC_Total_Value = 0;
for (int i = 0; i < 6; i++) {
ADC_Total_Value = ADC_Total_Value + ADC_Values [i];
}
We can then calculate the distance in centimeters using an Arduino code representation of the formula
discussed earlier. The ‘pow’ function is used to calculate an exponent. It requires 2 arguments. The first
is the number we want to raise to a power and the second number is the power. We have converted our
ADC reading back to an analog voltage representation for the first argument.
//Calculate distance
float distance = 12.08 * pow((5 * average_ADC_Value) / 1023, -1.058);
We then check to see what unit is required. If centimeters were selected then we print the distance
directly and if inches were selected, we divide the distance by 2.54. It is worth noting that the serial
monitor prints floating point numbers to 2 decimal places by default. Luckily, this is what we want for
this Sketch.
The delay of 500ms, is there so that we do not overwhelm the serial monitor. It also means that you will
need to depress the switch for up to half a second to toggle the units.
Certainly, for my setup the readings beyond 20cm were unreliable. The sensor was working, but the
resolution was such that the setup could not distinguish between 20cm and 30cm. The reading was
generally showing 20cm. The readings were accurate for shorter distances as the voltage change is much
greater per centimeter at these shorter distances. A fact worth noting when considering using this
sensor.
Summary
In this chapter you learnt about the infrared proximity sensors, specifically the Sharp GP2Y0A41SK0F.
You learnt how it uses triangulation to work out the distance to an object. You learnt that these sensors
do have limitations. You also learnt how to create sounds with the Arduino and how to use more
complex functions such as the ‘pow’ function.
Chapter 3: Object Counting and Timing
Applications
Using a break beam sensor with a transmitter and receiver have obvious applications in security, but
they can also be used for counting objects and timing tasks. In this chapter we will look at the latter two
applications.
void setup() {
pinMode(LED_BUILTIN, OUTPUT); //Use internal LED
pinMode (RECEIVER_PIN, INPUT);
Serial.begin (9600);
digitalWrite (LED_BUILTIN, LOW); //Turn off built-in LED
}
void loop() {
sensorState = digitalRead (RECEIVER_PIN);
if (!sensorState) {
digitalWrite (LED_BUILTIN, HIGH); //Turn on LED
Serial.println ("Beam Broken");
} else {
digitalWrite (LED_BUILTIN, LOW); //Turn off LED
Serial.println ("Beam Unbroken");
}
delay (200); //Slow down for serial monitor
}
Listing 3-2: The Pseudocode for our Lap Counter and Timer
Listing source: The author
Now copy or type in the Sketch as in Listing 3-3.
/*
Lap Counter Timer
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/
//some comments removed to facilitate readability
//download code for fully commented listing
#include <LiquidCrystal.h>
void setup() {
pinMode (SENSOR, INPUT);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.clear(); //clear display
lcd.print ("Ready");
Serial.begin(9600);
}
void loop() {
//Wait until beam is broken to start
currentSensorState = digitalRead(SENSOR);
if (currentSensorState == LOW && lastSensorState == HIGH) {
lastSensorState = currentSensorState; //read only 1 beam break state
startTimer = millis (); //set the initial timer
lastTimer = startTimer;
updateTimer = startTimer;
//rewrite display
lcd.clear();
lcd.print ("Time");
lcd.setCursor (0, 1); //move to second row
lcd.print ("Lap");
lcd.setCursor (4, 1); //move to second row
lcd.print (lapCount);
Serial.println("Start");
while (lapCount < TOTAL_LAPS) {
currentTimer = millis(); //get current time
if (currentTimer > (updateTimer + 10)) {
//updating total time only if at least 0.01s has passed
elapsedTime = formatTime (currentTimer); //format as MM:SS.00
lcd.setCursor (5, 0); //move to column 6 first row
lcd.print (elapsedTime);
updateTimer = millis (); // ready for next 10ms increment
}
//Look for beam break
currentSensorState = digitalRead(SENSOR);
if (currentSensorState == LOW && lastSensorState == HIGH) {
//beam broken
lapCount++; //increment lap count
long lapTime = currentTimer - lastTimer; //work out laptime
lastTimer = millis(); //reset lap timer
String formattedLapTime = formatTime (lapTime);
lcd.setCursor (4, 1); //move to second row
lcd.print (lapCount);
lcd.setCursor (8, 1);
lcd.print (formattedLapTime); //print laptime
Serial.print("Lap ");
Serial.print (lapCount);
Serial.print (" ");
Serial.println (formattedLapTime);
if (lapCount == 12) {
Serial.print ("Total time: ");
Serial.println (elapsedTime);
}
}
lastSensorState = currentSensorState; //read only 1 beam break state
}
}
Listing 3-3: The Sketch for the Lap Counter and Timer
Listing source: The author
Those new to Arduino may look at this Sketch and think that is too complex to understand. Like many
large tasks, all we need do is break down the program into function parts and it will become easier to
understand.
First, we add the library for the liquid crystal display with the code below.
#include <LiquidCrystal.h>
We need to create an object of the LCD display and pass the connected pin numbers as arguments. We
create an object by preceding the object name with the name of the Class within the library that we want
to create an object of. The Class name is ‘LiquidCrystal’ and the object name is ‘lcd’. We do not
need to use the ‘pinMode’ function as the library takes care of that when we pass the IDs of the pins as
arguments.
LiquidCrystal lcd(6, 7, 11, 10, 9, 8);
In this book, I have not referred to Classes. In object-oriented programming, there can be Classes and
functions. In short, functions do things and Classes are things. The code in the ‘LiquidCrystal’ Class
defines the functional characteristics of the display (it is in effect the display). We have one user defined
function in the Sketch that has the task of formatting the time (that is what it does – format the time).
This may sound confusing, but I hope you hold onto those definitions as you build your experience and
then things will become second nature.
The Arduino timing function generates a result in milliseconds. We want to present the time in minutes,
seconds, tenths of a second and hundredth of a second (MM:SS.TH). We need to develop code to do
this and so we first create constant values that represent milliseconds in a minute and in a second and
so on. That value for minutes is greater than 32,768 and so needs to be defined as datatype ‘long’.
const long minute = 60000; //60000 milliseconds in a minute
const int second = 1000; //1000 milliseconds in a second
const int tenthSecond = 100; //100 milliseconds in a tenth of a second
const int hundredthSecond = 10; //10 milliseconds in a 1/100 of a second
We need to define several timers, the lap count value and a string to hold the time, as ultimately, we
will be formatting the integer based time as a string for output to the display and serial monitor.
long lastTimer; // used at start of lap
long currentTimer; // used at end of lap
long updateTimer; // used to update running timer
long startTimer; //timer at start
int lapCount = 0;
String elapsedTime; //total time
The ‘elapsedTime’ will be the total time. The ‘currentTimer’ variable will hold the time when the
beam is broken and the ‘lastTimer’ will be the time when the beam was last broken. The difference
between the two will be the lap time. The ‘updateTimer’ is used as we want to update the time on the
display every 10ms. ‘startTimer’ is clearly the time at the start.
In the setup function, we want to initialize the I/O pin for the sensor and write some initial text to the
display.
pinMode (SENSOR, INPUT);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.clear(); //clear display
lcd.print ("Ready");
Serial.begin(9600);
We need to specify the size of the display and the LCD1602 has 16 columns and 2 rows. We then clear
the display of any text and print the word ‘Ready’ to the display.
In the main ‘loop’ function, the Sketch loops continuously until the beam is broken.
currentSensorState = digitalRead(SENSOR);
if (currentSensorState == LOW && lastSensorState == HIGH) {
lastSensorState = currentSensorState; //read only 1 beam break state
// main code here
}
We only want to act on the ‘LOW’ state if the previous state of the sensor was ‘HIGH’. Bear in mind the
program is looping extremely fast and so breaking the beam even for a short time will lead to multiple
laps being counted while the beam sensor output is in the ‘LOW’ state. We prevent this by setting the
‘lastSensorState’ to the ‘currentSensorState’, so that only ‘HIGH’ to ‘LOW’ transitions are used
as the trigger and not the ‘LOW’ state as a whole. The ‘lastSensorState’ is reset to ‘HIGH’ when the
beam is restored.
After the beam is first broken, the clock is started and the ‘lastTimer’ and ‘updateTimer’ are set to
the start time.
startTimer = millis (); //set the initial timer
lastTimer = startTimer;
updateTimer = startTimer;
The next section of code rewrites the display after the beam is broken for the first time and prints ‘Start’
to the serial monitor.
lcd.clear();
lcd.print ("Time");
lcd.setCursor (0, 1); //move to second row
lcd.print ("Lap");
lcd.setCursor (4, 1); //move to second row
lcd.print (lapCount);
Serial.println("Start");
You can move the cursor of the display by using the ‘setCursor’ function. The first argument is column
and the second the row. The column and row numbers are indexed from zero, so column numbers are
0-15 and row numbers are 0-1 for the LCD1602.
We then want the code to loop until 12 laps are counted as we set 12 to be the maximum number. All
the following code is run in this loop.
while (lapCount < TOTAL_LAPS) {
// main code here
}
We want to update the total elapsed time every 1/100th of a second or every 10ms. So, the code checks
to see if the ‘currentTimer’ is greater than 10ms compared to the ‘updateTimer’ value. If it is, we
update the LCD display and set the ‘updateTimer’ to the current time.
currentTimer = millis(); //get current time
if (currentTimer > (updateTimer + 10)) {
//updating total time only if at least 0.01s has passed
elapsedTime = formatTime (currentTimer); //format as MM:SS.00
lcd.setCursor (5, 0); //move to column 6 first row
lcd.print (elapsedTime);
updateTimer = millis (); // ready for next 10ms increment
}
You will see that we have create a function that converts the time in milliseconds to an ‘MM:SS.TH’
string. We will review that function later.
Next, we want to check for a beam break to indicate a complete lap. When we detect this, we first
increment the lap count. The next action is to calculate the lap time which is the ‘currentTimer’ minus
the ‘lastTimer’. We then reset the ‘lastTimer’ by setting it to the current time. The code then
updates the LCD display and serial monitor with the formatted lap time. We want to print the final time
to the serial monitor and so only do that when 12 laps have passed.
currentSensorState = digitalRead(SENSOR);
if (currentSensorState == LOW && lastSensorState == HIGH) {
//beam broken
lapCount++; //increment lap count
long lapTime = currentTimer - lastTimer; //work out laptime
lastTimer = millis(); //reset lap timer
String formattedLapTime = formatTime (lapTime);
lcd.setCursor (4, 1); //move to second row
lcd.print (lapCount);
lcd.setCursor (8, 1);
lcd.print (formattedLapTime); //print laptime
Serial.print("Lap ");
Serial.print (lapCount);
Serial.print (" ");
Serial.println (formattedLapTime);
if (lapCount == 12) {
Serial.print ("Total time: ");
Serial.println (elapsedTime);
}
}
So that really is the functionality of the code. The only other aspect of review is the time formatting
function. To understand how we convert a total time in milliseconds to minutes, seconds, and fractions
of seconds, you first need to understand modulo arithmetic.
Modulo arithmetic is about dividing using just integers. Specifically, the result is the remainder of a
division. For example, 5 divided 2 is 2 remainder 1. Therefore, 5 MOD 2 is 1. 17 divided by 3 is 5
remainder 2. Therefore, 17 MOD 3 will be 2. The ‘%’ sign is often used in place of ‘MOD’. The
‘formatTime’ function is shown below:
String formatTime(long timeToFormat) {
int minutes = timeToFormat / minute; //number of minutes
int seconds = (timeToFormat % minute) / second; //number of seconds
int tenthSeconds = ((timeToFormat % minute) % second) / tenthSecond ;
int hundredthSeconds = (((timeToFormat % minute) % second) %
tenthSecond) / hundredthSecond;
char formattedTime [9]; //8 chars needed for string + 1 null char
// minutes + ":" + seconds + "." + hundredthSeconds
sprintf_P(formattedTime, PSTR("%02d:%02d.%d%d"), minutes, seconds,
tenthSeconds, hundredthSeconds);
return formattedTime;
}
It takes the time in milliseconds as an argument from the ‘loop’ function. We first declare an integer
called ‘minutes’. We divide the time in milliseconds by the number of milliseconds in a minute. Since
we are working with integers, any fractional part of the result is discarded and so we have the number
of minutes for that period. The function then calculates the seconds. What we need to do now is
calculate the remainder after dividing the time by the number of milliseconds in a minute. We then
divide that remainder by the number of milliseconds in second to arrive at the number of whole seconds
in that period. There is a similar process for calculating the tenths of a second and hundredths of a
second.
The next part of the function converts the integer results for minutes, seconds, tenths of a second and
hundredths of a second into a string and concatenates them with a ‘:’ and ‘.’ in the respective places.
The Arduino programming language (based on C++) has a convenient function that allows us to do
that. The ‘sprintf_P’ function formats a character buffer. We define that buffer with the line of code
below:
char formattedTime [9];
We need a minimum of 8 characters for the formatted time and we need to allow for 1 null character.
Note that using ‘sprintf_P’ and ‘PSTR’ places the resultant string in program memory rather the
using RAM. You can use the ‘sprintf’ function to place the result in RAM. The format of the string is
defined as follows:
%02d:%02d.%d%d
What this means is the first integer (which is ‘minutes’) will be placed first. The ‘02’ means up to 2
leading zeros are printed if the minutes value is zero or less than 10 seconds. We then add a semicolon
‘:’. The seconds are expressed in the same way followed by a decimal point ‘.’. Finally, we print the
tenth of a second and hundredth of a second. Therefore, the order in which ‘minutes’, ‘seconds’,
‘tenthSeconds’, and ‘hundredthSeconds’ appear in the ‘PSTR’ function is critical.
The final task is for the function to return the formatted time as a string to the calling function which is
the main ‘loop’ in this case.
You may see that this timer only works up to 99 seconds. We have not allowed for more characters in
the character buffer to show more. You could easily modify this and apply modulo arithmetic to show
days as well as hours, minutes, and seconds. You can reset the system using the Arduino reset button.
You can see a video demonstration of this experiment here (https://youtu.be/4IxXuXe9yvQ).
Summary
In this chapter you learnt how to use a break beam sensor to detect objects and applied code to count
objects and time objects. You learnt about the concepts of Object-Oriented programming and how to
use Arduino libraries to make coding much simpler. You learnt how to use the LDC1602 display that
uses the HD44780 LCD display controller. You learnt about modulo arithmetic and how to use
functions to return values to the main program.
Chapter 4: Time of Flight
Many range finding sensors use the Time of Flight (ToF) principle, so it is worth taking some time to
look at what Time of Flight is. There are a range of sensor types and we will look at a simple sensor as
part of the Experiment within this chapter.
#include <LiquidCrystal.h>
void setup() {
pinMode (TRIG, OUTPUT);
pinMode (ECHO, INPUT);
pinMode (START_MEASURE, INPUT);
pinMode (UNITS, INPUT);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
}
void loop() {
//check for cm or inches
currentUnitsButton = digitalRead(UNITS); //Read the switch state
if (previousUnitsButton != currentUnitsButton)
{
delay(5); // Wait 5ms - switch debounce
currentUnitsButton = digitalRead(UNITS);// Read switch again
}
if (previousUnitsButton == HIGH && currentUnitsButton == LOW)
{
unit = !unit; //Toggle between cm and inches
}
previousUnitsButton = currentUnitsButton; //Reset button value
We need 2 floating point variables related to the HC-SR04. 1 for the distance value and 1 for the duration
of the output pulse.
float duration; //time of HC-SR04 pulse
float distance; // calculated distance
We need to set up 2 Boolean flags t0 indicate if the display has been updated. We only want to refresh
the display once, for each change. This would be to show the word ‘Ready’ and the display the distance.
We could add a delay to the program that would reduce the display flicker, but it is good for us to
consider alternative methods that may be better.
boolean updatedDistanceDisplay = false;
boolean updatedReadyDisplay = false;
All other constants and variables are ether pin assignments or are needed to debounce the switches.
Debouncing a switch was covered in Chapter 2 as well as previous books in this series.
In the main ‘loop’ function we first check the unit of measurement as to whether it is the default
centimeters or inches. We need to debounce the switch. The units of measurement are set by a Boolean
flag and we invert this flag each time the button is pressed. Logic true is centimeters and logic false is
inches.
currentUnitsButton = digitalRead(UNITS); //Read the switch state
if (previousUnitsButton != currentUnitsButton)
{
delay(5); // Wait 5ms - switch debounce
currentUnitsButton = digitalRead(UNITS);// Read switch again
}
if (previousUnitsButton == HIGH && currentUnitsButton == LOW)
{
unit = !unit; //Toggle between cm and inches
}
previousUnitsButton = currentUnitsButton; //Reset button value
We only to take a measurement if the measurement button is depressed so we read the state of this
switch.
boolean takeMeasurement = digitalRead (START_MEASURE);
If the switch is not depressed it will be in a ‘LOW’ state as we are using a pull-down resistor.
‘takeMeasurement’ will be ‘false’ and so the ‘else’ part of the ‘if else’ statement will be executed
and will display the word ‘Ready’.
if (!updatedReadyDisplay) {
updatedReadyDisplay = true;
lcd.clear(); //clear display
lcd.print ("Ready");
}
The Sketch will continually execute this section of code extremely fast as we are not adding any delays.
The display will flicker. Therefore, we have set a Boolean flag (‘updatedReadyDisplay’) initially to
‘false’ so that the ‘lcd.print’ function is only executed once and we ensure we have a stable display
by setting ‘updatedReadyDisplay’ to ‘true’.
If the measurement switch is depressed, we will take a reading from the HC-SR04 and calculate the
distance.
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
duration = pulseIn(ECHO, HIGH);
First, we ensure that the trigger pin is set to ‘LOW’. We then wait 2 microseconds. For those following
this series of books, this will be the first time you have seen the ‘delayMicroseconds’ function. The
argument for the standard ‘delay’ function is in milliseconds. Next, we need to send the trigger pin
‘HIGH’ for 10 microseconds to initiate the HC-SR04 before sending the trigger pin ‘LOW’ again. We can
then use the Arduino ‘pulseIn’ function to read the duration of the pulse on the echo pin. The
‘pulseIn’ function returns the duration is microseconds and so is ideal for the HC-SR04.
The code then converts the pulse width to centimeters or inches and accounts for the breadboard width
too. Again, we only want to update the display once as this portion of code would normally be executed
repeatedly while the switch is depressed.
if (!updatedDistanceDisplay) {
updatedDistanceDisplay = true; //stop flicker of display
if (unit == true) {
// display cm
distance = (duration / 58) + BB_WIDTH_CM;
lcd.clear();
lcd.print (distance);
lcd.print("cm");
} else {
distance = (duration / 148) + BB_WIDTH_INCHES;
lcd.clear();
lcd.print (distance);
lcd.print("in");
}
}
The final task is to reset the flags that prevent the display from updating continuously. We do this by
looking for a ‘LOW’ to ‘HIGH’ transition of the ‘takeMeasurment’ button. That is the point where we
have finished taking the measurement and the system will reset. The section of code below looks for
this transition after the debounce and if the previous button state was ‘HIGH’ (depressed) and the
current one is ‘LOW’ (released) the updated display flags are reset to ‘false’.
//stop display flicker by only updating display when needed
currentMeasureButton = digitalRead(START_MEASURE);
if (previousMeasureButton != currentMeasureButton)
{
delay(5); // Wait 5ms - switch debounce
currentMeasureButton = digitalRead(START_MEASURE);// Read switch again
}
if (previousMeasureButton == HIGH && currentMeasureButton == LOW)
//Detect a button release
{
updatedReadyDisplay = false;
updatedDistanceDisplay = false;
}
previousMeasureButton = currentMeasureButton; //Reset button value
}
To use the measure, I attached the Arduino board to the underneath of the breadboard using an elastic
band and was able to place the unit against a wall to measure the distance to another wall. Figure 4-5
shows the arrangement and Figure 4-6 shows how I used the project.
Summary
In this chapter you learnt about the principles of Time of Flight and took a close look at the HC-SR04
Ultrasonic ToF sensor. You were introduced to the ‘pulseIn’ function and how to add delays in
microseconds.
Chapter 5: Object Avoidance and Follow Me
This chapter will introduce object avoidance and follow me algorithms. The latter is where we can
configure a robot to follow an object. We will only touch on these subjects and the experiments are
aimed at those just getting started in Arduino and electronics. You can appreciate this is a subject that
we could fill a few books. There are complex object avoidance algorithms used in self driving cars,
interplanetary rovers, and autonomous factories. Many of these systems use complex and state of the
art Artificial Intelligence. That too in an area for further study. We could look at algorithms using
multiple sensors. However, I want to pitch the subject for the novice engineer and keep the experiments
low cost and easy to follow. You can achieve good results using a single sensor and that is what we will
do in this chapter. We will use the HC-SR04 sensor for both experiments covered here.
Controlling DC Motors
Before we get into the first experiment, you will need to understand a little about controlling DC motors.
This subject was covered in Book 3 of this series (‘Controlling Motors’), but we will take a brief look
again at the H-Bridge that is used to control the speed and direction of a DC motor. The speed of a DC
motor can be controlled by using Pulse Width Modulation. However, the Arduino pin cannot drive the
motor directly since the current draw is limited to 40mA per pin. Even a small DC motor will draw
about 160mA on start-up. We also must consider protection of the electronics since a DC motor is an
inductive load and when the power is removed it will generate a voltage that can damage the Arduino
board. Finally, we need a device that will reverse the direction of the motor based on an input control
from the Arduino. The H-Bridge is a device that will address all these issues.
The Principles of H-Bridge Operation
Figure 5-4 shows diagrammatically how a H-Bridge works.
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, HIGH);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, speed); //PWM to drive left motor
Serial.println (speed);
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, HIGH);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, speed); //PWM to drive right motor
Serial.println (speed);
}
}
//Stop motor
void brake (String motor)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, HIGH); //Brake left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, LOW);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, HIGH); //Brake right motor
}
}
To control the H-Bridge, we first need to disable it to prevent a short circuit. We then set the inputs to
control the internal switches and the direction of the motor. Then, by enabling the H-Bridge with a
Pulse Width Modulated waveform, we can control the speed of the motor. The functions need 2
arguments. The speed and whether it is the left or right motor we are controlling. Braking the left-hand
motor whilst driving forward the right-hand motor, we can turn the vehicle left. Doing the opposite, we
can turn the vehicle right. The top speed will be represented by a value of 255 and low speed 0.
Since, we understand the HC-SR04, we can go on to the final Sketch. This is shown is Listing 5-1.
/*
Object Avoiding Robot
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/
//HC-SR04 pins
const int TRIG = 2;
const int ECHO = 3;
//H-Bridge pins
const int ENABLE1 = 5;
const int INPUT1 = 8;
const int INPUT2 = 9;
const int ENABLE2 = 6;
const int INPUT3 = 10;
const int INPUT4 = 11;
float duration; //time of HC-SR04 pulse
float distance; // calculated distance
void setup() {
//Set up HC-SR04
pinMode (TRIG, OUTPUT);
pinMode (ECHO, INPUT);
//Set H-Bridge
pinMode (ENABLE1, OUTPUT);
pinMode (INPUT1, OUTPUT);
pinMode (INPUT2, OUTPUT);
pinMode (ENABLE2, OUTPUT);
pinMode (INPUT3, OUTPUT);
pinMode (INPUT4, OUTPUT);
//Force stop both motors
brake ("left");
brake ("right");
}
void loop() {
//Take reading from HC-SR04
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
duration = pulseIn(ECHO, HIGH);
distance = (duration / 58);
if (distance < 30) {
brake ("left");
brake ("right");
delay (250); //stop for 1/4 second
//reverse about 40cm
reverse ("left", 255);
reverse ("right", 255);
delay (1300);
int direction = random(2); //0 = left 1 = right
if (direction == 0) {
forward ("right", 255);
brake ("left");
delay (500);
} else {
forward ("left", 255);
brake ("right");
delay (500);
}
} else {
forward ("left", 255);
forward ("right", 255);
}
}
void forward (String motor, int speed)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, HIGH);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, speed); //PWM to drive left motor
Serial.println (speed);
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, HIGH);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, speed); //PWM to drive right motor
}
}
//Stop motor
void brake (String motor)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, HIGH); //Brake left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, LOW);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, HIGH); //Brake right motor
}
}
Following an Object
In this final experiment we will look at how to follow an object with the vehicle. This is often referred
to as a “follow me” robot. The only modification we will make to our vehicles is to control the HC-SR04
sensor with a servo motor to create a sweep sensor. Let us first look at how the sensor can be used to
follow an object.
Figure 5-10 illustrates the principle.
Figure 5-10: An Object Following Methodology
Image source: The author
We want to sweep the sensor to detect the right-hand and left-hand edges of the object. The object may
be large and close to the vehicle, so we need to sweep the sensor to ensure that the edges are in the field
of view of the HC-SR4 sensor. The degree of rotation will depend on the size of the object, the distance
you want to maintain as well as the field of view of the sensor. Therefore, experimentation is needed.
If we want to maintain the distance to the object at 25cm and it is straight ahead, both the right-hand
and left-hand distance measurements will be the same and so we can reverse the vehicle if the distance
is less than 15cm and drive forward if greater then 25cm. If the distance is greater than 70cm we will
stop the vehicle so as not to allow distance objects to interfere.
If the object we are following turns, then one edge will be measured closer than the other and so we can
turn the vehicle accordingly until the edges of the object are equidistant.
Servo Operation
You will see that all servos have 3 wires. Usually red and black (or brown) are +5V and ground
respectively, and the positional control wire is usually orange. They work on the principle of PWM to
define the angle. They require a positional feedback mechanism, and the simplest type is a
potentiometer built into the motor casing.
PWM operation of the servo motor is illustrated in Figure 5-12. A PWM pulse is triggered every 20ms.
This is generally consistent across all DC servo motors and so makes programming easy with the use of
an Arduino library. If a 1ms pulse is present in the period, the servo rotates to 0 0. If the pulse is 1.5ms,
the servo rotates 900. Finally, if the pulse is 2ms, the servo rotates to 1800. If the pulse is between these
values the servo rotates to the proportionate angle.
Figure 5-12: Servo PWM Pulses
Image source: The author
If you want the servo to hold its position and resist any rotational torque from the load, simply resend
the same pulse width every 20ms.
/*
Follow Me Robot
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/
#include <Servo.h>
//HC-SR04 pins
const int TRIG = 2;
const int ECHO = 3;
//H-Bridge pins
const int ENABLE1 = 5;
const int INPUT1 = 8;
const int INPUT2 = 9;
const int ENABLE2 = 6;
const int INPUT3 = 10;
const int INPUT4 = 11;
//servo pin
const int SERVO = 12; //Servo on Pin 12
float distanceLeft = 0;
float distanceRight = 0;
Servo myServo;
void setup() {
//Set up HC-SR04
pinMode (TRIG, OUTPUT);
pinMode (ECHO, INPUT);
//Set H-Bridge
pinMode (ENABLE1, OUTPUT);
pinMode (INPUT1, OUTPUT);
pinMode (INPUT2, OUTPUT);
pinMode (ENABLE2, OUTPUT);
pinMode (INPUT3, OUTPUT);
pinMode (INPUT4, OUTPUT);
//Force stop both motors
brake ("left");
brake ("right");
myServo.attach(SERVO);
}
void loop() {
myServo.write (60); //move servo to the left
distanceLeft = distanceReading ();
delay (100);
myServo.write (120); //move servo to the right
distanceRight = distanceReading ();
delay (100);
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, HIGH);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, speed); //PWM to drive left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, HIGH);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, speed); //PWM to drive right motor
}
}
//Stop motor
void brake (String motor)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, HIGH); //Brake left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, LOW);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, HIGH); //Brake right motor
}
}
float distanceReading () {
float duration; //time of HC-SR04 pulse
float distance; // calculated distance
//Take reading from HC-SR04
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
duration = pulseIn(ECHO, HIGH);
distance = (duration / 58);
return distance;
}
The servo control pin is connected to I/O pin 12 of the Arduino. The ‘attach’ function tells the Servo
code which pin the servo control wire is connected to.
myServo.attach(SERVO);
To move the servo, you only need use the ‘write’ function and pass the number of degrees as an
argument.
myServo.write (60);
The main ‘loop’ function starts by taking a distance reading to the left and to the right. I am using the
angles 600 and 1200 for left and right. You may need to tweak the angles for you setup based on the
object you wish to follow and the orientation of the servo. Also, the length of delay is important and the
longer the delay, the further to the left or right the vehicle will move. So, the delay too will need tuning
to your setup.
myServo.write (60); //move servo to the left
distanceLeft = distanceReading ();
delay (100);
myServo.write (120); //move servo to the right
distanceRight = distanceReading ();
delay (100);
It is then simply a case of moving the vehicle based on the measurements. We have created a function
to take the measurements (‘distanceReading’) and it returns the distance in centimeters.
if ((distanceLeft > 70) && (distanceRight > 70)) {
//stop and wait for object
} else if ((distanceLeft >= 25) && (distanceRight >= 25)) {
//follow object
} else if ((distanceLeft <= 15) && (distanceRight <= 15)) {
//back away from object
} else if ((distanceRight - 3) > distanceLeft) {
//turn left
} else if ((distanceRight + 3) < distanceLeft) {
//turn right
} else {
//stop
}
The vehicle will turn toward the object if the difference in left or right distance measurements is greater
than 3cm. I used a book for the object and remember to twist the object to trigger the vehicle to turn.
Although the performance is quite crude, it is still satisfying to understand what can be achieved with
a single inexpensive sensor.
Figure 5-15 shows my completed vehicle and there is a video demonstration of the vehicle in action here
(https://youtu.be/t0lna-UVEKA).
Summary
In this chapter you explored some object avoidance and follow me concepts and used an HC-SR04
ultrasonic sensor to put these into action. You learnt about the H-Bridge to control the speed and
direction of DC motors and learnt about servo motors. You also learnt about the power draw that motors
will assert on the Arduino and how to use a voltage regulator to provide an external power source for
high current devices such as motors.
Chapter 6: Take it to the Next Level
In this book we have only touched the surface of this subject to explore and learn about some basic
concepts using inexpensive components and sensors. There is currently a step change happening in
areas of technology looking at automation, machine leaning and intermachine communications. You
can imagine what object detection capabilities a self-driving car would need or even some of the
manufacturing systems in modern factories. If you are interested in this subject, there are a few areas
that you can explore for a modest outlay and touch on technologies used in more sophisticated systems.
In this chapter we will look at some of these sensors and give you some project ideas. I chose not to put
experiments in this book that use these devices as my ethos is to pitch the content to the novice engineer
by exploring basic concepts and make the experiments accessible as possible by using low cost and
readily available components. What follows are a few such sensors that have caught my attention. There
are alternatives with similar prices and capabilities.
LiDAR Systems
LiDAR (Light Detection and Ranging) is a technology that uses laser light for range finding and digital
mapping. LiDAR based sensors operate using the ToF principles. Laser light can be focused extremely
finely and so you are able to target specific points in space and the results are often within millimeters
tolerance for that point. This of course does come at extra expense. There are, however, affordable
options for the hobbyist and inquisitive engineer.
The tinyLiDAR is a compact ToF sensor manufactured by MicroElectronicDesign. It has a range of up
to 2m and is backed by a comprehensive library set and examples. Distance calculations are fed back
using the I2C protocol. These units retail for about $25. Figure 6-1 is an image of the tinyLiDAR.
Figure 6-1: The tinyLiDAR by MicroElectronicDesign
Image source: Courtesy of MicroElectronicDesign
Since LiDAR systems are so accurate you can use them for some interesting projects. In Figure 6-2, the
3 tinyLiDAR units are mounted on a servo-controlled pan and tilt mechanism to track objects in 3
dimensions.
Laser Safety
Great caution must be observed when using lasers as certain types of laser can damage your eyes. Never
look directly into any laser. All the lasers in these LiDAR systems are Class 1 lasers. This means they are
eye safe so present no danger. However, you must receive professional training and be fully aware of
the risks if using other laser classes. The main laser classes are shown in Table 6-1 but be aware there
are sub-classes. Class 1 laser are safe. Class 2 lasers are generally safe, but caution must be used. Class
3 and Class are eye dangerous.
Class 1 CD/DVD Players
Class 2 Barcode readers, prestation pointers
Class 3R High power pointers, some longer range targeting and measuring devices
Class 3B High power laser products for professional use
Class 4 Laser light show equipment, medical applications, welding and cutting, scientific applications
Figure 6-5: The Charmed Labs LLC Pixy2 Smart Vision Sensor
Image source: Courtesy of Charmed Labs
Epilogue
So, we have come to the end of this part of the journey and I hope to have given you a good foundation
of knowledge in the area of range finding, object detection, object avoidance (and object following)
using the Arduino platform. There are many examples on the Web of how to use the Arduino
microcontroller for some very interesting projects, but the purpose of this book is to give you all of the
basic information you need in one place to get you started and present it in a clear and systematic way.
In the subsequent books in the series we will use this knowledge to look at other focus areas and create
ever more challenging, creative and interesting projects. Whatever your goals are, I hope to have
inspired you and helped you some way to achieving those goals.
If you like this book and the series of books, please leave a review on the Amazon website. For the latest
news on other books in the series you can following my Facebook page, Twitter or follow me as an
author on Amazon.
About the Author
Gary Hallberg has over 34 years of experience in the telecommunications and data communications
industries. He started his career working with circuit switched voice and data technologies in PDH and
SDH environments and then moved on to work with early packet switched networks using Frame Relay
and ATM. His career shifted focus to IP routing when the Internet started to grow, designing large scale
service provider networks using leading edge equipment from vendors such as Juniper and Cisco. Gary
attained Cisco Certified Professional status during this time. Presently, he is working for a global
equipment vendor with a focus on Ethernet networks and is at the forefront of network evolution,
providing infrastructures for SD-WAN, Network Functions Virtualization, SDN and 5G backhaul. Gary
has a Bachelor of Engineering degree in electronic engineering and a Master of Philosophy degree in
robotics and manufacturing.