# How to detect direction while measuring angle of servo motor

Sir, I have used optical encoder to measure angle, where encoder disc is cut into 1 degree each. The desired angle is sent from arduino by sending the corresponding pulse width and actual angle is measured by the optical encoder and displayed in LCD. Error is also displayed. The encoder works on the principle that as it crosses each slot the angle count is incremented and this is how i get the measured angle. The problem is that if the measured angle is greater than desired angle, on correcting the error when the arm moves anti clockwise, the angle count still increases as the encoder steps backward again cutting some slots. Please help me in coding to detect the direction of motion.

#include <LiquidCrystal.h>
int servoPin=6;
int angle=10;
int pulsewidth;
int inPin = 7; // the number of the input pin
int outPin = 13; // the number of the output pin
int encoderPulse=1;
int state = HIGH; // the current state of the output pin
int previous = LOW; // the previous reading from the input pin
int y;
int x;
long time = 0;
long debounce = 20;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup()
{
pinMode(servoPin,OUTPUT);
pinMode(inPin, INPUT);
pinMode(outPin, OUTPUT);
lcd.begin(16,2);

}
void servoPulse(int servoPin,int angle)
{
pulsewidth=(angle*10)+600;
digitalWrite(servoPin,HIGH);
delayMicroseconds(pulsewidth);
digitalWrite(servoPin,LOW);

}

void loop()
{

servoPulse(servoPin,angle);
delay(2);
lcd.home();
lcd.print(“Dangle=”);

lcd.print(angle);
lcd.print(" Err=");

if (reading == HIGH && previous == LOW && millis() - time > debounce) {
if (state == HIGH)
{ state = LOW;
y= encoderPulse++ ;

}
else
{ state = HIGH;
y= encoderPulse++ ;
time = millis();
}
x=angle-2*y;
}

digitalWrite(outPin, state);
lcd.setCursor(0,1);
lcd.print(“Mangle=”);
lcd.print(2*y);
lcd.print(" ");

lcd.print(x);

}

Since your code is directing the motor forward or backward, just have a flag to keep track of which direction it is commanded. Then for backward, decrement the counter instead of incrementing.

I did something similar recently, this is how I handled it:

``````void CountLR(){

if (RevLR == 8){// 8 pulses per 1mm of travel. Only run below every 8 pulses
RevLR=0; //reset rev counter

if(DirLR == LEFT && digitalRead(L_LIM) == 1){ //if motor is going forward, count up
LR_COUNT++;
}

if(DirLR == RIGHT && digitalRead(R_LIM) == 1){ //if motor is going backward, count down
LR_COUNT--;
}
}

RevLR++; //This counts raw pulses

if(digitalRead(R_LIM) == 0){ //this code checks the limit switches and resets the count to min and max if they are reached.
LR_COUNT=0;
RevLR=0;
}
LR_COUNT=64;
RevLR=0;
}
}
``````

I had limit switches in my application which I used to set the count at min and max when they were tripped. That allowed me to accurately have a scale of positions. In the code above, I also translated the pulses to revolutions so my numbers were smaller. So for every 8 pulses, I incremented the counter.

This code was in the interrupt routine for the encoder pulses. I needed this solution because I was controlling existing hardware that had a single channel as yours does. And I could not change it to a quadrature encoder. If you have more access to changing the design, I would suggest installing another led/detector pair. Have them set up so that while one is blocked by the flag, the other is shining through a slot. This puts the signals 90 degrees out of phase and you can tell direction simply by watching which on trips first. This is a quadrature encoder and is how a mechanical mouse sensed position and direction.

The best solution would be to use two optical sensors, half a slot out of phase with each other, so that you can tell which direction the encoder wheel is moving. Without that you can't tell the direction and would have to guess - and may get it wrong sometimes.

Is the encoder disc attached to something other than the servo? If it's connected directly, how is this an improvement over the servo's own positional feedback?

I'm not sure you're outputting a standard servo PWM signal, but it looks like it. In that case you should consider using the Servo library rather than trying to generate the pulse yourself.

I am assuming we are using just a DC motor here. Using a servo wouldn't make a whole lot of sense as you mentioned, Peter.

I also just noticed that the OP is not using an interrupt on the encoder. Yikes! I would question whether he would really get an accurate and reliable count just checking it in the loop, especially when he is using delays which are going to vary.

This is not at all how I would recommend.

EDIT: You're right. He is using only one pin to control the motor. It must be a servo.