Non-Contacting PWM Encoder

Hello all,

I need help with coding for a rotary encoder. It is a Bourns EMS-22P50-B28-LS6.

Data Sheet:http://www.bourns.com/data/global/pdfs/EMS22P.pdf

I'd like to use this with the Arduino Uno to tell me position of the rotary encoders shaft. For now the code can just read off to the serial monitor.

Any help would be much appreciated.

Thanks.

What kind of accuracy are you expecting? The simplest, and least accurate, way to read it is by polling. The most accurate, and most complex, way to read it is to setup a timer to measure the duty cycle directly in hardware. There are other approaches in-between.

What will you be controlling with it? The application determines the precision needed.

The basic sequence to read it is:

Wait for input to be LOW
Then wait for input to go HIGH, and record time
Wait for input to go LOW again, and record time
The difference between the two times, in uSec, gives the count, from 0-1023

This can easily be done in loop(), using digitalRead, and micros(). Actual resolution will depend on what else you’re doing in loop(). If you do it using blocking code (i.e. - a loop that waits for each transition), you’ll get better resolution, at the expense of tying up the processor while it’s waiting. For periodic reads (10-100X/second?), this should not be a problem.

Regards,
Ray L.

For now the code can just read off to the serial monitor.

What is showing on the serial monitor? What do you want the code to show?

Please read and follow the instructions at #7 in the How to Use this Forum link and post your code with the code tags.

http://forum.arduino.cc/index.php/topic,148850.0.html

Thanks for the replies. I do not require much accuracy actually. The accuracy could be as large as +/- 15 degrees. I am attaching it to the top of a wind vane (the moving part). I will eventually use the signal from the encoder to drive a servo.

Right now, all I wanted was some example code to pull up the degrees in the serial monitor so I can physically see the sensor working.

I have never used rotary encoders, and I tried to find information on ones using PWM, but it seems less than others out there. I did not post code yet because I do not have any right now.

Thanks again all.

PriceyTrash:
I have never used rotary encoders, and I tried to find information on ones using PWM, but it seems less than others out there. I did not post code yet because I do not have any right now.

The output interface of that encoder is not real a typical "rotary encoder output".

Did you see the pictures for "Analog output using an external low pass filter" and "Recommended Filter" in the data sheet?

Connect the "Recommended Filter" circuit to your encoder and "analog out" of the filter circuit to A0 of your Arduino. Then "analogRead(A0)" will read you the output signal in the range 0...1023.

I agree with jurs. The programming will be simple if you use the external low pass filter (which will convert the PWM pulses to an analog output) and using analog read. Following Ray's approach of reading the pulse length will work, but the path is more complex.

For 15 degree accuracy, all that's needed is a simple potentiometer, read with analogRead().

Doing LPF on the "encoder" PWM output will add significant lag, as it only outputs at 1kHz, and you'd want any filter to have a time constant of at least 10X that, probably more like 100X.

Regards,
Ray L.

RayLivingston:
For 15 degree accuracy, all that's needed is a simple potentiometer, read with analogRead().

I am not using a potentiometer because I need infinite "cycles" or spins. I have no idea how many times the wind direction will change during operation.

jurs:
The output interface of that encoder is not real a typical "rotary encoder output".

Did you see the pictures for "Analog output using an external low pass filter" and "Recommended Filter" in the data sheet?

Connect the "Recommended Filter" circuit to your encoder and "analog out" of the filter circuit to A0 of your Arduino. Then "analogRead(A0)" will read you the output signal in the range 0...1023.

Yes, I saw the recommended filter. I guess because it is not a typical "rotary encoder output" as you say, is why I was confused with exactly how to operate and code for the sensor.

I will try a setup today and let you know how it goes.

Anymore input/helpful code is welcome.

Thanks, as always!

There are potentiometers with no stops, so they will turn 360 degrees. A more conventional quadrature encoder would also do what you need, and may well be cheaper. For the low resolution you need, you could even make your own encodier, using a multipole ring magnet and a pair of 50 cent Hall Effect sensors. I do this all the time.

I am curious what that encoder costs?

Regards,
Ray L.

RayLivingston:
I am curious what that encoder costs?

I know there are pots that can turn 10 times, but if the wind is very fidgety, it could possibly go around 10 times? If there are pots with more turns I couldn't find them. I already have purchased this encoder, it was about $35. It cost a pretty penny, but it's for senior design, so school pays for it. It has two ball bearings in it, making it very low friction and able to turn with wind easily.

Pots wear out, are not envrinmentally hardy - this kind of encoder is probably just
going to work for a decade or more without fuss. Probably simplest to use LPF.

PriceyTrash:
I know there are pots that can turn 10 times, but if the wind is very fidgety, it could possibly go around 10 times? If there are pots with more turns I couldn't find them. I already have purchased this encoder, it was about $35. It cost a pretty penny, but it's for senior design, so school pays for it. It has two ball bearings in it, making it very low friction and able to turn with wind easily.

If you don't have good luck with that encoder, take a look at the CUI capacitive quadrature encoders:

http://www.cui.com/product/resource/amt10-v.pdf

Zero friction (they are 100% non-contact), lower cost (about $25 typically), very reliable, very accurate, and selectable resolution.

Regards,
Ray L.

PriceyTrash:
I need help with coding for a rotary encoder. It is a Bourns EMS-22P50-B28-LS6.
Data Sheet: http://www.bourns.com/data/global/pdfs/EMS22P.pdf

The datasheet says the PWM output is a HIGH pulse from 1 to 1024 microseconds.

   int pulseLength = pulsePin(sensorPin, HIGH, 3000);  // 3000 is the timeout
   if (pulseLength == 0) {
       // The read failed.  Hardware error.
    } else {
       angle = map(pulseLength, 1, 1025, 0, 360); // Convert from pulse width to degrees
   }

I’ve worked with this type of encoder before.

If you don’t need the Arduino doing anything else for a millisecond (like controlling a motor or reading other inputs) then pulseIn() is perfect. Pay attention to the formula in the datasheet to calculate the position - it subtracts Toff from Ton, which takes care of any timing errors. (The formula is just under the timing diagrams, in small text.) In practice, you can usually get away with just measuring Ton like John showed.

If you need to be doing something else and can’t afford to have your processor locked up for a whole millisecond, then you need interrupts. This is actually difficult to do on the 16MHz Arduino. The 0 degree and 369.65 degree cases only give you a microsecond to service the interrupt and rearm it to catch the next edge of the signal. The best I could do was skip from 1022 to 2 when passing through zero, which is insignificant for most angle measurements.

I have the encoder working, so thanks for the help everyone. I will be creating a negative feedback loop with it to control a servo. I'll post here with more information if I need further help!

Thanks!

So today I began my negative feedback control using the same encoder and a continuous rotation servo.

The encoder reads between 0 and 1024

For the most part I have the system working. However, I cannot get the servo to stop when the rotary encoder reads between a certain value specified in the sketch.

Can someone look at the sketch and tell me why? The servo does not even slow down during that period.

Right now the servo moves clockwise between 0 and 512, and counterclockwise between 512 and 1024.

I want it to stop between 974 and 50.

Here is the sketch

#include <Servo.h>

Servo myservo; //create servo object to control a servo

int pos=0; // variable to store the servo position
int encoderValue; 

void readEncoder()
{
  encoderValue=analogRead(A0);
} 

void setup()
{
  Serial.begin(9600);
  myservo.attach(9); //attaches the servo on pin 9 to the servo object
}


void loop()
{
  // read input
  readEncoder();
  
  //processing
  if (encoderValue > 50 && encoderValue < 512)
  {
    //send 120 degrees to servo to get it moving clockwise
    myservo.write(120);
    if(encoderValue < 50 && encoderValue > 974) myservo.write(90); //if encoder reads between 974 and 50, the servo will stop
  }
  else if (encoderValue > 512 && encoderValue < 974)
  {
    //send 60 degrees to servo to get it moving counterclockwise
    myservo.write(60);
    if(encoderValue < 50 && encoderValue > 974) myservo.write(90);
  }
  //output
  Serial.println(encoderValue);
  delay(1);  //delay in between reads for stability
}