Quote:
Originally Posted by sumadin
Sorry to hijack the thread, but I'm wondering how you would tell what direction you moved. I don't doubt this can work very well for something that only goes under a revolution. However, let's say you moved from 100 degrees to 200. How do you know if you moved 100 forwards or 260 back?
Thanks.
|
Before I even start, here's the, well, you might call it the Nyquist rate for sampling these rotary analog encoders (aka Limitless Pots). Unless you use adaptive sampling rates (DO NOT if you are using a PID and don't want to have dynamic constants on the terms) you have to sample the voltage about four times per revolution, or else you won't know which way you went (there may be a more efficient way but this is what I used last season). Therefore, I suggest you figure how many RPM the shaft you are coupled to could do in the worst possible situation, then add some to that (use your engineering sense). Obviously if you miss a revolution you'll be in trouble and have problems like you mentioned above.
I drew a diagram (using my graphic tablet I got on Black Friday...

) that explains how this system works. Essentialy you break the waveform that the analog encoder outputs into sections, and do a state-based decode. Since you're sampling at a rate four+ times that of the rate of revolution, you will be able to detect a high-contrast change in the values comming back from the analog encoder and be able to figure that you went from a high-to-low or low-to-high transition, thus indicating the direction in which you moved.
Aside from that, the rest of the system functions on deltas: you add or subtract how much the values have changed depending on which direction the analog encoder is moving.
Here's the code snippet that handles one of the analog encoders (there were two) on our robot. This function was called at a rate of 100Hz using a CCP module for timing (it also was running a high-performance pwm signal for the pid'ed traction motors on the robot):
Code:
void encoder_left_handler(void)
{
if(ServoOn) //if servos running, sample encoder
{
leftencoderpos = Get_Analog_Value(LEFTENCODER); //get value from other encoder
if (leftencoderpos <= 253)
{
leftencoderstate = 0; //state a
}
else if (leftencoderpos <= 505)
{
leftencoderstate = 1; //state b
}
else if (leftencoderpos <= 757)
{
leftencoderstate = 2; //state c
}
else
{
leftencoderstate = 3; //state d
}
if (leftencoderstate == 0 && oldleftencoderstate == 3) //from top to bottom, rev
{
//going backwards
leftencoder -= (int)((1009 - oldleftencoderpos) + (leftencoderpos-2));
}
else if (leftencoderstate == 3 && oldleftencoderstate == 0) //from bottom to top, fwd
{
//going forward
leftencoder += (int)((1009 - leftencoderpos) + (oldleftencoderpos-2));
}
else //intra-state position calculation
{
if (leftencoderpos < oldleftencoderpos)
{
//goingfwd, intra state
leftencoder += (int)(oldleftencoderpos - leftencoderpos);
}
else
{
//goingbkwd, intra state
leftencoder -= (int)(leftencoderpos - oldleftencoderpos);
}
}
oldleftencoderstate = leftencoderstate; //save encoder state
oldleftencoderpos = leftencoderpos; //save old encoderposition
} //end if servo on
//...
This system works very very well, we used it to run a 100Hz update rate PID (as I stated before, we were feeding the Victors a 16-bit PWM signal at 100Hz as well as opposed to the standard 8-bit 39.37Hz) which performed with silky-smooth motion control during our post-season autonomous work. I definitely reccomment analog encoders. As long as you show 'em a little love with shielded cables, smart wiring (keep the wires short!), and a little software know how, you get fantastic positional accuracy without the need to handle extreme high frequency (in the KHz) interrupts at high speed.
Questions? Post!
-q