Issues with Python readline() when reading data from Arduino - python

I am attempting to use pyserial to read the data from an arduino on Windows.
import serial
device = 'COM3'
baud = 9600
with serial.Serial(device,baud, timeout = 0) as serialPort:
while True:
line = serialPort.readline()
line = line.decode("utf-8")
if line:
print(line)
void setup() {
Serial.begin(9600);
}
void loop() {
int x = 12;
int y = 34;
int z = 56;
Serial.print(x);
Serial.print(',');
Serial.print(y);
Serial.print(',');
Serial.println(z);
}
The arduino Serial monitor is outputting exactly what I expect.
12,34,56
12,34,56
12,34,56
The python script on the other hand is outputting:
1
2,34
,56
12,
34,5
6
1
2,34
,56
12,
34,5
6
I have tried delaying the output from the Arduino, I have tried making a buffer in the arduino code and only output the data when the buffer was full, thinking maybe python would have time to read it correctly.
I have see numerous people on this site and others make similar code and suggest it works fine, I however cannot get coherent data from python. Anyone know my issue?

Try to do like this
Python
import serial
device = 'COM3'
baud = 9600
with serial.Serial(device, baud) as port:
while True:
print(port.readline().decode("utf-8"))
Arduino
void setup() {
Serial.begin(9600);
}
void loop() {
int x = 12;
int y = 34;
int z = 56;
Serial.println(x + ',' + y + ',' + z);
}

Related

Sending Float Values from Python to Arduino - Data in buffer but no values read

I am trying to send float values from Python on Windows to an Arduino. The first problem I encounter is that I cannot view the serial monitor when I think I am sending data from my Python script. I have read online that this is becuase only one application can manage the port at once: https://forum.arduino.cc/t/serial-communication-only-working-when-serial-monitor-is-opened/601107/12
However I have seen examples where the user is viewing the serial monitor to see data coming in over serial from Python and serial.print outs from the Arduino. So I am unsure what is the case... not being able to view the serial monitor sure does make debugging this senario hard.
My Python code:
import struct
import serial
import time
print('test123')
x=0.8
y=0.2
ser = serial.Serial('COM5', 9600, timeout=1)
#print(ser)
time.sleep(3)
def sendmess():
bin = struct.pack('ff',x,y) #Pack float value into 4 bytes
data = ser.write(bin)
#print(bin)
#print(len(bin))
#print([ "0x%02x" % b for b in bin])
#ser.close()
while True:
sendmess()
My Arduino Code:
int d = 250;
float incomingByte = 1;
void setup() {
// initialize the serial communication:
Serial.begin(9600);
pinMode(2, OUTPUT);
}
void loop() {
digitalWrite(2, HIGH);
delay(d);
digitalWrite(2, LOW);
delay(d);
// reply only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
d = 1000;
float incomingByte = Serial.read();
// say what you got:
Serial.println(incomingByte);
}
else{
Serial.println(incomingByte);
d = 20;
}
}
I see the LED flash every second so I know the serial buffer is >0, but I cannot get any data out :(.
Thanks in advance!
Mark
I have tried examples online, but I never get any data to display in the serial monitor. Nor can I say have a pin turn HIGH when I think I am getting the data I think I have sent. But without the Serial Monitor how can I debug this?
Unfortunately, you aren't able to connect more than two devices to the serial connection. However, using Python you should be able to read a response from your arduino and then print that to the python Terminal (or a file) and take a look at that.
The easiest way to do that would be to use pySerial and either ser.read(4) to read back 4 bytes of your float or ser.readline() which will look for either a '\n' which you can add to your arduino code, or a timeout. Then just print it to the python terminal with print().
As for actually reading the float, Serial.read() will only read in the next byte in the buffer. Since a float is 4 bytes long, you need to either read the 4 bytes into an array or use Serial.parseFloat()
Python Code
import struct
import serial
import time
x=0.8
y=0.2
ser = serial.Serial('COM5', 9600, timeout=1)
#print(ser)
time.sleep(3)
def sendmess():
bin = str(x) + str(y) #Pack float value into 4 bytes
data = ser.write(bin.encode())
echo = ser.readline()
print("Echo: " + echo)
#ser.close()
while True:
sendmess()
Arduino Code:
int d = 250;
float X;
float Y;
char buffer[40];
void setup() {
// initialize the serial communication:
Serial.begin(9600);
pinMode(2, OUTPUT);
}
void loop() {
digitalWrite(2, HIGH);
delay(d);
digitalWrite(2, LOW);
delay(d);
// reply only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
d = 1000;
X = Serial.parseFloat();
Y = Serial.parseFloat();
// say what you got:
sprintf(buffer, "X: %f Y: %f", X, Y);
Serial.println(buffer);
}
else{
Serial.println(buffer);
d = 20;
}
}

How to send an int from Python to an Arduino in order to use it as an argument for the neopixel function setPixelcolor()?

I am trying to send an int number from Python to an Arduino using PySerial, using .write([data]) to send with Python and Serial.read() or Serial.readString() to recieve on the Arduino, then .setPixelColor() and .show() to light a LED on a matrix which position corresponds to the int sent by the arduino (I am using the Duinofun Neopixel Shield).
But It does not seem to work properly, and I can't use the Serial Monitor as I am sending my data as the port would be busy.
I have tried to input a number myself using Serial.readString() then converting the string to an int and finally putting in into my function that displays the LED.
It does work properly when I do this, but when I send some data over, all the previously lit LEDs suddenly switch off which can only be caused by a reset of the Arduino board as far as I know.
This is the python code, it simply sends an int chosen by the user
import serial
a = int(input('Enter pixel position : '))
ser = serial.Serial("COM16", 9600)
ser.write([a])
And this is the part of the Arduino program that reads the incoming data.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(40, 6, NEO_GRB + NEO_KHZ800);
void setup() {
// put your setup code here, to run once:
pixels.begin();
Serial.begin(9600);
}
void loop() {
String a = Serial.readString();
int b = a.toInt();
pixels.setPixelColor(b, 30,30,30);
pixels.show();
Serial.println(a);
delay(1000);
}
All the LED switch off when I send some data, except the first LED which position corresponds to a 0 used in the .setPixelColor() function.
Problem is, the LED should light to the corresponding int sent by Python (e.g light the fifth LED for an int of 4).
You don't need to send an int from your Python script. Just send a string and then convert it back to int on your Arduino. Also, you can verify the number simply on your Arduino code if the received value is valid.
Another problem with your Arduino code is you are not checking the Serial port availability which would return an empty string by Serial.readString().
A simple approach is shown below but you can extend it for other pixels.
Python script:
import serial
ser = serial.Serial("COM16", 9600)
while True:
input_value = input('Enter pixel position: ')
ser.write(input_value.encode())
Arduino code:
#define MIN_PIXEL_RANGE 0
#define MAX_PIXEL_RANGE 100
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(40, 6, NEO_GRB + NEO_KHZ800);
void setup()
{
// put your setup code here, to run once:
pixels.begin();
Serial.begin(9600);
}
void loop()
{
if (Serial.available())
{
String a = Serial.readString();
Serial.print("Received Value: ");
Serial.println(a);
int b = a.toInt();
if ((b >= MIN_PIXEL_RANGE) && (b <= MAX_PIXEL_RANGE))
{
pixels.setPixelColor(b, 30, 30, 30);
pixels.show();
delay(1000);
}
}
}
You can communicate between Ardinos and Python really easily and reliably if you use the pip-installable package pySerialTransfer. The package is non-blocking, easy to use, supports variable length packets, automatically parses packets, and uses CRC-8 for packet corruption detection.
Here's an example Python script:
from pySerialTransfer import pySerialTransfer as txfer
if __name__ == '__main__':
try:
link = txfer.SerialTransfer('COM13')
link.txBuff[0] = 'h'
link.txBuff[1] = 'i'
link.txBuff[2] = '\n'
link.send(3)
while not link.available():
if link.status < 0:
print('ERROR: {}'.format(link.status))
print('Response received:')
response = ''
for index in range(link.bytesRead):
response += chr(link.rxBuff[index])
print(response)
link.close()
except KeyboardInterrupt:
link.close()
Note that the Arduino will need to use the library SerialTransfer.h. You can install SerialTransfer.h using the Arduino IDE's Libraries Manager.
Here's an example Arduino sketch:
#include "SerialTransfer.h"
SerialTransfer myTransfer;
void setup()
{
Serial.begin(115200);
Serial1.begin(115200);
myTransfer.begin(Serial1);
}
void loop()
{
myTransfer.txBuff[0] = 'h';
myTransfer.txBuff[1] = 'i';
myTransfer.txBuff[2] = '\n';
myTransfer.sendData(3);
delay(100);
if(myTransfer.available())
{
Serial.println("New Data");
for(byte i = 0; i < myTransfer.bytesRead; i++)
Serial.write(myTransfer.rxBuff[i]);
Serial.println();
}
else if(myTransfer.status < 0)
{
Serial.print("ERROR: ");
Serial.println(myTransfer.status);
}
}
Lastly, note that you can transmit ints, floats, chars, etc. using the combination of these libraries!

Cannot send/receive number through USB to Arduino to control a motor

I'm having a project to use pyserial to send a number to an Arduino. This number is RPM (round per minute). Arduino will receive this number to control the motor (in here I use PID Controller) and then send the number Arduino received back to Python console. The problem is, I tried to send float number to Arduino, but it receives nothing. Here is the problem:
#include <TimerOne.h>
#include <Encoder.h>
#define A 2 //Encoder pins
#define B 3
Encoder encoder(2,3);
//Config pins for motor control:
int pinAIN1 = 9; //Direction
int pinAIN2 = 8; //Direction
int pinPWMA = 5; //Speed
int pinSTBY = 4; //Stanby
float receive;
float tsamp = 0.01;
float xung = 0;
float last_xung = 0;
float current_speed = 0;
float ref_speed ; //The reference speed
float error = 0;
float last_error = 0;
float PID,last_PID;
float Kp =0.15 , Ki =0, Kd = 0.01;
void dotocdo()
{
if ( ref_speed >= 0)
{
digitalWrite(pinAIN1, 1);
digitalWrite(pinAIN2, 0);
analogWrite(pinPWMA, PID);
}
if ( ref_speed < 0)
{
digitalWrite(pinAIN1, 0);
digitalWrite(pinAIN2, 1);
analogWrite(pinPWMA, abs(PID));
}
float P;
static float I,D;
current_speed = 60*(xung-last_xung)/(tsamp*374*4);
last_xung = xung;
Serial.println(current_speed);
error=abs(ref_speed)-abs(current_speed);
P = Kp*error;
D = Kd*(error - last_error)/tsamp;
I = Ki*error*tsamp;
PID = last_PID + P + I + D;
last_error = error;
last_PID = PID;
if (PID >= 255) {PID = 255;}
if (PID <= -255) {PID = -255;}
}
void setup() {
Serial.begin(115200);
pinMode(pinPWMA, OUTPUT);
pinMode(pinAIN1, OUTPUT);
pinMode(pinAIN2, OUTPUT);
pinMode(pinSTBY, OUTPUT);
pinMode(A, INPUT);
pinMode(B, INPUT);
digitalWrite(pinSTBY, 1);
Timer1.initialize(10000);
Timer1.attachInterrupt(dotocdo);
}
void loop()
{
if (Serial.available())
{
receive= Serial.parseFloat();
ref_speed=receive;
Serial.println(receive);
}
xung=encoder.read();
}
And here is the Python code on Raspberry:
import time
import socket
import sys
import serial
import struct
UNO_1 = serial.Serial('/dev/ttyUSB0', 115200)
while (1):
n=float(25)
UNO_1.write(bytes(b'%f'%n))
receive=UNO_1.readline()
print(receive)
This is the error (Arduino receives nothing):
Does anyone know how to fix this problem?
Has any communication worked before?
Double-check your connections (swapped TX and RX, forgot GND)
Try using a serial terminal (I think pyserial has a demo included) to send data manually.
Your Python script may just be timing out.
Your Python script might be sending too many zeroes or control characters that Serial.parseFloat() does not like (it stops if it does not like something).
Alternativley, just get started with echo programs that don't actually try to parse numbers to see if any data comes through: try this.

Send a String from Python to Arduino LCD

I want to display a string on an Arduino LCD 16x2 using python, but I’ve encountered problems with serial communication.
Here is the code running in Arduino:
Arduino Code
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String stringa;
const unsigned long TimeOut = 10; // timeout 10 ms
String stringa1;
String stringa2;
void setup() {
lcd.begin(16, 2);
Serial.begin(9600);
}
void loop() {
stringa = "";
unsigned long T = 0; // timer
T = millis(); // timer running
while (millis() - T < TimeOut) {
// waiting timeout
while (Serial.available() > 0) {
// receiving Serial
stringa += char(Serial.read()); // add char
T = millis(); // reset timer
}
}
if (stringa.length() > 32) {
lcd.setCursor(0, 1);
lcd.print("stringa length: " + stringa.length());
delay(2000);
lcd.print(" ");
} else {
stringa1 = stringa.substring(0 , 16);
stringa2 = stringa.substring(16);
lcd.setCursor(0, 0);
lcd.print(stringa1);
lcd.setCursor(0, 1);
lcd.print(stringa2);
delay(5000);
}
}
It works perfectly with Serial communication from Keyboard provided in Arduino IDE. But it doesn't work when I try to send a string using the Python script below:
Python Code
import serial
import sys
import time
arduino = serial.Serial('COM3', 9600, timeout=0)
stringa = 'hello'
arduino.write(bytes(stringa,'utf-8'))
arduino.close()
Where is the problem? I can't find a solution! Thanks.
Take a look at the difference between the timeouts in the C file above and the python script below.
The timeout is 10 milliseconds in your C file wheareas it’s 0 in your Python script. Also check the result of the arduino.write() to make sure that it was successful.
Possibly implement something like the following:
import serial
import sys
import time
arduino = serial.Serial('COM3', 9600, timeout=10)
stringa = 'hello'
try:
arduino.write(stringa.encode())
except OsError:
print "Write failed!"
arduino.close()
If this does not work then try checking the serial ports between both the C file and the Python script. Make sure they are the same. Hope this helps!

Arduino to Raspberry Pi serial communication creates only random chars after a few seconds

For my project I need a Raspberry Pi to communicate with several peripheral components, two of them are Arduinos. The one which causes my problem is a Pro Mini 3.3 V ATmega328. The Arduino receives input from two sensors and transfer the data to the Raspberry Pi via serial. A Python code with the serial-package is used on the Raspberry which establishes a connection every 50 ms.
When the input to the Raspberry is printed, the first few lines are correct but after about two, three seconds the printed lines are random chars.
My Python code looks like this:
import serial
ser = serial.Serial('/dev/ttyS0', 115200, timeout=1)
if ser.isOpen():
ser.close()
ser.open()
...
# loop
try:
ser.write("1")
ser_line = ser.readline()
print ser_line
...
The Arduino code:
#include <Wire.h>
#include "SparkFunHTU21D.h"
#include <FDC1004.h>
FDC1004 fdc(FDC1004_400HZ);
HTU21D myHumidity;
int capdac = 0;
void setup() {
Wire.begin();
Serial.begin(115200);
myHumidity.begin();
}
void loop() {
String dataString = "";
dataString += String(myHumidity.readHumidity());
dataString += " ";
dataString += String(myHumidity.readTemperature());
dataString += " ";
for (uint8_t i = 0; i < 4; i++){
uint8_t measurement = 0;
uint8_t channel = i;
fdc.configureMeasurementSingle(measurement, channel, capdac);
fdc.triggerSingleMeasurement(measurement, FDC1004_400HZ);
//wait for completion
delay(15);
uint16_t value[2];
if (! fdc.readMeasurement(measurement, value)) {
int16_t msb = (int16_t) value[0];
int32_t capacitance = ((int32_t) 457) * ((int32_t) msb);
capacitance /= 1000; //in femtofarads
capacitance += ((int32_t) 3028) * ((int32_t) capdac);
dataString += String(capacitance);
dataString += " ";
int16_t upper_bound = 0x4000;
int16_t lower_bound = -1 * upper_bound;
if (msb > upper_bound) {
if (capdac < FDC1004_CAPDAC_MAX)
capdac++;
} else if (msb < lower_bound && capdac > 0) {
capdac--;
}
}
}
Serial.println(dataString);
delay(20); // delay in between reads for stability
}
The output of this loop looks like:
So the output loses accuracy and become random chars after about six lines and the output doesn't recover. When I print the serial output in the Arduino's serial monitor the output stays correct all the time. After several tests I run out of ideas. Has anyone a solution for this problem or experienced a similar behavior?

Categories