Quadrature Encoder Counts on 25Dx52L motor 48 CPR encoder

I am using an Orangutan SVP-1284 with the 25Dx52L motor with 48 CPR encoder.

I am writing my own code to get the encoder counts and seeing different results from what the Pololu library provides. In my code I am able to count 48 CPR, but using the Pololu library I am seeing only 24. From what I have looked at the method is_digital_input_high(pin) returns the value of the pin masked to the pin’s location. So when IO_D3 is set it reports as a 0x8 instead of a boolean or 0x1. This affects the behavior of the lines:

unsigned char plus_m1 = m1a_val ^ gLastM1B_val; unsigned char minus_m1 = m1b_val ^ gLastM1A_val;
In the case where we receive a 0x8 and 0x4 for the IO_D3 and IO_D2 pins the XOR operation will drive a plus and a minus in the condition where the m1b pin goes high and the previous m1a pin is high and is currently high. I am basing this on the waveform on the page https://www.pololu.com/product/2285

I want to make sure that I am understanding this correctly. I’ve been trying to use the library as a basis to make sure I am coding it up myself correctly. Here is my code where you can compile in to use the library or the procedure I wrote. Hopefully its self explanatory. In my code I look at the pin output and set it to a 1 or a 0 based on the value returned, essentially treating it as a boolean.

[code]#include <pololu/orangutan.h>
#include <stdio.h>

// uncomment to use the pololu library to get encoder counts
// if not defined we’ll use our own ISR to get them
//#define USE_POLOLU_LIBRARY

// uncomment to use the pololu library is_digital_input_high function
// only valid if USE_POLOLU_LIBRARY is not defined
// if not defined we’ll use our own read of PIND
//#define USE_POLOLU_LIBRARY_INPUTHIGH

volatile unsigned char gLastM1A_val = 0;
volatile unsigned char gLastM1B_val = 0;
volatile int32_t gCounts = 0;

int main()
{
lcd_init_printf();
clear();
printf(“Loaded”);
delay_ms(1000);
clear();

#ifdef USE_POLOLU_LIBRARY
encoders_init( IO_D3, IO_D2, IO_C4, IO_C5 );
#else
PCMSK3 |= (1 << IO_D2) | (1 << IO_D3); //0x0c
PCICR |= (1 << PCIE3); //0x08
sei();
#endif

while(1)
{
	// avoid clearing the LCD to reduce flicker
	lcd_goto_xy(0, 0);
	print("encoder=");

#ifdef USE_POLOLU_LIBRARY
print_long(encoders_get_counts_m1());
#else
print_long(gCounts); // print the number of encoder counts
#endif
print(" "); // overwrite any left over digits
}
}

#ifndef USE_POLOLU_LIBRARY
ISR(PCINT3_vect)
{

#ifdef USE_POLOLU_LIBRARY_INPUTHIGH
// code that will get me 24 encoder counts for a single rotation
unsigned char m1a_val = is_digital_input_high(IO_D3);
unsigned char m1b_val = is_digital_input_high(IO_D2);
#else
// code that will get me 48 encoder counts for a single rotation
// treat each high as a value of 1 and lows as a value of 0
unsigned char m1a_val = (PIND & (1 << IO_D3)) > 0 ? 1 : 0;
unsigned char m1b_val = (PIND & (1 << IO_D2)) > 0 ? 1 : 0;
#endif

// rest of code imitates what the library provides
unsigned char plus_m1 = m1a_val ^ gLastM1B_val;
unsigned char minus_m1 = m1b_val ^ gLastM1A_val;

if ( plus_m1 )
{
	gCounts += 1;
}
if ( minus_m1 )
{
	gCounts -= 1;
}

gLastM1A_val = m1a_val;
gLastM1B_val = m1b_val;

}
#endif[/code]

Please let me know if I am doing something incorrectly. The way I read the waveform and understood the documentation on the motor page, I should be counting the pin changes. Not only when it goes high, but also when it goes low as part of the CPR.

Hello.

It looks like there might be a bug in the library. We will be looking into it.

- Jeremy

Hello.

Thank you for reporting this bug to us and figuring out what causes it. It sounds like you already got your encoders working, but a fixed version of the Pololu AVR C/C++ Library is now available in the Pololu AVR C/C++ Library User’s Guide.

–David