/**
* Encoder example code
*
* This is a code intended to test the encoder connections and to demonstrate the encoder setup.
*
*/
#include <SimpleFOC.h>
Encoder encoder = Encoder(2, 3, 2500);
// interrupt routine intialisation
void doA() {
encoder.handleA();
}
void doB() {
encoder.handleB();
}
void setup() {
// monitoring port
Serial.begin(115200);
// enable/disable quadrature mode
encoder.quadrature = Quadrature::ON;
// check if you need internal pullups
encoder.pullup = Pullup::USE_INTERN;
// initialise encoder hardware
encoder.init();
// hardware interrupt enable
encoder.enableInterrupts(doA, doB);
Serial.println("Encoder ready");
_delay(1000);
}
void loop() {
// iterative function updating the sensor internal variables
// it is usually called in motor.loopFOC()
// not doing much for the encoder though
encoder.update();
// display the angle and the angular velocity to the terminal
if (encoder.getAngle() == 0) {
Serial.println("zero");
};
//Serial.print(encoder.getAngle());
//Serial.print("\r\n");
//Serial.println(encoder.getVelocity());
}
it's the angle read example from Simple.FOC, that i modified to output "zero" every time the shaft is back to the origin.
the idea is to test repeatability.
It drifts. After going a couple of full turns in one direction and back, the point at which i get "zero" message shifts by a considerable angle (a visible angle i mean). I can easily make it drift by as much as 30 degrees after a minute of twitching the knob.
Any ideas why? and how to fix it?
i don't have to use simpleFOC -- i can use a simple code with the same result. for example this:
volatile long temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder
void setup() {
Serial.begin(115200);
pinMode(2, INPUT_PULLUP); // internal pullup input pin 2
pinMode(3, INPUT_PULLUP); // internalเป็น pullup input pin 3
//Setting up interrupt
//A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
attachInterrupt(digitalPinToInterrupt(2), ai0, RISING);
//B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
attachInterrupt(digitalPinToInterrupt(3), ai1, RISING);
}
void loop() {
// Send the value of counter
if (counter != temp) {
Serial.println(counter);
temp = counter;
}
}
void ai0() {
// ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
// Check pin 3 to determine the direction
if (digitalRead(3) == LOW) {
counter++;
} else {
counter--;
}
}
void ai1() {
// ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
// Check with pin 2 to determine the direction
if (digitalRead(2) == LOW) {
counter--;
} else {
counter++;
}
}
The drift clearly indicates either code errors or line noise interfering with the counts, or both.
Try the Arduino Encoder library.
The INPUT_PULLUP resistors are far too weak for open collector outputs on long leads. Use external pullups of 5K or even lower to avoid line noise errors.
By the way, you make the classical mistake of failing to protect a shared variable from being corrupted by the interrupt, while being accessed by the main program.
This frequently fails:
if (counter != temp) {
Serial.println(counter);
temp = counter;
}
This is the correct approach:
noInterrupts();
long counter_copy = count;
interrupts();
if (counter_copy != temp) {
Serial.println(counter_copy);
temp = counter_copy;
}
pull-up resistors didn't help.
Arduino library -- issue remains
i used this code:
/* Encoder Library - Basic Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
#include <Encoder.h>
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(2, 3);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(9600);
Serial.println("Basic Encoder Test:");
}
long oldPosition = -999;
void loop() {
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
}
volatile long temp, counter = 0; //This variable will increase or decrease depending on the rotation of encoder
int i = 0; // just to make 0 lines differ
void setup() {
Serial.begin(115200);
pinMode(2, INPUT_PULLUP); // internal pullup input pin 2
pinMode(3, INPUT_PULLUP); // internalเป็น pullup input pin 3
//pinMode(4, INPUT_PULLUP); // pin 4
//Setting up interrupt
//A rising pulse from encodenren activated ai0(). AttachInterrupt 0 is DigitalPin nr 2 on moust Arduino.
attachInterrupt(digitalPinToInterrupt(2), ai0, RISING);
//B rising pulse from encodenren activated ai1(). AttachInterrupt 1 is DigitalPin nr 3 on moust Arduino.
attachInterrupt(digitalPinToInterrupt(3), ai1, RISING);
//Z
//attachInterrupt(digitalPinToInterrupt(4), aiZ, RISING);
}
void loop() {
// Send the value of counter
noInterrupts();
long counter_copy = counter;
interrupts();
if (counter_copy != temp) {
Serial.println(counter_copy);
temp = counter_copy;
}
if (counter == 0) {
Serial.println(counter);
Serial.println(i);
i++;
}
}
void ai0() {
// ai0 is activated if DigitalPin nr 2 is going from LOW to HIGH
// Check pin 3 to determine the direction
if (digitalRead(3) == LOW) {
counter++;
} else {
counter--;
}
}
void ai1() {
// ai0 is activated if DigitalPin nr 3 is going from LOW to HIGH
// Check with pin 2 to determine the direction
if (digitalRead(2) == LOW) {
counter--;
} else {
counter++;
}
}
/*
void aiZ() {
if (digitalRead(2) == LOW) {
Serial.println("Z");
Serial.println(counter);
} else {
//
}
}
*/
the issue remains
Draw the pulse train, the quadrature signals. Then look for the point where it makes ++ to the count variable. Do the same for the --.If You switch the direction in an unfortunate moment the rewerse count comes to early.
I saw this problem in an industrial sawing machine some 35 - 40 years ago. Sadly I don't remember the details that fixed it, how I fixed it.
Not a very scientific method of determining repeatability. You may be exceeding the maximum frequency of the encoder and/or processing speed of the nano every. At 2500 PPR, count will increment 5000 times/revolution.
To test repeatability you should have a means of rotating the encoder at a controlled rate.
it's a sound suggestion. But on further analysis it cannot be the reason. Here's why. it's 2500 ppr. 10000 pulses per rotation. 0.036 degree between changes. If this were the reason, the error would be in the single numbers, which gives fraction of a degree. something like a tenth of a degree. I see 30 degrees after a dozen of turns. that's 1000 times higher (in the ballpark). Do you still think the explanation you gave is likely?
could you explain a bit. I don't understand. I thought the best way to check repeatability of the result is to put the system in unfavorable conditions. it's ability to do the milage in a continuous rotation for example is of no use to me. I want to see if it behaves reliably in after a few random rotations.
Your code and/or circuitry is obviously not working correctly, but you haven't provided enough information to confidently identify all the actual problems.
A complete schematic diagram, with links to all the system components, would be a good place to start. Have a look at the posting instructions in the "How to get the best out of this forum" post.
the encoder is rated at 5000RPM, and i'm turning it with my fingers -- so, no. Also, i go at most 1revolution per second (60 RPM), which results in a pulse frequency of 1khz. Nano works at 20Mhz, which is 2000 times higher. Do you still think it may be the case?