0% found this document useful (0 votes)
28 views236 pages

The Arduino Robot. Robotics For Everyone

Uploaded by

sahbarafii
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views236 pages

The Arduino Robot. Robotics For Everyone

Uploaded by

sahbarafii
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 236

.. ..

- -
11111111
Table of Contents

1. Introduction to Robot Building................. 1


Why Build a Robot? .............................................. 4
How Robots Move... . .. . .. . ......... . . . . ....... . . . . .. .. . . ... . .. . 5
Tools ............................................................ 6

2. Building the Electronics........................ 9


Hardware Required .............................................. 9
Construction Techniques ........................................ 1 O
Soldering ..................................................... 1 o
Building the Motor Controller................................. 1 O
Soldering the Reflectance Sensors............................ 17
Making a Line Sensor Mount.................................. 17
Next Steps.................................................... 20

3. Building the Two-Wheeled Mobile Platform.. 21


Hardware Required............................................. 22
Mechanical Assembly ........................................... 23
Lay Out the Chassis Parts ...................................... 23
Motor Assembly .............................................. 24
Assemble the Chassis Components ............................ 26
Attaching the Control Electronics............................. 37
Mounting the IR sensors ........................................ 38
Mounting the IR Sensors for Edge Detection................... 39
Mounting the IR Sensors for Line Following .................... 41

iii
Next Steps ................................. ....... .............. 43

4. Building the Four-Wheeled Mobile Platform ... 45


Hardware Required .............................................. 46
Mechanical Assembly ............................................ 47
Lay Out the Chassis Parts ...................................... 47
Motor Assembly............................................... 49
Assemble the Chassis Components ............................ 51
Solder the Power and Motor Connections ...................... 54
Connecting the Battery Pack and Power Switch................. 55
Building the Optional Trickle Charg er.......................... 56
Assemble the Chassis .......................................... 57
Mounting Arduino and Connecting Wires to the Shield......... 58
Mounting the IR sensors ......................................... 65
Mounting the IR Sensors for Edg e Detection.................... 65
Mounting the IR Sensors for Line Following ..................... 67
Next Steps ................ ...................................... 68

s. Tutorial: Getting Started with Arduino ........ 71


Hardware Required .............................................. 72
Arduino Software................................................ 72
Arduino Hardware ............................................... 72
Installing the Integ rated Development Environment (IDE) ........ 74
Installing Arduino on Windows ................................ 74
Installing Arduino on OS X ..................................... 75
Installing Arduino on Linux.................................... 76
Driver Installation ............................................. 76
Connecting the Arduino Board................................... 78
Using the IDE.................................................... 78
Uploading and Running the Blink Sketch ......................... 81
Using Tabs...................................................... 82
Installing Third-Party Libraries...... ........... . ... ...... ........ 83

s. Testing the Robot's Basic Functions ........... 85


Hardware Required.............................................. 85
Software Prerequisites ........................................... 86
Sketches Used in This Chapter................................... 87
Load and Run helloRobot.ino .................................... 88
About the Sketch ................................................ 95
Troubleshooting ................................................. 98
Making the Sketch Easy to Enhance.............................. 99

7. Controlling Speed and Direction .... . .... . . .. 103


Hardware Required............................................. 103
Sketches Used in This Chapter.................................. 103
Types of Motors ......... ..... .. .. .... ... .. .. ...... ... ... . ..... . 104
Motor Controllers.............................................. 106
Controlling Motor Speed....................................... 109
How Motor Speed Is Controlled............................... 109
Code for Motor Control....................................... 11 0
Calibrating Rotation and Tracking ............................. 116
Software Architecture for Robot Mobility ........................ 119
Functions to Encapsulate Robot Movements .................... 123
Core Movement Code........................................ 124
Additional Core Functions .................................... 126
Functions to Rotate the Robot................................ 127
Higher-Level Movement Functions ............................ 130

8. Tutorial: Introduction to Sensors.......... ... 133


Hardware Discussed............................................ 133
Software ....................................................... 134
Infrared Reflectance Sensors .................................... 134
Sonar Distance Sensors ......................................... 137
Maxbotix EZ1 Sonar Distance Sensor ............................ 139
Sharp IR Distance Sensor........ .. ........................ ..... 141
Proximity Sensor............................................... 142
Sound Sensor .................... .... .... ................ ...... 143
Arduino Cookbook ............................................. 146

s. Modifying the Robot to React to Edges and Lines


................................................. 147
Hardware Required............................................. 147
Sketches Used in This Chapter.................................. 148
The Look Code ......................... ........... ...... . ...... 149
Edge Detection ..... . . ...... . ... . .... . ...... .... . ... .... . .. .... 150
Line Following ............ ... ................. . ...... .... . ... .. 154
Seeing Sketch Data ............................................. 160

10. Autonomous Movement ...... ..... ...... . .... . 163


Hardware Required ............................................. 163
Sketches Used in This Chapter.................................. 164
Mounting a Ping Distance Sensor ............................... 165
Making a Mount for the Ping Sensor .......................... 166
Mounting the Ping Sensor in a Fixed Position .................. 168
Mounting the Ping Sensor on a Servo ......................... 168
Letting the Robot Wander...................................... 170

Table of Contents v
Adding Scanning............................................... 178

11. Remote Control .. . ...... . .... . . .. . . . . .. . . . .... 185


Hardware Required ............................................. 185
Sketches Used in This Chapter ...................... ............ 186
Design of the Remote Control Code ...................... .... ... 186
Controlling the Robot with a TV Type IR Remote ................. 190
Installing the IR Decoder Chip ................................ 190
The IR Remote Software ...................................... 192

Appendix A. Enhancing Your Robot................ 201

Appendix B. Using Other Hardware with Your Robot 205

Appendix C. Debugging Your Robot................ 211

Appendix D. Power Sources........................ 221

Appendix E. Programming Constructs............. 231

Appendix F. Arduino Pin and Timer Usage ......... 235


Introduction to Robot
Building

This book takes you through the steps needed to build a robot capable of
autonomous movement and remote control. Build instructions are provided
for 2WD (two wheel drive) and 4WD (four wheel drive) platforms. The platforms
shown in Figure 1-1 and Figure 1-2 will make the construction a snap, but you
can build your own robot chassis if you prefer. The connection and use of the
control electronics and sensors are fully explained and the source code is in­
cluded in the book and available for download online (see "How to Contact
Us" (page xv) for more information on downloading the sample code).

Figure 1-1. The assembled two wheeled robot chassis

1
Introduction to Robot Building

Figure 1-2. The assembled four wheeled robot chassis

Here is a preview of the projects you can build:

• Controlling speed and direction by adding high level movement capabil­


ity.
• Enabling the robot to see the ground-using IR sensors for line and edge
detection (see Figure 1-3 and Figure 1-4).
• Enabling the robot to look around-scanning using a servo so the robot
can choose the best direction to move, as shown in Figure 1-5.
• Adding remote control using a TV remote control or a wired or wireless
serial connection.

2
Introduction to Robot Building

Figure 1-3. Robot moves around but remains within the white area

Figure 1-4. Robot follows black line

Chapter 1 3
Why Build a Robot?

Figure 1-5. Two wheeled and four wheeled robots with distance scanners

Why Build a Robot?


Building a robot is different from any other project you can make with a mi­
crocontroller. A robot can move and respond to its environment and exhibit
behaviors that mimic living creatures. Even though these behaviors may be
simple, they convey a sense that your creation has a will and intent of its own.
Building a machine that appears to have some spark of life has fascinated
people throughout the ages. The robots built over 60 years ago by neuro­
physiologist W. Grey Walter (see http://www.extremenxt.com/walter.htm) ex­
plored ways that the rich connections between a small number of brain cells
give rise to complex behaviors.

4
How Robots Move

There are many different kinds of robots, some can crawl, or walk, or slither.
The robots described in this book are the easiest and most popular; they use
two or four wheels driven by motors.

Choosing Your Robot


The projects in this book can use either a two or four Four Wheeled Robot
wheeled platform, but if you are still deciding which This robot's four wheel drive makes this a good
is right for you, here are some factors that will help choice if you want it to roam over rougher sur­
you choose: faces. This platform has a large top plate that can
Two Wheeled Robot be used to carry small objects. The robot is heav­
Light and very maneuverable, this is a good ier and draws more current than the 2WD robot,
choice if you want to experiment with tasks such so battery life is shorter.
as line-following that require dexterous move­
ment. However, the caster that balances the ro­
bot requires a relatively smooth surface.

How Robots Move

The robots covered in this book move forward,


back, left and right much like a conventional
car. Figure 1-6 shows the wheel motion to
move the robot forward .
. ...

Figure 1-6. Left and Right wheels turn forward, Robot


moves Forward

If the wheels on one side are not driven (or are


driven more slowly than the other side) the ro­
bot will turn, as in Figure 1-7.

Figure 1-7. Only Left wheels turn, Robot Turns Right

Chapter 1 5
Tools

Figure 1-8 shows that reversing the wheel ro­


tation drives the robot backward.

... _. ..._ .

Figure 1-8. Left and Right wheels turn backward, Robot


moves Backward

Unlike a car (but a little like a tank), these robots


can also rotate in place by driving the wheels
on each side in different directions. If the
wheels on each side are spinning in opposite
,._ ,._ directions, the robot will rotate. Figure 1-9
shows clockwise rotation.
Figure 1-9. Left wheels turn forward, Right wheels re­
verse, Robot rotates Clockwise

Tools
These are the tools you need to assemble the robot chassis.
Phillips Screwdriver
A small Phillips screwdriver from your local hardware store.
Small long-nose or needle-nose pliers
For example, Radio Shack 4.5-inch mini long-nose pliers, part number
6 4-062 (see Figure 1- 10) or Xcelite 4-inch mini long-nose pliers, model L 4 G.
Small wire cutters
For example, Radio Shack 5" cutters, part number 6 4-06 4 (Figure 1 - 1 1) or
Jameco 16 1 411
Soldering iron
For example, Radio Shack 640-2070 (Figure 1- 12 ) or Jameco 2094 143 are
low cost irons suitable for beginners. But if you are serious about elec­
tronics, a good temperature controlled iron is worth the investment, such
as Radio Shack 55027897 or Jameco 1 46595.
Solder 22 AWG (.6mm) or thinner
For example, Radio Shack 6 40-0013 or Jameco 73605 .

6
Tools

Figure 1-10. Small Pliers


Figure 1-11. Wire Cutters (Side Cutters)

Figure 1-12. Soldering Iron

Chapter 1 7
Building the Electronics 2

This chapter guides you through the electronic systems that will control your
robot. Both the two wheeled and four wheeled platforms use the same mod­
ules, a pre-built Arduino board (Arduino Uno or L eonardo), and a motor con­
troller kit. The motor controller featured in this book is the AFMotor shield from
Adafruit Industries. Although other motor controllers can be used (see Ap­
pendix B) the AF Motor shield provides convenient connections for the signals
and power to all the sensors and devices covered in this book. It is also capable
of driving four motors, which is required for the four wheel drive chassis.
Although the attachment of the boards to the robot differs somewhat de­
pending on the chassis, the build ing of the AFMotor circuit board kit is the
same for both. If you don't have much experience with soldering, you should
practice soldering on some wires before tackling the circuit board (you can
find soldering tutorials here: http://www.la dya da.n et/learn/so/derin g/
thm.htmn.

Hardware Required

• Tools listed i n "Tools" (page 6 )


• AFMotor shield kit
• Three 6 way 0.1 " female headers
• Three QTR-1 A reflectance sensors
• Stripboard, three 3 way 0.1 " headers for line sensor mount
• Ribbon Cable, 1 1- way or wider, cut with a sharp knife as follows:
- One 10 inch length of 5 conductor ribbon cable for line sensors

9
Construction Techniques

- Two 1 0 i n c h leng ths of 3 c on ductor ribbon ca ble for edg e sensors


• O pti onal: 3 wa y 0. 1 " fem a l e hea der for opti onal c ha rg i ng c i rc ui t
• O ptional: 3 wa y 0.1 " fem a l e h ea der for optional wi reless con necti on

Construction Techniques
Th i s secti on provi des a n overvi ew of the mot or c ontroll er shi eld c on structi on.

Soldering
S ol dering i s ea sy to do if you un dersta n d the ba si c pri n c i pl es a nd ha ve a l ittl e
pra c ti c e. The t ri c k for making a good solder joi nt i s to provi de the rig h t amount
of heat to the pa rts to be soldered a n d use the rig ht sol der. 22 AWG solder
(0.6mm or .025 inc h) or thi nner i s a g o od c hoi c e for solderi ng pri nted c i rc uit
boards. A 25-watt to 40-watt i ron, i dea l l y with tem perature control, is best. The
com p on ent s to be joined shoul d be m ec ha ni c a ll y secure so they don't m ove
whi le the sol der i s c ooli ng-wi res shoul d be c rim ped a round term i nal s ( see
Fig ure 4- 1 1 a n d Fig ure 4- 1 2). To make the joint, th e tip of th e i ron shoul d ha ve
g ood c onta c t with all the c omp onen ts to be soldered. Feed a sma ll a m oun t of
solder where th e iron i s touc hing t he pa rt s t o be j oi ned. When t he sol der flow s
a round the j oint, rem ove the solder first a n d then the i ron. The con n ection
sho uld be m ec ha ni c a l l y sec ure and the joi nt shi n y.

Building the Motor Controller


Th e motor control ler shi el d i s the h ea rt of thi s robot. As wel l a s controlling the
mo tors, all the sensors a re con n ec ted to Ardui no throug h thi s b oa rd. The shi el d
i s provi ded a s a kit a nd i s the sa m e for use with either t he 2WD a nd 4WD robots,
differing onl y in the m ethod of connecting th e motors an d m ounting to the
c ha ssi s (both a re deta i l ed in later cha pters).
The following i s a n overvi ew of the c on struc tion with som e ti ps tha t you shoul d
rea d throug h before sta rting to bui l d the c i rc ui t boa rd. You c a n fi nd step by
st ep co nstructi on detai l s for the shi el d at thi s site: http://ladyada.net/make!
mshield!so/der.html
Fig ure 2- 1 sh ow s the c om pon ents for the shi el d.

10
Construction Tech niques

Figure 2-1. Parts required to build the Motor Shield

The parts to the right of (as well as below) the board are packed with
the shield, but the three 6-pin headers on the left are not supplied with
the standard shield. These headers are used to connect the sensors.
These headers are included with the Maker Shed companion kits that
go along with this book. You can also purchase female headers from
Adafruit and other suppliers.

The two Maker Shed kits can be found at http://www.makershed.com/


Bots_and_Bits_for_Bots_s/46.htm. Look for either the Rovera 2 W
(Arduino-Controlled 2 Wheel Robotics Platform) o r Rovera 4 W (Ardu­
ino Controlled 4 Wheel Robotics Platform).

S older the sma l l e st componen ts fi rst (F i gure 2-2). The three sma l l ca pacitors
and two resi stors a re n ot polarized so you ca n i n sert th em either way a r oun d.

Chapter 2 11
Construction Techniques

Figure 2-2. Solder the Small Components

The resistor network (the long thin component with ten pins) is polarized­
the end with the white dot goes to the left of the PCB (nearest to C l ) as shown
in Figure 2-3.

Figure 2-3. Solder the resistor network - the marker (circled) indicates correct orientation

The large capacitors, I Cs, and L ED are all polarized. The color of the components
shown in the step-by-step assembly pictures on the Adafruit site (you can find
the link at the beginning of these build notes) may not match the components
or layout for the parts you received (particularly the capacitors) so carefully

12
Construction Techniques

check that you have placed the correct value component in the correct orien­
tation. Figure 2-4 shows the layout for version 1 .2 of the shield PCB. The kit
includes two IC sockets for the L 293D chips. As mentioned in the assembly
instructions on the Adafruit site, these are optional but if you like to play safe
and want to use the sockets, solder them so the indent indicating pin 1 matches
the outline printed on the PCB.

Figure 2-4. Solder the rest of the polarized components

Figure 2- 5 shows the board with all of the standard shield components (push­
button, headers, screw terminals) soldered. The final assembly step is to solder
the three 6-pin female headers near the analog input pins. These headers are
not included in the shield package or mentioned in Adafruit's step-by-step
build instructions, but are included with the Maker Shed kits.

Chapter 2 13
Construction Techniques

Figure 2-5. Everything soldered except the sensor headers

Figure 2-6 s h ows all compon ents i ncl u di ng th e s ensor h eaders sol dered. Tri m
th e component pi ns ( except th e h eader pins th at c onnect th e s h i el d to th e
Ardui no) on th e u ndersi de of th e board so th ey are cl ear of th e Ardu i n o when
th e shi eld is p lugg ed onto th e board. Locate one of th e jumpers suppli ed with
th e s h i el d and pl ug thi s onto th e pi ns m arked power jumper-thi s conn ects
th e motor p ower i nput and th e Ardui no VI N (power i nput) tog ether so both
are fed from th e batteri es th at you will be wiring after you h ave bui l t th e robot
chassis.

14
Construction Techniques

Figure 2-6. Shield with sensor headers

Figure 2-7 shows where all of the sensors and other external devices will be
connected. The three pin female headers are not needed for some of the
projects but you will find it convenient to solder these to the shield at this time.
Figure 2-8 shows two styles of connections. On the left, you'll find the
stripboard-based wiring scheme as described in "Making a L ine Sensor
Mount" (page 17). As you'll see in later chapters, you can experiment with a
variety of mounting methods, including the stripboard-based one. The right
side of Figure 2-8 shows the wiring for separately connected sensors. As you
read through the later chapters and experiment with various mounting tech­
niques, you'll use one or the other wiring schemes. Because you'll be using
sockets and ribbon connectors to hook up the sensors, you won't be locked
into any particular connection scheme; you can mix and match.

Chapter 2 15
Construction Techniques

The leff and right designation in the diagram refers to leff and right
from the robot's perspective, and the later chapters will explain where
to connect these.

To
Servo

2 servos
2 s t ep p e r
4 de m o t o r
v1.2

motor control 0
s h i e l d f o r a r du i n o
IR
Module

AS

To
Battery Left Right Center
Reflectance Sensors

Figure 2-7. Connections for devices covered in the chapters to come

16
Construction Techniques

IR IR
Module Module

A5 A5

Left Rig ht Center Left Right Center


Reflectance Sensors Reflectance Sensors

Figure 2-8. Connec tion detail - stripboard wiring is shown on the left, individual jumpers shown
on the right

Soldering the Reflectance Sensors


Each sensor package contains a small PCB and a 3-pin header. Insert the header
so the shorter length pins emerge on the side of the board with components
already soldered, see Figure 2-9 . After ensuring you have the header the right
way around, solder the three pins.

Figure 2-9. QTR-lA Reflectance Sensors

Making a Line Sensor Mount


The line sensing project in this book uses three reflectance sensors wired to
analog inputs. Although it is possible to wire the three connections (+SV, Gnd,
and Signal) using 9 jumpers, it is more convenient to use a small piece of

Chapter 2 17
Construction Techniques

stripboard to connect the power lines together. Header sockets soldered to


the stripboard enable the sensor to be easily unplugged so you can change
configuration if you want to swap back and forth between line and edge de­
tection. Figure 2-10 shows the layout of the stripboard (note the five holes
you'll need to drill out with a hand drill). Figure 2-12 shows the wires soldered
directly to the stripboard pads. If you'd like to add some strain relief, you can
drill out a few extra holes in an unused area of the stripboard. Next, divide the
wire into two groups (one for positive and negative, and three for the analog
pins), and feed the wires through large holes in the board before you solder
them. That way, if you tug on the wires, they'll pull against the holes before
they pull against your solder joints.


1111

• Gnd +5v

Figure 2-10. Stripboard layout for moun ting QTR-lA reflectance sensors for line following

To ensure that the mounting bolts don't short the tracks, you can either cut
the tracks as shown in Figure 2- 10 (you will be cutting along the third column
from the left, or the "C" column) or use insulated washers between the bolts
heads and the tracks. Figure2- 11 shows how the header sockets are connected,
and Figure 2-12 shows the completed stripboard, with the ribbon cable con­
nected. A ten inch length of cable is more than ample. Figure 2-1 3 shows the
other end of the ribbon connected to shield pins.

18
Construction Tech niques

Figure 2-11. Stripboard with three 3 pin header sockets

Figure 2-12. Stripboard with all wires soldered

Chapter 2 19
Construction Techniques

Figure 2·13. Ribbon cable connections t o shield pins

The m ethod of m ou nti ng the strip b oa rd depen ds on the rob ot cha ssi s; see
Chap ter 3, Building the Two-Wheeled Mobile Platform or C hap ter 4, Building the
Four-Wheeled Mobile Platform. The three h ol es shown will sui t ei th er cha ssi s
but you may p refer to wa i t until y ou ha ve bui l t the cha ssi s a nd only dri l l the
hol es you need.

Next Steps
The nex t sta g e i n bui l di ng the robot is to a ssem ble the cha ssi s. C hap ter 3 cover s
the two-wheeled robot a nd C hapter 4 i s for the four-wheeled versi on.

20
Building the Two-Wheeled
Mobile Platform

This chapter provi des ad vice on the constructi on of a Two Wheel Dri ve (2WD)
chassis with front caster, as shown in Fi g ure 3- 1 . C onstructi on is st raig htfor­
ward; y ou can fol l ow the detai led steps or i mprovise if you want to cust omize
your robot. The chapter als o shows how you attach and c onnect sensors used
i n the projects c overed i n later chapters.
If you prefer to build a two wheeled robot of your own des ign, you should read
the sect ions on attaching control electronics and sens ors; this will prepare you to
use the code for the projects in the chapters to come. Inform ati on in this chapter
my also provi de s ome ideas to help with the des ig n of your own robot.

21
Hardware Required

Figure 3-1. 2WD Robot Chassis

Hardware Required

• Tools listed in "Tools" (page 6 )


• The assembled electronics (see Chapter 2 , Building the Electronics
• 2WD Mobile Platform (two wheeled robot kit made by DFRobot)
• Two 0. 1 uF ceramic capacitors
• Two lengths of 3 conductor ribbon cable, two 3 way 0.1" headers for edge
sensors
• Optional: charging circuit resistors and diode, see detailed parts list

22
Mechanical Assembly

Mechanical Assembly
Lay Out the Chassis Parts
Figure 3-2 shows a ll of the parts contai ned in the 2WD chassi s packa g e. The
three bla ck bra ckets to the left of t he figure are not needed fo r a ny of the
proj ects i n t hi s book.

Figure 3-2. 2 WD Chassis Parts

Fig ure 3-3 shows the contents of the bag contai ni ng t he mounting hardwa re.
Locate t he two bolt s with t he flat hea ds a nd put t hem a si de for mounting the
battery case. Also i dentify t he two thi cker (M4) bolts that will be used to attach
the caster. The rema i ning short bolt s in t his pack a re i dent i ca l.

Chapter 3 23
Mechanical Assembly

0
0

Figure 3-3. 2WD hardware pack contents

Motor Assembly
Use two long bolts with lock washers and nuts, as shown in Figure 3- 5, to attach
each motor to the chassis lower plate. Tighten the nuts snugly but take care
not to stress the plastic motor housing.

Lock washers are used to prevent a nut from accidentally coming lose
due to vibration. This is particularly important for attaching the motor
and switch. These washers have a split ring or serrations that apply
extra friction when tightened.

If you find that things still come lose, don't overtighten the nuts; an
effective solution is retighten the nut and apply a dab of nail polish to
the point where the threads emerge from the nut.

Figure 3- 4 shows the motors in place with the nut seen on the upper right
ready to be tightened.

24
Mechanical Assembly

Figure 3-4. Motors moun ted on the chassis lower plate

Chapter 3 25
Mechanical Assembly

Chassis
Lower Plate

-
--
....._..◄

-.-.....◄

M 2 . 5x25mm
Phillips Bolts
Lock M2 .5
Washer N ut
Washer
Figure 3-5. Motor Assembly

Assembl e the Chassis Components


P ush the wheels o nto the motor assem bly shafts, a li g ni ng the slots i n the
wheels with the flat section of the moto r shaft. Attach the caster with two M4
bolts a nd nuts. Fig u re 3-6 a nd Fi g u re 3-7 show this.

26
Mechanical Assembly

Caster
M4 N ut

Figure 3-6. Motor Assembly

Figure 3-7. Wheels and caster mounted

Chapter 3 27
Mechanical Assembly

Attac h the sensor bracket to the undersi de of the lower c ha ssi s plate, as seen
i n Fi g u re 3-8 a nd Fi gure 3-9.

This robot is sometime s built with the se nsor plate mounted at the
opposite e nd of the cha ssis (furthest from the ca ster). You ca n bu ild
yours however you like, but the orie ntation s hown here enable s the
servo moun ted distance scanner to be attached in the front ofthe rob ot.
Also, the se nsor bracket in this location maximizes the dista nce be­
tween the wheels a nd the line sensors a nd this improve s line following
sensitivity.

Figure 3-9 shows the un dersi de of the cha ssi s after mou nti ng t he sen sor brack­
et. Note that the sensor bracket i s attac hed to t he bottom of the c ha ssi s plate.

Figure 3-8. Sensor bracket viewed with the robot right Figure 3-9. Sensor bracket viewed with the robot up-
side up side down

The battery pack is bolted to the bottom ba se plate with two cou ntersu nk (flat
headed) Phil li ps bolt s a s shown in Figure 3- 1 0 a nd Figu re 3-1 1 . You may wa nt
to delay thi s step unti l after t he battery lea ds ha ve been soldered to make it
ea si er to po sition a l l the wires.

28
Mechanical Assembly

Figure 3-10. Motor Assembly


Figure 3-11. Chassis with Battery Pack Attached

C u t two p i ec es of red/black wi re, each a bo u t 7 1 /2 i nches long. Stri p to ex pose


a bo ut 3/1 6 i nch of bare wire at one end of the wi res a nd a ttach to the motor
termi nals. S trip 1 /4 i n ch off the other end of the pai rs of wi res; th ese will be
connected to th e motor sh i el d. Connect a 0.1 uF capa ci to r a cross ea ch of th e
mo tor termi nals, as shown i n Fig ure 3- 1 2. The ca pacitors sup press electrica l
spi kes g enera ted by th e mo tor tha t could i nterfere with signals on th e Arduino
boa rd.

Figure 3-12. Wires and capacitors soldered to Motors

Chapter 3 29
Mechanical Assembly

The DC power jack is bolted to the top plate using the large (MB) lock washer
and nut. The switch is mounted using two (M6 ) nuts and a lock washer. Put
one nut on the switch leaving around 3/16 " of thread above the nut. Then place
the lock washer on the thread and push this through the opening in the rear
plate and secure with the second M6 nut.
Orient the switch so the toggle moves towards the jack, as shown in Figure 3- 1 3
and Figure 3-1 4 (Figure 3- 1 5 shows the view from beneath).

Top
Plate

0 0
0 0

0
0 0

M6 N ut

Lock �
Washer
M6 Nut
' Lock
Power Washer
Switch DC
Charger
Jack
Figure 3-13. Switch and Jack Assembly

30
Mechanical Assembly

Figure 3-14. Top panel showing location of switch and Figure 3-15. Top panel underside showing orientation
DC jack of switch and jack

The battery can be wire d a s sh own i n Figu re 3- 1 6 a n d Fi g u re 3- 1 7. The power


switch wil l di scon nect the battery when the robot is n ot in use. The DC j ack i s
n ot u se d i n thi s configurati on ( other than a s a j u n ct i on poi nt fo r t he bl ack
g r ou n d wi res). The switch i s off when the togg le i s closer to t he DC jack a s
shown (the toggle i s a lever; when the ex pose d en d i s u p a s seen i n the fig ure,
the conta ct at the bottom i s con nected a n d the conta ct wi re d t o the shiel d i s
open).

Power
Switch

Figure 3-16. Basic Switch Wiring (no trickle charger)

Chapter 3 31
Mechanical Assembly

Figure 3-17. Solder the battery wires to the switch

You ca n b ui l d a sim ple trickle charg er i nto the robot if you wi ll be usi ng re­
char g eab le N i M H b atteri es. Th e c harg er ca n be built usi ng the circui t shown
in F i g ure 3- 1 S a nd Fi g ure3- 1 9. S ee"TrickleCh argi ng" (pa g e 229) for i nform ation
abou t usi ng the c harg er.

Charging
Jack
9 -1 2V DC

Power
Switch

Figure 3-18. Optional Trickle Charger Wiring

32
Mechanical Assembly

Figure 3-19. Wiring of the optional charger jack

The easiest way to mount the Arduino board is with a strip of Velcro. A 2.5" x
1 .5" strip is supplied with the Rovera 2W (Arduino- Controlled 2 Wheel Robotics
Platform) kit. To prevent the Arduino pins from accidentally shorting to the
chassis, apply insulating tape to the underside of the Arduino board. Gaffer
tape works well but you can use (non- conductive) duct tape or heavy duty
electrical tape. Attach the 'hairy' side of the Velcro to the taped Arduino board,
the hook side is fastened as shown in Figure 3-20.

Chapter 3 33
Mechanical Assembly

Figure 3-20. Velcro pad in position on the 2WD chassis. Inset shows Velcro attached to the
Arduino board.

Figure 3-21 shows the mounted boards. The Velcro will hold the boards in
position when the robot is moving about, but use one hand to steady the
Arduino when you unplug the shield and take care not to use too much down­
ward pressure that could push the Arduino pins through the tape when plug­
ging in the shield.

34
Mechanical Assembly

Figure 3-21. Arduino board mounted using Velcro

If you prefer a more rigid mo unt, you can use two of the 1 0mm brass standoffs
suppl ied with the chassi s and two M3 bolts and nut s ( seen on the rig ht side of
the board as shown in Figure 3-22). U se a 1 0m m spacer and M2.5 in the hole
near the re set switch. (The hol e near the DC j ack at the lower l eft is not used.)

The spacer is required fora Leonardo board because there is insufficient


space for an M3 bolt in the munting hole near the switch. The Uno
board has more room so you can use a another of the 1 0mm spacers
and M3 hardware for moun ting tha t board.

Fig ure 3-23 shows the location of the mounting poi nt s viewed from the un­
dersi de of t he panel.

Chapter 3 35
Mechanical Assembly

Figure 3-22. Mounting the A rduino board as viewed Figure 3-23. Underside showing location of the three
from the top of the chassis Arduino mounting points

Atta ch the top plate wi th four M3 bolts a s s h own in Fig ure 3-24.

M3x6 Truss
(Flange} Bolt

Figure 3-24. Top Plate Assembly

36
Mechanical Assembly

Attaching the Control Electronics


Figure 3-25 shows where the battery and motor wires are con nected. L eft and
right are from the robot's perspective (the right wheel is the one closest to the
switch). Figure 3-26 shows the main electronics in place.

.....,
To

Figure 3-25. Motor and battery connections

Chapter 3 37
Mounting the I R sensors

Figure 3-26. 2 WD built and ready to mount sensors

Mou nti ng the I R sensors


This section covers mounting of the infrared (IR) reflectance sensors for use in
edge detecting or line following. "Infrared Reflectance Sensors" (page 1 34) ex­
plains how these sensors work and Chapter 9 , Modifying the Robot to React to
Edges and Lines describes how to use IR sensors. This section explains how to
mount these to the 2WD platform and connect them to Arduino. The first
projects in this book should have the sensors mounted as shown in the section
on edge detection. When you are ready to i mplement the line following ap­
plication in Chapter9 , refer back to the section here on positioning the sensors

38
Mounting the I R sensors

for li ne followi ng. The stripboard mount descri bed in "M aki ng a Li ne Sensor
Mount" ( pag e 1 7) si mplifi es the attachm ent and wiring of the sensors for line
detection and thi s can also be u sed for edg e detection, bu t bear in mi nd th at
the robot will perform the edg e detection task best with the sensors further
apart. If the sensors are clo se tog ether, the ro bot can have diffi culty determin­
i ng the best angle to turn when an edge i s encountered.

Mounting the I R Sensors for Edge Detection


E dge detection req ui res two QTR- 1 A senso rs mounted on the front of the ro­
bot. These should be spaced as wi dely as po ssi bl e. The i deal location i s wi th
each sensor po si tioned i n front of a wheel so an edg e can b e detected before
a w heel would otherwi se fall off a 'cliff'. However, if your priori ty i s si mpli ci ty
of construction rather than accuracy of edge detection, yo u can use the same
mo unt descri bed i n the nex t section co veri ng line detection.
The si de with the sensor faces the g round and the header pins face upwards.
Mount each sensor usi ng a 2-56 bolt and nut (M2 bol ts and nuts can al so be
u sed) with a 1 /2" plasti c spacer so the face of the sensor i s 3/8" or clo ser to the
g rou nd. Figure 3-27, Fig ure 3-28, Fig ure 3-29, and Figure 3-30 show sugg ested
mounti ng.

Figure 3-27. Reflectance Sensor location for Edge Detection

Chapter 3 39
Mounting the I R sensors

Figure 3-28. Edge Detection Sensor Mounting Detail

Figure 3-29. Front view showing location of the Edge Figure 3-30. Edge sensors wired and ready to run
Detection Sensors

40
Mounting the IR sensors

Mounting the I R Sensors for Line Following


Three QTR- 1 a sensors are required for line following. "Making a L ine Sensor
Mount" (page 17) describes how to build a stripboard mount for line sensing.
However, you can also mount and attach each sensors as described in this
section if you want to experiment with how varying the spacing of the sensors
affects line following.
The sensors can be attached using 2- 56 or M2 hardware. The component side
faces down and the header pins face upwards. They are mounted in the front,
eq ually spaced with approximately 1 /2 inch between the center and the left
and right bolts (Figure 3-3 1 ).

--+
--
T.35 - .5
inch
.35 - .5
_ _ J_ inch

Figure 3-31. Reflectance Sensor location for L ine Following

If you use the stripboard mount for line sensors covered in Chapter 2, Building
the Electronics, the stripboard can be mounted above or below the sensor
bracket, enabling you to experiment with sensor distance to the ground-but
use insulated washers to ensure that the tracks with sensor connections are
not shorted to the bracket. Figure 3-32 and Figure 3-33 show how the strip­
board can be mounted.

Chapter 3 41
Mounting the I R sensors

Figure 3-32. Reflectance Sensor location for line following

42
Next Steps

Figure 3-33. Reflectance Sensor location for line following. alternate view

See Figure 3-2 7 for information on connecting the stripboard wires to the mo­
tor shield.

Next Steps
Chapter S, Tutoria l: Getting Sta rted with Arduino explains how to set up and use
the development environment that will be used to upload code to the robot.
If you are already an Arduino expert, you can skip to Chapter 6 , Testing the
Rob ot's Basic Fu nctions, but first, see "I nstalling Third-Party Libraries" (page 83)
for advice on the libraries used with the code for this book.
If you have the libraries installed and want run a simple test to verify that the
motors are working correctly, you can run the sketch shown in Example 3- 1 .

Example 3-1 . Initial m otor test for 2 WD


/ *******************************************
* MotorTest2wd . ino
* I nitial Moto r test for 2WD - robot rotates clockwise
* Left Moto r d r iven fo rwa rd , right backwa r d
* then cou nte r - clockwise

Chapter 3 43
Next Steps

* Michael Ma rgolis 24 July 2012


***** ****** *** ******** *** *** * ** *** ******** ** /
con st int LED_PIN = 1 3 ;
con s t int s peed = 60 ; II percent of MaxiMuM s peed

#include <AFMotor . h> II adafruit Moto r shield libr a ry ( Modified MY MM )


AF_DCMotor Moto r_Left ( l , MOTOR12_1KHZ ) ; I I Motor 1
AF_DCMotor Moto r_Rig ht ( 2 , MOTOR 12_1KHZ ) ; II Motor 2

int pwM ;

void setup ( )
{
Serial . begin ( 9600 ) ;
blinkNuMbe r ( S ) ; II open port while flashing . Needed for Leon a rdo only

II scale percent into pwM range ( 0 - 2 5 5 )


pwM= Map ( s peed , 0 , 100 , 0 , 2 5 5 ) ;
Motor_Left . setSpeed ( pwM ) ;
Motor_Rig h t . setSpeed ( pwM) ;
}

II run over and over


void loop( )
{
Serial . println ( " rotate cw " ) ;
Motor_Left . r un( FORWARD ) ;
Motor_Rig ht . run ( BACKWARD) ;
delay ( 5000 ) ; II run fo r 5 seconds
Serial . println ( " rotate ccw" ) ;
Motor_Left . r un( RELEASE ) ; I I stop the Moto rs
Motor_Rig h t . ru n ( RELEAS E ) ;
delay( S000 ) ; II stop for 5 seconds
}

II fu nction to indicate nuMbers by fla shing the built - i n LED


void blinkNuMbe r( byte nuMbe r ) {
pi nMode ( LED_PIN , OUTPUT) ; II enable the LED pin for output
while ( nuMbe r - - ) {
digitalWrite ( LED_PI N , HIGH ) ; delay ( 1 00 ) ;
digitalWrite ( LED_PI N , LOW) ; delay(400 ) ;

Thi s sketch runs the motors i n o pposite d i rections to cause the robot to rota te
clockwise for 5 second s, then reverses direc tion to ro ta te co un ter-clockwi se.
Th i s will repea t until the power is swi tched off.

44
Building the Four-Wheeled
Mobile Platform ..,.

This chapter provides advice on the construction of the 4WD (4 Wheel Drive)
chassis shown in Figure 4-1 . Construction is straightforward-you can follow
the detailed steps or improvise if you want to customize your robot. The chap­
ter also shows how you attach and connect sensors used in the projects cov­
ered in later chapters.
If you prefer to build a four wheeled robot of your own design, you should read
the sections on attaching control electronics and sensors if you want to use
the code for the projects in the chapters to come. Information in this chapter
my also provide some ideas to help with the design of your own robot.

45
Ha rdwa re Req u i red

Figure 4-1. The 4 WD robot chassis

You will need a Phillips screwdriver, long- nose pliers, wire cutters, wire strip­
pers, a soldering iron, and solder. If you don't have these on hand, you can find
more information in Chapter 1 , Intro ductio n to Robot Building.

Hardware Required
• Tools listed in "Tools" (page 6 )
• The assembled electronics (see Chapter 2 , Building the Electronics
• 4WD Mobile Platform (four wheeled robot kit made by DFRobot)
• Four 0.1 uF ceramic capacitors
• Two lengths of 3 conductor ribbon cable, two 3 way 0.1" headers for edge
sensors
• Optional: charging circuit resistors and diode, see detailed parts list

46
Mechanical Assembly

Mechanical Assembly
Mechani ca l a ssembly of the 4WD cha ssi s i s stra i g h tforwa rd a nd the only tools
needed a re a Philli p s screwdri ver a nd pliers. Followi ng the steps i n order will
e nsu re that you u se the correct hardwa re in each a ssembly. You w i ll nee d a
solderi ng i ron, wire cutte rs, a nd wire strippe rs to wire u p the m otor a nd power
lead s.

Lay Out the Chassis Parts


Fi g u re 4-2 sh ows a ll of the pa rts contai ne d i n the 4WD cha ssis pa cka ge.
Fi g u re 4-3 sh ows the contents of the ba g conta i ni ng the mou nti ng hardwa re.
The three black brackets to the left of the fi g u re a re not needed for a ny of the
projects i n this b ook. Loca te the two bolts with the flat heads a nd put them
a side for m ou nting the battery ca se. The rema i ni ng sh ort b olts i n thi s pa ck a re
identi cal.

Chapter 4 47
Mechanical Assembly

..
•• • •. . • • • •

Figure 4-2. 4 WD chassis parts

48
Mechanical Assembly

0
oo

Figure 4-3. 4 WD hardware pack contents

Motor Assembly
Use four long bolts to attach two motors to each of the s i de plates. The motor
shaft goes through the la rge hole a n d there i s a small locati ng stud on the
motor that fits into the sma ller hole. The lock washer (the one with a ra ised
e dge) goes between the n ut and flat washer. Ensure the m otor is flat agai nst
the plate and ti ghten the n u ts firm ly but take ca re not to use too much force
or you wi ll stress the plastic motor hous i n g. Figure 4-4 a n d Fig ure 4-5 shows
the assembly.

Chapter 4 49
Mechanical Assembly

,,..---
M2 . 5x25mm
Philips Bolts

Motor ��,ide Plate


Assembly

,
,
,, ,,
.,.'ff,' ,/
@· ,/

M2.5 Washe
Lock Washer
M2.5 Nut
Figure 4-4. Mo tor assembly

Lock washers are used to p revent


a nut fro m accidentally co ming
loose due to vib ration. This is crit­
ical for attachin g the moto r and
s witch. Th ese washers have a
sp lit ring o r serrations that app ly
extra friction when tig hten ed. If
you find that thin gs s till come
loose, don't overtig hten the nuts.
Instead, retighten the nut and
apply a dab of n ail po lis h to the
Figure 4-5. Motors mounted onto side plates point whe re the threads emerge
fro m the nut.

50 M a ke an Ard u i n o-Control led R obot


Mechanical Assembly

Assembl e the Chassis Components


The battery p ack i s bolted to the bottom base plate with two cou n tersunk (flat
headed) Phillips bolts as shown in Fig u re 4-6 and Fig ure 4-7.

M3
Battery
Countersu nk
� Holder
Bolt
f

M3 Nut Base Plate


Figure 4-6. Battery holder assembly

Chapter 4 51
Mechanical Assembly

Figure 4-7. Battery holder assembly

The DC power jack i s bolted to the rear pl ate u sing the larg e (MB) lock washer
an d n ut as shown in Figu re 4-8. The switch i s m ounted using two nut s and a
l ock washer (the locatin g washer i s n ot u sed). Put on e n u t on the swi tch, l eaving
abou t enoug h thread for the nut to be att ached to the other si de. Pl ace the
l ock washer on the thread an d pu sh thi s through the open i ng i n the rear plate
an d secure with the secon d M6 n u t. Orient the switch so the toggle m oves
from si de to si de, as shown in the figure. Fig ure 4-9 an d Fig u re 4- 1 0 show two
views of the assembly.

52
Mechanical Assembly

M6 Nut � M8 N ut
�M8 Lock
rWasher
,----l"(
ear Plate
/

M6 Lock
'

Washer �
/
'

M6 N ut

Power
Switch
l_ DC Power
Jack
Figure 4-8. Switch and power jack assembly

Figure 4-9. Rear panel switch and power jack assem· Figure 4-10. The other s ide of the panel showing the
bly viewed from the front switch orientation and power jack

Chapter 4 53
Mechanical Assembly

Solder the Power and Motor Connections

It is easier to solder the connections before ev­


erything is bolted together. The motor con­
nections use the red and black wire provided
in the kit. Cut four pieces, each three inches
long. Strip 1 /4 inch off the red and black wires
on one end; this end con nects to the motor
shield. The other end is connected to the motor
terminals; strip to expose about 3/1 6 inch of
bare wire. Connect a 0.1 uF capacitor across
each of the motor terminals, as shown in
Figure 4-1 1 . The capacitors suppress electrical
spikes generated by the motor that could in­
terfere with signals on the Ardui no board. Con­
nect and crimp the wires as shown in
Figure 4- 12, and then solder the wires and ca­
pacitors to the motor terminals as shown in
Figure 4- 1 3.
Figure 4-11. Crimp the capacitor leads to the motor
terminals

Figure 4-12. Crimp the w ires Figure 4-13. Solder the motor terminals

54
Mechanical Assembly

Connecting the Battery Pack and Power Switch


The battery ca n be wired a s shown in Fi gure 4- 1 4, but you ca n n ot c ha rge t he
battery in t h i s c onfi g u rati on. Th e p ower switch will d i sconnect the battery
when the robot is n ot in u se. The DC jack is n ot u sed in thi s c onfi g u rati on (ot her
tha n a s a j u ncti on p oint for t he black ground wires) . The switch is off when t he
tog gle i s closer to t he DC jack a s sh own (the t og g l e i s a lever, when t he exp osed
end is up as seen in t he fi gure, t he contact at t he b ottom is con nected a n d t he
c ontact wired to the shi eld is open). Fi g u re 4-1 5 shows t he c ompleted c i rc u it.

Power
Switch

Figure 4-14. Basic s witch wiring (no trickle charger)

Figure 4-15. Red wires soldered to switch

Chapter 4 55
Mechanical Assembly

Building the Optional Trickle Charger


You can build a simple trickle charger into the robot if you will be using re­
chargeable NiMH batteries. See "Trickle Charging" (page 229 ) for information
about using the charger.
The circuit is wired as shown in Figure 4- 16 and Figure 4- 17 . The battery is
connected to both the robot and charger when it is switched on, enabling the
Arduino to monitor and display the battery voltage. The connection via the
resistor to pin 13 is required to tell the Arduino that a charger is connected so
it can monitor the voltage instead of driving the robot.

Charging
Jack
9 -1 2V DC

Power
Switch

Figure 4-16. Wiring for trickle charging with Arduino voltage monitoring

56
Mechanical Assembly

Figure 4-17. Wiring for trickle charging with Arduino voltage monitoring

Assembl e the Chassis


Attach th e front an d rear plates to th e si des u sing eig h t of th e M3x6 bolts
(Fig ure 4-1 8). Th e si des are sym metrical so i t do esn' t ma tter which en d goes
to th e front or back.

Side Plate j

Rear Plate

M3x6 Truss } .i, Front


(Flange) Bolt Plate

Figure 4-18. Chassis assembly

Attach th e bot tom p late u sing fou r M3x6 bolts (Fig u re 4- 1 9).

Chapter 4 57
Mechanical Assembly

Bottom Plat
M3x6 Truss
(Flange) Bolt
i

Figure 4-19. Bottom plate assembly

Mounting Arduino and Connecting Wires to the Shi eld


The ea si est wa y t o mou nt t h e Arduino b oard i s with a strip of Velcro. A 2 . 5 " x
1 .5" strip i s suppli ed with the R overa 4W (Ardui no-Control l ed 4 Wheel R obotics
Platform) kit. To prevent the Ardui n o pin s from a cci denta l l y shorti ng t o the
cha ssi s, apply insu lati ng tape t o the u ndersi de of the Ardui no boa rd. Gaffer
ta pe w ork s well but you ca n u se (non-conductive) du ct tape or hea vy duty
electri ca l tape. Atta ch the 'hai ry' si de of the Vel cro to the taped Ardu i n o b oard;
the hook si de i s fa sten ed a s shown i n Figure 4-20. Fig ure 4-2 1 shows som e
other vi ew s of thi s.

58
Mechanical Assembly

Figure 4-20. Velcro pad in position on the top plate

The Velcro will hold the boards in position when the robot is moving about,
but use one hand to steady the Arduino when you unplug the shield and take
care not to use too much downward pressure that could push the Arduino pins
through the tape when plugging in the shield.

Chapter 4 59
Mechanical Assembly

Figure 4-21. Inset shows Velcro attached to the Arduino board.

If you prefer a more rigid mount, you can use three 3/8" or 1/4 inch (5mm)
spacers with three 1/2 inch 2-56 bolts and nuts. Figure 4-22 and Figure 4-23
show the location of the mounting hardware.

• • •


ta II


I :,,
:1
,


• •
Figure 4-22. A rduino board mounted using three Figure 4-23. Underside view showing mounting nuts
spacers

Figure 4-24 shows the motor wires and battery wires inserted through the
cutouts in the top plate ready for the connections shown in Figure 4-25 .

60
Mechanical Assembly

Figure 4-24. Wires ready to connect to shield Figure 4-25. Wires connected

Fi g ure 4-26 sh ows h ow the m otor a nd battery wires attach to the c onnectors
on the motor sh ield.

CCXC 0 D1 2tal 1/D


00000000 00000000
□ 1 2tal 1/D

CCXC
- + s
AAef qnd 1 3 1 2 1 1 1 0 9 8 6 5 4 3 2 l 0
□ □ □ 0• 0M l 502 05 1 0• 0• 0M3 0M4 0e 0M2 □ □ □
� .�----
.. - - --- - - - - �
7

- - - - - - - ..
O Used pins -+

0
·�
2 servos
2 s t epper
4 de motor
0 Left
v1.2 Front
Motor
Left
Rear
Motor

Right
Rear
Motor
------
• • • • ■ • +5
al
Gnd
0
shield f o r arduino ■ ■ ■ ■ ■ I
GND
,e� w!� O D O D D 01
J,= � S T 3v 5v Gnd Vin

0
I
1

2

3

4
I
5
l.a,,gJ 0 0 0 0 0 0 0 0Analo
000 [n
0

To
Battery

Figure 4-26. Motor and battery connections

Chapter 4 61
Mechanical Assembly

Attac h th e sen sor plate wit h two M3 bolt s as shown in Fig ure 4-27; the to p
plate i s attach ed usi ng four M3 bolt s as seen i n Fig u re 4-28.

M3x6 Truss
( Flange) Bolt

Top Plate

Figure 4-27. Sensor plate assembly

M3x6 Truss
(Flange) Bal�

Figure 4-28. Top plate assembly

62
Mechanical Assembly

The u pper dec k is b olted to four 50m m sta ndoffs that a re attached a s s hown
in Fi g u re 4-29.

M3x6 Truss
(Flange) Bolt -----,

y
' '
'
'

M2x50
Standoff

Figure 4-29. Attach the upper deck

Chapter 4 63
Mechanical Assembly

Figure 4 -30 shows the fully-assembled chassis (a side view is visible in


Figure 4-3 1). You can seethe front and rear views in Figure4 -32 and Figure 4-33.

-
Figure 4-30. The assembled chassis Figure 4-31. Side vie w

I I

.,
II

Figure 4-32. Front view Figure 4-33. Rear view

64
Mounting the I R sensors

Mou nting the I R sensors


This section covers mounting of the infrared (IR) reflectance sensors for use in
edge detecting or line following. "Infrared Reflectance Sensors" (page 134) ex­
plains how these sensors work and Chapter 9 , Mo difying the Robot to Rea ct to
Edges and Lines descri bes how to use I R sensors. This section explains how to
mount these sensors onto the 4WD platform and connect them to Arduino.
The first projects in this book should have the sensors mounted as shown in
the section on edge detection. When you are ready to implement the line
following application in Chapter 9 , refer back to the section on positioning the
sensors for line following. The stripboard mount described in "Making a L ine
Sensor Mount" (page 1 7) simplifies the attachment and wiring of the sensors
for line detection and this can also be used for edge detection, but bear in
mind that the robot will perform the edge detection task best with the sensors
further apart. If the sensors are close together, the robot can have difficulty
determining the best angle to turn when an edge is encountered.

Mounting the I R Sensors for Edge Detection


Edge detection requires two QTR- 1 A sensors mounted on the front of the ro­
bot. These should be spaced as widely apart as possible. The ideal location is
with each sensor positioned in front of a wheel so an edge can be detected
before a wheel would otherwise fall off a 'cliff'. However, if your priority is sim­
plicity of construction rather than accuracy of edge detection, you can use the
same mount described in the next section covering line detection. But bear in
mind thatthe robot will perform the edge detection task best with the sensors
further apart. If the sensors are close together, the robot can have difficulty
determining the best angle to turn when an edge is encountered.
Mount each sensor using a 2-56 bolt and nut (M2 bolt and nut can also be
used). The component side faces the ground and the header pins face upwards.
The sensors can be angled as shown in Figure 4-34 and Figure 4-35.

Chapter 4 65
Mounting the I R sensors

Figure 4-34. Reflectance sensor location for edge detec tion

Figure 4-35. Reflectance sensor location for edge detection

66
Mounting the I R sensors

Mounting the I R Sensors for Line Following


Three QTR- 1 a sensors are requ ired for li ne followi ng. "M aki ng a Li ne S enso r
Mou nt" (pag e 1 7) d escri bes how to build a stripboard mo unt for l i ne sensi ng.
However, you can also mou nt and attach each sensors as descri bed i n thi s
sectio n if you want to exp eri m ent wi th how varyi ng the spacing of the sensors
affec ts l i ne fol lowi ng. Like th e edg e sensors, th ey ca n be a ttach ed u si ng 2-56
or M 2 h ardware. The compo nen t sid e faces down a nd th e h ea d er pi ns face
u pwards. They are mou nted i n the fro nt, equa lly spac ed with approxim ately
1 /2 inch between th e center and t he l eft and rig h t bolts ( see Fi g ure 4-36).
Figu re 4-37 and Figure 4-38 show the sensors attac hed to the c hassi s.

--
--+ T.35 - .5
i nch
.35 - .5
__ J_ inch

Figure 4·36. Reflectance sensor location for line following

Chapter 4 67
Next Steps

Figure 4-37. Reflectance sensor location for line follow­ Figure 4-38. Reflectance sensor location for line fol­
ing, viewed from front lowing, alternate view

Next Steps
Chapter 5, Tutorial: Getting Started with Arduino explains how to set up and use
the development environment that will be used to upload code to the robot.
If you are already an Arduino expert, you can skip to Chapter 6 , Testing the
Robot's Basic Functions, but first, see "Installing Third-Party Libraries" (page 83)
for advice on the libraries used with the codefor this book and the steps needed
to configure the RobotMotor library for the 4W D robot.
If you have the libraries installed and want run a simple test to verify that the
motors are working correctly, you can run the following sketch:

Example 4-1. Initial motor test for 4 WD


/ *******************************************
* MotorTest4wd . ino
• I nitial Motor test for 4WD
* robot rotates clockwise
* ( Left Motors d r iven fo rwa rd , right backwa r d )

• Michael Ma rgolis 2 4 July 2012


********************************************/
con st i n t LED_P IN = 13;
con st int speed = 60 ; // pe rcent of MaxiMUM speed

#include <AFMotor . h> // adafruit Moto r shield libr a ry ( Modified MY MM )


AF_DCMotor Moto r_Left_Front ( 4 , MOTOR34_1KHZ) ; // Motor 4
AF_DCMotor Moto r_Rig ht_F ront ( 3 , MOTOR34_1KHZ ) ; / / Motor 3
AF_DCMotor Moto r_Left_Rea r ( l , MOTOR12_1KHZ ) ; / / Motor 1

68
Next Steps

AF_DCMotor Moto r_Right_Rear ( 2 , MOTOR 12_1KHZ) ; // Moto r 2

int pwl'I ;

void setup ( )
{
Serial . begin ( 9600 ) ;
blinkNul'lbe r ( S ) ; // open po rt while flashing . Needed for Leonardo only

/ / scale percent into pwl'I range ( 0 - 25 5 )


pwl'I= l'lap ( s peed , 0 , 100 , 0 , 2 5 5 ) ;
Motor_Left_F ront . setSpeed ( pwl'I ) ;
Motor_Right_F ron t . setSpeed ( pwl'I ) ;
Motor_Left_Rear . set5peed ( pw1'1) ;
Motor_Right_Rea r . setSpeed ( pwl'I ) ;

/ / r u n ove r and over


void loop( )
{
Serial . p r intln( " rotate cw " ) ;
Motor_Left_F r on t . ru n ( FORWARD ) ;
Motor_Left_Rear . ru n ( FORWARD ) ;

Motor_Righ t_F ront . ru n ( BACKWARD) ;


Motor_Right_Rea r . run ( BACKWARD ) ;

delay( 5000 ) ; / / run fo r 5 seconds


Serial . p rintl n ( " stopped " ) ;
Motor_Left_F ron t . r u n ( R ELEAS E ) ; / / stop the l'lotors
Motor_Right_F ront . r u n ( RELEAS E ) ;
Motor_Left_Rear . ru n ( RELEAS E ) ; / / stop the l'lotors
Motor_Right_Rea r . r u n ( R ELEAS E ) ;

delay( S000 ) ; / / stop for 5 second s


}

/ / function to indicate n ul'lbers b y flashing the buil t - i n LED


void blinkNul'lber ( byte nul'lbe r ) {
pi nMode ( LED_PIN , OUTPUT) ; // enable the LED pin for output
while ( n ul'lbe r - - ) {
digitalWrite ( LED_PIN , HIGH ) ; delay ( 100) ;
digitalWrite( LED_PIN , LOW) ; delay(400 ) ;
}

This sketch runs the motors in opp osite directi ons to cause the rob ot to rotate
cl ockwise for 5 s econds, then stops for 5 s econds. This will rep eat u nti l the
p ower is switch ed off.

Chapter 4 69
Next Steps

This test sketch does not use the RobotMotor library-if this test func­
tions correctly but the tes t in Chap ter 6, Testing the Robot's Basic Func­
tions does not work, the most likely cause is the configuration of the
motor library-make sure you copy the 4wd version of the library code
as described in "Installing Third-Party Libraries" (page 83).

70
s
Tutorial: Getting Started
with Arduino

The Arduino environment has been designed to be easy to use for beginners
who have no software or electronics experience. If you are new to Arduino, this
chapter will help you get started but you will need to consult the Arduino
online help and a good book on Arduino will be a big help (the author's
"Arduino Cookbook" is highly recommended as reference.)

If you're already familiar with Arduino, please feel free to skip the in­
troductory materia l in this chapter. Ho wever, you will need to install
the libraries that are included in the do wnload the code available from:
http:!/s hop.oreilly.com!product/0636920028024.do. The sectio n "In­
stalling Third-Party Libraries" (page 83 ) ha s details o n installing the re­
quired libraries.

Arduino is best known for its hardware, but you also need software to program
that hardware. Both the hardware a nd the software are called "Arduino:' The
combination enables you to create projects that sense and control the physical
world. The software is free, open source, and cross-platform. The boards are
inexpensive to buy or you can build your own (the hardware designs are also
open source). I n addition, there is an active and supportive Arduino commu­
nity that is accessible worldwide through the Arduino forums and the wiki
(known as the Arduino Playground). The forums and the wiki offer project
development examples a nd solutions to problems that can provide inspiration
and assistance as you pursue your own projects.
The information in this chapter will get you started by explaining how to set
up the development environment and how to compile and run an example
sketch.

71
Hardware Required

Source code containing computer instructions for controlling Arduino


functionality is usually referred to as a sketch in the Arduino commu­
nity. The word sketch will be used throughout this book to refer to
Arduino program code.

The Blink sketch, which comes with Arduino, is used as an example sketch in
this chapter. If you have already assembled the robot and downloaded the
source code for this book, feel free to use the HelloRobot sketch described in
Chapter 6, Testing the Robot's Basic Functions.

If you don't have the Arduino software and driver installed on your
machine, wait until "Connecting the Arduino Board" (page 78) to plug
the Arduino into your computer.

Hardware Required
• Computer with Arduino 1 .0. 1 or later installed
• L eonardo (or Uno) Arduino board
• Motor Shield (see Chapter 2, Building the Electronics)
• USB cable

Arduino Software
Software programs, called sketches, are created on a computer using the Ar­
duino integrated development environment (IDE). The IDE enables you to write
and edit code and convert this code into instructions that Arduino hardware
understands. The I DE also transfers those instructions to the Arduino board (a
process called uploading) .

Arduino Hardware
The Arduino board is where the code you write is executed. The board can only
control and respond to electricity, so specific components are attached to it to
enable it to interact with the real world. These components can be sensors,
which convert some aspect of the physical world to electricity so that the board
can sense it, or actuators, which get electricity from the board and convert it
into something that changes the world. Examples of sensors include switches,
accelerometers, and ultrasound distance sensors. Actuators are things like
lights and L EDs, speakers, motors, and displays.

72
Arduino Hardware

There are a variety of official boards that you can run your Arduino sketches
on and a wide range of Arduino-compatible boards produced by members of
the community.
The most popular boards contain a USB con nector that is used to provide
power and connectivity for uploading your software onto the board. Figure 5-1
shows the board used for the robots in this book, the Arduino Leonardo.

Figure 5-1. Basic board: the Arduino Leonardo

You can get boards that are smaller and boards with more connections. The
L eonardo is used with these robotics projects because it is inexpensive but you
can use other boards such as the Uno if you prefer.

Ifyou want to use an Uno board (or earlier Arduino boards), you may
need to use a s slightly higher voltage (an additional battery) to power
the robot, see Appendix D).

Add- on boards that plug into Arduino to extend hardware resources are called
shields. The robots covered in this book use a shield that controls the direction
and speed of the motors, see Figure 5-2:

Chapter 5 73
Installi ng the Integrated Development Environment (IDE)

Figure 5-2. Motor Shield plugged into the Arduino Leonardo

Online guides for getting started with Arduino are available at http://ardui
no. cc/en/Guide/Windows for Windows, http://arduino.cc/en/Guide!MacOSX for
Mac OS X, and http://www.arduino.cc/p/ayground!Learning!Linux for Linux.

I nstall ing the I ntegrated Development


Environment (IDE)
The Arduino software for Windows, Mac, and Linux can be downloaded from
http://arduino.cc/en/Main/Software.

Installing Arduino on Windows


The Windows download is a ZIP file. Unzip the file to any convenient directory
-Program Files/Arduino is a sensible place.
Unzipping the file will create a folder named Arduino- 1.0.<nn> (where <nn> is
the version number of the Arduino release you downloaded). The directory
contains the executable file (named Arduino.exe), along with various other files
and folders. Double- click the Arduino.exe file and the splash screen should
appear (see Figure 5-3), followed by the main program window (see
Figure 5-4). Be patient, as it can take some time for the software to load.

74
Installing the I ntegrated Development Environment (I DE)

uduino-1.0-rcl Nam,

drivm
examples
hardware
java
lib
tibmits
reftrenct

tools
E, arduino.ext
� cygiconv-2.dll
i!i cygwinl.dll

.)

Figure 5-3. Arduino splash screen (Version 1.0 in Windows 7)

Installing Arduino on OS X
The Arduino download for the Mac is a disk image (.dmg); double-click the file
when the download is complete. The image will mount (it will appear like a
memory stick on the desktop). Inside the disk image is the Arduino application.
Copy this to somewhere convenient-the Applications folder is a sensible
place. Double- click the application once you have copied it over (it is not a
good idea to run it from the disk image). The splash screen will appear, followed
by the main program window (Figure 5- 4).

Chapter 5 75
Installi ng the Integrated Development Environment (IDE)

Figure 5·4. /0£ main window (A rduino 1.0 on a Mac)

Installing Arduino on Linux


L inux installation varies depending on the L inux distribution you are using.
See the Arduino wiki for information (http://www.arduino. cc/playground!Learn
ing!Linux) .

Driver Installation
To enable the Arduino development environment to communicate with the
board, the operating system needs to use the appropriate drivers for your
board.
On Windows, use the USB cable to connect your PC and the Arduino board
and wait for the Found New Hardware Wizard to appear. If you are using a
L eonardo or Uno board let the wizard attempt to find and install drivers.

76
Installing the Integrated Development Environment (I DE)

Troubleshooting the Found New Hardware Wizard


If the Found New Hardware Wizard does not appear Panel>System and Security. Click on System, and
when you fi rst connect a Leonard o board, open De­ then open Device Manager. In the listing that is dis­
vice Manager as descri bed in the next paragra ph and played fi nd the entry in COM and LPT named Ardui
if you see Other device> Ardu"i.no Leona rdowith no UNO ( COM n n ) . n n wi l l be the nu mber Windows
an exclamation poi nt, right click on the entry a nd se­ has assigned to the port created for the board. You
lect U pdate Driver Software. Choose the Browse my will see a warning logo next to this because the ap­
com puter for Driver Software option, and navigate propriate drivers have not yet been assig ned. Right
to the Drivers folder i nside the Arduino folder you j ust click on the entry and select U pdate Driver Software.
unzi pped. Select the d r ivers folder and windows Choose the Browse my computer for Driver Softwa re
shou ld then proceed with the i n sta l l ation process. If option, and navigate to the Drivers folder inside the
the Wi ndows c a n ' t verify the pub U s h e r o f Arduino folder you just u nzipped. Select the A rdui
the d rive r softwa re dialog pops u p, select I n noUNO . i n f fi le and windows should then proceed
stall this softwa re anyway. with the instal lation process. If the Windows c a n ' t
verify the publisher of the d rive r soft
If the Wiza rd starts but fai l s to find drivers (don't wor­
ware dialog pops u p, select I n stall this soft
ry, this is the expected behavior with an Uno board).
ware a nyway.
To fix it you now need to go to Start Menu>Control

If you are using an earlier board (any board that uses FTDI drivers) with Win­
dows Vista or Windows 7 and are online, you can let the wizard search for drivers
and they will install automatically. On Windows XP (or if you don't have internet
access), you should specify the location of the drivers. Use the file selector to
navigate to the FTDI USB Drivers directory, located in the directory where you
unzipped the Arduino files. When this driver has installed, the Found New
Hardware Wizard will appear again, saying a new serial port has been found.
Follow the same process as before.
On the Mac, the latest Arduino boards can be used without additional drivers.
When you first plug the board in a notification will pop up saying a new network
port has been found; you can dismiss this. If you are using earlier boards (boards
that need FTDI drivers), you will need to install driver software. There is a pack­
age named FTDIUSBSeria/Driver, with a range of numbers after it, inside the
Arduino installation disk image. Double- click this and the installer will take you
through the process. You will need to know an administrator password to
complete the process.
On L inux, most distributions have the driver already installed, but follow the
L inux link given in "Arduino Hardware" (page 72) for specific information for
your distribution.

Chapter 5 77
Connecting the Arduino Board

If the software fails to start, check the troubleshooting section of the


Arduino website, h ttp://arduino.cc/en/Guide/Troubleshooting, for
help solving installation problems.

Con necting the Arduino Board


Plug the board into a USB port on your com pu ter and check that the g reen
LED power i ndi cator on the board i llu m i n ates. The location of the LED is i ndi­
cated in Fi g u re 5-5.

i l. ......
00
USB
: Coo,,.c!or :
.. ................

LEONARDO


ARDUINO
i
1 o
a
j ICSP
00
; Programrrir,g i
.........................
i Co, nector ,i
00

Figure 5-5. The Leonardo

If you have a factory fresh board, an o ran g e LED (lab eled "Pi n 1 3 LED" i n
Fi g u re 5-5) s hould flash on and off when the board i s powered u p (boards com e
from the factory preloaded w i th software to flas h the L E D as a sim ple c heck
that the board is worki ng).

If the power LED does not illuminate when the board is connected to
your computer, the board is probably not receiving power.

Using the I DE
Use the Arduino IDE to create, o pen, an d mo dify s ketches that defi ne what the
board will do. You can use bu ttons alo n g the to p of the I D E to perform th ese
actions (shown in Fi gure 5-6), or you can use the menus o r keyboard shortcu ts
(som e are shown i n Fi g ure 5-7).

78
Using the IDE

New sketch

Compile

Serial monitor

New tab

Script editor

Text console
(status and
error messages)

Figure 5-6. Arduino /DE

The Sketch Editor area is where you view and edit code for a sketch. It supports
common text editing keys such as Ctrl-F (�- F on a Mac) for find, Ctrl- Z (�-Z on
a Mac) for undo, Ctrl-C (�-C on a Mac) to copy highlighted text, and Ctrl-V (�­
V on a Mac) to paste highlighted text.
Figure 5- 7 shows how to load the Blink sketch (the sketch that comes preloaded
on a new Arduino board).
After you've started the ID E, go to the File ➔ Examples menu and select 1 .Ba­
sics➔ Blink, as shown in Figure 5-7 . The code for blinking the built-in L ED will
be displayed in the Sketch Editor window.

Chapter 5 79
Usi ng the IDE

Sketch Tools Help


XN
XO

Close XW
Save XS
Save As... ◊XS
Upload XU
Upload U sing Prog rammer ◊XU 6.Sensors
7.Display
a.Strings
ArduinolSP
EEPROM
Ethernet
Firmata
LiquidCrystal
Mouse
SD
Servo
SoftwareSerial
SPI
Stepper
Wire

Figure 5-7. IDE menu (selecting the Blink example sketch)

Before the code can be sent to the board, it needs to be converted into in­
structions that can be read and executed by the Arduino controller chip; this
is called compilin g. To do this, click the compile button (the top-left button
with a tick inside), or select Sketch➔Verify/Compile (Ctrl- R, �- R on a Mac).
You should see a message that reads "Compiling sketch ..:' and a progress bar
in the message area below the text editing window. After a second or two, a
message that reads "Done Compiling" will appear. The black console area will
contain the following additional message:

Bin a ry s ketch siz e : 1026 bytes ( of a 32256


byte l'laxil'lul'I)

The exact message may differ depending on your board and Arduino version;
it is telling you the size of the sketch and the maximum size that your board
can accept.
The final message telling you the size of the sketch indicates how much pro­
gram space is needed to store the controller instructions on the board. If the
size of the compiled sketch is greater than the available memory on the board,
the following error message is displayed:

80
Uploading and Running the Blink Sketch

Sketch too bi.g ;


see http : / /www . a rdui.no . cc/en/Gu i.de/Tr oubleshooti.ng#si.ze fo r ti.ps
on reduci.ng i.t .

If this happens, you need to make your sketch smaller to be able to put it on
the board, or get a board with higher capacity. You will not have this problem
with the Blink example sketch.
If there are errors in the code, the compiler will print one or more error mes­
sages in the console window. These messages can help identify the error.
As you develop and modify a sketch, you should also consider using the
File➔ Save As menu option and using a different name or version number reg­
ularly so that as you implement each bit, you can go back to an older version
if you need to.

Uploading and Running the Blink Sketch


To transfer your compiled sketch to the Arduino board, connect your board to
your computer using the USB cable. L oad the sketch into the ID E as described
in "Using the IDE" (page 78).
Next, select Tools➔ Board from the drop-down menu and select the name of
the board you have connected.
Now select Tools ➔ Serial Port. You will get a drop- down list of available serial
ports on your computer. Each machine will have a different combination of
serial ports, depending on what other devices you have used with your
computer.
On Windows, they will be listed as numbered COM entries. If there is only one
entry, select it. If there are multiple entries, your board will probably be the last
entry.
On the Mac, your board will be listed twice (you can use either one):

/dev/tty . usbModeMXXXXXXX
/dev/cu . usbModeMXXXXXXX

Chapter 5 81
Usi ng Tabs

If you have an older board, it will be listed as follows:

/dev/tty . u s bseri.a l - XXXXXXX


/dev/cu . u sbseri.al - XXXXXXX

Each board will have different values for XXXXXXX. Select either entry.
Click on the upload button (in Figure 5- 6, it's the second button from the left),
or choose File➔ Upload to 1/0 board (Ctrl- U, :Jt- U on a Mac).
The software will compile the code, as in "Using the IDE" (page 78). After the
software is compiled, it is uploaded to the board. If you look at your board, you
will see the LED stop flashing, and two lights (labeled as Serial LEDs in
Figure 5-5) just below the previously flashing LED should flicker for a couple
of seconds as the code uploads. The original light should then start flashing
again as the code runs.
The ID E will display an error message if the upload is not successful. Problems
are usually due to the wrong board or serial port being selected or the board
not being plugged in. The currently selected board and serial port are dis­
played in the status bar at the bottom of the Arduino window
If you have trouble identifying the correct port on Windows, try unplugging
the board and then selecting Tools➔ Serial Port to see which COM port is no
longer on the display list. Another approach is to select the ports, one by one,
until you see the lights on the board flicker to indicate that the code is
uploading.

Using Tabs
Tabs provide a convenient way to organize code when your sketch starts to
grow. It enables you to keep functionally related code together and simplifies
sharing this code across more than one sketch.
The arrow in the upper right of Figure 5-8 points to the button which invokes
a drop- down window of tab related functions. This window displays the names
of the tabs and offers a list of commands:

• New Tab creates a new tab that (you will be prompted to name the tab)
• Renar,e enables you to change the name of the currently selected tab
• Delete deletes the current tab (you are asked if you are sure you want to
do that)

82
Installing Third-Party Libraries

� I ""°"'"° LO.I
Rt Edit 5btth look Help

00 n a a □
� Cl
"" '
1,
S.n&I . n (96001 :
1 1 2000 ) :

®��
aotodleqln{JIOTOR_LtrrJ :
aotorBeq1n flKITM_RIGHTJ : Pf1MOU1 hb Ctrl•Alt•ldt

}
M"I (LED_PIN, OUT1UT) ; " 11 tbl LED pin tot 1111q,u,•

S.n al . p, ,tJ1, t"'la1 ung tot I Hl'UIOc to detect blodl:ed u,tltcuonM ) ;

I I
, .. 1..., 1 1

I f 1 t' t i t c 1 b d ltft lldt


t (100Ho,Ob1tacle(OllST_Lt1'T_CGll ... � I I
cahbuttRotu1onRatt(l>IP._Ltrr, 360 ) : callbute "" touuoa
calibuuRot.et1onRatc {DIR_u:rr, 901 : 1lUlr1te «- ,ouu•

f ( 1ootrocOb1ucle (O!IST_IUCHT_DtilJ •• t I I
cal1bUtd�t.et.ionR4tt{l>IR_RJCiHT, 360 ) ; lU,utt CV (Ot.ltiCIO

Figure 5-8. /DE tabs

Each tab is a separate file and when you copy these files to other sketches you
add the tab to that sketch.
Because there are many functional modules used in this book and these are
shared across most of the sketches, tabs are used extensively. Figure 5- 8 shows
the myRobot sketch, discussed in the next chapter, that uses tabs for infrared
sensor code (irSensors) and for program constants and definitions (robotDe
fines. h).

Installing Third-Party Libraries


The download code for this book (see "How to Contact Us" (page xv)) contains
three libraries that are required to run all the sketches described in the book.
These libraries are in a folder called libraries in the zip. You need to copy these
so they are in a folder called libraries inside your Arduino document folder. To
find the Arduino document folder, open Preferences (Arduino➔ Preferences on
Mac; File ➔ Preferences on Windows) and note the sketchbook location. Navi­
gate to that directory in a file system browser (such as Windows Explorer or
the OS X Finder) or at the terminal. If no libraries folder exists, create one and
put the folder you unzipped inside it.
If the Arduino IDE is still running, quit and restart it. The IDE scans this folder
to find libraries only when it is launched. If you now go to the menu
Sketch➔lmport L ibrary, at the bottom, below the gray line and the word Con­
tributed, you should see the library you have added.

Chapter 5 83
I nstalli ng Thi rd -Party Libraries

Configuring the Library for Four Wheels


If you r robot uses fou r wheel drive, you must config­ 3. Right-click the RobotMotor.h file, and open it
ure the RobotMotor library code by modifying the with a plain text editor. On Windows, you can
RobotMotor.h file to tell the compiler that the library use Notepad. On the Mac, you can use TextE­
should be built for the 4WD chassis. dit. On Linux, use your favorite plain text ed­
itor.
To modify the RobotMotor.h file to use the 4WD chas­
sis, first go to Arduino's preferences (File➔Preferences 4. Change #defi.ne CHASSIS_ZWD to #defi.ne
on Windows or Linux, Arduino ➔ Preferences on Mac). CHASSIS_4WD and save the file
Under Sketchbook Location, you'll find the name of
the directory that contains your sketches and libra­ A version of RobotMotor.h with the modification fo r
ries. Next: 4wd preconfigured is in the libraries/RobotMotor/
RobotMotor4wdfolder ofthe examples zip file. Copy­
1 . Open the sketchbook folder in the Finder ing this file to the RobotMotor folder will replacing
(Mac) or Explorer (Windows). the 2wd with the 4wd version of the file.
2. Locate the libraries directory inside, and then
open the directory named RobotMotor .

If the l ibraries provide example sketches, you can view these from the ID E
menu; click File➔Examples, and the library's examples will be under the li­
brary's name in a section between the general examples and the Arduino dis­
tributed libraries example listing.
If the library examples do not appear in the Examples menu or you get a mes­
sage saying "Library not found" when you try to use the library, check that the
libraries folder is in the correct place with the name spelled correctly. A l ibrary
folder named <LibraryName> (where <LibraryName> is the name for the li­
brary) must contain a file named <LibraryName>.h with the same spelling and
capitalization. Check that additional files needed by the library are in the folder.

84
Testi ng the Robot's Basic
Fu nctions

In this chapter, you will upload a test sketch to the robot that will verify that
your robot is working correctly.

Hardware Required
• The assembled robot chassis.
• Motors connected to shield (see Figure 3-25 for 2WD or Figure 4-26 for
4WD).
• Example code and libraries installed, see "Installing Third- Party L ibraries"
(page 83).
• 5 AA cells inserted into the battery holder (USB does not provide sufficient
power to drive the motors).
• Reflectance sensors mounted and connected (left sensor to analog input
0, right to analog 1 ). You can use the stripboard wiring described in "Mak­
ing a Line Sensor Mount" (page 1 7). But to run the edge detecting project
described in Chapter 9 , you need more space between the sensors.

Figure 6-1 shows the assembled two wheel robot; Figure 6-2 shows the as­
sembledfour wheel robot. Figure 6-3 shows the sensor and motor connections.

85
Software Prerequis ites

Figure 6-1. Two wheeled robot with reflectance sensors Figure 6-2. Four wheeled robot with re flectance sen­
sors

0 0 0 0 0 0 0 0 o o o o' o o o o
□�□ □ 0• 0 0 0l 0e 0• 0r 0 0• 0 □ □ 0

....
,,..,
.,,� y-

·-
-------. �or ,wo
Motors fof 'lWO Ooly
\_ rear mo!Ol"S lor 4WO D
'--__..--<. Right

lttl Sentol' Rlght Sent0r

Figure 6-3. Reflectance sensor connections

Software Prerequisites
Although the sketch code used in this chapter is printed in the pages that
follow, you will need some libraries that are included in example code (see
"How to Contact Us" (page xv) for the URL). The sketch folders can be copied
to your Arduino sketchbook folder (if you are not familiar with the Arduino
environment, read through Chapter 5). The download files in the library folder
must be copied to your Arduino libraries folder (see "Installing Third- Party L i­
braries" (page 83)).

86
S ketches Used in This Chapter

Install the AFMotor library contained in the download zip file. This library is
modified from the one on the Adafruit site to work with the L eonardo board;
the standard Adafruit library can be used with the Uno board.
Install the RobotMotor library contained in the example code download. This
library comes configured for the two wheeled robot; if you have the four
wheeled robot will need to update the library for this robot as described in the
Note below.

If your rob ot uses four wheel drive, you must configure the RobotMo
tor library code by modifying the RobotM otor.h file to tell the compiler
that the library should b e built for the 4WD chassis. See "Installing
Third-Party Libraries" (p age 83) for details o n ho w to do this.

A third library, named lrRemote, is also included in the download. This library
won't be needed until Chapter 11 , but copying it into your libraries folder now
will save you having to do this later.

Sketches Used in This Chapter


• he l loRobot . 1.no-A sketch that rotates the robot when triggered by a
sensor. The code uses constants to refer to sensors and motors, and con­
tains functions for handling the infrared reflectance sensors. The sketch
uses the RobotMotor library to interface with the motors as shown in
Figure 6-4 .
• l'lyRobot . ino-The functionality from helloRobot.ino restructured into
modules using Arduino tabs. Program constants are moved into a tab
named robotDefines.h. Reflectance sensor code is moved into a tab named
lrSensors as shown in Figure 6- 5.

I I
I Program 11 11 Reflectance1 RobotMoto1
HelloRobot : constants 1 1 sensors I _. -, Library
1 1 I
Figure 6-4. Hel/oRobot Sketch

Chapter 6 87
Load and R u n hel loRobot.ino

- - - - - - --. ,- - - - - - -
1 I
1 I
I Program 1 1 Reflectance 1
Hello Robot : constants 1 1 sensors 1
L- - - 1 1- - --
I

myRobot robotDefines l rSensors


RobotMotor
Library

Figure 6-5. myRobot Sketch

Load and Run helloRobot.ino


Example 6-1 shows the sketch you can use to test edge detection. Before you
upload the sketch, ensure the battery power switch is off (switch toggle angled
toward the DC jack) and connect your Arduino to your computer with a USB
cable. Next, u pload the sketch (see Chapter 5 if you need help loading the
sketch).

Example 6-1. The Hello, Robot sketch


/ *** * * * *** * ** ** ** *** * * *** * *** * * * ** ** * ******** * **** ** *
HelloRobot . ino : I nitial Robot test sketch

Michael Margolis 4 J uly 2012


************** *************************************** /
II include Moto r libra ries
#include <AFMotor . h> II adafruit Moto r shield library
#include <RobotMotor . h> II 2wd or 4wd Motor lib rary

I ***** Global Defines **** I


II defines to iden tify senso r s
can st int S ENS E_IR_LEFT = 0;
can s t int SENSE_IR_RIGHT = 1;
can st i n t S ENS E_I R_CENTER = 2;

II defines for di rections


can st int D I R_LEFT = 0 ;
can st i n t D I R_RIGHT = 1 ;
can s t i n t D I R_C ENTER = 2 ;

can st c h a r * locationSt ring [ ] = { " Left " , " Rig h t " , " Center " } ; I I Debug labels
II http : lla rduino . cclenl ReferencelSt ring for More on cha racter string a r rays
II obstacles constants
can st int DBST_NONE = 0; II no obstacle detected
can st int OBST_LEFT_EDGE = 1; II left edge detected
can st int OBST_RIGHT_EDGE = 2 ; II right edge detected
can st int OBST_FRONT_EDGE = 3 ; II edge detect at both left a n d right sensors

88
Load and Run helloRobot.ino

con s t int L ED_PIN = 1 3 ;


I **** E n d o f Global Defines **************** I
II Setup runs at startup and is used configu re pins a nd init systeM va riables
void setup( )
{
Serial . begin ( 9600 ) ;
blinkNuMber ( B ) ; II open po rt while flashing . Needed for Leon a rdo only

MotorBegin(MDTOR_L EFT) ;
MotorBeg i n ( MOTOR_R IGHT ) ;

i rSensorBegin ( ) ; I I initialize senso r s


pinMode( L ED_PI N , OUTPUT ) ; II enable t h e L E D pin f o r output

Seria l . println( " Wai ting for a sensor to detect blocked reflection" ) ;

void loop( )

II call a function when reflection blocked on left side


if( lookForObstacle (DBST_LEFT_EDG E) == true) {
calibrateRotationRate( D I R_LEFT , 360 ) ; II calibrate CCW rotation
}
II as above fo r right sensor
if( lookForObstacle ( OBST_R IGHT_EDGE) == true)
calibrateRotationRate( D I R_RIGHT , 360 ) ; II calib rate CW rotation

II function to indicate n uMbers by flashing the built - i n LED


void blinkNuMbe r( byte nuMbe r ) {
pinMode( LED_PIN , OUTPUT ) ; II enable the LED pin fo r output
while (nuMbe r - - ) {
digitalWrite ( LED_PIN , HIGH ) ; delay ( 1 00 ) ;
digitalWrite ( LED_PIN , LOW) ; delay(400 ) ;

/ **********************
code to look for obstacles
********************** /

II retu rns true if the given obstacle is detected


boolean lookFo rObstacle ( int obstacle)
{
switc h (obstacle ) {
case DBST_FRONT_EDGE : return i r EdgeDetect( DIR_LEFT) 1 1 i r EdgeDetect ( D I R_R IGHT ) ;
case OBST_LEFT_EDG E : return i rEdgeDetec t ( DIR_LEFT ) ;
case OBST_R IGHT_EDGE : ret u r n i rEdgeDetect( DIR_RIGHT) ;
}
return false;

Chapter 6 89
Load and Run helloRobot.ino

/ *************************************
fu nctions to rotate the robot
********************** *************** /

/ / retu r n the tiMe in Milliseconds to turn the g iven angle at the given s peed
long rotationAngleToTiMe ( int a ngle , int speed )
{
int fullRotationTiMe ; // tiMe to rotate 360 degrees at g iven speed

if( speed < MIN_SPEED )


return 0 ; / / ignore speeds slowe r then the fi rst table entry

angle = a b s ( angle) ;

if( speed >= 100 )


fullRotationTiMe = rotationTiMe [ NBR_SPEEDS - 1 ] ; / / the last ent ry is 100%
else

int index = ( s peed - MI N_SPEED) / SPEED_TABLE_INTERVAL; // index into s peed


// and tiMe tables
int t0 = rota tionTiMe [ index ] ;
int t 1 = rotationTiMe [ index+ 1 ] ; / / tiMe of the next higher speed
fullRotationTiMe = M a p ( s peed ,
s peedTa ble [ index ] ,
s peedTa ble [ i ndex+ 1 ] , t 0 , t 1 ) ;
// Serial . p rin t ( " index= " ) ; Serial . p rint ( index ) ; Serial . print ( " , t0 " ) ;
/ / Serial . p rin t ( t0 ) ; Serial . p rint ( " , t 1 = " ) ; Serial . p rint( t 1 ) ;
}
// Serial . print( " full rota tion t\Me = " ) ; Seria l . printl n ( fullRotationHMe ) ;
long result = Ma p ( a ngle , 0 , 360 , 0 , fullRotationTiMe ) ;
return resul t ;

/ / rotate the robot froM MIN_SPEED to 1 00% i n c reasing by SPEED_TABLE_INTERVAL


void calib r a teRotationRate( int sen s o r , int angle )
{
Serial . print ( locationSt ring [ sensor ] ) ;
Serial . println ( " calibratio n " ) ;
fo r ( i n t s peed = MI N_SP EED ; speed <= 100 ; s peed += SPE ED_TABLE_INTERVAL )
{

de lay( 1000) ;
blinkNuMbe r ( s peed/10 ) ;

if( sensor == DIR_LEFT)


{ // rotate left
Motor Reve rse(MOTOR_LEFT , speed ) ;
Moto r Forwa r d ( MOTOR_RIGHT , speed ) ;
}
else if( sensor == DIR_RIGHT )
{ / / rotate right
Motor Forwa r d (MOTOR_LEFT , speed ) ;
Motor Reve rse(MOTOR_RIGHT , speed ) ;

90
Load and Run helloRobot.ino

}
else
Serial . println ( " I nvalid senso r " ) ;

int tiMe = rotationAngleToTiMe( angle, speed ) ;

Serial . print( locationSt r i ng [ sensor ] ) ; Serial . print( " : rotate " ) ;


Serial . print ( a ngle ) ; Se rial . print ( " degrees a t speed " ) ; Serial . p rint( speed ) ;
Serial . print( " for " ) ; Serial . p rint( tiMe ) ; Serial . p rintln ( " Ms " ) ;

de lay( tiMe ) ;
Moto rStop( MOTOR_LEFT ) ;
MotorStop( MOTOR_R I GHT ) ;
delay( 2000 ) ; / / two second delay between s peeds

/ ****************************
i r reflectance sensor code
**************************** /

con st byte NBR_SENSORS = 3 ; // t h i s ve rsion o n l y has left a nd right sensors


con s t byte I R_S ENSOR [ NBR_SENSOR S ] = { 0 , 1, 2 } ; / / a nalog pins for sensors

int i rSenso rAMbient[ NBR_SENSORS ] ; / / sensor value with no reflection


int i rSenso rReflect[ NBR_S ENSORS ] ; / / value considered detecting an object
int i rSensorEdge [ NBR_SENSOR S ] ; / / value considered detecting a n edge
boolean isDetected [ NBR_SENSOR S] = {false , false } ; // set true if object detected

con st int i r ReflectTh reshold = 10; / / % level below aMbien t to trigger reflection
con st int i r EdgeTh reshold = 90; / / % level above aMbien t to trigger edge

void irSensorBegin ( )
{
for ( int senso r = 0 ; sensor < NBR_SENSORS ; sensor++)
irSensorCalibrate ( senso r ) ;

/ / calibrate t h resholds for aMbient light


void irSensorCalib rate( byte senso r )
{
int aMbient = analogRea d ( I R_SENSOR [ sensor ] ) ; / / get aMbient level
i rSensorAMbient [ sensor] = aMbien t ;
// precalculate t h e levels for object and edge detection
i rSensorReflect [ sensor] ( aMbient * (long ) ( 10 0 - i rReflectThreshold ) ) / 100;
i rSensor Edge [ senso r ] = ( aMbient * (long ) ( 100+i r EdgeTh reshold ) ) / 100 ;

/ / retu rns true if an object reflection detected on the given sensor


/ / the sensor paraMeter is the index into the sensor a r ray
boolean i r Senso rDetect(int sensor )
{
boolean result = false ; // default value
int value = analogRead ( IR_S ENSOR [ sensor ] ) ; / / get I R lig h t level

Chapter 6 91
Load and Run helloRobot.ino

if( value <= i rSenso rReflect [ senso r ] ) {


result = t r ue ; // obj ect detected ( lowe r value Means More reflection )
if( isDetected [ senso r ] == false) { // only print on initial detection
Serial . p r i n t ( locationSt ring [ senso r ] ) ;
Serial . p rintln ( " object detected " ) ;
}
}
isDetected [sensor) = result ;
return resul t ;

boolean ir EdgeDetect ( int sensor )


{
boolean result = false ; // default value
int value = a nalogRead ( IR_SENSOR [ sensor ] ) ; / / get IR light level
if( value >= irSensorEdge [ sensor ] ) {
result = t r ue ; / / edge detected (higher value Means less reflection )
i f ( isDetected [ senso r ) == fals e ) { // only print on initial detection
Seria l . print( locationSt ring [ senso r ] ) ;
Serial . p rintln ( " edge detected " ) ;
}

isDetected [sensor] = resul t ;


r e t u r n result ;

The sketch tests the ca li bra ti on of the robot's speed of movemen t. The front
sen sors are used to i n i ti a te a motor test-the motors rota te the robot 360
degrees in the di recti on of the sensor tha t wa s trigg ered. If the robot is fun c­
ti oni ng correctly, i t wil l execute a compl ete revol u ti on a t seven sp eeds ra ngi ng
from sl owest to fa stest.
To ru n the test, pla ce th e robot on a refl ective whi te surfa ce su ch a s a larg e
sheet of pap er. When the robot's u p and ru nni ng, Arduin o's pin 1 3 L E D wil l
fla sh once.

Another way to test is to put the robot on something that will raise the
wheels off the ground by an inch or so. This will enable the motors to
turn without the robot skittering around.

Thi s sketch di splays debugging informa ti on to the seri a l con sol e. If you'd li ke
to vi ew i t, you'll n eed to keep the USB ca bl e p l ugg ed i n to your comp uter and
your rob ot; b e careful, sin ce the robot will be moving. If you're using an Ardui n o

92
Load and Run helloRobot. ino

Leonardo, wait until the robot's L ED flashes to indicate it's ready before open­
ing the Arduino Serial Monitor (the Serial Monitor is the rightmost icon on the
Arduino toolbar). When the sketch starts, you should see the following in the
Arduino Serial Monitor:
Waiting fo r a sensor to detect blocked reflection

Swi pe something dark (a small piece of matte black paper the size of a business
card works well) near one of the sensors (panel2 seen in Figure6-7 ). The Serial
monitor should now display the output similar to that shown in Example 6 -2.
The number of lines and the values displayed will vary with different robots
but you should see multiple lines showing the direction of rotation, speed and
time in m illiseconds.

Example 6-2. Serial output from HelloRobot.ino


Left calib ration
Left : rotate 360 degrees a t s peed 40 for SS00Ms
Left : rotate 360 degrees at s peed 50 for 3300Ms
Left : rotate 360 degrees at s peed 60 for 2400Ms
Left : rotate 360 degrees at speed 70 for 2000Ms
Left : rotate 360 degrees at s peed 80 for 1750Ms
Left : rotate 360 degrees at s peed 90 for 1550Ms
Left : rotate 360 degrees at s peed 100 for 1 150Ms

Motors on the left side should spin in reverse, motors on the right should spin
forward for the indicated time in milliseconds (if the robot was on the ground,
it would rotate to the left (counter-clockwise). If you don't see the expected
results, see "Troubleshooting" (page 9 8) for help.
Completing this test will verify that everything (the robot motors, power
source, Arduino and motor shield) is wired up and functioning correctly. Dou­
ble check that you have completed all the building steps. Take particular care
that the battery wires to the motor shield are attached to the correct polarity.

Chapter 6 93
Load a nd Run helloRobot.ino

Figure 6 -6 shows the robot stationary on a re­


flective surface. If the robot moves when
placed on the surface, switch the power off and
then on so the robot can measure and calibrate
for the ambient light level. It should remain
motionless until a sensor detects a reduction
in the light reflected off the surface.

Figure 6-6. Robot sitting on a reflective surface

The robot should rotate in the direction of the


sensor that detects the reduced reflection. In
Figure 6-7 , a non- reflective card is swiped un­
der the right sensor which will trigger the robot
to turn clockwise.

Figure 6-7. Non-reflective card under right sensor

Figure6- 8 shows the right motor running back­


wards and the left forwards which will rotate
the robot clockwise.

Figure 6-8. Robot rotates in direction of swiped sensor

94
About the Sketch

About the S ketch


The code in Exa mple 6-1 forms the nucleus of a ll the sketche s that follow so it
is worthwhi le taking a moment to look thro ug h t he code to see how it works.
The p urpo se of t he co de i s to dri ve the motors i n oppo site di rections for a
d u ration t hat will rotat e the robot one revolution at sp eeds ra ng i ng fro m t he
sl ow est sp eed to th e fa stest. Al l t h e sketch es i n th e book refer to sp eed s a s a
percent of ma xi mum speed, the next c hapter, Chapter 7, Controlling Speed and
Direction e xpla i ns speed control in detail.
The functions to acce ss t he Adafruit motor shield ( see Cha pter 2, Building the
Electronics) are i ncluded by the li ne shown i n Example 6-3.

Example 6-3. #include line for Adafruit library


#include <AFMotor . h> // adafruit Motor shield library

The li ne shown in Example 6-4 i nc ludes the library written for thi s book
(RobotMoto r . h).

Example 6-4. #include line for this book's library


#include <RobotMotor . h> // 2wd or 4wd Motor library

Thi s lib rary provides a consi stent interface for motor functions in order to i so­
lat e the hig h er le vel logic fro m ha rdwa re specific s. Thi s mea ns that yo u ca n
use the sa me sketch code with (a lmo st) a ny motor hardware si mp l y b y cha ng­
i ng the RobotMotor libra ry code to suit the ha rdware. The motor co de is e x­
plai ned in the next chapter a nd yo u ca n fi nd exa mple code to support a dif­
ferent motor controller i n Appendix B, Using Other Hardware with Your Robot.
The block that begins with: /***** Global Defi. nes **** / contains declara­
tions for constants that i dentify: sensors, di re ctions a nd o b sta cle s. The se con­
sta nts enable you to refer to ele ment s i n your sketch usi ng mea ni ngful na me s
i nstea d of numbers, for exa mple thi s:
calibrateRotationRate ( D I R_LEFT , 360 ) ;

i nstea d of thi s:
MotorForwa r d ( 0 , 360 ) ;

The setup section cal ls functions to i nitialize the motor a nd se nsor modu le s
(more on these later). The loop function u se s the lookForObstac le function to
determi ne if a reflection i s detecte d. It waits unti l no reflection i s detected o n

Chapter 6 95
About the Sketch

either sensor; the robot is not on the g round (or on a non-reflecti ve s urface).
The lookForObstac le func tion is checke d to determ i ne if the left or ri ght sensor
detects a reflection, and if so, calls the ca l"i.brateRotati.onRate function to
rotate the robot for a short perio d.
The lookFo rObstac le func tio n is told wh ich obstacle to check for (the obsta­
cles a re i dentified usi n g the defines described a bo ve). The case sta tement (see
h ttp://arduino.cc/en!Referen ce/SwitchCase) is use d to call i. r EdgeDetect func­
tion that returns true if a n object is de tec te d on that sensor. If no object i s
detecte d, the function returns OBST_NONE, shown in Exam ple 6-5 . See "I nfrared
Reflectance Sensors" ( page 1 34) for a detai led ex pl an ation of i. r EdgeDetect and
relate d functions.

Example 6-5. The /ookForObstac/e function


II retu rns true if the given obstacle is detected
boolean lookForObs tacle ( int obstacle)
{
switc h (obstacle ) {
case OBST_FRONT_EDGE : ret u r n i r EdgeDetect(DIR_LEFT) &&
i r EdgeDetect ( D IR_RIGHT ) ;
case OBST_LEFT_EDG E : ret u r n i r EdgeDetect ( DIR_LEFT ) ;
case OBST_R IGHT_EDGE : ret u r n i r EdgeDetect(DIR_RIGHT) ;
}
return false ;

The sensor detection is done i n the function i.rSensorDetect, shown i n


Example 6-6.

Example 6-6. The irSensorDetect function


II retu rns true if reflection level reduces below a th reshold
II for exaMple if the robot is does not sense the reflective s u rface
II the sensor pa raMeter is the index into the sensor ar ray
boolean ir EdgeDetect ( int sens o r )
{
boolean result = false ; II default value
int value = a nalogRead ( IR_SENSOR [ sensor ] ) ; II get IR light level
if( value >= irSensorEdge [ sensor ] ) {
result = t r u e ; II edge detected ( higher value Means less reflection)
if( isDetected [ sensor] == fals e ) { II only print on initial detection
Serial . p rint ( locationString [ senso r ] ) ;
Serial . p rintln ( " edge detected " ) ;

96
About the Sketch

isDetected [ sens o r ] = res ult;


retu rn result;

Thi s function will return true if th e reflec tion level is reduced. Thi s is deter­
mi ned thro ug h a call to ana logRead to g et a raw sensor rea di ng tha t i s co m­
pared to a detected/not detected th reshold. Values g re ater th an or eq ual to
the th reshold are co nsi dered a loss of reflec tion ( th e vol tage fro m th e sensor
i ncre ases wh en the reflec ted light decrease s , see "I nfrared R eflec tance Sen­
so rs" (page 1 34) for deta i ls on the refl ec ta nce sensors). The resul ts fro m thi s test
is stored in an a rra y named "i.sDetected. The a rra y can be used to recall the
sensor state of th e most recent cal l to "i.rSensorDetect and is used h ere to
sup press printing of the test result if a previo us test alrea dy i ndica ted tha t a n
o bj ec t was detec ted, a s shown i n E xampl e 6-7 .

Example 6-7. Initial detection


if( i sDetected [ senso r ] == false ) { / / only print on initial detection
Serial . p rint ( locationString [ senso r ] ) ;
Serial . p rintln ( " object detected " ) ;

Th e motor code co mm and s the motor controller board to d ri ve th e motor


forwards, backward s or sto p.
For exam pl e, th e followi ng wil l spi n th e rig h t motor forward at a speed gi ven
by the speed para meter (the pa ra meter is the perc entag e of the ma xim um
speed):
�otorForwa r d ( MOTOR_R I GHT , s peed ) ;

Motor cod e i s expl ai ned i n d etail i n Ch apter 7, Controlling Speed and Direction.
Rota ti ng the ro bot i s handled by the ca HbrateRotat"i.onRate func tion. For
exampl e. if th e l eft sensor is trigg ered, the cod e wil l spi n the left motor i n
re verse and the rig ht moto r forward, thus rotati ng the robo t towards the left
(counterclockwise):
if( sensor == DIR_LEFT)
{ / / rotate left
MotorReve rse( MOTOR_LEFT , speed ) ;
Moto rForwa rd ( MOTOR_RI GHT , s peed ) ;

Chapter 6 97
Troubleshooting

Troubleshooting
If you are h avi ng t rouble g etti ng H elloRobot w orking th en th e fi rst thing to d o
i s t o put th e robot d own, walk away from your com puter screen and have a
refresh i ng d ri nk. C om e back and look at th i ngs with fresh eyes and ch eck to
see if you h ave thi ngs wi red up and c on nected correctly. If i t looks li ke t he
c onnecti ons are okay, t h en th e next step is t o m ake a list of t h e maj or symp­
toms:
Compile errors

• ' AF _DCMotor ' does not nal'le a type error m essag e-this m ess ag e i n­
dicates th e AFM otor li brary h as not been found. This li brary is i n cluded
with the d ownload c od e for this book (see "H ow t o Contact Us" (pag e x v)
for the U RL). S ee " I nstalli ng Thi rd-Party Li brari es" ( page 83) i n Cha pter 5,
Tutorial: Getting Started with Arduino for h elp with this.
• " This chip is not supported ! " error m ess ag e-Th is m essag e is dis­
played if the chip s elected in the I DE is n ot rec og n ized by the library. This
will occu r if you s elect the Leon ard o board and use a versi on of the AF­
m otor library th at d oes not support thi s chi p. Replacing your AFM ot or
li brary with the on e in th e book's example c od e will fix th is problem.
• " expected definition : CHASSI S_ZWD o r CHASSIS_ 4WD not found " will
be displayed if you ch anged the d efi nes i n t h e R obotM ot or library t o an
i nvalid value. This li brary expects to fi nd either CHASSIS_2WD or CHAS­
SIS_4WD foll owi ng the #define i n Robot M ot or.h.

Softwa re Errors

• The S eri al M onit or is not dis playing th e text s hown at th e end of "L oad and
Run h elloRobot.i no" (pag e 88)-read th rough Ch apter 5, Tutorial: Getting
Started with Arduino and c h eck th at you have the d ri vers for your board
c orrectly i nstalled.
• The S eri al M oni tor displays th e i ni ti al text but th en dis plays errors or oth er
un expected text-s ee A ppendix C, Debugging Your Robot.

Ha rdware symptoms

• N o LEDs on th e Ard ui no b oard are lit (y ou m ay need to rem ove th e m ot or


shi eld to ch eck this). - This usually m eans that eith er no p ower i s bei ng
suppli ed to the board. If the power switch is on, check that t h e batteri es
h ave suffici ent voltag e and are located c orrectly. Check the wiri ng from
th e b attery and switch to th e shi eld.
• M ot ors d on't turn-Ch eck that th e batteri es are fitted correctly (USB d oes
not p rovide enough power to d ri ve the m otors). Check the m otor wiri ng.

98
Making the Sketch Easy to Enhance

You can test each motor by disconnecting the motor wires going to the
motor terminals on the shield and connecting them directly to the battery
terminals. If the motors still do not turn but theshield LED is lit, then double
check the shield soldering.
• Twoof thefourmotors don'tturn onthe4WD robot-Have you configured
the library for 4WD?-see "Software Prerequisites" (page 86).
• Motors run but the robot does not rotate 360 degrees-the robot rotation
does not need to be exact; anything within 20 or 30 degrees is good
enough. See Chapter 7 if you do want to adjust the rotation rate.

See Appendix C, Debugging Your Robot for more on debugging.

Making the Sketch Easy to Enhance


Although this is the simplest sketch in this book, it performs a number of dif­
ferent tasks: controlling the motors, interfacing with sensors, and rotating the
robot in response to object detection. You will be adding much more func­
tionality to the robot in later chapters. To help keep the various functional
elements under control, it makes sense to organize the code into modules to
keep functionally similar code together and to separate code that is not func­
tionally related.
The He l loRobot sketch naturally divides into three sections: the main logic (the
loop and rotation code), sensor interface, and motor control.
Moving the sensor interface and motor control into separate modules makes
the code easier to enhance. You can change one of the modules without dis­
turbing the code for the other. And you can easily copy modules into other
sketches-the tab code file has the same name as shown in the tab, with the
extension . 1.no. Adding this file to another sketch will automatically create the
tab for that sketch the next time the sketch is opened on the IDE.
The Arduino ID E provides tabs as a convenient mechanism for managing
modules (see Chapter 5, Tutorial: Getting Started with Arduino, "Using Tabs"
(page 82)). The following explains how sections of He l loRobot code are moved
into two new tabs, one providing an interface for IR sensors, the other an in­
terface for motors. All of the code in later chapters use tabs as containers for
functional modules.
The following steps creates a sketch named 111yRobot derived from He l loRo
bot that contains two tabs for sensor and motor functions:

Chapter 6 99
Making the Sketch Easy to Enhance

You can download the fTlyRobot sketch from the book's website but you
may want to go through these steps yourself to familiarize yourselfwith
the procedure for creating and using tabs in the /DE.

1 . Load the HelloRobot sketch and use the ID E file menu to save as 'myRobot'.
2. Create a tab by clicking the tab dropdown and selecting 'New Tab' (see
Figure 5-8). Name the tab 'lrSensors'.
3. Click the l'lyRobot tab, scroll down to the end of the sketch and cut all code
from the end up to the i. r reflectance sensor code (Example 6- 8) com­
ment and paste it into the I rSensors tab.

Example 6-8. IR reflectance sensor code


/ ****************************
i r reflecta nce sensor code
**************************** /

con st byte NBR_SENSORS = 3 ; // t h i s ve rsion only has left a n d right sensors


con st byte I R_S ENSOR [NBR_SENSOR S ] = { 0 , 1, 2 } ; / / analog pins for sensors

int i rSenso rAMbient[ NBR_SENSORS ] ; / / sensor value with no reflection


int irSensorReflect[ NBR_S ENSORS ] ; // value considered detecting an object
int i rSenso r Edge [ NBR_SENSORS ] ; / / value considered detecting an edge
boolean isDetected [ NBR_S ENSORS] = { false, false } ; // set true if object detected

con st int i r ReflectThreshold = 10; / / % level below aMbient to trigg e r reflection


con s t int i r EdgeTh reshold = 90; / / % level above aMbient to trigger edge

void i r SensorBegin ( )
{
fo r ( i n t sensor = 0 ; sensor < NBR_SENSOR S ; senso r++ )
i r SensorCalibrate ( senso r ) ;

/ / calibrate for aMbient ligh t


void i r SensorCalibrate( byte senso r )
{
int aMbient = analogRead ( IR_SENSOR [ sensor ] ) ; // get aMbient level
i rSensorAMbient [ senso r ] = aMbien t ;
/ / precalculate the levels fo r object and edge detection
i rSen sorReflect [ senso r ] ( aMbient * (long ) ( 10 0 - i r ReflectThreshold ) ) / 100 ;
i rSensorEdge [ senso r ] = ( aMbient * ( long ) ( 100+i r EdgeTh reshold ) ) / 100 ;

/ / retu rns t rue if an object reflection detected on the given sensor


/ / the sensor pa raMeter is the index into the sensor a r ray
boolean irSenso rDetect(int sensor )

100
Making the Sketch Easy to Enhance

boolean result = false ; II default value


i n t value = analogRead ( IR_SENSOR [ sensor ] ) ; II get I R lig h t level
if( value <= irSenso rReflec t [ senso r ] ) {
result = true; II object detected ( lowe r value Means Mo re reflection )
if( isDetected [ senso r ] == false) { II only p rint on initial detection
Serial . p rint ( locationString [ senso r ] ) ;
Se rial . p rintln ( " object detected " ) ;

}
isDetected [ senso r ] = result;
retu rn result;

boolean i r EdgeDetect ( int sensor )


{
boolean result = false ; II default value
int value = analogRead ( IR_SENSOR [ sensor ] ) ; II get I R lig ht level
if( value >= irSensorEdge [ sensor ] ) {
result = true; II edge detected ( highe r value Means les s reflection)
if( isDetected [ senso r ] == false) { II only print on initial detection
Serial . p rint ( locationString [ senso r ] ) ;
Serial . println ( " edge detected " ) ;

}
isDetected [ sen sor] = result;
retu rn result;

The l'lyRobotOk exa mple ske tc h provide d i n the boo k down loa d code shows
the code after the c ode is moved i n to the tabs.

Global Definitions
Definitions that need to be accessed across multiple process will automatically make all of the functions
modules are called 'g lobal' definitions.These are gen­ i n each tab accessible throughout the sketch, con­
erally stored in files called 'header files' (or 'headers'). stant definitions should be explicitly included at the
These files typically have a file extension of . h and top of the main tab as follows:
the file containing these global definitions is here II include the global defines
called robotDefi.nes . h. Although the Arduino build #include " robotDefi. n es . h "

The fin al ste p i n re structuring the sketc h i s t o move the c on stan t defini ti on s
at the top of the sketch i n to a sep arate tab. The se con sta n ts are used by a
n umber of different mod ules and c ollecting the se together m akes i t easier to
ensure th at the val ues are accessible by a l l the modules:

1. Crea te a tab na med robotDefi.nes . h (d on't forget the . h).

Chapter 6 101
Making the Sketch Easy to Enhance

2. From the top of the myRobot tab, m ove th e defin es start i ng from:
I **** Global Defines **** I
and en di ng at:
I *** End of Global Defines *******I
(Exam ple 6-9) i nto the tab you j u st created.
3. Switch ba ck t o the myR obot ta b, a n d a dd this line at the t op, ri g ht after
the #i.nc lud e s for AFMotor.h and RobotMotor.h:
#include " robotDeftnes . h "

Thi s i s the code that g oe s into the robotDefi.nes . h:

Example 6-9. Global defines


I ***** Global Defines **** I
II defines to iden tify senso r s
canst i n t S ENS E_I R_LEFT = 0 ;
canst i n t SENS E_IR_RIGHT = 1 ;

II defines for directions


canst int D I R_LEFT = 0 ;
canst int D I R_RIGHT = 1 ;
canst int D I R_CENTER = 2 ;

canst char * locationSt ring [ ] = { " Left " , " Right " , " Center " } ; II Debug labels
II http : lla rduino . cclenlRefe rencel String for �ore on cha racter string ar rays
II obstacles constants
canst i n t OBST_NONE = 0; II no obstacle detected
canst i n t OBST_LEFT_EDGE = 1; II left edge detected
canst int OBST_RIGHT_EDGE = 2; II right edge detected
canst int OBST_FRONT_EDGE = 3; II edge detect a t both left a n d right senso r s

canst int L ED_PIN = 1 3 ;

I **** E n d of Global Defines **************** I

102
Controlling Speed and
Direction

This chapter covers the principles of robot motor control that apply to both
two wheeled and four wheeled platforms. The motor controller hardware is
explained, as is the code used to make this functionality accessible to the
sketches. The second half of this chapter ("Software Architecture for Robot
Mobility" (page 1 19)) describes software modulesthat frees the sketch logic from
a dependency on any specific motor hardware. All sketches use the library
named RobotMotor that provides a consistent interface to the hardware spe­
cific motor system. An optional software module named Move provides high
level functions to move the robot that simplifies the code in the more complex
sketches that follow in chapters to come.

Hardware Required
• This chapter uses the AFMotor shield described in Chapter 2.

Sketches Used in This Chapter


• The motor control code used in Chapter 6 is explained and two new
sketches are introduced:
• MyRobotCa l ibrateRotation . ino-A sketch for running the robot through
a range of speeds to calibrate the robot.

103
Types of Motors

• MyRobotMove . 1.no-This sketch s hows how to use hig her level movement
functi ons. Constants for d efining the cu rrent rob ot movement a re add ed
to the rob otDefin es tab. A n ew tab named M ove is add ed t hat c ontains
the hig h level movement functi ons. The l rS ens or tab and R ob otM otor li­
bra r y a re unc hanged (Fig ure 7-1 ).

myRobot robotDefines lrSensors


-
Move
myR obotM ove Move state -I RobotMotor
-
(Movement
added Library
Codel

Figure 7-1. myRobotMove Sketch

Types of Motors
Brushed DC M ot ors, such as the on es used in the two wheeled and fou r
wheel ed platforms (see Figure 7-2) are the most c ommon t y pe used wit h Ar­
d u i n o rob ots. Th es e have two l eads c on n ected to brush es (contacts) that con­
trol the mag n etic fi eld of the coi ls th at d rive t he mot or c ore (a rmature) . M ot or
d i recti on can be reversed by reversing the polarity of the power s ourc e. These
m ot ors typically rotate t oo fast t o di rectl y d rive t h e rob ot wheels or tracks, s o
g ea r red ucti on is used t o reduce s peed and increase t orq u e.

104
Types of Motors

Figure 7·2. DC motor with gearbox

O ther ki nds of m otors can be used to power robots; here are som e you m ay
com e across:
Continuous rotation servo
These m otors are u sed on sm al ler robots. Th ey have the advantag e that
the m otor control ler, motor, and g earbox are all m ou nted i n the sam e
hou sing, so they are easy to attach to a robot and can be driven directly
from Ardu i no pins. However they u sually h ave l ess torq ue th an typi cal
stand·alone bru shed motors.
Brush/ess motors
These h ave i ncreased torqu e and effi ci ency com pared to bru shed m otor s
but they are m ore expensive and complex to control. However, pri ces are
droppi ng and they are a g ood choi ce for a l arg er robot.

Chapter 7 105
Motor Controllers

Stepper motors
Th ese motors are u sed on large robots when prec i se c ontrol i s requ ired.
Th ese motors typically requ ire 1 2 or 24 vol ts so they are not often u sed on
smal l battery operated robots. H owever they may becom e m ore popu l ar
d u e to th e recen t avai l abi l i ty of l ow c ost 5 volt steppers.

Motor Controllers
The two wheel a nd four wh eel pl atforms u se sma l l DC m otors tha t are con­
trol l ed u si ng an H -Brid g e. The H-Brid g e featu red in th i s book is part of the
AFM otor sh i eld from Ad afru i t I n d u stries. Thi s can d rive up to fou r m otors i n­
d epen den tly, alth ough on ly two a re u sed wi th the two wheel ed robot. This
shi eld req u ires a library for i nterfaci ng sketc h c ode wi th th e hard wa re; thi s
l i bra ry is i nc l u d ed with the cod e d ownload for th i s book (see " H ow to Contac t
U s" ( pa ge xv)).

The name H-bridge derives from the characteristic shape that you can
see in these figures.

To enab l e th e sketches to work wi th oth er H-Brid g e h ard ware, a l i b rary named


RobotMotor is provided wi th th e ex am pl e cod e th at provides gen eric control
fu ncti ons th at th e li brary transl ates i nto the specific commands for the AFM o­
tor sh ield or another shi eld if you h ave u se different h ard ware. see "S oftware
Archi tectu re for R obot M obi lity" (page 1 1 9)

This library is modified from the one on the Adafruit site to work with
the Leonardo board. The standard Adafruit library can be used with
the Uno board). See "Installing Third-Party Libraries" (page 83) if you
need directions for installing a library. If you followed along with
Chapter 6, you will already have the library installed.

106
Motor Controllers

The followi ng diagra ms ex pla i n how an H-bri dge works a n d the RobotMotor
func ti ons used to con trol the motors:

Supply Voltage
T Figu re 7-3 is a schematic dra wi ng tha t shows

I
how an H-bri dge works. The m otor is connec­
ted to the positive su pp ly voltage a nd g rou nd
throug h fou r swi tches (in the actual H-bri dge,
A the swi tchi ng is done wi th transis tors). When
a ll the s wi tches a re open, no cu rrent flows a n d
the m otor i s stopped. The c ode to s top a m otor
is:
MotorStop(Motor ) ;

The parameter in brackets


(Motor) is a constan t identifying
the motor (MOTOR_LEFT or
MO TOR_RIGHT) to control. The soft­
G round ware for the four wheeled robot
Figure 7-3. H-Bridge with Motor Idle
treats the two motors on the
same side as if they were a single
motor.

Supply Voltage Fig ure 7-4 sh ows the two swi tches tha t when
closed will ca u se the motor to ru n forwa rd. The
one marked A c onnects the posi tive m otor ter­
m i na l to the p ositive p ower supply. S wi tc h D

0 c on nects the neg a ti ve motor termi nal to


ground. The c ode to run a m otor forwa rd a t the
given s peed is:
MotorForwa rd ( Moto r , speed ) ;

B The constant speed is a value rep­


resenting speed as a percent of
maximum speed. This is de­
scribed in the section: "Control­
Ground ling Motor Speed" (page 1 09).

Figure 7-4. H-Bridge with Motor Running Forward

Chapter 7 107
Motor Controllers

Supply Voltage Figure 7-5 shows that the opposite switches


result in the motor reversing. Switch C con­
nects the positive supply to the negative motor
terminal. Switch B connects the positive motor
@) terminal to ground. The code to run a motor in
reverse at the given speed is:
MotorReve r s e ( Moto r , speed ) ;

"
E
8 Ground
.o,(.
0

I
Figure 7-5. H-Bridge with Motor Running i n Reverse

l Supply Voltage
T
Figure7-6 shows switches B and D closed. Both

I
motor terminals are connected together - nei­
ther terminal is connected to the positive sup­
ply voltage. This is a mode supported by some
A
H-bridge hardware to stop the motor more
quickly than it would in the previous case
where the motor is simply disconnected from
the power. Because the motor terminals are
shorted, the motor will resist rotation. If the
motor had been spinning and then set to this
mode, it will stop more quickly than if the ter­
minals were simply disconnected. The code to
brake a motor is:
Mot o r B r a ke (Moto r ) ;
Ground

Figure 7-6. H-Bridge with Motor Brake Not all H-bridges, including the
Adafruit library, support this
mode. The Robo tMotor library will
call !'lotorStop when the !'lotor
Brake function is called.

108
Controll ing Motor S peed

Controlling Motor Speed


How Motor Speed Is Controlled
M otor speed is c ontrolled by a tech nique c alled Pulse Width Modulation (PWM),
which vari e s the proporti on of the motors on-ti me to- off ti me. The h i gher the
proporti on of on-ti m e, the gre ater the motor p ower and the fas ter the robot
wi l l move (see Fi gure 7-7).

Motor stopped: AnalogWrite(M_PWM, 0) [0% duty cycle]


HIGH

LOW __________________

Motor slow: AnalogWrite(M_PWM, 63) (25% duty cycle}


HIGH

LOW

Motor half speed: AnalogWrite(M_PWM, 1 27) (50% duty cycle}

::: I I I I I
Motor ¼ speed : AnalogWrite(M_PWM, 191 ) (75% duty cycle}

::: I I I I I I
Motor max speed: AnalogWrite(M_PWM, 255) [1 00% duty cycle}
HIGH

LOW

Battery Positive

r7_J7__

Ground

Figure 7-7. Controlling motor power using Pulse Width Modulation

Chapter 7 109
Controlling Motor Speed

All the code in this book uses a percent value to refer to speed. This value is
the percentage of power given to the motors (technically, its called the duty
cycle). Percent speed is used instead of the raw PWM value to isolate the sketch
logic from the low level motor code. Different motor hardware use various
techniques for controlling motor rotation speed. For example, continuous ro­
tation servos can use servo angle (where 90 is stop and O actually rotates the
motor at full reverse speed), and stepper motors don't use PWM to control
speed. Because the h igh level logic always uses percent and this is mapped to
the range needed by the hardware in the motor interface code, the same high
level code can be used with other hardware simply by swapping the appro­
priate motor interface module.

Code for Motor Control


The AFMotor library that interfaces with the motor hardware expects a PWM
value ranging from O to255, so the r1otorSetSpeed function in the RobotMotor
library converts the percent into a PWM value using the r1ap function, as shown
in Example 7-1 .

Example 7-1. Setting the motor speed; from RobotMotor. cpp


void MotorSetS peed ( in t Moto r , in t s peed )
{
MotorSpeed [Moto r ] = speed ; // save the v alue
int pwM = Ma p ( s peed , 0 , 100 , 0 , 25 5 ) ; // scale to PWM range

Moto r s ( Motor ] . setSpeed ( pwM)

l'lap is a ha ndy fu nction that is used exte nsively throughout this b ook.
The fu nction scales a value from one ra nge to a nother ra nge. For ex­
a mple, the following scales a value from ana l ogRead (0-1 023) to a
p ercent (0- 1 00):

i n t toPercen t = Map(va l , 0, 1 023, 0, 100) ;

You ca n rea d more ab out map here: http://arduino.cc/en/Reference/


map.

Bear in mind that the speed percentage is actually controlling motor power
and this is usually not directly proportional to speed, particularly at low power.

110
Control ling Motor S peed

The amount of p ower requ i re d to get the robot movi ng is depen dent on the
motor, gearbox, batte ry voltage, robot wei g ht an d the su rface the robot is on.
The meth od to calib rate the rob ot wi l l be descri be d shortly, bu t first, here is
an exp l an ati on of h ow the s oftware handles robot speed control.
The c ode frag ment shown in Example 7-2 c on tai ns the cons tants that are used
to calculate the app ropri ate delays for different speeds to rotate the rob ot.
rotati.onTi.l'le stores the durati on fo r a 360 de gree rotati on for all practical
speeds. Spee ds less than MIN_SPEED (40%) do n ot provi de suffi cient power to
overc ome fric ti on in the dri ve sys tem.

Example 7-2. Constants for the delays needed to rotate the robot, from RobotMotor.cpp
con st int MIN_SPEED = 40 ; // fi rst table entry is 40% s peed
con st int SPEED_TABL E_INTERVAL = 1 0 ; // each table entry is 10% faster s peed
con s t int NBR_SPEEDS = 1 + ( 100 - MIN_SPEED ) / SPEED_TAB LE_INTERVAL;

int s peedTab le [ NBR_SPEEDS ] = { 40 , 5 0 , 60 , 70 , 80 , 90 , 100 } ; / / s peeds


int rotationTi�e [ NBR_SPEED5 ] = { 5500 , 3300 , 2400 , 2000 , 1750 , 1550 , 1 150 } ; // ti�e

The table holds du rati ons in m illisecon ds for speeds in in tervals of 1 0%. The
values we re deri ve d from experi men tat i on wi th the two wheeled robot using
a s ke tch named l'lyRobotCa l i.brateRotati.on sketch an d notin g the an g les for
each of the speeds as s h own in Fi g u re 7-8.

Rotation Angle
for Speeds from 40% to 100%

t 2 50 +----------------------,....-=--t
QI� 200 +--------------==-- �- �--------­
-=
O 15 0 +------------,:::,;;;,o+-=-----"'�------------
.5
QI 100 +-----=-S:,.,..,.---_.::.c;_:__________________
� so
o +----�---�---�---�---�---�--�
40 so 60 70 80 90 100
Speed (as percent)

Figure 7-8. Angle that the robot rotates for one second burst at each of the supported speeds

By calc ul ating the ang le as a fracti on of 360 degrees, the time to rotate the
robot one c omplete revoluti on can be determi ned foreach speed ( the calcu­
l ati on for the val ue in millisecon ds is: 1000* ( 360/ang le ) .

Chapter 7 111
Controlling Motor Speed

Figu re 7-9 shows the actu al ti m es for the 2WD ro bot.

Time to Rotate 360 Degrees


for Speeds from 40% to 100%
6000

5000

-g0 4000

:: 3000
::JE
.!:
E 2000
i=

1000

0
40 so 60 70 80 90 100
Speed (as percent)

Figure 7-9. Time for a full rotation a t various speeds

The rel ationshi p between rotation ang l e an d speed percen tag e i s not li near,
so inter polation i s u sed to calc ulate the duration to produ ce a fu ll ro tation for
an y speed (as long as i t i s as fast or faster than the m i n i m um speed).
Exam ple 7-3 shows the code th at u ses the table wi th tim es based on the data
shown in Figu re 7-9.
The RobotMotor l i brar y has the code to determi ne how m uch tim e the robo t
req uires to rotate 360 d egrees. Thi s wil l differ between the two an d fou r
wheeled chassi s and vary as the motor speed vari es. Ex am pl e 7-3 show s the
val u es used in the RobotMotor.cpp code for the 2WD chassi s.

112
Contro l l i ng Motor S peed

Example 7-3. Controlling rotation rate


/ / tables hold tiMe in MS to rotate robot 360 degrees at various speeds
// this enables conve r sion of rotation angle into tiMed Moto r MoveMent
/ / The speeds a re pe rcent of Max speed
// Note : low cost Motors do not have enough torque at low speeds so
// the robot will not Move below this value
/ / I n te r polation is used to get a tiMe for any speed froM MIN_SPEED to 100%

can st int MIN_SPEED = 40 ; / / fi rst table entry is 40% speed


can s t int SPEED_TABLE_INTERVAL = 10; / / each table entry is 10% faster speed
can st int NBR_SPEEDS = 1 + ( 100 - MIN_SP E ED ) / SPEED_TAB LE_INTERVAL;

int speedTab le [ NBR_SPEEDS] = { 40 , 5 0 , 60 , 70 , 8 0 , 90 , 100} ; / / speeds


int rotationTtMe [ NBR_SPE EDS ] = { 550 0 , 3300 , 2400 , 2000 , 1750 , 1550 , 1150} ; // tiMe

Exam ple 7-4 shows the values for the 4WD cha ssi s.

Example 7-4. Controlling rotation rate


can s t int MIN_SPEED = 60 ; // fi rst table entry is 60% speed
can s t int SPE ED_TABL E_INTERVAL = 1 0 ; // each table entry is 10% faster speed
can st int NBR_SPEEDS = 1 + ( 100 - MIN_SP EED ) / SPEED_TAB LE_INTERVAL;

int speedTable [ NBR_SPEED S ] = { 60 , 70, 80 , 90, 100 } ; / / speed s


int rotationTtMe [ NBR_SPE EDS ] = { 5S0 0 , 3300 , 2400 , 2000 , 1750 } ; // ttMe

Note that there are fewer entries in the ta bles for the 4WD robot beca use thi s
cha ssi s req ui res a hi gher spee d to get going. "Ca li brating Rotation a n d Tra ck­
i ng" ( page 1 1 6) expla i ns how to a dj ust the tab le s to suit yo ur robot.
The table entries a ssume speed i nterva ls of 1 0% so the va lue for M I N_SPEED
should be m ulti ple of 1 0. There m ust be o ne rotation time per spee d so if yo u
i ncrease M I N_SPEED by 1 0 for e xam ple, you will a lso need to remove the fi rst
element i n both speedTa ble and rotationTime.
The code in RobotMotor.cpp that uses the data in the rotationTime ta ble is the
same for both cha ssi s (see Exa m ple 7-5).

Chapter 7 113
Co ntrolling Moto r Speed

Modifying a Library
You know how to modify an Arduino sketch-just 2. Locate the libraries directory i nside, and then
edit it in the Arduino IDE. But modifying a li brary is a open the directory named RobotMotor.
bit more involved. You need to go into the sketch
folder, open up the library directory, and find the file. 3. Right-click (or Control-click on the Mac) the
Then you need to open it i n a text editor. Here's how RobotMotor.h fi l e, and open it with a plain text
to modify the RobotMotor.h file to use the 4WD chas­ editor. On Windows, you should use Notepad.
sis. On the Mac, you can use TextEdit. On Linux,
use your favorite plain text editor.
First, find the sketchbook location. Go to Arduino's
preferences (File ➔ Preferences on Wi ndows or Li nux, 4. Change #defi.ne CHASSI S_ZWD to #defi.ne
Ardui no➔ Preferences on Mac) . Under Sketchbook CHASSI S_4WD and save the file.
Location, you'll find the name of the d irectory that
contains your sketches and libraries. Next: Although you need to quit and restart the Arduino
IDE when you i nstall a new li brary, you don't need to
1 . Open the sketchbook folder in the Finder do so each time you modify a library.
(Mac) or Explorer (Windows).

Example 7-5. Applying the rotation Time table


// retu rn the ttMe tn Mtlltseconds to turn the given angle at the given speed
long rotattonAngleToTtMe ( int a ngle , int s peed )
{
tnt fullRotattonTtMe ; // ttMe to rotate 360 deg rees at g iven speed

tf( speed < MIN_SPEED )


ret u r n 0; / / ignore s peed s slower then the ftrst table entry

a ngle = a b s ( angle) ;

tf( speed >= 100 )


fullRotattonTtMe = rotattonTtMe [NBR_SPEED S - 1 ] ; / / the last entry ts 100%
else

tnt tndex = ( s peed - MIN_SPEED) / SPEED_TABLE_INTERVAL // tndex tnto s peed


// and ttMe tables
tnt t0 = rota ttonTtMe [ tndex ] ;
tnt tl = rotattonTtMe [ t ndex+ l ] ; / / ttMe of the next higher s peed
fullRotattonTtMe = Map( s peed ,
s peedTable [ tndex ] ,
s peedTa ble [ t ndex+ l ] , t0, t l ) ;
/ / Sertal . p rtn t ( " tndex= " ) ; Se rtal . p rtnt ( tndex ) ;
/ / Sertal . p rtnt( " , t 0 = " ) ; Sertal . p rtnt ( t0 ) ;
/ / Sertal . p rtn t ( " , t l = " ) ; Sertal . p rtnt ( tl ) ;

114
Control ling Motor S peed

// Seri.al . pri.nt ( " full rotati.on ti.Me = " ) ; Seri.al . pri.ntl n ( fullRota ti.onTi.Me ) ;
long result = Ma p ( a ngle , 0 , 360 , 0 , fullRotati.onTi.Me ) ;
return result ;

Thi s c ode determin es the i ndex i nto the s peedTab le array that i s c losest to ( but
not greater than) t he desi red speed. Thi s i n dex is stored in the vari abl e t0. The
i nterpolated time will be between th i s valu e an d t he n ext i n dex (tl ) , with the
rotat i on time c alc ul at ed usi ng t h e rati o of the rotat'i.onHMe valu e between tO
and t l i n the sam e proportion as the desi red speed i n the s peedTab le. It may
be easi er to u nderstan d how thi s works by c on su lting Fig ure 7-1 0.

2400 (t0)
C/l 2300 -
2200 -
E
C: 2 1 00 -
Q) 2000 (t1 )

62.5 65 67.5
60% 70%
Speed (as percent)
Figure 7-10. Speed Interpolation

Chapter 7 115
Controlling Motor Speed

For exam ple, for a speed of 65%, whi ch is halfway b etween the valu es for 60%
and 70%, t he tim e a ssociated wit h 65% speed will be 2200, which i s ha lf way
b etween 2400 (the 60% speed value) a n d 2000 (the 70% speed val ue). A speed
of 62.5% i s 1 /4 of the range between t he tabl e entri es (60 a n d 70), so the time
will be 1 /4 of the rang e between t he speeds for that ra nge (2400 and 2000,
whi ch is 2300 mi llisecon ds). The l'lap fun ction is u sed to cal culate thi s pro por­
tional value:
fullRotationTiMe = M a p ( s peed , s peedTable [ index ] , s peedTable [ i ndex+ 1 ] , t0 , t 1 ) ;

To calculate the time to rotate an ang l e other tha n 360 deg rees, the r1 a p func­
tion i s used again:
long result = r,ap ( a ngle , 0 , 360 , 0 , fullRotatlonTlr,e ) ;

Cal ibrating Rotation and Tracking


Motor timing s do not n eed to be exact but if you a re u si ng t he four wheeled
platform you will proba bly want to calibrate the values i n the ta ble b eca use
thi s platform req ui res more rotation time than the two wheeled version. You
can cali bra te yo ur robot wi th the r1yRobotCa HbrateRotatlon sketch. H ere i s
the main ta b for that sketch; the a ctua l ca libration i s perform ed in the call
b rateSpeed fun ction shown i n Example 7-6.

Example 7-6. Robot calibration


/ ********************************* *************************
MyRobotCalibrateRotation . ino
*********************************************************** /
/ / include Moto r libra ries
#include <AFMotor . h> / / adafruit Motor shield libra ry
#include <RobotMotor . h > / / 2wd or 4wd Motor lib rary

/ / Setup runs at startup and is used configu r e pins a nd init systeM va riables
void setup ( )
{
MotorBeg i n (MOTOR_LEFT) ;
MotorBeg i n ( MOTOR_RIGHT ) ;
calibrateSpeed ( ) ;

void loop( )
{
}

void calib r a teSpeed ( )


{
fo r ( int s peed = MI N_SP EED; speed <= 100 ; s peed += 10)
{
// rotate robot left for 1 second
Motor Reve rse(MOTOR_LEFT , speed ) ;

116
Controlling Motor Speed

Motor Forwa r d ( MOTOR_RIGHT , speed ) ;


delay ( 1000 ) ; / / delay 1 second
MotorStop(MOTOR_LE FT) ;
MotorStop(MOTOR_RIGHT ) ;

delay( 3000 ) ; / / wait 3 seconds

// rotate robot right for 1 second


MotorReve rse( MOTOR_RIGHT , speed ) ;
Motor Forwa r d ( MOTOR_LEFT , s peed ) ;
delay ( 1000 ) ; / / delay 1 second
MotorStop(MOTOR_LE FT) ;
Moto rStop(MOTOR_RIGHT ) ;
delay ( 3000 ) ; / / wait 3 second s
}
}

Running this sketch will rotate the robot left (CCW ) for one second, stop for
one second, then rotate the robot right (CW) for a second. If you mark the angle
of the robot after each CCW rotation, you can calculate how much longer or
shorter it would take the robot to turn360 degrees for each speed. If your robot
does not rotate at all at the slower speeds, note the lowest speed that the robot
does move and set MI N_SPEED in RobotMotor.cpp to this value.
The RobotMotor library also supports the ability to adjust the relative power
to each motor in order to prevent the robot drifting off a straight course due
to differences in performanee between the left and right motor(s). If your robot
does not track a straight line when moving forward or backward, you can
modify the motor library (see next section) to correct this.
The RobotMotor.cpp library file contains a constant that can be adjusted to
correct drift:
con st int differential = 0; / / % faster left Motor t u r n s coMpa red to right

Here is how the differential constant is used in the code:


if( Motor == MOTOR_LEFT
&& speed > diffe rential)
speed - = diffe rentia l ;

If your robot drifts, adjust the constant d lfferentla l t o compensate. Set the
value using trial and error, positive values nudge the robot to the right, nega­
tive values to the left. The correct value will be the difference in speed between
the motors in percent. The drift will vary somewhat with motor speed so best
to set this when testing with the robot running at a speed midway between
the minimum and maximum speeds.

Chapter 7 117
Controlling M otor Speed

Here is a modified version of the previous sketch that will drive the robot in a
straight line when the differential constant is adjusted to correct drift. You can
make di. ffe renti.a l a negative number if your right motor turns faster than
your left (the robot drifts to the left).

Example 7-Z Robot tracking


/**********************************************************
MyRobotCalibrateT r acking . ino
***********************************************************/
/ / include Motor libra ries
#include <AFMotor . h> / / adafruit Motor shield library
#include <RobotMotor . h> / / 2wd or 4wd Motor lib rary

con st i n t TEST_SPEED = MIN_SPEED + 10 ; // Typical speed to run the robot


con s t int diffe rential = 0; // % faster left Motor t u r n s coMpa red to right

/ / Setup runs at startup and is used configu re pins a nd init systeM varia bles
void setup ( )
{
MotorBeg i n ( MOTOR_L EFT) ;
MotorBeg i n ( MOTOR_RIGHT ) ;
calib rateDrift( ) ;

void loop( )
{
}

void calib r a teDrift( )


{
Motor Forwa rd ( MOTOR_LEFT , T EST_SPEED - diffe rentia l ) ;
Motor Forwa rd ( MOTOR_RIGHT , TEST_SPEED ) ;
delay( 2000 ) ; / / delay 2 second
MotorSto p ( MOTOR_LEFT ) ;
MotorSto p ( MOTOR_RI GHT) ;
}

118
Software Architecture for Robot Mobility

If the robot drifts the right when running this sketch, try setting dHferen
ti.al to 2. If this overcorrects (the robot now drifts to the left), decrease the
differential value. If you need more correction, increase the value. If the robot
was drifting to the left, use negative values of differential to compensate. You
should be able to get the robot running more or less straight after a little trial
and error. Don't worry about minor deviations which are caused by small dif­
ferences in the efficiency of the motors at varying battery levels.
After you have settled in a value for di. ffe renti.a l you must change this in the
RobotMotor.cpp file. Open this file with a text editor and (see "Modifying a
Library" (page 11 4)) and find the declaration towards the beginning of the file:
can st tnt dtfferenttal = 0; / / % faster left Motor t u r n s coMpa red to rtght

Replace O with the value determined from the calibration sketch and save the
file.

Software Architecture for Robot Mobility


This book provides software modules to minimize the coupling between the
application logic and the hardware that actually moves the robot. This mini­
mizes changes that would otherwise be required if you want to use the same
logic with different hardware. A low level motor interface library named Ro
botMotor encapsulates the motor hardware functions so that the same sketch
code can be used with the two wheeled or four wheeled robot with the Adafruit
shield or with a different motor shield. A higher level module named Move is
also provided to enable the sketch logic to deal with robot movements instead
of motor power, for example, the Move module has commands to move the
robot left or right, to move backward, or rotate 90 degrees. Figure 7-1 1 shows
how the software and hardware is layered. The high level Move code is de­
scribed in detail later in this chapter.

Chapter 7 119
Software Architecture for Robot Mobility

Sketch
Sketch calls any function at any level

r Move code (Arduino Tab)


moveFoward •1
l
moveBackward One of these libraries required
moveLe ft I only if a different motor shield is
moveRight I
l moveRotate used
lm'::eS.:.,:S�e� I

RobotMotor Library RobotMotor


r_ _ .1_ _ Library RobotMotor
_ 1 [ _ _ .i. _ Library
_l
(AF Motor) (Ardu moto)
I motorfo (Customized for shield) I
I I moto
moto rfo rwa rd rwa rd r Forward
moto rReverse 2WD & 4WD lmoto rReve rse J lmoto rReve rse I
motor Stop motor Stop motorStop I
motorBrake
versions
lmotorBrake I lmotorBrake
motorSetSpeed lmotorSetSpeed
- - T - - I lmotorSetSpeed
--T--I
1 1
I I
AFMotor Library I I
Moto r . run ( FORWARD) I
Motor . run ( BACKWARD )
I

Motor . run ( RELEASE )


I I
Moto r . run ( BRAKE )
I I
7 softwa re Moto r . setSpeed I I
I I
I I
H a rdware AFMotor Shield
l Ardu
_ t._ _l
moto
I_ J _ 7
Other Motor I
I Shield I I Shield
I
L - r -
L _T _ J
I 1
I I
I I
I I
I I
+ - -' + - - - - - - - -'

4 M otors 2 M otors

Figure 7-11. Software architecture for motor control

Example 7-9 shows the source code for the RobotMotor library's .cpp file. The
header file RobotMotor . h (Example 7- 8) defines the constants for the left and
right motors and declares the functions for speed and direction.

120
Software Architectu re for Robot Mobility

Example 7-8. RobotMotor. h header file


/ *******************************************************
RobotMotor . h
low level Motor d rive r interface
Copy right Michael Margolis May 8 2012
******************************************************** /
/ * if you have the 4WD chas sis , change the line :
#define CHASS IS_2WD
to:
#define CHASSIS_4WD
•I
#define CHASSI S_2WD / / change suffix f roM 2WD to 4WD if using the 4WD chassis
/ / defines for left and r ig h t Moto rs
can st int MOTOR_LEFT = 0;
can st int MOTOR_R IGHT = 1;
exte r n can st int MIN_SPEED;
exter n int s peedTable [ ] ;
exter n int rotationTiMe [ ] ;
exter n can st int SPE ED_TABLE_INTERVAL;
exte r n can st int NBR_SPE EDS ;
void MotorBegin(int Moto r ) ;
/ / s peed range i s 0 t o 100 percent
void MotorSetSpeed ( i n t Moto r , i n t s peed ) ;
void Motor Forwa rd ( int Motor , int speed ) ;
void MotorReverse( int Motor , int speed ) ;
void MotorStop ( in t Moto r ) ;
void MotorB rake ( i n t Moto r ) ;

Example 7-9. RobotMotor functions


/ *******************************************************
RobotMotor . cpp / / Adafruit version for 2WD and 4WD chassis
low level Motor d rive r for use with adafruit Motor s hield
Motor constants used are defined AFMotor . h
Copy right Michael Margolis May 8 2012
******************************************************** /
#include <Arduino . h>
#include <AFMotor . h> // adafruit Moto r shield library
#include " RobotMoto r . h "
can st int diffe rential = 0; // % faster left Motor turns coMpa red to rig h t
/ / tables hold tiMe in MS to rotate robot 3 6 0 deg rees at various s peeds
/ / this enables conve rsion of rotation angle into tiMed Motor MoveMent
/ / The s peeds a re pe rcent of Max speed
// Note : low cost Motors do not have enough torque at low s peeds so
/ / the robot will not Move below this value
/ / I nterpolation i s used to get a tiMe for any s peed froM MIN_SPEED to 100%
/ / constants for 2 wheeled robot chassis
#if defined CHASSIS_2WD
can st int MIN_SPEED = 40 ; // fi rst table entry i s 40% s peed
can st int SPEED_TABL E_INTERVAL = 10 ; // each table entry is 10% faster s peed
can st int NBR_SPEEDS = 1 + ( 100 - MIN_SP E ED ) / SPEED_TAB LE_INTERVAL;

Chapter 7 121
Software Architecture for Robot Mobility

i.nt speedTa ble[ NBR_5P EED5 ] = {40 , 5 0 , 60 , 70 , 8 0 , 90 , 100 } ; // s peeds


i.nt rotati.onTi.Me [ NBR_5PEED5] = {5500 , 3300 , 2400 , 2000 , 1750 , 1550 , 1150 } ; / / ti.Me
AF_DCMotor Moto rs [ ] = {
AF_DCMotor ( l , MOTOR12_1KHZ ) , // left i.s Motor #1
AF_DCMotor ( 2 , MOTOR12_1KHZ) // ri.ght i.s Motor #2 } ;
// constants for 4 wheeled robot
#eli.f defi.ned CHA55I 5_4WD
con st i.n t MI N_5PEED = 60 ; // fi. rst table entry i.s 60% speed
con s t i.n t 5PEED_TABL E_INTERVAL = 1 0 ; // each table entry i.s 10% faster s peed
con st i.n t NBR_5PEED5 = 1 + ( 100 - MIN_5PEED ) / 5PEED_TABLE_INTERVAL;

i.nt speedTa ble[ NBR_5 PEED5 ] = {60 , 70, 8 0 , 90 , 100 } ; / / speeds


i.nt rotati.onTi.Me [ NBR_5PEED5] = {5500 , 3300 , 2400 , 2000 , 175 0 } ; // ti.Me
AF_DCMotor Moto rs [ ] = {
AF_DCMotor ( 4 , MOTOR34_1 KHZ ) , // left f ront i.s Motor #4
AF_DCMotor ( 3 , MOTOR34_1 KHZ) , // ri.ght front i.s Motor #3
AF_DCMotor ( l , MOTOR12_1KHZ ) , // left rea r i.s Motor #1
AF_DCMotor ( 2 , MOTOR12_1KHZ) / / ri.ght rea r i.s Motor #2
};
#else
#er ror " expected defi.ni.ti.on : CHA55 I 5_2WD o r CHA55I5_4WD not found "
#endi.f
i.nt Motor5peed [ 2 ] = {0 , 0 } ; // left and ri.ght Motor speed s sto red here ( 0 - 100% )
voi.d MotorBegi.n(i.nt Moto r )
{
Motor5top( Motor ) ; / / stop the front Motor
#i.f defined CHA55I5_4WD
Motor5to p ( Motor+2 ) ; // stop the rear Motor
#endi.f
}
// s peed range i.s 0 to 100 percent
voi. d Motor5et5peed (i.nt Moto r , i.nt s peed )
{
i.f( Motor == MOTOR_LEFT && speed > di.ffe renti.al )
speed - = di.ffe renti.a l ;
Motor5peed [Moto r ] = speed ; // save the value
i.nt pwM = Ma p ( s peed , 0 , 100 , 0 , 25 5 ) ; // scale to PWM range

Moto r s [ Motor ] . set5peed ( pwM )


#i.f defined CHA55I5_4WD
Motor s [ Motor+2 ] . set5peed ( pwM)
#endi.f
}
voi. d Motor Forwa rd ( i.nt Motor , i.nt s peed )
{
Motor5et5peed (Moto r , s peed ) ;
Motor s [ Motor ] . ru n ( FORWARD ) ;
#i.f defi.ned CHA55I5_4WD
Motor s [ Motor+2 ] . ru n ( FORWARD) ;
#endi.f
}
voi.d MotorReverse(i.nt Motor , i.nt speed )
{

122
Functions to Encapsulate Robot Movements

MotorSetSpeed ( Moto r , speed ) ;


Moto r s [ Motor ] . ru n ( BACKWARD ) ;
#if defined CHASSIS_4WD
Motor s [ Motor+2 ] . run ( BACKWARD) ;
#endH
}
void MotorStop ( in t Motor )
{
// todo set speed to 0 ? ? ?
Motors [Motor ] . r u n ( RELEASE ) ; / / stopped
#if defined CHASS I S_4WD
Moto r s [ Motor+2 ] . run ( RE LEAS E ) ;
#endH
}
void MOtorB rake ( i n t Moto r )
{
Motor s [ Motor ] . r u n ( BRAKE) ; / / stopped
#if defined CHASSI S_4WD
Motor s [ Motor+2 ] . r u n ( BRAKE ) ;
#endH

The R ob otM otor. cpp file contains code for both the two wheel and four wheel
chassis. Conditional compilation is used to build the library for the appropriate
version. #H defi.ned CHASSIS_2WD and #H defi.ned CHASSIS_ 4WD are checks
to see which chassis has been defined in the Rob otM otor. h file. code between
#H defi.ned CHASSI S_2WD and #end-L f will only be compiled if CHASS IS_2WD is
defined in RobotM otor. h. See "Installing Third- Party L ibraries" (page 83) for
more details on changing the define for the four wheel chassis.
This library can be modified to support different hardware. For example, see
Appendix B for the code to use the Ardumoto shield (but note that Ardumoto
only supports two motors so is not suitable for the four wheeled robot).

Functions to Encapsulate Robot Movements


You can simplify you r code for controlling your robot's behaviou r by using
higher level movement functions provided in the Move module. These func­
tions reference the desired movement from the robot's perspective rather than
specific motor control. For example, to rotate the robot, rather than calling
functions to run one motor forwards and the other backwards, you can call a
single function that rotates the robot. And by calibrating the speed of rotation,
you can easily get the robot to rotate to any desired angle.
The sketch named r,yRobotMove has the movement code in a tab called Move.
That s ketch is similar to the r,yRobot sketch from "Making the Sketch Easy to

Chapter 7 123
Functions to Encapsulate Robot Movements

Enh an ce" ( pag e 99) but uses the rot atio n fu n ctions in the Move tab to drive
the robot. Using the hig her level fun ctions to drive the ro bot not only si mplifi es
your code, it isolates the sketch lo g i c from the h ardware specific motor code.
Th e sketch es in all of th e followi ng ch apters control ro bot movement thro ug h
the fun ctio ns in th e Move tab.

Core Movement Code


H ere is a list of the core movem en t fun ctions:
Move Forward
Both motors are driven forward at th e s am e speed
Move Backward
Both motors driven in revers e at th e same s peed
Move Left
Left motor sto pped, right motor driven forward
Move Righ t
Right motor sto pped, Left motor driven forward
Move Stop
Both motors stop ped
Set Move Speed
Used to set the s peed for future ro bot movem en ts
Example 7- 1 0 shows th e code i n th e Move t ab th at provi des th e core move­
m ent function ali ty.

Example 7-10. The core movement functions


/ **** ** **** *** **** ** ** *** *** * ** *******
Drive : Mid level MoveMent functions
****************** **** ***** **** ****** /

int MoveState = MOV_STOP ; // what robot is doing

int MoveSpeed = 0; // Move s peed stored here ( 0 - 100%)


int speed inc reMent = 10 ; // percent to inc rease or dec rease speed

void MoveBegin ( )
{
Moto rBegin( MOTOR_LEFT ) ;
Moto rBegin( MOTOR_RIGHT ) ;
MOVeStop( ) ;

void Moveleft ( )
{
Motor forwa r d ( MOTOR_LEFT , 0);

124
Functions to Encapsulate Robot Movements

Motor Forwa r d ( MOTOR_RIGHT , MoveSpeed ) ;


changeMoveState (MOV_LE FT ) ;

votd MoveRtg ht( )


{
MotorForwa r d ( MOTOR_LEFT , MoveSpeed ) ;
MotorForwa r d ( MOTOR_RIGHT , 0 ) ;
changeMoveState ( MOV_RIGHT ) ;

votd MoveStop( )
{
MotorSto p ( MOTOR_LEFT ) ;
MotorStop ( MOTOR_RIGHT ) ;
changeMoveState ( MOV_STOP) ;

votd MoveB rake ( )


{
MotorBrake(MOTOR_L EFT ) ;
MotorBrake(MOTOR_R IGHT ) ;
changeMoveState (MOV_STOP) ;

votd MoveBackwa rd ( )
{
MotorReve rse( MOTOR_LEFT , MoveSpeed ) ;
MOtorReverse(MOTOR_RIGHT , MOVeSpeed ) ;
changeMoveState (MOV_BACK) ;

votd MoveFo rwa rd( )


{
MotorForwa rd ( MOTOR_LEFT , MoveSpeed ) ;
MotorForwa r d ( MOTOR_RIGHT, MOveSpeed ) ;
changeMoveState ( MOV_FORWARD ) ;
}

votd MoveSetSpeed ( tnt speed )


{
MotorSetSpeed (MOTOR_LEFT , speed )
MotorSetSpeed (MOTOR_RIGHT , speed ) ;
MoveSpeed = s peed ; I I save the value

The co de provi des functions that com bine the i n divid ua l motor co mma n ds
described in "Motor Con trollers" ( page 1 06). For exam ple, the r1oveForward
fu ncti on cal ls the i ndivi dual fu nctions to rotate the left a nd right motors i n the

Chapter 7 125
Functions to Encapsulate Robot Movements

di recti on that m oves the robot forwa rd. Th e speed to move is set by the !'love
Set Speed functi on. l'loveSe tSpeed commands the motors to run at the desi red
speed a nd stores th e speed va l ue so the robot ca n resume runni ng at the last
set speed fo l l owi ng a n eva sive acti on nee de d to avoi d obstacles.

Additional Core Functions


S ome a ddi ti ona l functi ons are i ncl ude d i n th i s ta b tha t a re not use d i n a ny of
the sketches i n th i s book but a re c onveni ent if you wa nt to sl ow down or speed
up the robot, for exam ple with remote c ontrol . The l'loveSlowe r a nd l'love Fast
e r functi ons can be used to c om ma nd the robot to decrea se or i ncrea se speed:

Example 7-11. Functio ns to speed up or slow down the robot


void MoveSlowe r ( t n t decreMe n t )
{
Serial . p rint ( " Slower : " ) ;
tf( MoveSpeed >= s peed lncreMent + MIN_SPE ED)
MoveSpeed - = speedlncreMen t ;
else MoveSpeed = MIN_SPEED;
MoveSetSpeed ( MoveSpeed ) ;

void Movefaste r ( tnt tncreMe n t )


{
Serial . print ( " Faste r : " ) ;
MoveSpeed + = speed l n c reMent;
tf( MoveSpeed > 100)
MoveSpeed = 100 ;
MoveSetSpeed( MoveSpeed ) ;

int MoveGetState( )
{
retu rn MOVeState ;

// this ts the low level MoveMent state .


// tt will differ froM the coMMand state when the r obot ts avoiding obstacles
void changeMoveState( tnt newState)
{
tf( newState ! = MoveState)
{
Sertal . p rtnt( " Changtng Move state froM " ) ; Serial . p rint( state s [ MoveState ] ) ;
Serial . p rint( " to " ) ; Sertal . p rtntln( states [ newState ] ) ;
MoveState = newState ;
}
}

126
Functions to Encapsulate Robot Movements

The f'loveFaster function i ncrease s the current speed by a specified increment


and calls f'loveSetSpeed to m ake this the current speed. For e xam ple, f'lovefast
e r ( 1 0 ) ; wil l re sult i n the robot movi n g at85% speed if it was previously movi n g
a t 75%.
The f'loveSlower fu nction is sim i l ar but decrea se s rather than increases the
speed. Both functio n s check to en sure t h at the n ew speed i s val i d. If f'loveSlow
e r ( 20 ) was c al le d when the robot was mo vi n g at 85% spee d, the robot would
slow down to run at 65% s peed.
The movement function s also c all the fun ction changeMoveState to store the
c u rrent movement state. These states are defined i n the robotDefi.nes . h tab
(see Exa mple 6-9) a n d a re u sed to en able the robot to make deci sions with the
knowle dge of what it i s currently doing. For e xample, detectin g an obst acle i n
front c an be han dle d differently depen di n g on whether the robot i s movi n g
forwards o r backwards. The robot can check the current move state when it
encounters an object an d take action if the robot i s movi n g towards it but
i gnore obstacles that a re n ot in the di rection of move ment. Here are all the
move states:
enu� {MOV_LEFT , MOV_RIGHT , MOV_FORWAR D ,
MOV_BAC K , MOV_ROTATE , MOV_STOP} ;

If you are unfa miliar with enuf'I (enu merated lists), see "Code Style
(A bout the Code)" (pa gexii) in Prefa ce or a n o nline C o r C++ reference.

To assist debu g g i ng, each state has an associ ated te xt label that can be printed
to the seri al monitor to show what the robot sho u l d be doing.
canst c ha r* states ( ] = { " Left" , " Right " , " Forwa rd " ,
11
8 ack 11 ,
11
Rotate'' , ''Stop ' ' } ;

The move state defin e s are loc ated at the e n d of the robotDefi.nes . h tab.

Functions to Rotate the Robot


Rotation i s a com mon task as the robot i s e xplori n g an d movi n g to avo i d ob­
st acles. The robot s de scri be d in thi s book do not know the an g le they are facin g
or how m uch actu al movement re sult s from dri vin g the motors. Com man ds
to rotate the robot at particular a n g le a re i m plemente d by tim i n g h ow lon g to
turn the motors base d on data collecte d duri ng cal ibration. E xample 7- 1 2
shows the rotation functions from the Move tab:
Move Rotate
One motor forward, one re verse forthe du ration to rotate the robot to the
g i ven an g le. Po siti ve ang le s rotate clockwise, neg ati ve an g les counter­
clockwi se

Chapter 7 127
Functions to Encapsulate Robot Movements

Rotation Angle to Time


Fun ction u sed to calcula t e the dura tion to ro ta te the ro bot to a given a ng le
a t a given speed. Thi s fun ction i s t h e sam e a s l i sted i n "Load a nd R u n h el­
loRobo t.i no" ( page 88)
Calibrate Rotation Rate
Fun ction used for calibra tion-the robo t will a ttem pt to ro ta te a t a given
a n g le a t speed s from m i ni m u m speed up to 1 00% at i nterva ls of 1 0%. Thi s
fun ction i s t h e sam e a s li sted i n "Loa d a n d Run h elloRobot.ino" (pa g e 88)

Example 7-12. Functions to rotate the robot


void MoveRotate(int angle)
{
Serial . print ( " Rotating " ) ; Serial . p rintln ( a ngle ) ;
if( angle < 0 )
{
Serial . p rintln ( " ( left ) " ) ;
MotorReve r se( MOTOR_LEFT , MoveSpeed ) ;
Moto rFo rwa rd( MOTOR_R IGHT , MoveSpeed ) ;
a ngle = - a ngle; changeMoveState(MOV_ROTAT E ) ;
}
else i f ( a ngle > 0 )
{
Serial . println ( " ( right ) " ) ;
MotorForwa rd( MOTOR_LEFT , MoveSpeed ) ;
MotorReve r se( MOTOR_RIGHT , MoveSpeed ) ;
changeMoveState( MOV_ROTATE) ;
}
int MS = rotationAngleToTiMe ( angle , MoveSpeed ) ;
MovingDelay ( Ms ) ;
MoveB rake ( ) ;

/ / retu rn the tiMe in Milliseconds to turn the given angle at the given speed
long rotationAngleToTiMe ( int a ngle , int speed )
{
int fullRotationTiMe ; // tiMe to rotate 360 degrees at g iven s peed

if( speed < MIN_SPEED )


ret u r n 0; / / ignore speeds slower then the fi rst table entry

a ngle = a b s ( angle) ;

if( speed >= 100 )


fullRotationTiMe = rotationTiMe [ NBR_SPEEDS - 1 ] ; / / the last ent ry is 100%
else

int index = ( s peed - MI N_SPEED) / SPEED_TABL E_I NTERVAL ; // index into s peed and tiMe tables
int t0 = rota tionTiMe [ index ] ;
int t l = rotationTiMe[ index+ l ] ; / / tiMe o f the next higher speed
fullRotationTiMe = M a p ( s peed , speedTabl e [ index ] , s peedTable [ index+ l ] , t0 , tl ) ;

128
Functions to Encapsu late Robot M ovements

/ / Serial . p rint ( " index= " ) ; Serial . print( index ) ; Serial . print ( " , t0 = " ) ; Se rial . p rin t ( t0 ) ;
/ / Serial . p rint ( " , t l = " ) ; Serial . print( t l ) ;
}
// Serial . print( " full rotation ti!'le = " ) ; Serial . p rintln ( fu llRotationTil'le ) ;
long result = !'la p ( a ngle , 0 , 36 0 , 0 , fullRotationTil'le ) ;
return result ;

/ / rotate the robot frol'I MI N_SPEED to 100% inc reasing by SPEED_TAB LE_I NTERVAL
void calib rateRotationRate(int directio n , int angle )
{
Serial . print ( locationString [di rection ] ) ;
Seria l . println ( " calibration" ) ;
for ( int s peed = MIN_SPEED; speed <= 100 ; speed += SPE ED_TABLE_INTERVAL)
{
delay( 1000 ) ;
//blin kNul'lber ( speed/ 10) ;

if( di rection == DIR_LEFT )


{ / / rotate left
l'lotorReve rse(MOTOR_LEFT , speed ) ;
l'loto r Forwa r d ( MOTOR_RIGHT , speed ) ;
}
else if( di rection == DIR_RIGHT )
{ / / rotate right
l'IOto r Forwa r d ( MOTOR_LEFT , speed ) ;
l'IOto rReve rse(MOTOR_RIGHT , speed ) ;
}
else
Serial . p rintln ( " I nvalid d irection " ) ;

int til'le = rotationAngleToTil'le( a ngle , speed ) ;

Serial . print( locationSt ring [di rection ] ) ;


Serial . print( " : rotate " ) ; Serial . p ri n t ( a ngle ) ;
Serial . print( " deg rees a t s peed " ) ; Serial . p ri n t ( speed ) ;
Serial . print( " for " ) ; Serial . p ri n t ( til'le ) ;
Serial . println ( " l'ls " ) ;
delay( til'le ) ;
l'IOto rStop( MOTOR_LEFT ) ;
l'loto rStop( MOTOR_R I GHT ) ;
delay( 2000 ) ; / / two second delay between s peeds
}
}

Chapter 7 129
Functions to Encapsulate Robot Movements

Th e fTloveRotate fu ncti on will rot ate a robot by the gi ven angle. Neg ati ve ang l es
tu rn c ounter c l oc kwi se, positive angles turn c l ockwi se. R ot ation is ach i eved by
running th e motors in opposite d i recti on s (see "H ow Robots M ove" (pag e 5) ).

Higher-Level Movement Functions


Hig her l evel m ovement fu ncti ons work toget h er to provi de a si m p l e way to
instruct th e robot bri efly move aw ay from one obst acl e while ch ecki ng to see
if it need s to avoid another obst acle encountered w h i l e t aking evasi ve acti on.
Timed Move
M oves the robot in a specified di recti on for a specifi ed du r ati on.
Moving Delay
C h ecks for obst ac l es whi l e d el ayi ng for a specified peri od. U ses checkMove
fTlent ( ) fu nction in the Look mod u l e to see if an obst acle is d etected in the
cu rrent di recti on of movement.

Example 7-13. Higher level movement functions


/ ************* hig h level � o v e � ent functions **************** /

/ /Moves in the given di rection at the c u r rent speed for the given duration in Milliseconds
void tiMedMove (int direction , int d u ration )
{
Seria l . print( "HMed Move " ) ;
i f ( di rection == MOV_FORWARD ) {
Serial . p rintln ( " fo rwa rd " ) ;
MoveForward ( ) ;
}
else if(di rection == MOV_BACK)
Serial . println ( " back " ) ;
MoveBackwa rd( ) ;
}
else
Serial . println ( " ? " ) ;

MovingDelay(du ration ) ;
Moves top( ) ;

/ / check for obstacles while delaying the given duration i n MS


void MovingDelay( long duration)
{
long startTiMe = Millis ( ) ;
while( Millis ( ) - sta rtTiMe < duratio n )
// function in Look Module checks fo r obstacle in d irection of MOVeMent
if( checkMoveMen t ( ) == false ) {
if( MOVeState ! = MOV_ROTATE ) // rotate is only valid MOVeMent
{
Serial . p rintln ( " Stopping in Moving Delay ( ) " ) ;
Moves rake ( ) ;

130
Functions to Encapsulate Robot Movements

}
}

The ti.l'ledMove and l'lov"i.ngDe lay fun c tions work tog ether to provi de a si mp le
wa y to instr uc t the robo t bri efly mo ve awa y from a n obstacle. Beca use !'loving
De lay can c h ec k for obsta c les wh i le taking evasive ac tion, i t can a voi d b umping
into n ew obs tacles while mo ving awa y fro m a not her. Th e checkMovel'lent
fun c tion is implemen ted in th e Look module ( see "The Look Co de" ( pag e 1 49)).

Chapter 7 131
Tutorial: Introduction to
Sensors 8

Sensor information can be used by your robot to navigate and interact with
its environment. Sensors report on the world around them; measuring light,
distance, sound, movement, direction, temperature, pressure, or location. This
chapter describes how common sensors used with two wheeled and four
wheeled platforms work.
The first half of this chapter covers the primary sensors used in the chapters
that follow: IR reflective sensors and SONAR distance sensors. These are used
to determine if an object is near the robot. Reflective sensors detect nearby
objects and are used for line following and edge detection (determining if the
robot is near the edge of the surface it is moving on, such as the edge of a
table). Distance sensors are used to determine the distance to objects up to
ten feet away from the robot. The second half of the chapter covers other types
of sensors you can add to enable the robot to respond to distance, sound,
movement, or other stimuli. You should also have a look at Appendix D, Power
Sou rces which describes a very useful aspect to sense, the robot's battery volt­
age.

Hardware Discussed
QTR- JA refle cta nce sensors
Two are used for edge detection, but a third is required for line following.
Additional sensors are available from many internet shops that stock robot
parts, or direct from the manufacturer: http://www.pololu. co m/catalo g/
pro duct/958/
SONAR Dista nce Senso r
One is used to measure the distance to obstacles (Maker Shed product
code M KPXS).

133
Software

Maxbotix Ell distance sensor


This is an optional item that can be used to measure distance.
Sharp JR
This is an optional item that can be used to measure distance.
PIR (Passive Infrared) sensor
This is an optional item that can be used to activate the robot when it
detects the presence of a 'warm body' (Maker Shed product code: M KPX6 ).
Sound Sensor
This is an optional item that can activate the robot on a sound level, such
as a hand clap. (SparkFu n product code BOB-099 64 ).

Software
The chapter contains background information on sensors that will be added
to the robot in later chapters. The reflectance sensor code is from the sketches
introduced in Chapter 6 , Testing the Robot's Basic Functions. The Ping (Sonar
distance sensor) hardware and software is covered in Chapter1 0, Autonomous
Movemen t.

Infrared Reflectance Sensors


These sensors use reflected infrared light to detect the presence of a line for
line following, or the absence of a reflection for edge (cliff) detection.

Obstacle
IR
Reflects
Emitter I R beam

IR
Detector

Figure 8-1. Sensor using Infrared t o detect obstacles

The robot uses a function named irSensorDetect, shown in Example 8-1 to


return true if the light level has increased sufficiently above the ambient level
indicating that a nearby object is reflecting the IR beam.

134
Infrared Reflectance Sensors

Example 8-1. Detecting an obstacle that reflects light


con st byte NBR_SENSORS = 3; // this version only has left a nd right sensors
con st byte IR_S ENSOR [ NBR_SENSOR S ] = { 0 , 1 , 2 } ; / / analog pins for sensors

/ / retu rns true if an object is detected on the given sensor


/ / the sensor paraMeter i s the index into the sensor a r r ay
int i rSenso rDetect (int senso r )
{
boolean result = false ; // default value
int value = analogRead ( IR_S ENSOR [ sensor ] ) ; / / get I R light level
if( value <= irSenso rReflect [senso r ] ) {
result = true; / / obj ect detected ( lower value Means More reflection )
if( isDetected [ senso r ] == fals e ) { // only print on initial detection
Serial . p rint (location String [ senso r ] ) ;
Seri a l . println ( " object detected " ) ;
}
}
isDetected [ sensor] = resu l t ;
r e t u r n resul t ;

Sensor constants determine which sensor to use: SENSE_IR_LEFT for the left
sensor, S ENSE_IR_RIGHT for the right (these constants are defined in robotDe
fines . h (see "Making the Sketch Easy to Enhance" (page 99 )). The i. rSensor
Detect function uses the sensor constant to retrieve the analog pin number
stored in the I R_S ENSOR array. If the ana logRead value is less than a predeter­
mined threshold, the function returns t rue indicating that a reflection has
been detected. These functions use arrays instead of simple variables to store
pins and thresholds because arrays make it easy to extend the code to support
any number of sensors. To add a sensor, increase the NBR_S ENSORS constant
and add the sensors pin number to the list of pins in the IR_S ENSOR array.

The sensor voltage reduces with increased light, so lower readings


mean more reflectance. Therefore, the closer a reflecting object is to
the sensor, the lower the reading on the analog pin monitoring the
sensor.

Whereas i.rSensorDetect returns true when a reflection is detected, sometime


you want the opposite case-to return true if an edge (no reflection) is detec­
ted, as in Example 8-2. The i.r EdgeDetect provides this capability; it is used to
return true when an edge is detected. In other words, when the sensor is look-

Chapter 8 135
Infrared Reflectance Sensors

ing downwards, no reflection from the surface is detected because a dark ob­
ject is blocking the reflection or the nearest surface-probably the floor-is
many inches away! This effect is used in the examples from Chapter 6 to detect
when you've placed a dark object under the sensor.

Example 8-2. Detecting the absence of a reflection


boolean ir EdgeDetect ( int sens o r )
{
boolean result = false ; / / default value
int value = a nalogRead ( IR_SENSOR [ sensor ] ) ; / / get IR light level
tf( value >= irSensorEdge [ sensor ] ) {
result = t r u e ; // edge detected ( higher value Means less reflection )
if( isDetected [ senso r ] == false ) { / / only print on initial detection
Seria l . print( locationString [ senso r ] ) ;
Sertal . p rtntln ( " edge detected " ) ;
}
}
isDetected [ sensor] = result;
return result ;

The sensors need to be calibrated to take ambient light into account. Reflec­
tance sensors respond to sunlight and artificial light so a threshold is measured
with no object near the sensor. L evels above this threshold mean the light level
is above ambient, which indicates that a nearby object is reflecting the IR light
from the sensor. Ambient light calibration is done using the code shown i n
Example 8-3.

Example 8-3. Light calibration


// calib rate th resholds for aMbient light
void trSensorCalib rate( byte senso r )
{
tnt aMbient = analogRead ( IR_SENSOR [ senso r ] ) ; // get aMbient level
t rSensorAMbtent [ sensor ] = aMbten t ;
// precalculate t h e levels fo r object and edge detection
t r SensorReflect [ sensor ] ( aMbient * ( long ) ( 10 0 - i rReflectTh reshold ) ) / 100 ;
t rSensor Edge [ senso r ] = ( aMbient * (long ) ( 100+t r EdgeTh reshold ) ) / 100;

136
Sonar Distance Sensors

( l ong) is u sed in the calculation to prevent overflow. Valueslike 95000


ca nnot fit into a nArduino integer (max value is 32, 767) wh erea s a long
ca n store values up to 2, 147,483,647.

You may com ea cross code that perfo rm s this calculation u sing floating
point (af11b ient * 0 . 95). However, floating point requires m ore code
a nd memory tha n integer calculations.

This loads the am bient l i g ht level i n to the variable ar1b1.ent, c alcul a tes levels
for reflec tance detec tion (stored in the "i.rSensorReflect a rray) and levels for
e dge detec tion ( sto red in the "i.resens o r Edge array). The con stant "i.rReflect
Th reshold is the percentage differen ce in l i g ht to de tect a refle c ti n g obst acl e.
The con stan t -L r edge Th res hold i s the perc e nt diffe rence to detect an e dge. The
defa ult values for the se thre shol ds are 1 0% for reflection a n d 90% fo r e dge
detec tion.
Here is a n exam ple assum i n g the a mbient val ue from a nalog Rea d wa s 1 000
wi th "i.rReflectTh resho ld equal to 1 0 :
( 1000 * 9 0 ) / 1 0 0 =
90000 / 100 =
900

In t h i s exam ple, if the ambient read i n g wa s 1 000, the i rSe nso rReflect's thre sh­
o l d rea di n g fo r object detection i s 900, w hich i s 1 0% below the a mbient rea d­
i n g.

Sonar Distance Sensors


Soun d pul ses c an be use d to measure distan ce. The ti me it takes for a pul se to
bounce off an object a n d return to the sen so r i s proportional to the di sta n c e.

I ) }))
Outgoing Pulse


( ( ( ! < .....-
Reflected Pulse

Figure 8-2. Ping Sensor using SONAR to determine distance

Chapter 8 137
Sonar Distance Sensors

Th e speed of sound is 340 m eters per secon d, whi ch m ea n s it takes 29 mi cro­


seco nds for sound to travel 1 cen tim eter (th e reci procal of 340 m etres per
seco nd). To derive th e dista nce in cm, th e du ra ti on i s divi ded by 29. Th e dura­
tion i s the time for the sum of outg oing a n d reflected pul ses so the di sta n ce
to th e obj ect i s rri.croseconds / 29 / 2.
The pulse dura tion is mea su red usi ng the Arduino pulsel n functi.on. Thi s
retur ns th e a pulse durati on in mi croseconds, see h ttp://arduino.cc/en/Refer
ence/pulse/n.
Exam ple 8-4 shows th e code tha t uses th e Pi ng sensor to return th e di sta n ce
i n i nch es. You'll see this code i n a cti on i n Cha pter 1 0.

Example 8-4. The source code for the Ping sensor


/ *********************************
code for ping distance sen s o r
********************** ************ /

// Retu rns the dista nce in inches


/ / this ret u r n s 0 if no ping sensor is connected or the distance is g reater than a round 10 feet
int pingGetDistance(int pin g Pin )
{
// establish variables fo r du ration of the ping ,
// and the dista nce result in inches and centiMete r s :
long duration , CM;

II The PING ) ) ) is t riggered by a HIGH pulse of 2 o r More Microseconds .


// Give a short LOW pulse befo rehand to e n s u re a clean HIGH pulse :
pinMode( pingPin , OUTPUT ) ;
digitalWrite ( pingPin , LOW ) ;
delayMic rosecond s ( 2 ) ;
digitalWrite ( pingPin , HIGH ) ;
delayMic rosecon d s ( S ) ;
digitalWrite ( pingPin , LOW ) ;

pinMode( pingPin , INPUT ) ;


d u ration = pulsei n ( pingPin , HIGH , 20000 ) ; f l i f a pulse does not a r rive
I I i n 2 0 MS then the ping sensor
I f is not connected
if(du ration >=20000 )
ret u r n 0 ;

// convert the tiMe into a dista nce


CM = Microsecond sToCentiMeters ( d u ration ) ;
return ( cM * 10 ) I 25 ; II conve rt CM to inches

long MtcrosecondsToCen tiMete r s ( long Microseconds )


{
II The s peed of sound is 340 Mis or 29 Mic rosecond s per centiMeter .

138
Maxbotix EZl Sonar Distance Sensor

// The ping t ravels out and back , so to find the distance of the
// object we take half of the distance travelled .
return �icroseconds / 29 / 2 ;

The pi.ngGetDi.stance fun ction return s the dista nce in i n ches a s m ea su red with
a ping sen sor on the dig i ta l pin (pi.ngPi.n) pa ssed to the fun ction. The sou nd
pul se u sed to m ea sure t he di stan ce i s tri g gered by sen din g a di g ital pu lse that
is low fo r 2 m i crosecond s a nd hi g h for 5 m i crosecon ds. The pin m ode i s
cha n g ed from ou tput t o i n put a nd the pulse I n fun cti on i s u sed t o m ea su re
the respon se from the sen sor, which a rri ves a s an i n coming pulse width. The
formu la descri bed a t the beginning of thi s secti on i s u sed to con vert t his val u e
t o the distan ce.

Maxbotix EZl Sonar Distance Sensor


Exa m pl e 8-5 sh ows th e cod e for the Maxbotix EZ1 SONAR d i stan ce sen sor
(pi ctured in Fig u re 8-3).

Outgoing Pulse

II))}
(I! ' '
Reflected Pulse

Figure 8-3. Maxbotix Ell SONAR distance sensor

Example 8-5. Code for the El l sensor


/********************************
code for the EZ1 SONAR sensor
********************************* /
/ / retu rn distance using EZ1 connected to analog pin
int ezD1stanceAN( 1nt pin ) // using analog
{
const int bitsPer lnch ; 2 ; // each bit is 0.5 inch
int value ; analogRead (pin ) ;
int inches ; value / 2 ;
retu rn inches;

// retu rn distance using EZ1 connected using PW


int ezD1stancePW( 1nt pin ) //using digital pin
{
int value ; pulsel n ( pin , HIGH ) ; / / ti�eout can be added ( MAX_DISTANCE * 147L * 2 )

Chapter 8 139
Maxbotix EZl Sonar Distance Sensor

int CM = value / 58; // pulse width is 58 MS per CM


int inches = value / 147; // which is 147 MS per inch
retur n inches ;

The version using pul se width (ezDtstancePW ) will wait for o n e seco n d before
g i ving up if n o return pulse i s detected (for example, if t he sen sor i s di scon­
n ected). You can o ptionally set the m axim um ti me to wait for pu lsein; the
following example set stheti meo ut to t he duration n eeded for a pulse to travel
the m aximum di stance detectable by t he sen sor:
int value = pulse i n ( pin , HIGH, MAX_DISTANCE * 147L * 2 ) ;
// pulsein with tiMeout
You can use the analog i n put version (ezDtstanceAN), if you have a spare an alog
i n put pin, but if yo u only have digital pin s free, then use t he pulse width cod e
(ezDtstancePW) . The an alog version takes only as long as n eeded to measure
the voltag e so does no t need a timeout.
You can fin d more i nformation on thi s sen sor on the man ufa cturers web pag e:
http://www.maxb otix. com/Ultrasonic_Sensors/MB 1 0 1 O.htm

140
Sharp I R Distance Sensor

Sharp IR Distance Sensor


Example 8- 6 shows the code for the Sharp GP2Y0A02YK0F long range IR dis­
tance sensor (pictured in Figure 8- 4).

IR
Emitter

Figure 8-4. Sharp IR Distance Sensor

Example 8-6. Code for the Sharp JR sensor


/ *********************************
code for Sharp GP2Y0A02YK0F IR distance sensor
********************************** /
con st long refe renceMv = 5000 ; / / the reference voltage tn Mtlltvolts

int t rGetDtstance ( byte ptn)


{
tnt val = analogRead ( p t n ) ;
tnt MV = Map ( val , 0 , 1023 , 0 , referenceMv ) ;
/ / or :
/ / tnt MV = ( val , * referenceMv) / 1023 ;

tnt CM = MVToDt sta n ce ( MV) ;


return cM ;

/ / the following ts used to inte rpolate the distance froM a table


/ / table ent ries a re distances tn steps of 250 Mtlltvolts
con st tnt TABLE_ENTR IES = 1 1 ;
con st tnt ft rstEleMent = 250 ; / / ftrst entry ts 2 5 0 MV

Chapter 8 141
Proximity Sensor

con s t int INTERVAL = 250; / / Millivolts between each eleMent


static int dis tance [ TABLE_ENTRIES] = { 200 , 130 , 90 , 64 , 50 , 4 1 , 35 , 30 , 25 , 2 0 , 15 } ;

int MvToDistance( int MV)


{
if( MV < fi rst EleMent )
retu r n distance [ 0 ] ;
if( MV > INTERVAL * TABLE_ENTR I ES )
retu r n dista nce [ TABLE_ENTR IES - 1] ;
else

int index = MV / INTERVAL ; // highest table eleMen t <= MV value


int MV0 = index * INTERVAL; // MV value of this eleMent
int MV1 = MV0 + INTERVAL; // MV value of the next higher eleMent
int result = Map(MV , MV0 , MV1 , distance [ index - 1 ] , distance[index ] ) ;
result = Map( result , 0 , 200, 0 , 7 9 ) ; / / conve r t froM CM to inches
retu r n result;

You can fin d lots more inform ation o n thi s sen sor h ere: h ttp://www.societyo
frobots. com/sensors_sharpirrange.sh tml .

Proximity Sensor
A P I R (Passi ve I nfrared) sensor can be used to acti vate your ro bot when it d e­
tects th e presence of a nearby person, or even a do g or c at. Th e sensor ac ts
l i ke a swi tch th at sends a HIGH si g nal to an Arduino pi n when motion i s detected
(th ey work by detecti ng chang es in th e h eat radi ated from peo pl e or p ets).
Fi g ure 8-5 shows th e sen sor con nected to analog pi n 5, bu t you can use any
spare pin, such as A4 i nstead of AS.

142
Sound Sensor

To
o�:�:;• .=:::,,..:c -:,:--c=-----0-_ '"Uic.c-,-,-
0 0_0 1 ()--,
, ,....
0_0_0_0_0cc1 0
.,,,",--
'o'l() 0-0""'-
""U-
()
PQer 1 12 11 10 9 E 6 S -1 3 1 l 0
To
□□□00000
p1 ,c..._. e M 2 1 •
0e 0 0 0 0 □ □ □,
MJ M-1 e r

· ··- -- -- -- -- -- -- -- -- �..
Servo .

left
Motor

To
Battery left Right Center PIR Sensor

Figure 8-5. Pl R Sensor Connected to Analog Pin 5

The following loop code will spin the robot when movement is detected. If you
wan t you r robot to do this, replace the loop fun ction in the MyRobot ske tch
from "M aking the Sketch E asy to En han ce" (page 99) wi th the code shown i n
Example 8-7.

Example 8-7. Spinning the bot


voi.d loop ( )
{
Seri.al . pri.ntln ( " Wai.ti.ng to detect MoveMent froM PIR senso r " ) ;
pi.nMode(AS , I NPUT) ; I I confi.g ure the pi.n for i.nput
i.f( di.gi.talRead(AS) == HIGH )
{
cali.brateRotati.onRate( D IR_LEF T , 360) ; II spi.n robot CCW one rotati.on
}
}

Sound Sensor
You can use a sou n d sensor to s tart or stop your robot in response to sou n d,
for example a hand clap or whis tle. You will need a mi crophone wi th an am­
plifier, for example, the BOB-09964 breakout board from SparkFun. Figure 8-6
shows the board c onnected to an alog pin 4.

Chapter 8 143
Sound Sensor

To

:::::---o-o-o-ocoiic,oiii"aio11r;ooo--o-o-oiiio,ciioT,1bif1T10lio10-o"
�:�;:: =:::i:::iii.:�-=---o
To
Servo
0 ARef nd 13 12 11 10 9
D □00000 00000□ □□
U• ed p,�

'• . .
e Ml S2 51 e
B

e M3 M◄ e M2
. · - - - - - - - - - ..
- - - - - --- - ,
7 6 5 ◄ 3 2 1 0

Lett
Motor

Right
Motor

al
O shield for arduino

�� u;� O D D □ □
J� AST 3v 5v Grd U1
� 00000

To
Battery Left Right Center
Reflectance Sensors

Figure 8-6. Sound Sensor Connected to Analog Pin 4

The code that follows is the main tab from the r1y Ro botS o u n d sketch available
in the download for this book. Noise level above a threshold will drive the robot
forward. The robot stops when the level drops below the threshold. If you need
to change the sensitivity, experiment with higher or lower values for the
threshold. Example 8- 8 shows the code for the main tab.

Example 8-8. Soun d sen sor code


/ * ***************** * ***************************************
MyRobotSound . tno

Robot Moves when a sound level exceeds a threshold


Based on Recipe 6 . 7 froM Ardutno Cookbook

Copy rig ht Michael Ma rgolis 20 J uly 2012

*********************************************************** /

#include <AFMotor . h> // adafrutt Moto r shield library


#include " RobotMotor . h " / / 2wd o r 4wd Motor Hbrary

#incl ude " robotDeHnes . h " / / global defines

canst int a nalog l n Ptn = 5 ; / / analog pin the sensor t s connected to

144
Sound Sensor

con st int MiddleValue = 512; / /the Middle of the range of analog values
con s t int nuMbe rOfSaMples = 128 ; / / how Many readings will be taken each tiMe

i n t s aMple ; / /the value read froM Microphone each tiMe


long signal ; / / the reading once you have reMoved DC offset
long ave rageReading; / /the average of that loop of readings

long runningAve rage=0 ; //the running average of calculated values


con st int aver agedOver= 1 6 ; / /how quickly new values affect running average
/ / bigger n uMbers Mean slowe r

con s t int th reshold=400 ; //at what level the robot will Move

int s peed = 50 ;

// Setup runs at startup and is used configure pins a nd init systeM variables
void setup ( )
{
Seria l . begin ( 9600) ;
blinkNuMbe r ( S ) ; // open po rt while flashing . Needed for Leon a rdo only

MotorBeg i n (MOTOR_L EFT) ;


MotorBeg i n ( MOTOR_R IGHT ) ;

void loop( )
{
i n t level = getSoundLevel ( ) ;
i f ( level > threshold ) / / i s level More than the th reshold
{
Motor Forwa rd (MOTOR_LEFT , s peed ) ;
Motor Forwa rd (MOTOR_RIGHT , speed ) ;
} else
{
MotorStop( MOTOR_LEFT ) ;
MotorStop( MOTOR_RIGHT) ;

/ / fu nction to indicate n uMbers by flashing the built - i n LED


void blinkNuMbe r( byte nuMbe r ) {
pinMode ( LED_PI N , OUTPUT ) ; // enable the L ED pin for output
while ( n uMbe r - - ) {
digitalWrite ( LED_PIN , H I GH ) ; delay ( 100 ) ;
digitalWrite ( LED_PIN , LOW) ; delay(400 ) ;

int getSou nd Level ( )


{
long suMOfSq uares = 0;
for (int i=0 ; i<nuMbe rOfSaMples ; i++) { //take Ma ny readings and average theM
s aMple = a nalogRead ( a nalog l n Pin ) ; //take a reading
signal = ( saMple - MiddleValue ) ; //work out its offset froM the center

Chapter 8 145
Arduino Cookbook

signal *= signal ; //square it to Make all values positive


s uMOfSq uares += signal ; //add to the total
}
averageReading = suMOfSqu a res/nuMberOfSaMples ; //calculate running ave r age
r u n ningAve rage= ( ( ( averagedOve r - l ) * r u nningAve rage) +averageReading ) / averagedOve r ;

return r u nningAverage;

See the Arduino Cookbook if you want a detailed description of how this code
works.

Arduino Cookbook
For descriptions of how to use lots of additional sensors with Arduino, see:
Arduino Cookbook by Michael Margolis (O'Reilly).

146
Modifying the Robot to
React to Edges and Lines

This chapter covers techniques that enable your robot to use sensors to gain
awareness of its environment. Using reflectance sensors, the robot will gain
the ability to follow lines or to avoid falling off the edge of the surface it is on.
Information from the sensors is abstracted so that the robot logic has a single
consistent interface and can easily be enhanced to support other sensors. The
physical mounting of the sensors varies with different platforms: see Chapter4,
Building th e Four-Wheeled M obile Platform if you have the 4WD chassis, Chap­
ter 3, Building th e Two-Wh eeled M obile Platfor m if you have the 2WD chassis.

Hardware Required
• Two reflectance sensors are used for edge detection and a third is needed
for l ine following. Although you can use the stripboard mount (for the
three line following sensors) discussed in Chapter 2 to experiment with
edge detection, the robot will perform the edge detection task best with
the sensors further apart (the stripboard approach is best for line follow­
ing). If the sensors are close together, the robot can have difficulty deter­
mining the best angle to turn when an edge is encountered.

See Chapter 3, Building the Two-Wh eeled M obile Platform for de­
tails of mounting thes e sens ors on the 2WD chassis and Chapter 4,
Building the Four-Wheeled M obile Platform for the 4WD chassis.
The prin ciples of reflectan ce sens ors are covered in "Infrared Re­
flectance Sensors" (page 1 34) in Chapter 8, Tutorial: In troduction
to Sens ors.

147
S ketches Used in This Chapter

• A reflective surface with non-reflective edges for the edge detection


sketch (see Figure 9-2. You can use a large sheet of plain white paper with
the edges marked using a black marker pen or black electrical tape. The
border should be around 3/4 of in inch thick or so. The optimal surface
would be white, but with sufficient friction that your robot won't slip. L in­
ing paper, often sold as unpasted wall liner, is a great surface. It's designed
to provide an even surface or wallpapering or painting, but with enough
texture that makes it great for racing robots.
• A reflective surface with a non-reflective line approximately 3/4 inch wide,
see Figure 9 -3. If your surface is at least a couple of feet wide, you can use
the same course for edge detection and line following. The sketches have
been tested using a three foot length of 27 inch wide lining paper.

Sketches Used in This Chapter


l'lyRo bot Edge . i. no
The robot will move about in an area bounded by a non-reflective surface
(for example, a large sheet of white paper placed on a non-reflective sur­
face. Most surfaces that reflect visible light will reflect infrared from the
sensor).
l'lyRo botli.ne . i. no
This repositions the sensors used in l'lyRobo t Edge . i. n o to allow the robot
to follow black lines painted on or taped to a white surface. The only
change to the tab code is support for the center sensor. A variant of this
sketch that sends data over serial for display on an external serial device
is named l'lyRobot L i.neDi.sp lay and is included in the example code down­
load (see "How to Contact Us" (page xv)).
Figure 9 - 1 shows the organization of the modules for this chapter.

myRobotMove robotDefi nes lrSensors Move

-
myRobotEdge Look
(Obstacle H RobotMotor
Library
detection)

myRobotline
��
sensor
added �
... Robot Motor
Library

Figure 9-1. myRobotfdge and myRobotLine Sketches

148
The Look Code

T he Look Code
The code to look for a n obs ta c l e a nd ret urn t r ue if detected is i mplem ented
i n the function nam ed lookFo rObstac le. You saw thi s func tion i n the main ta b
of the sketch descri bed i n Chap ter 6, Testing the Robot's Basic Functions. Beca us e
this c ode wi ll be extended i n this a nd later cha pters to s upp ort a dditiona l
sensors, it makes sense t o extrac t t h i s code into its own tab. Th e downloa d
c ode for a ll sketches i ntrod uced from here on i n ha ve a ta b nam ed Look tha t
c onta i ns the code s hown i n Exam ple 9- 1 .

Example 9-1. Code for the Look tab


/ **********************
code to look for obstacles
********************** /

void lookBeg in ( )
{
i rSensorBegi n ( ) ; / / initialize senso r s

/ / retu rns t r u e if t h e given obstacle is detected


boolean lookFo rObstacle ( i nt obstacle)
{
switc h (obstacle ) {
case OBST_FRONT_EDG E : ret u r n irEdgeDetect( SENSE_IR_LEFT) && i r EdgeDetec t ( S ENSE_IR_R I GHT ) ;
case OBST_LEFT_EDG E : ret u r n irEdgeDetect( SENSE_IR_LEFT) ;
case OBST_RIGHT_EDG E : ret u r n irEdgeDetect( SENSE_IR_RIGHT ) ;
}
return false;

/ / fu nction to check if robot can continue Moving when taking evasive action
// retu rns true if robot is not blocked when Moving to avoid obstacles
/ / this ' placeholde r ' ve r sion always returns true
boolean checkMoveMent ( )
{
return t r u e ;

As m entioned i n Chapter 6, Testing the Robot's Basic Functions, the lookForOb


stac le func ti on ena bl es yo u to enq ui re if a n o bs tacle is d etec ted a nd wil l return
true if s o. The case s ta tem ent ( s ee http://arduino.cc/en/Reference/SwitchCase)
tries to matc h the obs tac le vari a bl e wi th on e of th e obs ta c l e c onsta nts (d e­
fi ned i n robotDefi.nes . h ) . If th ere is a ma tch, th e i. rEdgeDetect fu ncti on is

Chapter 9 149
Edge Detection

called with relevant sensor and this will return true if an object is detected on
that sensor. If no object is detected, the function returns 0BST_N0NE. The look
functionality can be expanded by adding code to the case statement and call­
ing appropriate sensor functions, as you will see later in this chapter.
But first, let's use the existing functionality to give the robot the ability to follow
lines and detect edges.

Edge Detection
Edge detection is one of the easier behaviors to understand and program. The
robot moves until it encounters an edge; it should then change direction to
avoid moving over the edge. Edges are detected by using reflectance sensors
(see: Chapter 8, Tutorial: In troduction to Sensors). Typically, the edge is an area
that does not reflect, for example the edge of a table.
In the sketch that follows, the robot will remain within a reflective surface (for
example, a large white sheet of paper) that is bounded by a black line. Black
electrical tape (3/4 inch or wider) works well but a black line of similar width
drawn with magic marker or paint can also work as the 'edge'. To avoid dam­
aging your robot, an actual table is not recommended for early experiments
until you are sure you have everything working correctly.
Figure 9 -2 shows how the robot responds to moving over an edge. In panel 1,
the sensors do not detect an edge so the robot moves forward. In panel 2, the
left sensor moves off the reflective surface so the robot stops and rotates 1 20
degrees. In panel 3, the robot completes its rotation; panel 4, shows the robot
moving forward again.

150
Edge Detection

Figure 9-2. Robot stays within the reflective area

Example 9-2. Main sketch code for edge detection


/******************************************************************************
MyRobotEdge . i.no

Robot sketch to Mo ve wi.thi.n a rea borde red by a non- reflecti.ve li.ne

Mi.chael Ma rgoli.s 7 July 2012


*************************** * * *************************************************/

Chapter 9 151
Edge Detection

#include <AFMoto r . h> II adafruit Moto r shield library


#include " RobotMotor . h " II 2wd o r 4wd Motor library
#include " robotDefines . h " II these we re the global defines froM MyRobot

I ll Setup runs at startup and is u sed config u r e pins and init systeM variables
void setup ( )
{
Seria l . begin ( 9600 ) ;
blinkNuMbe r ( S ) ; II open port while flashing . Needed for Leon ardo only

lookBegin ( ) ; I ll added Look tab


MoveBegi n ( ) ; I ll added Move tab
Seria l . println ( " Ready" ) ;

void loop ( )
{
I l l code for roaMing a round and avoiding obstacles
if( lookForObstacle ( OBST_FRONT_EDGE) == t r u e )
{
Serial . println ( " both sensors detected edge" ) ;
tiMedMove ( MOV_BACK , 300 ) ;
MoveRotate ( 120 ) ;
while ( lookFo rObstacle( OBST_FRONT_EDGE ) == t r ue )
MoveStop( ) ; II stop Moto rs if still ove r cliff
}
else if( lookForObstacle (OBST_LEFT_EDGE ) == t r u e )
{
Serial . println ( " left sensor detected edge" ) ;
tiMedMove ( MOV_BACK, 100 ) ;
MoveRotate ( 30 ) ;
}
else if( lookForObstacle (OBST_R IGHT_EDGE) = = true)
{
Serial . printl n ( " right sensor detected edge" ) ;
tiMedMove ( MOV_BACK, 100 ) ;
MoveRotate( - 30 ) ;
}
else

MoveSetSpeed (MIN_SPEED ) ;
Moveforwa r d ( ) ;
}
}

II fu nction to indicate nuMbers by fla shing the buil t - i n LED


void blinkNuMbe r( byte nuMbe r ) {
pi nMode ( LED_PIN , OUTPUT) ; II enable the LED pin for output
while ( nuMbe r - - ) {
digitalWrite ( LED_PI N , HIGH ) ; delay ( 1 00 ) ;

152
Edge Detection

di.gi.talWri.te ( LED_PIN , LOW) ; delay(400 ) ;


}

The code fo r thi s sketch is derive d from the m y Ro botMove ske tch di scussed
i n C hapter 7, Controlling Sp eed and Direction . You ca n downloa d the exam ple
code, loca te m y RobotEdge, open the sketch a nd uploa d it to the robot. Or yo u
ca n de rive the ske tch yourself:

1. Ope n the m y RobotMove sketch i n the exa mple code a nd do a Save As a nd


name i t myRobotE dge.
2. Crea te the Look ta b.
3. Loca te a nd move the two fu nctions at the e nd of the mai n ta b sta rti ng
from the comment "code to look for obsta cles" i nto the Look ta b. Thi s code
i s liste d in the section: "The Look Code" (page 1 49).
4. Repla ce the m a i n sketch code wi th the code li ste d here: Example 9-2.
5. Compi le a nd uploa d the code

Pla ce the robot with i n the bou nde d su rfa ce a nd swi tch the power o n (the ro bot
calibra tes the sensors afte r i t i s swi tched o n so a l l the se nsors sho ul d be ove r
the reflective a rea). After a sho rt delay the ro bo t wil l move fo rwa rd unti l i t
detects a no n-reflective e dge.
The loop code checks if a n edge i s detecte d di rectly ahea d wi th bo th senso rs
(OBST_FRONT_EDGE), o r o n the left (OBST_LEFT_EDGE) or ri g ht (OBST_RI GHT_EDGE).
If the e dge wa s a hea d, the ro bot backs awa y for 0.3 secon ds, rota tes 1 20 de­
g rees a nd then moves fo rwa rd a ga i n. If the e dge wa s to the si de, the robo t
turns 30 deg rees awa y from tha t si de a nd then moves fo rwa rd. Feel free to
experiment with the a ng le s to get a behaviour tha t sui ts the a rea you have
defi ne d fo r conta i ni ng you r ro bo t.

Is Your Robot Not Moving Right?


If your robot is not rotating enough or too much I f the robot does not detect the edge, you can make
when attempting to move away from an edge, you it more sensitive by reducing the value of i. r E
may need to calibrate rotation rates; see "Controlling dgeThreshol d in the lrSensors tab.
Motor Speed" (page 1 09). If the robot 'stutters' in-
stead of turning, try increasing the speed by chang-
ing the loop code from l'love Set
Speed( MIN_SPEED ) ; to l'loveSetSpeed (MIN_SPEED
+10) ; .

Chapter 9 153
Line Fol lowing

Line Following
L i ne following i s a cla ssic ta sk for a robot. The robot u ses sensor s to det erm ine
its positi on i n relation to a li ne and follow s t hi s li ne by movi ng to keep its
sensors centered above the lin e. Fig ure 9-3 show s a robot m ovi ng a rou nd a
tra ck ma rked with a bla ck li ne on a whi te surfa ce.

Figure 9-3. Robot follows a black line on a white surface

I n Pa nel 1 , the robot i s a pproachi ng a corner but i s sti l l centered over t he l i ne


- t he motors are both ru nni ng at the same speed (i ndi cated by theequa l length
a rrow s), a nd the robot moves straig ht a hea d. The robot ha s reached the left

154
Line Following

ha nd cur ve in panel 2-the ri g ht motor s peed is i ncreased, the l eft slowed to


turn the robot to the ri g ht. Panel 3 shows the ro bot com pletin g t he turn. I n
Pa nel 4, the robot is about t o reach a c urve to t he left w he re i t will continue to
a djust motor s peeds to kee p t he sensors ove r the li ne.
The i ll ustrations that follow show what ha ppens in more detai l. Fi gure 9-4
shows the location of t he sensor with res pect to the line when the robot i s
centere d. The left a n d ri g ht sensors are a bove t he reflect i ve s urface. Lots of
l i g ht will reflec t bac k to the sensor a n d the a nalogRead val ues a re low. The
center sensor is a bove the black line so has l ittle reflecte d l i g ht, causing the
rea ding to be hi g h. The difference i n rea di n gs be tween left a n d right i n dica tes
drift a n d is close to zero so both motors wi ll be dri ven at the same spee d-the
robot moves stra i g ht a hea d. Yo u ca n rea d about how to dis pla y s ketch data i n
rea l t i me i n "Seei n g S ketc h Da ta" (pa g e 1 60).

�:�· ·ri
0 ,..

Righi

Drift

Figure 9-4. Robot centered on black line

Fi g ure 9-5 shows t he robot to the left of the l i ne because the line is curvi n g to
the ri g ht. The left sensor detects maximum reflection (the a n a logRead value is
low). As the center sensor moves towards the e dge of the l i ne, the reflection
i ncreases (decreas i ng the a n a logRead val ue). The rig ht sensor moves towards
the li ne so its rea di ng i ncreases. The drift (the difference between t he left a n d
ri g ht) is positi ve s o the left motor s peeds u p a n d t he ri g ht motor slows down
-the robot turns to the ri g ht.

Chapter 9 155
Line Following

0 "'"'

r
�:�le r ri
Righi

Dnft

Figure 9-5. Robot off to left of line

Figure 9- 6 shows the robot to the right of the line because the line is curving
to the left. The right sensor detects maximum reflection (the a n a logRead value
is low). The reading from the center sensor increases as it moves towards the
edge of the line. The left sensor moves towards the line so its reading increases.
The drift is negative so the left motor slows down and the right motor speeds
up-the robot turns to the left.

0 1000

�::1., r,
Righi

Drift .,

Figure 9-6. Robot off to right of line

For the robot to successfully follow a curvy line, the movement must be re­
sponsive enough to make sharp turns but not so responsive that it zigs and
zags its way along even straight lines. Tuning the software to get this just right
requires experimentation and patience. The code that follows uses the differ­
ence value between the left and right sensors to adjust the differential motor
speed. The preceding figures display the relative signal levels from the sensors
and the difference value is indicated as 'Drift'. Sensitivity is controlled by map­
ping the drift value to the actual motor differential speed.

156
Line Following

Example 9-3 shows the line sense code that calculates the drift value (you'll
see it again in a moment when you see the complete listing for the sketch):

Example 9-3. L ine se nse code for calcu lating drift


/ / returns d rift - 0 if over line , Minus value if left , plus if right
int HneSense ( )
{
int leftVal = analogRea d ( S ENSE_IR_LEFT ) ;
int centerVal = analogRea d ( SENSE_IR_CENTER ) ;
int rightVal = analogRead ( S ENSE_IR_RIGHT ) ;

int leftSense = cente rVal - leftVal ;


int rightSense = rightVal - centerVa l ;
i n t d rift = rightVal - leftVa l ;
return d r H t ;

The drift and desired speed are passed to the l i.n e Fo ll o w function to drive the
robot. To adjust the motor's sensitivity, drift is divided by a 'damping' factor -
the higher the factor, the less sensitive to drift. Decrease the damping if you
need to make the robot more sensitive, for example, if it is not turning fast
enough to follow sharp bends. Increase the damping if the robot is unneces­
sarily zig-zagging on straight lines. The drift value is subtracted from the speed
for the left motor and added to the speed of the right motor to provide a
differential speed proportional to drift. The Arduino c o n s t r a i n function is used
to ensure the values remain within the valid range for speed (0 to 100 %).
Depending on the radius of you r bends, you may not be able to completely
eliminate the zig-zags.
int line Follow(int d rift , int s peed )
{
int leftSpeed con strain ( speed - ( d r ift / daMping ) , 0, 100 ) ;
int rightSpeed con strain ( speed + ( d r ift / daMping ) , 0 , 100 ) ;

Moto r Forwa r d ( MOTOR_LEFT , leftSpeed ) ;


Moto r Forward (MOTOR_RIGHT , rightSpeed ) ;
}

Example 9-4. Complete listing for code in the myRobotL ine main tab
/ ******************************************************************************
MyRobotlfoe . ino

Robot sketch to follow lines

Michael Ma rgolis 7 J uly 2012


****************************************************************************** /

Chapter 9 157
Line Fol lowing

#include <AFMoto r . h> // adafruit Moto r shield library


#include " RobotMotor . h " / / 2wd o r 4wd Moto r library

#include " robotDefines . h " / / these we re the global defines froM MyRobot

int speed = MIN_SPEED ; // speed in percent when Moving along a straight line

/ / / Setup runs at startup and is used config u re pins and init systeM variables
void setup ( )
{
Seria l . begin ( 9600 ) ;
blinkNuMbe r ( S ) ; // open po r t while flashing . Needed for Leon a rdo only

lookBegi n ( ) ; /// added Look tab


MoveBegin ( ) ; / / / added Move tab
lineSenseBegin( ) ; / / i nitialize sensors
Seria l . println ( " Ready " ) ;

void loop ( )
{
int d r ift = lineSense( ) ;
linefollow( d r ift , speed ) ;

/ / function to indicate n uMbers by fla shing the built - i n LED


void blinkNuMbe r ( byte nuMbe r ) {
pi nMode ( LED_PIN , OUTPUT ) ; // enable the LED pin for output
while ( n uMbe r - - ) {
digitalWrite ( LED_PI N , HIGH ) ; delay ( 1 00 ) ;
digitalWrite ( LED_PI N , LOW) ; delay(400 ) ;

/ ****************************
Line Sensor code
**************************** /

int daMping = 5 ; / / 1 is Most sensitive , range 1 to 1023 )

void lineSen seBeg i n ( )


{

/ / returns d r ift - 0 if over line , Minus value if left , plu s if right


int HneSen se( )
{
int leftVal = an alogRead ( S ENSE_IR_LEFT) ;
int cente rVal = analogRea d ( SENSE_IR_CENTER ) ;
int rightVal = analogRead ( SENSE_I R_RI GHT ) ;

int leftSense = centerVal leftVal;


int rightSense = rig htVal centerVa l ;

158
Line Following

int d rift = rightVal - leftVal ;


return d rift ;

int line Follow ( int d rift , int speed )


{
int leftSpeed constr a i n ( s peed - ( d r ift / daMping ) , 0 , 100 ) ;
int rightSpeed constrain( s peed + ( d r ift / daMping ) , 0 , 100 ) ;

MotorForwa r d ( MOTOR_LEFT , leftSpeed ) ;


Motor Forwa r d ( MOTOR_RIGHT , rightSpeed ) ;

The code for this sketch is derived from the myRobotEdge sketch discussed
earlier in this chapter. You can download the example code, locate myRobot­
L ine, open the sketch and upload it to the robot. Or you can derive the sketch
yourself:

1 . Open the myRobotEdge sketch in the example code and do a Save As and
name it myRobotline.
2. L ocate the defines for locations of sensors in the robotDefines tab and add
the center sensor following the defines for the left and right sensors: con st
1nt SENSE_IR_CENTER = 2 ; .
3 . Replace the main sketch code with the code listed here: Example 9-4.
4 . Compile and upload the code

Place the robot on the surface with the center sensor above the line and switch
the power on. After a short delay the robot will move forward and track the
line. The robots ability to follow the line depends on many factors:

• L ine thickness - the optimum thickness depends on the spacing of the


sensors. 3/4 inch works well with the robot built as described but you can
experiment with different line widths and different sensor spacing.
• Sensor height above surface - the sensors are less sensitive when further
from the surface- try using spacers to move the sensors closer to the sur­
face.
• Speed - too slow and the robot may not have enough torque, too fast and
the robot will overshoot the line. Try running ata speed around 10% above
minimum speed if the robot appears to be sluggish- in the top of the main
tab, change the code to : 1nt speed = MIN_SPEED+10;.

Chapter 9 159
Seeing Sketch Data

• Robot over sensitive - if the robot follows the line but zig- zags excessively ,
increase the damping value in the line sensor code in the main tab. Try
larger values until you find a range that works. Note that you may need a
different damping value if you change the speed.
• Robot not sensitive enough - if the robot drifts off the line, decrease the
damping value in the line sensor code in the main tab. Try smaller values
until you find a range that works. Note that you may need a different
damping value if you change the speed.

Seeing Sketch Data


Viewing the values of variables in real time makes it much easier to tune or
debug your code. You can view values printed to the serial port on the Serial
Monitor, but that can be difficult to read if these values are changing quickly.
Appendix C describes how to use a Processing sketch to display data as bar
charts, similar to the that shown earlier in this chapter (see Figure 9-4).

Iii ArduinoDataDisplay Id, 11..£1.,1

Arduino Data (C0M7)

I 88

t===:::::
Left Une ===:J (0-1 0:'.,

b
Center line 1-------------� (0·1 0, 680

Rioht llne (0 -1 0:'1\ 1 44

Drift

Len Motor

Right Molor
::::===================�=::::
=================�======:::::
(· 1 013•1 0,3) 1 25

(0·1 00)

(0·1 00)
55

68

(0 ·1 024) 0

(0•1 0'4) 0

10 (0•1 0,4) 0
11 (0·1 0,4) 0

12 (0·1 0,4) 0

Figure 9-7. Arduino Data Displayed i n Processing

Here is how the line following sketch should be modified to display the sensor
value:
Add the DataDisplay tab to the sketch (the myRobotlineDisplay sketch in the
example code download ("How to Contact Us" (page xv)) has this tab added
as well as all the other code changes that follow).

160
Seeing Sketch Data

In the main sketch, add constants identifying the list of items to be displayed,
labels for each item, and the minimum and maximum values. Example 9 -5
shows the constants used to produce the display in Figure 9- 7.

Example 9-5. Constan ts for display labels


enuM { DATA_st a r t , DATA_LEFT , DATA_CENTER , DATA_RIGHT ,
DATA_DR I F T , DATA_L_S PEED , DATA_R_SP EED , DATA_nb r i teMs } ;

cha r * labels [ ] =
{ 11 ", " Left Li.ne " , " Center Li.ne " , "Ri.ght Li.ne " ," D r i. ft " , " Left Speed " , " Ri.ght Speed " } ;

i.nt Mi.nRange [ J
{0 , 0, 0, 0, - 1023 , 0, 0} ;

i.nt MaxRange [ J
{0 , 1023 , 102 3 , 1023 , 1023 , 100 , 100} ;

Add the function call shown in Example 9 -6 to setup ( ) .

Example 9-6. Adding a call to begin the data display


dataDi.splayBegi. n ( DATA_n briteMs , label s , Mi.nRange , MaxRange ) ;

You can then call the send Data function to send the values you want to display.
Example 9 -7 shows the l i.neSense ( ) function updated to send sensor data.

Example 9-7. lineSense now sending sensor data


/ / returns d ri.ft - 0 i.f over li.ne , Mi.nus value i.f left , plus i.f ri.ght
i.nt l i.neSense ( )
{
i.nt leftVal = analogRea d ( S ENS E_IR_LEFT) ;
i.nt cente rVal = analogRea d ( SENSE_IR_CENTER ) ;
i.nt ri.ghtVal = a nalogRead ( SENSE_IR_RIGHT ) ;

sendData ( DATA_L EFT , leftVa l ) ; / / send left sensor value


sendData ( DATA_C ENTER , cen terVal) ; / / send center sensor value
sendData ( DATA_RIGHT , ri.ghtVal ) ; // send ri.ght sensor values

i.nt leftSense = cente rVal - leftVal ;


i.nt ri.ghtSense = ri.ghtVal - centerVa l ;
i.nt d ri.ft = ri.ghtVal - leftVal ;

Chapter 9 161
Seeing Sketch Data

sendData ( DATA_DRIFT , d rift ) ; / / send d rift sensor values

return d r Ht ;

M otor sp eed can b e di splayed by addi ng c al ls t o sendData i n the l "i. n e F o l low


fu ncti on as shown i n Example 9-8.

Example 9-8. Adding support for displaying motor speed


int line Follow ( in t d rift , int s peed )
{
int leftSpeed constrain ( s peed ( d rift / daMping ) , 0, 100) ;
int rightSpeed constrain ( s peed + ( d r ift / daMping ) , 0 , 100) ;

sendData ( DATA_L_SPEED , leftSpeed ) ; / / send left Mot o r s peed


sendData ( DATA_R_SPEED , rig h tSpeed ) ; // send right Motor s peed

Motor Forwa r d ( MOTOR_LEFT , leftSpeed ) ;


MotorForwa r d ( MOTOR_RIGHT , rightS peed ) ;
}

162
Autonomous Movement

This ch apter descri b es how to use a distanc e sens or to en able the rob ot to see
a n d av oi d obstacles as i t m oves a rou nd. The fi rst sketch, nam ed l"lyRobotWan
der, drives the rob ot forward, and if i t detec t s an ob stacle, it stops and rotates
th e rob ot to try and fin d a clear path to m ov e forward. Anoth er sketch, n amed
l"lyRobotScan, adds a serv o that can rotate the sens or s o the rob ot can look left
an d ri g ht with out h avi ng to twist itself around.

Hardware Required
• Ping distance sen sor from Parall ax; see "S onar Distance S ens ors" ( pag e
1 37) in Cha pter 8, Tutorial: Introduction to Sen sors.
• Servo requi red for myR ob otScan; see "S on ar Dist ance Sensors" ( page 1 37)
in Chapter 8, Tutorial: Introduction to Sensors.

C onne ct th e Ping sensor an d servo the ri g h t way a round; the black wires
(g round) go n earest the pin mark ed -, th e whi te (or li ghter col or) si g n al wire
g oes nearest the pin m arke d S (Fi g ure 1 0- 1 ).

-
To
Distance
0
D1qpal i 0 lCi,!_tal I
Sensor 00000000 00000000
AA�d 13 12 11 10 9 8 7 6 5 1 3 2 1 A
□ □ □ 0 0Ml 0S2 0,1 0• 0 0 0 0 0 □ □ □1
To :;; - +5 O Used p,ns�

·- - ·-· • ·---·- .
· · · - - •- - - - - -• �M3 Mi e M2

(0lC
0
Servo '•

2 servos �

Figure 10-1. Ping sensor and servo plug into pins on the motor shield

163
Sketches Used in This Chapter

Sketches Used in This Chapter


MyRobotWander . ino
U se s a SONA R di sta nce sen sor (the Ping sensor) to ena ble the robot to see
a n d a voi d ob sta cle s a s i t wa nders around. #defines are adde d for fron t
a n d rear ob sta cle s (onl y the fron t i s im plemen ted i n the sketch), the l ook
mod u l e h a s added support for d i stan ce sen sing. Thi s sketch i n troduces a
new ta b, name d Di sta nce, whi ch con ta i ns the Ping sen sor code that you
originally saw in "S onar Di sta n ce S ensor s" ( page 1 37).
MyRobotSca n . ino
Has the se nsor m ounted on a servo so it can sca n i n depen dentl y of robot
m ovemen t. Thi s code i s si milar to MyrobotWande r wi th the Look m odule
enha nced to su ppor t control of th e ser vo to l o ok a rou nd. A new m odul e
nam ed softS ervo i s added fo r ser vo control.

The Distance tab's code is not listed in this chapter, but it is included in
the examp le code (see "How to Contact Us" (page xv) for information
on downloading the exam ple code).

Fig ure 1 0-2 sh ows the m odul es used i n thi s cha pter.

myRobotline robotDefines lrSensors Move Look

Front & rear


obstacle Distance
myRobotWander support
Distance io----..i RobotMotor
Defines (Ping sensor) library
added added

myRobotScan RobotMotor
Library

Figure 10-2. myRobotWander and myRobotScan Sketches

164
Mounting a Ping Distance Sensor

Mounting a Ping Distance Sensor


There are various ways to mount a Ping sensor. You can buy a commercial off­
the-shelf product such as the one illustrated in Figure 10-3.
The bracket shown in Figure 10-4 and Figure 10- 5 is another commercial off­
the-shelf bracket that mounts the sensor on a servo so it can be rotated to scan
for objects on either side of the robot. If you use a com mercial off-the-shelf
product, follow the supplied instructions for assembly and mounting.

Figure 10-3. Parallax Ping Bracket

Chapter 10 165
Mounting a Ping Distance Sensor

Figure 10-4. Parallax Ping Servo Bracket Figure 10-5. Parallax servo bracket parts

If you prefer to make a bracket, it's easy to do, as the next section explains.

Making a Mount for the Ping Sensor


You can make a simple mount from a small piece of wood. A small mount can
be cut from 1 " x 1 3/4" x 3/8" pine. You can drill holes for bolts (4-40 or M3) or
use small wood screws to attach the sensor. The holes are close to the edges,
so drill pilot holes if you use wood screws. Figure 10-6 shows a template you
can use for the mount. You can see the Ping sensor attached to the mount in
Figure 10-7 and Figure 10-8.

------ 1 .8" -------.


----- 1 .7" ----+<

.84"
(21 .3mm) .74"
( 1 8.8mm)

0.1" i
(2.54mm) � !◄

Figure 10-6. Dimensions for the holes for a simple mount

Figure 10-7 shows the a small block of wood cut and drilled.

166
Mount i ng a Ping Distance Sensor

Figure 10-7. Ping sensor with homemade wood mount. Figure 10-8. Rear view of mount; note nuts used as
not fully assembled spacers between PCB and moun t

Fig u re 1 0-9 and Figure 1 0- 1 0 show the mount attached to the robot.

Figure 10-9. Sensor can be mounted directly to the chassis or on a servo

Cha pter 10 167


Mounti ng a P i ng D istance Sensor

Figure 10-10. Feel free to make your mount in a different size or shape

Mounting the Ping Sensor in a Fixed Position


Th e ma n ufact u red mou nts are s uppl ied with mounting hardwa re. If you a re
usin g a h ome made wooden m ou n t, you can a ttach it t o the base with two
wood screws from the un derside of the top pl ate.

Mounting the Ping Sensor on a Servo


Th e wooden mounts can be hot g l ued or screwed onto the servo horn su ppl ied
with the servo as s h own i n Fig ure 1 0-1 1. F i g u re 1 0-1 1 sh owed the sensor at­
tached to a servo that's attached to the 2WD. Fig u re 1 0-1 2 shows the sens or
on a servo attached to the 4WD.

168
Mount i ng a Ping Distance Sensor

Figure 10-11. Servo mount showing attachment detail

Cha pter 10 169


Letting the Robot Wander

Figure 10-12. 2 WD with sensor mounted onto servo

Letting the Robot Wander


The MyRobotWander sketch adds support for a fixed forward- facing distance
sensor that enables the robot to move forward when no obstacle is detected
(panel 1 in Figure 10- 13). The robot stops when approaching an obstacle ahead
(panel 2). It rotates left (panel 3) to see if there is an obstacle in that direction.
If no obstacle is seen, the robot will turn in that direction and move off. If the
left is obstructed, it will turn right and move off in that direction (panel 5). If
both left and right are blocked, the robot will turn around and move off in the
opposite direction.

170
Letting the Robot Wander

, , )))
((( I <

3 4 5

Figure 10-13. Ping Sensor fixed in place to look for obstacles ahead

The code to p rovi de this beha viour is i n the sketch named My robotWande r.
Example 1 0-1 shows the main m yRobo tWa nder tab for this sketch.

Example 10-1. Contents of the sketch's main tab


/ ******************************************************************************
MyRobotWande r . ino

Robot wanders using forward scanning for obstacle avoidance

Michael Ma rgolis 28 May 2012


* ***************** ********* ** ***** **** ************* *********** *** ************* /

#include <AFMotor . h> / / adafruit Moto r shield library


#include " RobotMotor . h " / / 2wd o r 4wd Motor library

#include " robotDeftnes . h " / / global defines

// Setup runs at startup and is used configure pins a nd init systeM variables
void setup ( )

Serial . begin ( 9600 ) ;


blinkNuMbe r ( B ) ; // open po rt while flashing . Needed for Leon a rdo only

lookBegin ( ) ;
MOVeBegi n ( ) ;

Chapter 10 171
Letting the Robot Wander

MoveSetSpeed (MIN_SPEED + 1 0 ) II Run at 10% a bove MiniMUM speed


Serial . println ( " Ready" ) ;

void loop ( )
{
MoveForwa rd ( ) ;
roaM ( ) ; I I look around

II function to indicate nuMbers by fla shing the built - i n LED


void blinkNuMbe r( byte nuMbe r ) {
pinMode ( L ED_PIN , OUTPUT ) ; II enable the LED pin for output
while ( nuMbe r - - ) {
digitalWrite ( LED_PIN , HIGH ) ; delay ( 1 00 ) ;
digitalWrite( LED_PIN , LOW) ; delay (400 ) ;

This s i mply i ni ti al izes the 'Look' modu le ("Th e Look Code" (pag e 1 49 )) and
'M ove' modu l e ("C ore M ovem ent C ode" (pag e 1 24)) and then cal l s a functi on
named roal'l th at d oes all th e h ard w ork of l ooki ng for obstacl es and moving
to avoi d th em. The roal'l functi on is a dd ed into code i n the Look tab;
Example 1 0-2 replaces th e enti rety of the Look tab code tha t you saw in earl i er
examples.

Example 10-2. The new version of the Look tab code


/ **********************
code to look for obstacles
********************** /

con st i n t MIN_DI STANC E = 8 ; II robot s t o p s when object is nea re r ( i n inches )


con s t i n t CLEAR_DI STANCE = 24; II d istance in inches conside red attractive to Move
con st int MAX_DI STANCE = 1 5 0 ; II the MaxiMUM range of the distance sensor

I I angles left , rig h t , center


con st int lookAngles [ ] = { - 30 , 30 , 0 } ;

con st byte pingPin = 1 0 ; II digital pin 10

void lookBegin ( )
{
i rSensorBegin ( ) ; I I initialize senso r s

II retu rns t r u e if t h e given obstacle i s detected


boolean lookForObstacle(int obstacle)
{

172
Letting the Robot Wander

sw1tch (obs tacle ) {


case OBST_FRONT_EOGE : return 1 r EdgeDetect( DIR_LEFT ) && 1 r EdgeDetec t ( D I R_R IGHT ) ;
case OBST_LEFT_EDG E : return 1 rEdgeDetect( DIR_LEFT ) ;
case OBST_RIGHT_EDGE : return 1 r EdgeDetect( DIR_RIGHT) ;
case OBST_FRONT : retu rn lookAt ( lookAngle s ( DI R_CENTER J ) <= MIN_DISTANCE;
}
return false ;

I I retu rns the distance of objects at the given a ngle


II this ve rsion rotates the robot
int lookAt (1nt angle )
{
l'loveRotate ( a ngle ) ; I I rotate the robot

int distance , sal'lple s ;


l o n g cul'le ;
distance = sal'lples = cul'le = 0 ;
for ( 1nt 1 =0 ; 1 < 4 ; 1++)
{
distance = p1ngGetD1stance( p1ngP1n ) ;
1f(d1s tance > 0 )
{
// printlnValue( " D= " , distance ) ;
sal'lples++ ;
cul'le+= distance ;

}
H( sal'lples > 0 )
distance = cul'le I sal'lple s ;
else
distance = 0;

l'loveRotate ( · angle ) ; I I rotate back to original d i rection


return distance ;

II function t o check if robot c a n continue Moving in c u r rent di rection


II retu rns true if robot is not bloc ked 1'1ov1ng in c u r rent d i rection
II this ve rsion only tests for obstacles in front
boolean chec kMovel'lent ( )
{
boolean 1sClear = t r u e ; II default retu r n value if no obstacles
1f( MoveGetState ( ) == MOV_FORWARD )
{
1f( lookForObstacle( OBST_FRONT) == true)
{
1sClear = false;

}
return is Clea r ;

II Look for and avoid obstacles b y rotating robot

Chapter 10 173
Letting the Robot Wander

voi.d roar1( )
{
i.nt di.sta nce = lookAt ( lookAngles [ DIR_CENTER ] ) ;
i.f( di.stance = = 0 )
{
l'lOVeStop( ) ;
Seri.al . p ri.ntln ( " No front sensor " ) ;
ret u r n ; / / n o sensor
}
else i.f(di.stance <= MIN_DISTANCE)
{
l'lOVeStop( ) ;
//Seri.al . pri.nt ( " Scanni.ng : " ) ;
i.nt leftDi.stance = lookAt( lookAngles [ DIR_LEFT] ) ;
i.f( leftDi.stance > CLEAR_DI STANCE) {
/ / Seri.al . pri.nt ( " r1ovi.ng left : " ) ;
r1oveRotate( - 90 ) ;
}
else {
delay ( 500 ) ;
i. n t ri.gh tDi.stance = lookAt (lookAngles [ D I R_RIGHT] ) ;
i.f( ri.ghtDi.stance > CLEAR_D ISTANCE ) {
// Seri.al . p ri.ntln ( " r1ovi.ng ri.gh t : " ) ;
r1oveRotate ( 90 ) ;

else {
/ / Seri.al . p ri.nt ( " no clearence : " ) ;
di.stance = r1ax( leftDi.stance , ri.ghtDi.stance ) ;
i. f ( d i.stance < CLEAR_DI STANCE/2 ) {
ti.r1edMove( MDV_BAC K , 1000 ) ; / / back up for one second
r1oveRotate( - 180) ; // t u r n around
}
else {
i.f( leftDi.stance > ri.ghtDi.sta nce )
r1oveRotate ( - 90 ) ;
else
r1oveRotate(90 ) ;

}
}

// the followi.ng i.s ba sed on loop code fror1 r1yRobotEdge


/ / robot checks for edge and r1oves to avoi.d
voi.d avoi.d Edge ( )
{
i.f( lookForObstacle (OBST_FRONT_EDGE) == true)
{
Seri.al . pri.ntl n ( " left and ri.ght senso r s detected edge" ) ;
ti.r1edMove ( MOV_BACK , 300 ) ;
r1oveRotate ( 120) ;
whi.le( lookFo rObstacle( OBST_FRONT_EDG E ) == t r ue )
r1oveStop( ) ; / / stop r1oto rs i.f sti.ll over cli.ff

174
Letting the Robot Wander

else if( lookForObstacle(OBST_LEFT_EOG E) == t r u e )


{
Serial . println ( " left sensor detected edge " ) ;
tiMedMove ( MOV_BACK, 100 ) ;
MoveRotate ( 30 ) ;

else if( lookForObstacle( OBST_RIGHT_EDGE) = = true)


{
Serial . println( " right sensor detected edge " ) ;
tiMedMove ( MOV_BACK, 100 ) ;
MoveRotate ( - 30 ) ;
}
}

The roal'l fu nction uses i nfor mat i on reported by the distance se ns or to detect
obstacles. The distance sens or code i s des cribed in "S onar Distance Sens ors"
(page 1 37), the sketches i n this ch apter contai n the code i n a new tab name d
Distance.
The checkMovel'lent fu nction i ntrodu ced i n the previ ous chapter i s enhanced
here to check fo r and return false if there are obstacles in front when the robot
is m ovi ng forward. checkMovel'lent is cal l e d when the robot is taki ng evas i ve
action dur i ng a t i med move. You can add addi ti onal checks i nto thi s fu nction
if needed. For example, if you add sens ors to detect an e dge to the rear of the
robot and added your own code that returne d true when this sens or detecte d
a n e dge, the l og i c shown i n Example 1 0-3 would prevent the rob ot from g oi ng
over an e dge when b acking up to avoi d an obstacle i n front.

Example 10-3. The checkMovement function


boolean checkMoveMent ( )
{
boolean isClear = t r u e ; // default retu r n value if no obstacles
if( MoveGetState ( ) == MOV_FORWARD)
{
if( lookForObstacle( OBST_FRONT) == t r u e )
{
isClear = fal s e ;
}
}
else if( MoveGetState( ) == MOV_BACK)
{
if( lookForObstacle(OBST_REAR_EDGE) == t r u e )
{
isClear = fal s e ;

Chapter 10 175
Letting the Robot Wander

}
}
return i.s Clea r ;

I n thi s fragm ent, i f the robot is m oving backward a call i s m ade t o lookFo rOb
stacle (wi th a new case you need to add for a rear edg e sensor) th at ch ecks if
an edg e is detected at th at back of th e robot.
The rest of th e L ook code is si milar to th e code descri bed i n C hapter9, Modifying
the Robot to React to Edges and Lines. The lookForObstac le fun cti on has an
addi ti on al case fo r detecting an ob stacle in fron t (OBST_FRONT). This case calls
a n ew functi on nam ed lookAt that i s given the ang le to look tow ards, and
returns th e distance of th e nearest obj ect detected at that angle. That di stance
i s com pared to a mi ni m um allowable di stance and lookFo rObstac le returns
true if the robot is any closer (in oth er words, i t h as detected an obstacle).
The lookAt fun cti on (repeated in Ex am ple 1 0-4 from the previ ous listi ng ) ro­
tates the robot to the desired angle usi ng th e r,oveRotate comm and descri bed
in Ch apter 7, Controlling Speed and Direction.

Example 10-4. The /ookAt function


// retu rns the di.stance of obj ects at the g i ven a ngle
/ / thi.s ver sion rotates the robot
i. n t lookAt ( i.nt angle)
{
MoveRotate ( a ngle ) ; / / rotate the robot

i.nt di.stance , saMples;


long cuMe ;
di.stance = s aMples = cuMe = 0 ;
fo r ( i.nt i. =0; i. < 4 ; i.++)
{
di.stance = pi.ngGetDi.stance( pi.ngPi.n ) ;
i.f(di.stance > 0 )
{
saMples++ ;
cuMe+= di.sta nce ;
}
}
i.f( saMples > 0)
di.stance = cuMe / saMple s ;
else
di.stance = 0;

176
Letting t h e Robot Wander

MoveRotate ( - angle ) ; II rotate back to o r i.gi.nal d i. recti.on


return di.stance ;

The pingGetDi sta nce func ti on ( Ex am ple 8-4) returns t he d i stan ce i n i n c he s. To


minimize spu ri ou s reflecti on affecting t he reading s, t he functi on i s c al led fou r
ti mes to get an average d i stance. After taking t he reading s, the robot i s rota ted
so it i s fa c ing in the orig i n al directi on. Bec au se the rob ot d oe sn't rotate to
exa c tly the angle reque sted (d ue to c ha nges in bat te ry vol tage, fri cti on, etc.),
the robot may not end up fa c i ng exa ctly the same d i re c ti on and may a ppear
to zig-zag a s i t m ove s forward.
The #defines shown i n Exam ple 1 0-5 are added to the robotDefi.nes tab.

Example 10-5. New constan ts for fron t and rear detection


con st i.nt OBST_FRONT = 4 ; II obstacle i. n front
con st i.nt OBST_REAR = 5 ; I I obstacle behind

Adding Edge Detection


Unlike the earlier chapters, the sketches in this chap­ voi.d loop( )
ter do not try to avoid edges. This enables the robot {
to wander over surfaces such as wooden floors that Move forwa rd ( ) ;
could create false triggers on the edge sensors. The roaM ( ) ; I I look a round
edge detection code that was in the loop of the myR­ avoi.dEdge( ) ; II avoid edges
obotEdge sketch has been moved to the Look tab
i nto a function named avoi.d Edge. If you want to add
edge detection capability to these sketches, add a
call to avoi.dEdge in loop as follows:

Chapter 10 177
Adding Scanning

Add ing Scanning


In the previous sketch, the robot needs to turn in order to look left and right.
Mounting the distance sensor on a servo adds the ability to rotate the sensor
so the robot can 'turn its head' to look around as shown in Figure 10-14.

3 4 5

Figure 10-14. Robot Scans using Ping Sensor Mounted on Servo

The sketch logic is the same, but the Look module has code added to command
a servo to rotate left and right for brief periods. This allows the sensor to look
to see if it can detect an obstacle (see Figure 10- 1 5). If your distance sensor is
not centered, you can add a line in setu p ( ) that will center the servo.
Example 10-6 shows the complete setup function with the servo centering line
added.

Example 10-6. The new setup function


voi.d setup ( )
{
Seri.al . begi.n ( 9600 ) ;
bli.nkNuMbe r ( S ) ; // open port whi.le flashing . Needed for Leon a rdo only

lookBegi.n ( ) ;
MoveBegi.n ( ) ;

178
Adding Scann i ng

MoveSetSpeed (MIN_SPEED + 1 0 ) / / Run a t 10% above MiniMUM s peed


softSe rvoWrite ( 9 0 , 2000 ) ; // Add this line to center the se rvo
Seria l . println ( " Ready" ) ;

The call to softSe rvoWri te cen ters the servo an d wai ts for two sec on ds. If your
sen sor i s n ot centere d, follow these steps:

1. Switch the power off


2. Un sc rew the servo shaft sc rew ( see the i n struc ti on s supplied w i th the Ping
bra c ket)
3. Lift the Ping m ounting bra c ket and re positi on so it i s fa c i ng forwa rd
4. Repla ce the servo shaft sc rew
5. Power on and rec heck

Servo Angle Servo Angle Servo Angle


= 1 50° = 90• = 30 '

IL JL JL
1 .2ms 1 .5ms 1 .Bms

Figure 10-15. Servo used to scan left, center. and right

The servo angle i s c on trolled by a djusting the pulse wi dth on the Ard ui n o pi n
c on n e c te d to the servo. 1 .S m s pul se s wi ll center the servo, a n d i n c rea sing or
dec rea si ng the pulse wi dth will turn the servo one di re c ti on or the other.

The exact relationship between pulse width and servo angle varies
across different servo products. Ifyour servo turns right when it should
turn left, swap the righ t and left servo angles in the servoAng le s array:

II servo angles left, righ t, cen ter


canst int servoAng les[] = { 1S0, 30, 90};

Chapter 10 179
Adding Scanning

Arduino has a S ervo li bra ry tha t can control up to 1 2 servos, however this is
not used in this s ketc h for two reasons. The S ervo li brary ena bles you to send
an angle to t he servo and carry on exec uti ng sketch cod e whi le t he servo is
being m oved in the background, but yo ur cod e must wai t un til t he ser vo i s
faci ng the d esired d i rec tion befo re req uesti ng a reading from t h e dista nce
sensor. However, the mai n reason n ot to use the S ervo li brary is becaus e i t
req u i res exclusi ve us e of on e of t he Ard u i n o chi p's hardware tim ers (ti m er 1 )
and tim ers a re i n s hort s upply on a sta ndard Ard uino chi p (see Appendix F,
Arduino Pin an d Tim er Us age ).
The cod e to con trol t he s ervo g oes in a ta b named Softservo (see
Exa m pl e 1 0-7).

Example 10-7. The co de from the Softservo tab


/ *******************************
Soft servo . i.no
softwa re servo control wi.thout usi.ng ti.Me rs
note that these functi.ons block u n ti.l coMplete
*******************************/

i.nt servoPi.n ;

voi.d softSe rvoAttach ( i.nt pi.n )


{
se rvoPi.n = pi.n ;
pi.nMode ( pi.n , OUTPUT ) ;

/ / wri.tes gi.ven angle to se rvo for gi.ven delay i. n Mi.lli.seconds


voi.d softServoWri.te ( i. n t angle , long servoDelay)
{
i.nt pulsewi.dth = M a p ( a ngle , 0, 180, 544 , 2400 ) ; // wi.dth i.n Mi.c rosecond s
do {
di.gi.talWri.te( servoPi.n , HIGH ) ;
delayMi.croseconds ( pulsewi.dth ) ;
di.gi.talWri.te( servoPi.n , LOW) ;
delay( 20) ; // wai.t for 20 Mi.lli.second s
servoDelay - = 20 ;
} whi.le(se rvoDelay >=0 ) ;

The softSe rvoAttach func tion stores the pin num bertha t the servo i s a ttached
to. The softServoWri. te func tion con verts the d esired angle i nto a pulse wid t h

180
Adding Scan n i ng

and creates the p u l se u s i n g di.gHa lWrHe with a pulse width dete r m i n ed by


a ca l l to de layMi.c r osecond s . The pu lses a re sent repeatedly for the d u ration of
the g iven s e r voDe lay which is a period sufficient for the servo to turn to the
desired d i rection.

The Look code is si m i l a r to the code descri bed at the beg i n n i ng of th i s cha pter,
but here the lookAt fu ncti o n ca l l s softSe rvoW ri. te to rotate the servo i n stead
of rotati n g the entire robot. Exa mple 1 0-8 shows the Look tab used in the
l'lyRobotScan s ketch.

Example 10-8. The m odified L ook tab code


/ ** ** ******************
code to look for obstacles
**********************/

II se rvo defines
con st int sweepSe rvoPin = 9 ; II pin connected to se rvo
con st int servoDelay = 500; II tiMe in MS for servo to Move

con s t int MIN_DI5TANC E = 8 ; II robot stops when object is nearer (in inche s )
con st i n t CLEAR_DISTANC E = 24; II d istance in inches conside red att racive to Move
con s t int MAX_DISTANC E = 150; II the MaxiMUM range of the dista nce sensor

II se rvo angles left , rig h t , center


con s t int servoAngles [ ] = { 150 , 30 , 90 } ;

con s t byte pingPin = 10; II digital pin 10

void lookBegin ( )
{
i rSensorBegi n ( ) ; II initia lize senso r s
softServoAttach ( sweepServoPin ) ; I ll attaches t h e servo p i n to t h e servo object

II retu rns true if the given obstacle is detected


boolean lookForObstacle ( int obstacle)
{
switc h ( obstacle ) {
case OBST_FRDNT_EDGE : ret u r n i r EdgeDetect( DIR_LEFT) && i r EdgeDetec t ( D I R_R IGHT ) ;
case OBST_LEFT_EDG E : ret u r n ir EdgeDetect( DIR_LEFT) ;
case OBST_R IGHT_EDGE : ret u r n i r EdgeDetect( DIR_RIGHT ) ;
case OBST_FRONT : retu r n lookAt ( se rvoAngle s [ D IR_CENTER] ) < = MIN_DI STANCE ;
}
return false;

I I retu rns the distance of objects at the given a ngle


int lookAt ( in t angle )
{
softServoWrite( a ngle , servoDelay ) ; II wait fo r servo to get into position

Chapter 10 181
Adding Scanning

i n t dista nce , saMples;


long cuMe ;
dista nce = saMples = cuMe = 0 ;
fo r ( i n t i =0 ; i < 4 ; i++)
{
distance = pingGetDistance( ping Pin ) ;
if(distance > 0 )
{
/ / p r in tlnValue ( " D= " , distance ) ;
s aMples++ ;
cuMe+= dista nce ;

}
H ( saMples > 0 )
distance = cuMe / saMple s ;
else
distance = 0;

if( a ngle != servoAngles [ D I R_CENTER J )


{
Serial . p rint( " looking at dir " ) ;
Serial . p rint ( a ngle ) , Serial . print ( " dista nce= " ) ;
Serial . printl n ( d i stance ) ;
softServoWrite(servoAngles [ D IR_CENTER J , se rvoDelay/ 2 ) ;
}
return dista nce ;

// fu nction to check if robot can continue Moving in cu r rent di rection


// retu rns t rue if robot is not blocked Moving in c u r rent di rection
/ / this ve r s ion only tests for obstacles in front
boolean checkMoveMen t ( )
{
boolean isClea r = t r u e ; // default retu r n value if no obstacles
if( MoveGetState ( ) == MOV_FORWARD)
{
if( lookForObstacle(OBST_FRONT) == true)
{
isClear = fals e ;

}
return isClea r ;

/ / Look for a n d avoid obstacles using servo t o scan


void roaM( )
{
int dista nce = lookAt ( servoAngles [DIR_CENTERJ ) ;
if(distance == 0 )
{
MOVeStop( ) ;
Serial . p rintln ( " No front sensor " ) ;
retu r n ; / / n o sensor

182
Adding Scann i ng

else if( distance <= MIN_DI STANCE)


{
l'IOVeStop ( ) ;
/ /Serial . p rint ( " Scanning : " ) ;
int leftDi stance = lookAt ( servoAngle s [ DIR_LEFT] ) ;
if( leftDistance > CL EAR_DISTANC E ) {
// Serial . print ( " l'loving left : " ) ;
l'loveRotate( - 90 ) ;
}
else {
delay ( S00 ) ;
i n t rightDistance = lookAt (servoAngles [ D IR_RIGHT] ) ;
if( rightDistance > CLEAR_DISTANCE ) {
/ / Serial . p rintln ( " l'loving righ t : " ) ;
l'loveRotate ( 90 ) ;
}
else {
// Serial . p rint ( " no clea rence : " ) ;
distance = l'lax( leftDis tance , righ tDistance ) ;
if( distance < CL EAR_DISTANC E / 2 ) {
til'ledMove ( MOV_BACK, 1000 ) ; // back u p for one second
l'loveRotate ( - 180) ; // t u r n around

else {
if( leftDistance > rightDistance )
l'loveRotate ( - 90) ;
else
l'loveRotate(90 ) ;

}
}
}
}

/ / the following is based on loop code frol'I l'lyRobotEdge


// robot checks for edge and l'loves to avoid
void avoid Edge ( )
{
if( lookForObstacle( OBST_FRONT_EDG E ) == true)
{
Serial . println( " left and right senso r s detected edge" ) ;
til'ledMove ( MOV_BACK, 300 ) ;
l'loveRotate ( 1 2 0 ) ;
while ( lookFo rObstacle( OBST_FRONT_EDGE ) == t r ue )
l'loveStop( ) ; / / stop l'lotors if still over cliff
}
else if( lookForObstacle( OBST_LEFT_EDG E) == t r u e )
{
Serial . println( " left sensor detected edge " ) ;
til'ledMove ( MOV_BACK, 100 ) ;
l'loveRotate ( 30 ) ;
}
else if( lookForObstacle (OBST_RIGHT_EDGE) = = true)
{

Chapter 10 183
Add i ng Scanning

Serial . println ( " right sensor detected edge" ) ;


tiMedMove ( MOV_BACK, 100 ) ;
MoveRotate ( - 30) ;
}
}

Th e lookFo rObstacle an d roal'l functions are modifi ed from t he non- scanni ng


version to u se the appropriate servo angles for looki ng left, rig ht, an d center.
Th e servo angles are stored i n th e array servoAng le ( swap the l eft an d right
val ues if your servo turns in th e wro ng di rectio n). Th e lookAt function now
rotates the servo to the desired ang le i nstead of movi ng th e enti re robot.

184
Remote Control

This chapter describes how to remotely control robot movement. Techniques


for sending Serial commands as well as TV type infrared remote control are
both explained. The example sketches enable you to command the robot to
perform any of the higher level drive functions described in Chapter 7 .

Hardware Required
• The TV remote control sketch requires an infrared decoder module.
TSOP4 838 (or the equivalent PNA4602 ) modules (Figure 1 1-1 ) have power
and signal pins oriented to enable them to plug directly into the socket
on the motor shield.
You will also need an infrared remote control-almost any controller from
a TV or DVD player will do.

Figure 11-1. Infrared Decoder Module

185
Sketches Used in This Chapter

Sketches Used in T his Chapter


• l"lyRobotSeri.a lRel"lote . i.no- enables the robot t o be controlled by com­
m an ds from the seri al port.
• l"lyRobotRel"lote . i.no - uses com mand s from a TV ty pe remote to control
th e rob ot.

Figure 1 1 -2 sh ows th e mod u l es used i n this cha pter.

myRobotSerial Remote robotDeflnes lrSensors


Move RobotMotor
Library

(Sarne as Look Distance


myRobotRemote Wander & (no Servo) (Ping sensor) RobotMotor
Scan Library

Look
myRobotWanderRemot same as SoftServo
(no Timer)
RobotMotor
myRobotScan library

Figure 11-2. Remote Control sketches

Design of the Remote Control Code


The cod e to handle remote control functi ons i s contai ned i n a m odule nam ed
R emote that appears as a tab i n sketch es i ntrod uced i n this chapter. Thi s m od­
u le:

• D efi nes con stants that i dentify each com mand.


• Matches recei ved data t o a com mand.
• Executes a funct i on associ ated with each comman d w hi ch acti vates the
appropriat e acti on.

H ere are the commands u sed i n the remote c ontrol exam ple:
con st cha r MOVE_FORWARD = ' f ' ; II Plove fo rwa rd
'b'
const cha r MOVE_BACK ; II P1ove backward
'C'
con st cha r PIVOT_CCW ; II rotate 90 deg rees CCW
'c'
con st cha r PIVOT_CW ; II rotate 90 deg rees CW
'p';
const cha r PIVOT II rotation a ngle (Plinus rotates CCW)
'h';
const cha r HALT II stop PIOVlng

These constant s are usedto switc h program executi on to a functi on associated


with each command:
void proces sCOPIPland(int Cl'ld , int val)
{
swltc h (CP1d )
{

186
Design of the Remote Control Code

case MOVE_FORWARD changeCMdSta te ( MOV_FORWARD ) ; Move Forwa r d ( ) ; break;


case MOVE_BACK changeCMdState ( MOV_BACK ) ; MoveBackwa rd ( ) ; break;
case PIVOT CCW changeCMdState( MOV_ROTAT E ) ; MoveRotate ( - 90 ) ; break;
case PIVOT CW changeCMdState( MOV_ROTAT E ) ; MoveRotate ( 90 ) ; break;
case PIVOT changeCMdState ( MOV_ROTAT E ) ; MoveRotate(val ) ; break;
case HALT changeCMdState ( MOV_STOP) ; MOVeStop( ) ; break;
}
}

B efore cal l i ng a m ovem ent function, a function nam ed changeCMdState is


ca lled to store th e current command state. Th is enabl es the robot logic to b e
aware o f what i t was l ast asked to do so i t can m a k e d ecisions i f it encounters
obstacl es while tryi ng to execute the commanded m ovem ent.
To g et this cod e worki ng with s erial commands, a ll that is n eeded is to add a
function that passes s eria l data to th e processCoMMand functi on. Exa m pl e 1 1 -1
shows th e cod e for th e R emote tab that s upports si m pl e s erial remote control.

Example 11-1. Remote tab code fo r simple serial remote con trol
II robot reMote coMMands
II T hi.s ve rsion i.s for seri.al coMMands

II CoMMand con stants

con st char MOVE_FORWARD = 'f' ; II Move forwa rd


con st char MOVE_BACK 'b'; II Move backwa rd
con st char MOVE_LEFT ' l ' II Move left
;
con st char MOVE_RIGHT ,r,;
II Move ri.ght
con st char P IVOT_CCW ' C ' ; II rotate 90 degrees CCW
con st char P IVOT_CW C ' II rotate 90 degrees CW
con st char P IVOT ' p ' ; II rotation angle (Mi.nus rotates CCW)
con st char HALT 'h';
II stop Movi.ng

II not u sed i.n thi.s exaMple


con st char MOVE_S PEED 's' ;
con st char MOVE_S LOWER 'v'
; II red uce speed
con st char MOVE_FAST ER II increase s peed

i.nt COMMandState = MOV_STOP ; II what robot i.s told to do

voi.d reMoteServi.ce ( )
{
i.f( Seri.al . avai.lable ( )
{
i.nt cMd = Seri.al . read ( ) ;
p roces sCoMMand ( cMd ) ;
}
}

voi.d changeCMd State ( i.nt newState)

Chapter 11 187
Design of the Remote Control Code

i.f( newState != coMMa ndState )


{
Seri.al . pri.nt( " Changing (Md state f roM " ) ; Seri.al . print( states [coMMandState ] ) ;
Seri.al . p rint( " t o " ) ; Seri.al . p ri.ntln( states [ newState ] ) ;
coMMand State = newState;
}
}

voi.d proces sCoMMa n d ( i.n t cMd )


{
i.nt val = 0 ;
i. f ( CMd = = PIVOT 1 1 CMd = = SPEED) {
val = Seri.al . pa rseint( ) ;
}
processCoMMand( cMd , val ) ;

voi.d proces sCoMMa n d ( i.n t cMd , i.nt val)


{
byte speed ;
Seri.a l . w r i. te ( cMd ) ; / / echo
swi. tch ( rnd )
{
case MOVE_LEFT changeCMdState( MOV_LE FT ) ; MOVeleft ( ) ; break;
case MOVE_RI GHT changeCMdState( MOV_RIGHT) ; MoveRi.g h t ( ) ; break;
case MOVE_FORWARD changeCMdState( MOV_FORWARD ) ; Move Forward ( ) ; break;
case MOVE BACK changeCMdState( MOV_BACK ) ; MoveBackwa r d ( ) ; break;
case PIVOT_CCW changeCMdState( MOV_ROTATE ) ; MoveRotate ( - 90 ) ; break;
case PIVOT_CW changeCMdState( MOV_ROTATE ) ; MoveRotate ( 90 ) ; break;
case PIVOT changeCMdState( MOV_ROTATE ) ; MoveRotate ( val ) ; break;
case HALT changeCMdState(MOV_STOP ) ; MOVeStop( ) ; break;
case SPEED speed = val ; MoveSetSpee d ( s peed ) ; break;
}
}

This cod e adds a function na med reMoteServi.ce tha t is cal l ed from the mai n
sketch to check i f any remote co mmands ha ve been recei ved. The reMoteSer
vi.ce function will be exand ed la ter in this chapter to s upport oth er remo te
con trol i nputs.
You ma y ha ve noti ced tha t th ere a re two fun ctions nam ed p rocessCoMMand.
The one tha t takes a si n g l e pa ra meter tests if a s econd para meter is requi red
(as in the cas e of the PIVOT com mand) and if so g ets this using the S erial Strea m
parse I n t function.
Exa mpl e 1 1 -2 s hows the mai n sketch cod e from the exam ple, my Robo tS eria l­
Remote tha t responds to the s eria l co mmands.

188
Design of the Remote Control Code

Example 11-2. Main sketch code


/ **** ** *** **** ******* *** *** *********** **** *********************** **** **** ******
MyRobotSerialReMote . ino

Robot sketch with serial reMote COMMands

Created by Michael Margolis 10 June 2012


******************************************************************************/

#include <AFMotor . h> II ad afruit Motor shield library


#include " RobotMotor . h " II 2wd o r 4wd Motor library
#include " robotDeftnes . h " II global defines

II Setup runs at startup and is used configure pins a nd init systeM variables
void setup ( )
{
Seria1 . begi n ( 9600 ) ;
whHe( ! Serial ) ; II only needed for leo n ardo

MOVeBegt n ( ) ;
MoveSetSpeed( MIN_SPEED + 1 0 ) II Run at 10% above MtntMUM s peed
}

void loop( )

reMoteService ( ) ; II wait for serial coMMands

II fu nction to check if robot can continue Moving when taking evasive action
II retu rns true if robot ts not blocked when Moving to avoid obstacles
II this ' placeholder ' ve r sion always retu rns true
boolean checkMoveMent ( )
{
return t r u e ;

If you h ave a wireless device th at passes ser i al data such as a Bluetoo th module,
you can wirele ssly con trol th e robot by con n ec ti ng th e serial outpu t of th e
adapter to th e Arduino seri al input an d wi ring up th e power leads. If you a re
using a Leonardo, note tha t th e TX/RX pins ( digi tal 1 an d O) are accessed
through Se ri.a l1 rather th an Se ri.al, so mo dify you r cod e accordingly (you'll
n eed to replac e all i n stances of S erial with Seri al 1 in all th e tab s of your sketch).

Chapter 11 189
Controlling the Robot with a TV Type IR Remote

Controlling the Robot with a TV Type IR Remote


The remote code can be expanded to support the decoding of IR remote con­
trols. To do this, an I R module is used to receive and condition the IR pulses so
they can be decoded by Arduino.

Installing the I R Decoder Chip


The I R receiver module looks something like a three pin transistor with a bulge
for the IR sensor lens. The module is plugged into the shield as shown in
Figure 1 1 -3 and Figure 1 1 -4. lt is polarized, so make sure it is facing the direction
shown or you can damage the module.

� 0

U1 c_u.tal 1,u
00000000 00000000
�Re f _gn d 1 3 12 1 1 1 0 9 8
01aital I,U

6 5 1 3 2 1 0


(0XCJ □ □ □ 0 0Mt 520 0S1 0• 0• 0MJ 0M1 0e 0M2 □ □ □
S OUsed pms -
-� - - •- - - - - - �
'• •· - - - - - - - - ·
,

2 servos
2 s tepper 1!!!!!!!!!!11
4 de � o t or
0
v1.2

Left
Motor

Right
Motor

To
Battery

Figure 11-3. /R Receiver Module

190
Contro l l i ng the Robot with a TV Type I R Remote

Figure 11-4. /R Receiver Module plugged into the motor shield

If the receiver module does not plug securely into the socket, use a long-nose
pliers to twist the ends of each of the three leads 90 degrees, as shown in
Figure 1 1 -5.

Figure 11-5. /R Receiver Module with leads twisted to for better fit into socket

Chapter 11 191
Contro l l i ng the Robot with a TV Type I R Re mote

The IR Remote Software


The low level decod ing of the i nfra red s i g n a l is hand led by a n A rd u ino l i bra ry
named I R rer1ote that is incl uded with the boo k's down load code.

If you need h e l p i nsta l l i n g a l i bra ry, see " I n sta l l i n g Thi rd-Pa rty L i b ra ries" (page
83).

You don't need to u n dersta nd how the l i brary works i n order to use it, but if
you a re curious, the followi n g is an ove rview of h ow the l i brary works.

The I R r er1ote l i brary u ses an "i.r recv object to decode the pu lses fro m the IR
Receiver.

The IRremote Library and Pin Assignments


The code to create the i. r recv object is: analog pin 3 is not digita l pin 3! The A3 constant is the
IR recv i.rrecv ( i.rRecei.vePi.n) ; Ardu ino way of referring to the digital pin number
associated with the ana log i nput (the i. r recv object
The i. r Recei.vePi.n is the pin that the module is con­ expects the digital pin n u mber). On Leonardo, ana log
nected to. This pin is defined at the top of the main i n put 3 is u sed as d igital i nput 2 1 ; on a standard AT­
sketch tab: mega328 board l i ke the U no, A3 is digital pin 1 7. If
const byte i.rRecei.vePi.n = A3; you use Arduino constants to refer to the digital pin
// analog pi.n 3 assignments for the a na log input pins, the correct
va l ues wil l automatically be assigned.
The Arduino analog input pins can also be used as
digita l pins, but the pin n u m bers a re not the same-

A n u meric va l u e is p rovided for each remote keypress detected. Th e specific


key va l u es decoded w i l l depend on the remote controller you use.
Exa m p l e 1 1 -3 shows code fo r the Rer1ote ta b with su pport for the IR receiver.

Example 11-3. The Remote tab code


// robot reMote coMMands

#i.nclude <IR reMote . h> // I R reMote control li.brary

IRrecv i. r recv( i. rRecei.vePi.n ) ;

decode_results results ;

/ / CoMMand con stants

const char MOVE_FORWARD = I f ' ; / / Move fo rwa rd


con st char MOVE_BACK b';I / / Move backwa rd
con st char MOVE_L EFT 'l' ; / / Move left
con st char MOVE_R IGHT I I
r ; I I Move ri.ght
con st char PIVOT_CCW l c ; l
/ / rotate 90 degrees CCW
con st char PIVOT_CW I C I ;
/ / rotate 90 degrees CW

192
Controlling the Robot with a TV Type IR Remote

con st char P IVOT ' p ' ; // rotation angle (Minus rotates CCW)
con st char HALT ' h ' ; / / stop

/ / not used in this exaMple


con st char MOVE_SPEED 's';
con st char MOVE_S LOWER ' v , ; // reduce speed
con st char MOVE_FASTER // increase s peed

/ / I R reMote keycodes : replace this with codes for you r reMote


f l See text for p roced ure for obtaining codes .
con s t long I R_MOVE_FORWARD = 1064;
con st long I R_MOVE_BACK 3112;
con st long IR_MOVE L EFT 1128;
con st long I R_MOVE_R IGHT 2152;
con st long IR_PIVOT_CW 136;
con st long IR PIVOT_CCW 1160;
con st long I R_HALT 2216;

int COMMandState = MOV_STOP ; II what robot is told to do

void reMoteBegin( byte i rPin )


{
i r recv . enableIR i n ( ) ; // Sta rt the receiver

void reMoteService ( )
{
if ( i r recv . decode ( & results ) )
{
if ( results . decode_type ! = UNKNOWN )
{
/ /Serial . println ( results . value ) ; / / uncoMMent to see r aw result
conve rti rToCoMMa n d ( results . value ) ;
}
i rrecv . resuMe ( ) ; / / Receive the next value
}
/ / additional s u pport for serial coMMands
i f ( Serial . available ( ) )
{
int cMd = Serial . read ( ) ;
p roces sCoMMan d ( cMd ) ;

void conve r t i r ToCoMMa nd( long value)

{
switc h ( value )
{
case IR_MOVE_LEFT processCoMMa nd( MOVE_LEFT ) ; b reak;
case IR_MOVE_RIGHT processCoMMa nd( MOVE_RIGHT) ; break;
case IR_MOVE_FORWARD processCoMMand( MOVE_FORWARD) ; b reak;
case IR_MOVE_BACK processCoMMand( MOVE_BACK) ; break;
case IR_PIVOT_CCW processCoMMand ( PIVOT_CCW ) ; break;

Chapter 11 193
Controlling the Robot with a TV Type IR Remote

case I R_PIVOT_CW processCoMMand ( PIVOT_CW ) ; brea k ;


case I R_HALT proces sCoMMand ( HALT ) ; brea k ;
II c a s e IR SLOWER processCoMMand ( SLOWER ) ; brea k ;
II c a s e IR FASTER p rocessCoMMand ( FASTER ) ; brea k ;
}
}

void changeCMd State( int newState )


{
if( newState ! = coMMa ndState )
{
Serial . print( " Changing CMd state f roM " ) ; Serial . print( states [ coMMandState ] ) ;
Serial . print( " to " ) ; Seria l . p r intln ( states [ newState ] ) ;
coMMandState = newState;

void proces sCoMMand(int cMd )


{
int val = 0 ;
if( c M d == MOVE_SPEED) {
val = Serial . pa rseint( ) ;
}
else if( cMd == PIVOT) {
val = Serial . pa rsei n t ( ) ;
}
p roces sCoMMa nd( cMd , val ) ;

void proces sCoMMand(int cMd , int val)


{
byte s peed ;
I I Serial . write ( cMd ) ; II u ncoMMent to echo
switc h ( rnd )
{
case MOVE_LEFT changeCMdState( MOV_LE FT ) ; MoveLeft ( ) ; break;
case MOVE_RI GHT changeCMdState( MOV_RIGHT ) ; MoveRig h t ( ) ; break;
case MOVE_FORWARD changeCMdState( MOV_FORWAR D ) ; MoveForward ( ) ; break;
case MOVE_BACK changeCMdState(MOV_BACK ) ; MoveBackwa r d ( ) ; break;
case PIVOT_CCW changeCMdState( MOV_ROTATE ) ; MoveRotate ( -90 ) ; break;
case PIVOT_CW changeCMdState( MOV_ROTATE ) ; MoveRotate ( 90 ) ; break;
case PIVOT changeCMdState( MOV_ROTATE ) ; MoveRotate ( val ) ; break;
case HALT changeCMdState( MOV_STO P ) ; MoveStop( ) ; break;
case MOVE_SP EED s peed = val ; MoveSetSpeed ( s peed ) ; b reak;
II case S LOWER : MoveSlowe r ( speed i nc reMen t ) ; break;
II case FASTER : MoveFas te r ( speed i nc reMen t ) ; break;
case ' \ r ' : case ' \ n ' : b reak ; I I ignore e r and lf
default Serial . p rint( ' [ ' ) ; Serial . write ( cMd ) ; Serial . p rintln ( " ] Ignored " ) ; brea k ;
}

194
Controlling the Robot with a TV Type IR Remote

Timers and IRremote Library


The standard IR reMote l ibrary uses Timer 2 and, at were selected so the same code can be used with the
the time of writing, d id not support the Leonardo 2 motor and 4 motor robots with either the Arduino
board. However, Timer 1 is the only available timer Uno or Arduino Leonardo boards. If you want to use
when using the 4WD with the Leonardo board. The a timer other than Timer 1 and you are sure that an­
version of this l ibrary included with the example code other timer is free, then the information on "Modify­
(see "How to Contact Us" (page xv)) supports the ing a Libraryto Change Timer Allocation" (page 236) wil l
Leonardo board and is modified to use Timer 1 . help you modify the library for use with a different
Timer.
"Pin and Timer Tables" (page 237) shows how the
sketches in this book use the timers. These timers

To u se this cod e with you r rem ote, you need to repl ace th e I R comm ands with
th e o nes your remote controller sends. Fig u re 1 1 -6 shows a typical co ntroller
with a sugg est ed key assig nm ent bu t you can ch oos e any k eys you want.

Figure 11-6. Remote Controller Command Buttons

You can u se th e sketch sh ow n in Ex am pl e 1 1 -4 to d i splay th e actu al IR cod es


th at are s ent. After you upload and ru n th e sketch, it will prom pt you to press
a k ey for each com m and to be l earn ed. Th ese are: fo rw ard, reverse, l eft, right,
pi vot cou nt erclockwi se, pi vot cl ockwi se, and st op. Th e d ecod ed valu e will b e
d is pl ayed for each recog nized keypress. After all th e keys are l earned, th e cod es
are wri tten to th e S eri al Moni tor i n a form at th at you can co py i nto th e Re
f"lote tab bel ow th e com m ent li ne th at reads: / / I R ref"lote keycodes : rep lace
this with codes fo r you r ref"lote.

Example 11-4. Learning remote sketch


/*
* LearningRe�ote . cpp

Chapter 11 195
Controlling the Robot with a TV Type IR Remote

*/
#include < I R reMote . h > / / I R reMote cont rol lib r a r y

con st int i r Pin = A3 ; / / an alog i n p u t pin 3 (digital 1 7 )


con st l o n g NO_KEY = - 1 ;
con st long TIMEOUT = 500 0 ; / /Max nuMber o f Milliseconds t o wait for a key ( 5 sec s )
con st i n t KEYCOUNT = 7 ; / / the nuMbe r of key codes s upported

long i r KeyCodes [ KEYCOUNT] ; // this will store r aw codes for all keys
char * reMoteKeyNaMe s [ KEYCOUNT] =
{ " Forward " , " Back 1 1 , 11 Left 11 , " Ri g ht " , " Pi.votCW " , " Pi.votCCW 1 , 11 Ha lt " } ;
/ / not used : Slowe r , Faster

IRrecv i rrecv ( i rPin ) ; // create the I R receive object


decode_results results ; / / ir data goes here

void setup ( )
{
Seria l . begin ( 9600 ) ;
while ( ! Se r ial ) ; / / only needed fo r leonardo

i r recv . enableIR i n ( ) ; / / Start the ir receiver


lea rn Keycodes ( ) ;
p rintCon stants ( ) ;
Se rial . println( ) ;
Serial . println ( " Now press the reMote keys t o ve rify correct detection " ) ;

void loop( )
{
long key = geti r Keycode(TIMEOUT ) ;
if( key ! = NO_KEY )
{
int index = findKey (key ) ;
if( index ! = NO_KEY )
{
Seria l . p rintln ( reMoteKeyNaMe s [ index ] ) ;

}
}

/ / get reMote cont rol codes


// the key Map should be set to zero befo re calling this
void learnKeycodes ( )
{
Serial . println ( " Ready to learn reMote codes " ) ;
fo r ( int i = 0 ; i < KEYCOUNT ; )
{
/ /delay ( 100 ) ;
Serial . println ( ) ;
Serial . p rint( " press reMote key for " ) ;
Serial . p rint( reMoteKeyNaMe s [ i ] ) ;
long key = get i r Keycode ( TIMEOUT ) ;

196
Controlling the Robot with a TV Type IR Remote

i.f( key > 0 )


{
Seri.al . pri.ntln ( " , release key . . . " ) ;
long tel'lp ;
do {
tel'lp = get i r Keycode ( 200 ) ;
}
whi.le( tel'lp == key) ;
i.f( fi.ndKey( key ) == NO_KEY )
{
Seri.al . p ri.n t ( " - > usi.ng code " ) ;
Seri.al . p ri.nt( key ) ;
Seri.al . p ri.nt ( " fo r " ) ;
Seri.al . p ri.ntln( rel'loteKeyNal'les [ i. ] ) ;
i. r KeyCodes [ i. ] = key ;
i..++;
}
else

Seri.al . p r i.ntln ( " key already assi.gned " ) ;

}
else conti.nue ;
}
Seri.a l . p ri.ntln( " Done\n " ) ;

/ / wai.t u p to ti.l'leou t l'li.lli.seconds for a key


long get i r Keycode ( long ti.l'leout)
{

flushKeys ( ) ;

long key = NO_KEY;


u nsi.g ned long sta rtTi.l'le = l'li.lli.s ( ) ;
whi.le( l'li.lli. s ( ) - sta rtTi.l'le < ti.l'leout
{
i.f( i.r recv . decode( &results) ) {
key = result s . value;
/ / Se ri.al . pri.ntl n ( key, HEX ) ;
i. r recv . resul'le( ) ; / / Recei.ve the next value
i.f( key ! = NO_KEY ) {
break;
}
}
}
return key ;

/ /clear the bu ffe r


voi.d flushKeys ( )
{
whi.le ( i.r recv . decode (& result s ) )

Chapter 11 197
Controlling the Robot with a TV Type IR Remote

i. rrecv . resuMe ( ) ;
results . value = · 1 ;

/ / retu rns the i.ndex for the gi.ven key code i. f found
// retu rns NO_KEY i.f code i.s not found
i.nt fi.ndKey( long code )
{
fo r ( i.nt i. = 0; i. < K EYCOUNT ; i.++
{
i.f(i.rKeyCodes [ i. J == cod e )
ret u r n i. ;
}
return NO_KEY;

voi.d pri.ntConstan ts ( )
{
i.nt i. = 0 ;
Seri.al . pri.ntln ( " / / I R reMote keycodes : " ) ;
Seri.al . pri.nt( " const long IR_MOVE_FORWARD = " ) ; Seri.al . p ri.nt ( i. r KeyCode s [ i.++ ] ) ;
Seri.al . pri.ntl n ( " ; " ) ;
Seri.al . pri.nt( " con s t long IR_MOVE_BACK " ) ; Seri.al . p ri.nt (i. rKeyCodes [ i.++ J ) ;
Seri.al . pri.ntln ( " ; " ) ;
Seri.al . pri.nt( " const long IR_MOVE_LEFT It
) ; Seri.al . p ri.nt(i. rKeyCodes [ i.++ J ) ;

Seri.al . pri.ntln ( " ; " ) ;


Seri.al . pri.nt( " const long IR_MOVE_R IGHT II ) ;
Seri.al . pri.nt ( i. rKeyCodes [ i.++ J ) ;
Se ri.al . pri.ntln ( " ; " ) ;
Seri.al . pri.nt( " con st long IR_PIVOT_CW " ) ; Seri.al . pri.nt ( i. rKeyCodes [ i.++ J ) ;
Se ri.al . pri.ntln ( " ; " ) ;
Seri.al . pri.nt( " const long IR_PIVOT_CCW It
) ; Seri.a l . pri.nt ( i. r KeyCode s [ i.++ J ) ;

Seri.al . pri.ntln ( " ; " ) ;


Seri.al . pri.nt( " const long IR_HALT II ) ;
Seri.a l . pri.nt ( i. r KeyCode s [ i.++ ] ) ;
Seri.al . pri.ntln ( " ; " ) ;

Seri.al . pri.ntl n ( ) ; Seri.a l . p ri.ntln( ' Copy the a bove li.nes to the ReMote tab' ) ;
}

The IR remote example sketch shown in Example 1 1- 5 is similar to the example


earlier in this chapter with some additional lines for the IR remote.

Example 11-5. IR remote sketch code


/ ******************************************************************************
MyRobotReMote . i.no

Robot s ketch wi.th reMote COMMands


Note : i.f Moto r s don ' t tu r n , check that i.rReMotei nt . h uses Ti.Me r l , not Ti.Mer2

Mi.chael Margoli.s 28 May 2012

198
Contro l l i ng the Robot with a TV Type l R Remote

********** ********************************************************************/

#include <AFMotor . h> II adafruit Moto r shield library


#include " RobotMotor . h " II 2wd or 4wd Moto r library
#include " robotDefines . h " II global defines

con st byte irReceivePin = A3 ; Ill analog p i n 3

II Setu p runs at startup and is used configure pins a nd init systeM variables
void setup ( )
{
Seria l . begin ( 9600 ) ;
blinkNuMbe r ( S ) ; II open po rt while flashing . Needed for Leonardo only

lookBegi n ( ) ;
MOVeBegi n ( ) ;
reMoteBegi n ( i rReceivePi n ) ; Ill added ReMote tab

MoveSetSpeed (MIN_SPEED + 1 0 ) II Run at 10% above MiniMUM speed


Seria l . println ( " Ready " ) ;

void loop( )
{
reMoteService ( ) ;

II fu nction to indicate n uMbers by flashing the buil t - i n LED


void blinkNuMbe r( byte nuMbe r ) {
pinMode ( LED_PI N , OUTPUT ) ; II enable the LED pin for output
while ( n uMbe r - - ) {
digitalWrite ( LED_PIN , HIGH ) ; delay ( 1 00 ) ;
digitalWrite ( LED_PIN , LOW) ; delay(400 ) ;

The refTloteBegi.n ( i. rRecei.vePi.n ) ; function called i n setup initializes the IR­


decode library. i.reRecei.vePi.n is the pin the ir decoder module is connected
to, in this case, analog pin 3. Because the l ibrary expects a digital pin number,
the Arduino constant A3 is used.

Chapter 11 199
Enhancing Your Robot A

Experienced software engineers use a variety of techniques to help manage


complex projects. This section provides a list of useful tips for designing and
building complex robotics projects.

Planning
T hink Before You Code
It helps to think about you r project and be clear on what you want it to achieve
before you start coding. Tinkering around without a plan is a good way to learn
and to have fun, but it can make a large project too cumbersome to manage.

Avoid Feature Bloat


Don't add features that you don't need. Features added 'just in case' may seem
like a good way to save time later on, but nine times out of ten, the features
you actually need will require changes to the code you wrote that are usually
more troublesome than writing the feature from scratch after you are clear on
what you really need.

Don't Reinvent the Wheel


See what's out there that you can reuse. The Arduino community has made
available a vast collection of useful software. Even if you don't end up using
something off the shelf, seeing how others have solved problems similar to
yours can inform your own solutions.

201
Implementing a Complex Project

Structure to Reflect Functionality


Think about functional associations when organizing your code. Grouping
similar functionality together enables you to create modules which can be
tested in isolation from the rest of your code, simplifying debugging and re­
ducing the likelihood that adding functionality later will have side effects on
other parts of your sketch.

Use Clear Names for Functions and Variables


Each function should have a single clear purpose. Choose a name that reflects
that purpose so when you later need to debug, add or change functionality, it
will be clear what each function or variable is doing. A few extra seconds spent
finding evocative names when you are coding can save hours later on when
you are trying to figure out what a piece of code is intended to do.

Implementing a Complex Project


Test Often
Testing after each major addition or change in code saves time because you
will find and fix problems more quickly. It may seem more efficient to wait until
you have lots of code completed before stopping to test, but when the inevi­
table bugs arise, you can waste a huge amount of time just trying to locate
which part of the code is causing the problem.

Simpl ify
Spending time simplifying code will be repaid in reduced debug time. Complex
code can be difficult to debug or enhance, particularly when you come back
to it after a while. L ooking at each completed function with an eye to seeing
if there is a simpler way of achieving the functionality can result in cleaner code
that is easier to maintain.

If It Is Awkward, Start Over


Don't be afraid to throw away prototype code that becomes a burden. Some­
times you need to tinker to get things working, but if this ends up making your
code a tangled mess, use what you have learned to rethink your structure and
start over.

Don't Confuse Activity with Progress


If you are not making progress, stop and take a break and come back fresh. It
is easier taking in the big picture after a break, particularly if you pause to get
a clear picture in your mind of the problem you are trying to solve and a list of
the assumptions you are making about what is standing in your way.

202
I m plementing a Complex Project

Experiment
If what you have tried isn't working, try someth ing new. Softwa re problems
may actually be a hardware issue (and vice versa).

Be Tenacious
Interesting projects usually come with difficult problems-overcoming these
is part of the reward for a job well done.

Have Fun
Isn't that why you started this project in the first place?

Appendix A 203
Using Other H ardware with
Your Robot B

You may want to add more capability to you r robot or perhaps substitute dif­
ferent hardware than the items covered in the text. This chapter describes how
to use some common alternative components.

Alternative Motor Controllers


Ardumoto
This popular H-bridge can be used instead of the Adafruit shield described in
the text if you have a two wheeled robot (the shield only supports two motors).
It also lacks the convenient layout for the analog sensors and you will need to
add two 3 pin headers for the servo and distance sensor connections. The
Motor code for Ardumoto is shown in Example B-1 .

Continuous Rotation Servos


Continuous rotation servos are hobby servos modified to rotate continuously
with a speed and rotation direction controlled by the Servo library that comes
with Arduino. The servo rotates in one direction as the angle written to the
servo is increased from 90 degrees; it rotates in the other direction when the
angle is decreased from 90 degrees. The actual direction forward or backward
depends on how you have the servos attached. Continuous rotation servos
may not stop rotating when writing exactly 90 degrees. Some servos have a
small potentiometer you can trim to adjust for this, or you can add or subtract
a few degrees to the r1otorStopAng le element to stop the servo. This version
uses digital pins 7 and 8 but you can change this by altering the elements of
the servoPi.ns array (the first element for all the arrays is the left servo, the
second is the right servo). See Example B-2.

205
Alternative Motor Contro llers

These fu nctions convert req u ests to set the motor s peed i nto servo a n g les that
a re written to the continuous rotati on servos. The conve rs ion is performed
using the Ard u i no m a p fu nction.

This code uses the Servo library. Ifyou wan t to build the infrared remote
control project with con tinuous rotation servos, you will need to ensure
that the IRref'lo te library is configured to use a timer other than Timer
1) because the Servo library requires Timer 1. See "Modifying a Library
to Change Timer Allocation" (page 236) for timer usage and details on
how to configure timers for the IRref'lo te library.

Example 8-1. RobotMotor library code for the Ardumoto shield


/ ****** **** *********** ************* ******* **** *** ** ** ***
RobotMotor . cpp / / Ard uMoto version
low level Moto r d r iver for use with a r duMoto Motor shield and 2WD robot

Michael Ma rgolis May 8 2012


* **** ***** *********** ****** ******** * ** **** ********* **** * /

#include <Arduino . h>


#include " RobotMotor . h "

con st i n t diffe rential = 0 ; / / % faster left Motor turns coMpa red to right

/****** �oto r p i n def i nes ************* /


/ / Pins connected to the Motor d rive r . The PWM pins cont rol the s peed , and the
/ / other pins are select forwa rd and reve rse

/ / Motor uses pins : 3 , 1 1 , 12 , 13


con st byte M_PWM_PI N [ 2 ] = { 1 1 , 3} ; // arduMoto v13
con st byte M_DIR_PIN [ 2 ] = { 1 3 , 1 2 } ;
/ * end of Motor pin defines * /

int Motor5peed [ 2 ] = { 0 , 0 } ; // Moto r s peed stored here ( 0 - 100%)

// tables hold ttMe tn MS to rotate robot 360 deg rees at v a r ious s peeds
// this enables conversion of rotation angle into ttMed Moto r MoveMent
// The s peed s a re percent of Max s peed
// Note : low cost Motors do not have enough torque at low s peeds so
// the robot will not Move below this value
// I nte r polation t s used to get a ttMe fo r any speed froM MIN_SPEED to 100%

con st i n t MIN_5PEED = 40 ; // fi rst table entry ts 40% s peed


con st int SPEED_TABL E_INTERVAL = 1 0 ; // each table entry ts 10% faster s peed
con st int NBR_SPE EDS = 1 + ( 100 - MIN_SPEED ) / SPEED_TABLE_INTERVAL;

int s peedTa ble[ NBR_SP EEDS ] = { 40 , 50 , 60 , 70 , 80 , 90 , 100} ; / / s peeds


int rotattonTtMe [ N BR_SPEEDS ] = { 5500 , 3300 , 2400 , 2000 , 1750 , 1550 , 1150} ; // ttMe

206
Alternative Motor Controllers

void MotorBegin(int Moto r )


{
pinMode( M_DIR_P I N [ Moto r ] , OUTPUT ) ;
MOtorStop( Motor ) ;

II speed range i s 0 t o 100


void MotorSetSpeed ( i n t Moto r , int s peed )
{
Moto rSpeed [ Moto r ] = s peed ; II save the value
s peed = Map( speed , 0 , 100 , 0 , 2 55 ) ; II scale to PWM range
analogWrite ( M_PWM_PIN [Moto r ] , speed ) ; II write the value

void Motor Forwa rd ( int Motor , int s peed )

digitalWrite ( M_DIR_PIN [ Moto r ] , HIGH) ;


MotorSetSpeed (Moto r , s peed ) ;

void MOtorReverse( int Motor , int s peed )


{
digitalWrite ( M_DIR_PIN [Moto r ] , LOW ) ;
MotorSetSpeed (Moto r , s peed ) ;

void MotorStop ( in t Motor )


{
analogWrite( M_PWM_P I N [ Motor ] , 0 ) ;

void MotorB rake ( int Moto r )


{
II ArduMoto does not support brake , so j ust stop the Moto r
analogWrite( M_PWM_P I N [ Moto r ] , 0 ) ;

Example B-2. RobotMotor library header fo r continuous rotation servos


/ *************** * ******** ** **** ******************** *****
RobotMotor . cpp II continuous rotation servo version
low level Motor d r iver for use with continuous rotation servos and 2WD robot

Copy right Michael Ma rgolis May 8 2012


******************************************************** /

#include <Arduino . h>


#include <Servo . h>
#include " RobotMotor . h "

Servo Myservo [ 2 ] ; II create instances for two servos

Appendix B 207
Alternative Motor Contro l lers

con st int MAX_ANGLE 60; II nuMber of degrees that Motor d r iven at Max s peed
con st int se rvoPi n s [ 2 ] {7 , 8 } ; II digital pins con nected to se rvos : ( left , right )

II change sign to reve r se di rection of the Motor


int Moto r5ense [ 2 ] = { 1 , - 1 } ; II 1 increases angle fo r forwa r d , -1 decreaes

int Motor5topAngle [ 2 ] = { 90 , 90 } ; II inc o r dee so Motor stops when Motor5top is called

int Moto r5peed [ 2 ] = { 0 , 0 } ; II left and right Motor speeds stored here ( 0 - 100%)

II tables hold tiMe in MS to rotate robot 360 degrees at various speeds


II this enables conver sion of rotation angle into tiMed Motor MoveMen t
II T he s peeds a re percent of M a x s peed
II N ote : low cost Moto rs do not have enough torque at low s peeds so
II the robot will not Move below this value
II I nterpolation is used to get a tiMe fo r any s peed froM MIN_5PEED to 100%

con st int MIN_5PEED = 40 ; II fi rst table entry is 40% s peed


con s t int 5PEED_TABL E_INTERVAL = 10; II each table entry is 10% faster speed
con st int NBR_5PEED5 = 1 + ( 100 - MIN_5PEED ) I 5PEED_TABLE_INTERVAL;

int s peedTa ble[ NBR_5P EED5 ] = { 40 , 5 0 , 60 , 70 , 80 , 90 , 100 } ; // s peeds


int rotationTiMe [ NBR_5PEED5 ] {5500 , 3300 , 2400 , 2000 , 1750 , 1550 , 1150 } ; II tiMe

void MotorBegin (int Moto r )


{
Myservo [ Moto r ] . attac h ( se rvoPins [ Moto r ] ) ;

I I s peed ra nge is 0 to 100


void Motor5et5peed(int Moto r , int s peed )
{
Moto r5peed [Moto r ] = s peed ; II save the value

void Motor Forwa rd ( int Motor , int s peed )


{
Motor5et5peed (Moto r , s peed ) ;
int s topAngle = Moto r5topAngle [Motor ] ;
int Max5 peedAngle = stopAngle + ( MAX_ANGLE * Motor5ens e [ Moto r ] ) ;
int angle = Map ( speed , 0 , 100 , stopAngle , Max5peedAngle ) ;
Myservo[Moto r ] . write ( angle ) ;
}

void MotorReverse( int Motor , int s peed )


{
Motor5et5peed (Moto r , s peed ) ;
int stopAngle = Moto r5topAngle [Motor ] ;
int Max5peedAngle = stopAngle - ( MAX_ANGLE * Motor5ens e [ Moto r ] ) ;
int a ngle = Map ( speed , 0 , 100 , stopAngle , Max5peedAngle ) ;
Myservo[Moto r ] . write ( angle ) ;

208 Make an Ardui no-Controlled Robot


Alternative Motor Controllers

void MotorStop ( in t Motor )


{
Myservo[ Moto r ] . write(MotorStopAngle[ Motor ] ) ;

void MotorBrake(int Moto r )


{
Myservo [ Moto r ] . write( Moto rStopAngle[ Moto r ] ) ;

Appendix B 209
Debugging Your Robot

Complex projects inevitably throw up obstacles in the form of bugs. As these


arise, you can congratulate yourself for choosing such a challenging project
and bear in mind the satisfaction you will feel when all the problems have been
overcome. Here is some software that should help you find and fix problems
you may encounter.

Identify the Symptoms and Local ize the problem


Seeing What the Robot Is Doing
Visualizing data from the sensors in real time can be tremendous help in un­
derstanding what is actually happening in your sketch. Figure C-1 shows the
screen from a Processing sketch that enables you to easily view Arduino values.

211
Identify the Symptoms and Localize the problem

II ArduinoOataDisplay --
Ardulno Data (COM7)

Len Line :::::J


I
Center Line ::===================::::=====::::::
(0--1 02"

(0 1 023)
88

680
Right Line ,---� (0--1 0:3) 1 44
Drift ,. , o:J--1 o:? 1 25
Distance <o-1 44) 24
(0 1 024) 0
(0--1 024) 0

(0-1 0,4) 0
(0·1 0,4) 0
10 (0--1 024) 0
11 (0·1 0'4) 0

12 (0-1 024) 0

Figure C-1. Arduino Data Displayed i n Processing

Figu re C- 1 depicts the an alo gRead values from left, cen te r and right and se n­
sors used in lin e detection. The grey numbers i n parentheses on the righ t in­
d i c ate the possi bl e ran ge of values, the following number i s the n u meric value
sen t from Ardui no.

The figure shows the values when the robot i s strayi n g sl ightly to the righ t of
a d ar k li ne it is t ryi n g to follow (th e values incre ase when the sensor is over the
l i ne). The Position value goes positive when straying right and negative when
left. The Posi ti on value i s u sed in the line followi n g sketch to adj u st the robot
d i rection so it stays on the l ine. The Distance val ue is in inches and is obtai ned
fro m the pi n g d i stance sen sor.

The Processi n g sketch expects d ata in the following format; field s are separated
by c om mas:

• The stri n g: D ata


• The row to di splay; th e fi rst row is row 1
• The v alue to d i spl ay
• The newline c h aracte r "\n"

For example, sen d i n g " Data , 2 , 680\ n " will d i spl ay a bar w i th a value of 680 o n
t he second li ne.
You can send l abels for each li ne by sen d i n g a strin g such as: " Labe l , 2 , Center
L lne\ n " , which will tag the second row with the label "Center Line''.
The d at a ran ge c an be sent usi n g a stri n g such as " Range , 5 , 0 , 144\ n " which
wi l l set the ran ge of the fifth li ne from O to 1 44.

212
Identify the Symptoms and Local ize the problem

The ea sies t way to sen d thi s da ta is to a dd the Da ta Di splay ta b to you r ske tch
a nd call the functi ons to form a t a n d sen d the da ta:

• sendDat a ( row , value) ; sends the specified value for di splay on the g i ven
row
• send Label ( row , label ) ; sen ds the specified label for di spla y on th e g i ven
row
sendRange( row , mn1.1'1Ul'1 , 1'1axi.1'1u1'1 ) ; se nds the m i n i m u m a nd ma ximum
values for the specified row

The sketch named l"lyRobotDebug c ontain s the DataDi splay tab and provi de s
a n exa m ple of how to send da ta to the Proce ssi ng. E xa m ple C-1 sh ow s the
main sketch c ode.

Example C-1. myRobotOebug main sketch code


/ **********************************************************
MyRobotDebug . ino

SiMple debug exaMple using Processing debug Monitor


This ve rsion displays values froM the line and distance senso r s

***********************************************************/
#include " robotDefines . h " // global defines

con st byte pingPin = 10; // Distance sensor connected to digital pin 10

enuM { DATA_st a r t , DATA_LEFT , DATA_C ENTER , DATA_RIGHT , DATA_DRI FT, DATA_DISTANCE ,


DATA_nb r iteMs } ;

cha r * label s [ ) = { " " , " Left Line" , " Center Line " , "Right Line" , " Drift " , " Distance " } ;
int Mtn Range [ J = { 0 , 0, 0, 0 , - 1023 , 0 };
int MaxRange [ ) = { 0 , 1023 , 1023 , 1023 , 1023 , 144} ;

/ / Setup r u n s at startup and is used configure pins a nd init systeM variables


void setup ( )
{
Serial . begin ( 9600 ) ;
while( ! Se rial ) ; / / only needed for leo n ardo

dataDisplayBegin ( DATA_n briteMs , label s , MinRange , MaxRange ) ;


Serial . p rintln ( " Ready " ) ;

void loop( )

lineSens e ( ) ;
int distance = pingGetDis ta nce ( pingPi n ) ;
sendData ( DATA_DI STANC E , distance ) ; / / send distance

Appendix C 213
I dentify the Symptoms and Loca l ize the problem

/ * * **************************
Line Sensor code
**************************** /
/ / defines for locations of sensors
canst i n t S ENSE_L I NE_LEFT = 0;
canst i n t SENSE_LINE_RIGHT = 1;
canst i n t S ENSE_LINE_CENTER = 2;

/ / returns d rift - 0 if over line , Minus value if left , plu s if right


int HneSense( )
{
i n t leftVal = an alogRead ( S ENSE_LINE_LEFT ) ;
int cente rVal = analogRea d ( SENSE_LINE_CENT ER ) ;
int rightVal = ana logRead ( SENSE_LINE_RIGHT ) ;

sendData ( DATA_LEFT , leftVal ) ; / / send left sensor value


sendData ( DATA_C ENTER , centerVal) ; / / send center sensor value
sendData ( DATA_R IGHT , rightVal ) ; / / send right sensor values

int leftSense = centerVal - leftVal;


int rightSense = rig htVal - centerVal ;
int d rift = leftVa l - rightVal

sendData ( DATA_DRIFT , d rift ) ; / / send d rift sen sor values

return d rift ;

/ / Retu rns the distance in inches


/ / this will retu r n 0 if no ping sensor is connected or
/ / the distance is g reater than around 10 feet
int pingGetDis tance(int pingPin )
{
long duration , CM;

pinMode( pingPin , OUTPUT ) ;


digitalWrite ( pingPin , LOW ) ;
delayMic rosecon d s ( 2 ) ;
digitalWrite ( pingPin , HIGH ) ;
delayMic rosecond s ( S ) ;
digitalWrite ( pingPin , LOW ) ;

pinMode( pingPin , INPUT ) ;


d u r ation = pulsei n ( pingPin , HIGH , 20000 ) ; / / i f a pulse does not a r rive i n 2 0 M S then
/ / the ping sensor is not con nected
if(du ration >=20000 )
ret u r n 0 ;

214
Identify the Symptoms and Local ize the problem

// convert the tiMe into a distance


CM = duration / 29 / 2 ;
return ( cM * 10 ) / 25 ; / / conve rt C M t o inches

The A rdui n o code tha t sen ds the da ta is in the ta b named DataDi.sp lay
(Exam ple C-2), you ca n co py the code into any sketch you wan t to debug, or
yo u can sim ply a dd the ta b to th e sketch.

Example C-2. the Data Display tab code


// DataDisplay

void dataDisplayBegi n ( in t nbriteMs , char * labels [ ] , int MinRange [ ] , int MaxRang e [ ] )


{
fo r ( int i = 1 ; i < nbr iteMs ; i++ )
{
sendlabel ( i , labels [ i ] ) ;
sendRange ( i , MinRange [ i ] , MaxRange [ i ] ) ;

void sendlabel( int row, char * label)


{
sendString ( " Label" ) ; sendValue ( row) ; sendSt ring (label ) ; Seria l . println ( ) ;

void sendRange( int row, int Min , int Max )

sendString ( " Range" ) ; sendValue ( row) ; sendValue ( Min ) ; sendValue( Max ) ; Serial . p rtntln ( ) ;

void sendData ( int row , int val)


{
sendString ( " Data" ) ; sendValue ( row) ; sendValue ( val ) ; Serial . p rintln ( ) ;

void sendValue( int value)


{
Serial . p rint (value ) ; Serial . p rint( " , " ) ;

void sendString(char * strin g )

Serial . p rin t ( s t ring ) ; Serial . print ( " , " ) ;

Appendix C 215
I dentify the Symptoms and Loca l ize the problem

Th e Processing sketch is cal led Ardui.noDataDi.splay and is located i n the Pro


ces si.ng folder of the exa mple code download (see "How to Contact Us" (page
xv) for the downl oad location). Exa m p l e C-3 shows the code.

Example C-3. Processing sketch for displaying data


/*
* ArduinoDataDisplay
* based on Arduino Cookbook code f roM Recipe 4 . 4
*
* Displays b a r g r aphs of sensor data sent a s CSV froM Arduino
* in all cases , N is the Row to be associated with the given Message
* Labels sent as : " La bel , N , the label \ n " // " the label " i s u sed for Row N
* Range sent a s : " Range , N , Min , Max\ n " / / Row N has a ra nge froM Min to Max
* if Min is negative then the bar g rows froM the Midpoint of Min and Max ,
* else the bar g rows froM Min
* Data sent a s : "Data , N , val\n" // val is plotted fo r row N
*/

short porti ndex = 1 ; // select t h e coM port , 0 i s the fir st port

int MaxNuMbe rOfRows = 12 ;


int g ra phWidth = 600 ;
int displayWidth = 1024;
int dis playHeight = 800 ;

int fon tSize = 1 2 ;


PFont fontA ;

int windowWidt h ;
i n t windowHeight;

int g ra phHeight ;
int rectCente r ;
int rectleft ;
int rectRig h t ;
int topMa rgin ;
int bottoMMa rgin;
int leftMa rgin = 50;
int rightMa rgin = 80;

int textHeight ;

Arr aylist<String> labellist = new Arraylist<String> ( ) ;


int [ ] values { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0} ;
int [ ] rangeMin = { 0 ' 0 ' 0 ' 0 ' 0 ' 0 ' 0 ' 0 ' 0 ' 0 ' 0 ' 0 ' 0} ;
int [ ] rangeMax = { 0 , 1024 , 1024, 1024 , 1024 , 1024 , 1024, 102 4 , 1024 , 1024 , 1024 , 1024 , 1024 } ;

float lastMsgTiMe ;
float displayRefreshinte rval = 20; // Min tiMe between screen d raws

void setu p ( ) {
String os=SysteM . getProperty( " os . naMe " ) ;

216
Identify the Symptoms and Local ize the problem

p ri.ntln( os ) ;
i.ni.t(Ol'll'IS( ) ;
fontA = c reateFont ( "Ari.al . nomal " , fontSi.ze) ;
textFont ( fontA) ;
textHei.ght = ( i. n t ) textAscent ( ) ;
for ( i.nt i. = 0 ; i. < = MaxNuMberOfRows ; i.++)
labelli.st . add ( I ntege r . toStri.ng ( i. ) ) ;
adj ustSi.ze ( ) ;
d rawG r i.d ( ) ;

voi.d ad j u stSi.ze ( )

topMa rgi.n = 3 * textHei.gh t ;


bottoMMa rgi.n = 0 ;
i.f (di.splayWi.dth > 800 ) {
wi.ndowWi.dth = 800 ;
wi.ndowHei.g ht = topMa rgi.n + bottoMMargi.n + yPos ( MaxNuMbe rOfRows ) ;
si.ze (wi.ndowWi.dth , wi.ndowHei.gh t ) ;
}
else {
wi.ndowWi.dth = di.s playWi.dt h ;
wi.ndowHei.g h t = di.splayHei.g h t ;
}
/ / leftMa rgi.n = getleftMargi.nlen ( )
g raphHei.ght = wi.ndowHei.ght - topMa rgi.n - bottoMMa rgi.n ;
rectCenter = leftMargi.n + g ra phWi.dth / 2 ;
rectleft = leftMa rgi.n;
rectRi.ght = leftMa rgi.n + g r aphWi.d t h ;

voi.d drawG ri.d ( ) {


fi.ll ( 0 ) ;
Stri.ng Ti.tle = " Ardui.no Data" + coMMsPo r tStri.ng ( ) ;

i.nt xPos = ( i.nt ) ( rectCen ter - textWi.dt h (Ti.tle ) / 2 )


text( Ti.tle , xPos , fontSi.ze* 2 ) ; // Ti.tle

li.ne( rectleft , topMa rgi.n + textHei.gh t ,


rectleft , yPo s ( MaxNuMberOfRows) + 2 ) ; // left ve rti.cal li.ne

li.ne( rectRi.g h t , topMargi.n + textHei.g h t , rectRi.ght , yPo s ( MaxNuMbe rOfRows )+ 2 ) ; / / ri.ght li.ne
li.ne( rectCenter , topMa rgi.n+textHei.g h t , rectCenter , yPos( MaxNuMbe rOfRows ) + 2 ) ; / / cente r li.ne

for ( i.nt i.=1 ; i. <= MaxNuMbe rOfRows ; i.++ ) {


fi.ll ( 0 ) ;
text ( l a bel li.s t . get( i. ) , 2 , yPos ( i. ) ) ; // row labels
fi.ll ( 1 50 ) ;
Stri.ng rangeCapti.on = " ( " + rangeMi.n [ i. ] + • - • + rangeMax [ i. ] + " ) " ;
text ( r angeCapti.on , rectRi.ght + textWi.d th ( " " ) , yPos ( i. ) ) ; / / range capti.on

i.nt yPos ( i. n t i.ndex) {

Appendix C 217
I dentify the Symptoms and Loca l ize the problem

return topMa rgin + ( ( index ) * textHeig ht * 2 ) ;

void d r awBa r ( int rowl ndex) {


fi ll( 204 ) ;
if ( rangeMi n [ rowl ndex ] < 0 ) {
if ( values [ rowlndex] < 0 ) {
i n t width = int ( Ma p ( value s [ rowlndex ] , 0 , r a ngeMin [ rowlndex] , 0 , g r a phWidth/2 ) ) ;
rect ( rectCente r - width , yPo s ( rowlndex ) - fontSize , width , fontSize) ;
}
else {
i n t width = int(Map(values [ rowlndex ] , 0 , ra ngeMax [ rowl ndex] , 0 , graphWidth /2 ) ) ;
rect ( rectCente r , yPos ( rowlndex ) - fontSi z e , width , fon tSize ) ;

}
else {
int width=int ( Ma p ( values [ rowlndex ] , rangeMin [ rowl ndex] , rangeMax [ rowl ndex ] , 0 , g raphWidth ) ) ;
rect ( rectleft , yPos( rowl ndex ) - fontSiz e , width , fontSiz e ) ; / / d raw the value
}
fill ( 0 ) ;
text(value s [ rowlndex ] ,
rectRig ht + ( i n t ) textWidth ( " ( - 1000·1000) " ) , yPos ( rowlndex ) ) ; / / print the value

void processMessages ( ) {
while ( true ) {
String Mes sage = coMMsGetMes sage ( ) ;
i f ( Message . length ( ) > 0 )
{
i n t row = 0 ;

String [ ] data = Message . split( " , " ) ; / / Split the CSV Message
if ( data [0 ] . equals ( " Data " ) ) { / / check for data header
row = I ntege r . parselnt( data [ l ] ) ;
values [ row] = Intege r . parselnt( data [ 2 ] ) ;
checkRefresh ( ) ;

else i f ( data [ 0 ] . equals ( " La bel " ) ) { / / check fo r label heade r


row = I ntege r . parselnt( data [ l ] ) ;
labellist . set ( row , data [ 2] ) ;
if ( ( in t ) textWidth ( data [ 2 ] ) > leftMa rgin ) {
leftMargin = ( i nt ) ( textWidth ( data[ 2 ] ) + textWidth ( " " ) + 2 )
adju stSize ( ) ;
}
checkRefresh ( ) ;

else i f ( data [ 0 ] . equals ( " Range " ) ) { / / check fo r Range heade r


row = Intege r . parselnt( data [ l ] ) ;
rangeMi n [ row] = I nteger . pa r selnt( data [ 2 ] ) ;
rangeMax [ row] = I nteger . pa r selnt( data [ 3 ] ) ;
checkRefresh ( ) ;

else
println ( Message)

218
Identify the Symptoms and Local ize the problem

else
brea k ; / / finish p roces sing when the Message length is 0

void checkRefresh( )
{
if ( lastMsgTiMe < 1 )
lastMsgTiMe = Millis( ) ; / / update the tiMe i f i t was reset b y t h e last dis play refresh

void d r aw( ) {
processMessages ( ) ;
i f ( Millis( ) - lastMsgTiMe > displayRefreshinterval)
{
background ( 255 ) ;
d rawGrid ( ) ;
for ( int i=1 ; i <= MaxNuMberOfRow s ; i++ )
{
d rawBa r ( i ) ;
}
lastMsgHMe = 0 ;

/ ******************************
code for Serial po rt
***************************** /

iMpo r t p rocessing . se rial . * ;

Serial MyPo r t ; / / Create object fr oM Serial class

void initCoMMs ( ) {
String portNaMe = Seria l . list( ) [ po rt!ndex ] ;
p rintln ( Serial . list( ) ) ;
p rintln ( " Connecting to · > " + portNaMe ) ;
MyPort = new Seria l ( this , por tNaMe , 9600 ) ;

String COMMSPortString ( ) {
return " ( " + Serial . li st ( ) [port! ndex] + " ) "

String Mes sage;

String coMMsGetMessage( )

if (MyPort . available ( ) > 0 )


try {
Message = MyPo r t . r eadStringUntil ( 10 ) ;
i f ( Message ! = null ) {

Appendix C 219
I dentify the Symptoms and Localize the problem

/ / print (Message ) ;
return Message;
}
}
catch ( Exception e ) {
e . printStackTrace ( ) ; / / Display whatever e r ro r we received
}
}
return 11 1 1
;

Thi s sketch tal k s to Ardui no using the serial po rt a n d you need to en sure t hat
the Proce ssing sketch is using the same port t hat is con nected to your robot.
The port Ardui no uses i s dis playe d o n i n the A rduino I D E. You set t he Proce ssing
port by changi n g the value of the vari able portl ndex. When starti ng the Pro­
cessing sketch, yo u will see a list of t he ports on your com puter. po rtl ndex i s
the position o f the Ard uino port i n thi s l ist, but note t hat the i ndex sta rts from
0, so t he default va lue of 1 for po rtlndex is for t he second port i n the li st.
A robot tethered via USB i s not very con venient w hen you want to see what
the robot i s doing whi le moving. Addi n g a wi reless serial de vi ce such a s Blue­
toot h or XBee can be a big hel p when debuggi n g or tun i n g your robot. If you
a re usi n g a Leonardo, note that the TX/ RX pi ns (di gital 1 a nd O) a re a ccessed
through Seri.a l1 ra ther tha n Seri.al, so mo dify your code a ccordingly (you'll
need to re pla ce a l l insta n ces of Serial with Serial l in a l l the ta bs of your sket ch).
A stan da rd boa rd like the Uno uses t he same Se ri.al obje ct as USB a n d a l­
though yo u don't need to modify the exam ple code, yo u w i l l need to discon­
nect the wi rele ss de vi ce from the pin s when uploading code. T his is beca use
the wireless device use s the same pi ns (digita l 1 a n d O) a s USB.

220 Make an Arduino-Controlled Robot


Power Sources D

Monitoring Battery Voltage


The ba ttery voltage ca n be monitored u si ng an Ardu i no ana lo g input, but yo u
can't direct ly connect the ba ttery to a n i nput pin beca use a full y cha rged ba t­
ter y can exceed the maxi mu m voltage tha t the Ardu ino chi p ca n tolera te.
Another facto r to be aware of is that the defa ult volta ge reference for a n alog
Read i s the S volto utput fro m the regula tor on the Ard ui no boa rd. This reg ulator
requi res more tha n 6 volts to p roduce a sta ble 5 vo lt output. When the volta ge
difference between the regu la tor i nput a nd output (referred to in the re g u la tor
da ta sheet a s the dropout voltage) i s le ss than a volt, the output volta g e will
drop below the re qui re d 5 volt le vel. Beca use th is volta g e is use d as the default
Arduino reference for ana lo g conversion, the a na lo g rea ding s will no longer
be accurate. In short, you shouldn't rely o n the battery voltage as a reference
to measure the battery voltage. So yo u nee d a relia ble voltage reference tha t
i s not de pendent on the output from the reg ula tor.
The solu tion i s to u se an intern a l vo ltage reference tha t i s bui l t i nto the Ardu i no
chip. Thi s provi de s a 1 . 1 volt reference tha t i s sta ble for a ny voltage tha t i s
sufficient to power the Arduino chi p. Becau se the reference i s 1 . 1 vol ts, the
volta g e being meas ured must not exceed this va lue, so a voltage di vi de r to
d rop battery voltage down to a n a cceptable ra nge is requi red ( Fig ure D- 1 ).

221
Monitoring Battery Voltage

R1

R2 Vo = Vin • R2 / (R1 + R2)

Figure D-1. Resistors used as a voltage divider

To support a wi de ra nge of ba ttery choice s (includi ng 8.4 volt LiPo ba tteries),


re si stor va lue s of 1 8 k oh m s for Rl a nd 2.2k o hm s for R2 provi de a voltage ra nge
of up to 1 0 volts.

Here is the voltage divider formula for these resistor values: R2 / Rl +


R2. Substituting the chosen values results in:

2200/(1 8000 + 2200)

= 0 . 109

Therefore the voltage on the terminal will be the battery voltage times
0. 109. For example, 1 0 volts at the battery will be dropped tojust under
the 1. 1 volt range of the in ternal reference.

The resi stors can be atta che d to the ba ttery term inal s as shown i n Fig ure D-2,
but a more permanent solu tio n i s to solder the re si stors to the shield a s shown
i n Fig ure D-3 a nd Fig ure D-4.

222
Monitori ng Battery Voltage

To

Di:�::: .:::::::i::'.iii.&A--;:::::----__iii1oi<1<1(;fl717.o,----ij"u110ii11aai()'li7()u-'
o 0 0 0 () () ) 0 0 0 0 0 0 00
□ □ □ 0e 0Ml 0,2 0Si 0e oe oM3 oMi oe □ □ cr o
SA•f q n d 13 12 11 10 9 8 7 6 5 < l ? 1 �
To Used plns �
Servo - -. - - - - -. - -. .
. . .. - - . - .

Left
Motors

Right
Motors

+5
Gnd

To
Battery

Figure D-2. Resistors added to shield to monitor battery

To

Di:�•::: .:::::::i:s.;::..;-.:--:;::::-------1ii1iii<1<

1 ;rlll;------ ici
, ii
llai71
o 0 () () i7D------
00 00 0 0 0 0 0 () () 0 0

0
�ef qnd 1 3 12 11 10 9 8 7 6 5 "I 3 i 1- A

To lsed pins -
□□□ 00000 0000
e M l S2 Si e e MJ M• e M
□□□□
Servo 1· · - - - - - - - - - •

0
'• · · - - - - - - - - �

Left
Motors

Right
Motors

+5
Gnd

power 0
IDBI
O D DO
R T J\1 5v ,n
0 0 0 0

To
Battery

Figure D-3. Voltage Divider Resistors soldered to Vin and Gnd pins

Appendix D 223
Monitoring Battery Voltage

Figure D-4. Voltage Divider Resistors soldered to Vin and Gnd pins

The co de to rea d a n d i nterpret t he voltag e i s in the Battery tab (Exa mple D- 1 ).


This cod e rea ds th e output of th e voltage d i vider usi ng a n a logRead and con­
verts this i nto th e ba ttery vo ltage expressed in mi ll i vol ts. This is co mpa red to
preset th resholds l evels so a n LED ca n be fla sh ed to indi ca te low and cri ti ca l
battery levels. The code can al so detect if the o ptional cha rg er pl ug i s con­
n ected to sto p robo t movemen t whi l e b eing recha rg ed.

Example 0-1. Battery tab code


// code to Monitor battery voltage

/******************************************************************
* LED starts flashing when volage d rops below warning level
* Mark space ratio increses froM 10% to 50% as voltage decreses f roM wa r ning to c r itical
* robot shuts down when battery below critical a nd led flashes SOS
*
* LED Mar k space ratio changes froM 10% to 90% as voltage inc reases to full
***************************************************************** /

// th reshold s a re the cell Millivolts tiMes n uMber of cells

224
Monitori ng Battery Voltage

con st int batte ryFull 1500 * 5 ; / / th reshold for battery is low wa rning
con st int batte ryWa rning 1 100 * 5; / / th reshold for battery is low warning
con st int batteryCritical= 1000 * 5; / / threshold to shut down robot

int batteryMonito r Pi n ; / / an alog pin to Monitor


int cha rgerDetectPin = - 1 ; / / pin goes open circuit when charger connected , default is no pin
int blinkPi n ; / / led p i n t o flash

void batteryBegin ( int Monito r Pin , i n t ledPin )


{
batte ryMonito rPin = Monito r Pin ;
blinkPin = ledPin;
pinMode( blinkPin , OUTPUT ) ;

/ / ve rsion for charger detection


void batte ryBegi n ( i n t Monito rPin , int led Pin , int chargerPin)
{
batte ryBegin ( Monito r Pin , ledPin ) ;
cha rgerDetectPin = chargerPin ;
pinMode( cha rgerDetectPi n , INPUT_PULLUP) ; / / con nect pull - u p resistor

/ / indicates battery status u sing the given LED


void batte ryCheck ( )
{
int MV = batteryMv ( batteryMonito rPin ) ; // get batte ry level in Millivolts
Serial . print( "Mv=" ) ; Serial . p r in t ( Mv ) ;
if( charge rDetectPin >=0 && digitalRead ( chargerDetectPin ) == HIGH)
{
// here if charger detect is enabled and charger plugged in
while( digitalRead (chargerDetectPin ) == HIGH ) / / while charger is plugged in
{
MoveStop( ) ;
MV = batteryMv( batte ryMonitorPin ) ; / / get battery level i n Millivolts
Serial . print ( " , cha rger detected , voltage= " ) ;
Serial . println(Mv ) ; Serial . p rintln ( " , pe rcent= " ) ;
int percent = Map(Mv , batte ryCritical , batteryFull , 50 , 100 ) ;
pe rcent = constrain ( percen t , 0 , 100) ;
Serial . println( pe rcen t ) ;
flas h ( percent , blinkPin ) ;

}
else
{

if(MV < batte ryC ritical )


{
Serial . p rintln ( " C ritical " ) ;
/ / s h u t down the robot
MOVeStop ( ) ;
while ( l ) {
flashCritica l ( blinkPi n ) ;

Appen dix D 225


Monitoring Battery Voltage

II check of the cha rger is plugged in


if ( chargerDetectPin >=0 && digitalRead (chargerDetectPi n ) == HIGH )
retu r n ; II exit if charging

delay( S000 ) ;
}
}
else if (MV < batteryWa rning )

int percent = Map(Mv, batteryC ritica l , batteryWar ning , 10 , 50) ;


flas h ( perce n t , blinkPin ) ;

}
delay( 1000 ) ;
Serial . println ( ) ;

II retu rn the voltge o n the given pin i n Millivolts


II see text for voltage divider resistor values
int ba tteryMv ( in t pin )
{
#if defined ( _AVR_ATMega3 2U4_) II is this a Leonardo boa r d ?
c o n s t long INTERNAL_REFERENCE_MV = 2560 ; II leo reference i s 2 . 56 volts
#else
const long INTERNAL_REFERENCE_MV = 1100; II ATMeg a328 is 1 . 1 volts
#endif
con st float R 1 = 18 . 0 ; II voltge dividier resisto r s value s , see text
con st float R2 = 2 . 2 ;
const float DIVISOR = R2l ( R 1+R2 ) ;

analogRefe rence ( INTERNAL ) ; II set reference to internal ( 1 . 1V)


analogRead ( pi n ) ; II allow the ADC to settle
delay ( 10 ) ;

int value = 0 ;
fo r ( int i=0; i < 8 ; i++) {
value = value + analogRead ( pin ) ;
}
value = value I 8 ; II get the average of 8 readings
int MV = Map( value , 0 , 1023 , 0 , INTERNAL_REF ERENCE_MV I DIVISOR ) ;

analogRefe rence ( DE FAULT ) ; I I set the reference ba ck t o default (Vee)


analogRead ( pin ) ; II j u s t to let the ADC settle ready for next reading
delay( 10 ) ; II allow reference to sta balise

return Mv ;

II flashes 505 in Mo rse code


void flashCritical (int pin)
{
fo r ( int i=0; i< 3; i++ )
fla s h ( 20 , pin ) ;
fo r ( int i=0; i< 3 ; i++ )

226
Monitoring Battery Voltage

fla s h ( 60 , pi.n ) ;
for ( i.nt i.=0; i. < 3 ; i.++ )
fla s h ( 20 , pi.n ) ;

// pe rcent i.s the pe rcent of on ti.Me ti.Me (duty cycle)


voi.d flash ( i. nt pe rcent , i.nt pi.n )
{
Seri.al . p ri.nt( " , flash percent= " ) ; Seri.al . pri.ntln( percent ) ;
const i.nt d u r ati.on = 1000 ;
// Bli.nk the LED
di.gi.talWri.te( pi.n , HIGH ) ;
i. n t onTi.Me = Map(perce n t , 0 , 100 , 0 , dur ati.on ) ;
delay( onTi.Me ) ;
di.gi.talWri.te( pi.n , LOW ) ;
delay ( d u r a ti.on - onTi.Me) ;

There are two versions of the batte ryBegi.n function. Use the one with three
parameters if you have wired up the trickle charger circuit. The three param­
eters passed to the function are: the pin that the voltage divider is connected
to, the L ED pin, and the pin that detects the charger plug. Here is the function:
batteryBeg i. n ( alog BatteryPi.n , ledPi. n , ch argerDetectPi.n)

If you have not wired the robot to use a charger, then call batte ryBeg i. n with
two parameters: the pin that the voltage divider is connected to and the L ED
pin:
batte ryBeg i. n ( a logBatteryPi.n , ledPi. n )

The checking is done in the batteryCheck function. This gets the battery level
in millivolts by calling batteryMv and compares this to the warning and critical
thresholds. The L ED is flashed when the level drops below the warning level
with a flash ratio (blink on time to off time) that changes as the voltage drops.
If the voltage drops below the critical level, the robot movement is stopped,
and the L ED flashes a distress signal (SOS in morse code) every 5 seconds. When
this happens, the batteries must be replaced or recharged before the robot
will reactivate.
The l'lyrobotBa tteryMoni.to r example sketch (Example D-2) in the download
shows how to use the battery monitor function.

Example D-2. Battery monitor example sketch


/ ******************************************************************************
MyRobotBatteryMoni.to r . i.no

Appendix D 227
Monitoring Battery Voltage

s ketch to deMonstrate batte ry voltage Monito ring


based on MyRobotWa nder

Robot wand e r s using fo rwa rd scanning fo r obstacle avoid ance


LED blinks when battery runs low , robot goes to sleep when battery is critica l .

Created b y Michael Margolis 22 July 2012


****************************************************************************** /
#include " robotDefines . h " I I global defines

#include <AFMoto r . h> II adafruit Moto r shield library


#include " RobotMotor . h " II 2wd o r 4wd Motor library
con s t int ledPin = 13; I I onboa rd LED
con st i n t alogBatteryPin = S; II input on analog 5
con st int chargerDetected Pin 2; II digital pin 2
II Setup r u n s at startup and is used configure pins a nd init systeM va riables
void setup ( )
{
Seria l . begin ( 9600 ) ;
blinkNuMbe r ( B ) ; II open po r t while flashing . Needed for Leon a rdo only

lookBegi n ( ) ;
MOVeBegin ( ) ;
llbatteryBegin( alogBatteryPin , ledPin ) ;
batte ryBegin ( alogBatteryPin , ledPin , cha rgerDetectedPin) ;

pinMode( ledPin , OUTPUT ) ;


Serial . println ( " Ready " ) ;

void loop( )
{
I I roaM( ) ;
batte ryCheck ( ) ;

I I fu nction to indicate nuMbers by fla shing the built - i n LED


void blinkNuMbe r ( byte nuMbe r ) {
pi nMode ( LED_PIN , OUTPUT) ; II enable the LED pin for output
while ( nuMbe r - - ) {
digitalWrite ( LED_PI N , HIGH ) ; delay ( 1 00 ) ;
digitalWrite ( LED_PI N , LOW) ; delay (400 ) ;

228
Trickle Charging

Trickle Charging
The build chapters i n the begi nni ng of the book de scribed a simple trickle
cha rger that you ca n u se to recha rge NiMH batterie s. Thi s section de scribes
how to use the cha rger a s well a s some i m porta nt poi nt s to ensu re that yo u
d on't damage your batteries.
Trickle cha rg i ng i s a method of rechargi ng N i M H batte ries that provi de s a slow
but stea dy charg i ng cu rrent which shou l d fu lly recharge 5 AA cel ls i n a ro u nd
1 4 to 1 6 ho urs. The cha rger ha s been de signe d for cells with a rated capacity
of 2000 to 2500 mAh (mi l liam pere hou rs). Cells with a higher rating can be
u se d but the y will requ i re a longer cha rg i ng peri o d.

Do not try to charge non-rechargeable batteries.

The batterie s sta rt charg i ng when a DC power su ppl y i s plugged i nto the
cha rging socket a nd the power switch i s tu rned on. The cha rging circuit i s
d e signe d fo r u se with a 1 2 volt sup pl y with a 2.1 mm plug ( po sitive o n the
center co nnector) . Cells with the sugge ste d rati ng sho ul d ha ndle the trickle
cha rge cu rrent fo r long periods, however it is good practice to kee p you r cha rge
se ssion to 24 hou rs or l e ss, pa rticula rly if yo ur DC su pply cou ld be deliveri ng a
little m ore than the recom mended 1 2 volt s.

Appendix D 229
Programming Constructs

The code in this book takes advantage of a number of Arduino functions that
are summarized in this appendix. See the on line Arduino reference for each
function if you want more detail.

Digital 1/0
plnMode ( pln , Mode ) ;
Configures a digital pin to read (input) or write (output) a digital value; see
http://arduino.cc/en/Reference/PinMode
dlgltalRead ( pln ) ;
Reads a digital value (HIGH or LOW ) on a pin set for input; see http://ardu
ino. cc/en/Reference/Digita/Read
dlgltalWrlte ( pln , value ) ;
Writes the digital value (HIGH or LOW ) to a pin set for output; see http://
arduino.cc/en/Reference/Digita/Write
pulseln ( pln , pulseType , tlMeout ) ;
Returns the pulse width in microseconds of a changing digital signal on
the given pin. pu lseType (either H IGH or LOW ) determines if duration is
for a high or low pulse. tlMout is an optional value indicating how long to
wait for a pulse (the default is one second); see http://arduino.cc/en/Refer
ence/Pu/seln

231
Analog 1/0

Analog 1/0
analogRead ( pln ) ;
R ea ds a val u e from th e specifi ed a na log pi n. Th e val u e ra ng es from O to
1 023 for volta g es tha t ra ng e from 0 to th e reference voltag e (S volts by
defa ult, b u t ca n be ch ang ed by u si ng a nal ogReference; see http://ardui
no. cclen!Reference/An alo gRe ad

a nalogReference( type ) ;
C onfig u res th e referenc e volta g e used fo r a na log i nput. Thi s i s u sed i n th e
ba ttery m oni tor code di scu ssed i n Appendix D, Power Source s; see http://
arduino.ccle n/Referen ce/An alogReference

Math functions
l'li.n ( x , y ) ;
R eturns th e smaller of two num bers; see http://arduino. cc/en/
Reference/Min
l'lax( x , y ) ;
R eturns th e l arg er of two num bers; see http://arduino. cc!en!Referen ce/Max
constraln ( x , lower , upper ) ;
C onstra i ns th e valu e of x to b e b etween th e lower a nd upper range; see
http:/!arduino.ccle n!Refere nce!Constrain

l'lap ( x , frol'llow , frol'lHi.g h , destlow , destHi.gh ) ;


Scales a va lu e from one ra ng e to a noth er rang e. Th e resu lt will h a ve th e
sam e prop orti on wi thi n th e desti na ti on ra ng e a s i n th e sou rc e ra ng e. Th e
followi ng c ode sca les th e a na log Read valu e to a percentage of th e full
scale readi ng:
int val = a nalogRead ( 0 ) ;
int percent = Ma p ( val , 0 , 10 2 3 , 0 , 100)

Th e fol lowi ng code scales a n ana logRead valu e to i ts va lu e in milli volts


(refMv i s th e reference voltage ex pressed in m i ll i volts):
int MV = Map( val , 0 , 1023 , 0 , refMv ) ;

See http://arduino.cc!en!Reference!M ap

Other Functions and Constructs


swi.tch / case statel'lents
C ontrols prog ram flow by testi ng if a num b er matches one of a num ber of
a lterna ti ve valu es. H ere i s a sim plifi ed exam ple from th e rem ote control
sketch th at uses swi. tch to execute th e appropri ate func ti on associ ated
wi th eac h comm and:

232
Other Fu nctions and Constructs

void processCoMMand( int coMMan d )


{
switc h ( comand )
{
case MOVE_LEFT MOVeleft ( ) ; break;
case MOVE_R IGHT MoveRight ( ) ; break;
case MOVE_FORWARD Moveforwa r d ( ) ; break;
case MOVE_BACK MoveBackwa rd ( ) ; break;
case PIVOT_CCW MoveRotate ( - 90) ; break;
case PIVOT_CW MoveRotate ( 90 ) ; break;
case HALT MOVeStop( ) ; break;
}
}

The break statement i s necessary to prevent execut i on fa lli ng through t o


the followi ng case statement. S e e http://arduino.cc/en/Reference/Switch
Case

a r ray
An array i s a collecti on of va riables accesse d using a n index num ber. The
fi rst element of a n Ardui no a rray is accessed usi ng a n i n dex of 0. An array
can be i nitia lized when it is decla red by placi ng values in curly brackets.
The follow i ng decla res an array na med l'loto rSpeed with two elements that
will store the speed for the left a n d right mot ors a nd i nitia lize the speed
va lues to O:
con st int NUMB ER_OF_MOTORS = 2 ;
int MotorSpeed[NUMBER_OF_MOTORS] = { 0 , 0 } ; / / Moto r s peed stored here ( 0 - 100%)

see: http://arduino.cc/en/Reference/Array
#include " header . h "
Th is ma kes functi ons a nd va ria bles declared i n the specified file ava i lable
to your s ketch. See http://arduino.cc/en!Reference!lnc/ude

Append i x E 233
Arduino Pin and Timer
Usage F

The tables in this section show the pin and timer resources used by the projects
in this book. You can use the same pin assignments for the Leonardo boards
or the standard ATmega328 boards such as the Uno. However, there are subtle
low level differences between these boards, so if you are adding capabilities
that use additional pins or resources beyond those described in this book, then
check the documentation on pin and resource usage for your board.

Handling Resource Conflicts


The Arduino chip has a rich collection of hardware resources, but you can run
up against a conflict if a feature you are adding requires a hardware resource
that some other feature is already using. A resource conflict occurs when a
function reconfigu res or requires exclusive access to some hardware capability.
Running out of analog or digital pins is one kind of resource conflict, usually
easy to spot.
More subtle is a conflict caused by a library that requires a resource such a
hardware timer that is already used by some other function. For example, a
motor shield uses PWM to control motor speed and each motor requires a
timer component. Arduino tries to hide the underlying hardware (one of the
things that makes it easy to use) but this can result in things going wrong when
a resource conflict does occur. Sometimes the compiler will report a problem
with an error message about a resource conflict. But sometimes the sketch will
compile without an error message even though a resource conflict is prevent­
ing the code from functioning as expected.
For example, the infrared remote control library uses a timer to decode pulses
in the background. If this is the same timer used by some other function, say

235
Handl ing Resource Conflicts

the Ardui no S ervo library, one or both of th es e librari es will m alfu nction. Th e
solution is to eit her reassi g n one of the librari es to us e a different tim er, or to
fi nd an alternative way to p erform one of the functions without a tim er. Both
of th ese ap pro ach es will be d iscuss ed i n this appendix.

Modifying a Library to Change Timer Allocation


Modifyi ng a library is not a task for a begi nner, but some librari es are designed
to allow confi g u ration. For ex ample, th e l rRel'lote li brary used in Ch apter 1 1 ,
Rem ote Contro l h as a file nam ed i. rRel'lotel nt . h t h at can be edi ted to ch ang e
the tim er used by thi s library. H ere are fragm ents of this file t h at d etermi nes
th e ti m er used by the l ibrary:
// Leonardo or Teensy 2 . 0
#elif defined ( _AVR_ATMega32U4_)
/ /#define IR_US E_TIMERl / / tx = pin 14
// #define IR_US E_TIMER3 / / tx = pin 9
#define IR_USE_TIMER4_HS / / tx = pin 10

A nd furth er down th e fi le:


// Arduino DueMilanove , DiectMtla , LilyPad , Min i , Fie, etc
#else
/ /#define IR_USE_TIMERl // tx = pin 9
#defi ne IR_USE_TIMER2 // tx = pin 3
#endtf

Th efi rst co defrag m ent determ i nes th e tim er to be used with a Leo nardo bo ard
(th e Ardui no bui ld process w i l l use the code in this frag m ent if t h e chip is an
ATl'lega32U4). Th e uncomm ented li ne contai ns: #defi.ne IR_USE_TIMER4_HS
whi ch results in th e library usi ng Ti m er 4. However, Ti m er 4 is also used to
control one of th e motors i n th e 4WD robot. If you h ave th e 4WD robot and
w ant to us e th e i nfrared remote control library, you need to fi nd a free tim er
to use. Yo u can't easily ch ang e th e motor li brary because th e pin fo r Ti m er 4 is
h ard wi red to th e moto r control ler chip. But you can ch ang e th e remote tim er
by com m enti ng out th e l i ne fo r Ti m er 4 and uncomm enti ng a line th at enables
a free ti m er. Th e Leonardo h as 5 timers but as shown i n Table F-2, only Ti m er
1 is avail able. Th e code to dis able Ti m er 4 and enable Ti m er 1 is as follows:
// Leonardo o r Teensy 2 . 0
#elif defined (_AVR_ATMega32U4_)
#define IR_USE_TIMERl // tx = pin 14
// #define IR_US E_TIMER3 // tx = pin 9
// #define IR_US E_TIMER4_HS / / tx = pin 10

Usi ng your text edi tor to m ake and s ave th at ch ang e i n i. rRel'lotelnt . h will
eli m i nate th e conflict by usi ng Ti m er 1 i nstead of Tim er 4.
If your 4WD robot uses an Ardui no Uno, then th e ch ang e is to remove th e / /
com m ent ch aracters before th e I R_USE_ TIMER! l i ne and add th e com m ent
ch aracters before I R_US E_TIMERZ

236
Pin and Timer Tables

// Arduino DueMila nove , DieciMila , LilyPad , Min i , Fio, etc


#el se
#define I R_USE_TIMER1 // tx = pin 9
/ /#define I R_USE_TIMER2 // tx = pin 3
#endif

Writing Code That Avoids the U se of a Timer


Som etim es th ere is a conflict b ut no alternative resource to use. An exam pl e
of this is if your i nfrared remote li brary is usi ng Ti m er 1 (s ee previo us sectio n)
and you also want to use th e S ervo li brary, which also uses Ti m er 1 . If you h ave
th e 2WD robo t with a U no, th en you could use Tim er 2 for the remo te li brary
so th e Servo li brary can rem ai n on tim er 1 . Th ere are no free tim ers avai labl e
if you h ave a 4WD robot or th e 2WD robo t wi th a Leonardo board, but yo u can
solve this conflict by addi ng som e code th at controls the s ervo wi thout usi ng
a ti m er. S ee "Addi ng Scanni ng" (pag e 1 78) for an exam pl e of h ow this can be
done.

Pin and Timer Tables


Th e bes t way to h andle hardware conflicts is to plan i n advance by fam i li arizing
yours elf with th e reso urces currently in use and th e resources needed by th e
function yo u are add i ng. Th e tabl es i n this app end i x show th e ch i p pi ns and
ti m ers used b y th e proj ects i n this book. Althoug h you will h ave som e pi ns free
after co nnecti ng up all th e projects presented i n this book, th ere m ay not be
enoug h pi ns to connect all th e optional s ensors m entio ned in Ch apter 8, Tu­
torial: Introduction to Sensors along w i th some of th e sug g es tions i n th e ap­
pendices. Use Tabl e F- 1 and Table F-2 to keep track of your pi n and tim er al lo­
cations.
Table F-1. Pin Usage
Pin Usage Comment
Digital O Serial Receive
Digital 1 Serial Transmit
Digital 2 Unused Leonardo can use this for 12C
Digital 3 Motor 2 PWM limer 2b on Uno, limer Ob on Leo (Leo uses this for 12C)
Digital 4 Motor control
Digital 5 Motor 4 PWM limer Ob on Uno, limer 3a on Leo
Digital 6 Motor 3 PWM limer Oa on Uno, limer 4d on Leo
Digital 7 Motor control
Digital 8 Motor control
Digital 9 Scan Servo used in Chapter 1 0, Autonomous Movement
Digital 10 Distance Sensor used in Chapter 1 0, Autonomous Movement

Appendix F 237
P i n a n d T i mer Tables

Pin Usage Comment


----------------------
Digital 1 1 Motor l PWM Timer 2a on Uno, Timer Oa or le on Leo
----------------------
Digital 1 2 Motor control
----------------------
Digital 1 3 On-board LED This can be used as a digital pin if LED not needed
----------------------
----------------------
Analog O Left Reflectance Sensor
----------------------
Analog 1 Right Reflectance Sensor
----------------------
Analog 2 Center Reflectance Sensor
----------------------
Analog 3 IR Remote Decoder used in Chapter 1 1 , Remote Control
----------------------
Analog 4 Optional Battery Monitor Uno can use this for 12C
----------------------
Analog S Optional sound o r proximity sensor Uno can use this for 12C

Table F-2. Timer Usage

Timer Uno 2WD Uno 4WD Leo 2WD Leo 4WD


11mer 0 PWM for motors 3 & 4 PWM for motor 1 & 2 PWM for motor 1 & 2
----- -------------- -------------- ------------- -------------
11merl I R Remote IR Remote IR Remote IR Remote
----- -------------- -------------- ------------- -------------
11mer2 PWM for motors 1 &2 PWM for motors 1 &2 Not available Not available
----- -------------- -------------- ------------- -------------
11mer3 Not available Not available PWM for motor 4
----- -------------- -------------- ------------- -------------
11mer4 Not available Not available PWM for motor 3

238

You might also like