Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

Pololu Forum

Using Pololu Wheel Encoder library in Arduino (under Linux)

Hello. I am trying to use the Pololu library within the Arduino environment, on an ATMega328P. Since Arduino uses C libraries and because theres an ATMega328P version of the Pololu library which uses the same C header format, I set out thinking this should be relatively trivial. However, I’ve had no luck in getting an Arduino ‘sketch’ to use the Pololu library. Specifically, I need to use the wheel encoders library with a ATMega328P.

Unpacking *.o and *.h files to /usr/share/arduino/hardware/libraries/pololu (and deleting them from everywhere else, to be sure) does get the Arduino environment ‘seeing’, and trying to compile, the library. In the case of importing encoders.h, then using compiling encoders_init(7,8,9,10), I receive the following error:

undefined reference to 'encoders_init(unsigned char, unsigned char, unsigned char, unsigned char)'

/tmp/build5757683369907846729.tmp/core.a(HardwareSerial.cpp.o): In function `global constructors keyed to rx_buffer':

/usr/share/arduino/hardware/cores/arduino/HardwareSerial.cpp:114: multiple definition of `__vector_18'

hardware/libraries/Pololu/OrangutanSerial.o:/home/darkmoon/Programming/libpololu-avr/devices/atmega328p/../../src/OrangutanSerial/../../src/OrangutanSerial/OrangutanSerial.cpp:58: first defined here

o: In function `main':
undefined reference to `encoders_init(unsigned char, unsigned char, unsigned char, unsigned char)'

The reference to OrangutanSerial.cpp tells me that this library is dependant on the Orangutan specific serial library and that its therefore not going to be a trivial task to get the Pololu library working under Arduino.

I assume this means I need to grab the sourcecode for the encoder functions and set about rewriting them under Arduino. While I work on this, if anyone knows a shorter solution, I’d obviously be very happy to hear of it :slight_smile:

Hello.

The Arduino environment makes it easy to add your own software libraries, and we designed the Pololu AVR library to integrate easily with the Arduino environment (please note that my last experience was with the Arduino-0012 IDE, so hopefully nothing significant has changed since then to invalidate any of the following instructions). You do this by putting the source code files in a special Arduino directory. Opening the Arduino IDE automatically compiles the files in this directory into object files that you can then reference from your sketches. The following steps will hopefully get your encoders up and running with your Arduino:

  1. Download the Pololu AVR library.
  2. Copy the directory libpololu-avr/src/PololuWheelEncoders from the downloaded archive into the Arduino directory arduino-0017/hardware/libraries, so you would end up with arduino-0017/hardware/libraries/PololuWheelEncoders, in which you’d have the files PololuWheelEncoders.cpp and PololuWheelEncoders.h.
  3. Restart or open your Arduino IDE, which automatically generate the file PololuWheelEncoders.o in this directory. If there are any errors while building the library, you should see them now. We haven’t tested this code on an Arduino, so while I expect it to work, keep your eye out for problems.
  4. Create a new sketch and select:

Sketch > Import Library > PololuWheelEncoders

This will add the line #include <PololuWheelEncoders.h> at the top of your sketch and give you access to this class’s methods. Since all of the methods in the library are static, you can call them in one of two ways:

PololuWheelEncoders encoders; // instantiate an encoder object
encoders.method();

or

PololuWheelEncoders::method(); // call the method statically

See the command reference for documentation on the class’s methods: pololu.com/docs/0J18/13

Please let me know if you have problems getting it working.

To answer your other question (from a post you made earlier and seem to have since deleted), every pin on the ATmega328 has interrupts called Pin Change interrupts, and the Pololu library uses these interrupts to detect encoder output changes (so yes, it’s possible to use two encoders simultaneously). You referred to a second kind of interrupt (external interrupt) that is specific to three ATmega328 pins. Pin change interrupts are harder to use than external interrupts since multiple pins can trigger the same ISR, which means you typically have to put code in the ISR to figure out which pin changed and what the change was. This can make them slightly slower than external interrupts, but the cost doesn’t have to be that high if it’s done right.

- Ben

Hi Ben, thanks so much for a thorough and enlightening reply… I can’t wait to try this out but my wife has just informed me in no uncertain terms that ‘robot time’ has ended for the evening (its 11:45pm here). Sigh, tomorrow :slight_smile: Thanks again, I’ll keep things updated here.

It compiles! Thanks once again, Ben, for spelling this out for me. Perhaps use the appropriate /src/ folder is well known to more experienced Arduino users, but it wasn’t for me. While I haven’t had a chance to actually hook up the encoders over morning coffee, I have seen that…

#include <PololuWheelEncoders.h>
...
PololuWheelEncoders encoders;
...
encoders.init(8,9,10,11);

…compiles properly. Props to yourself and Pololu for providing versatile libraries and excellent support for your products. I’ll report back on actual usage tonight.

Hi all,

I’m new to use pololu products. I used the Arduino platform, and on the example below is shows that 4 inputs are bing used ?

Can i ask why 4 are being uased at the Encoder only has OUTA & OUTB, as you wouldn’t normally define VCC / GND.

Do these encoders require 4 free digital pins as i only have 2 free, which i assumed was ok for OUT A / OUTB

Rich.

For differential-drive robots, you typically want to use one encoder on each drive wheel. You’ll notice that the library code lets you track the counts for two individual motors. If you only have a single motor and encoder, you can just use two pins (e.g. m1a and m1b) and only refer to counts from that one motor (e.g. motor 1). You can use an invalid pin number (such as 255) for the two unused pins (e.g. m2a and m2b); this will cause them to be ignored.

- Ben

That’s great news, as i was starting to panic as the documentation isn’t very clear.

I have the Arduino platform, and reading the documentation and i’m finding it a bit confusing to follow. The documentation mention’s both digital pins and Analog pins, I’m assuming that the wheel encoder needs 2 digital pins.

Does anyone have any code examples for using this with the Arduino Interface as i’m struggling trying to follow the documentation.

I’m a newbie to the whole electronics / programming scene so please excuse me if i seem like i may ask silly questions :

Question 1
Firstly I’m not quite sure how to define the 2 digital pins to be used, in my case pins (10 & 13). So how do i define these ?

Question 2
in the main part of my code, i’m note quite sure how to define the actual measurment of the wheel moving. Do i need to do some sort of IF statement, or does the getCountsM1 statment controll al of that and i just read it’s value ?

Question 3
Arduino doesn’t seem to like the statement below.
static void PololuWheelEncoders::init(unsigned char m1a, unsigned char m1b);

It gives me the following error :

error: prototype for ‘void PololuWheelEncoders::init(unsigned char, unsigned char)’ does not match any in class 'PololuWheelEncoders’C:\arduino\hardware\libraries\PololuWheelEncoders/PololuWheelEncoders.h:52: error: candidate is: static void PololuWheelEncoders::init(unsigned char, unsigned char, unsigned char, unsigned char)

#include <PololuWheelEncoders.h>
PololuWheelEncoders encoders;

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

//Arduino doesn't seem to like this ?
static void PololuWheelEncoders::init(unsigned char m1a, unsigned char m1b);

static int getCountsM1();
static int getCountsAndResetM1();
static unsigned char checkErrorM1();

#define OUTB 10;  // Do i define the pins to use this way ?
#define OUTA 13;

void setup()
{
    lcd.begin(20, 4);
    lcd.setCursor(0,0);
    lcd.print("Wheel Encoder Test");
    lcd.setCursor(0,1);
    lcd.print("==================");
    Serial.begin(9600);
}

void loop()
{
   
  }

Hello,

There is no reason for that line of code to be in your program - it looks like you are trying to declare a function that is not defined anywhere. What were you hoping that it would do?

What you need to do is to actually call init in a function somewhere, giving it all four arguments but using your pin values for m1a and m1b and 255 for m2a and m2b.

-Paul

Hi Paul,

That line of code came from the main instructions for the wheel encoder onthe main pololu web site. This is why iwas saying the instructions a very poor and very confusing.

If i dont need to use that code, i’m very confused as to why Pololu wrote a specific library for the encoder

So bascially i just need to initialize the pins, then count each time the pin changes state from high to low.

Rich.

Rich,

I think you are confusing the declaration of the function given in the command reference with the actual use of the function, which you need to put in code somewhere.

Here is an example for C:

pololu.com/docs/0J20/6.n

You can do something similar using the Arduino/C++ names for the functions instead of the C names. Instead of encoders_init(16,17,18,19), you would use PololuWheelEncoders::init(16,17,18,19). In your case, you would use PololuWheelEncoders::init(10,13,255,255).

-Paul

Hi Paul,

Would it be possible to put up a working example for an Arduino setup.

Rich.

Sorry, we do not have a ready-to-go Arduino example. But we would be happy to help you debug your code if you give it a try yourself and tell us what happens! Does it not work to do PololuWheelEncoders::init(10,13,255,255)?

-Paul

Hi Paul,

No that doesn’t seem work at all.

I’m new to Arduino so I asked on the Arduino forum, and got a few people to look at the instructions and the library from the pololu site. After looking at it most of them are saying that the library file will never work with Arduino, so one guy is looking to write a new library over the next week.

Hopefully, they can come up with something, or I will have wasted my money…
:frowning:

Rich.

Hello.

What about the code is incompatible with Arduino? I found this thread on the Arduino forum:

arduino.cc/cgi-bin/yabb2/YaB … 798247/3#3

The person in this thread seems to think our library will work just fine and is only writing his own because he wants a different interface. If there are other threads that offer differing opinions, can you link to them?

As Paul said, if you post your code and describe what it does, we can offer you some suggestions on how to fix it. Just saying “it doesn’t work” doesn’t give us much to worth with.

- Ben

Paul / Ben,

This is the code i wrote that i’m having trouble with. I’m only using a single encoder.

I have managed to get Arduino to see when the spoke of the wheel as it passes over the each of the sensors, which returns a value of 1 when a sensor is is covered and 0 when it is not.

I’m trying to get Arduino to incrament / decrament a value (i) based on the direction of movement of the wheel, but i’m having trouble getting a stable counter to work.

I thought if i used simple if statements, i could dteremine this, but i’ve had no joy. Below is a rough example of what i mean.

if (sensorA == 0 & sensorB == 1){i++;}
         if (sensorA == 1 & sensorB == 0){i--;}

I have included my main code for you to see if you can suggest anything.

#include <avr/io.h>
#include <avr/interrupt.h>

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

#include <Wire.h>
#include <inttypes.h>

// quadrature encoder

#include <QuadratureEncoder.h>

#define encLtA 10
#define encLtB 0
#define encRtA 13
#define encRtB 0

QuadratureEncoder encoder = QuadratureEncoder(encLtA, encLtB, encRtA, encRtB);

int32_t encLt, encRt;
int i=0;

void setup() 
{ 
  encoder.init();
  Serial.begin(9600);
  lcd.begin(20, 4);  
}


void loop()
{
  int  enc_count;
  int  tot_count = 0;
  int  enc_lt, enc_rt, enc;
  
 
 if (encLt == 0 & encRt == 1){i++;}
 if (encLt == 1 & encRt == 0){i--;} 
 
    enc = encoder.readLt();
    enc_lt += abs(enc);			// read a single step encoder
    encLt += enc_lt;
    enc = encoder.readRt();
    enc_rt += abs(enc);			// read a single step encoder
    encRt += enc_rt;
    tot_count += enc_lt;
    tot_count += enc_rt;

lcd.setCursor(0,0);
  lcd.print(tot_count, DEC);
  lcd.print(" ");
  lcd.print(enc_count, DEC);
  lcd.print(" ");
  lcd.print(encLt, DEC);
  lcd.print(" ");
  lcd.print(encRt, DEC);
  lcd.print("    ");
  lcd.print(i);
 
   /* reset encoder */  
  //enc_lt = 0;
  //enc_rt = 0;
  encLt = 0;
  encRt = 0;
delay (50);
}

Thanks in advance for any help,

Rich.

Hey there, I realize this post is epically old now but my question is along the same line. I’m using a Metal Gear motor (part #2828) and I’m also using a motor driver (part #1451). I think I’ve got this working on an Arduino Uno, but was hoping someone could take a look at my code to see if I’ve done something wrong.

#include <PololuWheelEncoders.h>

#define IN_A_PIN 5  //can be any digital pin, used for motor direction and braking
#define IN_B_PIN 6  //can be any digital pin, used for motor direction and braking
#define SpeedSettingPin 9 // can be almost anything, PWM pin for speed to motor

#define EncoderA 12 // Yellow from motor
#define EncoderB 13 // White from motor

PololuWheelEncoders encoders;

int32_t encoderPosition;

void MotorCW(){
   //set direction to CW, states from Truth table in "VNH5019 - IC datasheet for motor driver.pdf"
   digitalWrite(IN_A_PIN, LOW);
   digitalWrite(IN_B_PIN, LOW);
   digitalWrite(IN_A_PIN, HIGH);
}
void setup() { 

  Serial.begin(9600);
  
  // setup the pins to control motor direction and speed
  pinMode(IN_A_PIN, OUTPUT);
  pinMode(IN_B_PIN, OUTPUT);
  pinMode(SpeedSettingPin, OUTPUT);
  
  //initialize the encoder, NOT using a second motor and have set the second encoder to 255 to not be used
  encoders.init(EncoderA,EncoderB,255,255);

  //Set the motor direction to Clockwise and start moving forward
  //This code is just being used to test the encoder
  MotorCW();
  analogWrite(SpeedSettingPin, 150);
}

void loop() {
  // read and reset the encoder position <----Not sure the best way to read the encoder once it overflows so I'm doing this, if there's a better way, I'd love some input
  encoderPosition = encoders.getCountsAndResetM1();
  Serial.print("Encoder Position = ");
  Serial.print(encoderPosition);
  Serial.println(", counts since last reading"); // does not account for gear ratio
}

If this does what I think it’s doing it reads how many ‘ticks’ the motor has turned since it’s last reading, under no load and constant speed this is essentially a constant though there is some slight fluctuation. To use that number for RPM, or distance traveled I’d then need to account for the time between readings, wheel diameter, and gear ratio (wheel mechanics-101 type stuff). Is there anything obviously wrong with the way I’m doing this? Or a better/more efficient way if something is just horrifically bad-practice?

Hello, Diesel77.

It sounds like you are on the right track, and I think that library should be fine to use with your Arduino Uno, even though it was originally intended for a different purpose. Overal your code looks okay, but, you will need to revise your code for tracking the motor position since using getCountsAndResetM1(); in your main loop like that will just reset your encoder value continuously. You could either add the result of getCountsAndResetM1(); to the encoderPosition value (rather than setting it equal to the encoderPosition value), or you could just use getCountsM1(). With either of these approaches you will still might need to work out how to handle overflows if that turns into an issue.

- Patrick