0% found this document useful (0 votes)
165 views82 pages

Controlling Motors Arduino

Uploaded by

Jon London
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
165 views82 pages

Controlling Motors Arduino

Uploaded by

Jon London
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 82

Controlling Motors

Book 3 of the Arduino Short Reads Series

Gary Hallberg

North Border Tech Training


First Edition
Copyright © 2020 Gary Hallberg and North Border Tech Training
All reserved. This book or any portion thereof may not be reproduced or used in any manner whatsoever
without the express written permission of the publisher except for the use of brief quotations in a book
review.
First Published, 2020
Contents
About the Arduino Short Reads Series ..................................................................................................... 5
Foreword.................................................................................................................................................... 6
Prerequisites for this Book ........................................................................................................................ 7
Download the Code ................................................................................................................................... 8
Chapter 1: DC Motors ................................................................................................................................ 9
Parts needed for this Chapter ................................................................................................................ 9
How a DC Motor Works ........................................................................................................................ 9
Controlling A DC Motor with a Transistor ........................................................................................... 11
Transistors ........................................................................................................................................... 12
General Purpose Diodes ...................................................................................................................... 14
Capacitors .............................................................................................................................................15
Experiment 1: Interfacing a DC Motor using a Transistor ................................................................. 16
Pulse Width Modulation ...................................................................................................................... 19
Experiment 2: Speed Control Using PWM ......................................................................................... 20
Summary .............................................................................................................................................. 22
Chapter 2: The H-Bridge ......................................................................................................................... 23
Parts needed for this Chapter .............................................................................................................. 23
The Principles of H-Bridge Operation ................................................................................................ 23
The L293D H-Bridge ........................................................................................................................... 24
Experiment 3: Direction and Speed Control using a H-Bridge .......................................................... 26
The HX1838 Infrared Remote Control and Receiver ......................................................................... 30
Experiment 4: IR Controlled Vehicle ...................................................................................................31
Troubleshooting Experiment 4 ........................................................................................................... 44
Summary .............................................................................................................................................. 44
Chapter 3: Servo Motors ......................................................................................................................... 46
Parts needed for this Chapter .............................................................................................................. 46
What are Servos? ................................................................................................................................. 46
Servo Operation ................................................................................................................................... 47
The SG90 9G Servo .............................................................................................................................. 48
The Servo Power Supply ...................................................................................................................... 49
Experiment 5: Servo Control using a Potentiometer .......................................................................... 50
The DHT11 Temperature and Humidity Sensor ................................................................................. 52
Experiment 6: A Servo based Thermometer ....................................................................................... 53
Summary .............................................................................................................................................. 57
Chapter 4: Stepper Motors ...................................................................................................................... 58
Parts needed for this Chapter .............................................................................................................. 58
Stepper Motor Operation .................................................................................................................... 58
The NEMA-17 Bipolar Stepper Motor ................................................................................................. 60
The L298N Dual H-bridge DC Stepper Motor Controller .................................................................. 61
The 28BYJ-48 Unipolar Stepper Motor and ULN2003 Driver Board ............................................... 63
Experiment 7: Basic Control of the NEMA-17..................................................................................... 65
Experiment 8: Basic Control of the 28BYJ-48.................................................................................... 68
Rotary Encoders ................................................................................................................................... 71
The KY-040 Rotary Encoder Module .................................................................................................. 72
Experiment 9: Controlling the 28BYJ-48 with a Rotary Encoder ...................................................... 73
Summary .............................................................................................................................................. 79
Epilogue ................................................................................................................................................... 80
About the Author ..................................................................................................................................... 81
About the Arduino Short Reads Series

The idea underpinning the Arduino short reads series is to provide a comprehensive, easy to follow
tutorial set and reference guide for anybody wanting to learn about Arduino and basic electronics.
Having a short reads series means that students and hobbyists can select key topics of interest in the
field with minimal outlay. The series aims to provide an easy introduction to all topics of interest and
expand on these topics to provide a broader and deeper understanding of that focus area. The books
are currently only available in Kindle format to provide a very inexpensive package backed up by video
content and interactive social media.
The series is aimed at youngsters and adults interested in getting into electronics and it takes a modern
approach combining the use of the inexpensive software driven Arduino controller board with a
multitude of sensors and discreet electronic components. The experiments in this series of books are
easy to follow, inexpensive to implement and compelling for all interested in STEM education. I hope
to inspire anybody looking for a future career in technology or to simply to have fun.
The first book of this series looks at the Arduino microcontroller and explains its operation and purpose.
Experiments look to show you how to set up the programming environment and drive LEDs as well as
read input from switches, thermistors and photocells. Book 1 will give you a solid foundation of how
some basic electronic components work and how to use them to make simple designs.
Books 4 and 5 in this Arduino short read series are still being written but the series focuses on the
following:
• Book 1 – First Steps with Arduino (published)
• Book 2 – Working with Displays (published)
• Book 4 – Range Finding, Object Detection and Object Avoidance
• Book 5 – Building a Simple Rover
There will be more books to follow the first 5 covering a wide range of focus topics so watch this space!

If you find this series of books useful then please leave your review and rating on
Amazon.
Follow North Border Tech Training on Facebook and Twitter for the latest news and
insights as to how this series will develop.
Foreword

Book 1 of this series sets out to provide a basic understanding of the Arduino platform, how to program
it and how to interface simple electronics. In this book we build on those skills in the focus area of
controlling the many types of motor.
I have been looking forward to writing this book. Motors and other actuators such as solenoids are an
essential component in any control system and using the Arduino to control these devices is a natural
marriage. Controlling motors from the Arduino does present us with some challenges in that the
Arduino cannot provide the power to drive a motor directly. Therefore, we need more in the way of
interfacing electronics. Furthermore, if you cut off the power from a spinning motor, its inductive
properties, and the fact that it will act as a generator, will necessitate extra electronics to protect the
Arduino and the interfacing circuitry. Therefore, there will be much more emphasis on the electronic
engineering aspects around the Arduino and this is a positive deviation from the other books in the
series.
I have no doubt the skills learnt here will allow you to develop more engaging and useful projects.
Without further delay let us get into the content.
Prerequisites for this Book

This book assumes you have read Book 1 of the series (’First Steps with Arduino’) or you already have
some experience of the Arduino platform, how to set up the IDE and undertake some basic Arduino
programming tasks. Basic functions such as ‘digitalRead’ and ‘digitalWrite’ are not covered here
but are explained in Book 1. We will revisit Pulse Width Modulation as it is an essential technology for
speed control of DC motors. Transistors too are an essential device and although they were covered in
book 2, they will be covered again here as the books in this series are intended be standalone, but with
the basics covered in book 1. We will introduce capacitors to readers who are new to electronics and are
following this series of books sequentially.
Download the Code

You can download the Arduino Code for the experiments in this book from GitHub using the link below.

https://github.com/ghallberg-nbtt/cautious-spoon
I recommend that you do this as I have removed some of the comments from the code in the book
listings to aid readability in print form. I strongly recommend that you comment your code heavily to
facilitate understanding and to become familiar with best engineering practice.
Chapter 1: DC Motors

Direct Current or DC motors are by far the easiest type of motor to work with and at the same time they
allow us to address all the issues of driving the motors from an Arduino board. They are common
devices in all sorts of equipment such as toys, radio-controlled cars and DVD players. As a result, they
are cheap. Therefore, they are a great place the start.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x 3-6V DC motor (<250mA power draw)
• 6V battery box (4 x AA) or main adapter
• 1 x PN2222 NPN Transistor
• 1 x 1N4001 diode (or similar 1A general purpose diode)
• 1 x 0.1uF capacitor
• 1 x 1KΩ resistor
• 1 x 10KΩ potentiometer
• Jumper wires

How a DC Motor Works


We will not go too much into the science behind the operation of the motor, but we will look at the
principle of operation. If you hold the thumb of your left hand straight up, then hold you index finger
straight out and then hold you middle finger perpendicular to those, you will be able to visualize the
physics behind the motor operation. Refer to Figure 1-1.
Figure 1-1: Electromagnetic Forces
Image source: The author
If you place a conductor such as a copper wire in magnetic field and then pass a current through that
wire a force will be asserted that will try and push the wire out of the field as depicted in Figure 1-1.
We can engineer a device (a DC motor) to utilize that force and create a rotary motion. Figure 1-2 shows
a simplified DC motor.
Figure 1-2: A Simplified view of a DC Motor
Image source: The author
A DC motor is built with permanent magnets within the motor body. In Figure 1-2 there is just 1 set. In
real motors there may be more sets. A commutator is connected to a copper coil and it is split into 2
halves. Power from a Direct Current source such as a battery connects to the commutator with
components called ‘brushes’ These just touch the commutator allowing it to spin freely. When the
current ‘i’ flows through the coil a force is asserted on the coil as indicated in Figure 1-2 and so the coil
rotates. The split communicator ensures that the direction of the forces is always in the same direction
and so we have a spinning motor.

Controlling A DC Motor with a Transistor


We must consider that motors are powerful devices and the Arduino I/O pin can only supply and sink
40mA of current. The small DC motor I will be using in the next experiment will draw about 250mA.
In book 2 we used a transistor to sink current from several LEDs to protect our Arduino board. Here
we will use a similar circuit. Book 1 covers resistors as they are such a fundamental component linked
to ohms law, but we will revisit the operation of transistors, and introduce rectifying diodes and
capacitors.
First, let us look at the circuit needed to interface a motor to an Arduino board. This is shown in Figure
1-3. We will then go on to explain its operation.
Figure 1-3: Interfacing Electronics for the DC Motor
Image source: The author

Transistors
You can consider a transistor as a voltage-controlled switch. They also have applications as amplifiers,
but we will not cover that area in this book. Transistors come in many forms, but we will be using the
most common Bipolar Junction Transistor (BJT). Figure 1-4 shows the symbol for a BJT Transistor.
They come in two forms NPN and PNP. We will be using the NPN type.

Figure 1-4. Symbols for BJT Transistors


Image source: The author
Figure 1-3 shows a typical configuration for a transistor acting as a voltage-controlled switch.
Operation is quite simple. When the Arduino pin is set ‘LOW’, there will be no voltage applied to the base
of the transistor. In that situation, no current will be allowed to flow from the collector of the transistor
to the emitter. If we set the Arduino pin to a ‘HIGH’ state, a voltage of about 5V will be applied to the
base of the transistor. When this occurs current can flow freely between the collector and the emitter of
the transistor powering the motor. The current needed to turn the transistor on is small. The 1KΩ
resistor means this current will be in the order of 4mA and well within the capability of the Arduino
pin. A small transistor can pass in the order of 600mA between the collector and the emitter and so can
cope with the 250mA of the small motor I will be using. If we used a PNP transistor in place of the NPN
transistor, the operation would be the opposite. A low signal will turn on the transistor and a high signal
will turn it off.
We will be using the PN2222 general purpose NPN transistor. General purpose means it can be used
for both switching and amplification applications. Figure 1-5 shows the pinouts for this device. Be sure
to connect the collector, base and emitter correctly and ensure you have the resistor in place, or you
may damage your Arduino board and the transistor itself. If you are using a different type of transistor,
then ensure you should check the datasheet for the pinouts as they may vary.
Figure 1-5: The PN2222 Transistor Pinouts
Image source: The Web (public domain) with annotations by the author

General Purpose Diodes


We have worked a lot with Light Emitting Diodes (LEDs) in the previous books and in principle they
are the same devices as general purpose diodes. All semiconductors emit light when passing current
and the LED is engineered to optimize this property. This comes at the expense of the forward voltage
drop that is about 2-3V compare to a general purpose diode that has a forward voltage drop of about
0.7V. Although we could use an LED for general purpose applications, the large forward voltage drop
means it would not be particularly good. Furthermore, they can only pass a limited amount of current.
General purpose diodes are used for two applications. These are rectification to covert AC voltage to DC
voltage and for use as ‘flyback diodes’. Flyback diodes are also called ‘snubber’ or ‘freewheeling diodes’.
In Figure 1-3 we are using the diode in the flyback application and we will look at that later.
Diodes are the simplest of semi-conductors. They are usually made from silicon but can also be made
from germanium and selenium. The electrical symbol for a diode is shown in Figure 1-6 along with an
image of a general purpose diode. The Cathode is identified by the band at the end of the body.

Figure 1-6: The Symbol for a Diode with an Image of a Device


Image source: The author
The diode has 2 terminals. If the Anode is connected to a positive supply and the Cathode connected to
a negative supply or ground, the diode will pass current. If connected the other way round, the diode
will block current.
So why do we need a flyback diode in our circuit? A DC motor has coils and so is an inductive load.
When power is suddenly removed from an inductive load, it creates a large voltage spike that can
damage the components. In normal motor operation the positive voltage will not pass through the diode
as the Cathode is connected to the positive supply. If the power is removed, the motor will generate a
reverse voltage spike and the Anode of the diode will be positive compared to the Cathode. The diode
will conduct. It will behave like a short circuit across the motor and suppress the reverse voltage.

Capacitors
Those who started with Books 1 and 2 of this series would not have been introduced to capacitors. So,
what is a capacitor? It is essentially a device that stores electrical energy. They are two terminal devices
and made from many types of material. All capacitors consist of at least 2 plates with a tiny gap between
each plate. This gap can be air, or some other insulating material called the dielectric as indicated in
Figure 1-7.

Figure 1-7: A Diagrammatical Representation of a Capacitor


Image source: The author
When a positive voltage is applied to one plate it will hold a positive charge and the other will hold a
negative charge. Aside from storing a charge, capacitors are used in electrical filters such as found in
radio tuning circuits and to smooth fluctuations in voltage supplies (also referred to as decoupling). The
electrical symbol for a capacitor is shown in Figure 1-8 but note there are variations in this symbol to
represent different capacitor types. Also, in Figure 1-8 are some images of capacitors.

Figure 1-8: The Symbol for a Capacitor and an Image of various types
Image source: The author
The capacitance is measured in Farads and is a measure of the component’s ability to store electrical
charge. Farad is named after the English physicist Michael Faraday. The value of capacitance is stamped
on the body of the component. In our circuit we need a 0.1uF capacitor. The number ‘104’ will usually
identify the capacitor as 0.1uF. Just like resistors, it is a good idea to check the component using a
component tester as the values are often hard to read.
DC motors are electrically noisy, and the capacitor is there simply to filter out that noise (decoupling
application).

Experiment 1: Interfacing a DC Motor using a Transistor


Now that we have discussed how to interface a DC motor to the Arduino, it is time to test it. I will be
using small DC motor found in many toys and is shown in Figure 1-9.

Figure 1-9: A small DC Motor that will be used in Experiments 1 and 2


Image source: The author
Next build the breadboard layout as shown in Figure 1-10.
Figure 1-10: The Breadboard Layout to Control a Motor with a Transistor
Image source: Created with Fritzing
You need to consider how to power the Arduino board such that it can deliver sufficient voltage and
current to the motor. We could use a separate power supply just for the motor and use the standard 5V
USB to power the Arduino board. Using 2 separate power inputs is not efficient and is unnecessary. An
option is to use the barrel input of the Arduino board. This will take an unregulated 7-12VDC supply.
This input is connected to the onboard 5V regulator so it will power the Arduino board. The positive
central pin of the barrel connector is directly connected to the Vin pin of the Arduino. This means the
unregulated supply can be fed to the breadboard as in Figure 1-10 and supply the power associated with
the external power source. That power source could be a mains adapter set at 6VDC or set of batteries.
Of course, if your motor is of a different voltage rating then set the power source to that voltage,
provided it does not exceed 12V.
Given that the central positive pin of the barrel connector is connected to the Vin pin of the Arduino
board, you can power the experiment by the method shown in Figure 1-11. If the battery box you are
using only has bare wires, it can be located in the breadboard as in the figure. The jumper connecting
the positive supply bus to the Arduino Vin pin will then power the board.

Figure 1-11: Powering the Arduino from the Breadboard


Image source: The author
Next simply load or type in the Sketch as in Listing 1-1.
/*
Controlling a Motor using a Transistor
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/
const int MOTOR = 3; //pin for motor control

void setup() {
pinMode (MOTOR, OUTPUT); //set pin 3 for output
}

void loop() {
digitalWrite (MOTOR, HIGH);
delay (2000); //turn on motor for 2 seconds
digitalWrite (MOTOR, LOW);
delay (2000); //turn off motor for 2 seconds
}

Listing 1-1: The Sketch to Power the DC Motor


Listing source: The author
The Sketch is basic. It turns the motor on for 2 seconds and then off.
Some limitations should come to mind. The motor only runs at full speed and the direction cannot be
changed. In Experiment 2 we will look at how to control the speed using Pulse Width Modulation and
in Chapter 2 we will look at how to change the motor’s direction.

Pulse Width Modulation


Ideally, we would want to have the ability to set an analog voltage onto a pin and control the speed of
the motor in the normal way by increasing and decreasing that voltage. The issue here is that we cannot
write an analog voltage to a pin of an Arduino Uno. The Arduino Duo does have a Digital to Analog
converter on board, but the Uno does not. However, we do have available a clever technique called Pulse
Width Modulation (PWM). This can be used to trick the eyes and brain into thinking the brightness of
a component such as an LED is being controlled by an analog voltage. PWM can also be used to control
the speed of a DC motor.
So, what is PWM? Essentially, what we do is allocate a regular period over which we want the Arduino
pin to be in a high state. The Pulse Width is a measure of the time that the pin is set high over that
period. We call this the duty cycle of the waveform. Figure 1-12 illustrates the scenario of 0%, 25%, 50%,
75% and 100% duty cycle.
Figure 1-12: A Diagram showing PWM Duty Cycle
Image source: The author
We can see that for a duty cycle of 0%, the pin is set low, for 25% the pin is high 25% of the time so on
an so forth until we have a duty cycle of 100% when the pin is constantly high. So, we can see that the
output voltage is not analog but is either high or low. What this means is that we accelerate the motor
for a short period and before it gets to full speed, cut the power off and the momentum keeps the motor
spinning and we simply ‘kick it on’ with the next pulse. The narrower the pulse, the slower the motor
will spin. The PWM period within the Arduino is about 2ms. This equates to a frequency of 500Hz.

Experiment 2: Speed Control Using PWM


In this experiment, we will build on the circuit used in Experiment 1 to add a potentiometer. This will
act as the speed controller. Potentiometers were covered in Book 1 and use an analog input pin of the
Arduino to connect the wiper. You could connect a fan to the motor and a thermistor in place of the
potentiometer, and using the same Sketch, you have a temperature-controlled fan. I will be using a
piece of tape around the motor shaft to easily see the speed changes.
The modified layout is shown in Figure 1-13.
Figure 1-13: The Breadboard Layout to Control the Speed of the Motor
Image source: Create with Fritzing
Now copy or type the Sketch as in Listing 1-2.
/*
Speed Control of a DC Motor using PWM
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/
const int MOTOR = 3; //pin for motor control
const int POT = 5; //A5 pin
int speed = 0; //variable for the speed

void setup() {
pinMode (MOTOR, OUTPUT); //set pin 3 for output
}

void loop() {
speed = analogRead (POT); //read the pot value
speed = map (speed, 0, 1023, 0, 255); // Map the ADC value to PWM value
analogWrite(MOTOR, speed); //change speed of motor
delay (50);
}

Listing 1-2: The Sketch to Control the Motor Speed


Listing source: The author
The ‘analogWrite’ and ‘map’ functions were covered in Book 1, but we will touch on them here.
We need to connect the wiper of the potentiometer to an analog pin. These are A0 to A5 on the Arduino
board. You will have noticed that we chose pin 3 to control the transistor. This pin and pins 5, 6, 10 and
11 on the Uno are marked with a tilde symbol ‘~’. This means these pins can support PWM outputs and
we control the outputs with the ‘analogWrite’ function. The PWM duty cycle is defined by the
argument we pass to ‘analogWrite’ and is between 0 and 255. 0 being 0% and 255 being 100%.
We need to map the value of the potentiometer to a PWM duty cycle value. The potentiometer value
will be between 0 and 1023 since we have a 12-bit Analog to Digital Converter (ADC) within the Arduino
Uno. We can use the ‘map’ function to do this mapping. The value of the speed is the potentiometer
reading. This is held in the ‘speed’ variable. We pass this value to the ‘map’ function and its usage is
shown below:
map(value, fromLow, fromHigh, toLow, toHigh)
In our experiment ‘value’ will be ‘speed’, ‘fromLow’ will be 0, ‘fromHigh’ will be 1023, ‘toLow’ will
be 0 and ‘toHigh’ will be 255. We can reuse the variable ‘speed’ for the new value. The ‘map’ function
is not bound in that if we went negative with ‘value’ or exceeded the maximum, the ‘map’ function
would work out a proportionate new value. We can use the ‘constrain’ function to impose bounds,
but this is not needed in this case since the ADC of the UNO has bounds between 0 and 1023.
You can see a video demonstration of this experiment here (https://youtu.be/z3UFlcL-Vos). We will go
on to look at directional control in the next Chapter.

Summary
In this chapter you learnt about the basic operation of a DC motor. You were introduced to transistors,
capacitors and general purpose diodes. You learnt how to interface the motor to the Arduino board to
protect it and protect the electronics from flyback currents.
You learnt about Pulse Width Modulation and how to use the technology to control the speed of a DC
motor.
Chapter 2: The H-Bridge

We cannot generate a negative voltage from the Arduino board to reverse the direction of the motor.
But what we can do is reverse the polarity of the supply by using a device called a H-Bridge. In this
chapter we will look at the H-Bridge and explore its operation.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x 3-6V DC motor (<250mA power draw)
• 1 x 2 wheel robot car chassis with geared DC motors
• 1 x L293D H-Bridge
• 1 x HX1838 IR remote and receiver set
• 1 x 6V battery or mains adapter (will be discussed later)
• 1 x 10KΩ potentiometer
• 1 x pushbutton switch
• Jumper wires

The Principles of H-Bridge Operation


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

The L293D H-Bridge


This device is likely to be your first introduction to the H-Bridge. It is a 16-pin dual in Line IC with dual
H-Bridges so, as well as being low cost, it is ideal for driving 2-wheeled vehicles. This device can support
loads of up to 600mA, well within the demands of our small DC motors.
Figure 2-2 shows the pinouts of this device and how it should be connected to the Arduino and motor.
Note that some manufacturers label the pins differently, but their function and position will be the
same.
Figure 2-2: The L293D H-Bridge and Connectivity
Image source: The author
The device is split into a right-hand and left-hand driver. The +5VDC logic supply from the Arduino is
connected to pin 16. A separate motor supply will be connected to pin 8. Pins 4, 5, 12 and 13 are all
connected to ground and this arrangement also helps dissipate heat from the device. Outputs 1 and 2
(pins 3 and 6 respectively) are outputs to which a motor is connected. Likewise, for Outputs 3 and 4
(pins 11 and 14 respectively). Inputs 1 and 2 (pins 3 and 7 respectively) control the right-hand H-Bridge
with digital I/O pins from the Arduino. Likewise, Inputs 3 and 4 (pins 10 and 15 respectively) control
the Left-hand H-Bridge. The left-hand and right-hand H-Bridges each have an enable input on pins 1
and 9, respectively. By holding these low, we can disable the H-Bridge and protect the electronics. We
can also use PWM on these pins to turn the H-Bridge on and off to control the speed of the motor.
You may be wondering how 2 inputs can control 4 voltage-controlled switches. With 2 inputs there are
4 possible logic combinations. The way these logic inputs map to H-Bridge switch connection is shown
in Table 2-1.
Input 1 Input 2 Action
LOW LOW Brake
LOW HIGH Reverse
HIGH LOW Forward
HIGH HIGH Freewheel

Table 2-1: Actions Associated with H-Bridge Inputs


Clearly, the directions shown here are nominal, but it does lead us into the next experiment.
Experiment 3: Direction and Speed Control using a H-Bridge
In this experiment will control a single DC motor with a H-Bridge using the potentiometer to control
the speed and a pushbutton switch to control the direction.
First build the breadboard layout in Figure 2-3.

Figure 2-3: The Breadboard Layout for Controlling a Motor with an H-Bridge
Image source: The author
We can structure the code by creating functions to control the motor direction and speed. We need 3
functions: forward, reverse and brake. These are shown below:
//Drive motor forward at the specified speed (0 – 255)
void forward (int speed)
{
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, HIGH);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, speed); //PWM to drive motor
}
//Drive motor backward at the specified speed (0 – 255)
void reverse (int speed)
{
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, HIGH);
analogWrite (ENABLE1, speed); //PWM to drive motor
}
//Stop motor
void brake ()
{
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT1, LOW);
analogWrite (ENABLE1, HIGH); //Brake motor
}
You must always disable the H-Bridge before changing the state of the internal switches. The
‘analogWrite’ function is used to enable the H-Bridge with the given PWM duty cycle, so controlling
the speed. We only need pass that speed to each function as an integer argument from the main loop.
The speed will be controlled by the potentiometer.
In the full Sketch, we will first read the state the switch to change direction if a ‘HIGH’ to ‘LOW’ transition
is detected. The switch will need to be debounced. Debouncing was covered in Book 1, but there will be
a brief explanation here. The Sketch will then read the value of the potentiometer and the appropriate
function will be called to control the motor direction, i.e. forward, reverse or brake. We will call the
‘brake’ function if the potentiometer value is 10 or less. Listing 2-1 shows the full Sketch.
/*
Controlling a Motor using a H-Bridge
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/

const int ENABLE1 = 3;


const int INPUT1 = 4;
const int INPUT2 = 5;
const int SWITCH = 6;
const int POT = 0;
int speed = 0;
// Variable containing the previous button state
boolean previousButton = HIGH;
// Variable containing the current button state
boolean currentButton = HIGH;
boolean goForward = true; //Set initial direction as forward

void setup() {
pinMode (ENABLE1, OUTPUT);
pinMode (INPUT1, OUTPUT);
pinMode (INPUT2, OUTPUT);
pinMode (SWITCH, INPUT_PULLUP);
brake (); //Stop motor
}

void loop() {
//Read the switch to check for direction toggle
currentButton = digitalRead(SWITCH); // Read the switch state

if (previousButton != currentButton) // If switch pressed


{
delay(5); // Wait 5ms
currentButton = digitalRead(SWITCH); // Read switch again
}
// Detect a button press
if (previousButton == HIGH && currentButton == LOW)
{
goForward = !goForward; // Change direction
}
previousButton = currentButton; // Reset button value

//Read the potentiometer


speed = analogRead (POT);
speed = map (speed, 0, 1023, 0, 255);
if (speed <= 10) {
brake();
} else {
if (goForward == true) {
forward (speed);
} else {
reverse (speed);
}
}
}
//Drive motor forward at the specified speed (0 – 255)
void forward (int speed)
{
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, HIGH);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, speed); //PWM to drive motor
}

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


void reverse (int speed)
{
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, HIGH);
analogWrite (ENABLE1, speed); //PWM to drive motor
}

//Stop motor
void brake ()
{
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, HIGH); //Brake motor
}

Listing 2-1: The Sketch to Control the Motor with a H-Bridge


Listing source: The author
We only need focus on the main function. The first task is to scan the switch to see if is depressed and
hence, changing direction of the motor. We need to debounce the switch. A switch is a mechanical
device and so the contacts will bounce, making and breaking the contacts before it settles. The program
loop is scanning so fast it can detect the bounce conditions and so will switch the direction of the motor
for each bounce. We want to read the switch reliability. The process is simple. We read the switch and
if the current state is not equal to the previous it means that the switch has been depressed. In that
situation we simply wait 5ms for the contacts to settle and then read it again. 5ms is enough time to
eliminate the bounce. We must set the previous button state to the current button state otherwise the
code will constantly toggle the direction. The code for reading the switch and debouncing is shown
below and there is a video with more on the subject here (https://youtu.be/cF8lq5sEV48).
//Read the switch to check for direction toggle
currentButton = digitalRead(SWITCH); // Read the switch state

if (previousButton != currentButton) // If switch pressed


{
delay(5); // Wait 5ms
currentButton = digitalRead(SWITCH); // Read switch again
}
// Detect a button press
if (previousButton == HIGH && currentButton == LOW)
{
goForward = !goForward; // Change direction
}
previousButton = currentButton; // Reset button value

We then read the value of the potentiometer to establish the speed and map the potentiometer reading
to the PWM limits.
speed = analogRead (POT);
speed = map (speed, 0, 1023, 0, 255);

The final part of the code calls the appropriate directional function based on the limits we set for the
braking, speed and direction.
if (speed <= 10) {
brake();
} else {
if (goForward == true) {
forward (speed);
} else {
reverse (speed);
}
}

It really is as simple as that.


I think we cannot move on from DC motors before building a simple vehicle. In Book 5 we will build an
autonomous vehicle that will avoid obstacles. For now, we will build a simple remote-controlled vehicle.

The HX1838 Infrared Remote Control and Receiver


We will be using the HX1838 IR remote transmitter and receiver pair for this Experiment. These are
extremely low-cost devices and very versatile. The button arrangement may be different between styles
of remote and the transmit codes associated each remote may be different. There is a handy Arduino
library that makes programming easy, but you will need to interrogate the remote to get the correct
codes for your type. An image of the HX1838 set is shown for your reference in Figure 2-4.
Figure 2-4: The HX1838 IR Remote and Receiver Set
Image source: The Web (public domain)
The IR receiver we are using has a photocell on board. The difference between this photocell and the
LDR used in Book 1 is that the IR receiver is tuned to sense Infrared light which is just outside of the
visible spectrum. The LDR is tuned to detect yellow and green visible light. Another major difference is
that the IR receiver has a demodulator onboard. Simply shining an IR beam at the receiver will not have
any effect. They require pulses of light to work with a frequency of 38KHz.
There are many codes used by different manufacturers of remote such a Panasonic, Sony and NEC.
Luckily, the Arduino library supports many implementations and so you could use the Sketch we are
going to write to see the codes from the remotes for your domestic appliances.

Experiment 4: IR Controlled Vehicle


Let us move on to the experiment. The IR receiver we will be using has 3 pins. One for the +5v supply,
one for the 0V and one for data as shown in Figure 2-5.

Figure 2-5: The IR Receiver Pinouts


Image source: The author
What you need to do now is to get the codes from your IR remote and make a note of them. We can do
this with a simple layout and Sketch. I will be using the buttons on my remote as shown in Figure 2-6.

Figure 2-6: The Buttons Allocated to Control the Motor


Image source: The author
Next build the layout as in Figure 2-7.

Figure 2-7: The Layout to Scan the Remote


Image source Created with Fritzing
Now load or type in the Sketch shown in Listing 2-2. You will need to load in the ‘IRremote’ library
written by Shirriff and z3to. Note I used version 2.6.1.
Those who have read Book 2 would have been introduced to libraries and Object-Oriented
programming. These make our tasks much easier. For those joining straight into this book, what follows
is a brief explanation. Those who read Book 2 can skip this part.
Object-Oriented programming certainly leads to more reliable, simple and scalable code. It has not
always been the case. When I started programming there was no Object-Oriented approach and things
were far more complex and problematic. So, what is Objected-Oriented Programming? The best way I
can explain to someone who has never been exposed to it is to draw and analogy with the physical world.
Let us say you run a business that paints wooden chairs. You paint chairs red, white or blue only. If the
world were not Object-Oriented, you would also have the source the materials for every chair, shape
them and construct every chair before painting it. That is a complex and inefficient way to do business.
In an Object-Oriented world, you would buy in each chair ready assembled and simply customize it
with the color. That is a much simpler activity where you focus on your core business.
Object-Oriented Programming is the same. The object we are interested in is the IR remote receiver.
You could develop the functions from scratch to control the receiver in your Sketch and repeat that
process for every Sketch that needed an IR remote. This would be time consuming for you and you
would have much more to support if it were part of a commercial product. Alternatively, you could
import a predefined library that has an object for the IR receiver and associated functions to customize
it. Customization is this case would be to understand the codes from the remote and act on them. We
will use an external library to do this for this experiment.
First open a new Sketch. You then need to load the ‘IRremote’ library. To do this select Tools >
Manage Library. A window will pop up with a search bar at top. Type in ‘IRremote’ and press enter.
Several options for suitable libraries will pop up. I am using the one written by Shirriff and z3to. Figure
2-8 shows the Library Manager window.
Figure 2-8: The Arduino IDE Library Manager
Image source: The Arduino IDE
If you hover your mouse over the library, then you will see an install button appear. Simply click this to
install the library. If you click on ‘more info’ you will be taken to the Github repository where you can
find instructions for how to use the library with some examples.
Now type in or copy the Sketch as shown in Listing 2-2.
/*
Reading IR Remote Codes
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/

#include <IRremote.h>

const int RECEIVER = 2;

/*-----( Declare objects )-----*/


IRrecv irrecv(RECEIVER); //Create instance of 'irrecv'
decode_results results; //Create instance of 'decode_results'

void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
irrecv.blink13(true); // flash built in LED
}

void loop() {
if (irrecv.decode(&results)) // have we received an IR signal?
{
Serial.println(results.value, HEX);
irrecv.resume(); // receive the next value
}
}

Listing 2-2: The Sketch to Interrogate the Remote Control


Listing source: The author
We include the library to allow the Sketch to access the classes and functions in that library.
#include <IRremote.h>

This would be the first time I have mentioned Classes. Classes differ from functions in that functions
do things and Classes are things or objects. Classes have functions associated with them. The Classes
or objects we need within the library are for the IR receiver and a container for the results.
We first create an object of the IR receiver class in our main Sketch and pass the Arduino I/O pin
number as an argument. We do not need to set the ‘pinMode’ as input as the ‘IRremote’ library does
that for us. ‘IRrecv’ is the name of the Class we need to reference. ‘irrecv’ is the object name we gave
for that reference and ‘RECEIVER’ is the argument (the integer value 2).
IRrecv irrecv(RECEIVER);

Each time we want to access a function in that class, we precede it with ‘irrecv’ followed by the name
of the function.
Next, we want to create an object of the ‘decode_results’ class and we called the object ‘results’.
decode_results results;

In the ‘setup’ function, we initialize the serial monitor, start the receiver, and enable the LED built
into the Arduino board to flash when data is being received.
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
irrecv.blink13(true); // flash built in LED

It is then simply a case looping until we receive a signal and print that result to the serial monitor in
hexadecimal format.
if (irrecv.decode(&results)) // have we received an IR signal?
{
Serial.println(results.value, HEX);
irrecv.resume(); // receive the next value
}
Run the Sketch and open the serial monitor. The output obtained from my remote is shown in Figure
2-9.

Figure 2-9: The Serial Monitor Output Showing the Remote Codes
Image source: The author
We have the following codes for our final Sketch
• FF629D – Up arrow: forward
• FFA857 – Down arrow: reverse
• FFC23D – Right arrow: turn right
• FF22DD – Left arrow: turn left
• FF02FD – OK button: stop
• FF6897 – Number 1: low speed
• FF9867 – Number 2: medium speed
• FFB04F – Number 3: top speed
You may be wondering what the ‘FFFFFFFF’ codes are. These are repeat codes and can be ignored. Bear
in mind that the program is scanning extremely fast and it will detect that a button is still depressed on
the second pass. The ‘decode_results’ class will return the code ‘FFFFFFFF’ so that we only act on
the first detected button press.
Before developing the final Sketch, let us look at the vehicle chassis.
Figure 2-10 is an image of the chassis kit I am using. This style of kit is common and inexpensive. I have
gone for the two-wheel drive version to save cost and allow us to use the existing H-Bridge. This kit has
the advantage that is has pre-drilled holes in the acrylic with spacing suitable for mounting many types
of sensor such as object detection and white line following sensors as well as Arduino and Raspberry Pi
boards. Any premade, 2 wheeled chassis will do the job, or you can make your own. The key is to use
geared motors. A DC motor can spin at up to 4000rpm. We can convert that energy into torque at the
wheels using a gearing system and be able to carry greater loads or work in rougher terrain. The motors
I am using have a 48:1 gear reduction. They draw 160mA and so will work with the L293D H-Bridge.
Make sure the motors you use are within the 600mA limit of the L293D H-Bridge. If you want to take
a closer look at this chassis kit and another I have, then you can watch the video here
(https://youtu.be/r9DWmWnpvdo).

Figure 2-10: The Motor Chassis for this Experiment


Image source: The author
Next build the breadboard layout for the vehicle as in Figure 2-11. Figure 2-10 shows 4 x AA type cells
to form a 6V battery. This type of battery must be of high quality and new if they are to power this type
of chassis for some time. You can use a pair of lithium-ion ICR18650 cells in place of AA cells. This is
an effective, but expensive option. Another approach is to use a 9V PP3 battery, but that too must be
new and of good quality. There will be more about using the PP3 in the troubleshooting section
associated with this experiment.
Figure 2-11: The Breadboard Layout for our Vehicle
Image source: Created with Fritzing
Figure 2-12 shows the finished vehicle. The components are simply held in place with an elastic band.
Figure 2-12: The Finished IR Controlled Vehicle
Image source: The author
We can now create the complete Sketch as shown in Listing 2-3. There is no need to review the Sketch
in detail as it reuses much of the H-Bridge code. However, be sure to follow it through and make sure
you understand each step.
/*
IR Controlled Vehicle
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/

#include <IRremote.h>
//Remote code definitions
const long FORWARD = 0xFF629D;
const long REVERSE = 0xFFA857;
const long RIGHT = 0xFFC23D;
const long LEFT = 0xFF22DD;
const long STOP = 0xFF02FD;
const long LOW_SPEED = 0xFF6897;
const long MEDIUM_SPEED = 0xFF9867;
const long TOP_SPEED = 0xFFB04F;
//pin assignments
const int RECEIVER = 12;
const int ENABLE1 = 6;
const int INPUT1 = 4;
const int INPUT2 = 5;
const int ENABLE2 = 9;
const int INPUT3 = 7;
const int INPUT4 = 10;

//variables
int vehicleSpeed = 150;
long remoteCode = 0;
String direction = "stop";

/*-----( Declare objects )-----*/


IRrecv irrecv(RECEIVER); //Create instance of 'irrecv'
decode_results results; //Create instance of 'decode_results'

void setup() {
pinMode (ENABLE1, OUTPUT);
pinMode (INPUT1, OUTPUT);
pinMode (INPUT2, OUTPUT);
pinMode (ENABLE2, OUTPUT);
pinMode (INPUT3, OUTPUT);
pinMode (INPUT4, OUTPUT);
Serial.begin(9600); //Only needed for troubleshooting
irrecv.enableIRIn(); // Start the receiver
irrecv.blink13(true); // flash built in LED
brake ("left");
brake ("right");
}

void loop() {
//First read the remote
if (irrecv.decode(&results)) // have we received an IR signal?
{
remoteCode = results.value;
switch (remoteCode) {
case (FORWARD): {
Serial.println ("Forward");
forward ("left", vehicleSpeed);
forward ("right", vehicleSpeed);
break;
}
case (REVERSE): {
Serial.println ("Reverse");
reverse ("left", vehicleSpeed);
reverse ("right", vehicleSpeed);
break;
}
case (RIGHT): {
Serial.println ("Right");
forward ("left", 255);
forward ("right", 150);
break;
}
case (LEFT): {
Serial.println ("left");
forward ("left", 150);
forward ("right", 255);
break;
}
case (STOP): {
Serial.println ("Stop");
brake ("left");
brake ("right");
break;
}
case (LOW_SPEED): {
Serial.println ("Low speed");
vehicleSpeed = 150;
break;
}
case (MEDIUM_SPEED): {
Serial.println ("Medium speed");
vehicleSpeed = 200;
break;
}
case (TOP_SPEED): {
Serial.println ("Top speed");
vehicleSpeed = 255;
break;
}
}
irrecv.resume(); // receive the next value
}
delay (50);
}

void forward (String motor, int speed)


{

if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, HIGH);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, speed); //PWM to drive left motor
Serial.println (speed);
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, HIGH);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, speed); //PWM to drive right motor
Serial.println (speed);
}
}

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


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

//Stop motor
void brake (String motor)
{
if (motor == "left") {
digitalWrite (ENABLE1, LOW); //Disable H-Bridge
digitalWrite (INPUT1, LOW);
digitalWrite (INPUT2, LOW);
analogWrite (ENABLE1, HIGH); //Brake left motor
} else {
digitalWrite (ENABLE2, LOW); //Disable H-Bridge
digitalWrite (INPUT3, LOW);
digitalWrite (INPUT4, LOW);
analogWrite (ENABLE2, HIGH); //Brake right motor
}
}

Listing 2-3: The Sketch to Control our Vehicle


Listing source: The author with library functions by Shirriff and z3to
We have assigned constants to the IR codes and assigned extra pins for the second motor. The functions
to control the motor direction have been modified to control each motor independently. We pass a
second argument to identify the motor as well as the speed. The IR code is reused from the previous
Sketch.
This will be the first time in this series of books that you would have seen the ‘switch’ and ‘case’
statement. In short, the ‘switch’ and ‘case’ is an alternative way of presenting nested ‘if elseif’
statements. It does the same thing but is far neater and easier to read, so I encourage you to use it if
there are to be many ‘case’ conditions.
We need to present a variable to the ‘switch’. In our example it is the ‘remoteCode’. The Sketch looks
down the list of ‘case’ statements and executes the block of code when there is a match. The ‘break’
ensure that the statement terminates when the block of code finishes and the program will resume after
the ‘switch’ block. In our Sketch there is always a match but if there is not, just like the ‘else’
statement, you can add the ‘default’ keyword as the last ‘case’ block.
switch (var) {
case label1:
// statements
break;
case label2:
// statements
break;
default:
// statements
break;
}
The speeds are preset at 255, 200 and 150 for top, medium and slow respectively. These values will have
to be tuned to your motors as all motors are different. I found that 110 was the minimum speed that
would reliably overcome the inertia created by my vehicle. Within each case block, the appropriate
directional function is called for each motor in turn and the speed is also passed as an argument.
You can see a video demonstration of the IR controlled vehicle here (https://youtu.be/IqQ7v68lYBI).
This is a great experiment for you to modify and enhance. For example, try changing the turns with 1
wheel braking and 1 at full speed. Try adding turning whilst reversing turning too.

Troubleshooting Experiment 4
Compared to other experiments, Experiment 4 is complex and involves aspects of coding, a micro-
controller, electronic parts, mechanical parts, and power considerations. There is a good chance it will
not work first time. Here are some considerations to help with troubleshooting.
A potential problem is a conflict between the ‘IRremote’ library and the PWM operation of the Arduino
Uno. There are 3 timers on board the Arduino Uno referred to as Timer 0, Timer 1 and Timer 2. The
‘IRremote’ library needs to use Timer 2. However, PWM pins 3 and 11 also use this timer. Therefore,
if you try to use these pins as the enable inputs to the H-Bridge there will be a conflict. You will find
that only a PWM value of 255 will work. For all other values, the motor will stop and so the pins can
only be used as digital outputs. If this occurs, use any PWM pin other than 3 and 11. Incidentally, the
following PWM pins are associated with the following timers:
• Timer 0 - 6 and 5
• Timer 1 - 9 and 10
• Timer 2 - 11 and 3
This Experiment is hungry on batteries. You are best first using a mains PSU adapter to debug and test
the vehicle. A battery containing 4 x AA cells may not last long or may not provide enough power to get
the vehicle moving. Lithium-ion batteries are effective, but expensive. You may have some in a radio-
controlled vehicle you can use. A cheaper alternative is to use a PP3 9V battery. Again, it must be new
and of high quality. I am using 6V motors but driving these for a short time at 9V will not do any harm.
The extra torque this increased voltage delivers makes the vehicle work better. This is only a temporary
build and for the short term, so this approach is OK, but not recommended for long term use.
You will also need to tune the speed levels for the motors you are using. I worked out that I needed a
PWM value over 110 just to overcome the inertia and move the vehicle at minimum speed. I chose 150
as a minimum speed value, 200 as medium and 255 as top speed.
If the motors run the wrong way, simply swap the leads around, but really check your wiring. It is critical
that the motor and +5V logic supplies are kept separate and wired to the correct components or you
could damage your Arduino board. However, both supply grounds must be tied together so that the
complete system works off the same voltage reference.

Summary
In this chapter you learnt how to use a H-Bridge to control the speed and direction of a motor. You were
introduced to a common and inexpensive device all the L293D. You learnt how to develop Sketches and
projects that use infrared remote control. You learnt how to apply this knowledge to build a simple IR
controlled vehicle and learnt about some of the challenges this can present.
On the coding side you were introduced to the concept of Object-Oriented Programming, libraries and
the ‘switch’ and ‘case’ statement.
Chapter 3: Servo Motors

DC motors are great for driving systems, but angular control is next to impossible as well as holding a
set position. This is what servo motors are designed to do as are stepper motors. We will cover stepper
motors in the Chapter 4.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x SG90 9G servo
• 1 x LM7805CV
• 2 x 10uF 50V electrolytic capacitors
• 1 x DHT-11 temperature and humidity sensor
• 1 x 9V battery or mains adapter
• 1 x 10KΩ potentiometer
• Jumper wires

What are Servos?


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

Servo Operation
You will see that all servos have 3 wires. Usually red and black (or brown) are +5V and ground
respectively, and the positional control wire is usually orange. They work on the principle of PWM to
define the angle. They require a positional feedback mechanism and the simplest type is a
potentiometer built into the motor casing.
PWM operation of the servo motor is illustrated in Figure 3-2. A PWM pulse is triggered every 20ms.
This is generally consistent across all DC servo motors and so makes programming easy with the use of
an Arduino library. If a 1ms pulse is present in the period, the servo rotates to 00. If the pulse is 1.5ms,
the servo rotates 900. Finally, if the pulse is 2ms, the servo rotates to 1800. If the pulse is between these
values the servo rotates to the proportionate angle.
Figure 3-2: Servo PWM Pulses
Image source: The author
If you want the servo to hold its position and resist any rotational torque from the load, simply resend
the same pulse width every 20ms.

The SG90 9G Servo


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

The Servo Power Supply


We need to consider the external power supply for the servo. Here we can take advantage of the barrel
connection to power the Arduino and connect the Vin pin of the Arduino to the input of a 5V voltage
regulator. We will be using the 7805 voltage regulator, specifically the LM7805CV as this is able support
up to 1.5A. Figure 3-4 illustrates our basic voltage regulator circuit.

Figure 3-4: The Voltage Regulator Circuit to Power the Servo


Image source: The author
The voltage regulator is a device with 3 terminals. One is the input; one the output and one is ground.
Its purpose is to provide a stable output voltage at a specified level. Provided that the input voltage is
higher than the output voltage, the device will work correctly. The 7805 provides an output voltage of
+5V. The minimum input voltage is +7VDC and the maximum input voltage is +35VDC. A 7812 device
will provide an output voltage of +12V and the 7815, +15V and so on. If you want a negative output
voltage that you can use a 7905 for -5VDC, a 7912 for -12VDC etc. You need to note that the voltage
drop across the device is lost as heat. Therefore, if the input voltage is much higher than the output
voltage you will need to attach a heat sink to the voltage regulator. The regulator has a TO-220 package
and there are many types of heat sinks available for this type of package.
You will notice that there are capacitors connected across the supply on both the inputs and the outputs.
These act as ‘decoupling’ capacitors. Capacitors have the property of counteracting transient voltage
and instabilities in the supply that can be caused by changes in load. Since the load asserted by the
motors are inductive in nature, these too will generate voltage spikes that leads to variations in the
supply that the capacitors will smooth out.
You will also notice that these capacitors have a different symbol to the others used so far. This identifies
the capacitors as ‘electrolytic capacitors’. This is the only type of capacitor that is polarity sensitive and
so you must connect it the correct way round, otherwise it will most likely be damaged. Electrolytic
capacitors generally have a higher capacitance compared to the other types and the negative lead is
always clearly identified on the casing. You will also find that electrolytic capacitors have a voltage
rating. This is the maximum voltage difference that can be applied across the device. A 50V device will
be adequate for most project work but be sure to check the rating before using the capacitor.
Figure 3-5 is an image of the 7805 voltage regulator and an electrolytic capacitor.

Figure 3-5: The 7805 Voltage Regulator and an Electrolytic Capacitor


Image source: The Web (public domain) with annotations by the author

Experiment 5: Servo Control using a Potentiometer


This experiment is common when first exploring servos. It simply involves sweeping the servo between
00 and 1800 using a potentiometer. First build the breadboard layout as in Figure 3-6. It is important
that the +5V supply for the servo is kept separate to the +5V supply for the components. In this case
the only other component is the potentiometer. However, the grounds for both supplies must be
connected to ensure all components work from the same voltage reference.
Figure 3-6: The Breadboard Layout for Basic Servo Control
Image source: Created with Fritzing
Next type in or load the Sketch as in Listing 3-1. We will be using to built-in library called ‘Servo.h’ by
Michael Margolis, so check you have that loaded.
/*
Servo
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/

#include <Servo.h>

const int SERVO = 3; //Servo on Pin 3


const int POT = 0; //Pot on Analog Pin 0

Servo myServo;
int val = 0; //Value of potentiometer
void setup()
{
//Create the Servo Object and pass pin number
myServo.attach(SERVO);
}

void loop()
{
val = analogRead(POT); //Read Pot
val = map(val, 0, 1023, 0, 179); //scale it to servo range
myServo.write(val); //moves the servo to desired angle
delay(15); //waits for the servo to finish moving
}

Listing 3-1: The Sketch to Drive the Servo


Listing source: The author with library functions by Michael Margolis
The Sketch is simple, and we have covered all elements before, including loading the library. You need
to create a servo object and pass the identity of the Arduino pin to which the servo control wire is
connected. You may be wondering why the value of degrees is specified as 0 to 179. 0 to 179 equates to
180 values as zero in programming is a valid number and counts as an entity. Also bear in mind that
servos do not operate in degrees, they operated according to the width of the pulses. We use degrees as
a convenient unit for the programmer. You will find some servos will travel 1900 and so you must test
each servo individually if you want any degree of accuracy. You can see a video demonstration of the
experiment here (https://youtu.be/jgjKTZGRLuA).

The DHT11 Temperature and Humidity Sensor


Before moving on from servos, I wanted to include another experiment that offers a bit more of an
application and a bit more fun. I am reusing the DHT-11 sensor from Book 2 to build a servo-controlled
thermometer. You could expand on this experiment by using a sensor like the BME280. This measures
atmospheric pressure, temperature and humidity. You could use 3 servos to display each reading or use
a switch to toggle between readings.
An image of the DHT11 is shown in Figure 3-7 with its associated pinouts.

Figure 3-7: The DHT11 Temperature and Humidity Sensor


Image source: The author
The DHT-11 is a low-cost sensor that measures temperature and humidity. The package may come with
4 pins, but only 3 pins have connections. Check your device, it is usually pin 3 that has no connection
on a 4-pin device. The DHT-11 requires just a supply, ground and a single Arduino I/O pin for
connectivity. The unit can measure temperature in the range of 0-50C with 1-degree resolution. It has
an accuracy of about +/-2C. It can measure humidity from 20% ~ 90% with 1% resolution and +/-5%
accuracy. There is a selection of libraries available in the Arduino IDE and we will use the ‘simpleDHT’
library written by Winlin.

Experiment 6: A Servo based Thermometer


We will start by designing a simple faceplate for the thermometer. The DHT-11 measures from 0C to
50C so we can equate the temperature to a rotational angle of the servo. I created the one out of card
shown in Figure 3-8.

Figure 3-8: The Faceplate for the Servo Thermometer


Image source: The author
Next, build the breadboard layout as in Figure 3-9.
Figure 3-9: The Breadboard Layout for the Servo Thermometer
Image source: Created with Fritzing
The Sketch for this experiment is shown in Listing 3-2.
/*
Servo Thermometer
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/

#include <Servo.h>
/*
This Sketch was written with SimpleDHT version 1.0.11
The code may need to be modified if other versions are used
*/
#include <SimpleDHT.h>

const int SERVO = 3; //Servo on Pin 3


int pinDHT11 = 2;
int angle = 0; //angle for servo
Servo myServo;
SimpleDHT11 dht11(pinDHT11);

void setup()
{
//Create the Servo Object and pass pin number
myServo.attach(SERVO);
Serial.begin (9600);
}

void loop()
{

// now read temperature and humidity


byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) !=
SimpleDHTErrSuccess) {
Serial.println("DHT11 read fail");
Serial.print ("err="); Serial.print(err); delay(1000);
return;
}
Serial.print ("temperature :"); Serial.print (temperature);
angle = map(temperature, 0, 50, 179, 0); //scale it to servo range
//ensure we do not pass an angle outside of range
angle = constrain (angle, 0, 179);
Serial.print (" angle :"); Serial.println (angle);
myServo.write(angle); //moves the servo to desired angle
delay(1500); //wait for next temperature sample
}

Listing 3-2: The Sketch for the Servo Controlled Thermometer


Listing source: The author library functions by Michael Margolis and Winlin
You will need to load the library ‘SimpleDHT.h’ that was written by Winlin. My Sketch was written
using version 1.0.11 of this library. There are variations in the code structure between library versions
so, to be sure your Sketch will work, use version 1.0.11 or follow the more info link to check for any
changes in the code. The serial monitor is used to check the reading from the DHT-11 sensor and
compare the servo angle.
You will need to create an object of the DHT-11 with the line of code below and I am using the I/O pin
2 of the Arduino for the data input from the sensor.
SimpleDHT11 dht11(pinDHT11);
The first task is to take a reading from the sensor and log any reading errors to the serial monitor. The
code for this comes directly from the library examples. In version 1.0.11 of the library, the code checks
to see if there is an error when reading the sensor and displays the error code if one occurs. If there is
no error, the temperature and humidity values are inserted in the respective byte variables. The ‘&’
symbol in front of the temperature and humanity values means we are passing a reference to those
variables so they can be used in the ‘dht11.read’ function. Although we are not using the humidity
value in this project, a variable for humidity was declared in the Sketch for consistency with the
‘dht11.read’ function. The ‘return’ statement means that the current function (which is the main
loop) will terminate at that point and start over if there was an error in the reading.
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) !=
SimpleDHTErrSuccess) {
Serial.println("DHT11 read fail");
Serial.print ("err="); Serial.print(err); delay(1000);
return;
}

Assuming we have a valid reading, the next tasks are to print the temperature to the serial monitor,
map the temperature to a servo angle and print that angle to the serial monitor. I added the
‘constrain’ function to be sure we do not drive the servo beyond 00 and 1800. The delay is needed as
we cannot sample the DHT-11 too fast. You will notice that I mapped 0C to 1800 and 50C to 00. I needed
to do this simply because of the way I mounted the motor and armature, I could flip it around, but it
was just as easy to modify the code. Be sure to check your motor orientation and make the appropriate
changes.
A photograph of the finished project can be seen in Figure 3-10.
Figure 3-10: The Finished Servo Controlled Thermometer
Image source: The author

Summary
In this chapter you learnt about servos and how they work to deliver positional control. You learnt about
power requirements of servos and were introduced to the voltage regulator to provide an external power
supply.
You also learnt about the DHT-11 temperature and humidity sensor and how feedback from sensors
can be used to control servos.
Chapter 4: Stepper Motors

In this final chapter we will look at stepper motors. Stepper motors provide a means for precise
positional control and are capable of great torque but use more power. Due to their superior accuracy
over servos, they are used in robotics and items such as printers, scanners and cutting beds. In this
chapter we will look at two types of motor, both are significant in the educational and hobby arena.
These are the NEMA-17 stepper motor and the 28BYJ-48 stepper motor. Each unit uses a stepper motor
controller board.

Parts needed for this Chapter


• Arduino Uno or clone board
• Full or half size breadboard
• 1 x NEMA-17 stepper motor (<=1.5A)
• 1 x 28BYJ-48 stepper motor
• 1 x L293D dual H-Bridge controller
• 1 x ULN2003 driver board
• 1 x LM7805CV
• 2 x 10uF 50V electrolytic capacitors
• 1 x KY-040 rotary encoder
• 1 x 9V battery
• 1 x Mains adapter 7-12VDC 1.5A
• Jumper wires including Dupont M-F jumpers

Stepper Motor Operation


You could devote the best part of a whole book to the various types of stepper motor. However, we will
cover just the most common types used in Arduino based projects and that is the bipolar, 4-wire stepper
motor and the unipolar 5-wire stepper motor.
Stepper motors are brushless. They work by energizing sets of coils in turn that are set around a
permanent magnet rotor. The coils are arranged at set angles, and when turned on in ‘phases’, are able
to turn the rotor one step at a time. These steps are highly repeatable, and the motor can generate great
torque. This makes the stepper motor perfect for industrial applications that require a high degree of
precision and power. You find them in industrial robots, aerospace components, CNC machines,
printers to name but a few applications.
To better understand the operation of a stepper motor you can refer to Figure 4-1. This shows a
simplified stepper motor with 4 steps per revolution.
Figure 4-1: Simplified Diagram to show Stepper Motor Operation
Image source: The author
• Stage 1: The motor is not energized and so can spin freely.
• Stage 2: A current is applied to Coils 1A and 1B and they generate a magnetic field with north
at the top. The north pole of the rotor is aligned with this magnetic field and the rotor is ‘locked’
in position.
• Stage 3: Coils 1A and 1B are de-energized and a current is applied to Coils 2A and 2B. These
coils create a magnetic field that causes the north pole of the rotor to align with Coil 2B. The
motor ‘steps’ by 900.
• Stage 4: Coils 2A and 2B are de-energized and a current is applied to Coils 1A and 1B, but in the
opposite direction compared to Step 2. This causes the rotor to step through another 900.
• Stage 5: Coils 1A and 1B are de-energized and a current is applied to Coils 2A and 2B, but in the
opposite direction compared to Step 3. The rotor steps though another 900.
• Stage 6: The rotor has now gone through a full rotation and Step 2 is repeated.
In real stepper motors there will be many more coils and many more steps per rotation. The NEMA-17
motor will have 200 steps per revolution and the 28BYJ-48 32. These motors are discussed in more
detail in the next sections.
Stepper motors do consume a lot of power and so using a battery to power projects in not recommended.
I will be using a mains adapter connected to the Arduino barrel connector and a jumper from the Vin
pin to the power supply.

The NEMA-17 Bipolar Stepper Motor


The first point to note about the NEMA-17 stepper motor is that NEMA-17 refers to the type of face
plate mounting. The actual motors are available in many torque and power variants. The more powerful
the motor the deeper it will be. I am using a 1.5A variant. This is one of the less powerful types and so
is cheaper. Clearly, we cannot drive it directly from the Arduino board and so we can use a H-Bridge
controller or some transistor-based controller. Our L293D H-Bridge can cope with 600mA. This means
we could use the L293D for our Experiment as we will not be putting the NEMA-17 motor under load,
but I do want to encourage good engineering practice, and so I will be using a L298N dual H-bridge
motor controller. This controller can pass 2A so is ideal for our NEMA-17. It should be noted that the
direction of the stepper motor is controlled by the sequence the coils that are energized. This means we
do not switch direction using the H-Bridge and so we can permanently enable the outputs and use the
device simply to meet the power requirements. There is no chance of causing a short if we are not
switching the H-Bridge. Likewise, we can simply use transistors in a similar way to what you explored
in Chapter 1, but they will need to pass at least 1.5A.
An image of the NEMA-17 is shown in Figure 4-2.

Figure 4-2: A NEMA-17 Stepper Motor


Image source: The Web (public domain)
The rotation per step of the NEMA-17 is 1.80. This means there are 200 steps per revolution of the rotor.
Unlike the 28BYJ-48, the NEMA-17 is not geared, and we will look at the benefits of gearing when we
discuss the 28BYJ-48. Having no gears does means that the motor is easier to work with from a coding
perspective.
The NEMA-17 is a 4-wire motor and the typical color coding of the wires is shown in Figure 4-3.

Figure 4-3: NEMA-17 Motor Wiring


Image source: The author

The L298N Dual H-bridge DC Stepper Motor Controller


The L298N motor drive module contains a dual channel full H-bridge driver. This driver allows up to
two DC motors to be independently controlled in both forward and reverse directions or a single stepper
motor. The L298N can pass much more current than the L293D with a 2A limit. Operation is like other
H-Bridges. H-Bridge operation was discussed in Chapter 2. An image of the L298N is shown in Figure
4-4.
Figure 4-4: The L298N Dual H-Bridge Motor Controller
Image source: The Web (public domain)
We need to take a closer look at the L298N to better understand the connectivity. There is a chance that
connecting this incorrectly will damage it. Figure 4-5 shows the connectivity.
Figure 4-5: L298N Connectivity
Image source: The Web (public domain) with annotations by the author
Let us first focus on the inputs that have pin connectors such that Dupont jumpers can be used from
the Arduino or breadboard. Four pins will be needed just like other H-Bridges. By default, the 2 enable
pins, EN A and EN B have jumpers connecting them to +5V. We will leave them in place so that the
inputs are permanently enabled. Remember that the stepper motor library will ensure that the H-
Bridge cannot be configured in a way that will cause a short. If you want to control DC motors with this
bridge, then remove the jumpers and the enabled pins can be used in the same way as the L293D H-
Bridge.
The L298N has a built in 5V voltage regulator. We can connect a mains adapter to the barrel connector
of the Arduino and connect the Vin pin of the Arduino to the +12VDC supply. The ground of the L298N
will be connected to the ground of the Arduino. The +12VDC input of the L298N is a maximum voltage.
It will operate from +7vDC. The input must not exceed +12VDC, otherwise you can damage the
controller. I prefer to run a voltage lower than +12VDC simply because the L298N will run cooler as
less voltage is dropped across the voltage regulator. You can connect a +5VDC supply directly to +5V
pin of the L298N, but do not connect both a +5VDC supply and a +12VDC input at the same time. The
+5V pin can be used as an output voltage to power other components if the +12VDC supply is being
used.

The 28BYJ-48 Unipolar Stepper Motor and ULN2003 Driver Board


The 28BYJ-48 is often bundled with the ULN2003 Driver Board and it really makes sense to use that
driver. The bundle is extremely inexpensive, so it is worth buying a few. The 28BYJ-48 is a low power
motor with 32 steps per rotor revolution. It is a unipolar stepper motor and so each coil needs a center
tap that is powered with +5VDC. The 28BYJ-48 has an inbuilt gear system and has a gear reduction
ratio 0f 64:1. This means to achieve a full rotation of the shaft the motor requires 64 x 32 or 2048 steps.
The gearing increases the torque at the shaft and allows for a fine degree of positioning, but at a much
lower speed of rotation. Furthermore, it does provide us with some challenges when programming and
we will explore this in the exercises.
The ULN2003 Driver is not a H-Bridge, but houses an array of 7 Darlington transistor pairs, each
capable of driving loads up to 500mA and 50V. Basically, a Darlington pair is a pair of transistors, where
the second transistor amplifies the output current of the first transistor.
An image of the 28BYJ-48 stepper motor and ULN2003 driver board is shown in Figure 4-6 and the
wiring of the 28BYJ-48 stepper motor is shown in Figure 4-7.

Figure 4-6: The 28BYJ-48 Stepper Motor and ULN2003 Driver Board
Image source: The Web (public domain)
Figure 4-7: The 28BYJ-48 Stepper Motor Wiring
Image source: The author

Experiment 7: Basic Control of the NEMA-17


I wanted to start with a basic experiment to simply rotate the stepper motor 1 full rotation clockwise
and 1 full rotation counter-clockwise. This way you can focus on the usage of the stepper motor library
and get a full understanding of how to control the motor. We will do a similar experiment with the
28BYJ-48 to compare the operation.
Start by building the circuit layout in Figure 4-8 and check your motor’s wiring as they do vary. I am
using a 9V mains adapter of 1.5A rating. A 1A supply should be OK, but the higher rating the better. I
chose to use 9V as the L298N can get hot using higher voltages as more voltage is dropped across the
voltage regulator. I recommend that you use good quality jumpers between Vin pin and the ground.
The jumpers need to be as thick as possible otherwise the cables can get hot too.
Figure 4-8: The Circuit Layout to Drive the NEMA-17 Stepper Motor
Image source: The author
Now load or type in the Sketch as in Listing 4-1.
/*
NEMA-17 Stepper Motor Control
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/
#include <Stepper.h>

//Most NEMA-17 Motors have 200 steps/revolution


const int STEPS_PER_REVOLUTION = 200; //200 steps/rev

//L298N pins
const int INPUT1 = 2;
const int INPUT2 = 3;
const int INPUT3 = 4;
const int INPUT4 = 5;
// Initialize the stepper library - pass it the Switch control pins
Stepper myStepper(STEPS_PER_REVOLUTION, INPUT1, INPUT2, INPUT3, INPUT4);

void setup()
{
//Set the stepper speed
myStepper.setSpeed(60); //60 RPM
}

void loop()
{
// step one revolution in one direction:
myStepper.step(STEPS_PER_REVOLUTION);
delay(500);

// step one revolution in the other direction:


myStepper.step(-STEPS_PER_REVOLUTION);
delay(500);
}
Listing 4-1: The Sketch to Control the NEMA-17 Stepper Motor
Listing source: The author
We need to load the stepper motor library with the line of code below:
#include <Stepper.h>

We defined a constant to inform the servo library of the steps needed for 1 revolution
const int STEPS_PER_REVOLUTION = 200;

We then defined the Arduino pins that will connect to the L298N inputs.
const int INPUT1 = 2;
const int INPUT2 = 3;
const int INPUT3 = 4;
const int INPUT4 = 5;

We then created an object of the servo library and pass the steps per revolution and the Arduino pin
numbers as arguments.
Stepper myStepper(STEPS_PER_REVOLUTION, INPUT1, INPUT2, INPUT3, INPUT4);

In the setup function we defined the speed for any sequence of steps and here we set the speed to 60rpm.
myStepper.setSpeed(60);
We simply move the motor by calling in the function below. We chose to move the motor 200 steps for
1 revolution, but we could pass any number as the argument. You need to note that the ‘step’ function
is blocking. This means that the code will wait until this function has finished moving the motor and
only then will the code resume.
myStepper.step(STEPS_PER_REVOLUTION);

Passing the number of steps as a negative number changes the direction of the motor.

Experiment 8: Basic Control of the 28BYJ-48


We will look at controlling the 28BYJ-48 stepper motor in a similar way to the NEMA-17. Start by
building the breadboard layout shown in Figure 4-9.
Figure 4-9: The Breadboard Layout to Control the 28BYJ-48
Image source: The author
Next load or type in the Sketch shown in Listing 4-2.
/*
28BYJ-48 Stepper Motor Control
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/
#include <Stepper.h>

//Most 28BYJ-48 Motors have 32 steps/revolution or 2048 allowing for gears


const int STEPS_PER_REVOLUTION = 2048; //2048 steps/rev

//ULN2003 pins
const int IN1 = 2;
const int IN2 = 3;
const int IN3 = 4;
const int IN4 = 5;

// Initialize the stepper library - pass it the Switch control pins


Stepper myStepper(STEPS_PER_REVOLUTION, IN1, IN3, IN2, IN4);

void setup()
{
//Set the stepper speed
myStepper.setSpeed(10); //10 RPM
}

void loop()
{
// step one revolution in one direction:
myStepper.step(STEPS_PER_REVOLUTION);
delay(500);

// step one revolution in the other direction:


myStepper.step(-STEPS_PER_REVOLUTION);
delay(500);
}

Listing 4-2: The Sketch to Control the 28BYJ-48 Stepper Motor


Listing source: The author
You will be able to power this stepper motor from a battery as the power draw of the 28BYJ-48 is much
less than the NEMA-17. You can see that the Sketch is like that of Experiment 7. We have changed the
step per revolution to 2048 since the 28BYJ-48 has 32 steps for rotor rotation but also has a 64:1 gear
reduction making 2048 steps for one shaft rotation. The upshot of this is that we must reduce the speed
of the motor. You can experiment and increase the speed above 10RPM. This approach makes it easier
to position the motor as we are working with a full shaft rotation of 2048 steps. Try changing the steps
per rotation to 32. You will now find that you can increase the speed to about 600-700rpm. Now the
focus has turned to measuring rotor rotations. You need to work out what is best for your application.
We will use 32 steps per rotation in Experiment 9 with a speed of 600rpm.
There is 1 other key point to note about this Sketch. We need to swap the positions of ‘IN2’ and ‘IN3’
compared to the Sketch in Experiment 7. If we do not do this the 28BYJ-48 will not change direction.
Rotary Encoders
In Chapter 3, I mentioned that servos use a potentiometer to feedback their angular position. This
method is low cost but not perfectly accurate. Potentiometers are prone to resistance drift with
temperature and will wear out relatively quickly since the wiper is in constant contact with the resistive
track. We also now live in a digital world and it would be much better to have a way of encoding the
angular position of a motor using a digital method and this is what rotary encoders do. Rotary encoders
can be connected to the shaft of a motor to feedback its positions or can be available as a manual input
device. They are found in all sorts of modern appliances too. They are often used as volume controls, to
change the timing on a microwave, in test equipment etc. You can tell that a control is a rotary encoder
by the fact that they are able to turn through 3600 without any stop and you may feel some notches as
you rotate the device. Some encoders are mechanical based, and the notches are created by switch
connections.
Encoders come in 2 types. These are absolute or incremental. They can also be optical or mechanical in
construction. Figure 4-10 illustrates the optical disk associated with 4-bit absolute encoder. This would
provide 16 angular positions. You can see that the absolute encoder transmits a specific binary number
to represent the position of the encoder. Light is shone through holes in the disk and blocked by the
rest of the disk to generate the 1’s and 0’s. An incremental encoder only requires 2 bits and the micro
controller detects which bit is received first to determine if the encoder is rotating and the direction of
rotation. How that works is explained when we look at the mechanical incremental encoder.

Figure 4-10: A Disk Associated with an Optical Absolute Encoder


Image source: The Web (public domain)
Figure 4-11 illustrates the basic concept of a mechanical incremental encoder.
Figure 4-11: The Basic Mechanical Incremental Encoder
Image source: The author
In the mechanical encoder there is a disk with conductive pads. There are also 2 contacts. These are
often labelled DT and CLK. As the disk rotates, either CLK or DT will strike the contact first. A voltage
is applied to these contacts and so one will go high before the other. We can use this low to high state
change to determine that the encoder is rotating and use the phase difference to determine the direction
of rotation. There are many animations on YouTube that show this type is rotary encoder in operation.

The KY-040 Rotary Encoder Module


For this final experiment, we shall be using the KY-040 rotary encoder. This is a common and very
inexpensive rotary encoder and has 32 positions. Being a mechanical device, it does tend to bounce and
so we will need to debounce the device in the code. An image of the KY-040 rotary encoder is show in
Figure 4-12.
Figure 4-12: The KY-040 Rotary Encoder
Image source: The Web (public domain)
As well as the DT and CLK pins, it has +5VDC and ground pins. There is also a switch that is activated
when you depress the shaft.

Experiment 9: Controlling the 28BYJ-48 with a Rotary Encoder


Start by building the breadboard layout in Figure 4-13. It is a simple enhancement of the breadboard
layout used in Experiment 8.
Figure 4-13. The Breadboard Layout to Control the Motor with a Rotary Encoder
Image source: The author
Now load or type in the Sketch as in Listing 4-3.
/*
28BYJ-48 Stepper Motor Control with Rotary Encoder
Copyright 2020 Gary Hallberg
Licensed under MIT https://github.com/ghallberg-nbtt/cautious-
spoon/blob/master/LICENSE
*/
#include <Stepper.h>

//Most 28BYJ-48 Motors have 32 steps/revolution or 2048 allowing for gears


const int STEPS_PER_REVOLUTION = 32; //32 steps/rev
const int MULTIPLIER = 50; //Multiplier for number of steps
//ULN2003 pins
const int IN1 = 2;
const int IN2 = 3;
const int IN3 = 4;
const int IN4 = 5;

//Rotary encoder inputs


const int CLK = 8;
const int DT = 9;
const int SWITCH = 10;

//Variables
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir = "";
boolean previousButton = HIGH;
boolean currentButton = HIGH;

// Initialize the stepper library - pass it the Switch control pins


Stepper myStepper(STEPS_PER_REVOLUTION, IN1, IN3, IN2, IN4);

void setup() {

//Set encoder pins as inputs


pinMode(CLK, INPUT);
pinMode(DT, INPUT);
pinMode(SWITCH, INPUT_PULLUP);
//Set the stepper speed
myStepper.setSpeed(600); //600 RPM

//Setup Serial Monitor


Serial.begin(9600);

//Read the initial state of CLK


lastStateCLK = digitalRead(CLK);
}

void loop() {

// Read the current state of CLK


currentStateCLK = digitalRead(CLK);

// If last and current state of CLK are different, then pulse occurred
// React to only 1 state change to avoid double count
if ((currentStateCLK != lastStateCLK) && (currentStateCLK == 1)) {

// If the DT state is different than the CLK state then


// the encoder is rotating CCW so decrement
if (digitalRead(DT) != currentStateCLK) {
counter --;
currentDir = "CCW";
//step motor one step CCW x multiplier
myStepper.step(-1 * MULTIPLIER);
} else {
// Encoder is rotating CW so increment
counter ++;
currentDir = "CW";
//step motor one step CW
myStepper.step(1 * MULTIPLIER);
}

Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
}

// Remember last CLK state


lastStateCLK = currentStateCLK;

// Read the button state


//int buttonState = digitalRead(SWITCH);

currentButton = digitalRead(SWITCH); // Read the switch state

if (previousButton != currentButton) // If switch pressed


{
delay(5); // Wait 5ms
currentButton = digitalRead(SWITCH); // Read switch again
}

if (previousButton == HIGH && currentButton == LOW) // Detect a button


press
{
Serial.println("Button pressed");
// Step motor back to start position
myStepper.step(-counter * MULTIPLIER);
counter = 0;
}

// Put in a slight delay to help debounce the reading


delay(1);
}

Listing 4-3: The Sketch to Control the Motor with a Rotary Encoder
Listing source: The author
There is quite a lot going on here, but only the code for the rotary encoder is new to us, so let us break
down what is going on. You will notice I set the steps per revolution to 32. This in turn means I can set
the stepper motor speed to much more than 10rpm. The 28BYJ-48 can cope with about 600 or 700rpm
so I set the speed to 600rpm. The idea is that we move the stepper motor on each increment of the
rotary encoder. However, if we move the motor 1 step for every encoder increment, we will see little
movement because of the gear ratio. I therefore set a multiplier so that we move the motor 50 steps for
each encoder increment.
We have defined several variables in the Sketch.
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir = "";
boolean previousButton = HIGH;
boolean currentButton = HIGH;

There is a counter to keep track of the encoder increments. This will increase by 1 for each clockwise
increment and decrement by 1 for each counter-clockwise increment. We need to track the current state
of the CLK output of the encoder to determine if the encoder has moved and in what direction. We do
this by comparing this to the last or previous state of the CLK output. The current direction of rotation
is only needed for the output to the serial monitor. Finally, we need to check for a button press and so
the previous button state and the current button state need to be tracked.
In the ‘setup’ function, we need to read the state of the CLK output and set it to the last state simply
to initialize the variable.
lastStateCLK = digitalRead(CLK);

In the main loop we get the latest state of the CLK output.
currentStateCLK = digitalRead(CLK);

We now need to check for a state change in the CLK output to detect that the encoder is rotating. We
only want to compare the state to the DT output on 1 transition, otherwise we will double count rotation.
We chose the low to high transition so the current state of the CLK output must not equal the previous
state and we only want to compare the DT output if the current state of the CLK output is 1 or ‘HIGH’.
if ((currentStateCLK != lastStateCLK) && (currentStateCLK == 1)) {

// If the DT state is different than the CLK state then


// the encoder is rotating CCW so decrement
if (digitalRead(DT) != currentStateCLK) {
counter --;
currentDir = "CCW";
//step motor one step CCW x multiplier
myStepper.step(-1 * MULTIPLIER);
} else {
// Encoder is rotating CW so increment
counter ++;
currentDir = "CW";
//step motor one step CW
myStepper.step(1 * MULTIPLIER);
}
}

If the DT output is low, then we know that the encoder is rotating counter-clockwise. Otherwise, it is
rotating clockwise. If the encoder is rotating counter-clockwise, then we decrement the counter and
move the motor 50 steps counter-clockwise. If the encoder is rotating clockwise, then we increment the
counter and move the motor 50 steps clockwise. We have some code in this block to print the counter
and direction to the serial monitor and it is useful to view the output.
We can then look to the state of the switch.
currentButton = digitalRead(SWITCH); // Read the switch state

if (previousButton != currentButton) // If switch pressed


{
delay(5); // Wait 5ms
currentButton = digitalRead(SWITCH); // Read switch again
}

if (previousButton == HIGH && currentButton == LOW)


{
Serial.println("Button pressed");
// Step motor back to start position
myStepper.step(-counter * MULTIPLIER);
counter = 0;
}

Much of this block of code is to debounce the switch and this is familiar to you from Experiment 3. On
detecting a valid button press, we can move the stepper back to that start position but multiplying the
current count by -1 and factoring the multiplier. Finally, we reset the counter to 0.
You can see a video demonstration of this project here (https://youtu.be/Y3ekvR_BrEQ).
Summary
In this chapter you learnt about the purpose of stepper motors and their operation. You compared 2
popular stepper motors in the NEMA-17 and the 28BYJ-48. You learnt that stepper motors can draw
lots of current and so must be matched to a capable controller. You learnt about the L298N and
ULN2003 controllers. You learnt about rotary encoders and how to write code to support their
operation.
Epilogue

So, we have come to the end of this part of the journey and I hope to have given you a good
understanding of how to drive various types of motor with the Arduino platform. There are many
examples on the Web of how to use the Arduino microcontroller for some very interesting projects, but
the purpose of this book is to give you all of the basic information you need in one place to get you
started and present it in a clear and systematic way. In the subsequent books in the series we will use
this knowledge to look at other focus areas and create ever more challenging, creative and interesting
projects. Whatever your goals are, I hope to have inspired you and helped you some way to achieving
those goals.
If you like this book and the series of books, please leave a review on the Amazon website. For the latest
news on other books in the series you can following my Facebook page, Twitter or follow me as an
author on Amazon.
About the Author

Gary Hallberg has over 34 years of experience in the telecommunications and data communications
industries. He started his career working with circuit switched voice and data technologies in PDH and
SDH environments and then moved on to work with early packet switched networks using Frame Relay
and ATM. His career shifted focus to IP routing when the Internet started to grow, designing large scale
service provider networks using leading edge equipment from vendors such as Juniper and Cisco. Gary
attained Cisco Certified Professional status during this time. Presently, he is working for a global
equipment vendor with a focus on Ethernet networks and is at the forefront of network evolution,
providing infrastructures for SD-WAN, Network Functions Virtualization, SDN and 5G backhaul. Gary
has a Bachelor of Engineering degree in electronic engineering and a Master of Philosophy degree in
robotics and manufacturing.

You might also like