You are on page 1of 91

Range Finding, Object Detection and Object

Avoidance
Book 4 of the Arduino Short Reads Series

Gary Hallberg

North Border Tech Training


First Edition
Copyright © 2020 Gary Hallberg and North Border Tech Training
All reserved. This book or any portion thereof may not be reproduced or used in any manner whatsoever
without the express written permission of the publisher except for the use of brief quotations in a book
review.
First Published, 2020
Contents
About the Arduino Short Reads Series ..................................................................................................... 5
Foreword.................................................................................................................................................... 6
Prerequisites for this Book ........................................................................................................................ 7
Download the Code ................................................................................................................................... 8
Chapter 1: The Passive Infrared Sensor .................................................................................................... 9
Parts needed for this Chapter ........................................................................................................... 9
The PIR Sensor ...................................................................................................................................... 9
HC-S501 PIR Motion Sensor ............................................................................................................... 12
Experiment 1: The HC-S501 PIR Sensor ............................................................................................. 14
Driving more LEDs for a Practical Security Light? ............................................................................. 16
Summary .............................................................................................................................................. 18
Chapter 2: The GP2Y0A41SK0F Infrared Proximity Sensor .................................................................. 19
Parts needed for this Chapter ......................................................................................................... 19
The GP2Y0A41SK0F Sensor ................................................................................................................ 19
The Passive Buzzer .............................................................................................................................. 22
Experiment 2: A Proximity Detector using the GP2Y0A41SK0F ....................................................... 23
Limitations of the GP2Y0A41SK0F ..................................................................................................... 28
Experiment 3: Distance Reading with the GP2Y0A41SK0F ............................................................... 28
Summary .............................................................................................................................................. 32
Chapter 3: Object Counting and Timing Applications ........................................................................... 33
Parts needed for this Chapter ......................................................................................................... 33
3mm IR Break Beam Sensor ............................................................................................................... 33
Experiment 4: Break Beam Basics ...................................................................................................... 34
The HD44780 LCD Display Controller ............................................................................................... 37
Experiment 5: Lap Counter and Timer ............................................................................................... 39
Summary .............................................................................................................................................. 48
Chapter 4: Time of Flight ........................................................................................................................ 49
Parts needed for this Chapter ......................................................................................................... 49
Time of Flight Principles ..................................................................................................................... 49
The HC-SR04 Ultrasonic Ranging Module ......................................................................................... 50
Experiment 6: Ultrasonic Measure ..................................................................................................... 52
Summary .............................................................................................................................................. 59
Chapter 5: Object Avoidance and Follow Me .......................................................................................... 60
Parts needed for this Chapter ......................................................................................................... 60
Object Avoidance using a Sweep Sensor ............................................................................................. 60
The Robot Vehicle Chassis................................................................................................................... 63
Controlling DC Motors ........................................................................................................................ 63
The Principles of H-Bridge Operation ................................................................................................ 64
The L293D H-Bridge ........................................................................................................................... 64
Experiment 7: Object Avoidance using a Single Static ToF Sensor .................................................... 66
Following an Object ............................................................................................................................. 73
The Servo Motor .................................................................................................................................. 74
Servo Operation ................................................................................................................................... 75
The SG90 9G Servo .............................................................................................................................. 76
Experiment 8: A Follow Me Robot ...................................................................................................... 77
Summary .............................................................................................................................................. 83
Chapter 6: Take it to the Next Level........................................................................................................ 84
LiDAR Systems .................................................................................................................................... 84
Laser Safety .......................................................................................................................................... 87
Arduino Vision Systems....................................................................................................................... 87
Epilogue ................................................................................................................................................... 89
About the Author ..................................................................................................................................... 90
About the Arduino Short Reads Series

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.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x HC-S501 PIR Sensor
• 1 x LED
• 1 x 220Ω resistor
• Jumper wires including Dupont jumpers

The PIR Sensor


All warm bodies emit infrared light. The PIR sensor is designed to detect changes in this infrared light
and so when a moving warm object such as a person or animal enters the field of view, the sensor will
trigger. But how does it work?
Figure 1-1 illustrates the principle of the PIR sensor with a simplified diagram.
Figure 1-1: Basic Operation of a PIR Sensor
Image source: The author
The PIR sensor compromises a core sensor of photo-reactive material sensitive to infrared light and a
Fresnel lens. We will talk about the lens later. There are 2 slots in the sensors that allows it to ‘see’ out
a distance within 2 zones. In normal conditions, when no warm object is present, the radiated infrared
heat from buildings and surroundings is consistent across the zones. The output from the sensor is
stable. When a warm object that is radiating infrared light passes through a zone, the photo-reactive
material will cause a positive differential change in the output voltage of the sensor. Likewise, when the
body leaves the zones there will be a negative differential voltage change. These changes are used to
trigger the motion detection. Figure 1-2 illustrates the output of the sensor.
Figure 1-2: The Voltage Differential Output of the PIR Sensor
Image source: The author
Some PIR sensors have extra electronics on board to convert this voltage differential into a logic high
or low. Logical high signifies motion detected. It is this sort of sensor that I will be using.
What about Fresnel lenses? In our simplified example above there are just two detection zones. In real
sensors we will want many more zones. The lens assists with this requirement. First, why use a Fresnel
lens? This type of lens was invented in 1822 by Augustin-Jean Fresnel and came into common use
within lighthouses. The main advantage of this type of lens is that it uses much less material than an
equivalent conventional lens. It can even be made from flat sheets of material and so is lighter and
cheaper to manufacture. Figure 1-3 illustrates the Fresnel lens.
Figure 1-3: The Fresnel Lens
Image source: The Web (Wikipedia) with annotations by the author
The lens can be considered as a series of prisms each bending the light by the angle needed for it to be
focused onto a single point. If you look closely at your PIR sensor you will see the arrangement of
Fresnel lenses. The overall lens is split into hexagonal sections and Fresnel lenses are present in each
section. The purpose of the sections is to split the detection zones into multiple small zones rather than
the two large zones depicted in Figure 1-1.

HC-S501 PIR Motion Sensor


The PIR sensor I will be using is the HC-S501. This is a low-cost unit that is ideal for learning with. An
image of this sensor is shown in Figure 1-4 and the PCB (Printed Circuit Board) layout is shown in
Figure 1-5.
Figure 1-4: The HC-S501 PIR Sensor
Image source: The Web (public domain)

Figure 1-5: The HC-S501 PCB Layout


Image source: The Web (public domain)
Table 1-1 sets out the controls for the HC-S501 PIR sensor.
Pin or Control Function
Time Delay Adjust Sets how long the output remains high after detecting motion. This can be
set from 5 seconds to 5 minutes
Sensitivity Adjust Sets the detection range from 3m to 7m
Trigger Selection Jumper Set for single or repeatable triggers
Ground Pin GND or 0V
Output Pin Low when no motion detected and 3.3V high when motion detected
Power Pin 5 to 20VDC input

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.

Experiment 1: The HC-S501 PIR Sensor


First build the breadboard layout as shown in Figure 1-6.
Figure 1-6: The Breadboard Layout for the PIR Sensor
Image source: Created with Fritzing
Next type in or load the Sketch as in Listing 1-1. Run the Sketch and let the PIR Sensor settle down for
a few seconds before triggering it.
/*
The PIR Sensor
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/

int ledPin = 2; // LED output


int pirPin = 3; // Input for HC-S501
int pirState; // The PIR output

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
}

Listing 1-1: The Sketch for the PIR Sensor


Listing source: The author
The Sketch is simple. We initially set the PIR state to be ’LOW’ to ensure it is off. In the ‘loop’ function,
the Sketch simply looks to see whether the PIR state is ‘HIGH’ or ‘LOW’ and set the LED state accordingly.

Driving more LEDs for a Practical Security Light?


Controlling a single LED is not the best option for a viable security light as we know from Book 1 that
the current limits of an Arduino I/O pin is 40mA. As an option, you could reuse the transistors switch
circuitry used in Book 2 of this series to be able to sink currents of up to 600mA through the collector
and emitter of a transistor. You can use a commercial low voltage 12V LED lamp for a brighter light or
an array of conventional LEDs. All LED lamps are DC powered. Even if they connect to an AC supply,
they will have onboard rectifiers and current limiting resistors so will work just as well from an AC or
DC supply. Figure 1-7 shows a possible arrangement using a PN2222 general purpose NPN transistor
and Figure 1-8 is a photograph of the PIR controlling an array of LEDs using the transistor to sink
around 80mA. You can refer to Book 2 ‘Working with Displays’ if you want to find out more about
transistor operation.
Figure 1-8: Using a Transistor to Drive more LEDs
Image source: The author
Figure 1-9: The Same Project but using a Transistor to Drive a Set of LEDs
Image source: The author

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.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x GP2Y0A41SK0F sensor
• 1 x 5V passive buzzer
• 1 x red LED
• 1 x green LED
• 3 x yellow or clear LEDs
• 1 x pushbutton switch
• 5 x 220Ω resistors
• 1 x 10KΩ resistor
• 1 x 10uF 50V electrolytic capacitor
• Jumper wires including Dupont jumpers

The GP2Y0A41SK0F Sensor


The GP2Y0A41SK0F was originally manufactured by Sharp. It is a small proximity sensor that uses
infrared light and can measure the range of an object from 4cm to 30cm. It is one of a family of similar
sensors and others can measure greater ranges: typically, 10cm to 80cm and 20cm to 150cm. It is not
a Time of Flight sensor but uses triangulation to work out the distance to the object. Typical applications
listed include touchless switching such as those used in sanitary equipment, robot cleaners, ATM,
vending machines, and amusement equipment. One critical point to note about this range of sensors is
that an object must be within the minimum and maximum range of operation. If the object is closer
than the minimum or further than the maximum range, the sensor will give unreliable readings. This
must be factored into any design. An image of the GP2Y0A41SK0F is shown in Figure 2-1.
Figure 2-1: The GP2Y0A41SK0F Sensor
Image source: The Web (public domain)
The sensor generates an analog voltage for any given distance, like all mass-produced items, there is a
tolerance associated with the output voltage. However, for most, if not all the applications, simply using
the manufacturer’s datasheet will be sufficient. Figure 2-2 is the graph included in the manufacturer’s
datasheet that shows the relationship between output voltage and distance. You can calculate the
distance for a given voltage with the formula below. The output voltage range is about 2.6V (4cm) to
0.42V (30cm)
𝐷𝑖𝑠𝑡𝑎𝑛𝑐𝑒 = 12.08 𝑥 𝑉𝑜𝑙𝑡𝑎𝑔𝑒-1.058
Figure 2-2: The Voltage Output of the GP2Y0A41SK0F with Distance
Image source: Courtesy of SHARP from the GP2Y0A41SK0F datasheet
Another consideration is that our Arduino board does not work directly using analog input voltages.
The analog voltage will be converted to a digital input 0V being 0 and 5V being 1023. We need to factor
this into any Sketch. More on that in Experiments 2 and 3.
So how does the GP2Y0A41SK0F work? It uses a triangulation technique, and you will see that the
sensor has 2 lenses. Infrared light is transmitted out through one of the lenses and that lens focuses the
light into a narrow beam. The light will be reflected off an object through the second lens. Behind the
second lens is a Position-Sensitive Detector (PSD). The principle of operation is illustrated in Figure 2-
3.
Figure 2-3: The Triangulation Principle for the GP2Y0A21YK0F Sensor
Image source: The author
When light from the transmitter is reflected from an object at close range, it will strike the PSD of the
sensor at a different position compared to an object further away. This is shown in Figure 2-3 as the
received light strikes the PSD at position P1 when the object is at distance D1. At distance D2 the light
strikes the sensor at position P2. The voltage output of the sensor depends on where the light strikes
the PSD.
The sensor also uses a modulated light pattern. This helps with the accuracy as ambient infrared
radiation will not trigger false readings. Likewise, since the sensor reads the position where the reflected
light strikes the PSD, the object can have different light absorption characteristic so long as enough
light is received to trigger the sensor.

The Passive Buzzer


For Experiment 2 we will introduce sound to add a little more interest to the experiment. The Arduino
is not to best board for sound generation, and natively it only supports a basic set of sound functions.
There are audio shields available, but we only want to generate a simple set of tones for the experiment.
We can use passive and active buzzers. The active buzzer will generate a sound simply when the unit is
electrified. The drawback is that generally they are only able to generate a single frequency. We want to
generate a few frequencies and we can do this with the passive buzzer. Passive buzzers are driven by a
square wave generated by an Arduino I/O pin and so we can vary the tone. Passive buzzers are generic
components and may not have a part number. Be sure to select a unit that will work on a 5VDC signal.
The type of buzzer I will be using is shown in Figure 2-4. They generally work by using a disc of
piezoelectric material that flexes when an electrical current is passed through the material. This in turn
creates the sound.
Figure 2-4. A Passive Buzzer
Image source: The Web (public domain)

Experiment 2: A Proximity Detector using the GP2Y0A41SK0F


In this experiment we will use the GP2Y0A41SK0F, the buzzer and some LEDs to explore the principle
of proximity detection. Start by building the breadboard layout as shown in Figure 2-5. The 10uF
capacitor across the supply is recommended to smooth out any voltage transients.
Figure 2-5: The Breadboard Layout for our Proximity Detector
Image source: Created with Fritzing
You will need to note the ADC values for the furthest and closest objects you wish to detect, and it would
be good practice to take some extra measurements. Grey card or a box makes a good object to test with.
The Sketch shown in Listing 2-1 can be used to obtain the readings.
/*
GP2Y0A41SK0F Calibration
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/

const int SENSOR_PIN = 0; //analog pin 0 for output of sensor


int value = 0; //holds ADC value

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

Table 2-1: Calibration Measurements for the GP2Y0A41SK0F


We can now move on to the full Sketch. Copy or type in the Sketch as shown in Listing 2-2. The red LED
will light then the range to the object is less than 8cm. This will be accompanied by a continuous beep.
The green LED will be lit when the range is greater than 20cm and there will be no sound. The clear
LED connected to I/O pin 9 will light when the range is greater than 16cm and less than or equal to
20cm. This will be accompanied by a single short beep every second. The clear LED connected to I/O
pin 10 will light when the range is greater than 12cm and less than or equal to 16cm. This will be
accompanied by a single short beep every second. The clear LED connected to I/O pin 11 will light when
the range is greater than 8cm and less than or equal to 12cm. This will be accompanied by 2 short beeps
every second.
/*
GP2Y0A41SK0F Proximity Detector
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/

const int GREEN_LED = 8;


const int CLEAR_LED1 = 9;
const int CLEAR_LED2 = 10;
const int CLEAR_LED3 = 11;
const int RED_LED = 12;
const int BUZZER = 3;
const int SENSOR_PIN = 0; //analog pin 0 for output of sensor
int value = 0; //holds ADC value

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);
}
}

Listing 2-2: The Sketch for the Proximity Detector


Listing source: The author
The Sketch is straightforward to understand. We have assigned digital I/O pins to the LEDs and the
buzzer. The buzzer must be on a PWM pin. The GP2Y0A41SK0F is connected as in the calibration
exercise.
The first thing the Sketch does in the ‘loop’ function is to read the voltage output from the sensor and
print the ADC value to the serial monitor. The Sketch then checks for our predefined threshold values
using a series of nested ‘if’ and ‘else if’ statements and lights the appropriate LED whilst ensuring
the others are turned off.
Creating sounds with the Arduino will be new to those who have only read the previous books in this
series. We need to connect the passive buzzer to a PWM capable pin. You then only need initiate the
‘tone’ function. When you initiate the ‘tone’ function, it uses one of the timers onboard the Arduino.
Therefore, it is non-blocking, and the Arduino can get on with other tasks. The ‘tone’ function has 2
usages as below:
tone(pin, frequency)
tone(pin, frequency, duration)

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).

Limitations of the GP2Y0A41SK0F


You will see from the calibration exercise that on occasion the sensor will deliver spurious readings
where the output voltage jumps. Although the modulated signal is designed to minimize interference
from ambient infrared light, the sensor is not perfect. Care should be used when deploying the sensor
in some environments. If it is used in a controlled setting, such as inside a machine, this may not be an
issue. If used in a robotic vehicle for instance, and the environment changes, then it may be worth taking
a few readings quickly and then averaging the result. We will do this in Experiment 3.
You will also see from the calibration readings that there is extraordinarily little voltage change between
20cm and 30cm. This too can cause misreading as a small deviation in voltage equates to a large change
in distance close to the higher range limit. In my view, it would be better to deploy similar sensor with
greater range limits (such as the GP2Y0A21YK0F) and only use it within 60% of its maximum range.

Experiment 3: Distance Reading with the GP2Y0A41SK0F


In this experiment we will test the formula provided to generate a distance in centimeters or inches and
print it to the serial monitor. We will also take 6 readings in quick succession to get and average to limit
the possibility of a spurious readings.
Start by building the breadboard layout as shown in Figure 2-6.
Figure 2-6: The Breadboard Layout for GP2Y0A41SK0F Distance Readings
Image source: Created with Fritzing
We will use a switch to toggle between centimeters and inches and use the formula given to convert the
voltage output to a distance. This formula is below:
𝐷𝑖𝑠𝑡𝑎𝑛𝑐𝑒 = 12.08 𝑥 𝑉𝑜𝑙𝑡𝑎𝑔𝑒-1.058
We also need to allow for the fact that the reading will be from the onboard ADC. We will have to convert
this reading back to an analog representation of the voltage. We know that an ADC value of 0 equates
to 0V and an ADC value of 1023 equates to 5V. Therefore, we need to use the following formula to
convert our ADC value to a voltage:
(𝐴𝐷𝐶 𝑅𝑒𝑎𝑑𝑖𝑛𝑔 𝑥 5)
𝑉𝑜𝑙𝑡𝑎𝑔𝑒 =
1023
Now copy or type in the Sketch as shown in Listing 2-3.
/*
GP2Y0A41SK0F Distance Measurements
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/

const int SENSOR_PIN = 0; //Analog pin 0 for output of sensor


const int SWITCH = 2; //cm - inch button
int ADC_Values[6]; //Array to hold ADC value
boolean previousButton = HIGH; //The previous button state
boolean currentButton = HIGH; //The current button state
boolean unit = true; //Flag for cm or inches

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

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
}
//work out total sum of readings
int ADC_Total_Value = 0;
for (int i = 0; i < 6; i++) {
ADC_Total_Value = ADC_Total_Value + ADC_Values [i];
}
//calculate average
float average_ADC_Value = round (ADC_Total_Value / 6);
//Calculate distance
float distance = 12.08 * pow((5 * average_ADC_Value) / 1023, -1.058);
//Convert to cm or inches
if (unit == true) { //unit is cm
Serial.print(distance); // Serial monitor prints 2 decimal places
Serial.println("cm");
} else { //Unit is inches
distance = distance / 2.54;
Serial.print(distance); //Serial monitor prints 2 decimal places
Serial.println("inches");
}
delay (500);
}

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];
}

The average is calculated. The ‘average_ADC_Value’ is declared as a floating-point number only


because the ‘pow’ function used later requires floating point numbers as arguments. Passing an integer
will give false results.
//calculate average
float average_ADC_Value = round (ADC_Total_Value / 6);

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.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x 3mm or 5mm break beam sensor set
• 1 x LCD1602 LCD display
• 1 x 10KΩ potentiometer
• 1 x 10KΩ resistor
• Jumper wires

3mm IR Break Beam Sensor


For this chapter, I will be using a break beam sensor that has a 3mm LED. These sensors tend to be
generic and have no specific part numbers, so it is case of matching the images here if you need to buy
one. This is a 2-part sensor that has a transmitter and a separate receiver. The transmitter has 2 wires.
These are for the voltage supply and ground. The supply can be 3.3VDC or 5VDC. 5V will give a larger
range of about 25cm between the transmitter and receiver. The receiver has 3 wires. These are for the
voltage supply and ground, and a signal wire that is white or yellow. The receiver has an open collector
output. This means you will need a pullup resistor of about 10KΩ for the receiver to operate. You can
use the internal pullup resistor on the Arduino if you prefer. Figure 3-1 illustrates the concept of ‘open
collector’.
Figure 3-1: The Open Collector Configuration
Image source: The author
In Books 2 and 3 we discussed the operation of transistors as voltage-controlled switches and in Book
1 we discussion issues with floating inputs. The output of the break beam receiver is transistorized.
However, there is no connection between the collector of the transistor and supply voltage. If the base
of the transistor is activated, the current will be allowed to flow between the collector and the emitter.
Any output connected to the collector will be pulled to ground. However, if the transistor is off, any
output connected to the collector will float in an unknown state. We need to connect a resistor between
the collector of the transistor and the supply voltage so that the output is pulled high when the transistor
is off. The output will be pulled low when the transistor is on.

Experiment 4: Break Beam Basics


In this experiment we will explore the basic operation of the break beam sensor simply by displaying
the status of the output on the serial monitor and lighting the built in LED when the beam is broken.
Start by building the breadboard layout in Figure 3-2.
Figure 3-2: The Breadboard Layout for the Break Beam Basics
Image source: Created with Fritzing
A photograph of my set up is shown in Figure 3-3.
Figure 3-3: My Break Beam Setup
Image source: The author
Now copy or type in the Sketch as in Listing 3-1.
/*
Break Beam Basics
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/
const int RECEIVER_PIN = 2;
boolean sensorState = false;

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-1: The Sketch for the Break Beam Basics


Listing source: The author
The code is simple. The Sketch reads the I/O pin of the Arduino and if ‘LOW’ the built in LED is turned
on. The status is also written to the serial monitor. The delay is only needed to stop the Sketch
overwhelming the serial monitor with data.

The HD44780 LCD Display Controller


For the next experiment we will use the HD44780 (LCD1602) LCD display covered in Book 2 of this
series ‘Working with Displays’. For those who have read Book 2 you can skip this section. The HD44780
is a Hitachi device and it is the chip that drives the display. The display units are sold as type HD44780
but there are compatible units available that often use the generic name LCD1602. All will work with
this experiment and the Arduino library. When you acquire a display unit, ensure it has the header pins
soldered in place, so you can locate the display in the breadboard. Figure 3-4 is an image of the
HD44780 display.

Figure 3-4: The HD44780 (LCD1602) Display with Header Pins


Image source: The Web (public domain)
When you examine the display, you will see 32 blocks of pixels arranged in 2 rows of 16 blocks. Each
block is 5x8 pixels. It is these blocks you can use for displaying standard characters or custom characters
that you create yourself. The display has 16 terminals in a linear arrangement. A header can be soldered
to these terminals and this will be needed to use the display on prototyping boards such as our
breadboard. Table 3-1 explains the pin numbering and the purpose of each pin.
Pin Number Pin Name Purpose
1 VSS Ground (0V) connection
2 VDD +5V Supply
3 V0 Contrast adjust (10KΩ pot wiper)
4 RS Register Selection (character or command)
5 RW Read/Write
6 EN Enable
7 D0 Data line 0 (unused in 4-pin mode)
8 D1 Data line 1 (unused in 4-pin mode)
9 D2 Data line 2 (unused in 4-pin mode)
10 D3 Data line 3 (unused in 4-pin mode)
11 D4 Data line 4
12 D5 Data line 5
13 D6 Data line 6
14 D7 Data line 7
15 A Backlight Anode
16 B Backlight Cathode

Table 3-1: The HD44780 (LCD1602) Pin Configuration


What follows is an explanation of how you will use the pins. The ground and +5V supply are pins 1 and
2, respectively. You can illuminate the backlight by connecting pin 15 to +5V and pin 16 to ground. The
intensity of the backlight can be adjusted by connecting the wiper of a potentiometer to pin 3. Pin 4 is
used to tell the display whether the next set of data should be printed or interpreted as a command,
such as ‘move the cursor’. Pin 5 will be connected to ground as we will always be writing to the display
and not reading from it. Pin 6 is used to tell the display when data is ready. We will be using the display
in 4-pin mode so we only will be using data lines 4 to 7 (pins 11 to 14). The other data pins are left
unconnected.
Programming the display from scratch would be difficult. Those who have read Books 2 and 3 in this
series would have been introduced to libraries and Object-Oriented programming. These make our
tasks much easier. For those joining straight into this book, what follows is a brief explanation. Those
who read the previous books can skip this part.
Object-Oriented programming certainly leads to more reliable, simple and scalable code. It has not
always been the case. When I started programming there was no Object-Oriented approach and things
were far more complex and problematic. So, what is Objected-Oriented Programming? The best way I
can explain to someone who has never been exposed to it is to draw and analogy with the physical world.
Let us say you run a business that paints wooden chairs. You paint chairs red, white or blue only. If the
world were not Object-Oriented, you would also have the source the materials for every chair, shape
them and construct every chair before painting it. That is a complex and inefficient way to do business.
In an Object-Oriented world, you would buy in each chair ready assembled and simply customize it
with the color. That is a much simpler activity where you focus on your core business.
Object-Oriented Programming is the same. The object we are interested in is the LCD display. You could
develop the functions from scratch to control the display in your Sketch and repeat that process for
every Sketch that needed the same display. This would be time consuming for you and you would have
much more to support if it were part of a commercial product. Alternatively, you could import a
predefined library that has an object for the HD44780 (LCD1602) and associated functions to
customize it. Customization is this case would be to write text to the display and define custom
characters. We will use an external library to do this for this experiment.
First open a new Sketch. You then need to load the ‘LiquidCrystal’ library. To do this select Tools
> Manage Library. It may be already loaded by default. A window will pop up with a search bar at
top. Type in ‘LiquidCrystal’ and press enter as shown in Figure 3-5.

Figure 3-5: The Arduino IDE Library Manager


Image source: The Arduino IDE
If you hover your mouse over the library, then you will see an install button appear. Simply click this to
install the library. If you click on ‘more info’ you will be taken to a Web location where you can find
instructions for how to use the library with some examples.

Experiment 5: Lap Counter and Timer


For this experiment we will look at object counting and timing. We will build a project that can be used
as a lap counter and lap timer. It will use the HD44780 (LCD1602) LCD display covered in Book 2 of
this series ‘Working with Displays’.
First build the breadboard layout is shown in Figure 3-6.
Figure 3-6: The Breadboard Layout for the Lap Counter and Timer
Image source: Created with Fritzing
There are quite a few tasks to do within the Sketch and so it is worthwhile designing the flow with some
pseudocode. Listing 3-2 is the high-level design for our code. With complex Sketches, it is worth
breaking the task down into small, manageable chunks and these in turn can be implemented using
bespoke functions.
Preset number of laps to 12
Set display to show “Ready”
If Beam is broken
Start timer
While laps are less than 12
Update running clock every 1/100 second
Display elapsed time and show lap count
If beam is broken
Calculate lap time
Increment lap count
Print to serial monitor
Display elapsed time, lap time and lap count
After 12 laps stop timer

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>

// initialize the library by associating any needed LCD interface pin


// with the Arduino pin number it is connected to
// LiquidCrystal(rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(6, 7, 11, 10, 9, 8);

const int TOTAL_LAPS = 12;


const int SENSOR = 2; //beam sensor on pin 2
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
int currentSensorState = LOW;
int lastSensorState = HIGH;
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

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
}
}

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;
}

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.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x HC-SR04 ultrasonic ranging module
• 1 x LCD1602 LCD display
• 1 x 10KΩ potentiometer
• 2 x 10KΩ resistors
• 2 x pushbutton switches
• 1 x 9V PP3 battery and clip
• Jumper wires

Time of Flight Principles


Time of Flight range finding sensors, also called proximity sensors, emit light or sound from a source
toward a target. The target will reflect the radiation and the sensor will measure the time between the
transmission and reception. Knowing the speed of the radiation, whether it be light or sound, the
resultant delay can be divided by 2 and the result will be the distance from the sensor to the target
object. A light source can be infrared or laser, and a sound source is usually ultrasonic. Figure 4-1
illustrates the principle.
Figure 4-1: The Time of Flight Principle
Image source: The author

The HC-SR04 Ultrasonic Ranging Module


We will explore an ultrasonic ToF module. The HC-SR04 ultrasonic ranging module is extremely
common and low cost. It is used in robotics for object detection and is a great choice of distance sensor
as it has a range of 2cm to 400cm with an accuracy of up to 3mm and a measuring angle of 150. An
image of the HC-SR04 is shown in Figure 4-2.
Figure 4-2: The HC-SR04 Ultrasonic Ranging Module
Image source: The Web (public domain)
You can see in Figure 4-2 that the HC-SR04 has 4 pins. Vcc is the 5V supply and GND is the ground.
The ‘Trig’ and ‘Echo’ pins are the input and output. The HC-SR04 does not generate a distance reading
directly in inches or centimeters. Instead, there is a sequence of events that are summarized by the
timing diagram shown in Figure 4-3.

Figure 4-3: The HC-SR04 Timing Diagram


Image source: The author
To start the measurement, the ‘Trig’ (trigger) pin of SR04 must receive a logic ‘HIGH’ for at least 10us.
After this pulse finishes, the sensor will transmit out a cycle of 8 ultrasonic bursts at 40kHz and wait
for the reflected ultrasonic signals. When the sensor detects the reflected ultrasonic signals at the
receiver, it will set the ‘Echo’ pin to logic ‘HIGH’ for a period. The width of this pulse will be proportional
to the distance. The distance in centimeters or inches can be calculated using the following formulae.
𝑊𝑖𝑑𝑡ℎ 𝑜𝑓 𝑝𝑢𝑙𝑠𝑒 𝑖𝑛 𝑚𝑖𝑐𝑟𝑜𝑠𝑒𝑐𝑜𝑛𝑑𝑠
𝐷𝑖𝑠𝑡𝑎𝑛𝑐𝑒 𝑖𝑛 𝑐𝑚 =
58
𝑊𝑖𝑑𝑡ℎ 𝑜𝑓 𝑝𝑢𝑙𝑠𝑒 𝑖𝑛 𝑚𝑖𝑐𝑟𝑜𝑠𝑒𝑐𝑜𝑛𝑑𝑠
𝐷𝑖𝑠𝑡𝑎𝑛𝑐𝑒 𝑖𝑛 𝑖𝑛𝑐ℎ𝑒𝑠 =
148
The sensor will return a pulse width of between 150us and 25ms for 2cm and 400cm respectively and
38ms if no object is detected. There are some excellent libraries available that support the SR-HC04
and that you can utilize these if you like. However, we are going to use a handy Arduino function to
measure the width of the pulse from the HC-SR04.

Experiment 6: Ultrasonic Measure


In this experiment we will use the HC-SR04 as an ultrasonic measure of the type that is often used to
measure distances between walls. We will use a 9V battery to power the project so the unit will be
portable. We will also reuse the LCD1602 LCD display.
First build the breadboard layout as in Figure 4-4.

Figure 4-4: The Breadboard Layout for our Ultrasonic Measure


Image source: Created with Fritzing
The project will function as follows by having the display show the word ‘Ready’ when it is waiting to
measure a distance. The user will then depress the switch connected to the Arduino I/O pin 3. The setup
will then measure the distance and display this on the LCD1602 display. Pressing the other switch will
toggle between inches and centimeters. Note that the measurement switch is using a pull-down resistor.
The only reason I did this was to make the logic of my Sketch read better.
Now type in or copy the Sketch as shown in Listing 4-1.
/*
Ultrasonic Measure
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/scaling-
train/blob/master/LICENSE
*/

#include <LiquidCrystal.h>

// initialize the library by associating any needed LCD interface pin


// with the Arduino pin number it is connected to
// LiquidCrystal(rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(6, 7, 11, 10, 9, 8);

// pin assignments for the HC-SR04


const int TRIG = 12;
const int ECHO = 13;
// pin assignments for switches
const int START_MEASURE = 3;
const int UNITS = 2;
const float BB_WIDTH_CM = 5.4;
const float BB_WIDTH_INCHES = 2.25;
// variables for HC-SR04
float duration; //time of HC-SR04 pulse
float distance; // calculated distance
boolean unit = true; //true = cm, false = inches
boolean previousUnitsButton = HIGH;
boolean currentUnitsButton = HIGH;
boolean updatedDistanceDisplay = false; //ensure we only update LCD once
boolean updatedReadyDisplay = false; //ensure we only update LCD once
boolean previousMeasureButton = LOW;
boolean currentMeasureButton = LOW;

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

//read status of measurement switch


boolean takeMeasurement = digitalRead (START_MEASURE);
if (takeMeasurement) {
//take a reading from HC-SR04
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
duration = pulseIn(ECHO, HIGH);
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");
}
}
} else {
if (!updatedReadyDisplay) {
updatedReadyDisplay = true;
lcd.clear(); //clear display
lcd.print ("Ready");
}
}

//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

Listing 4-1: The Sketch to control the Ultrasonic Measure


Listing source: The author
Although there looks to be a lot going on, much of the code is designed to stop the display flickering
and debouncing the switches. The reason why the display would normally flicker is that we have not
added a delay in the program and so the main ‘loop’ function cycles extremely fast. Let us break down
the code but focus on the parts that are new to us.
We added two floating point constants that represent the width of the breadboard in centimeters and
inches. The idea is that we can place the breadboard against a wall and take a measurement to another
wall. The HC-SR04 is located along the front edge of the breadboard and so adding the breadboard
width will compensate for this offset.
const float BB_WIDTH_CM = 5.4;
const float BB_WIDTH_INCHES = 2.25;

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.

Figure 4-5: The Final Arrangement of the Ultrasonic Measure


Image source: The author
Figure 4-6: Using the Ultrasonic Measure
Image source: The author
You can see a video demonstration of this project here (https://youtu.be/A_8-TlqLwQs).

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.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x HC-SR04 ultrasonic ranging module
• 1 x 2-wheel robot car chassis with geared DC motors
• 1 x HC-SR04 mounting bracket
• 1 x L293D H-Bridge
• 1 x LM7805CV voltage regulator
• 2 x 10uF 50V electrolytic capacitors
• 1 x SG90 9G servo
• 1 x 9V battery
• Jumper wires including Dupont wires

Object Avoidance using a Sweep Sensor


A sweep sensor is simply a sensor mounted on a servo motor that rotates from side to side while taking
distance readings. It can be used as a form of radar, as a ‘picture’ of the object environment can be built
up by associated a distance to the object with the angle at which the reading was taken. Figure 5-1 shows
a HC-SR04 based sweep sensor mounted to one of my robot vehicles.
Figure 5-1: A HC-SR04 based Sweep Sensor
Image source: The author
So how can we use this to avoid objects? Figure 5-2 is a flow chart that describes a simple object
avoidance algorithm for an autonomous vehicle.
Figure 5-2: Object Avoidance using a Sweep Sensor
Image source: The author
The algorithm is simple. The vehicle will move forward until an object is detected in its path. The sensor
will then rotate to the left and if no object is detected, it will turn left and continue to move forward. If
an object is detected on the left-hand side, the sensor will rotate to the right. If no object is detected on
the right-hand side, the vehicle will turn to the right and continue to move forward. If there are objects
in front and to each side, the vehicle will reverse a set distance and then first check left and then right
if there is still an object on the left.
We will not use a sweep sensor for the object avoidance experiment, but we will use one for the ‘follow
me’ experiment.
The Robot Vehicle Chassis
For the experiments in this chapter you will need a two wheeled robot vehicle chassis. You can make
your own, but I will be using the chassis shown in Figure 5-3. This type of chassis is readily available
and inexpensive. The chassis will need 2 DC motors that are geared to provide adequate torque to drive
the vehicle. Be aware that all types of chassis I have worked with are greedy on standard alkaline
batteries so ensure that the batteries are new and of good quality. Lithium ion batteries are great but
are relatively expensive.

Figure 5-3: The Robot Vehicle Chassis


Image source: The author

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.

Figure 5-4: H-Bridge Operation


Image source: The author
The H-Bridge is a clever, but simple device. It consists of 4 voltage-controlled switches. The supply and
motor are connected as in Figure 5-4. When all switches are open the motor is unpowered, but able to
freely spin. When a top switch is closed, along with the opposite bottom switch, the motor will run in
either direction based on which pair of switches are closed. You can use an effect called regenerative
braking when both bottom switches are closed. In this mode, when power is removed from the motor
it acts as a generator whilst still spinning. If we sink the generated current to ground, we will place a
large negative torque on the motor. It will slow quickly and the motor will be resistant to torque applied
to the shaft.
You may have noticed a potential problem with the H-Bridge. If for any reason both top and bottom
switches on the same side are simultaneously closed, then there will be a short circuit between the
supply and ground. Clearly not good! Real devices have disable/enable inputs that will disable the
supply until the switches are set. Real devices also have built in flyback diodes that protect the device
so connectivity is much simpler.

The L293D H-Bridge


This device is likely to be your first introduction to the H-Bridge. It is a 16-pin dual in Line IC with dual
H-Bridges so, as well as being low cost, it is ideal for driving 2-wheeled vehicles. This device can support
loads of up to 600mA, well within the demands of our small DC motors.
Figure 5-5 shows the pinouts of this device and how it should be connected to the Arduino and motor.
Note that some manufacturers label the pins differently, but their function and position will be the
same.

Figure 5-5: The L293D H-Bridge and Connectivity


Image source: The author
The device is split into a right-hand and left-hand driver. The +5VDC logic supply from the Arduino is
connected to pin 16. A separate motor supply will be connected to pin 8. Pins 4, 5, 12 and 13 are all
connected to ground and this arrangement also helps dissipate heat from the device. Outputs 1 and 2
(pins 3 and 6 respectively) are outputs to which a motor is connected. Likewise, for Outputs 3 and 4
(pins 11 and 14 respectively). Inputs 1 and 2 (pins 3 and 7 respectively) control the right-hand H-Bridge
with digital I/O pins from the Arduino. Likewise, inputs 3 and 4 (pins 10 and 15 respectively) control
the Left-hand H-Bridge. The left-hand and right-hand H-Bridges each have an enable input on pins 1
and 9, respectively. By holding these low, we can disable the H-Bridge and protect the electronics. We
can also use PWM on these pins to turn the H-Bridge on and off to control the speed of the motor.
You may be wondering how 2 inputs can control 4 voltage-controlled switches. With 2 inputs there are
4 possible logic combinations. The way these logic inputs map to H-Bridge switch connection is shown
in Table 5-1.
Input 1 Input 2 Action
LOW LOW Brake
LOW HIGH Reverse
HIGH LOW Forward
HIGH HIGH Freewheel
Table 5-1: Actions Associated with H-Bridge Inputs
Clearly, the directions shown here are nominal, but it does lead us into the next experiment.

Experiment 7: Object Avoidance using a Single Static ToF Sensor


In this experiment we will mount an HC-SR04 sensor to the front of the robot vehicle chassis and based
on inputs from the sensor we will control the vehicle to steer around the object. Figure 5-6 shows the
algorithm we will encode in the Sketch.

Figure 5-6: The Object Avoidance Algorithm for Experiment 7


Image source: The author
The algorithm is simple. The vehicle will move forward until an object is encountered. It will then move
backward about 40cm. It will then make a random turn to the left or to the right and continue to move
forward until the next object is encountered. We will set the distance to the object to be 30cm before
the vehicle will react.
Next build the breadboard layout as shown in Figure 5-7. I will be using a half width breadboard as it
fits this chassis better.
Figure 5-7: The Breadboard Layout for the Object Avoidance Robot
Image source: Created with Fritzing
Although the layout looks complicated, it is just a matter of connecting section by section and taking
your time. You will notice that I have added a 5V voltage regulator (L7805CV) to the circuit. This is
needed since the motors I will be using are 4.5VDC to 6VDC. The voltage regulator drops the 9V supply
from the battery down to 5V on the output side. The capacitors are needed to ensure the supply is
smooth by filtering out any spikes. This part of the circuit is shown in Figure 5-8. This forms 2 separate
5V supplies. One is for the Arduino and HC-SR04 and one is to drive the motors. Do not get them mixed
up and ensure the correct supply is connected to correct supply pin of the L293D H-Bridge, but note
the grounds of these supplies need to be connected together to ensure they work off a common
reference.
Figure 5-8. The Voltage Regulator Circuit using the L7805CV
Image source: The author
Looking ahead to the Sketch, we will need to write functions to control the direction of the robot. We
can do this with 3 functions that control the left and right motors in turn. These functions are below:
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
Serial.println (speed);
}
}

//Drive motor backward at the specified speed (0 – 255)


void reverse (String motor, int speed)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, HIGH);
analogWrite (ENABLE1, speed); //PWM to drive left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, LOW);
digitalWrite (INPUT4, HIGH);
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
}
}

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
}
}

//Drive motor backward at the specified speed (0 – 255)


void reverse (String motor, int speed)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, HIGH);
analogWrite (ENABLE1, speed); //PWM to drive left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, LOW);
digitalWrite (INPUT4, HIGH);
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
}
}

Listing 5-1: The Sketch for the Object Avoiding Robot


Listing source: The author
The program starts by assigning pins to the HC-SR04 and H-Bridge as well as ensuring the motors are
stopped by braking each one in turn. In the main ‘loop’ function, the program starts by taking a reading
from the HC-SR04. If the distance to an object is 30cm or greater the vehicle drives forward. If the
distance is less then 30cm, the vehicle will first stop for ¼ second and then reverse for 1.3s. This time
is what is needed for the vehicle to reverse about 40cm and the value will need to be tuned to your
chassis. A random number is then chosen between 0 and 1. The ‘random’ function is used to pick the
number. The argument is the higher end of the number range but is excluded from the result. If only
one argument is specified, the lowest number in the range is 0. The result can only be 0 or 1. If you want
the minimum to be another value other than 0, you can pass 2 arguments.
random(max)
random(min, max)
min: lower bound of the random value, inclusive (optional)
max: upper bound of the random value, exclusive
If the result is 0, the vehicle moves to the left for ½ second and to the right if the result is 1. If no object
is detected, the vehicle will then move forward again.
This is straightforward and is fun when seeing vehicle in action. It is extremely easy to modify the Sketch
to make differing degrees of turn or move the vehicle at different speed. Figure 5-9 shows the vehicle I
made and there is a video demonstration here (https://youtu.be/vk7jjTAJdLc). I bought an inexpensive
universal HC-SR04 mount to attach the sensor to the chassis. This too can be used to mount the sensor
onto a server motor.
Figure 5-9: The Object Avoiding Robot Vehicle
Image source: The author

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.

The Servo Motor


A servomotor is a rotary actuator or linear actuator that allows for precise control of angular or linear
position. Amongst other things, they are found in radio-controlled models, automated door locks and
the like. Images of servos can be seen in Figure 5-11.
Figure 5-11: An Assortment of Servo Motors
Image source: The Web (public domain)
A servo can have a fixed angular rotation limit. This is usually 1800. Other types can rotate freely. They
can generate great torque and hold their position while underload. For this reason, they can draw lots
of power so we will not be running them from the Arduino pins, but will provide an external power
supply using the voltage regulator of Experiment 7.

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.

The SG90 9G Servo


I will be using the SG90 9G servo for these experiments. This is an extremely common and inexpensive
servo used mainly for RC controlled models. Its operating voltage is 4.8VDC to 6VDC and it has a
stalling torque of 1.6Kg at 6V, so it certainly is capable for such a small servo. One of these servos is
shown in Figure 5-13. The red wire is the positive supply, the brown is ground, and the control wire is
orange. You will also see servos come with several attachment arms for various applications.
Figure 5-13: The SG90 9G Servo and Attachments Arms
Image source: The Web (public domain)

Experiment 8: A Follow Me Robot


We can put all this together in this experiment to make a vehicle that follows an object. First, build the
breadboard layout as in Figure 5-14. The only change from Experiment 7 is the addition of the servo
motor.
Figure 5-14: The Follow Me Robot
Image source: Created with Fritzing
We can reuse a lot of the code from the previous experiment. You will need to install the servo library
by Michael Margolis, Arduino and we can go straight on to the final Sketch shown in Listing 5-2.

/*
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 ((distanceLeft > 70) && (distanceRight > 70)) {


//stop and wait for object
brake ("left");
brake ("right");
} else if ((distanceLeft >= 25) && (distanceRight >= 25)) {
//follow object
forward ("left", 255);
forward ("right", 255);
delay (100);
} else if ((distanceLeft <= 15) && (distanceRight <= 15)) {
//back away from object
reverse ("left", 255);
reverse ("right", 255);
delay (100);
} else if ((distanceRight - 3) > distanceLeft) {
//turn left
forward ("right", 255);
brake ("left");
delay (10);
} else if ((distanceRight + 3) < distanceLeft) {
//turn right
forward ("left", 255);
brake ("right");
delay (10);
} else {
brake ("left");
brake ("right");
}
}

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
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, HIGH);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, speed); //PWM to drive right motor
}
}

//Drive motor backward at the specified speed (0 – 255)


void reverse (String motor, int speed)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, HIGH);
analogWrite (ENABLE1, speed); //PWM to drive left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, LOW);
digitalWrite (INPUT4, HIGH);
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;
}

Listing 5-2: The Sketch for the Follow Me Robot


Listing source: The author
The only code new to us is the servo code so let us take a quick look at that. You need to include the
‘Servo.h’ library.
#include <Servo.h>

You need to create an object of the servo class.


Servo myServo;

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).

Figure 5-15: The Completed Follow Me Robot


Image source: The author

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.

Figure 6-2: Object Tracking with the tinyLiDAR


Image source: Courtesy of MicroElectronicDesign
You can also use 2 of these units to track an object in 2 dimensions. A single unit can be interfaced to a
PC and a radar type scanning display can be developed.
If you want to measure more distant objects, then you can consider the LIDAR-Lite 3 manufactured by
Garmin, an image of which is shown in Figure 6-3. These retail at about $130 but can measure distances
up to 40m. This too uses the I2C protocol.

Figure 6-3: The LIDAR-Lite 3 Laser Rangefinder by Garmin


Image source: Courtesy of Garmin
You can take a step up from the above range finding LiDAR systems and consider using a 3600 scanner
such as the one manufactured by YDLIDAR. This unit has a scanning range of up to 11m and retails at
about $99. An image of the YDLIDAR X4 360° Laser Scanner is shown in Figure 6-4.
Figure 6-4: YDLIDAR X4 360° Laser Scanner
Image source: Courtesy of YDLIDAR
This system can be attached to a robot vehicle to build up a picture if its local environment and the
result can be used for route planning and object avoidance. It can also be used for 3D mapping.

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

Table 6-1: Generalized Table of Laser Classes

Arduino Vision Systems


The Arduino board does not have the power to process signals from a camera. However, there are some
low-cost systems now that have a camera and onboard image processing. This allows them to be
interfaced to an Arduino for control of subsystems. These systems cross into the world of Artificial
Intelligence and provide a good foundation to explore that upcoming area of technology.
One such affordable system is the Charmed Labs LLC Pixy2 Smart Vision Sensor. These retail at around
$60 -$80 for the cameras system. They also have a pan and tilt mechanism accessory as the camera can
be used for object tracking. The Charmed Labs LLC Pixy2 Smart Vision Sensor is shown in Figure 6-5.

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.

You might also like