06-05-2022 11:14 AM
cRIO 9053
9411 module
Wheel encoder GKZ-1000
https://cdn.automationdirect.com/static/specs/encoderhd.pdf
Python 3.9.5 with nidaqmx API
I can read the counter and see it increasing as I rotate the wheel, but I need to detect changes in both directions, so my preference would be that the counter decrease in one direction, increase in the other.
Here's a snippet of what I am doing (With some leftovers from previous attempts).
def startUsingRotation(self):
global running
total = 0.0
task = ni.Task(new_task_name="readCtr0")
# Can't seem to make this work, and perhaps this is not what we need, as direction matters
#channelA = task.ci_channels.add_ci_ang_encoder_chan(counter = 'Mod3/ctr0', decoding_type = EncoderType.X_1, zidx_enable=True, units=AngleUnits.DEGREES, pulses_per_rev=4000, initial_angle=0.0)
#channelA = task.ci_channels.add_ci_ang_encoder_chan(counter = 'Mod3/ctr0', decoding_type = EncoderType.X_1, zidx_phase=nidaqmx.constants.EncoderZIndexPhase.AHIGH_BHIGH, zidx_val=0, zidx_enable=True, units=AngleUnits.DEGREES, pulses_per_rev=1000, initial_angle=0.0)
#task.timing.cfg_samp_clk_timing(rate=10000, sample_mode=AcquisitionType.CONTINUOUS,samps_per_chan=100)
#task.timing.samp_timing_type = nidaqmx.constants.SampleTimingType.ON_DEMAND
channelA = task.ci_channels.add_ci_count_edges_chan(counter='Mod3/ctr0')
channelA.ci_count_edges_dig_fltr_min_pulse_width = 0.0003
channelA.ci_count_edges_dig_fltr_enable = True
#task.timing.samp_clk_dig_sync_enable = True
task.timing.samp_clk_overrun_behavior = nidaqmx.constants.OverflowBehavior.TOP_TASK_AND_ERROR
#channelA.ci_encoder_decoding_type = nidaqmx.constants.EncoderType.X_1
#channelA.ci_count_edges_active_edge = nidaqmx.constants.Edge.RISING
task.start()
previous = [0.0]
running = True
while running:
try:
count=task.read(number_of_samples_per_channel=nidaqmx.constants.READ_ALL_AVAILABLE)
print("Current register is {}".format(channelA.ci_count))
except nidaqmx.errors.DaqError:
print("Read error encountered")
continue
if count[0] != previous[0]:
if count[0] != previous[0] + 1:
print("Increased count by more than one")
#total += (count[0] - previous[0])
total = count[0]
print("Total movement {:.3f} Total clicks {}".format(total, count[0]))
if total % self._encode_clicks == 0:
print("revolution complete")
previous=count
print("Cleanup")
task.stop()
06-05-2022 04:54 PM
I don't know the syntax for the Python DAQmx API, but can offer up these general thoughts:
1. You *will* want to configure the task for an angular encoder rather than for edge counting
2. You'll need to further configure the task to specify where the A and B channels are wired. (And Z if you're using it). Sorry, I don't know the Python syntax for this.
3. At least at first, try to get this running without configuring a sample clock so that you keep the task in on-demand mode.
4. With no sample clock, you'll need to read single values from the task rather than an array. Again, dunno what the Python syntax looks like for that.
-Kevin P
06-05-2022 06:44 PM
I did make an attempt at setting the task up as an angular encoder, but I could never get the signal debounced by setting the minimum pulse width. So, I could read movement, and the values were what I expected (0.36, since I have a 1000 pulse encoder), but I have the same directional problem (my reading is -0.36 in both directions), and sometimes I just get a stream of readings even when there is no motion:
Thanks for the advice -- I will try again.
-Evan-
06-06-2022 12:43 PM
I revisited the code treating this as an angular encoder, and corrected my mistake on debouncing the signal.
Now I don't see the spurious readings while the wheel is stationary.
However, I still get odd readings: negative values in both directions of rotation -- mostly. Sometimes, I see a positive value read evan while rotating in one direction.
I've tried various things, so there are likely settings in the code that may not be needed. I don't intend to use Z, but things are really odd if I don't enable z index support.
def startUsingRotation(self):
global running
total = 0.0
self.log.debug("Begin rotation detection using counters")
task = ni.Task(new_task_name="readCtr0")
#channelA = task.ci_channels.add_ci_ang_encoder_chan(counter = 'Mod3/ctr0', decoding_type = EncoderType.X_1, zidx_enable=True, units=AngleUnits.DEGREES, pulses_per_rev=1000, initial_angle=0.0)
channelA = task.ci_channels.add_ci_ang_encoder_chan(counter = 'Mod3/ctr0', decoding_type = EncoderType.X_1, zidx_enable=True, zidx_phase=nidaqmx.constants.EncoderZIndexPhase.AHIGH_BHIGH, units=AngleUnits.DEGREES, pulses_per_rev=1000, initial_angle=0.0)
channelA.ci_encoder_a_input_dig_fltr_min_pulse_width = 0.0003
channelA.ci_encoder_a_input_dig_fltr_enable = True
channelA.ci_encoder_a_input_term = 'PFI0'
channelA.ci_encoder_b_input_dig_fltr_min_pulse_width = 0.0003
channelA.ci_encoder_b_input_dig_fltr_enable = True
channelA.ci_encoder_b_input_term = 'PFI2'
channelA.ci_encoder_z_input_dig_fltr_min_pulse_width = ODOMETER_DEBOUNCE
channelA.ci_encoder_z_input_dig_fltr_enable = True
channelA.ci_encoder_z_input_term = 'PFI1'
#task.timing.samp_clk_overrun_behavior = nidaqmx.constants.OverflowBehavior.TOP_TASK_AND_ERROR
#channelA.ci_encoder_decoding_type = nidaqmx.constants.EncoderType.X_1
#channelA.ci_ang_encoder_units = nidaqmx.constants.AngleUnits.DEGREES
task.start()
previous = 0.0
running = True
while running:
try:
ang =task.read() #number_of_samples_per_channel=nidaqmx.constants.READ_ALL_AVAILABLE)
#print("Current register is {}".format(channelA.ci_count))
except nidaqmx.errors.DaqError:
self.log.error("Read error encountered")
continue
if ang != 0:
total += ang
print("Total movement {:.3f} Angle change {}".format(total, ang)
06-06-2022 09:33 PM
When you perform ang=task.read(), the value 'ang' is *already* the cumulative total change in angle. There's no need for "total += ang", just display "ang" itself. See how that goes.
-Kevin P
06-07-2022 11:06 AM
Ah! This is a helpful observation. The read mostly returns -0.36 each time, so I was totaling it up. Now that I set the zidx_val to 100, I see the ang always reading -100.36, so it must always be resetting.
I actually don't need z values -- can I just not wire that up and turn support off? I think I tried to just set it off, and got strange readings for the angle.
-Evan-
06-07-2022 12:01 PM
You should be able to change the config to set "zidx_enable=False" to turn off the reset action, whether or not you disconnect the physical wiring. You may also want to consider setting "decoding_type = EncoderType.X_4" to get a boost in resolution.
-Kevin P
06-08-2022 01:28 AM
Reading your description, I assume that the polarity of the a, b and/or z signals is incorrect.
06-09-2022 12:34 PM
It's even worse, and I finally got around to scoping the signals to check the polarity. The reason that all I can do is count edges is that things are a bit fried -- A, B, and Z all have pulses _at the same time_. Now I know why Z was constantly resetting to zero with every small move. I've ordered a new one, and I'm sure I will have a new flurry of questions why I try to get that one working.
06-10-2022 04:58 AM
This indeed explains a lot!
Is there any doubt about how you wired the signals or is it obvious that the encoder is defective?