Reading integer from arduino using pyserial - python

I am sending integer value from arduino and reading it in Python using pyserial
The arduino code is:
Serial.write(integer)
And the pyserial is:
ser=serial.Serial ('com3',9600,timeout =1)
X=ser.read(1)
print(X)
But it doesn't print anything except blank spaces
Does anyone knows how to read this integer passed from arduino in Python?

You probably need to use a start bit.
The problem might be that the arduino has already written the integer by the time pyserial is running?
So write a character from pyserial to arduino to signal start like
ser=serial.Serial ('com3',9600,timeout =1)
ser.write(b'S')
X=ser.read(1)
print(X)
And write the integer from the arduino once you get this start bit.

That is the not the right way to read an Integer from Arduino. Integer is a 32-bit type while your serial port would be set to EIGHTBITS (Both in pyserial and Arduino. Correct me if I'm wrong) in byte size, therefore you have to write the Character version of the Integer from Arduino while transmitting it through a Serial Port because a Character takes only EIGHTBITS in size which is also the convenient way to do the stuff that you need to, very easily.
Long story short, convert your Integer into a String or a Character Array before transmitting. (Chances are there are inbuilt functions available for the conversion).
On a side note here is the correct python code that you'd prefer to use:
ser = serial.Serial(
port='COM3',
baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS
)
#RxTx
ser.isOpen()
while 1:
out = ''
while ser.inWaiting() > 0:
out += ser.read(1)
if out != '':
print ">>Received String: %s" % out

An easy program which I tested:
Arduino:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
void loop() {
int f1=123;
// print out the value you read:
Serial.println(f1);
delay(1000);
}
Python:
import serial
ser = serial.Serial()
ser.baudrate = 9600
ser.port = 'COM5'
ser.open()
while True:
h1=ser.readline()
if h1:
g3=int(h1); #if you want to convert to float you can use "float" instead of "int"
g3=g3+5;
print(g3)

Related

Python not printing same as Arduino Serial Monitor

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.

How to write and read binary (not ASCII encoded) to Arduino with pyserial

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: "))])

Processing raw data read from serial port with Python serial library?

I am not a Python programmer but am rather electronic circuit designer, however this time I must process some raw data sent by a microcontroller via RS232 port towards Python script (which is called by PHP script).
I've spent quite a few hours trying to determine the best ways of reading raw bytes from serial (RS232) port using Python and I did get the results - but I would like if someone could clarify certain inconsistencies I noticed during researching and here they are:
1:
I can see a lot of people who asked similar question had been asked whether they are using serial or pySerial module and how did they install the serial library. I can only say I don't really know which module I am using as the module worked out-of-the-box. Somewhere I read serial and pySerial is the same thing but I cannot find if that is true. All I know is I am using Python 2.7.9 with Raspbian OS.
2:
I've read there are read() and readline() methods for reading from the serial port but in the pySerial API docs there is no mention of the readline() method. Futhermore, I discovered the 'number of bytes to read' argument can be passed to readline() method as well as to the read() method (and works the same way, limiting the number of bytes to be read) but I cannot find that to be documented.
3:
When searching for how to determine if all of the data from the RS232 buffer has been read I have here found the following code:
read_byte = ser.read()
while read_byte is not None:
read_byte = ser.read()
print '%x' % ord(read_byte)
but that results with the:
Traceback (most recent call last):
File "./testread.py", line 53, in <module>
read_all()
File "./testread.py", line 32, in read_all
print '%x' % ord(read_byte)
TypeError: ord() expected a character, but string of length 0 found
upon reading the last byte from the buffer and I was able to detect the empty buffer only with the following code:
while True:
c = rs232.read()
if len(c) == 0:
break
print int(c.encode("hex"), 16), " ",
so I am not sure if the code that didn't work for me is for some serial library that is other than mine. My code for openinig port is BTW:
rs232 = serial.Serial(
port = '/dev/ttyUSB0',
baudrate = 2400,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
4:
The data I am receiving from µC is in the format:
0x16 0x02 0x0b 0xc9 ... 0x0d 0x0a
That is some raw bytes + \r\n. Since 'raw bytes' can contain 0x00, can someone confirm that is not a problem regarding reading the bytes into the Python string variable? As I understand that should work well but am not 100% sure.
PySerial works for me although haven't used it on a Pi.
3: Read() returns a string - this will be zero length if no data is read, so your later version is correct. As a string is not a character, you should use e.g. ord(read_byte[0]) to print the number corresponding to the first character (if the length of the string >0)
Your function:
while True:
c = rs232.read()
if len(c) == 0:
break
print int(c.encode("hex"), 16), " ",
Needs something adding to accumulate the data read, otherwise it is thrown away
rcvd = ""
while True:
c = rs232.read()
if len(c) == 0:
break
rcvd += c
for ch in c:
print ord(ch), " ",
4:
Yes you can receive and put nul (0x00) bytes in a string. For example:
a="\x00"
print len(a)
will print length 1

Sending a String from Raspberry Pi to Arduino via XBee modules

[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.

Weird Output Value: b'[value]\r\n' - Python Serial Read

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.

Categories

Resources