Hi all!
This is my first post in this Forum.
I’ve bought a Pololu wheel encoder set from Sparkfun (sparkfun.com/commerce/produc … ts_id=9209) and I’m mounting them on Sparfun’s Ardubot PCB. The brain will be an Arduino Pro board.
- Encoder 0 is tied to Arduino’s pins 2 (phase A) and 4 (phase B),
- Encoder 1 is tied to Arduino’s pins 7 (phase A) and 8 (phase B).
I’m planning to use AVR’s PCINT feature, so I can use “interrupt on change” linked to some microcontroller pins. I’ve tested your PololuWheelEncoder class and I’ve also written my own encoder class:
class Encoder {
// private methods and attributes
private:
static char global_last_m1a_val, global_last_m1b_val, countA, countB;
static uint8_t _pA, _pB;
static int32_t _position;
static void doEncoderA(void);
static void doEncoderB(void);
// public methods
public:
Encoder(uint8_t, uint8_t);
void start();
void stop();
void write(int32_t);
int32_t read(void);
};
char Encoder::global_last_m1a_val = 0;
char Encoder::global_last_m1b_val = 0;
char Encoder::countA = 0;
char Encoder::countB = 0;
uint8_t Encoder::_pA = 0;
uint8_t Encoder::_pB = 0;
int32_t Encoder::_position = 0;
//
// Constructor
//
Encoder::Encoder(uint8_t pA, uint8_t pB) {
// initialisation of class attributes
_pA = pA;
_pB = pB;
_position = 0;
// initialisation of I/O
pinMode( _pA, INPUT );
pinMode( _pB, INPUT );
digitalWrite( _pA, HIGH ); // pull-up
digitalWrite( _pB, HIGH ); // pull-up
}
void Encoder::start() {
PCattachInterrupt( _pA, doEncoderA, CHANGE );
PCattachInterrupt( _pB, doEncoderB, CHANGE );
global_last_m1a_val = get_val( _pA );
global_last_m1b_val = get_val( _pB );
}
void Encoder::stop() {
PCdetachInterrupt(_pA);
PCdetachInterrupt(_pB);
}
void Encoder::write(int32_t position) {
_position = position;
}
int32_t Encoder::read(void) {
return _position;
}
// Interrupt on A changing state
void Encoder::doEncoderA(){
countA ++;
unsigned char m1a = get_val( _pA );
char plus_m1 = m1a ^ global_last_m1b_val;
if (plus_m1) _position++;
global_last_m1a_val = m1a;
}
// Interrupt on B changing state
void Encoder::doEncoderB(){
countB ++;
unsigned char m1b = get_val( _pB );
char minus_m1 = m1b ^ global_last_m1a_val;
if (minus_m1) _position--;
global_last_m1b_val = m1b;
}
The code uses the standard code for PCINT as shown at arduino.cc/playground/Main/PcInt. When turning the wheel clock-wise, the number of pulses counted is not equal to the number of counts counter clock-wise. What’s wrong? Anyway countA and countB get the same values.
When debugging with my serial terminal, I get something like this:
10 1 0 1
00 2 0 1
01 2 1 0
00 2 2 0
10 3 2 1
00 4 2 1
01 4 3 0
00 4 4 0
10 5 4 1
00 6 4 1
01 6 5 0
11 7 5 0
10 7 6 -1
00 8 6 -1
01 8 7 -2
11 9 7 -2
10 9 8 -3
00 10 8 -3
01 10 9 -4
11 11 9 -4
10 11 10 -5
00 12 10 -5
- first column are phase A and B inputs;
- second column is phase A interrupt counter (called countA);
- third column is phase B interrupt counter (called countB);
- last column is the position counter.
Look at this:
- when countB is between 0 and 6, there is no increment in the position counter and both pins are never 1 at the same time! This was a quater turn CW very slowly.
- when countB is between 7 and 12, the position counter gets 5 pulses and both pins get all possible transitions.
I’ve been working with industrial encoders for years and this is not a good behaviour for an encoder. Maybe there is something wrong in the board or I’ve mounted it wrong, but all has been done as in your photos.
Best Regards,
suby