Let's Make Robots!

Trouble when counting encoder pulses

I have a pair of surplus Faulhaber gear motors with built-in quadrature encoders. I have a motor controller with Arduino and a SN754410 H-bridge. The channel A of the encoder is connected to an external interrupt on Arduino (INT0 and INT1) and the channel B is connected to a regular digital pin. The interrupt is set as Change and the ISR checks the logic level of the interrupt pin and then the level of the digital pin to determine if the counter should be incremented or decremented (depending on the direction of rotation). At a small speed (rotating the wheel by hand slowly) the counter works perfect. As soon as I increase the speed it starts to oscillate between incrementing and decrementing. I need some help troubleshooting this problem. What do you guys think happens? 

Here is the ISR code:

 void doEncoder_2(){

  if (digitalRead(Encoder_2_ChA) == HIGH) {   // found a low-to-high on channel A

    if (digitalRead(Encoder_2_ChB) == LOW) {  // check channel B to see which way the encoder is turning

      Encoder_Count[E2] = Encoder_Count[E2] + 1;         // CCW


    else {

      Encoder_Count[E2] = Encoder_Count[E2] - 1;         // CW



  else                                        // found a high-to-low on channel A


    if (digitalRead(Encoder_2_ChB) == LOW) {   // check channel B to see which way the encoder is turning  

      Encoder_Count[E2] = Encoder_Count[E2] - 1;          // CW


    else {

      Encoder_Count[E2] = Encoder_Count[E2] + 1;          // CCW



  //Serial.print ("Encoder 2 count   ");            // debug - remember to comment out

  //Serial.println (Encoder_Count[E2], DEC);        // debug - remember to comment out


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

I haven't worked with Encoders, but I'm pretty sure you need to use the Interrupts.


Good luck, hope this helps! :D

I would avoid interrupts. Quadrature encoders can easily overwhelm a processor especially one with a slower clock rate. I would skip the interrupts (you aren't going to have it do a lot when you are moving anyway) and have it constantly count encoder ticks until distance desired < distance traveled. Then you can have it go backward if needed. Are you going for P control, PI control or PID control, or just open loop (full voltage until distance desired is achieved).

AFAIK the Faulhaber motors with integrated encoders have a minimum resolution of 16 per motor revolution (not the gear revolution). That will be too much for the controller when the motors run on higher speed. You can reduce the resolution of the encoder to a quarter when you change your program:

  • only fire a interruppt on a change from low to high on Pin A
  • check if Pin B is high or low, for the direction.
Or use a timer instead of the pin change interrupt. The timer overflow interrupt must be fast enough to get each change of A, B. Scan the value of A and B and use a state machine for the different states or A and B. 
Here is an example for this.
I none of this tricks will help, you will need a hardware counter or a FPGA .


There are a couple slow things here: first off, digitalRead takes quite a few clock cycles, which means by the time it reads the I/O pin, the value might have changed, which is probably why it's messing up at high speed. I'd suggest first replacing all of your digitalRead() calls with direct register reads, for instance, if your encoder A channel were on PB0:


There are also other schemes for decoding that would give lower count per rotation, but run faster during the decode stage (for instance, only trigger on rising A, if A==B, then rotation in one direction, otherwise rotation in other direction). If it's still not fast enough, a quadrature decoder chip, such as the LS7084 could help. 



Quote: " if(PINB&0x01){... "

I'm afraid I don't understand the condition... Just to be sure, PINB&0  means as in Bascom PINB.0 and x01 means pin is HIGH? How do I check if pin is LOW? Can you give me an example if I need to check PB3 (so there is no confusion on what is what)?

 Thank you very much. 

Here is a review of the motors: http://www.robotroom.com/FaulhaberGearmotor.html

The encoders give 141 pulses per revolution. If I use Change, I should get double that number, but it seems that I actually get 256 counts. I'll try to eliminate the digital.read stuff and see if that helps (it probably should).

Quadrature encoders use 2 interrupts per encoder and they get 4 times the number of pulses, but Arduino has only 2 external interrupts. I know I could use pin change interrupts, but they are low priority so if a higher priority interrupt gets executed at the same time the pin change interrupt fires, I will lose counts.

Thanks for your suggestions! 

How about a quadrature IC that can keep up with the counts? US Digital has a few. The LS7166 (1 encoder) or LS7266 (2 encoders) with a parallel read of the count can read up to 25 million counts per second as does it in 4x mode (counting all 4 edges).

I use the same motors in a project I made.  It has two of these motors and I use PinChange interupts for the A&B from two motors and I'm able to keep up with them runing at twice the rated voltage of the motors with out error!  It uses FULL 4 time sampling so I get 576 ticks per revolution of the while!

 Here is the board I made with a dual HBridge driver driving the motors.


More images here:  http://bahbots.com/gallery/thumbnails.php?album=3

This was made for an advanced line follower that can record to a flash the quadrature movements to a micro sd card and then replay them.

 It uses a Mega644P MPU, and has P.I.D routines to drive PWM and the H-Bridge to the motors for very smooth movment.  :)

Here is a link to the code (in Bascom-avr): http://mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=6157&highlight=&sid=f6d70469f7c4a442b990f027b0eaabee



Very nice robot, would be good to see it fully posted here with video.  How well do you feel about how the Tamiya wheels are attached to the motor shafts? Did you add any epoxy or anything to strengthen the attachment?  Really good to see a BascomAVR bot. 

I posted the bot just after the reply above.

See here: http://letsmakerobots.com/node/13211

I should have a video in a few days.

The wheels worked very well and worked with just pressure fitting but I did crack the plastic a little and there was a very small amount of slipping over heavy use.  I think this could be fixed by placing some kind of metal or binging around the plastic to protect and make it stronger.