ni / nidaqmx-python

A Python API for interacting with NI-DAQmx
Other
428 stars 154 forks source link

Reading position from a quadrature encoder #619

Open sarrfar opened 1 month ago

sarrfar commented 1 month ago

I am using an NI cDAQ-9184 with the NI 9411 module to read a quadrature encoder, but I can't seem to figure out how to get position readings from it. I have a voltage pulse signal wired into the 9411 to act as my external sample clock, and the sample timestamps seem to be right, but I seem to be getting edge counts or something rather than actual angular position measurements. I'm assuming I need to use some other piece of the library to convert to position, but I can't seem to figure that part out. I would welcome any help!

    task_a = nidaqmx.Task()
    sample_rate = 2000  # Hz
    n_tot = sample_rate*seconds_to_record
    data_matrix = np.zeros((n_tot,))

    task_a.ci_channels.add_ci_ang_encoder_chan(
        counter="cDAQ9184-1C3169FMod3/ctr0",
        name_to_assign_to_channel="encoder 1",
        decoding_type=nidaqmx.constants.EncoderType.X_1,
        zidx_enable=True,
        units=nidaqmx.constants.AngleUnits.DEGREES,
        pulses_per_rev=4096
    )

    task_a.timing.cfg_samp_clk_timing(
        rate=sample_rate,
        source="/cDAQ9184-1C3169FMod3/PFI3",  
        sample_mode=AcquisitionType.CONTINUOUS,
        samps_per_chan=sample_rate*seconds_to_record
    )

    print("beginning data collection. time of collection is approx ", seconds_to_record, " seconds.")

    task_a.start()
    stream = stream_readers.CounterReader(task_a.in_stream)

    stream.read_many_sample_double(
        data=data_matrix,
        number_of_samples_per_channel=n_tot
    )

    task_a.stop()
    task_a.close()
zhindes commented 1 month ago

A few questions:

For details on how encoders work see NI Hardware Encoder Measurements: How-To Guide.

My best guess at what might be happening is that your encoder connections to the 9411 don't match the DAQmx defaults. See CIChannel.ci_encoder_a_input_term, CIChannel.ci_encoder_b_input_term, and CIChannel.ci_encoder_z_input_term

sarrfar commented 1 month ago

The data I am reading looks like a series of extremely quick fluctuations when I turn the encoder about 45 degrees, which is what led me to assume I'm reading pulses instead of position. Every peak maxes around +/-0.09, the sign seemingly dependent on which direction it's rotating image zoomed in image: image

The encoder is hooked up using the AMT-18C-3-072 cord from the encoder manufacturer (ending in pigtails) wired into a DB15 connector, which plugs in directly to the 9411. I did follow the diagram from NI on which wires to connect where, but maybe the defaults are different in the nidaqmx package? image

The encoder is the AMT132Q-V from CUI devices, datasheet here: CUI AMT Series Encoders

zhindes commented 1 month ago

From what I can tell the defaults should match that diagram, but it doesn't hurt to set them to be certain. you can modify your code this way:

    encoder_chan = task_a.ci_channels.add_ci_ang_encoder_chan(
        counter="cDAQ9184-1C3169FMod3/ctr0",
        name_to_assign_to_channel="encoder 1",
        decoding_type=nidaqmx.constants.EncoderType.X_1,
        zidx_enable=True,
        units=nidaqmx.constants.AngleUnits.DEGREES,
        pulses_per_rev=4096
    )
    encoder_chan.ci_encoder_a_input_term = "cDAQ9184-1C3169FMod3/PFI0"
    encoder_chan.ci_encoder_b_input_term = "cDAQ9184-1C3169FMod3/PFI1"
    encoder_chan.ci_encoder_z_input_term = "cDAQ9184-1C3169FMod3/PFI2"

That data is very interesting. You're only ever getting two values: 0 and -0.087 degrees. That second value is a single tick of the encoder, 360/4096. So you're resetting back to 0 very quickly. I wonder if the Z Index signal is not configured correctly, noisy, or bad? I can't tell from the data sheet how that Z index is supposed to behave. You could try these settings: