Discussion:
AI-AO feedback loop for 6259 using ANSI C
(too old to reply)
leh
2008-06-17 20:40:07 UTC
Permalink
I own a NI-6259 board.  I have used it with a WindowsXP and it worked fine.
Now, I have changed to a RedHat 4.6  Linux system.
My needs are simple:  I don't want to use LabView, all I want
to do is to simple ANSI C functions. I downloaded   nidaqmxbase-3.1.0.iso  and installed it.
It works.

What I want to do is to run a feedback loop where I read four AI channels in,
make some calculations on the data and then write three AO channels out to my drivers.
The loop should run at 5 to 10 kHz. 
I have been able to read the AI channels and write the AO channels separately but when I try to run them
simultaneously, it bombs.
The main part of the program looks like this:1    DAQmxErrChk (DAQmxBaseCreateTask("",&AOtaskHandle));2    DAQmxErrChk (DAQmxBaseCreateAOVoltageChan(AOtaskHandle,AOchan,"",AOmin,AOmax,DAQmx_Val_Volts,NULL));3   DAQmxErrChk    (DAQmxBaseCfgSampClkTiming(AOtaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,samplesPerChan));
4    DAQmxErrChk (DAQmxBaseCreateTask("",&AItaskHandle));5    DAQmxErrChk (DAQmxBaseCreateAIVoltageChan(AItaskHandle,AIchan,"",DAQmx_Val_Cfg_Default,AImin,AImax,DAQmx_Val_Volts,NULL));6    DAQmxErrChk (DAQmxBaseCfgSampClkTiming(AItaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,samplesPerChan));
7    DAQmxErrChk (DAQmxBaseStartTask(AItaskHandle));8   DAQmxErrChk (DAQmxBaseStartTask(AOtaskHandle));9    for(k=0;k<6;k++) {
10    DAQmxErrChk (DAQmxBaseReadAnalogF64 (AItaskHandle,samplesPerChan, timeout, 2, datain, bufferSize, &pointsRead, NULL));11    DAQmxErrChk (DAQmxBaseWriteAnalogF64(AOtaskHandle,samplesPerChan,0,timeout,2,dataout,&pointsWritten,NULL));

I get the following error message just after the first WriteAnalogF64 statement:  
"DAQmxBase Error: The generation has stopped to prevent the regeneration of old samples.   Your application was unable to write samples to the background buffer fast enough to    prevent old samples from being regenerated.   LavView caught fatal signal   
8.2.1 - Received SIGSEGV    Reason: address not mapped to object   Attempt to reference address: 0xb4496500  
Segmentation fault "
It looks like I got some serious timing problems.  I need some advice
I'll attach the whole program for your information.
 
Lee Holloway


AI-AO.C:
http://forums.ni.com/attachments/ni/250/40890/1/AI-AO.C
Brooks_C
2008-06-18 19:10:09 UTC
Permalink
Hello Lee,

 

As this error message indicates the analog output buffer is not being updated with new samples quickly enough to prevent regenerating samples.  In general this means that you either need to run your loop faster or write more samples to the buffer at a time.  In order to run your loop faster you would need to make your analysis more efficient or implement threading to make some of your code run in parallel (this may cause significant gains if you have a dual core computer).  Inevitably you will reach a speed that is the maximum your computer can handle.  On most non-real-time operating systems for basic PID control loops this rate is somewhere on the order of 1 kHz (this varies significantly based on your particular computer).

 

Are you looking to run your loop at a rate of 5-10 kHz meaning that you need to have a control loop response time at this speed or are you just wanting to update and read values at this rate?  The point I'm trying to make is that you can make your code more efficient by reading/writing multiple points.  If you read in 10 points at a time at a rate of 10,000 rather than 1 point at a time your loop will run 10 times slower and put much less strain on your CPU.  The downside here is that your control loop time also slows down (by control loop time I mean the delay between reading in a value, performing calculations, and outputting values) since you update the output only once per loop iteration.

 

The bottom line is that you're computer may not be able to handle running the analysis you require at the rate you want.  However, if you can still meet your needs by running the loop slower and dealing with larger data chunks then there is a good chance you can get this to work.

 

 

If your application requires that your output response time be 0.1-0.2 msec then you may need to consider moving to a real-time operating system.  However, if a response on the order of 5 msec is acceptable then you can probably get this to work by making your code more efficient and reducing the loop rate by working with more data each loop iteration.

 

I hope this helps, and have a good night!
leh
2008-06-18 20:10:34 UTC
Permalink
Hello Brooks,  Thanks for the reply.   It must be something more than that, perhaps synchronization or... something.Two reasons:   
leh
2008-06-18 20:10:34 UTC
Permalink
Hello Brooks,  Thanks for the reply.   There must be something more than that, perhaps synchronization or... whatever.Two reasons:    1. The loop won't run at even  a 1 Hz rate.  2. When I had the same type of program running on a WindowsXP system (the very same computer)       it  ran cheerfully at 10 kHz  (I even tried it successfully at 20 kHz).I Tried to sort of copy the old Windows version onto the Linux system but  the old Windows usedan older version of NIDAQ and some of the functions have changed names, or whatever.I'll try to find my old version and send it to you in a later post.Lee
leh
2008-06-19 03:40:06 UTC
Permalink
Hi Brooks. Below are the relevant function calls for the new, non working, and the old Windows version that worked well.There are differences that involve synchronization,  see line 23 which doesn't exist in DACmxBase.  I hope you can find my error.Lee    This is the new Linux version.  It bombs out at line 12 (even the first time through)1    DAQmxBaseCreateTask("",&AOtaskHandle);\par2    DAQmxBaseCreateAOVoltageChan(AOtaskHandle,AOchan,"",AOmin,AOmax,DAQmx_Val_Volts,NULL);\par3    DAQmxBaseCfgSampClkTiming(AOtaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,samplesPerChan);\par4    DAQmxBaseCreateTask("",&AItaskHandle);\par5    DAQmxBaseCreateAIVoltageChan(AItaskHandle,AIchan,"",DAQmx_Val_Cfg_Default,AImin,AImax,DAQmx_Val_Volts,NULL);\par6    DAQmxBaseCfgSampClkTiming(AItaskHandle,"",sampleRate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,samplesPerChan);\par7    DAQmxBaseStartTask(AItaskHandle);\par8    DAQmxBaseStartTask(AOtaskHandle);\par9    for(k=0;k<nloop;k++)10          {11     DAQmxBaseReadAnalogF64 (AItaskHandle,samplesPerChan, timeout, 2, datain, bufferSize, &pointsRead, NULL);\par12     DAQmxBaseWriteAnalogF64(AOtaskHandle,samplesPerChan,0,timeout,2,dataout,&pointsWritten,NULL);\par13         // Make calculations ...14          }        This is the old Windows version using NI-DAC        The function at line 23 usint DAQmx_Val_HWTimedSinglePoint doesn't exist in DAQmxBase21  DAQmxCreateTask("",&AItaskHandle);\par22  DAQmxErrChk(DAQmxCreateAIVoltageChan(*AItaskHandle,AIchan,"",DAQmx_Val_Cfg_Default,AImin,AImax,\par23  DAQmxCfgSampClkTiming(*AItaskHandle,"",rate,DAQmx_Val_Rising,DAQmx_Val_HWTimedSinglePoint ,2);\par24  DAQmxCreateTask("", AOtaskHandle);\par25  DAQmxCreateAOVoltageChan(*AOtaskHandle,AOchan,"",AOmin,AOmax,DAQmx_Val_Volts,NULL);\par26  DAQmxCfgSampClkTiming(*AOtaskHandle,"",rate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,2);\par27  DAQmxCreateTask("",&AOtaskHandle);\par28  DAQmxCfgDigEdgeStartTrig (*AOtaskHandle,"ai/StartTrigger",DAQmx_Val_Rising);\par29  if( numAIchannels ) DAQmxGetTaskAttribute(*AItaskHandle,DAQmx_Task_NumChans,numAIchannels);\par30  if( numAOchannels ) DAQmxErrChk2DAQmxGetTaskAttribute*AOtaskHandle,DAQmx_Task_NumChans,numAOchannels); \par31  DAQmxStartTask(AOtaskHandle);\par32  DAQmxStartTask(AItaskHandle);\par33  for(k=0;k<nloop;k++) \par34        {35   DAQmxWriteAnalogF64(AOtaskHandle,samplesPerChan,0,timeout,2,dataout,&pointsWritten,NULL);\par36   DAQmxReadAnalogF64(AItaskHandle,sampsPerChan,timeout,2,datain,bufferSize,&pointRead,NULL);\par37        \\ Make calculations ...38         }          
Brooks_C
2008-06-19 22:10:07 UTC
Permalink
Hello Lee,
 
Are you able to run the DAQmx Base code on your Windows machine?&nbsp; If so, does this machine have a better processor?&nbsp; If you don't already have DAQmx Base installed on your Windows machine you can download it <a href="http://joule.ni.com/nidu/cds/view/p/id/971/lang/en" target="_blank">here</a>.
&nbsp;
This would be the easiest test of the CPU theory.&nbsp; At a first glance your code looks like it should work okay as long as the program can loop fast enough so by running the DAQmx Base code on the same computer we can either eliminate or confirm this issue.
&nbsp;
Cheers,
leh
2008-06-20 04:10:06 UTC
Permalink
Hello Brooks, It's the same physical computer.&nbsp;&nbsp; I wiped out the Windows OS and installed Linux.&nbsp;&nbsp; There must be something wrong with the CfgDigEdgeStartTrig&nbsp; orCfgSampClkTiming&nbsp;&nbsp;&nbsp; orCfgDigEdgeStartTrig&nbsp; oror something else.All I know is that the old Windows program worked and the Linnux one doesn't.I can't copy the old program line by line because some of the function callsdon't exist in the DAQmxBase library.&nbsp; There are probably equivalent ones butI don't know what they are named.Lee
Brooks_C
2008-06-23 16:10:11 UTC
Permalink
Hello Lee,Here are a few things to try.There are DAQmxBase examples that are installed to this directory by default:&nbsp; /usr/local/natinst/nidaqmx/examplesI would suggest looking at the analog output (ao) example folder and running the continuous generation example.&nbsp; This example will call the same DAQmxBaseWriteAnalogF64 function you're using so we can test to make sure your driver install is working correctly.Secondly, it is possible that this error is being thrown because you aren't writing points to the analog output buffer before you start the task.&nbsp; If you start the task without putting samples in the buffer then I would expect an error to be thrown indicating that the task didn't have anything to write.&nbsp; To fix this you can call a DAQmxBaseWriteAnalogF64 function to put samples in the buffer before the task is started.The last thing I would do in your program is to add in the DAQmxBaseCfgDigEdgeStartTrig function call to synchronize your two tasks like you've done in you DAQmx code.Let me know what you find.Cheers,
Loading...