Main

Research & Learning

Class pages

Shop Admin

ITP Help Pages
Tom's pcomp site
DanO's pcomp site


Servo

In this lab, you'll control a servomotor's position using the value returned from an analog sensor. Servos are the easiest way to start making motion with a microcontroller. Even though they don't turn 360 degrees, you can use them to create all sorts of periodic or reciprocating motions. Check out some of the Flying Pig mechanisms for ideas on how to make levers, cams, and other simple machines for making motion.

For this lab you'll need:

Solderless breadboard
Solderless breadboard
hookup wire
22-AWG hookup wire
Arduino module
Arduino Microcontroller
module


resistors
10Kohm resistors
flex sensor
Flex sensors
(or a different
form of variable resistor)
servomotor
RC Servomotor


Prepare the breadboard

Connect power and ground on the breadboard to power and ground from the microcontroller. On the Arduino module, use the 5V and any of the ground connections:

If you're using an Arduino breadboard shield, there is a row of sockets connected to 5V on the analog in side of the breadboard, and a row connected to ground on the digital in side of the board:


Connect an analog input sensor and a servo

Pick any analog input and connect it to Analog pin 0 as you did in the Analog Input and Output Lab. Then connect an RC servomotor to digital pin 2. The yellow wire of the servo goes to the pin, and the red and black wires go to +5V and ground, respectively.

Schematic:

Breadboard version:

Breadboard Shield version:

Program the Microcontroller

The following code will move the servo as the value of the sensor changes.



/*
 Servo control from an analog input

The minimum (minPulse) and maxiumum (maxPuluse) values
will be different depending on your specific servo motor.
Ideally, it should be between 1 and 2 milliseconds, but in practice,
0.5 - 2.5 milliseconds works well for me.
Try different values to see what numbers are best for you.

This program uses the millis() function to keep track of when the servo was
last pulsed.  millis() produces an overflow error (i.e. generates a number
that's too big to fit in a long variable) after about 5 days. if you're
making a program that has to run for more than 5 days, you may need to
account for this.

by Tom Igoe
additions by Carlyn Maw & Rob Faludi
Created 28 Jan. 2006
Updated 10 Jun. 2008
*/

int servoPin = 2;     // Control pin for servo motor
int minPulse = 500;   // Minimum servo position
int maxPulse = 2500;  // Maximum servo position
int pulse = 0;        // Amount to pulse the servo

long lastPulse = 0;    // the time in milliseconds of the last pulse
int refreshTime = 20; // the time needed in between pulses

int analogValue = 0;  // the value returned from the analog sensor
int analogPin = 0;    // the analog pin that the sensor's on

void setup() {
 pinMode(servoPin, OUTPUT);  // Set servo pin as an output pin
 pulse = minPulse;           // Set the motor position value to the minimum
 Serial.begin(9600);
}

void loop() {
 analogValue = analogRead(analogPin);      // read the analog input
 pulse = map(analogValue,0,1023,minPulse,maxPulse);    // convert the analog value
                                                       // to a range between minPulse
                                                       // and maxPulse.

 // pulse the servo again if rhe refresh time (20 ms) have passed:
 if (millis() - lastPulse >= refreshTime) {
   digitalWrite(servoPin, HIGH);   // Turn the motor on
   delayMicroseconds(pulse);       // Length of the pulse sets the motor position
   digitalWrite(servoPin, LOW);    // Turn the motor off
   lastPulse = millis();           // save the time of the last pulse
 }
}

This code was written with a potentiometer in mind, so it assumes you're going to get values from 0 to 1023 from the sensor. If you don't, the servo won't move through its whole range. Determine the range of numbers the sensor is giving youm and adjust the servo formula to fit.

Here's a a scaling formula that will make the adjustment:

(pulseWidth - minPulse) / pulseRange = (sensorValue - minSensorValue) /sensorRange

Multiply both sides by pulseRange, and you get:

(pulseWidth - minPulse) = (sensorValue - minsensorValue * pulseRange /sensorRange

Add the minimum pulse to both sides and you get:

pulseWidth = ((sensorValue - minSensorValue) * pulseRange / sensorRange) + minPulse

That's the full ranging formula. However, because there are no floating-point variables (i.e. fractions) in the Arduino language (and in most microcontroller languages), you have to fudge the formula a bit. For example, if you have a sensor range from 0 to 512, and a servo range from 500 to 2500 (i.e. a 2000-point range), you know that you can just multiply the servo by 4 and add 500. You'll lose a little detail, but not enough to make a difference to the end user.

When you're making approximations like this, you have to test the approximation at the extremes of both the sensor and the output to make sure it does the job.

  Edit | View | History | Print | Recent Changes | Search Page last modified on June 17, 2008, at 04:52 PM