We have installed a VEX shaft encoder, connected to a digital input, on the shaft of a Fisher-Price motor. We have the routine that counts pulses from the encoder in the User Routines Fast section.
When the motor runs quickly, the encoder routine that counts pulses counts too few pulses. The spec sheet on this encoder indicates that it will handle ~ 1100 rpm. The FP motor is turning at ~100 rpm, so the shaft is not rotating too quickly.
Does anyone have any experience using this encoder, or any ideas on what could be causing this problem?
I have successfully used the vex encoders. I think that the biggest cause of your inaccuracy is that you are not using an interrupt for your input (a special kind of digital input). (Am I correct?)
Let’s do the math to see why an interrupt is necessary:
100 RPM x 100 pulses per revolution is 10,000 pulses per minute
10,000/60 = 167 per second
So frequency is 167 Hz.
Period is 1/freq. = 6 ms per pulse.
Now remember that if you are polling, the pulse will only be high for 3ms out of the 6ms period. So if you see that the signal is low on this pass through the loop and then come back 4ms later and it is still low, a 3ms pulse could occur that you would miss.
Try bringing the signal in on an interrupt line ( digital inputs 1-6 ). Interrupts 1 & 2 are edge triggered, 3-6 fire on each transition. See the Kevin
Watson encoder sample to help with the interrupt code.
I’m having some trouble with the VEX shaft encoders as well… I think it’s a hardware related problem, but here is the code I’m using to count the ticks:
if (rc_dig_int1 != left)
{
left = rc_dig_int1;
leftoptenc = 1 + leftoptenc;
}
if (rc_dig_int2 != right)
{
right = rc_dig_int2;
rightoptenc = 1 + rightoptenc;
}
It all sort of works, but even when I have both shafts tied together, the values will jump back and forth by 10, and if I leave it for a while, hundreds, although both have had the same amount of revolutions.
We have had problems that were solved by taking the cover off and using canned air to blow off the dust/plastic shavings. If you don’t mount them perfectly you can get some wear and tear causing dust/plastic shavings to accumulate.
I’ve cleaned both out as good as I can. I took both of them apart, and cleaned the wheel and the sensor with rubbing alcohol, and it’s still giving me the same result. I think I might had a dud sensor, but I can’t return them because Team Fusion has owned them for a long time now, and this is the first time we’ve tried to use them, but who knows… If anybody else has any suggestions, it will be greatly appreciated.
Looking at the code you posted above it looks like you aren’t using easyC. If you have access to easyC I would use the online window to look at the values being returned from the encoder.
You can also post at vexforum.com and someone over there might be able to help.
I would definitely rewrite the code using an interrupt routine, you are only checking the state of the encoder once every loop, for the regular FRC controller this is i believe once every 26ms I am not that familiar with the vex platform but I doubt that it is much faster.
If the math posted earlier in the thread is correct ( I believe it is) then running at full speed you might catch one out of every 4 or 5 pulses. You can’t adjust for this in software since the motor does not always run at the same speed.
What you need to do is write an interrupt service routine, this is just like a regular function but it is called immediately when an event occurs. For example when the system clock overflows or when a switch is pushed or in your case when the encoder goes high. the ISR would be very simple you would just increment the counter variable. You can then use the count any where in the code you want. As a warning never make your ISR code complicated for example do not include loops, since it may be called very ofter you want to make sure it executes quickly.
Could you help me with this. I’m new to programming, and am not very good at all. I was thinking that the cpu must be pretty fast to catch every loop perfectly. So where should I write this code and what should I write?
Alright, In User_routines.c you want to declare (globally, at the top where it says initialize user variables) a variable that will count pulses. For this example call it count.
in the User_Initialization function add this line
INTCON3bits.INT2IE=1;
This line enables Interrupt 2 if INTCON3bits.INT2IE is equal to 1 then every time the signal pin on digital input 1 goes high then it will enter the interrupt routine.
The final step is to add a line into the interrupt routine
Open user_routines_fast.c
go down to the InterruptHandlerLow function
The first if statement is the one you want to change just so you know what the if statement actually says.
it says “if (INTCON3bits.INT2IF && INTCON3bits.INT2IE)” INTCON3bits.INT2IF is the interrupt flag, it is tripped whenever the pin goes high, INTCON3bits.INT2IE is the interrupt enable flag you set that to 1 in the last step.
Inside the if statement you want to add “count++;” (or whatever you named the variable)
Make sure you leave INTCON3bits.INT2IF = 0; other wise the code will keep stepping into the interrupt.
Now you can use the count any where in the code you want, you can reset it to 0 if you want to, basically use it just like you were before.
The reason you need the interrupt is that at decent speeds the encoder can pulse more than once per loop, if you were using it in a lower speed application, say on a high torque gearbox it may not be necessary.
One last note, this will only count half as many pulses per revolution as yours did, the interrupt only counts high signals at the pin, your code counted every change, both low and high. THe interrupt however should give you plenty of resolution.
If you have any more questions my s/n on AIM is JamesBrownsSN otherwise just post or PM me. Good luck.
There are easier options. You could upgrade to the latest version of Easy_c and use the vex encoder block. If you want to use MPLAB and code in c you could take advantage of a function library Called WPLIB. Look under the easy-c intelitek sub forums. In the library there are functions for many of the sensors you can use for vex and FRC. This way you can concentrate on the robots action and not get buried and bogged down with low level routines. After you have increased your programming skills, revisit interrupts, counters and timers by studying Kevin Watson’s Source code.
I’m about to try the code. The reason I had it counting both High and Low is because I’ve noticed that the when the encoders stop, sometimes they will give a high signal all the time. So I had it setup to wait for a high, and if there is a high, then wait for a low, and so on…
I finally got the code working. After numerous problems with trying to make global variables (something I just learned today :yikes: ) and then having trouble with some crazy syntax error that I wasn’t sure what the heck it was talking about (so I just deleted the code) I finally got it working. It seems fairly accurate, although the robot still drives crooked, but the encoders are driving much more straight than before, which was in circles. Thanks JamesBrown for all your help, I couldn’t have done it without you.