Zeros get deleted! Sending a float between python and Arduino

So, I'm sending a number from python to my arduino using PySerial, and then transferring it back to python and displaying it. Integer numbers work great!

However, when sending a floating point number (number with a decimal), then my zeros get deleted in the conversion process:
10.2 becomes 1.2
230.4 becomes 23.4
203.04 becomes 23.4, etc.

Any ideas why this happens?

Arduino (Relevant) Code
msg = Serial.read();
Serial.print(msg);

Python (Relevant) Code
test_string = 202.023
arduino.write(test_string)
print (arduino.read(4))

msg = Serial.read(); only gets a single character, how are you reading the entire string? Or are you just echoing each char?

That doesn't explain why it's only 0s that are lost though.

Is the code too large to post?


Rob

That doesn't explain why it's only 0s that are lost though.

Doesn't it? A 0 is a NULL character. NULL characters have no visual representation.

NULL characters have no visual representation.

But neither does 1, 2, 3 or 4.

In Python just what exactly does test_string = 202.023 do when there's no ""?

chris899, can you change the Arduino code to

Serial.println (msg, HEX);

So we can see exactly that the Arduino is receiving.


Rob

Ok, so here is the entire code:
Arduino

char msg = '0';

void setup() {
Serial.begin(9600);
}

void loop(){
// While data is sent over serial assign it to the msg
while (Serial.available() > 0){
msg = Serial.read();
}

// see what value is given out
if (msg != '0') {
Serial.print(msg);
//Serial.print(msg, BYTE);
msg = '0';
}
}


#Python
import serial
import time

arduino = serial.Serial('COM4', 9600)
time.sleep(1)

try:
print ('MSG: Sending data to arduino')

write a single char to the arduino

#test_string = "Hello String"
test_string = 202.023
arduino.write(test_string)

print ('MSG: Sent data to arduino')

except:
print ('ERR: Unable to send data')
arduino.close()

try:

wait for arduino to reply

time.sleep(1)

print ('MSG: Attempting to read from arduino')

read one byte from the arduino

print (arduino.read(4))
except:
print ('ERR: Unable to read data properly')

arduino.close()

Changing the Serial.write to Serial.println (msg, HEX); does not help- it makes it worse.

With this new change, sending the same 202.023, python then writes:
32
3

whereas before sending it 202.023 displays in python:
22.23

  while (Serial.available() > 0){
      msg = Serial.read();
  }

msg is a char variable. It can hold one character. You keep stepping on the previous characters.

You mostly get away with this because serial data transmission is slow.

  if (msg != '0') {
    Serial.print(msg);
    //Serial.print(msg, BYTE);
    msg = '0';
  }

If the character received was not '0', print it back out.

And you wonder why the '0's are not printed?

So, since the python program is sending a float (202.023) over serial, I initialized "msg" as a float in the Arduino code. I also changed all instances of '0' to 0.0

Now, sending 202.023 returns 50.000, and sending 12.9 returns 49.005

Any ideas of the problem here?
Here is the updated Arduino code, and thanks for all the help!

How does serial work, exactly? Will PySerial send over a full floating-point number, or send it over digit-by-digit? Also, is the serial connection just a repository, or does it have different channels for when the Arduino writes to it versus when the Python code writes to serial?

float msg = 0.0;

void setup() {
  Serial.begin(9600);
}
  
void loop(){
  // While data is sent over serial assign it to the msg
  while (Serial.available() > 0){
      msg = Serial.read();
  }
  
  // see what value is given out
  if (msg != 0.0) {
    Serial.print(msg);
//    Serial.println (msg, HEX);
    msg = 0.0;
  }
}

Will PySerial send over a full floating-point number, or send it over digit-by-digit?

Unless we have a Python expert here that's what we have to find out. Hence my suggestion to print the incoming bytes in HEX. Either way it will be a few bytes because a float doesn't fit into one.

I would change loop() to this

void loop(){
   if (Serial.available() > 0){
      Serial.println (Serial.read(), HEX);
  }
}

So we can see exactly what is being transmitted.


Rob

Alright, so I changed the entire loop segment to

void loop(){
   if (Serial.available() > 0){
      Serial.println (Serial.read(), HEX);
  }
}

And when I send it the usual 202.023, it spits back:
32
30
(In that order, on two different lines)

If I send it another number, like 12, it spits back:
31
32

I'm completely confused now...

Now we're getting to the bottom of it.

It's sending the characters as ASCII

30 = '0'
31 = '1'
32 = '2'

etc

You have to accumulate those chars into a string then use a conversion function like atof() or scanf() to convert the string to a number.

BTW 202.023 should give

32
30
32
2E
30
32
33

Was that the case?


Rob

chris899:
I'm completely confused now...

Just explain why you are confused? Serial.println, by definition, prints on separate lines. Hence each thing printed is on a new line. And when you ask it to print in hex, it does.

You seem to have the impression that Serial.read() reads the whole string sent, and can automatically convert that string to the correct number.

That is not even close to reality. Serial.read() reads one character/byte from the serial port. If you are sending more than one character, you need to read the characters in a loop, until an end of packet marker arrives. Store each character in an array, except the end of packet marker.

When the end of packet marker arrives, use atoi() or atof() to convert the strings to numbers.