Problems accurately counting pulses

We have a mechanical setup with a motorized ratchet. A small switch is pressed as each tooth raises the pawl. The goal is to turn the ratchet a given number of notches.

The problem is that the code is not running fast enough to catch every pulse (there are about 5 pulses per second, we are not trying to count higher than 5.) We have confirmed with an oscilloscope that the switch is triggered by every tooth, at speeds several times faster than the motor can run (maybe 5 teeth in .1 seconds? It was very fast.)

The programmers claim that they are polling DIO as fast as they possibly can given all the other code that is running on the robot. They said it is about once every 100 ms. This is obviously too slow to catch the pulses.

This is where the trouble begins. As a disclaimer, I am a mechanics and electronics person with decent programming background, though not LabVIEW.

I claim that the cRIO can poll much faster than 100 ms, and that there is some team-introduced inefficiency in the code that causes the DIO loop to only run every 100 ms. I think that this bug should be located and fixed.

The programmers claim that we have designed a system incompatible with the cRIO’s capabilities, and that it is practically impossible to get faster than 100 ms polling due to FIRST’s code (I guess they mean things like radio communications). They say we need to mechanically change the system somehow to make it click slower.

I’d like to know which of us is being hard-headed in this situation. The fact that we ship tomorrow isn’t helping the tension, but we will still have a few weeks to work on the code as well as anything we choose to withhold.

To give some background on the code, we are using LabVIEW and CAN via a black jag bridge. The other parts of the code that could be taking up processing power are:

  • Open-loop meccanum drive code
  • Closed-loop ball-kicking code (a state machine that reads some limit switches, runs a motor accordingly) (this is where counts are being skipped)
  • Current sensing via CAN on a vacuum motor

To me, this all seems fairly easy on the processor and should run very fast. There is no vision code (we disabled it for testing) and no complicated closed-loop controls (ball-kicking deals with a limit switch and the ratchet counter switch, it hardly constitutes closed-loop.) It’s all just math. The programmers get very angry at me when I say it should run faster, because they say it can’t.

We’ve come up with a few options:

My idea: Find out why the code runs so slowly and optimize it so that it can count pulses well. This, of course, makes them angry, and they say that my problem doesn’t exist and therefore can’t be fixed.

Their idea: Modify the kicker so that it pulses slower. This is currently what we have implemented, specifically by decreasing the motor power to 50% (it was an easy change in code.)

This lets every count be registered, but puts the motor very close to stall and could stall when we run our 4-CIM meccanum drive simultaneously, or have a low battery. Stalling would be bad, since it’s a FP motor. However, my concerns are trumped because half-power makes it work. It still seems like a dangerous band-aid style fix, which to me isn’t much better than non-working.

Some other thoughts. I’ll letter them, to facilitate response:

a) Encoders count much faster than this switch, so there must be some way to count quickly, namely offloading this task to the FPGA. My thought is to tell the cRIO to pretend that this switch is actually an encoder (non-quadrature), thus forcing the FPGA to count the pulses. The programmers say that this will not help, because we would still only be able to retrieve the count every 100 ms, gaining us no advantage. I say it will give us a 2x speed improvement, since we do not have to see both the rising and falling edge of the limit switch, only the falling edge. Also, it will prevent missing multiple pulses; you would miss at most 1 rather than having the pulses line up such that they are all missed. I’m pretty sure I’m right in this case, but some confirmation would be nice to help me convince them that this is a good idea.

b) Back in the good old IFI days where you could read DIO lines faster than 10 hertz, you still had to use interrupts to count encoder pulses. Is there any interrupt feature on the cRIO? The programmers claim there isn’t, and I believe them, it just seems strange that such an elementary function is not implemented on such an advanced processor. Is it simply impossible to access with LabVIEW?

c) A final idea I came up with and have not discussed with them yet: If code really can’t keep up with our needs, we can make a custom circuit to do this. It would consist of a presettable decade counter connected to the limit switch header on a Jaguar. The cRIO would load the desired powerlevel into the decade counter, and each ratchet click would decrement it. When it reached zero, it would simulate a limit switch being pressed, thus stopping the Jaguar and bypassing the cRIO. It seems a ridiculous solution to something that should be done in code, but if the cRIO really can’t handle it, we’ll have to resort to something like this. As a side note, is it legal to interface such a custom circuit to the Jaguar in this way? I think it is, because it does not directly alter the CAN or PWM signal, and isn’t a limit switch already custom circuit?

What I’m looking for is some feedback on what we should do next, maybe some confirmation that we have correctly diagnosed problems and some insight as to the source of these problems (I know it’s difficult without the code, and with me not being a programmer.) Thanks for reading this marathon post, and hopefully we can find a suitable solution that makes everyone happy.

The FPGA also implements single channel counters.

You are correct that you should not try to poll any input quickly, as you’ll be disappointed in the results.

I think Joe’s suggestion is probably the best, but just so you can have a good conversation with the programmers, the interrupts are on the palette in bottom right – Utilities>>Interrupts. You can configure it for Digital or for an Analog level. A second way to accurately get very high speed data is in the DMA capabilities, right next to the interrupts. They can be used to return a buffer of I/O values including digital lines.

Finally, it sounds like you are wanting to read at ~10 ms. That isn’t very fast. In fact, you could stick the poll inside of the teleop and loop and while it doesn’t satisfy Nyquist, it might work well enough for what you need.

If the CPU is loaded, and your timing jitters too much to get the 10ms, make the polling loop be a timed loop and possibly give it a bit of a priority boost.

Joe, I’m curious if you can give details of what you are referring to?

Greg McKaskle


The pulse width would affect your ability to reliably detect all pulses with software polling.

How wide is the pulse width at the highest anticipated pawl speed? Have you measure this on the 'scope?

The pulse width would be affected by both pawl speed AND how deeply each tooth engages the switch (“dwell”, as we used to call it back in the days before electronic ignition).


We will try some of these solutions tomorrow morning. Glad to know that LabVIEW and the cRIO are not the cause of our problems, that we just didn’t know the right blocks to use.

Ether: The pulses are approximately symmetrical, equal time on and off. The point of transition is a little higher than halfway up a tooth, to account for the pawl not falling down all the way for very high ratchet speeds.

I wasn’t looking for timing on the scope, I was just making sure that every pulse was counted and clearly defined, eliminating electrical or mechanical failures as the cause of our problems. Hence, I don’t remember the timing.

I believe that the fastest the pawl will ever go back would be 5 teeth in about 1/2 second, or 20 hertz. It’s not nearing any unreasonable speeds, though it seems that the cRIO can handle very fast speeds using DMA.

Joe: This single channel counter seems useful. Will it be obvious to a programmer where to find it?

Thanks very much for the responses, I learned a lot about programming today :slight_smile:

He is talking about using the counter API in up/down mode.