I want to Control the current flowing through a circuit using an Arduino. I have trained a PID controller for this purpose. I am using a current sensor to determine the error. It runs successful on my Arduino. In my next step I want build a system where I can send the Current setpoint (deter mined by my python code) value to the Arduino through serial communication. I am able to send integer values to Arduino. But I am unable to send and receive float values from Python to Arduino. I want to know the necessary code to be written in both sender and receiver. I tried of converting float to string and then send it to Arduino. But I failed. Please help.
Arduino Code(edit- Sorry previous code was an old file. Here is the correct one):
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
//pinMode(13,OUTPUT);
}
float f;
void loop() {
if(Serial.available())
{f=Serial.parseFloat();
Serial.println(f);
}
delay(1000);
}
//count=count+1;
//delay(1);
//}
Python Code (edit- Sorry, the previous code was from an old file. Here is the correct one):
import serial
import time
import struct
ser = serial.Serial('/dev/ttyACM0', 9600, timeout = 1) # ttyACM1 for Arduino board
data=5.7
while True:
ser.write(str(data))
time.sleep(1)
ser.flush()
When I run this code I get the following output on the Arduino Serial Monitor. As shown in the figure below.
Thank you.
2 Answers 2
It would seem you managed to solve your problem with
Serial.parseFloat()
. This is probably the easiest solution, but it has
one serious drawback: it is a blocking function. Which means, during
all the time needed by the serial port to transfer the number, your
Arduino does nothing but wait for the incoming characters. This is an
issue if your program has other task to do like, e.g., manage a PID
regulation.
I suggest you consider reading the serial port in a non blocking
fashion instead. This should make your PID happier, as it won't feel
neglected while you read the incoming data. Look Alterno's answer is a
good example of a non-blocking function that combines reading and
parsing. However, I would like to point out that you do not need to
implement your own number parser if you don't want to. A very common
pattern is to instead store the incoming characters in a buffer and,
when you see the character chosen as a terminator (e.g. ASCII LF), you
parse the buffer at once using either strtod()
or atof()
. For
example:
void setup() {
Serial.begin(9600);
}
void loop() {
static char buffer[32];
static size_t pos;
if (Serial.available()) {
char c = Serial.read();
if (c == '\n') { // on end of line, parse the number
buffer[pos] = '0円';
float value = atof(buffer);
Serial.print("received: ");
Serial.println(value);
pos = 0;
} else if (pos < sizeof buffer - 1) { // otherwise, buffer it
buffer[pos++] = c;
}
}
}
-
Well sir, even this code has the same outcome as that of Alterno's code. The serial monitor is just empty. Again my python code is still the same.CR7– CR72018年02月10日 18:25:55 +00:00Commented Feb 10, 2018 at 18:25
-
@CR7: Your Python code is buggy: it fails to send a line terminator. You should
ser.write(str(data) + "\n")
.Edgar Bonet– Edgar Bonet2018年02月10日 18:40:28 +00:00Commented Feb 10, 2018 at 18:40 -
Thank you sir, it works. Takes less time too. Thanks once again.CR7– CR72018年02月10日 18:44:57 +00:00Commented Feb 10, 2018 at 18:44
Problem with Serial.parseFloat() is that it blocks until it read the value.
Try this code, which implement a minimal float parse routine (no error checking), and it's not blocking, so you can do other things while waiting for float to come
void setup()
{
Serial.begin(9600);
while(!Serial);
Serial.println("Start");
}
float result = 0;
bool dec = false;
int decDiv = 10;
void loop()
{
// Float are positive, with format 999.99 (no sign, variable length integer/dec
// We read only one char in each execution.
if(Serial.available()) {
// Read a single char from serial input.
char c = Serial.read();
if(isDigit(c)) {
int val = (c - '0'); // Convert ASCII to binary.
if(dec) {
// We just read a decimal digit.
result += (float) val / decDiv;
decDiv *= 10;
} else {
// We just read a integer digit.
result = result * 10 + val;
}
} else if(c == '.') {
// Decimal part start now.
dec = true;
} else {
// Any other thing is the end of the float value.
Serial.println(result);
// And reset everything for another float value.
result = 0;
dec = false;
decDiv = 10;
}
}
}
-
Well, sorry to say Sir but this didn't work. The serial monitor just shows "start". I didn't change the python code at all. Just implemented your Arduino code.CR7– CR72018年02月10日 09:33:19 +00:00Commented Feb 10, 2018 at 9:33
-
Did you type a float value in the Serial Monitor?user31481– user314812018年02月10日 09:46:53 +00:00Commented Feb 10, 2018 at 9:46
-
No Sir, I just uploaded the code. Started my python script and opened the serial monitor.CR7– CR72018年02月10日 09:48:01 +00:00Commented Feb 10, 2018 at 9:48
-
@CR7 Forget Python for a while. Just connect your Arduino to Arduino IDE's Serial Monitor and type a float value. Test the code until it perform as you require and then conect it with Python. Divide and Conquer.user31481– user314812018年02月10日 09:50:04 +00:00Commented Feb 10, 2018 at 9:50
-
Yeah sir, I entered a float value in serial monitor. Still the same result. Only start.CR7– CR72018年02月10日 09:55:27 +00:00Commented Feb 10, 2018 at 9:55
Explore related questions
See similar questions with these tags.
5.75.75.75.75.75.75.75.75.75.7
.