Go Down

Topic: Rotary Encoder Drift?? (Read 3150 times) previous topic - next topic

roypardi

I'm really stuck here so I hope someone can help-

This is with the Wiring board but maybe it's a more general issue that someone can tip me to.

I have a Maxon motor with a rotary encoder attached and am using the barebones code (+ using v12 of Wiring) below to try to sort out an issue with the encoder position drifting. By drift I mean that the reported position accumulates errors so that the reported position is out of scope with the actual number of motor shaft turns.

To try to isolate the issue I have the motor set up so I can rotate the shaft by hand a fixed number of turns- so I am confident that I return it to it's starting point. The greater the number of turns and the faster I turn, the more the errors accumulate.

For my project I don't need absolute accuracy but I can't have as much drift as I am seeing. I believe I have the encoder correctly wired up and the code below works so I am stumped and have spent 2 days at this trying everything I can think of.

Could the encoder be sending pulses faster than the Wiring board can handle? If so do I have any options? Would additional interrupts help? I don't need greater resolution - just less/no drift?

The only other thing I can think to try is to hold my test up to an arduino board to see if I get the same drift issue.

Thanks for *any* tips!!

--Roy (lists AT roypardi.com)


The encoder:
http://pdf.directindustry.com/pdf/maxon-motor/programm-07-08/7173-21152-_251.html


Code: [Select]
int statusLED = 48;
int encoder0PinA = 2;
int encoder0PinB  = 15;
int encoder0Pos = 0;

void setup(){
 pinMode(statusLED, OUTPUT);
 digitalWrite(statusLED, HIGH);

 Serial.begin(9600);

 pinMode(encoder0PinA, INPUT);
 pinMode(encoder0PinB, INPUT  );

 attachInterrupt(encoder0PinA, doEncoder, RISING);
}

void loop()
{
 Serial.println (encoder0Pos, DEC);
 delay(30);
}

void doEncoder(){
 if (digitalRead(encoder0PinB) == LOW) {
   encoder0Pos = (encoder0Pos + 1);  
   digitalWrite(statusLED, HIGH);
 }
 else {
   encoder0Pos = (encoder0Pos - 1);
   digitalWrite(statusLED, LOW);
 }
}

Daniel

hi

Are the errors occurring while the encoder is connected to the motor? that could be just a number/sampl9ng rate thing: the processor misses reading a few encoder states.  

Are the errors occurring when you turn it by hand? One thing in my experience is that encoders aren't designed to be accurate when turned by hand: the hand jitters at the start and end of a rotation. A motor, by contrast, usually doesn't do that: it starts slow, ramps up to speed, slows down and stops. It doesn't turn backwards at any point, which the hand does just for an instant when turning an encoder. Try and hold your hand steady for a few seconds, without moving more than the say 1mm resolution of movement that the encoder gives, and you'll see what I mean...

D

roypardi

hi daniel,

thanks for the reply!

I have a little test rig set up with the motor/pulley mounted at one end and a pulley at the other. They are connected by a timing belt so there is positive tracking (no slippage). The encoder is built on the motor. I have hard stops on the base of this rig so that when I run the belt back and forth by hand I can stop at known absolute positions.

The errors I am seeing are not slight hand jitter - I know what you mean there - rather they are much larger - so starting at one hard stop as zero, running the belt back and forth by hand and then returning to the zero point, the encoder output will be off by 20 or 30 steps, and continue to drift if I keep moving the belt back and forth. (i.e. the drift continues to increase).

The only thing I can think is that the processor is missing pulses somehow - even though I am using interrupts. I can't see how to compensate for this in code since it doesn't seem predictable. Right now the only ugly solution I can think of is to zero out the motor through the use of a limit switch before every move but that would be a real drag (return to known zero point triggered by the limit switch).





Digger450

#3
Aug 18, 2007, 12:37 am Last Edit: Aug 18, 2007, 12:38 am by Digger450 Reason: 1
I haven't messed with interrupts much yet, so I am just speculating here :)  I'm thinking you might be missing steps while you are sending serial data.  You could try having it send less frequently rather than constantly sending or possibly add a push button that triggers the serial send.  Just a thought, I may be way off.

Daniel

I think Digger has got it.... the processor is missing steps.
If it misses a lot, it means that [ch8710] is too high-- too fast of a rate of change for the processor. Not sure how to fix, but definitely fixable.
D

roypardi

brilliant! It doesn't solve my problem entirely but at least now I have confirmation that the Wiring board is missing encoder pulses - and that the Serial.print() command makes it much worse.

I added a 10 second delay in my loop() to throttle down Serial.print() and the missed pulses/drift is much less:
0        <------ hard stop start point
-2921  <------ hard stop end point
-2225  <------arbitrary stopping point w/ lots of movement for 10 seconds
-2557  <------arbitrary stopping point w/ lots of movement for 10 seconds
-7       <------ back to hard stop start point (error)
-2929  <------ back to hard stop end point (error)
-5       <------ back to hard stop start point (error)

So it's @ a 7 step error in this short test. That's a lot better- though once I actually add code to do some work in my loop() and run things longer the error will increase over time. But hey, it's a lot better than I was getting. Thanks for the help!!

I wonder if there is a counter chip I place in between the encoder + Wiring board?

--Roy

Code: [Select]
void loop()
{
 if  (millis() >= nextReportTime){
   nextReportTime = millis() + 10000;
   Serial.println (encoder0Pos, DEC);
 }
}


Daniel

just get rid of the serial entirely if possible! Or, increase the speed to 115200, as 9600 serial is slooooooooow, and we like fast in Arduinoland.


D



mellis

I would also remove the calls to digitalWrite() in your interrupt handler.  You can't trigger another interrupt until the first one finishes, and those calls probably take much longer than the rest of the code in the handler.

roypardi

Yeah - I put those in as a diagnostic to try to see when the interrupts were happening (and consequently making my missed pulses problem worse...)


Whew! I think I've got it working well enough now so I can move on to the next bit. And I thought the encoder was going to be the easy part...

Thanks everyone for your help and comments!! I was really stuck.

Interrupts are pretty cool! Have never used them before.

--Roy   :)

Go Up