Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Reading two encoders synchronously

I am attempting to use a USB-6215 to read two angular encoders from within a Visual C++ application (using the DAQmx C libraries, not LabView).  I have thus far been able to do the following:
    a)  Read both encoders correctly if I sequentially querry each task for individual samples (at ~ 500 Hz)
    b)  Read one encoder in buffered mode, with the individual samples triggered off of the 100 kHz hardware clock
          [ DAQmxCfgSampClkTiming(taskHandle1,"100kHzTimebase",1E5,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000) ]

What I would desperately like to do is set up two buffered encoder reading tasks with the actual encoder reads for each task triggered off of the same hardware clock (preferrably 1-10 kHz).  However, I can't seem to figure out how to setup/start the correct clock and route it to both encoder tasks. 

A snippet of my (non-functional) code (derived from the VC_AngularPosition_Buff_Cont example) and the resulting output is below.

Thanks in advance for any help that's out there...
Neal

--- Begin Code Fragment ----

    /*********************************************/
    // DAQmx Configure Code
    /*********************************************/
    DAQmxErrChk (DAQmxCreateTask("Task0",&taskHandle0));
    DAQmxErrChk (DAQmxCreateCIAngEncoderChan(taskHandle0,"Dev3/ctr0","",DAQmx_Val_X4,0,0.0,DAQmx_Val_AHighBHigh,DAQmx_Val_Ticks,250,0.0,""));
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle0,"100kHzTimebase",1E5,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));
    DAQmxErrChk (DAQmxCreateTask("Task1",&taskHandle1));
    DAQmxErrChk (DAQmxCreateCIAngEncoderChan(taskHandle1,"Dev3/ctr1","",DAQmx_Val_X4,0,0.0,DAQmx_Val_AHighBHigh,DAQmx_Val_Ticks,250,0.0,""));
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle1,"100kHzTimebase",1E5,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));

    /*********************************************/
    // DAQmx Start Code
    /*********************************************/
    DAQmxErrChk (DAQmxStartTask(taskHandle0));
    DAQmxErrChk (DAQmxStartTask(taskHandle1));

----- End Code Fragment ------

----- Begin Output -----
DAQmx Error: Specified route cannot be satisfied, because it requires resources that are currently in use by another route.
Property: DAQmx_SampClk_Src
Property: DAQmx_SampClk_ActiveEdge
Source Device: Dev3
Source Terminal: 100kHzTimebase

Required Resources in Use by
Task Name: Task0
Source Device: Dev3
Source Terminal: 80MHzTimebase
Desitnation Device: Dev3
Destination Terminal: Ctr0Source

Task Name: Task1

Status Code: -89137
----- End Output ------


0 Kudos
Message 1 of 10
(6,737 Views)
Hello Neal,

First of all, welcome to the NI discussion forums.  I was able to replicate your issue in LabVIEW (which I am more fluent in), and was able to figure out a method to accomplish what (I believe) you want to do. 

The trick with this application is that usually, with one counter in buffered mode, we use the second counter to create the sample clock.  This becomes an issue when we need that second counter for our second encoder.  In order to get this sample clock to time the buffered counting, usually the solution is to use an external clock.  However, you can get around this by starting an analog input task and then using its sample clock to read from the counters.

The logic flow is the same for both languages, so I will list the steps (in order) of how I programmed it:

-----------------

Create Analog Input Task
Create Analog Input Channel
Configure Timing (specify rate you want)

Create Counter Input Task1
Create Analog Input Channel1
Configure Timing1 (source is Dev#/ai/SampleClock)

Create Counter Input Task2
Create Analog Input Channel2
Configure Timing2 (source is Dev#/ai/SampleClock)

Start Counter Input Task1
Start Counter Input Task2

Start Analog Input Task              //I Do this here so that the 2 counters start filling the buffer starting at the same time

------------------------

The only catch with doing this is that you can only have 1 analog input task going at any given time, so if you are trying to do AI at the same time, this will not work.  Give this a try and let me know if this works for you.
Neal M.
Applications Engineering       National Instruments        www.ni.com/support
0 Kudos
Message 2 of 10
(6,716 Views)
Fantastic!  Not only did that solution work perfectly, but a very clear explanation as well.

From one Neal to another,  a great big Thank You!
Neal


0 Kudos
Message 3 of 10
(6,712 Views)

Neal T --

Can you send your C code to implement this?  When I try to do the same I get the following error when starting the encoder task:

Source terminal to be routed could not be found on the device.

Make sure the terminal name is valid for the specified device. Refer to Measurement & Automation Explorer for valid terminal names.

Should I assume in the logic flow laid out in the previous messages when he said "Create Analog Input Channel1" and "Create Analog Input Channel2" he really meant "Create Counter Input Channel1" and "Create Counter Input Channel2"?

Thanks,

AJ

 

0 Kudos
Message 4 of 10
(6,344 Views)
Hi AJJ,

Yes, you are correct that I meant "Create Counter Input Channel1" and "Create Counter Input Channel2".

The error that you are seeing says that your input string for the source of something (either your signal or the sample clock most likely) is not correct.  I suspect that you took my string literally ("
Dev#/ai/SampleClock").  What I meant by this was that you need to use the cards DAQmx name (which by default is Dev<something>, e.g. Dev1) to specify which device you are routing to.  In Neal T's example, he would use "Dev3/ai/SampleClock", but your device may be different.  This can be found in Measurement and Automation Explorer under My System»Devices and Interfaces»NI-DAQmx Devices.
Neal M.
Applications Engineering       National Instruments        www.ni.com/support
Message 5 of 10
(6,316 Views)
AJ,

I think that this is the right (working) version of my code that I used to test the two simultaneous encoders (the C version of what Neal M posted).  I started with the AngularPosition-Buff-Cont.c standard example code and modified the configuration portion as below.  Hopefully this will help some.

Good luck,
Neal T


////////////////////////// -- BEGIN CODE SECTION -- ////////////////////////////////////
    /*********************************************/
    // DAQmx Configure Code
    /*********************************************/
    // create a dummy analog input task, just to get it to start up a timer that we can then
    // hijack to trigger the encoder reads
    DAQmxErrChk (DAQmxCreateTask("Analog In", &taskHandleAI));
    DAQmxErrChk (DAQmxCreateAICurrentChan(taskHandleAI,"Dev3/ai0","",DAQmx_Val_Diff,-1,1,DAQmx_Val_Amps,DAQmx_Val_External,1,""));
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandleAI,"",10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,3000));
   
    // create the task for reading encoder 0
    DAQmxErrChk (DAQmxCreateTask("Task0",&taskHandle0));
    DAQmxErrChk (DAQmxCreateCIAngEncoderChan(taskHandle0,"Dev3/ctr0","",DAQmx_Val_X4,0,0.0,DAQmx_Val_AHighBHigh,DAQmx_Val_Ticks,250,0.0,""));
    // hijack the analog input timer
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle0,"ai/SampleClock",10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));
   
    // create the task for reading encoder 1
    DAQmxErrChk (DAQmxCreateTask("Task1",&taskHandle1));
    DAQmxErrChk (DAQmxCreateCIAngEncoderChan(taskHandle1,"Dev3/ctr1","",DAQmx_Val_X4,0,0.0,DAQmx_Val_AHighBHigh,DAQmx_Val_Ticks,250,0.0,""));
    // hijack the analog input timer
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle1,"ai/SampleClock",10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));


    /*********************************************/
    // DAQmx Start Code
    /*********************************************/
    printf("Starting Channel 0 \n");
    DAQmxErrChk (DAQmxStartTask(taskHandle0));
    printf("Starting Channel 1 \n");
    DAQmxErrChk (DAQmxStartTask(taskHandle1));

/////////////////////////////////// -- END CODE SECTION -- /////////////////////////////////



0 Kudos
Message 6 of 10
(6,310 Views)
Oops!  I cut the code snippet off a little too short in the previous post and missed the line that actually starts the analog input task.  I'll try again....
Neal T


/////////////////////////////// -- BEGIN CODE SEGMENT -- ////////////////////////////////////

   /*********************************************/
    // DAQmx Configure Code
    /*********************************************/
    // create a dummy analog input task, just to get it to start up a timer that we can then
    // hijack to trigger the encoder reads
    DAQmxErrChk (DAQmxCreateTask("Analog In", &taskHandleAI));
    DAQmxErrChk (DAQmxCreateAICurrentChan(taskHandleAI,"Dev3/ai0","",DAQmx_Val_Diff,-1,1,DAQmx_Val_Amps,DAQmx_Val_External,1,""));
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandleAI,"",10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,3000));
    
    // create the task for reading encoder 0
    DAQmxErrChk (DAQmxCreateTask("Task0",&taskHandle0));
    DAQmxErrChk (DAQmxCreateCIAngEncoderChan(taskHandle0,"Dev3/ctr0","",DAQmx_Val_X4,0,0.0,DAQmx_Val_AHighBHigh,DAQmx_Val_Ticks,250,0.0,""));
    // hijack the analog input timer
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle0,"ai/SampleClock",10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));
    
    // create the task for reading encoder 1
    DAQmxErrChk (DAQmxCreateTask("Task1",&taskHandle1));
    DAQmxErrChk (DAQmxCreateCIAngEncoderChan(taskHandle1,"Dev3/ctr1","",DAQmx_Val_X4,0,0.0,DAQmx_Val_AHighBHigh,DAQmx_Val_Ticks,250,0.0,""));
    // hijack the analog input timer
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle1,"ai/SampleClock",10000,DAQmx_Val_Rising,DAQmx_Val_ContSamps,1000));


    /*********************************************/
    // DAQmx Start Code
    /*********************************************/
    printf("Starting Channel 0 \n");
    DAQmxErrChk (DAQmxStartTask(taskHandle0));
    printf("Starting Channel 1 \n");
    DAQmxErrChk (DAQmxStartTask(taskHandle1));

    // start the analog input task last, so that both encoder tasks start filling their buffers at the same time.
    DAQmxErrChk (DAQmxStartTask(taskHandleAI));

    printf("Continuously reading. Press Ctrl+C to interrupt\n");
    while( 1 ) {
        /*********************************************/
        // DAQmx Read Code
        /*********************************************/
        DAQmxErrChk (DAQmxReadCounterU32(taskHandle0,1000,10.0,data,1000,&read0,0));
        enc0 = data[0];
        DAQmxErrChk (DAQmxReadCounterU32(taskHandle1,1000,10.0,data,1000,&read1,0));
        enc1 = data[0];

        // should probably set this up to hit a callback every N samples instead of
        // blocking execution while the read command waits for the buffer to fill up.
        // see documentation on "DAQmxRegisterEveryNSamplesEvent" to setup callback

        printf("Enc0: %d, Enc1: %d, Diff: %d, Samp: %d \n", enc0, enc1, enc0-enc1, read0);
        fflush(stdout);
    }


//////////////////////////////////////// -- END CODE SEGMENT -- //////////////////////////////////////////////

Message 7 of 10
(6,308 Views)
Thanks to both of you for the quick response -- I have it working now.
The problem was in the string used for the source: evidently it can't have the "DevX/" prefix and should only be "ai/SampleClock".
 
Thanks again,
AJ
 
0 Kudos
Message 8 of 10
(6,302 Views)

Hello to all,

 

I just found this useful discussion here.  I have the same problem but I have to use system timer.  Does any of you have an experience working with system timer as a sample clock for encoders?

 

Thanks,

 

FST 

0 Kudos
Message 9 of 10
(5,223 Views)

There is no way that I am aware of to export the system time to the DAQ card within the confines of the DAQmx driver.  If you had a method of externally exporting the system time, that could be fed into the DAQ board and used as an external clock.

 

Excepting that you could use a software timed counter input, which will use the system time to time a loop in code, every iteration of the loop would poll the card and see what the current count is.

Doug Farrell
Solutions Marketing - Automotive
National Instruments

National Instruments Automotive Solutions
0 Kudos
Message 10 of 10
(5,185 Views)