How to process a serial read value in Raspberry pi - python

I have been trying to have some serial communication between raspberry and my STM32 board (I use MBEDOS for the firmware).
Right now, I am able to do serial writing from my raspberry to the microcontroller, and succeed.
However, I wanted to try to write something from the microcontroller to the raspberry, and the raspberry should process it. But, it seems that it fails to do so.
The code of the raspberry is quite simple:
import time
import serial
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
while 1:
x=ser.readline()
if x[2] == "e":
break
print x
print("stop")
A little explanation to my code, what I wanted to do is when my microcontroller send an "e", it should break from the loop. I used x[2] because I noticed when we print the serial data, it will print:
b'eeeeeee\n'
hence,I decided to use x[2].
In the microcontroller part, I used:
if(butn == 1) {
// raspi.putc('e');
raspi.printf("eeeeeee");
swo.printf("e is printed");
}
where butn is the user button. I already tried using .putc('e') but it is the same as well.
How can I deal with this problem?
Thank you!!

The problem in your code is that Serial.readline() return a bytes object, not a string. That's why you see the b when it gets printed.
Now, indexing with bytes objects doesn't count the b and the ' that appear in its string
representation; so if you want the first character, you should use x[0]. However, when you use indexing in the bytes object you won't get a character, you will get the number representation of the particular byte you requested.
x = b'eeeee'
print x[0]
>>> 101
Unsurpisingly, 101 is the ascii for 'e'.
You need to cast x[0] to a character. The result would be:
while 1:
x=ser.readline()
if chr(x[0]) == "e":
break
print x

Another option is to write the following:
x = hex(int.from_bytes((ser.readline()), 'big'))
if x[2] == 'e':
break

Related

start reading incoming data from a serial port, using pyserial, when a specific character appears

I'm trying to read incoming data from a weight scale (Lexus Matrix One). I want the code to start reading the 8 characters after = appears.
The problem is that sometimes the code does that, and other times it starts reading the data at the middle of the measurement sent by the scale, making it impossible to read properly. I'm using the pyserial module on python 3 on windows.
import serial
ser=serial.Serial("COM4", baudrate=9600)
a=0
while a<10:
b=ser.read(8)
a=a+1
print(b)
the expected result is: b'= 0004.0'
but sometimes I get: b'4.0= 000'
I think we would need a little more information on the format of data coming from your weight scale to provide a complete answer. But your current code only reads the first 80 bytes from the stream, 8 bytes at a time.
If you want to read the next 8 bytes following any equals sign, you could try something like this:
import serial
ser = serial.Serial("COM4", baudrate=9600)
readings = []
done = False
while not done:
current_char = ser.read()
# check for equals sign
if current_char == b'=':
reading = ser.read(8)
readings.append(reading)
# this part will depend on your specific needs.
# in this example, we stop after 10 readings
# check for stopping condition and set done = True
if len(readings) >= 10:
done = True

Data saved to text file is inconsistent

My controller is receiving data from a radio module through a serial port, it's recording temperature and humidity to two decimal places every 1 second, using 'a' as a signal to time stamp it. For example:
a21.12 65.43
a21.13 65.40
Here is the code I'm using:
import serial
import datetime
connected = False
locations=['/dev/ttyUSB0','/dev/ttyUSB1','/dev/ttyUSB2','/dev/ttyUSB3']
for device in locations:
try:
print "Trying...",device
ser = serial.Serial(device, 9600)
break
except:
print "Failed to connect on",device
while not connected:
serin = ser.read()
connected = True
with open('tempdata.txt', 'w') as text_file:
while 1:
if ser.read() is 'a':
text_file.write(datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S'))
text_file.write(" ")
x = ser.read()
text_file.write(x)
text_file.flush()
ser.close()
When I check my text file afterwards the result seems to be different every time. If I let it run for just 2 or 3 seconds I sometimes get a correct result, sometimes I only get the humidity, sometimes I get the time stamp with a number that is half temperature, half humidity (like 2.16.3). If I let it run for more than a few seconds the file is just completely blank.
The basis for my code is from a question previously asked on here and it worked fine until I added the time stamp part. I tried changing the radio transfer rate from 9600 to 4800 but that just turned the numbers into garbage characters.
I'm running this on a Raspberry Pi 2 model B so I could be demanding too much from it in a short time.
You are calling read() twice and writing only the output of the second call. I don't imagine that is your intent.
You can change this section:
with open('tempdata.txt', 'a') as text_file:
while 1:
content = ser.read()
if content is 'a':
text_file.write(datetime.datetime.now().strftime('%d/%m/%Y %H:%M:%S'))
text_file.write(" ")
text_file.write(content)
text_file.flush()

sending and recieving through serial

I have got a simple program running in the uno that measures the distance using ping sensor and now i am trying to control some servos based on the distance in python but the conditional thingy is not working even in a simple code like this
import serial
data = serial.Serial('COM7',9600)
while(1):
if(data.inWaiting()>0):
dist = data.readline()
if(dist>100):
print("dist is greater than 100")
else:
print("this shit does not work")
It is always the if that works, I am a noob please help me!
Data from serial port type is str
You are trying to read the data and use if .... > 100 this will never work.
You need to read the data to a buffer and then check it, Also you need some sync frame to know you have got all the data(it's not a must but its much eaiser)
for example let say the read data is 100! and ! is your sync frame.
import serial
my_serial = serial.Serial('COM7',9600)
my_data = ""
while(1):
if(my_serial.inWaiting()>0):
my_data = my_serial.readline()
if '!' in my_data:
break
my_data = [:my_data.find("!")]
if int(my_data) > 100:
print("dist is greater than 100")
else:
print("this shit does not work")

Converting a bytearray from a serial port to a float

I am writing a python script that will communicate to a Fluke meter over a COM port. I am able to receive the data but want to parse it into a usable float. The code looks like this:
import serial
ser = serial.Serial('COM3', 115200, timeout=1)
#Decalring some variables
FlukeID = b'ID\r'
FlukeQM = b'QM\r'
#Requesting the meters ID to verify connection on terminal
ser.writelines(FlukeID)
line = ser.readline()
print(line)
#Declaring variables for my while loop
thermdata = 0
t=1
ser.writelines(FlukeQM)
thermdata = ser.readline()
while(t < 5):
ser.writelines(FlukeQM)
#thermdata = (thermdata + ser.readline()) /2
thermdata = ser.readline()
print(thermdata)
t+=1
The data returned by the device looks like this on the console:
8.597E3,OHM,NORMAL,NONE INCORRECT
EDIT: The data actually appears like this over the terminal:
b'0\r8.597E3,OHM,NORMAL,NONE\r'
I just want to be able to use the numerical value at the beginning so I can do some calculations over time. I also need to be able to use the scientific notion portion in my number as I will not know the range of my measurements before hand. I know there must be a simple way to do this and would greatly appreciate any help.
On a side note, I would also like to be able to graph these values or place them into some kind of .csv file. If you have any comments on where to look to learn how to do this also that would be great, but I am mostly concerned with the handling of the bytearray.
Use split() to break your string into the comma separated parts. Then the first part is the string '8.597E3', which you convert using the float() function.
s = '8.597E3,OHM,NORMAL,NONE'.split(',')
value = float(s[0])
How about something like:
def atof(text):
try:
return float(text)
except ValueError:
return text
thermdata = b'0\r8.597E3,OHM,NORMAL,NONE\r'
for line in thermdata.strip().split(b'\r'):
print(list(map(atof, line.split(b','))))
# [0.0]
# [8597.0, b'OHM', b'NORMAL', b'NONE']

python split string and pick substring

I am having a lot of trouble with the list returned by the split function in python. I am probably being incredibly dense.
My python code is as follows
str = "XXX:YYY:ZZZ"
var+=1
ins = str.split(':')
print ins
When the script runs it returns the following result
['XXX','YYY','ZZZ']
What i am struggling to do is pull out the string contained the second string in the list. I would have thought the following code at the end of the python code would work.
print ins[1]
but when i run it i get the following error
IndexError: list index out of range
Any help would be much appreciated
full code
import time
ser = serial.Serial("COM3", 9600)
print ser
time.sleep(3)
print "Sending serial data"
var = 0
while var<=10:
str = ser.readline()
print str
var+=1
ins = str.split(':')
print ins
print ins[0]
if (str.split(':')=='end\n'):
break
if(ser.isOpen()):
print "Serial connection is still open."
ser.close();
print "Serial connectionnow terminated."
This returns
Serial<id=0x2a7fc50, open=True>(port='COM3', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Sending serial data
Program Initiated
['Program Initiated\n']
Program Initiated
0:addsd:1
['0', 'addsd', '1\n']
0
1:addsd:2
['1', 'addsd', '2\n']
1
2:end:2
['2', 'end', '2\n']
2
Your code will not work in instances where the input you're analyzing has a length <= 1.
Try checking for that and handling it in your code.
One of the lines you are reading probably has a two '\n' characters in a row. When that string is read with readlines() and then spit it has no [1] index only a [0] index.
What output do you get for the program:
import serial // Or is serial a builtin for the version of python you are using?
print repr(serial.Serial("COM3", 9600))
Thanks,
Marlen

Categories