LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

PID loop rate with counters

I'm trying to use a PXI-8106 RT and LabviewRT 8.5 as a PID controller to control 3 motors.  I'm measuring the speed of the motors by measuring the frequency of the encoder with a 6608.

This article http://zone.ni.com/devzone/cda/tut/p/id/5423 claims a speed up to 107.5 khz.  I've set ethernet to polling and usb off, I didn't turn off  the CPU display, but I'll try that as soon as I can. However, I'm not anywhere close to 107khz, best I can get is about 10khz with one channel and about 2 khz with 3 channels.  I realize the tests were done with analog inputs, but I was hoping that  I'd get at least somewhere close using counters. With the 2Khz rate I really can't do what I need to do.

Does anyone know what a realistic rate would be with this setup?

I'm new at Labview so I may be doing something wrong, although I can't see what it could be. I've done quite a bit of research on the forums before I started to learn from other's examples.

Here's a couple of things I've learned  trying to optimize my loops.

Seems like Daqmx has some issues with applying a scale.  I have 2 scales, one is just a scale factor, 0.166, the other is .0002.  When applying the .0002 factor in Daqmx my performance takes  a huge hit, something like 10%!  If I just leave it at hz, and do the scaling myself I see no performance penalty.

There is something strange about the timed loop % display in RT8.5, I wrote my own routine using expected end, actual end time, and the period to give me a % loop useage and it matches very well to the RT8.5 display for most of the time, however, when the loop starts missing iterations because I've gone over 100% the RT display drops down to about 50% which pretty much makes it useless.

I've attached a couple of shots of my test loop. I can get this one to almost hit 10 khz. the other screen shots are of how I set up the counter, and how I read the counter. the read counter has the error trap to restart itself.  Also I set it to use DMA explicitly somewhere else in the program.

Thanks for any help.
Henri


Download All
0 Kudos
Message 1 of 20
(5,473 Views)
Hi Henri,

You can actually download the code used to determine the benchmark numbers at the following location:
http://zone.ni.com/devzone/cda/epd/p/id/5204

The main difference between your code and the benchmark code is that you use a continuous buffered acquisition while the benchmark uses a hardware-timed single point acquisition.

In your code, you have it set so that you read 10000 samples per DAQmx read (which samples acquired using the internal 80 MHz timebase).  Using this method, the DAQmx Read is going to wait until it has 10000 points available before it returns any values (of which, you only use the first value).  Since the DAQmx read needs to wait for the points to become available, this will greatly reduce your performance.  In addition, setting the timed loop rate to 200 uSec is also another limiting factor.

In contrast, the benchmarking code uses the DAQ card to control the timing of the acquisition.  By setting the rate of acquisition on the card and using hardware-timed single point, values will be read every time they become available.  The "DAQmx Wait for Next Sample Clock" VI is used in the acquisition loop to cause the VI to wait until another point is reading is available.  Following an architecture similar to the one used in the benchmarking example should help greatly improve your performance.

Another thing I noticed in your code is that you are using shared variables in your timed loop.  Since these are a shared resource, this can ruin the determinism in your application.  The "stop - RT" variable is fine since it is a RT FIFO shared variable (you can tell by the purple queue above the globe in the icon of the variable), but the "Control_Loop_Data" variable is just a regular shared variable and could cause problems.

Regards, 
0 Kudos
Message 2 of 20
(5,417 Views)
Devin,
 
Thanks for the suggestions.
 
A couple of related questions for you.
 
The 200 uSec is leftover from my attempts at getting the 3 PID loops to work within the loop availability.  I can run  about 70 uSec i.e about 14khz  with only  a single counter.
 
I've tried changing the buffers value and it has barely any effect on the speed of the loop. Right now I have 3 counters running with 200uSec timing and I get about 69% loop utilization. With a few missed iterations every once in a while. This is using 10000 samples, if I drop down to 100 samples utilization actually goes up to 70%!?  Doesn't make sense to me either, but this is using both my VI and the on screen Timed Structures % of LV8.5RT so I'm trusting it as real,
 
In theory if I can get my loop rate up to 10 khz I'll only need 10 for the buffers since my top frequency to be measured is 100 kHz.
 
Funny thing on the RT fifo variable... I turned on FIFO and it actually decreased performance by about 1%, both Total load and Time structures went up... so I turned it off for stop-RT, and got a 3% improvement! Down to 66% time structures.
 
You mentioned the hardware timing to get a hardware timed single point. Unless I misunderstood the counters, this isn't possible since the sample rate is implicit in the frequency measured? i.e. it latches the count every rising edge.. so I'm my case I'd get a 100 khz sample rate (although obviouslyl that would be the max) Can you let me know if I've missed something there.
 
I bought this system explicitly based on its dual core and its high speed so I could close my PID loops quickly enough with one CPU and still have processing time left over to log data, etc.  And the 6608 card is there so I can get high accuracy for my frequency measurements.   However, I'm really struggling to get this thing going.
 
Any help would be greatly appreciated.
 
Thanks
Henri
 
 
 
 
0 Kudos
Message 3 of 20
(5,407 Views)
Henri,

You're quite right about the timing source required for the counter frequency task.  You will need to use implicit timing, and not rely on a hardware-timed single point acquisition.  I apologize for overlooking that in my original post

I set up a system here with a PXI-8106 RT and PXI-6608, and were seeing numbers similar to what you reported using a single counter input.  I'd like to play around with it some more to see if I can get things working a bit better when I have some free time.

How fast do you actually require your control loop to be?  I know 5-10 KHz is not ideal, but I would think it would be more than enough for a lot of control applications.  Even if processing time wasn't a limiting factor (which it does indeed seem to be), you're still going to be limited by the frequency of the signal that you are measuring.

One thing to make sure of is that you have the DAQ I/O mode to Polling, and not to Interupt.  Also, the benchmark tests were performed on a headless system (not connected to any network targets, just running the application stand-alone), so it might be worth seeing how much network communication is hindering performance.
0 Kudos
Message 4 of 20
(5,363 Views)
Devin,
 
The application is to control a transmission dynamometer at high speed > 8000 RPM, so speed is of the essence. Also, PID is just the beginning, as I was hoping to use more complex control strategies later on.  My measurement frequencies in this case won't be the limitting factor since for  the speed range I'm going to be working in they will be >15Khz  and <100Khz.
 
How do I set the mode to polling? I've got it set to DMA which I assumed would be the fastest, but perhaps not.  Also, I'm chewing up some CPU power just checking for buffer overrun errors, which I explicitly set to ignore, but Daqmx still stops counting when it encounters them.  Daqmx seems to have some peculiar issues, like the scaling I noted above, as well as the fact that the sample buffer size has no effect. Would this be a case where perhaps it might be better to use traditional DAQ? (not that I actually know how to do it!, but maybe I should learn?)
 
Although I see your point on network resources tying up some CPU power, it's a moot point since I need to be able to control the system from my host to set up the test parameters, etc.
 
I appreciate the help since I'm now fully commited down the path of using the RT system for control and am running into some major limitations.
 
Thanks,
Henri
 
0 Kudos
Message 5 of 20
(5,353 Views)
Henri,

You can ignore my comment about the polling mode.  That only refers to the way the "DAQmx Wait For Next Sample Clock" VI  checks to see if another hardware-timed single point is available.  Since you aren't using those with your frequency measurements, you don't need to worry about it.

In regards to the buffer size, you can search the LabVIEW help for the page called "How Is Buffer Size Determined?" for an explanation of how the default buffer size is set and how to override it.  You can locate this article under the help at:
Taking Measurements >> NI-DAQmx Key Concepts >> Reading and Writing Data >> Buffering

In general, we advise against using Traditional DAQ in favor of DAQmx.  I believe that performance is more optimized in DAQmx, but feel free to create your own benchmarks for comparison.

I'm sorry that performance is not living up to your hopes.  I ran some more tests here today and wasn't able to make any real improvements.  Hopefully you're able to deal with any limitations and compensate appropriately.

Regards,
0 Kudos
Message 6 of 20
(5,311 Views)
Two things.  First, I made a reply to this question over on another board.  Link is here.   Check it out and then come back.  I'll continue here b/c it's the more active thread.
 
Second, I want to highlight your comment:
Also, I'm chewing up some CPU power just checking for buffer overrun errors, which I explicitly set to ignore, but Daqmx still stops counting when it encounters them.
This would be a good reason not to call DAQmx Read with a -1 to request 'all available samples'.  *Especially* since you're ignoring most of them anyway.  My suggestion at the link would help you avoid the buffer overrun errors.  I use the method quite a bit in apps where the data acq buffers overwrite many times before I make my first Read call.  No errors because I explicitly ask for recent data. 
 
One caveat: since your encoders are the implicit sampling clock, there won't be any data in the buffer before they start moving.  If you attempt to read most recent samples before any samples have been buffered, you'll get an error.  That may be a complication for your app, or you can trap that particular error code, ignore it, and return a 0 freq from your Read vi. 
 
One more caveat I just thought of:  After an encoder has has moved and then comes to rest, the requests to read most recent data will keep returning the same values and won't detect the 0 speed.  Another complication.  Drat!
 
-Kevin P.
 
CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 7 of 20
(5,143 Views)
Kevin,
 
Thanks for the suggestions.
 
Yes the true case just passes the read data.
Loop % used just tells me how much processor time I've chewed up, and pretty much just matches the display with RT 8.5. Doesn't slow down the code much.
 
I'll try explicitly starting the task, I seem to recall somewhere that you actually can't do that with a frequency counter, but will give it a shot.
 
Since my first post I've actually cleaned up my restart task code and is now just a stop and read without all the other stuff. Unfortunately, it doesn't help much.
 
The screenshot does show 5khz, I've play around with the values until I see 100% utilization. Basically I can get it up to somewhere around 13khz with a single counter.
 
The read tasks are parallel I'll try sequential and see if that helps any.
 
Strangely enough, the shared variables are actually slower with RTFifo on!
 
The reason I only read the first  value is because I'm trying to go as fast as possible, and although the last one would be the one I'd want, I figured if I couldn't get a simple loop to go fast, then changing more stuff would slow it down.  However, I'm going to experiment a little bit with maybe just reading the last sample instead of all samples instead.
 
Thanks
Henrri
 
0 Kudos
Message 8 of 20
(5,129 Views)
Henri,
 
A couple of things you may want to try:
 
1)  Explicitly commit or start your task before you enter the loop.  If you do this, when it starts, most of the configuration setup time will be taken out of the loop because the settings will have already been committed to the hardware and it will be ready to go.  Also, if the task stops and needs to be restarted, it will then only roll back to the last explicit state transition.   Therefore, explicit commit + stop = task at committed state or explicit start + stop = task at not started state.
 
2)  Don't configure timing.  If you don't care about the entire buffer of data (which it seems as you are just grabbing the oldest sample) it's actually quicker to do "on demand" timing.  This will read from the device programmatically and you also won't have to worry about any explicit buffer setting magic. 
 
3)  Run your counters in separate parallel tasks ("railroad tracks").  Since you have a dual core system the OS and DAQmx will utilize both CPU's to read and process your data, balancing between the two.
 
Let me know if any of these help.
0 Kudos
Message 9 of 20
(4,977 Views)
balki,
 
A couple of questions.
 
I've tried starting the task, but it seems that frequency counter functions don't use the start task function.
 
If I don't have a buffer how would it keep the count before I read it out? I'm doing a frequency count so that the quadrature encoder pulse is actually what latches the 80 mhz clock count into the buffer.
 
Thanks
 
-Henri
 
0 Kudos
Message 10 of 20
(4,888 Views)