Using Feedback

If a servo motor does what it is told to do, why do we need feedback?

RC servos usually do what they are told to do, but there are many cases where a servo motor might not. These can include:
  • Insufficient motor size
  • Insufficient power supply
  • Physical interference
  • Electrical interference
  • loose connection
In these cases, feedback could alert you to the problem.

But even if the servo is adequately sized and functioning normally, it still takes some time to respond to a position command, and in many applications it is just as important to know when the position is reached.

This following code snippet is from the "Sweep" example in the Servo library. Note the arbitrary 15 millisecond delay after
"myservo.write(val)".
Download: file
void loop() 
{ 
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023) 
  val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180) 
  myservo.write(val);                  // sets the servo position according to the scaled value 
  delay(15);                           // waits for the servo to get there 
} 
Without feedback, most servo programming has to make some assumptions about how long a particular move will take. Adding fixed-time delays to servo code works OK for simple applications, but can result in slow and/or jerky performance when trying to coordinate multiple servo motions or interactions between servos and other sensors or actuators.

Or worse: If the delays are not long enough, your servos may not reach the desired position in time. This can cause malfunctions and/or damage to your project. Timing problems are a big problem in battery-powered projects because the motors will run slower as the battery power fades.

Reading the feedback

The feedback signal is tapped off the position pot attached to the servo shaft. You can connect the white feedback wire to any of the analog input pins and read the feedback value using analogRead().
Download: file
  int feedback = analogRead(feedbackPin);

Calibrating the feedback

The raw feedback signal is a voltage. In order to convert that voltage into a meaningful position, we need to calibrate it to the servo. By reading the feedback values at two known positions, we can interpolate the expected feedback values for every position in between.

The following bit of code does just that. If you call "calibrate" in your setup function, it will perform the calibration on the two points you specify. These servos operate over a range of about 0 to 180 degrees. For maximum accuracy, you should choose the minPos and maxPos calibration points based on the range of motion required in your project.
Download: file
#include <Servo.h> 
 
Servo myservo;  

// Control and feedback pins
int servoPin = 9;
int feedbackPin = A0;

// Calibration values
int minDegrees;
int maxDegrees;
int minFeedback;
int maxFeedback;
int tolerance = 2; // max feedback measurement error

/*
  This function establishes the feedback values for 2 positions of the servo.
  With this information, we can interpolate feedback values for intermediate positions
*/
void calibrate(Servo servo, int analogPin, int minPos, int maxPos)
{
  // Move to the minimum position and record the feedback value
  servo.write(minPos);
  minDegrees = minPos;
  delay(2000); // make sure it has time to get there and settle
  minFeedback = analogRead(analogPin);
  
  // Move to the maximum position and record the feedback value
  servo.write(maxPos);
  maxDegrees = maxPos;
  delay(2000); // make sure it has time to get there and settle
  maxFeedback = analogRead(analogPin);
}

 
void setup() 
{ 
  myservo.attach(servoPin); 
  
  calibrate(myservo, feedbackPin, 20, 160);  // calibrate for the 20-160 degree range
} 

void loop()
{
}

Using feedback in your code

Now that we have a calibrated feedback signal, we can easily convert between servo position and feedback voltages in our code.

Seeking to a position

The following bit of code will seek to a position and return as soon as we reach it. There is no need to add an arbitrary delay to the code because the feedback signal will tell us exactly when we get there!
Download: file
void Seek(Servo servo, int analogPin, int pos)
{
  // Start the move...
  servo.write(pos);
  
  // Calculate the target feedback value for the final position
  int target = map(pos, minDegrees, maxDegrees, minFeedback, maxFeedback); 
  
  // Wait until it reaches the target
  while(abs(analogRead(analogPin) - target) > tolerance){} // wait...
}

Finding out where you are

Another great thing about feedback is: You don't need to write code to remember the last position command you sent to the servo (assuming it got there). If you want to find out what position your servo is in, you can simply ask it!

Once you have calibrated your servo with the calibration function above, this bit of code will tell you the current position (in degrees) of your servo:
Download: file
int getPos(int analogPin)
{
  return map(analogRead(analogPin), minFeedback, maxFeedback, minDegrees, maxDegrees);
}
The ability to simply read the servo position opens up the possibility of using it as an input device as well. The next page will show you how.
This guide was first published on Aug 24, 2013. It was last updated on Aug 24, 2013. This page (Using Feedback) was last updated on May 04, 2015.