Interpret serialdata in python - python

I'm currently struggling with an issue. I have an arduino sending serialdata to my raspberry pi. The raspberry pi reads the data and stores it in a database. What i'm struggling with is to get data in the correct order. If i start the script at the correct time, the values get read properly. If i don't they get mixed up.
I have a headerByte sent from the arduino, this value is 999 and it is the first value to be sent each time. Is there a way in python to make 999 the marker for the beginning of every read? My variables will never exceed 999 so this will not be a problem.
Python code:
import serial
import time
values = []
serialArduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1)
voltageRead = serialArduino.readline()
currentRead = serialArduino.readline()
while True:
voltageRead = serialArduino.readline()
currentRead = serialArduino.readline()
print"V=", voltageRead, "A=", currentRead
Arduino Code:
void loop() {
float voltageRead = analogRead(A0);
float ampsRead = analogRead(A1);
float calculatedVoltage = voltageRead / 103;
float calculatedCurrent = ampsRead / 1;
int headerByte = 999;
Serial.println(headerByte);
Serial.println(calculatedVoltage);
Serial.println(calculatedCurrent);
delay(1000);
}

Your method isn't particularly efficient; you could send everything as a struct from the Arduino (header + data) and parse it on the RPi side with the struct module though your way does have the advantage of simplicity. But, if 999 is the highest value you expect in your readings, then it makes more sense to use a number greater than 999 like 1000. And 999 isn't really a byte.
That said, if "1000" is your header, you can simply check for the header's presence like this:
HEADER = "1000"
serialArduino = serial.Serial('/dev/ttyACM0', baudrate=9600, timeout=1)
while True:
if serialArduino.readline().rstrip() == HEADER: # check for header
voltageRead = serialArduino.readline() # read two lines
currentRead = serialArduino.readline()
print"V=", voltageRead, "A=", currentRead

Related

Sending multiple sensor data from arduino to python,any idea?

So I have this problem,I'm trying to send sensor data from arduino to python through serial communication.
But the output is a kind of wierd.
Does anyone have an idea on this?
Arduino code: to send sensor data
void setup(){
Serial.begin(9600);
}
void loop(){
int sensor1 = 20;
int sensor2 = 40;
int sensor3 = 60;
Serial.write(sensor1);
}
python code: to receive sent data from arduino
import serial,time
ser = serial.Serial("/dev/ttyACM1",9600,timeout=1)
while True:
data = ser.read()
time.sleep(1)
print("data:",data)
output :
data: b'\x14'
target :
data: 20
second target : sending multiple sensor data in a single serial.write().
data: 20 40 60
By using Serial.write() on the arduino side, you are sending the sensor integers as single byte value characters, (as mentioned here in the reference) but on the receiving side seem to be expecting whole lines of input (readline()). The value printed, b'\x14' (hexadecimal 14) is decimal 20, so the transmission was actually correct. You can solve your problem by sending actual text integers from the arduino with:
Serial.println(sensor1);

how to read multiple values from com port using pyserial with python?

I have an STM32 connected to a thermal sensor which indicate the temperature of the room and i worte this program to read this temperatur from my com port. Now i need a program to read multiple value from my com port.
thank you for helping me to solve this problem.
import serial
serport = 'COM3'
serbaudrate = 38400
ser = serial.Serial(port = serport, baudrate = serbaudrate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=2)
try:
ser.isOpen()
except:
print("Error")
exit()
if ser.isOpen():
try:
while 1:
if ser.inWaiting() > 0:
#print(ser.readline())
response = ser.readline()
print(response.decode("utf-8"))
else:
ser.write(b"1")
except Exception as e:
print(e)
#Tarmo thank you for answering my question. This is the code i wrote for programming th microcontroller:
while (1)
{
// Test: Set GPIO pin high
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
// Get ADC value
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
raw = HAL_ADC_GetValue(&hadc1);
raw = ((raw*0.000244*3.3) - 0.25)/0.028;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
// Convert to string and print
sprintf(msg, "%hu\r\n", raw);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Pretend we have to do something else for a while
HAL_Delay(100);
}
in this case i am reading just one value because the thermal sensor gives only one value. if i have more than one value how can i delimit them with a semicolon?
If you've already gone the way of sending a numeric value as text, you can extend that. Assuming you want to send 3 integer values at the same time, just delimit them with a semicolon. E.g. 123;456;789\n.
Your microcontroller should then output data in this format and your Python program can read the entire line just like it does now. The you can parse this line into individual values using regex:
import re
...
response = ser.readline()
needles = re.match("(\d+);(\d+);(\d+)", response)
if needles:
print("Got: {} {} {}".format(needles[0], needles[1], needles[2]))
Let's assume you have 3 values from the ADC, in the variables raw1, raw2, and raw3. Then you can use sprintf() to format a message with all of them, and use Tarmo's suggestion to read them.
sprintf(msg, "%hu;%hu;%hu\r\n", raw1, raw2, raw3);
Please provide enough memory in the variable msg.

How to send float values from Python to Arduino LCD?

My classmate and I have been working on this project based on this Instructables article https://www.instructables.com/id/Building-a-Simple-Pendulum-and-Measuring-Motion-Wi/, our idea is to make a pendulum, calculate the g force (from the pendulum's period) and then show its value on a LCD we got connected to the Arduino. We got the code up and running (it calculates the period), and we understood that the Arduino has to do some type of conversion (utf-8) to pass the values it gets from the potentiometer to Python. However when we try to send the value we get from calculating the period of the graph back to the arduino and show it on the LCD, it shows 634 or other similiar values, we tried to instead of the decode it does initially, go the other way around with encode, but it won't work. We can't check the value it is getting from the serial, because the serial monitor simply doesn't open while the python script is running. What is the most pratical way we can use to "transfer" floats calculated in a Python script to the Arduino, so that we can calculate g and show it on the screen. Many forums advice to instead of transferring the floats, convert them to strings since it would be easy for the arduino to receive, but we aren't sure that would even work. I'm sure this is a simple question, but we just can't seem to get it. If you find anything else wrong with the code please let me know, we know it's a bit sketchy. Thanks.
Python code:
arduino = serial.Serial('COM3', 115200, timeout=.1) #Open connection to Arduino
samples = 200 #We will take this many readings
angle_data = np.zeros(samples) #Creates a vector for our angle data
time_data = np.zeros(samples) #Creates a vector of same length for time
i = 0;
calibrate = 123 #Value to zero potentiometer reading when pendulum is motionless, read from Arduino
while i!=samples:
data = arduino.readline()[0:-2].decode('utf-8')
if data:
angle_data[i] = (float(data) - calibrate)*math.pi/180
time_data[i] = time.perf_counter()
print(angle_data[i])
i = i + 1
min = np.min(angle_data)
print (min)
min_pos, = np.where(angle_data == min)
min_x = time_data[min_pos]
print (min_x)
nos_left = int(min_pos)
max = 0;
for i in range(nos_left,200):
if angle_data[i] > max: max = angle_data[i]
print (max)
max_pos, = np.where(angle_data == max)
max_x = time_data[max_pos]
print (max_x)
period = (max_x - min_x) * 2
print (period)
gforce = (0.165 * 4 * (math.pi) * (math.pi)) / ((period) * (period))
print (gforce)
value_g = arduino.write(gforce)
plt.plot(time_data,angle_data,'ro')
plt.axis([0,time_data[samples-1],-math.pi,math.pi])
plt.xlabel("Time (seconds)")
plt.ylabel("Angle (Radians)")
plt.title("Pendulum Motion - Measured with Arduino and potentiometer")
plt.show()
arduino.close()
Arduino code
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int period = 0;
void setup() {
lcd.begin(16, 2);
Serial.begin(115200); // use the same baud-rate as the python side
pinMode(A0,INPUT);
lcd.print(" Pendulo ");
int gforce = 0;
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
// print the number of seconds since reset:
int degrees;
degrees = getDegree();
Serial.println(degrees);
Serial.println("\n");
delay(50);
if (Serial.available() > 0) {
// read the incoming byte:
gforce = Serial.read();
Serial.print("I received: ");
Serial.println(gforce, DEC);
}
lcd.setCursor(0, 1);
lcd.print(gforce);
}
int getDegree()
{
int sensor_value = analogRead(A0);
float voltage;
voltage = (float)sensor_value*5/1023;
float degrees = (voltage*300)/5;
return degrees;
}
This appears to be a good case for the Arduino Serial's parseFloat() method:
if (Serial.available() > 0) {
/* instead of Serial.read(), use: */
gforce = Serial.parseFloat();
Serial.print("I received: ");
Serial.println(gforce, DEC);
}
Essentially, it pulls out anything that looks like a float within the received serial data, even if it's mixed with other non-numerical characters.
It also works with Software Serial.

As I can distinguish different data from Serial?

I trying to read by serial differents values, but i dont know hoy to split that, because the two values are numbers but from different source
First i have a PICAXE sending converted data by ADC of light sensor by serial to python.
Second i have a PICAXE sending data of temperature sensor by serial to python.
Light code PICAXE
symbol puerto = B.5
main: readadc10 puerto,w1 ; read value into w1
sertxd(#w1,cr,lf)
goto main ; loop back to start
Temp code PICAXE
symbol temp = B.4
readtemp temp, w0 ; read value into w1
debug
sertxd(#w0,cr,lf)
goto main
Python code
import pygame
import sys, serial
from pygame.locals import *
ser = serial.Serial()
ser.port = 3
ser.baudrate = 4800
while True:
datos = ser.readline()
grados = float(datos)
print grados
The problem is that picaxe send simultaneus data from light and temp, but when python receive data, i dont know how to recognized each data.
Anyone can help me??
Thank!
If you have a temperature reading and a light level reading to send at the same time, you could put them on one line separated by a space.
PICAXE:
sertxd(#w0," ",#w1,cr,lf)
Python:
readings = ser.readline()
[reading1, reading2] = readings.split()
temperature = float(reading1)
lightlevel = float(reading2)
If the two types of reading are produced irregularly, you could transmit a character before each one to identify what type it is.
PICAXE:
sertxd("T ",#w0,cr,lf)
...
sertxd("L ",#w1,cr,lf)
Python:
reading = ser.readline()
[readingtype, readingvalue] = reading.split()
if readingtype == "T":
temperature = float(readingvalue)
elif readingtype == "L":
lightlevel = float(readingvalue)

Read latest character sent from Arduino in Python

I'm a beginner in both Arduino and Python, and I have an idea but I can't get it to work. Basically, when in Arduino a button is pressed, it sends "4" through the serial port. What I want in Python is as soon as it reads a 4, it should do something. This is what I got so far:
import serial
ser = serial.Serial('/dev/tty.usbserial-A900frF6', 9600)
var = 1
while var == 1:
if ser.inWaiting() > 0:
ser.readline(1)
print "hello"
But obviously this prints hello no matter what. What I would need is something like this:
import serial
ser = serial.Serial('/dev/tty.usbserial-A900frF6', 9600)
var = 1
while var == 1:
if ser.inWaiting() > 0:
ser.readline(1)
if last.read == "4":
print "hello"
But how can I define last.read?
I don't know a good way of synchronising the comms with readLine since it's not a blocking call. You can use ser.read(numBytes) which is a blocking call. You will need to know how many bytes Arduino is sending though to decode the byte stream correctly. Here is a simple example that reads 8 bytes and unpacks them into 2 unsigned shorts and a long (the <HHL part) in Python
try:
data = [struct.unpack('<HHL', handle.read(8)) for i in range(PACKETS_PER_TRANSMIT)]
except OSError:
self.emit(SIGNAL("connectionLost()"))
self.connected = False
Here's a reference to the struct.unpack()
The Arduino code that goes with that. It reads two analog sensor values and the micro timestamp and sends them over the serial.
unsigned int SensA, SensB;
byte out_buffer[64];
unsigned int buffer_head = 0;
unsigned int buffer_size = 64;
SensA = analogRead(SENSOR_A);
SensB = analogRead(SENSOR_B);
micr = micros();
out_buffer[buffer_head++] = (SensA & 0xFF);
out_buffer[buffer_head++] = (SensA >> 8) & 0xFF;
out_buffer[buffer_head++] = (SensB & 0xFF);
out_buffer[buffer_head++] = (SensB >> 8) & 0xFF;
out_buffer[buffer_head++] = (micr & 0xFF);
out_buffer[buffer_head++] = (micr >> 8) & 0xFF;
out_buffer[buffer_head++] = (micr >> 16) & 0xFF;
out_buffer[buffer_head++] = (micr >> 24) & 0xFF;
Serial.write(out_buffer, buffer_size);
The Arduino playground and Processing Forums are good places to look around for this sort of code as well.
UPDATE
I think I might have misled you with readLine not blocking. Either way, the above code should work. I also found this other thread on SO regarding the same subject.
UPDATE You don't need to use the analog sensors, that's just what the project I did happened to be using, you are of course free to pass what ever values over the serial. So what the Arduino code is doing is it has a buffer of type byte where the output is being stored before being sent. The sensor values and micros are then written to the buffer and the buffer sent over the serial. The (SensA & 0xFF) is a bit mask operator that takes the bit pattern of the SensA value and masks it with the bit pattern of 0xFF or 255 in decimal. Essetianlly this takes the first 8 bits from the 16 bit value of SensA which is an Arduino short. the next line does the same thing but shifts the bits right by 8 positions, thus taking the last 8 bits.
You'll need to understand bit patterns, bit masking and bit shifting for this. Then the buffer is written to the serial.
The Python code in turn does reads the bits from the serial port 8 bits at a time. Have a look at the struct.unpack docs. The for comprehension is just there to allow sending more than one set of values. Because the Arduino board and the Python code are running out of sync I added that to be able to send more than one "lines" per transmit. You can just replace that with struct.unpack('<HHL',handle.read(8)). Remember that the ´handle.read()´ takes a number of bytes where as the Arduino send code is dealing with bits.
I think it might work with this modifications:
import serial
ser = serial.Serial('/dev/tty.usbserial-A900frF6', 9600)
var = 1
while var == 1:
if (ser.inWaiting() > 0):
ser.readline(1)
print "hello"

Categories