Question about using 2 encoders

Hello, I'm new to this forum and I would like some advice on using 2 motors with encoders on an Arduino Duemilanove! My friend told me that it supports only 1 encoder. Isn't there anyway to use 2 motors with encoders at the same time on this Arduino model? Thanks everyone!

As the 2009 has 2 IRQ lines it is perfectly possible to support 2 motors as only one is needed per encoder

The code below shows you how to read direction and counts with only one IRQ line and a normal digital IO line per encode. As you have two you need to implement it for IRQ 1 and encoder1 too.

#define encoder0PinA 2    //  = IRQ 0
#define encoder0PinB 4

volatile long pos = 0;         // long can hold far more pulses than int; signed to know direction since start. 
volatile boolean CW = true;    // direction if false it is CCW

void setup()
{
  // SERIAL COM
  Serial.begin (115200);
  Serial.println("Start app");

  // CONFIG IRQ
  pinMode(encoder0PinA, INPUT);
  attachInterrupt(0, doEncoder, RISING);    // CHANGE will work too but gives you twice the amount of irq's! Do you need that much?
}

void loop()
{
  // OUTPUT ENCODER INFO
  Serial.print("pos:  "); 
  Serial.println(pos);
  Serial.print("direction 0=CCW   1=CW:  ");   
  Serial.println(CW);

  delay(250);  // simulate other activities.
}

void doEncoderA()
{
  // determine direction
  CW = (digitalRead(encoder0PinB) != digitalRead(encoder0PinA));  

  // update position
  if (CW)  pos++; 
  else pos--;
}

Thanks for the quick answer! I'll take a look on it! =D

Have you ever used two motors with encoders like this?

My friend answered the following:

I cant understand what is happening there.
Each motor have 2 wires from the encoder, and you call the interruption only in one wire?
What if the other changes the value?

What i did was one wire in each interruption refreshing the position at any change of encoder0pinA or pinB.
But with that all the IRQ were being used.

For 2 motor i ll have 4 encoder wires, and i guess i need to call an interruption each time any wire of the same motor changes the value, but how to do that? Doing this ill have one interruption for each motor.

And how your pos calculation work? I dont need a state machine??

What do you think about that?

You can still make it work with 2 interrupts. If the other line changes its value, it just has to wait and you check it when the first line changes.

For example connect the A signal line from each encoder to one of the interrupt pins. Whenever the A line changes the interrupt routine can then check the B line, basically at that point if the A and B lines match you are going one direction, if they don't you are going the other.

Its true with 4 interrupts you would get finer resolution out of the encoders but then the arduino you have only has two external interrupts.

How many counts per revolution on the encoders and how fast do they go?

If they don't change state too frequently I would just poll the encoders from a timer overflow interrupt using a state machine, i.e., was in A high, B high, now I'm A high, B low, so increment encoder count.

What do you mean position calculations? Position of the wheel is easy, theta = (EncoderCount * counts/radian) +- counts/(radian*2). The last part is systematic error that will always exist, you know you are somewhere between ticks but not exactly where.

If you want position of the robot it is a bit more complex. Basically, something like this. On set intervals look for position changes, or encoder ticks. Translate rotational movement to linear movement based on the diameter of your wheels, any mismeasurement or mismatching of wheels will introduce more errors here. Then take the motion of both sides and calculate the change in angle and position of the entire robot in an arbitrary x-y frame. If you perform this calculation regularly and often you have a number that is basically the integration of the velocity of the robot as a whole, which is the position.

Things to consider, at each cycle you basically start with a direction you are facing, a position, and position changes for both sides and if you tried to actually do the math required to get the correct answer the arduino is likely going to have trouble keeping up especially if you are using floats, since the math also uses some trig functions, and all of this tends to works better the more often you run it.

This page has some approximations you may find useful. A Tutorial and Elementary Trajectory Model for The Differential Steering System

One last caveat, since the final position information you arrive at is the integration of velocity information, any error in velocity info gets compounded over time. Since you have error coming from several independent sources, including mismeasurement of wheels base, wheel radius, mismatched wheel radii, wheel slippage, missing encoder counts, math rounding errors and the like, inevitably, and possibly quite quickly, your robot will be completely wrong about where it is. You need some kind of external reference (beacons, floor marking and a way to sense them) if you want to combat the drift in position.

Sorry growler, I didn't understand what you explained. Are you talking about the use of two motors with encoders in a single Arduino? And have you ever made something like this work?

Thanks for the attention, and best regards.

Spielwurfel:
Sorry growler, I didn't understand what you explained. Are you talking about the use of two motors with encoders in a single Arduino? And have you ever made something like this work?

Thanks for the attention, and best regards.

I've used two independent encoders at the same time. I don't understand the "Each motor have 2 wires from the encoder for each encoder". Most encoders require four wires, power, ground, channel A, and channel B.

Perhaps a link to your motor/encoder would be helpful.

Lefty

Sorry, you're right, here is the motor I pretend to use.

And yes, the encoder has 4 wires, but what I mean is that the 2 power supply wires are not a problem since I can power up as many encoders as I want with no problem.

The problem are the 2 wires that reads the encoder, and their connection on Arduino!

I'll be very glad if you can help =)
Thanks everyone!

The problem are the 2 wires that reads the encoder, and their connection on Arduino!

Well each encoder has two output channels, A and B.

So:
wire encoder#1 channel A to arduino pin 2 (that is user interrupt 0)
wire encoder#2 channel A to arduino pin 3 (that is user interrupt 1)
wire encoder#1 channel B to arduino pin 4
wire encoder#2 channel B to arduino pin 5

Wire ground to both encoder ground pins, and wire +5vdc to both encoders power input pin, assuming they are +5vdc encoders.

You may have to wire four external pull-up resistor from pins 2,3,4,5 from +5vdc to the input pins as many encoders have an open collector type output stage and so require the pull-ups on their two channels A & B. 10k ohms would be fine.

The reset is all software in the two ISR routines.

Lefty

Sorry, I forgot the motor link, but I think it's not necessary anymore.

But well... So, is it really possible to use two encoders with the arduino?
Does the explanation of growler works? Because I didn't understood it actually... :blush:

Thanks everyone!

Spielwurfel:
Sorry, I forgot the motor link, but I think it's not necessary anymore.
Pololu - 131:1 Metal Gearmotor 37Dx57L mm 12V with 64 CPR Encoder (No End Cap)

But well... So, is it really possible to use two encoders with the arduino?

Yes, yes, yes, yes, and yes, an arduino can handle reading two encoders.

Does the explanation of growler works?

Yes...........

Because I didn't understood it actually... :blush:

Interrupts and writing ISR functions are an advance topic. Encoders are a little more complex then simple single input on/off sensors. You maybe should keep read the various encoder reading sketches until it 'clicks' what is going on.

Thanks everyone!

Wel, thanks a lot for growler and retrolefty!! I asked all this stuff because it's for a very importante work for college, and I need to use these motors with encoders, but I can only buy them in the USA, and they're very expensive, including the importing here to Brazil. So I didn't want to buy it with risk of not working.

Thanks a lot for the patience and all the explanation!

:slight_smile:

Spielwurfel:
Wel, thanks a lot for growler and retrolefty!! I asked all this stuff because it's for a very importante work for college, and I need to use these motors with encoders, but I can only buy them in the USA, and they're very expensive, including the importing here to Brazil. So I didn't want to buy it with risk of not working.

Thanks a lot for the patience and all the explanation!

:slight_smile:

Well the basic concept of an arduino handling two motors/encoders is not if it can do it or not, but rather at how high a speed of the motors will the arduino be able to keep up with without losing step counts from the encoder.

I can't answer that as that is a function of how much stuff you will be doing Vs the speed of the incoming encoder pulses. The ISR routines will need to be as short and fast as possible.

Lefty

Ok, looking at those motors I would not poll the encoders. According to the link you get 8384 counts per revolution, and a speed of 80 RPM.

Edit, preceded by bad arithmetic and forehead slap:

So at top speed you would have 80 * 8384 * 2 = 1,341,440 encoder counts per minute (this is what was wrong) coming in. This should be possible as long as you take care with your ISR's.

So at top speed you would have 80 * 8384 * 2 = 1,341,440 encoder counts per second coming in. Assuming you are running at 16 MHz that gives you 16,000,000/1,341,440 = 11.92~ clock cycles per event which doesn't seem possible.

Should not that be:

(80rpm / 60) X 8384 cpr X 2 encoders = 22,457 total counts per second for both encoders ?

Yes, that should, thank you. I suppose I'll edit that post to avoid confusion.

You are not limited to 2 encoders, the pin change interrupts can be configured to respond to changes on any set of I/O pins.

You are right that there is no theoretical limitation to two encoders but it is more of a hassle since the ISR needs to keep track of which pin triggered the interrupt and whether it was a rising or falling edge when using the pin change interrupts since you only have one ISR per i/o port, and it can't be set to an edge, just a change.

I understand you probably know this, more for the op's benefit.

Thanks thanks thanks everyone for your great attention! =)

I'm studing mechanical engineer, so this kind of thing is like rocket science to me! You made it much more easy for me to understand!

Thanks again!