I am fairly new to using pyserial and I am currently having difficulty with reading a scale. I believe that it has to do with some initialization that I am not doing correctly on python. I have been running the scale with LabVIEW but am trying to get away from it since my knowledge there is severely limited. When I execute the following code I get b ' ' printed. Without the timeout, the code will go on forever unless I unplug the device(i have also used ser.readline()). I have attached the initialization code that is used from labview if that helps (I know the settings on the block diagram differ from the code but you can manually change them on the front panel to match the scale settings). I appreciate any help in advance!
ser = serial.Serial("COM3",
9600,
timeout = 2,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_ODD)
print('Connected')
ser.read(5)
Your cable should be fine as you can connect the Scale UART. Then, you must properly setup the connection. According to your figure and some documentation (p. 55, also see) it should be:
import serial
ser = serial.Serial("COM3",
1200,
timeout = 2,
bytesize=serial.SEVENBITS,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_ONE)
If you got scrambled characters during communication, it is most likely the setup above that should be fixed to match the Scale setup.
Timeout occurs because there is not character to read from the UART. Most likely the device works in poll mode or streams character on specific conditions which are not met during the read
call.
Manual says (p. 65):
The print command can be transmitted by a software command or by pressing .
In the first case (poll mode), you must send commands (defined by a protocol) before reading any information back. This manual (p. 53-63) adds some shed of light on the protocol used to exchange information. Eg. if we want to poll the Scale Model:
ser.write(b"\x1bx1_\r\n") # Send data, stands for: ESC x 1 _ CR LF (p. 62)
rep = ser.read(64) # Try to read up to 64 bytes
To read data from Scale, use:
ser.write(b"\x1bP\r\n") # Equivalent to press button
# (block auto print, see p. 61)
rep = ser.read(ser.in_waiting) # Read pending bytes, should returns 16 bytes
# eg.: b"+****72.55*g**\r\n" (p. 57)
You can check this behaviour using:
rep = ser.read_until()
It will wait for \n
(Line Feed) before returning, start your script and press the button. You should receive data from the scale.
If the scale streams data on a specific event (eg.: button pressed) then you need to address a totally different problem. You will need to implement a Listener as you will need to continuously listen to the UART. It is generally done using a queue, the main idea is (emulated using a bytearray
for simplicity sake):
q = bytearray()
while True:
# Read until Line Feed:
d = ser.read_until()
# Update queue:
q.extend(d)
# Logic here to consume queue:
# ...
Do not use this last snippet in production, it just a dummy example to fix ideas. If you go to this solution you better implement a listener service to address the Producer-Consumer Problem.
Choosing between poll and stream is determined by the device capabilities and your application requirements.