Pololu's Encoders Problem Using Arduino Mega

When I use your library I only get zero returned from the getCountsM1 function. When I use interrupts I get multiple counts per interrupt (edit: because I am getting noise on my 5V rail; edit again: was coming from all 3 of my SharpIRs).

My code for using your library:

#include <PololuWheelEncoders.h>
PololuWheelEncoders encoders;

void setup() {
  Serial.begin(9600);
  encoders.init(2,3,18,19);//Arduino Mega pin numbers
}

void loop() {
  Serial.print(encoders.getCountsM1());
  Serial.print(" ");
  Serial.println(encoders.getCountsM2());
  delay(1000);
}

Code I am using for interrupts:

volatile int count = 0;

void setup(){
  Serial.begin(9600);
  
  attachInterrupt(0, blink, FALLING); // 0 = digital pin 2
}

void loop(){
  Serial.println(count);
}

void blink(){
  count = count + 1;
  //Serial.println(count);
}

Any help would be great! Thanks!

Ted and I ran a few tests today during the Atlanta Hobby Robotics Club meeting using my UNO, Mega, and my Pololu wheel encoders.

Using the encoders with an UNO worked great

Using the encoders with a mega, regardless of which pins we tried did the same at Ted’s.

It would appear there’s something that needs to be added into the wheel encoder library to make it work with a mega.

I just got my mega this week so I still need to test the QTR line sensor library to make sure that still works as well.

In short, I believe that the encoder library does not have code to work with the Mega2560 processor to set the interrupt pins in the “enable_interrupts_for_pin” function. I will see if I can make the changes but it is out of my area of expertise.

If anyone wants to join in on the fun I think these are 2 good starting points:

arduino.cc/playground/Main/PinChangeInt

arduino.cc/playground/Main/RotaryEncoders

Thanks for any help! :smiley:

Or, are we somehow using the software incorrectly?

I’m on a Mac, so we just downloaded the latest zip file, and I moved everything in the src directory over to my Documents/Arduino/libraries/ folder and restarted the Arduino software.

As I stated. That seemed to work fine when we were building and running on the Uno - we got back counts as expected (using just the first chunk of code Ted included above).

When we tried the same code on the Mega, (and yes, we set the target board to the Mega) we get nothing back - always 0.

Additionally, it would be nice if the Encoder stuff was available in an arduino-specific library as well (like the QTR Line sensors do) so it would be easier to use them on Arduino…

Ok, some more detective work has at least shed some light onto why this wasn’t working on the Mega…

You guys are making use of the Pin Change Interrupt capabilities of the AVR chip. Apparently the Mega does this a little differently due to the number of IO ports it supports.

I did find some information in the “Practical Arduino” book on how this is done on the Mega, and I also found a library called PinChangeInt that does this sort of thing on the Uno/Duem board’s ATmega328p chips, but doesn’t have the support for the Mega 2560’s chip.

So it looks like it’s just a matter of adding the support to the the library…

Keep us updated if you make any progress. I’m having the same issue.

Hi there!

I have the same problem as you guys.

Maybe this can be of help? I found that some other people have had a simmialr issue with the NewSoftSerial and pin change interrupts on the Mega 2560. Apparently not all pins on the Mega can be used with the interrupts.

One guy has modified the code for the NewSoftSerial to work with the Mega. Maybe these modifications can be implemented for the wheel encoders too?

Here’s his post in the Arduino forum: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1287382108

And here’s the code: http://code.google.com/p/rogue-code/downloads/detail?name=NewSoftSerial10c-withMegaAndStream.zip

I’ll check that out, thanks!

I’ve made some changes to PololuWheelencoders.cpp so it’ll work for my Mega2560. Note that it will only work for the Mega2560 with these changes.

It’s probably not the best way of doing things, but it works for me…

I only made changes in two functions. get_val and enable_interrupts_for_pin

inline unsigned char get_val(unsigned char pin)
{
	// Note: get_val will work (i.e. always return the same value)
	// even with invalid pin values, since the bit shift on the final
	// return will cause the port value to be shifted all the way to
	// 0.
/*	if(pin <= 7)
		return (PIND >> pin) & 1;	OLD CODE
	if(pin <= 13)
		return (PINB >> (pin-8)) & 1;*/

	if(pin <=13) 
		return (PINB >> (pin-6)) & 1;
	if(pin <= 50)
		return (PINB >> 3) & 1;
	if(pin <= 51)
		return (PINB >> 2) & 1;
	if(pin <= 52)
		return (PINB >> 1) & 1;
	if(pin <= 53)
		return (PINB >> 0) & 1;


//	return (PINC >> (pin-14)) & 1;		OLD CODE

	return (PINK >> (pin-62)) & 1;
static void enable_interrupts_for_pin(unsigned char p)
{
	// check what block it's in and do the right thing
/*	if(p <= 7)
	{
		PCICR |= 1 << PCIE2;    OLD CODE
		DDRD &= ~(1 << p);
		PCMSK2 |= 1 << p;
	}*/
	if((p >= 10) && (p <= 13))
	{
		PCICR |= 1 << PCIE0;
		DDRB &= ~(1 << (p - 6));
		PCMSK0 |= 1 << (p - 6);
	}
	else if(p == 50)
	{
		PCICR |= 1 << PCIE0;
		DDRB &= ~(1 << (3));
		PCMSK0 |= 1 << (3);
	}
	else if(p == 51)
	{
		PCICR |= 1 << PCIE0;
		DDRB &= ~(1 << (2));
		PCMSK0 |= 1 << (2);
	}
	else if(p == 52)
	{
		PCICR |= 1 << PCIE0;
		DDRB &= ~(1 << (1));
		PCMSK0 |= 1 << (1);
	}
	else if(p == 53)
	{
		PCICR |= 1 << PCIE0;
		DDRB &= ~(1 << (0));
		PCMSK0 |= 1 << (0);
	}
	else if(p <= 69)
	{
		PCICR |= 1 << PCIE2;
		DDRC &= ~(1 << (p - 62));
		PCMSK2 |= 1 << (p - 62);
	}
	// Note: this will work with invalid port numbers, since there is
	// no final "else" clause.
}

Jazzp,

I tried your changes but I don’t get any output from the encoders using the same sketch I posed in the first post in this thread. It uses 2,3,18,19. I am guessing your code doesn’t support those pins? Which pins should I use with your code? Could you post a working sample sketch?

Thanks!
Ted

The thing with the ATMega2560 is that not all pins are connected to Pin Change Interrupts. The Arduino pins that are connected are (and can be used with the modifications I made): 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69.

The Arduino Mega2560 PinMapping: http://arduino.cc/en/Hacking/PinMapping2560

Here’s a sample sketch that’s working for me, using pins 50, 51, 52, 53 as encoder inputs:

#include <PololuWheelEncoders.h>

const unsigned char m1a = 50;
const unsigned char m1b = 51;
const unsigned char m2a = 52;
const unsigned char m2b = 53;

PololuWheelEncoders encoders;

void setup(){
  encoders.init(m1a,m1b,m2a,m2b);
  Serial.begin(9600);
}

void loop(){
  Serial.print(encoders.getCountsM1());
  Serial.print(", ");
  Serial.println(encoders.getCountsM2());
  delay(500);
  
}

Jazzp,

Still didn’t work for me. I used mapped pins 36,37 and 40,41.

As an aside, do you have any code for computing speed from encoders? Seems like it would be simple but the timing between pulses seems to be random with a steady speed for me.

Thanks!
Ted

Sorry if my previous post was confusing. The Arduino Mega2560 pins that can be used are, 10, 11, 12, 13, 50, 51, 52, 53 and 62-69.

Unfortunately I don’t have any code for speed calks. I’m only going to use these to get distance traveled for each wheel.

Jazzp,

Ack! Sorry! face-plam Posed the wrong numbers, too confusing for me at 1am… :stuck_out_tongue:

I used mapped pin names 40,41 which are pin numbers 51,52. Didn’t work.

I got my speed code working, I was trying to do it under the interrupt before and I guess millis() doesn’t like that.

Thanks,
Ted

Ok, I’m getting REALLY confused on the pin #'s you guys are posting…

Where are pins in the 60’s??? Is that the Analog in pins? (If so, that would be AWESOME since I’m not currently using any of those!)

Or are those the CHIP pin #'s?

Please give the pin #'s in terms of on the Arduino Mega board itself…

I’m confused… Certainly want to give this a go though!

Ted, for speed calc-

Just going on my understanding here, but slowly rotate the wheel, see when you get the pulse that causes the increment to occur.

Once you know that, you measure the angular change on your wheel per pulse.

Then it’s just some basic trig - angle/360 = x/circumference of your wheel. Solve for X and that tells you the linear distance that should be covered when the wheel pulses once.

For speed, look at the time difference between the last measurement taken and now and the pulse count to get the speed. V= Distance/Time

Hope this helps.

I’m sorry for the confusion.

Using the modified functions in Pololuwheelencoders.h, posted earlier in the thread, the Arduino Mega2560 pins that you can use are:

Digital pins: 10-13 & 50-53.
Analog pins: 8-15. (These corresponds to pins 62-69 in the code).

I hope that makes more sense.

Ok, yes, MUCH more sense! THANK YOU!

I’ll have to give this a try after the game tonight…

Has anyone tried using the default PololuWheelsEncoder.cpp/h with the Arduino Uno Revision 3???

Similar symptoms to the Mega’s problem. Further testing has even weirder things happening like:

Wheels stop responding to PWM signal from Arduino (through Dual Channel Motor Driver Carrier). Wiggling the wheels somehow starts it up again. Seems like somethign to do with interrupt mappings?

All other pins has weird behaviors (IE: A working ultrasonic module + code would not work when motors are also connected to MCS. Again “wiggling” somehow fixes things).

Lastly, what exactly do I have to rewrite in the PololuWheelsEncoder source do I have to do to get it work with the Arduino Uno Revision 3?

@makopack
I actually first saw your post on the Arduino forums?
Did you a have any luck in getting everything working? What fixed it? (I’m assuming you probably changed some of the interrupt->pin mappings).