Python Serial: having trouble reading the port - python

I'm attempting to read the values of some GPIO. Here's the code:
import serial
import codecs
import time
ser = serial.Serial(port = 'COM4', baudrate = 9600, \
parity = serial.PARITY_NONE, \
stopbits = serial.STOPBITS_ONE, \
bytesize = serial.EIGHTBITS, \
timeout = 0, \
)
print('connected to: ',ser.name)
ser.close()
def SSend(input):
ser.write(codecs.decode(input, "hex_codec")) #send as ASCII
print('sent: ', input)
def ReadIO():
#open the port
try:
ser.open()
except:
print('error opening serial port')
exit()
#flush the buffers
ser.flushInput()
ser.flushOutput()
#write data to read from GPIO
#causes SC18IM to return a byte containing each of the 8 I/O values
SSend(b'4950')
time.sleep(0.1) #allow time for the data to be received
#read the data
serialData = False
serialData = ser.readline()
ser.close()
return serialData
while 1:
print(ReadIO())
time.sleep(0.5)
This prints the following:
sent:
b'4950'
b''
(I am expecting back either 0x00 or 0x20 instead of an empty byte)
I know my hardware is good as is what I'm sending because it get back what I expect when using Realterm and have successful write commands in my script elsewhere.
I had some luck using this
#read the data
serialData = False
for c in ser.readline():
print('in loop')
print(c)
serialData = c
ser.close()
However, I don't really understand why it worked and it only appears to work intermittently.
Thanks for reading.

readline() assumes that there is some end-of-line symbol, like \n or \r. You should read data byte-wise:
serialData = ''
while ser.inWaiting() > 0:
c=ser.read(1)
# or c=ser.read(1).decode('latin1')
serialData += c

Related

Unable to read data from serial port

I tried to read data from USB port on OSX using pyserial. When I tried to read it using CoolTerm, everything worked fine. This is the configuration:
Then I tried to write a short script which doesn't continuously output the data (it outputs the data only once and the even if I restart the script, nothing comes out):
import serial
import time
ser = serial.Serial("/dev/cu.SLAB_USBtoUART", 115200, timeout=5, bytesize=8, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE)
def getTFminiData():
while True:
# time.sleep(0.1)
count = ser.in_waiting
if count > 8:
recv = ser.read(9)
ser.reset_input_buffer()
if recv[0] == 0x59 and recv[1] == 0x59: # python3
distance = recv[2] + recv[3] * 256
strength = recv[4] + recv[5] * 256
print('(', distance, ',', strength, ')')
ser.reset_input_buffer()
if __name__ == '__main__':
try:
if ser.is_open == False:
ser.open()
getTFminiData()
except KeyboardInterrupt: # Ctrl+C
if ser != None:
ser.close()
Does anyone know what is the right way to get the same data as CoolTerm in this case does?
Thanks to Joe's comment, I fuggered out how to modify the code. The working example is the following:
import serial
import time
ser = serial.Serial("/dev/cu.SLAB_USBtoUART", 115200, bytesize=8, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE)
def getTFminiData():
bytes_read = 0
data = None
while True:
# time.sleep(0.1)
count = max(1, ser.in_waiting)
if count < 8:
if data is None:
data = ser.read(count)
else:
data.append(ser.read(count))
bytes_read += count
else:
recv = ser.read(9 - bytes_read)
bytes_read = 0
recv = data + recv
data = None
ser.reset_input_buffer()
if recv[0] == 0x59 and recv[1] == 0x59: # python3
distance = recv[2] + recv[3] * 256
strength = recv[4] + recv[5] * 256
print('(', distance, ',', strength, ')')
ser.reset_input_buffer()
if __name__ == '__main__':
try:
if ser.is_open == False:
ser.open()
getTFminiData()
except KeyboardInterrupt: # Ctrl+C
if ser != None:
ser.close()

Python serial port returing null string

Reading data from the serial port:
readline() in the below code return the null vector, the reading data from the serial port is hexadecimal number like AABB00EF the putty gives me the output means the communication is working but nothing works via python
here is the code:
#!/usr/bin/python
import serial, time
ser = serial.Serial()
ser.port = "/dev/ttyUSB0"
ser.baudrate = 115200
#ser.bytesize = serial.EIGHTBITS
#ser.parity = serial.PARITY_NONE
#ser.stopbits = serial.STOPBITS_ONE
#ser.timeout = None
ser.timeout = 1
#ser.xonxoff = False
#ser.rtscts = False
#ser.dsrdtr = False
#ser.writeTimeout = 2
try:
ser.open()
except Exception, e:
print "error open serial port: " + str(e)
exit()
if ser.isOpen():
try:
#ser.flushInput()
#ser.flushOutput()
#time.sleep(0.5)
# numOfLines = 0
# f=open('signature.txt','w+')
while True:
response = ser.readline()
print len(response)
#f=ser.write(response)
print response
# numOfLines = numOfLines + 1
f.close()
ser.close()
except Exception, e1:
print "error communicating...: " + str(e1)
else:
print "cannot open serial port "
readline will try to read until the end of the line is reached, if there is no \r or \n then it will wait forever (if you have a timeout it might work...) instead try something like this
ser.setTimeout(1)
result = ser.read(1000) # read 1000 characters or until our timeout occures, whichever comes first
print repr(result)
just use this code
ser = serial.Serial("/dev/ttyUSB0",115200,timeout=1)
print "OK OPENED SERIAL:",ser
time.sleep(1)# if this is arduino ... wait longer time.sleep(5)
ser.write("\r") # send newline
time.sleep(0.1)
print "READ:",repr(ser.read(8))
you can create a readuntil method
def read_until(ser,terminator="\n"):
resp = ""
while not resp.endswith(terminator):
tmp = ser.read(1)
if not tmp: return resp # timeout occured
resp += tmp
return resp
then just use it like
read_until(ser,"\r")

Python UART between 2 Raspberry Pis

I'm trying to send strings between two Raspberry Pis via UART. So far, one Pi is able to transmit a string and the second pi is only able to receive. I'm trying send a "command" from one Pi to the other, then the second Pi will receive the "command" and then send "sensor data" back to the first Pi. However, this doesn't seem to work. I'm unable to both send and receive data.
Any help would be greatly appreciated.
The Raspberry Pi that is sending the command:
import serial
ser = serial.Serial(
port = '/dev/ttyAMA0',\
baudrate = 115200,\
bytesize = serial.EIGHTBITS,\
timeout = 0)
dat = ''
while True:
#asks user for input
command = raw_input()
#terminates command with null
ser.write(command + '\0')
#reads data per char
for c in ser.read():
#appends string
dat += c
#terminates at null char
if c == '\0':
print(dat)
dat = ''
break
ser.close()
This RPi that receives command and then sends sensor data:
import serial
ser = serial.Serial(
'/dev/ttyAMA0' ,\
baudrate = 115200 ,\
bytesize = serial.EIGHTBITS ,\
timeout = 0)
dat = ''
sen1 = 'sen1\x00'
sen2 = 'sen2\x00'
com1 = 'hello'
com2 = 'this thing works!'
com3 = 'error!'
while True:
#reads data per char
for c in ser.read():
#appends string
dat += c
#terminates at null char
if c == '\0':
#decides which sensor to choose
if dat == sen1:
print(com1)
ser.write(com1 + '\0')
dat = ''
break
elif dat == sen2:
print(com2)
ser.write(com2 + '\0')
dat = ''
break
else:
print(com3)
ser.write(com3 + '\0')
dat = ''
ser.close()
The cause is most likely your zero timeout. You've set read() to non-blocking as a result, so your sender Pi's for loops will most likely read nothing (or only a byte) and will terminate before everything's arrived. Also iterating over ser.read() doesn't really make sense since it returns only a byte anyway by default.
Increase timeout to some non-zero value.
ser = serial.Serial(
'/dev/ttyAMA0' ,\
baudrate = 115200 ,\
bytesize = serial.EIGHTBITS ,\
timeout = 0.1)
Assuming you want the response to a command received, before another command is sent, this should work for the sender:
while True:
#asks user for input
command = raw_input()
#terminates command with null
ser.write(command + '\0')
dat = []
lastRead = time.time()
while time.time() - lastRead < 0.1:
while ser.inWaiting() > 0:
dat.append(ser.read())
lastRead = time.time()
if dat and (dat[-1] == '\0'):
print(''.join(dat[:-1]))
If 100ms or more passes before another byte is available, the while loop breaks and the last received byte is checked to know if its a null byte. Something similar should work for your receiver:
while True:
dat = []
lastRead = time.time()
while time.time() - lastRead < 0.1:
while ser.inWaiting() > 0:
dat.append(ser.read())
lastRead = time.time()
dat = ''.join(dat)
# begin your comparisons here

How to write on serial port in python that ttyUSB0 will be interpreted commands?

I have raspberry PI B+ with connected Telegesis ZigBee module(ETRX3 USB sticks) via USB. Using commands:
debian:~# stty -F /dev/ttyUSB0 -raw ispeed 19200 ospeed 19200
debian:~# cat < /dev/ttyUSB0 &
debian:~# echo "ATI" > /dev/ttyUSB0
the ZigBee module executed ATI command and I can see the correct output:
Telegesis ETRX357
R308C
OK
The same thing I want to do with python script. I was written python script with code:
#!/usr/bin/env python
# based on tutorials:
# http://www.roman10.net/serial-port-communication-in-python/
# http://www.brettdangerfield.com/post/raspberrypi_tempature_monitor_project/
import serial, time
SERIALPORT = "/dev/ttyUSB0"
BAUDRATE = 19200
ser = serial.Serial(SERIALPORT, BAUDRATE)
ser.bytesize = serial.EIGHTBITS #number of bits per bytes
ser.parity = serial.PARITY_NONE #set parity check: no parity
ser.stopbits = serial.STOPBITS_ONE #number of stop bits
#ser.timeout = None #block read
#ser.timeout = 0 #non-block read
ser.timeout = 2 #timeout block read
ser.xonxoff = False #disable software flow control
ser.rtscts = False #disable hardware (RTS/CTS) flow control
ser.dsrdtr = False #disable hardware (DSR/DTR) flow control
ser.writeTimeout = 0 #timeout for write
print 'Starting Up Serial Monitor'
try:
ser.open()
except Exception, e:
print "error open serial port: " + str(e)
exit()
if ser.isOpen():
try:
ser.flushInput() #flush input buffer, discarding all its contents
ser.flushOutput()#flush output buffer, aborting current output
ser.write("ATI")
print("write data: ATI")
time.sleep(0.5)
numberOfLine = 0
while True:
response = ser.readline()
print("read data: " + response)
numberOfLine = numberOfLine + 1
if (numberOfLine >= 5):
break
ser.close()
except Exception, e:
print "error communicating...: " + str(e)
else:
print "cannot open serial port "
and get results as on the screen
ATI
but I want to command be execute by ZigBee module, as like in shell commands. What am I doing wrong?
you need to append an end-of-line to your write()
ser.write("ATI\r\n")
you should change the timeout to:
ser.timeout = None
Otherwise readline() will return after 2 seconds, even if nothing has been read.

How to read a string of integers received on python from serial arduino

I'm sending a list of values (e.g. 80,539,345,677) from Arduino to a Python app running on my RPi. I have not been successful in extracting the values and assigning them to respective variables or objects in the app.
Here's my code:
def read_values():
#if DEBUG:
print "reading arduino data"
ser = serial.Serial('/dev/ttyUSB0', 9600)
print "receiving arduino data"
ser_line = ser.readline()
print ser_line
ser.close()
ser_list = [int(x) for x in ser_line.split(',')]
ambientLight = ser_list[1]
print ambientLight
return ambientLight
What I'm getting from Python is:
reading arduino data
receiving arduino data
80,477,82,2
Traceback (most recent call last):
File "serialXivelyTest4c.py", line 77, in <module>
run()
File "serialXivelyTest4c.py", line 63, in run
ambientLight = read_values()
File "serialXivelyTest4c.py", line 27, in read_values
ser_list = [int(x) for x in ser_line.split(',')]
ValueError: invalid literal for int() with base 10: '8254\r80'
You can see that I'm getting values, but that they're being truncated. Can anyone please tell me where I'm going wrong here. Thanks so much.
I've never used an Arduino but here's how I read from serial with a different board. I used serial.
import streamUtils as su # see below
ser = su.connectPort("/dev/tty.SLAB_USBtoUART") # make sure you have the right port name
data = ""
while True:
try:
data = data + ser.read(1) # read one, blocking
time.sleep(1) # give it time to put more in waiting
n = ser.inWaiting() # look if there is more
if n:
data = data + ser.read(n) # get as much as possible
# I needed to save the data until I had complete
# output.
if data:
# make sure you have the whole line and format
else:
break
except serial.SerialException:
sys.stderr.write("Waiting for %s to be available" % (ser.name))
sys.exit(1)
sys.stderr.write("Closing port\n")
ser.close()
Here's the streamUtils.connectPort():
import serial
def connectPort(portname):
# connect to serial port
ser = serial.Serial()
ser.port = portname
ser.baudrate = 9600
ser.parity = serial.PARITY_NONE
ser.stopbits = serial.STOPBITS_ONE
ser.bytesize = serial.EIGHTBITS
ser.timeout = 15 # need some value for timeout so the read will end
try:
ser.open()
except serial.SerialException:
sys.stderr.write("Could not open serial port %s\n" % (ser.name))
sys.exit(1)
return (ser)

Categories

Resources