We now have some experience with both digital and analog input and output. We're going to extend that knowledge by including an important output component typically used in embedded systems which we will discuss in Chapter 39. Today we will use the Servo.
What is a Servo?
A servo is a type of motor that can be controlled to rotate to a specific position. You can program it to move to a certain angle, and once it moves there it should stay there 🤞. The servo on the right has three different horns that can be attached to it. Various kinds of horns exist for different situations.
A servo is typically useful for controlling a:
robot arm 🤖;
steering wheel of a car 🚗;
flap on an airplane ✈️.
One can think of a servo motor as a robot hand that can hold and move things. The hand is connected to a control unit (like an Arduino Microcontroller) that tells it which way to move and how far to move.
How to hook up a servo on your circuit board
To connect a Servo to an Arduino, we use 3 PINs.
A live PIN, that should connect to the live on the breadboard.
A ground PIN, that should connect to the ground on the breadboard.
A signal PIN, that should connect to one of the Analog output pints on the Maker Uno X.
In this lesson... 📝
We will build a simple circuit with a servo that is user controlled using a potentiometer.
We will write a program to limit the movement of a Servo using a for-loop programming construct.
Use the potentiometer to control a servo
Remember from our last lesson...
A potentiometer has an input range of 0 to 1023.
We can map the value of this potentiometer input to any other range using the map() syntax.
And now...
The servo we will use supports values between 0 and 180, and it will rotate based on this input value.
Use this code to see the servo in your circuit move!
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int potPin = A0; // pin for the potentiometer
int servoPin = 11; // pin for the servo motor
int servoPos = 0; // current position of the servo
void setup()
{
// attaches the servo on pin 11 to the servo object
myservo.attach(servoPin);
// set the potentiometer pin as an input
pinMode(potPin, INPUT);
}
void loop()
{
// reads the value of the potentiometer (value between 0 and 1023)
int potentiometerVal = analogRead(potPin);
// scale it to use it with the servo (value between 0 and 180)
servoPos = map(potentiometerVal, 0, 1023, 0, 180);
// sets the servo position according to the scaled value
myservo.write(servoPos);
// waits for the servo to get there
delay(15);
}
Breaking it down
To use a servo, we make use of a library called Servo.h. Libraries are chunks of code that someone else has prepared to be re-used in other programs. In this case, the Servo library includes all the code necessary for a servo to perform actions like attach and write. We must include the library using the first line #include <Servo.h>.
We need to create a variable for the servo, using an object called Servo, which we name myservo. You probably already guessed that the object Servo is handled by the external library... we do not need to get into this complexity.
After we have declared our servo, we need to attach it to a pin in the setup section. In this case we attach it to pin 11, which supports analog output!
We read a value from the potentiometer as we have done in Arduino 4 - Fading an LED.
In this case, we use map() to scale the value from the potentiometer to a value between 0 and 180, which the servo supports.
We instruct the servo to move to that position with the myservo.write(), which takes the position as input.
We use a delay(15) to give the servo time to actually move before looping again to read a new value off the potentiometer. This is very important.
For-Loop Statement
Before we move on to a challenge, we will have a look at another programming construct in C++. We are in a good place to make use of the for-loop.
for(/* start; termination condition; increment; */) {
/* code statements that need to be repeated */
}
To use this programming construct you need to specify three statements:
start;
termination condition; and
increment
One can think of a for-loop as a flight of stairs that we need to climb, but every time we reach a step, we perform an action, for example, raise our arms up in the air. However, before we start clapping, we need to establish:
our starting point, which is our first stair,
the rate of increment, how many stairs we will climb after a completed action;
and how we will know whether we are on the last stair.
Let us look at an example:
/* assume we have to climb 10 stairs, 2 at a time*/
int start = 1;
int finish = 10;
for(stair = start; stair <= finish; stair += 2) {
/* code to raise raise your arms */
}
But what if we want to go down the stairs?
/* assume we have to climb down 10 stairs, 1 at a time*/
int start = 10;
int finish = 1;
for(stair = start; stair >= finish; stair -= 1) {
/* code to raise raise your arms */
}
Using a For-Loop to Move the Servo Smoothly
Let us go back to our circuit (left) and try out this concept. We will imagine that our servo is simulating an arm. We will program the servo to wave just once, but we would like a smooth motion. Almost like animating a character in a picture, we will use the for-loop to rotate the arm in very small increments and back so that hopefully we can a very smooth wave.
A change in the potentiometer value will trigger this motion.
Or use this code:
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int potPin = A0; // pin for the potentiometer
int servoPin = 11; // pin for the servo motor
int servoStart = 0;
int servoFinish = 135;
int signal = 0;
void setup()
{
myservo.attach(servoPin);
pinMode(potPin, INPUT);
}
void loop()
{
// reads the value of the potentiometer
// value between 0 and 1023
int potentiometerVal = analogRead(potPin);
if (potentiometerVal != signal) {
// record value
signal = potentiometerVal;
for (int servoPos = servoStart; servoPos <= servoFinish; servoPos+= 5) {
// sets the servo position according to the scaled value
myservo.write(servoPos);
// waits for the servo to get there
delay(15);
}
// reverse action
for(int servoPos = servoFinish; servo_pos >= servo_start; servo_pos-= 5) {
myservo.write(servo_pos);
delay(15);
}
}
delay(1000);
}
Comments