Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Using DAQmx python to read encoder position

Solved!
Go to solution

Hello,

 

I am trying to read the position of a quadrature encoder using the DAQmx python library. Here are my setup details:

 

cDAQ-9174

NI-9401 module

SICK DGS80B-TSHC08192 encoder:

https://cdn.sick.com/media/pdf/5/95/295/dataSheet_DGS80B-TSHC08192_1118689_en.pdf 

 

Python 3.12.4 running on PyCharm in a miniconda3 environment with NI DAQmx API, windows 10

 

I seem to be reading the counter and seeing a change as I rotate the encoder, but the readings don't make sense. I'll rotate the encoder approx. 80 degrees and my code output will show something between 2.1 and 2.6. I have been able to correctly read encoder position in NI DAQexpress where the displayed plot matches up with actual encoder position so I'm confident the hardware setup is working correctly. Here is the code I am using:

from nidaqmx.constants import AcquisitionType, EncoderType, AngleUnits, READ_ALL_AVAILABLE, Edge

def read_encoder_data(counter_name, encoder_type, position_units, encoder_resolution, start_angle):
    # Create a task
    with nidaq.Task() as task:
        # Add an encoder counter task
        sensor_position = task.ci_channels.add_ci_ang_encoder_chan(counter=counter_name, #passed in through main
                                                                   decoding_type=encoder_type, #passed in through main
                                                                   zidx_enable=False, #Explicitly set to false just to be sure
                                                                   units=position_units, #passed in through main
                                                                   pulses_per_rev=encoder_resolution, #passed in through main
                                                                   initial_angle=start_angle) #passed in through main

        # Configure clock timing. This does seem to change the behavior but still not the correct behavior
        #task.timing.cfg_samp_clk_timing(1000.0,'/cDAQ1Mod1/PFI1',active_edge=Edge.RISING, sample_mode=AcquisitionType.CONTINUOUS, samps_per_chan=1000)

        #Define which lines to read encoder channels A and B from.
        # These lines do not seem to affect behavior. ie. we get the same values even if these are commented out
        sensor_position.ci_encoder_a_input_term = 'PFI1'
        sensor_position.ci_encoder_b_input_term = 'PFI3'

        # Configuration for Z channel.
            # We are not using the Z channel in DAQexpress as it was causing a constant reset error so
            # we've opted to not use it here either. We may need it though, not sure.
        # sensor_position.ci_encoder_z_input_term_cfg
        # sensor_position.ci_encoder_z_input_term = 'PFI5'

        # Start task
        task.start()

        # Read data
        data = task.read() #Using the task.read function as we couldn't find a counter specific read function
                           #The C# example I found uses a "DAQmxReadCounterF64" function. From what I've read
                           #this is wrapped up in the task.read function in python

        return data

def main():

    # Define encoder variables
    counter_name = 'cDAQ1Mod1/ctr0' #Our D I/O module is in slot 1 of our cDAQ-9174
    encoder_type = EncoderType.X_2  #We are currently using X2 decoding. Better resolution than X1 but less sensitive to vibrations than X4
    position_units = AngleUnits.DEGREES #We want the result in degrees
    encoder_resolution = 8192 #Our encoder (SICK DGS80B-TSHC08192) has 8192 pulses per revolution
    start_angle = 0.0 #Define the starting angle to be 0.0 degrees
    current_angle = start_angle #Set current angle to start angle before current angle calculations happen in while loop

    try:
        while True: #While loop that is always running once main is called
            # Run the read encoder data function
            position_data = read_encoder_data(counter_name, encoder_type, position_units, encoder_resolution, start_angle) #pass argument values to the read_encoder_data function
            current_angle = current_angle + position_data #The output of the task.read function seemed to be giving the change in angle. This line adds the change to the current angle.
            
            print(current_angle)

    # Error handling
    except nidaqmx.DaqError as e:
        print('An error occurred: ', e)
    except KeyboardInterrupt:
        print("\nStopped by user")
    finally:
        print('Task complete')

 Here is a photo of the DAQexpress setup that is giving expected results:

Capture.PNG

Any help would be greatly appreciated!

0 Kudos
Message 1 of 3
(928 Views)
Solution
Accepted by topic author hfrende

You are looping the entire DAQmx task, which resets the task every iteration.

You should only call add_channel and task.start once, then put the task.read in a loop.

-------------------------------------------------------
Applications Engineer | TME Systems
0 Kudos
Message 2 of 3
(896 Views)

This was the problem! Thank you for catching that. Here is the updated code for anyone who may have this problem in the future:

 

from nidaqmx.constants import AcquisitionType, EncoderType, AngleUnits, READ_ALL_AVAILABLE, Edge

def encoder():

    # Define encoder variables
    counter_name = 'cDAQ1Mod1/ctr0' #Our D I/O module is in slot 1 of our cDAQ-9174
    encoder_type = EncoderType.X_2  #We are currently using X2 decoding. Better resolution than X1 but less sensitive to vibrations than X4
    position_units = AngleUnits.DEGREES #We want the result in degrees
    encoder_resolution = 8192 #Our encoder (SICK DGS80B-TSHC08192) has 8192 pulses per revolution
    start_angle = 0.0 #Define the starting angle to be 0.0 degrees
    current_angle = start_angle #Set current angle to start angle before current angle calculations happen in while loop

    with nidaq.Task() as task:
        task.ci_channels.add_ci_ang_encoder_chan(counter=counter_name, #passed in through main
                                                                   decoding_type=encoder_type, #passed in through main
                                                                   zidx_enable=False, #Explicitly set to false just to be sure
                                                                   units=position_units, #passed in through main
                                                                   pulses_per_rev=encoder_resolution, #passed in through main
                                                                   initial_angle=start_angle) #passed in through main

        task.start()
        try:
            while True: # While loop that is always running once main is called
                data = task.read() # Read the task data
                print(data)

        # Error handling
        except nidaqmx.DaqError as e:
            print('An error occurred: ', e)
        except KeyboardInterrupt:
            print("\nStopped by user")
        finally:
            print('Task complete')

if __name__ == "__main__": # Run the main function
    encoder()
Message 3 of 3
(879 Views)