I am trying to read some float values from the flash memory of an ESP32. They are stored one per line. I want to plot these values in Python, but the readings from its serial monitor vs Arduino's are all different.
Arduino sample code:
while(file.available()){
num = file.parseFloat();
str = String(num, 3);
Serial.println(str);
//Serial.println(num);
}
Serial.println("\nDone");
Python code:
while(1):
line = ser.readline() # read a byte string
if line:
string = line.decode() # convert the byte string to a unicode string
if ("Done" in string):
break
#num = float(string) # convert the unicode string to a float
print(string)
#print(num)
I tried both printing the float directly in Arduino as well as converting it to string, both work well in Arduino's Serial Monitor, neither works for the Python reading.
In the photo you can see some values are just thrash (ex -0.50.000). Any ideas for a fix? Thank you!
In the end I solved this by changing the baudrate down from 115200 to 9600.
Related
I need to make a Raspberry Pi communicate with an Arduino. I will only need values between 0 and 180, and this is within the range of a single byte so I want to only send the value in binary, and not send it with ASCII encoding for faster transfer (i.e.: if I want to write a "123" to the Arduino, I want 0x7B to be sent, and not the ASCII codes for 1, then 2, then 3 (0x31,0x32, 0x33).
In my testing I have been trying to write a Python program that will take an integer within that range and then send it over serial in binary.
Here is a test I was trying. I want to write a binary number to the Arduino, and then have the Arduino print out the value it received.
Python code:
USB_PORT = "/dev/ttyUSB0" # Arduino Uno WiFi Rev2
import serial
try:
usb = serial.Serial(USB_PORT, 9600, timeout=2)
except:
print("ERROR - Could not open USB serial port. Please check your port name and permissions.")
print("Exiting program.")
exit()
while True:
command = int(input("Enter command: "))
usb.write(command)
value = (usb.readline())
print("You sent:", value)
And here is the Arduino code
byte command;
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (Serial.available() > 0)
{
command = Serial.read();
Serial.print(command);
}
}
All this gives me is this:
Enter command: 1
You sent: b'0'
Enter command: 4
You sent: b'0000'
usb.write(command) expects command to be of type bytes not int.
It seems the write method internally calls bytes(), since it sends the number of zero bytes that you called it with.
Calling bytes() with an integer, creates a zero filled byte array, with the specified number of zeroes.
If you want to send a single byte, you need to call it with a list with a single element.
You should do:
command = bytes([int(input("Enter command: "))])
Every one second, Arduino prints (in serial) 'current time in milliseconds and Hello world'. On serial monitor, the output looks fine.
But in pySerial, sometimes there is line break at the middle of string.
313113 Hel
lo world
314114 Hello world
315114 Hello world
My python code is as:
import serial
import time
ser = serial.Serial(port='COM4',
baudrate=115200,
timeout=0)
while True:
str = ser.readline() # read complete line
str = str.decode() # decode byte str into Unicode
str = str.rstrip()
if str != "":
print(str)
time.sleep(0.01)
What am I doing wrong?
My configuration:
Python 3.7
pySerial 3.4
Board Arduino Mega
The problem definitely seems to be caused by very fast reads where the data is read when the serial output from the Arduino hasn't finished sending full data.
Now with this fix, the pySerial will be able to receive the complete data and no data is missed. The main benefit is that it can be used for any type of data length and the sleep time is quite low.
I have fixed this issue with code below.
# This code receives data from serial device and makes sure
# that full data is received.
# In this case, the serial data always terminates with \n.
# If data received during a single read is incomplete, it re-reads
# and appends the data till the complete data is achieved.
import serial
import time
ser = serial.Serial(port='COM4',
baudrate=115200,
timeout=0)
print("connected to: " + ser.portstr)
while True: # runs this loop forever
time.sleep(.001) # delay of 1ms
val = ser.readline() # read complete line from serial output
while not '\\n'in str(val): # check if full data is received.
# This loop is entered only if serial read value doesn't contain \n
# which indicates end of a sentence.
# str(val) - val is byte where string operation to check `\\n`
# can't be performed
time.sleep(.001) # delay of 1ms
temp = ser.readline() # check for serial output.
if not not temp.decode(): # if temp is not empty.
val = (val.decode()+temp.decode()).encode()
# requrired to decode, sum, then encode because
# long values might require multiple passes
val = val.decode() # decoding from bytes
val = val.strip() # stripping leading and trailing spaces.
print(val)
[SOLVED] the problem was with the USB-TTL PL2303 chip I was using to interface the XBee module with the Pi. It was creating the problem. It's drivers were not properly supported by the RPi2.
I am trying to send a string (possibly a number) from a python script on my Raspberry Pi2 through a XBee module connected to it, to an Arduino Uno. The data sent is being misinterpreted at the Arduino end. When I use the terminal on X-CTU and send strings through that it shows up correctly on the serial monitor of Arduino IDE.
Here is the Python Code I am using
import time
import serial
ser = serial.Serial("/dev/ttyUSB0",9600)
ser.isOpen()
x= '4'
ser.write(bytes(x, "ascii")) #writing as bytes
time.sleep(2)
ser.close()
Here is the Arduino code I used
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
void setup()
{
// Open serial communications
Serial.begin(9600);
// set the data rate for the SoftwareSerial port
mySerial.begin(9600);
}
void loop() // run over and over
{
int x;
if (mySerial.available())
{
x = char(mySerial.read()) - '0';
//reading data value from Software Serial port
//converting ASCII to int
//and storing it as x
Serial.print(x);
}
My guess, if you are already typecasting to char, you don't need to subtract '0', because then Serial.print() will interpret that value as an ascii code and print the corrosponding character. So just try, char(Serial.read()) and print it.
Well, you know the code on the receiving end is working correctly because you can test it by sending data with the X-CTU terminal. How are you sending from X-CTU? Just typing the number 4 in the window, or sending it as a hex value (0x04)?
What happens when you have the Python script send to the X-CTU terminal? What do you see? What if you just dump the value of the byte read on the Arduino side before doing any conversions to it? Compare what X-CTU sends to what Python sends.
Instead of using bytes() to convert your Python string, you could just assign x = b'4' and see what that does.
I have my Arduino connected to an OLIMEX-SHIELD-EKG-EMG, and there is this Arduino example for EKG capture and interface to Electric Guru for OLIMEXINO-328/Arduino boards.
I ran the Arduino software and then I made sure it's working using the Guru and it's all fine.
I tried to read the data from the serial port using Python and saving it to a text file, so I can use it for other stuff (Windows commands in my case). When I open the file the data is all garbage.
So what did I do wrong and how can I fix it?
Thank you all in advance.
This is my code:
import serial
from time import sleep
f = open("data2.txt", "w")
port = "\\.\COM4"
ser = serial.Serial(port, 38400, timeout=0)
while True:
data = ser.read(9999)
if len(data) > 0:
print ('Got:',data)
sleep(0.5)
print ('not blocked')
f.write( str(data) + "\n\n" )
f.close()
ser.close()
And this the data I get:
b'\x05\r\x1c\x1e\x10K\x12\x8a\x01\x0e\x14&\x1b\x1bW\x12\x80\x00\x7f\x11 \rZC:\x82\x12_.\x1a?\x10^\x12\x8a\x1a__\\x01:Q\x12\x8a\x15\x01\x1a\x1f\x1c6L\x1a\x82\x00t\x1e\x0c\x18\x19s:\x8a\x05]-\x01\x0e[G\x12\x8a\x15_\x0b9\x17>R\x12\x8a\x08__\x7f\x08:S\x1a\x82\x01\r\x18\x1d4\x10j:\x8a\n_0\x06\x10\x12Y\x10\x8a\nRH\x1c\x0bw#\x12\x80\x08\x7f\x0f7\x1f\x1bT:\x8a+\x7fU%\x18P:\x8a\x00\x0b}\x006\x11K\x12\x8a\x00Z\x19&\x16>\x1a\x82\x01\x02D\x1d\nYb:\x8a*$\x15\x12\x1cX:\x8a\x1b\x7f[\x06\x1bP\x12\x8a+\x0c\x1f?\x1b-F\x1a\x82\x05Z\x13\x0f7\x14}:\x8a\nUb\x19\n7^\x10\x8a\x15_\n\x14\x132_\x12\x80\x1d\x7f_x\x05\x15N:\x8a\x05<`\x025\x11I:\x8a\x0bZ1\x0f4\x18S\x12\x8a\x0bQK8\x0bvB\x1a\x82\x11\x7f\x0e\x1a\x18\x14q\x1a\x82\x07\xc1\xe1\x05\x14\x13q:\x8a+Sb\x02\x1b\x0cM\x12\x8a\x01\x1f\x1b%\x15\x15]\x1a\x82\x01B\x01.(\x1d\x7f\x1a\x82\xc2\xc1\x05,9\x1at\x10\x8a,__X\x024N\x1a\x80(xD!\x15\x10I\x1a\x82\x08|.
That looks to me like binary data. So i guess either each 16 or each 32 bit are a single numeric. You would have to cast the data you have and then format it into a text file.
It looks like ser.read() returns bytes not string. You need to decode that to if you want string. Use data.decode(your_encoding). You need to know the encoding.
For more see docs.
Decoding in UTF-16 could be promising...
data=b'\x05\r\x1c\x1e\x10K\x12\x8a\x01\x0e\x14&\x1b\x1bW\x12\x80\x00\x7f\x11 \rZC:\x82\x12_.\x1a?\x10^\x12\x8a\x1a__\\x01:Q\x12\x8a\x15\x01\x1a\x1f\x1c6L\x1a\x82\x00t\x1e\x0c\x18\x19s:\x8a\x05]-\x01\x0e[G\x12\x8a\x15_\x0b9\x17>R\x12\x8a\x08__\x7f\x08:S\x1a\x82\x01\r\x18\x1d4\x10j:\x8a\n_0\x06\x10\x12Y\x10\x8a\nRH\x1c\x0bw#\x12\x80\x08\x7f\x0f7\x1f\x1bT:\x8a+\x7fU%\x18P:\x8a\x00\x0b}\x006\x11K\x12\x8a\x00Z\x19&\x16>\x1a\x82\x01\x02D\x1d\nYb:\x8a*$\x15\x12\x1cX:\x8a\x1b\x7f[\x06\x1bP\x12\x8a+\x0c\x1f?\x1b-F\x1a\x82\x05Z\x13\x0f7\x14}:\x8a\nUb\x19\n7^\x10\x8a\x15_\n\x14\x132_\x12\x80\x1d\x7f_x\x05\x15N:\x8a\x05<`\x025\x11I:\x8a\x0bZ1\x0f4\x18S\x12\x8a\x0bQK8\x0bvB\x1a\x82\x11\x7f\x0e\x1a\x18\x14q\x1a\x82\x07\xc1\xe1\x05\x14\x13q:\x8a+Sb\x02\x1b\x0cM\x12\x8a\x01\x1f\x1b%\x15\x15]\x1a\x82\x01B\x01.(\x1d\x7f\x1a\x82\xc2\xc1\x05,9\x1at\x10\x8a,__X\x024N\x1a\x80(xD!\x15\x10I\x1a\x82\x08|.'
data.decode('UTF-16')
u'\u0d05\u1e1c\u4b10\u8a12\u0e01\u2614\u1b1b\u1257\x80\u117f\u0d20\u435a\u823a\u5f12\u1a2e\u103f\u125e\u1a8a\u5f5f\u785c\u3130\u513a\u8a12\u0115\u1f1a\u361c\u1a4c\x82\u1e74\u180c\u7319\u8a3a\u5d05\u012d\u5b0e\u1247\u158a\u0b5f\u1739\u523e\u8a12\u5f08\u7f5f\u3a08\u1a53\u0182\u180d\u341d\u6a10\u8a3a\u5f0a\u0630\u1210\u1059\u0a8a\u4852\u0b1c\u4077\u8012\u7f08\u370f\u1b1f\u3a54\u2b8a\u557f\u1825\u3a50\x8a\u7d0b\u3600\u4b11\u8a12\u5a00\u2619\u3e16\u821a\u0201\u1d44\u590a\u3a62\u2a8a\u1524\u1c12\u3a58\u1b8a\u5b7f\u1b06\u1250\u2b8a\u1f0c\u1b3f\u462d\u821a\u5a05\u0f13\u1437\u3a7d\u0a8a\u6255\u0a19\u5e37\u8a10\u5f15\u140a\u3213\u125f\u1d80\u5f7f\u0578\u4e15\u8a3a\u3c05\u0260\u1135\u3a49\u0b8a\u315a\u340f\u5318\u8a12\u510b\u384b\u760b\u1a42\u1182\u0e7f\u181a\u7114\u821a\uc107\u05e1\u1314\u3a71\u2b8a\u6253\u1b02\u4d0c\u8a12\u1f01\u251b\u1515\u1a5d\u0182\u0142\u282e\u7f1d\u821a\uc1c2\u2c05\u1a39\u1074\u2c8a\u5f5f\u0258\u4e34\u801a\u7828\u2144\u1015\u1a49\u0882\u2e7c'
I'm reading a value through Python from the serial port of a sensor of Arduino.
My code(Python):
arduino = serial.Serial(2, 9600, timeout=1)
print("Message from arduino: ")
while True:
msg = arduino.readline()
print(msg)
I don't know why the output result is something like b'[sensor-value]\r\n'.
So, I get something like b'758\r\n' b'534\r\n' b'845\r\n' etc (regarding to sensor change value).
How I convert this?
You need to decode it.
print(msg.decode('utf-8'))
Please check Lexical Analysis on Python 3 documentation to see what string prefixes means
Encountered a similar problem with a Raspberry Pi Pico where I needed to both decode and get rid of the extra characters. That can all be achieved with a one-liner. This relies on the pySerial package.
msg = ser.readline().decode('utf-8').rstrip()
For the above example, serial.Serial has been named arduino instead of ser, so the solution there would simply be:
msg = arduino.readline().decode('utf-8').rstrip()
Found the hint in this blog post.