Python U3 stream config for digital IO | LabJack
 

Python U3 stream config for digital IO

41 posts / 0 new
Last post
Terry
ttamboh's picture
Python U3 stream config for digital IO

Hello,

 

I am a bit new to using labjack U3. I am trying to configure streaming for digital input in python and I am running into the "This error is raised when you try to do an analog operation on a pin which is configured for digital." My understanding from reading the datasheet is that by default all the IO are set as digital inputs and only needs changing when we are dealing with analog inputs/output (ex. configIO(FIOAnalog=255))

A little about what I am trying to do. I have two hall sensor and 2 encoder, all outputting digital data, connected to the labjack. I am trying use the labjack to stream their data and save it to a file on my pc.

Following the stream. py code from the example, here is what I have 

import u3

MAX_REQUESTS = 75

d = u3.U3()

d.getCalibrationData()

d.configIO()

TestChannels = [0,1,3,8,10,17,19]

d.streamConfig( NumChannels = len(TestChannels), PChannels = TestChannels, NChannels = [ 31]*len(TestChannels), Resolution = 3, ScanFrequency = 5000 )

Is there something I am doing wrong?

 

Any help is appreciated

 

Thanks,

Terry

LabJack Support
LabJack Support's picture
That error indicates one or

That error indicates one or multiple channels you are trying to stream as analog inputs are configured as digital I/O. The TestChannels you use are analog input channels. Channels 0-15 are AIN0-AIN15. Channels 17 and 19 are not valid. If those are meant to be digital I/O, use channels 193 (EIO_FIO) and 194 (CIO). Those stream channels are documented here:

https://labjack.com/support/datasheets/u3/operation/stream-mode/digital-inputs-timers-counters

When getting the stream data with LabJackPython, the channel names are AIN#, where # is the channel number. So the digital readings will be in r["AIN193"] and r["AIN194"].

Before configuring/starting the stream, configure I/O as digital (with configIO and its FIOAnalog and EIOAnalog parameters) and digital directions to inputs (with getFeedback). The quickstart demonstrates configIO and getFeedback. To configure multiple digital directions, you can also use getFeedback with u3.PortDirWrite.

https://labjack.com/support/software/examples/ud/labjackpython/low-level

A quick demonstration of setting all FIOs and EIOs to digital I/O and direction to inputs (In the comments, numbers prefixed by "b" indicates binary. Each bit of the passed value is an I/O setting.):

# b0 = analog, b1 = digital
# FIOAnalog = 0 = b00000000
# EIOAnalog = 0 = b00000000
d.configIO(FIOAnalog=0, EIOAnalog=0)


# b0 = input, b1 = output
# Direction = [FIODirection, EIODirection, CIODirection] = [0, 0, 0] = [b00000000, b00000000, b0000]
d.getFeedback(u3.PortDirWrite(Direction=[0, 0, 0]))

LabJack Support
LabJack Support's picture
To add, factory power up

To add, factory power up defaults for FIOs and EIOs are digital inputs. On the U3-HV, FIO0-FIO3 are analog inputs only. So if you have not changed the power up defaults, or configured lines as analog inputs while the U3 has been powered, the configIO and getFeedback calls I mentioned at the end of my last post are not needed, but they do ensure all FIOs and EIOs are digital inputs before streaming.

Terry
ttamboh's picture
Thank you for yourn quick

Thank you for yourn quick responds,

Your guidance above is very helpful. To follow up, once I have configure all FIO, EIO and CIO as digital inputs (with channesl 193,194), how do i stream individual IO? Will the IO still follow the same numbering (0-15) for FIO_EIO and 17,19 in the CIO? If so can I just do the following:

for r in d.streamData(): if r is not None: # Our stop condition if dataCount >= MAX_REQUESTS: break print r['AIN0'], ",", r['AIN1'], ",", r['AIN3'], ",", r['AIN8'], ",", r['AIN10'], ",", r['AIN17'], ",",r['AIN19']
Terry
ttamboh's picture
I think I figured out it. 

I think I figured out it. 

I used the following and I don't get any errors at all

print (r['AIN193'][0]), ",", (r['AIN193'][1]), ",", (r['AIN193'][3]), ",", (r['AIN193'][8]), ",", (r['AIN193'][10]), ",", (r['AIN194'][17]), ",", (r['AIN194'][19])

 

LabJack Support
LabJack Support's picture
r['AIN193'] is a list of EIO

r['AIN193'] is a list of EIO and FIO samples. Each list element has a 2 element tuple, which are the FIO readings ( r['AIN193'][x][0] ) and EIO readings ( r['AIN193'][x][1] ).

r['AIN194'] is a list of CIO samples. Each list element has a 2 element tuple, which are the CIO readings ( r['AIN194'][x][0] ) and 0 (no data, ignore it).

FIO, EIO and CIO stream readings/samples are byte values, where each bit is a line's state. Bit 0 is the FIO0/EIO0/CIO0 state, bit 1 is the FIO1/EIO1/CIO1 state, and so on. 0 is a low state, and 1 is a high state.

Digital I/O 0, 1, 3, 8, 10, 17, 19 are FIO0, FIO1, FIO3, EIO0,  EIO2, CIO1, CIO3. To get the first scan of samples of the FIO, EIO and CIO states (parsed into lists of states) and display the ones you want:

fio = [(r["AIN193"][0][0] >> i) & 1 for i in range(8)]
eio = [(r["AIN193"][0][1] >> i) & 1 for i in range(8)]
cio = [(r["AIN194"][0][0] >> i) & 1 for i in range(4)]
print("1st: %d %d %d %d %d %d %d" % (fio[0], fio[1], fio[3], eio[0], eio[2], cio[1], cio[3]))

Second scan of samples:

fio = [(r["AIN193"][1][0] >> i) & 1 for i in range(8)]
eio = [(r["AIN193"][1][1] >> i) & 1 for i in range(8)]
cio = [(r["AIN194"][1][0] >> i) & 1 for i in range(4)]
print("2nd: %d %d %d %d %d %d %d" % (fio[0], fio[1], fio[3], eio[0], eio[2], cio[1], cio[3]))

And so on.

Terry
ttamboh's picture
Hello,

Hello,

I have a follow up question to the above. Why do we have two states. What is the difference between them?

what is the difference between r["AIN193"][0][0] and (r["AIN193"][1][0]

 

LabJack Support
LabJack Support's picture
r["AIN193"][0][0] is the

r["AIN193"][0][0] is the first reading of FIO0-7 states and r["AIN193"][1][0] is the second reading of FIO0-7 states. To continue, r["AIN193"][2][0] is the third, r["AIN193"][3][0] is the fourth, and so on. In my previous post I demonstrate parsing out the FIO, EIO, and CIO states for the first two set of readings (scans) and displaying the FIO0, FIO1, FIO3, EIO0,  EIO2, CIO1, and CIO3 states. My previous post goes into more details of the returned stream data when streaming with channels 193 and 194.

Terry
ttamboh's picture
I guess I am confused about

I guess I am confused about the following:

1. How are you getting the values of FIO1,FIO3 from below?

fio = [(r["AIN193"][0][0] >> i) & 1 for i in range(8)]
print("1st: %d %d %d" % (fio[0], fio[1], fio[3]))

I was under the impression that the values are obtained by doing r["AIN193"][1][0], r["AIN193"][3][0]. How is the fioproviding data for all FIO channels?

 

LabJack Support
LabJack Support's picture
With stream mode you are

With stream mode you are reading many samples/readings which the hardware is sampling at the configured scan rate. Refer to stream mode documentation for general details:

https://labjack.com/support/datasheets/u3/operation/stream-mode

r["AIN193"][1][0] is the second reading of FIO0-FIO7 states, and r["AIN193"][3][0] is the fourth reading of FIO0-FIO7 states. r["AIN193"][x] is not the digital I/O channel, but the reading number. When streaming digital I/O, you are reading digital I/O grouped. Refer to post #6 for details.

So lets break down the first reading of FIO0-7, which would be in r["AIN193"][0][0]. That will be a value of 0 to 255, an 8-bit value. Each bit is a state (0 = low, 1 = high). Bit 0 is the state of FIO0, bit 1 is the state of FIO1, and so on. For example, if FIO0-3 are low, and FIO4-7 are high, that would be a read value of 240, which in binary is b11110000. This code is parsing out the individual states from the 8-bit value (0-255):

fio = [(r["AIN193"][0][0] >> i) & 1 for i in range(8)]

Broken down is something like:

fio = [0]*8  # Create an 8 element array for the individual states
fio[0] = (r["AIN193"][0][0] >> 0) & 1  # Bit 0 value (FIO0 state)
fio[1] = (r["AIN193"][0][0] >> 1) & 1  # Bit 1 value (FIO1 state)
fio[2] = (r["AIN193"][0][0] >> 2) & 1  # Bit 2 value (FIO2 state)
fio[3] = (r["AIN193"][0][0] >> 3) & 1  # Bit 3 value (FIO3 state)
fio[4] = (r["AIN193"][0][0] >> 4) & 1  # Bit 4 value (FIO4 state)
fio[5] = (r["AIN193"][0][0] >> 5) & 1  # Bit 5 value (FIO5 state)
fio[6] = (r["AIN193"][0][0] >> 6) & 1  # Bit 6 value (FIO6 state)
fio[7] = (r["AIN193"][0][0] >> 7) & 1  # Bit 7 value (FIO7 state)

So if r["AIN193"][0][0] is value 240 for demonstration purposes, the above code parses it to:

fio[0] = 0
fio[1] = 0
fio[2] = 0
fio[3] = 0
fio[4] = 1
fio[5] = 1
fio[6] = 1
fio[7] = 1

So parsing the first reading's FIO states using the one line of code parsing is:

fio = [(r["AIN193"][0][0] >> i) & 1 for i in range(8)]

The second reading's FIO states:

fio = [(r["AIN193"][1][0] >> i) & 1 for i in range(8)]

The third:

fio = [(r["AIN193"][2][0] >> i) & 1 for i in range(8)]

The fourth:

fio = [(r["AIN193"][3][0] >> i) & 1 for i in range(8)]

and so on.

If you are reading digital I/O at a rate under 100 Hz, consider using command-response mode which is less complex than stream mode. Your software will control the rate of the readings. For example, getting one reading of FIO0, FIO1, FIO3, EIO0,  EIO2, CIO1, CIO3 could be:

command = [u3.BitStateRead(0), u3.BitStateRead(1), u3.BitStateRead(3), u3.BitStateRead(8), u3.BitStateRead(10), u3.BitStateRead(17), u3.BitStateRead(19)]
states = d.getFeedback(command)  # Returned are the states of only [FIO0, FIO1, FIO3, EIO0,  EIO2, CIO1, CIO3]

Terry
ttamboh's picture
Thank you for the explanation

Thank you for the explanation. How do I retrieve the actual sample values from the streams for the above channels? 

LabJack Support
LabJack Support's picture
Please see the above posts.

Please see the above posts. If that doesn't explain it, can you ask a more specific question?

Terry
ttamboh's picture
So the problem I am having is

So the problem I am having is I have a max_request of 75, each request should contain 48 packets and each packet should have 25 samples. So I should expect 90,000 samples in total per channel. So for 7 channel, i should expect a 90,000 x7 matrix of samples. However, I dont get that. I get 75 x7 samples.

LabJack Support
LabJack Support's picture
 

Why are you using 7 in your multiplication? Channels 193 and 194 are the only channels (as far as the returned array goes) you are streaming.

Do you understand how to parse out the FIO bits, EIO bits and CIO bits, which are the states? Do my previous explanations make sense?

You are streaming two channels Each channel will be one sample. You are not streaming 7 channels, but the two channels do contain the states you want (including all digital I/O states).

Channel 193 contains the FIO and EIO states in the one sample (the two element tuple mentioned earlier) and channel 194 contains the CIO states in one sample (also in a two element tuple). This is mentioned in post 6.

If you do len(r[“AIN193”]) and len(r[“AIN194”]) you will see how many samples there are for each channel, and you need to parse out the states from the samples. Previous posts go over the parsing out the states.

Terry
ttamboh's picture
Hello,

Hello,

Sorry for the confusion, the 7 that i was referring to was the 7 states that was pulling out of the AIN193 and AIN194. It seems that I was taking the first reading of each scan only. I just needed a loop to step through all the readings and do the approriate bitwise conversions you showed in post 6 and now I am getting the satisfied result. 

One question that I had is whether it is possible to stream 2 hall sensors and 2 encoders (quadrature with differential outputs) data at the same time. I am trying to map the hall states to the position of the encoders. I understand that each encoder takes 2 timers to operate. Is there a way to a way to have the two encoders share the same times? Could you point in the direction of how set that up perhaps an example? 

Thanks

LabJack Support
LabJack Support's picture
it is possible to stream 2

it is possible to stream 2 hall sensors and 2 encoders

To measure two quadrature encoders with the U3 you would need to stop and reconfigure the timers are regular intervals. Doing so would mean that reading of one encoder would be suspended while the other encoder is being read. To get that to work you would need to be able to guarantee that the encoder not being read is either not generating counts, or at least not generating counts that we care about.

Another possibility is to use a counter. The counter will just count pulses on one signal and thus will not have any indication of direction; will only count up.

Beyond that, we need a DAQ capable of reading two encoders or a second DAQ.

Terry
ttamboh's picture
Knowing direction is not

Knowing direction is not important because I will control that with the motor controller and will. Do you have any examples on how the counter(s) should be setup?

 

Thanks,

LabJack Support
LabJack Support's picture
You enable counters with

You enable counters with configIO. If enabling both counters, do it in one call. For example, to enable counters 0 and 1 on FIO4 and FIO5:

# Configuring Counter 0 and Counter 1 on FIO4 and FIO5. TimerCounterPinOffset sets the starting pin (4 = FIO4).
d.configIO(FIOAnalog=0x0f, EnableCounter0=True, EnableCounter1=True, TimerCounterPinOffset=4)

We have general documentation on timers and counters here:

https://labjack.com/support/datasheets/u3/hardware-description/timers-counters

As for streaming counters, the channels to use are mentioned here:

https://labjack.com/support/datasheets/u3/operation/stream-mode/digital-inputs-timers-counters

Keep in mind that a stream sample is 16-bits, and a counter reading is 32-bits, so 2 channels are needed for the full 32-bit value reading. So to configure the stream for digital I/O and 2 counters, with streamConfig you would use a scan list (PChannels) of [193, 194, 210, 224, 211, 224].

The 210/224 channel pair is for the full counter 0 reading and 211/224 channel pair for the full counter 1 reading. 210 and 211 are the lower 16-bits (LSW), and 224 is the upper 16-bits (MSW) of the reading.

Since 224 is used twice in the scan list (PChannels), both 224 scan readings will be put in r["AIN224"], so you will notice len(r["AIN224"]) will be double in size of len(r["AIN210"]) or len(r["AIN211"]. Data is interleaved for AIN224 in this case ([counter0_MSW, counter1_MSW, counter0_MSW, counter1_MSW, ...]).

So the first scan of readings are in:

FIO_EIO: r["AIN193"][0]
CIO: r["AIN194"][0]
Counter0 (LSW, MSW): r["AIN210"][0], r["AIN224"][0]
Counter1(LSW, MSW): r["AIN211"][0], r["AIN224"][1]

The second scan:

FIO_EIO: r["AIN193"][1]
CIO: r["AIN194"][1]
Counter0 (LSW, MSW): r["AIN210"][1], r["AIN224"][2]
Counter1(LSW, MSW): r["AIN211"][1], r["AIN224"][3]

Third:

FIO_EIO: r["AIN193"][2]
CIO: r["AIN194"][2]
Counter0 (LSW, MSW): r["AIN210"][2], r["AIN224"][4]
Counter1 (LSW, MSW): r["AIN211"][2], r["AIN224"][5]

and so on:

FIO_EIO: r["AIN193"][x]
CIO: r["AIN194"][x]
Counter0 (LSW, MSW): r["AIN210"][x], r["AIN224"][x*2]
Counter1 (LSW, MSW): r["AIN211"][x], r["AIN224"][x*2+1]

Parsing the the 32-bit counter values for the first scan:

counter0 = r["AIN210"][0] + (r["AIN224"][0] << 16)
counter1 = r["AIN211"][0] + (r["AIN224"][1] << 16)

The second scan:

counter0 = r["AIN210"][1] + (r["AIN224"][2] << 16)
counter1 = r["AIN211"][1] + (r["AIN224"][3] << 16)

And so on:

counter0 = r["AIN210"][x] + (r["AIN224"][x*2] << 16)
counter1 = r["AIN211"][x] + (r["AIN224"][x*2+1] << 16)

If you are fine with the counters being a 16-bit value (0-65536), you could simplify the the scan list to [193, 194, 210, 211]. Also, I just want to point out that stream channels 193 and 194 are the only channels where a channel reading is a 2 element tuple. All other channels a channel reading is just a value, so as seen above r["AIN210"][x], r["AIN211"][x], and r["AIN224"][x] are values (16-bit unsigned integer in those cases), instead of a tuple, when calculating the 32-bit counter value.

Terry
ttamboh's picture
Hello,

Hello,

 

Another thing i am curious about is how to set up differential inputs for streaming. I understanded that when we designate NChannels = [31], the 31 signifies single-end input. For differential inputs say for FIO0 and FIO1, Do I put EIO0 in the PChannel and EIO1 in the NChannel?

example: d.streamConfig(NumChannels = 1, PChannel = [0], NChannel=[1],  Resolution = 3, ScanFrequency = 1600)

Also if I want to use channels 193, 194, how do I set up the Nchannel

Thank

LabJack Support
LabJack Support's picture
Digital I/O cannot be

Digital I/O cannot be configured for differential, so with PChannels 193 and 194, the corresponding NChannel setting is not applicable (needs to be set but is ignored). Only analog inputs can be configured for differential. So say you want a AIN8-AIN9 (EIO0-EIO1 when analog) differential, that would be PChannel and NChannel 8 and 9.

Terry
ttamboh's picture
Hello, 

Hello, 

 

Hope this message finds you well. I have some questions with regards to counters that I am hoping to get some help with.

Firstly, referencing from comment #18 do I do a convertion of each significant bit to 16 before adding them together?

(r["AIN210"][1] + r["AIN224"][2]) << 16 or (r["AIN210"][1] <<16) + (r["AIN224"][2] << 16)?

Secondly, when stream encoder data, I notices that after a few while, the data does not change anymore even though the motor is moving. I have confirmed via the motor controller (copley) software (CME) that the encoder counts actually change for the same motion. Is there something I am missing. I have attached a what i see and the section of my code pertaining to the streaming setup below. Any help is really appreciated.

 

thanks

 

 

File Attachment: 
LabJack Support
LabJack Support's picture
1. You do:

1. You do:

(r["AIN210"][1] + r["AIN224"][2]) << 16

Channel 210 is the lower 16-bits and channel 224 is the higher 16-bits of the 32-bit value.

2. I don't see an obvious issue in your code why the count would stop. If you are on Windows, test the Counter in the LJControlPanel application with your motor. See if it stops counting at a certain point as well. If it does stop counting as well then we can troubleshoot hardware further.

If you can't test with LJControlPanel, for testing try simplifying your code to only do counting without streaming and see if you still see the issue. After enabling a counter, using command-response you can read the counter with:

# Counter 0 enabled earlier

#Get current count of Counter 0
counter0 = self._u3.getFeedback(u3.Counter0(Reset = False))

Earlier we discussed quadrature. To add, we point people here about "Quadrature Decoding or Simple Counting?" when discussing quadrature:

https://labjack.com/support/datasheets/t-series/digital-io/extended-feat...

Note that this is not specifically for the U3, but goes over the topic in general. For the U3, Counter 0 and Counter 1 are the high speed counters on the U3 and what you are using. Timer mode 5 (Firmware Counter Input) is an interrupt counter. Edge rate limits are different on the U3 than in the T-series.

Terry
ttamboh's picture
Hello, 

Hello, 

 

I tried testing just the counter( which the command in #22) while runing the motor and still ended up with an array of zero for the pulse counts.

from PyCopley import Accelnet as MC
import time
import concurrent.futures
import u3

sleeptime = 5

Labjack = u3.U3()
Labjack.getCalibrationData()
Labjack.configIO(EnableCounter0=True,TimerCounterPinOffset=8)
def counterCapture():
    starttime = time.time()
    Test = True
    Data = []
    while Test:
        datapoint = Labjack.getFeedback(u3.Counter0(Reset = False))
        # print(datapoint)
        Data.append(datapoint)

        endtime = time.time()
        timediff = endtime - starttime
        if endtime-starttime > sleeptime:
            Test = False
    return Data
AXIS_A = '.a'
Controller = MC()
cmd_vel = 100 # rpm
cmd_vel_scaled = (((cmd_vel*10) * 2000)/600)
Controller.setAxis(AXIS_A)

def moveMotor():
    Controller.enableProgrammedVelocityMode(True)
    Controller.configProgrammedVelocity(cmd_vel_scaled)
    time.sleep(sleeptime)
    Controller.configProgrammedVelocity(0)
    Controller.enableProgrammedVelocityMode(False)

with concurrent.futures.ThreadPoolExecutor() as executor:
    f1 = executor.submit(moveMotor)
    f2 = executor.submit(counterCapture)
    print(f2.result())

print ("end test")

Results: [[0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], [0],

 

LabJack Support
LabJack Support's picture
To figure out if this is a

To figure out if this is a software bound issue or hardware bound issue please try connecting the counter to a test signal rather than using your encoder output. Additionally, if you are on Windows, I would strongly suggest testing the counter with LJControlPanel before looking at your software.

One simple test could be to connect one end of a piece of wire to GND then touch the other end of the wire to the terminal tied to the counter (EIO0 based on your setup). This will generate an edge and the counter should increase in your test script.

Another test would be to set up a timer with a PWM output and put a jumper wire from the PWM to the counter (note that enabling a timer would change what terminal Counter0 appears on).

Terry
ttamboh's picture
Hello, 

Hello, 

 

Thank you for your suggestions. So I tried a couple of thing.

I confirmed using the LJControlPanel that counter increases when an external pwm signal, an arduino constantly generating pulses, is connect to the labjack. The increase is multiple counts at a time, on average about 100 counts every update.

I then tried to run the script in #21, to stream what the output. What I noticed is that there is are continuous repetition of some values in the stream. Please see attachment. 

This behaviour is also happening when I connect the encoder to the labjack. 

I am spinning the motor at about 20rmps so I was not expecting there to be repetition of some value. It give the elution that there is a delay between some pulses (and with respect to the encoder, the motor either slowed to a halt for a while and then started up again)

Could you help me understand why this could be happening and if there is any way to mitigate that? 

File Attachment: 
LabJack Support
LabJack Support's picture
I am not sure about the data

I am not sure about the data values you got, but it would make sense that you are getting repeated data if the loop you are using to read the counter is iterating faster than you get motor ticks (you are probably looping slightly faster than 1000 times per second).

What is the encoder output expected to look like in terms of ticks per rotation? What does the script output look like if you use the test signal instead of the motor encoder? Do you see the same results if you directly print each result from the feedback call in your counterCapture function?

Terry
ttamboh's picture
Hello, I am using the script

Hello, I am using the script attached to #21, which is just a slight modification of the the streaming example code that comes with the python labjack module. The modifcation being, using a counter and digital Inputs instead of analog ones.

 The encoder has 81,920 ticks per revolution. The output of the script with the test signal looks similar to that of the encoder in terms of seeing multiple repetition of some data values. 

Terry
ttamboh's picture
Hello,

Hello,

I used an oscilloscope to look at the signal from the encoder and i noticed that the low is a t 1.4v and the high is at 2.9v. What is the voltage threshold for high and low Could this be falling out of the threshold for high and low? Is it possible that this could be affecting the counter?

LabJack Support
LabJack Support's picture
It looks like you are left

It looks like you are left shifting the lower two bytes of your counter because each of your printed increments is 65536, which is 1<<16. If you only have counter0 set up then its value should be

r["AIN210"][x] + (r["AIN224"][x] << 16)

not

(r["AIN210"][x] + r["AIN224"][x]) << 16

We suggested the correct way to shift initially but had a typo in post #22.

Your increment is much too low for 20RPM at  81,920 ticks per revolution, but 81,920 ticks per revolution seems incredibly high for the encoder resolution. Even if the encoder resolution is correct, you should be able to monitor such a signal with a hardware counter (the max frequency input is 8MHz). Do you have an encoder datasheet we can look at?

Your output suggests a tick happens every 4-5 stream samples; this is consistent with a 20RPM motor with an encoder resolution of 1024 ticks per revolution.

20RPM = 0.33 rotations/s

(0.33 rotations/s) * 1024 ticks per revolution = 341.33 ticks/s

(1600 samples/s) / (341 ticks/s) = 4.69 samples per tick

I would suggest modifying the shift code then run the script with your test signal again.  Assuming a 100Hz signal we would expect there to be a tick increment every 16 updates of your 1600Hz stream.

LabJack Support
LabJack Support's picture
Sorry, I saw your new post

Sorry, I saw your new post right after posting my last response.

The transition levels you are seeing are problematic. 2.9V is within the logic high threshold, but 1.4V is outside of the logic low threshold and is in a sort of undefined range of voltages. See our DIO specs on this page:

https://labjack.com/support/datasheets/u3/appendix-a

Terry
ttamboh's picture
Hello,

Hello,

Attach is the datasheet for the encoder. This is the CE300-40

Terry
ttamboh's picture
The encoder type is R3213CE

The encoder type is R3213CE

LabJack Support
LabJack Support's picture
Given the encoder

Given the encoder specifications, I would maybe expect to see 20,480 ticks per revolution since we are looking at simple 1x counting (only tracking falling edges) rather than quadrature 4x counting.

The logic levels you are seeing still seem problematic. You could try adding a comparator to modify your output to something within range for the U3, or the 1.8V version of our LJTick-DigitalIO should work to give you 0 and 3.3V logic levels:

https://labjack.com/accessories/ljtick-lvdigitalio

Terry
ttamboh's picture
Hello,

Hello,

I would like some help configuring timers on the U3 for a quadrature encoder. I am particularly interested in how setup the labjack to increament and decrement counts. 

so far my setup is as follows:

self._u3.configIO(FIOAnalog=0, EIOAnalog=0, NumberOfTimersEnabled=2, TimerCounterPinOffset=8) self._u3.getFeedback([u3.TimerConfig(timer = 0, TimerMode = 8, Value = 0), u3.TimerConfig(timer = 1, TimerMode = 8, Value = 0)]) self.ALLDIO = [193, 194, 200, 201, 224] self.NChannels = [31, 31, 31, 31] self._u3.streamConfig(NumChannels=len(self.ALLDIO), PChannels=self.ALLDIO, NChannels=self.NChannels, Resolution=self.ScanResolution, ScanFrequency=self.ScanRate, )

How do I now read counts?

How do I setup an the counts to increment or decrement?

Thanks

LabJack Support
LabJack Support's picture
Looks like you have

Looks like you have quadrature input configured on EIO0 and EIO1. When reading the quadrature input, you only read from one of the timers. So stream only 200 and 224 for the quadrature timer's count ( self.ALLDIO = [193, 194, 200, 224] ). A timer reading is a 32-bit value from the two channels 200 and 224. Note that the quadrature input's count is a 32.bit 2's compliment value (signed 32-bit value), so that needs to be considered when parsing out the reading:

import ctypes

...

# Using ctypes to convert unsigned 32-bit value to a signed 32-bit value
ctypes.c_int(r["AIN210"][x] + (r["AIN224"][x] << 16)).value

Quadrature input mode is documented here:

https://labjack.com/support/datasheets/u3/hardware-description/timers-co...

 

 

Terry
ttamboh's picture
Hello Thank you for your

Hello Thank you for your response.

 

I inplemented your suggestion as follows:

counter0 = ctypes.c_int(r["AIN200"][k] + (r["AIN224"][k] << 16)).value self.totalcount = self.totalcount+counter0

where self.totalcount was initialized to 0 prior to the count. 

One thing that I am noticing is that the counts(7113 max) are significantly less the expected encoder output for 1 revolution (81,920) for a quadrature.

Is there anything I am doing wrong?

Is there some delay associated with the ctype conversion that could significantly impact the count?

Also, I tried doing a continuous count where I span the motor forward by 1 rev and then reverse another rev. The results seem to either increase in the forward direction only or the reverse. I was expecting an increase in count and then midway, a decrease down. Is this not possible?

lastly, is there a way to save the last count in memory and have the labjack continue either incrementing or decrementing from that value?

 

Thanks

LabJack Support
LabJack Support's picture
You are running up against

You are running up against the edge rate limit on the quadrature feature, with stream running you are limited to around 7000edges/s on the timers. See this page:

https://labjack.com/support/datasheets/u3/hardware-description/timers-co...

If you need to use quadrature readings I would suggest looking into an external quadrature counter. You could look into something like this board and use our SPI feature to get readings from the LS7366R counter:

https://www.mouser.com/ProductDetail/Mikroe/MIKROE-1917?qs=0lHBc9ha0jdWk...

See this page for more information on configuring SPI:

https://labjack.com/support/datasheets/u3/high-level-driver/example-pseu...

Terry
ttamboh's picture
Hi Soloman,

Hi Soloman,

 

Thank you for replying. I actually began my project using just a simply counter and counting pulse on a single encoder line. The issue that I had was that I could not get the counts in the forward and reverse direction to match. I can control the directional spin of the motor via the motor controller so directionality isn't really the problem. I am currently taking these counts separately. I subtract the last count for the forward from all of the reverse counts to get the decrement. most of the time end up with negative values towards the end of the reverse count array. Which tells me that it does not align with the forward value.

 

Do you have any suggestion for me?

LabJack Support
LabJack Support's picture
This is still Soloman at

This is still Soloman at LabJack, I just switched accounts on you; apologies if that was confusing.

What did your set up look like when you changed from counting ticks in the positive direction to the negative direction? I am not sure the best way to help troubleshoot the issue you were having, but here is what I imagine the system should look like to get the right number of counts with a direction change, hopefully it is of some help:

  1. Enable your hardware counters before the motor starts turning
  2. Accumulate edges on both counters until the engine stops to change direction
  3. Read, record, and reset the counters while the engine is stopped, before reversing. You probably need around 2ms of the engine not moving to capture the last count read and reset properly. If you use some trigger signal to determine when the direction change happens you likely need around 3ms between your count read and restart

    The delay I am estimating comes from our expected command response overhead values:
    https://labjack.com/support/datasheets/u3/operation/command-response
  4. Repeat 2-3 above
Terry
ttamboh's picture
Hello,

Hello,

 

I am experiencing an unusual error and was hoping you could help me understand what is causing it. I am trying to use LJControlPanel to configure  a counter at EIO1 or EIO3 but seem to be getting this error: TC Config error 0: INVALID_OFFSET Excep: :Bad offset 

So far the only pin that seem to not give me that error is EIO0 any other pin in the EIO series seem to give my the above error.

What could be causing this error. Could it be a hardware failure?

 

Thanks

LabJack Support
LabJack Support's picture
Valid pin offsets are 4-8 as

Valid pin offsets are 4-8 as documented here:

https://labjack.com/support/datasheets/u3/hardware-description/timers-co...

Otherwise you will get the error you are seeing. A pin offset of 9 (EIO1) or 11 (EIO3) are not valid. Looks like LJControlPanel and its test panel doesn't max. limit the pin offset to 8, so choosing anything above 8 will have an error which isn't a hardware failure.