I'm using this incremental rotary encoder with a rotating disc.
Here is my system:
I will explain the system briefly and above is the illustration for that:
The rotary encoder(blue) is attached/fixed to a larger disc(yellow) concentrically at its origin, so both the encoder and the disc rotate together the same angle. The disc is rotating on a fixed plane(gray). The plane has a fixed point mark(red X) on its surface. There is also a fixed red arrow on the disc.
Each time before the system is powered, I will manually rotate the disc such that its red arrow will be aligned to the red X mark on the surface. This adjustment each time at the beginning will provide the reference point.
After this adjustment I want to output the actual angles via Arduino.
I tried the following example code from Arduino website:
#define encoder0PinA 2
#define encoder0PinB 4
volatile unsigned int encoder0Pos = 0;
void setup() {
pinMode(encoder0PinA, INPUT);
digitalWrite(encoder0PinA, HIGH); // turn on pull-up resistor
pinMode(encoder0PinB, INPUT);
digitalWrite(encoder0PinB, HIGH); // turn on pull-up resistor
attachInterrupt(0, doEncoder, CHANGE); // encoder pin on interrupt 0 - pin 2
Serial.begin (9600);
Serial.println("start"); // a personal quirk
}
void loop(){
// do some stuff here - the joy of interrupts is that they take care of themselves
}
void doEncoder() {
/* If pinA and pinB are both high or both low, it is spinning
* forward. If they're different, it's going backward.
*
* For more information on speeding up this process, see
* [Reference/PortManipulation], specifically the PIND register.
*/
if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
encoder0Pos++;
} else {
encoder0Pos--;
}
Serial.println (encoder0Pos, DEC);
}
/* See this expanded function to get a better understanding of the
* meanings of the four possible (pinA, pinB) value pairs:
*/
void doEncoder_Expanded(){
if (digitalRead(encoder0PinA) == HIGH) { // found a low-to-high on channel A
if (digitalRead(encoder0PinB) == LOW) { // check channel B to see which way
// encoder is turning
encoder0Pos = encoder0Pos - 1; // CCW
}
else {
encoder0Pos = encoder0Pos + 1; // CW
}
}
else // found a high-to-low on channel A
{
if (digitalRead(encoder0PinB) == LOW) { // check channel B to see which way
// encoder is turning
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
Serial.println (encoder0Pos, DEC); // debug - remember to comment out
// before final program run
// you don't want serial slowing down your program if not needed
}
But this code increases one count for each encoder tick at CW direction, and decreases one count for each tick at CCW direction. It keeps increasing from zero to 65535 in CW and decrease from 65535 to 0 in CCW. I want to translate this code such that I can output the angle in degrees.
My encoder says its ppr is 15 and 30 ticks. This code increase/decrease one count for each tick.
Any idea how to extract the angle from this setup? (It doesn't have to use the specific code I provided.)
Serial.println()
can cause problems when used within an ISR. Set a flag instead, and print fromloop()
volatile byte cchange;
, and set it true in the ISR. Inloop()
, sayif (cchange) { cchange=false; printstuff(); }
¶ Re double counts, the ISR shown is slow, which can mess up counting. If your ISR were to catch all the edges and treat them correctly, eg via a state machine like in my answer to question 32572, bouncing would cancel out.