1

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.

Ardiuno Serial Monitor

Thank you.

5
  • Please edit your question to include a Minimal, Complete, and Verifiable example of code, not just snippets. Minimal means you've stripped away irrelevant stuff, just leaving what's needed to show the problem. Complete means all the library names are shown, all the variable declarations, and all the function definitions – so people don't have to waste time guessing what you did or what you meant. Verifiable means it can be compiled and tested, allowing other people to test their theories about the problem
    – user31481
    Commented Feb 10, 2018 at 8:10
  • Problems: 1) Data doesn't arrive in all at once, but in chunks. 2) You don't filter out control chars like LF, CR and others. 3) You never look for a delimiter to sync things between Arduino and Python. 4) Never convert the string to float. Google "Arduino parse string" and study that
    – user31481
    Commented Feb 10, 2018 at 8:30
  • Start by removing the "delay(1000);" in loop(). Why would you want that? And change the order of "time.sleep(1)" and "ser.flush()". Last but not least add a space character between writing numbers. Commented Feb 10, 2018 at 10:16
  • @Mikael Patel... Thank you for the response. It works. Thanks again.
    – CR7
    Commented Feb 10, 2018 at 10:26
  • You are sending 5.75.75.75.75.75.75.75.75.75.7.
    – gre_gor
    Commented Feb 10, 2018 at 16:45

2 Answers 2

0

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;
        }
    }
}
3
  • 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
    Commented 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"). Commented Feb 10, 2018 at 18:40
  • Thank you sir, it works. Takes less time too. Thanks once again.
    – CR7
    Commented Feb 10, 2018 at 18:44
0

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;
        }
    }
}
7
  • 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
    Commented Feb 10, 2018 at 9:33
  • Did you type a float value in the Serial Monitor?
    – user31481
    Commented Feb 10, 2018 at 9:46
  • No Sir, I just uploaded the code. Started my python script and opened the serial monitor.
    – CR7
    Commented 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
    Commented Feb 10, 2018 at 9:50
  • Yeah sir, I entered a float value in serial monitor. Still the same result. Only start.
    – CR7
    Commented Feb 10, 2018 at 9:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.