Arduino/Python Serial communication - python

I want to send data from python to may Arduino Mega via serial output. The Arduino's RX Led blinks, when I run the Python script. However, the Serial.available() = false. This is just an example code. The real project is building a speedometer for sim racing games (using UDP data). Any idea why it isn't working?
Here is the code:
Python:
import time
import serial
port = "COM3"
Arduino = serial.Serial(port ,9600, timeout=1);
i = 0
while i<= 9999 :
time.sleep(1/10)
i+=1
print(i)
Arduino.write(i)
Arduino:
#include <Arduino.h>
#include <TM1637Display.h>
#define CLK 2
#define DIO 3
int i=0;
int Number;
TM1637Display display(CLK, DIO);
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
display.setBrightness(0x0f);
display.showNumberDec(9999);
delay(3000);
}
void loop() {
Number= Serial.read();
if (Serial.available()>0){
display.setBrightness(0x0f);
display.showNumberDec(Number);
}
if (Serial.available() == false){
display.setBrightness(0x0f);
display.showNumberDec(0000);
}
}

This is how it works. Big thanks to csongoose from reddit who helped me a lot. Also thanks to all your replies on this.
Python:
import time
import serial
port = "COM3"
Arduino = serial.Serial(port ,9600, timeout=1);
i = 0
while i<= 9999 :
time.sleep(1)
i+=1
print(i)
#converts int i to string b
b = "%s" %i
Arduino.write(bytes(b, 'utf-8'))
#the Arduino waits for this and can seperate the numbers
Arduino.write(b'\n')
Arduino:
#include <Arduino.h>
#include <TM1637Display.h>
#define CLK 2
#define DIO 3
#define D1 5
#define D2 7
int Number;
String b;
//i am using a 7-digit display to show the numbers
TM1637Display display(CLK, DIO);
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(D1 ,OUTPUT);
pinMode(D2 ,OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available()>0){
//looks for new numbers, which are sperated with '\n'
b = Serial.readStringUntil('\n');
//converts string b to integer Number
Number = b.toInt();
display.setBrightness(0x0f);
display.showNumberDec(Number);
//delay equals the same rate as python sends data
delay(1000);
}
//this indicates if the data is available and if the Arduino has rebooted
//you need to wait for it and then start your Python stream
if (Serial.available() == 0){
digitalWrite( D1, HIGH);}
else digitalWrite(D1, LOW);
if (Number != 0){
digitalWrite( D2, HIGH);}
else digitalWrite(D2, LOW);
}

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;
}
}

Serial Communication - Why isn't this C program behaving like this Python program?

I have two programs that communicate through a serial USB interface with a CNC machine running grbl. The first program, written in Python using the pyserial library, produces intelligible output:
b'ok\r\n'
b'ok\r\n'
The second program, written in C using the libserialport library produces mangled output:
Found port: /dev/ttyUSB0
in:
in: M3 S100
out: �]�
in: M3 S0
out: �WH�
I've been staring at this for days trying to find substantive differences that could explain why the Python program works and the C one doesn't, but I haven't come up with anything yet. Both programs flush their input buffers, both programs send the same data with the same line endings, and both programs wait for the same amount of time in the same places. Any ideas on what I am doing wrong?
Python program:
import serial
import time
s = serial.Serial('/dev/ttyUSB0', 115200)
s.write(b"\r\n\r\n")
time.sleep(2)
s.flushInput()
s.write(b'M3 S100\n')
out = s.readline()
print(out)
time.sleep(1)
s.write(b'M3 S0\n')
out = s.readline()
print(out)
time.sleep(2)
s.close()
C program:
#include <libserialport.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct sp_port **port_list;
struct sp_port *main_port;
void ports_init() {
sp_list_ports(&port_list);
for (int i = 0; port_list[i] != NULL; i++) {
struct sp_port *port = port_list[i];
char *port_name = sp_get_port_name(port);
printf("Found port: %s\n", port_name);
if (strcmp(port_name, "/dev/ttyUSB0") == 0) {
sp_open(port_list[i], SP_MODE_READ_WRITE);
sp_set_baudrate(port_list[i], 112500);
main_port = port_list[i];
return;
}
}
}
void send_command(char *c) {
sp_blocking_write(main_port, c, strlen(c), 1000);
printf("in: %s\n", c);
}
void read_response() {
char hi[256];
bzero(hi, 256);
sp_blocking_read(main_port, hi, 255, 1000);
printf("out: %s\n", hi);
}
int main() {
ports_init();
send_command("\r\n\r\n");
usleep(2 * 1000 * 1000);
sp_flush(main_port, SP_BUF_BOTH);
send_command("M3 S100\n");
read_response();
usleep(1 * 1000 * 1000);
send_command("M3 S0\n");
read_response();
usleep(2 * 1000 * 1000);
}
You have a typo. In your python program you use 115200 as your baud rate, but in your C program you use 112500. Just change this line:
sp_set_baudrate(port_list[i], 112500);
to
sp_set_baudrate(port_list[i], 115200);

Read multiple arduino's using a Raspberry Pi 3 through USB

I have 3 arduino's that have RC522 rfid readers attached to them. They each have their own power supplies and they are connected to a raspberry pi 3 via the usb ports. I am getting really inconsistent results when running the reader in python. It does appear all 3 are reading but the loop does some weird things. Sometimes the chip code keeps repeating after the chip is removed and other times it works properly. There does not appear to be any consistency with which arduino is behaving oddly either.
Any help would be greatly appreciated!!!
Here is the arduino code (The same code was copied to each arduino with the exception of the initial println that indicates which arduino is connected).
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 5 // Configurable, see typical pin layout above
#define SS_PIN 53 // Configurable, see typical pin layout above
#define MOSI_PIN 51
#define MISO_PIN 50
#define SCK_PIN 52
MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
MFRC522::MIFARE_Key key;
String read_rfid;
void setup() {
Serial.begin(9600);
SPI.begin(); // Init SPI bus
rfid.PCD_Init(); // Init MFRC522
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("The Toy Maker's Sanctuary RDIF Reader 1 Online."));
//Serial.println(F("Using the following key:"));
//printHex(key.keyByte, MFRC522::MF_KEY_SIZE);
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! rfid.PICC_IsNewCardPresent())
return;
// Select one of the cards
if ( ! rfid.PICC_ReadCardSerial())
return;
dump_byte_array(rfid.uid.uidByte, rfid.uid.size);
Serial.println(read_rfid);
}
/*
Helper routine to dump a byte array as hex values to Serial.
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
read_rfid = "";
for (byte i = 0; i < bufferSize; i++) {
read_rfid = read_rfid + String(buffer[i], HEX);
}
}
Here is the python code
import serial
ser0=serial.Serial("/dev/ttyACM0", 9600, timeout=1)
ser1=serial.Serial("/dev/ttyACM1", 9600, timeout=1)
ser2=serial.Serial("/dev/ttyACM2", 9600, timeout=1)
ser0.baudrate=9600
ser1.baudrate=9600
ser2.baudrate=9600
read_ser0=""
read_ser1=""
read_ser2=""
while True:
read_ser0=ser0.readline()
print("0: ",read_ser0)
read_ser1=ser1.readline()
print("1: ",read_ser1)
read_ser2=ser2.readline()
print("2: ",read_ser2)
read_ser0=""
read_ser1=""
read_ser2=""

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.

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