Sending float data from Arduino to Python

I need to send floating point data to Arduino from Python and get the same value back. I decided to first send some swimming data from Arduino. Data is sent as 4 consecutive bytes. I am trying to figure out how to collect these serial bytes and convert them to the correct format at the end of Python (end of system)

Arduino Code:

void USART_transmitdouble(double* d) { union Sharedblock { char part[4]; double data; } my_block; my_block.data = *d; for(int i=0;i<4;++i) { USART_send(my_block.part[i]); } } int main() { USART_init(); double dble=5.5; while(1) { USART_transmitdouble(&dble); } return 0; } 

Python code (end of system):

 my_ser = serial.Serial('/dev/tty.usbmodemfa131',19200) while 1: #a = raw_input('enter a value:') #my_ser.write(a) data = my_ser.read(4) f_data, = struct.unpack('<f',data) print f_data #time.sleep(0.5) 

Using the struct module, as shown in the above code, allows you to print floating point values.

50% of the time, data is printed correctly. However, if I get confused with time.sleep() or stop the transfer and restart it, invalid values ​​will be printed. I think the wrong set of 4 bytes is unpacked in this case. Any idea what we can do here?

Any other ideas besides using a structural module to send and receive float data to and from Arduino?

+4
source share
3 answers

Well, the short answer is there is some kind of interaction between the software and the hardware. I'm not sure how you stop transmitting. I suspect that everything you do actually stops sending the byte in the middle of the byte, so enter a new byte when you start the backup. Part of time.sleep () may be that some hardware buffer overflows and you lose bytes, which causes an alignment offset. As soon as you start capturing several bytes from one float and several bytes from another, you will begin to receive the wrong answer.

One thing that I noticed is that you do not have a leveling mechanism. This is often difficult to do with UART, because all you can send is bytes. One way is to send a handshake back and forth. The computer restarts, the hardware restarts the connection (stops sending material, clears w / e-buffers, etc.) and sends some magic, like 0xDEADBEEF. Then the computer can find this 0xDEADBEEF and find out where the next message will start. You still need to know what buffers exist in the hardware / OS and take precautions so as not to overflow them. There are several flow control methods that allow XON / XOFF to perform actual hardware flow control.

0
source

Since this question is highly dependent on search engines, I put together a working solution.

A WARNING. If you don't need full floating point precision, convert it to a string and send it (using sprintf or dtostrf or use Serial.print (value, NumberOfDecimalPlaces) (documentation) ). This is because the following solution: a) does not work for machines of different consistencies, and b) some of the bytes may be misinterpreted as control characters.

Decision. Get the pointer for the floating point number, and then pass it as an array of bytes to Serial.write ().

eg.

 /* Code to test send_float function Generates random numbers and sends them over serial */ void send_float (float arg) { // get access to the float as a byte-array: byte * data = (byte *) &arg; // write the data to the serial Serial.write (data, sizeof (arg)); Serial.println(); } void setup(){ randomSeed(analogRead(0)); //Generate random number seed from unconnected pin Serial.begin(9600); //Begin Serial } void loop() { int v1 = random(300); //Generate two random ints int v2 = random(300); float test = ((float) v1)/((float) v2); // Then generate a random float Serial.print("m"); // Print test variable as string Serial.print(test,11); Serial.println(); //print test variable as float Serial.print("d"); send_float(test); Serial.flush(); //delay(1000); } 

Then, to get this in python, I used your solution and added a function to compare the two outputs for verification.

 # Module to compare the two numbers and identify and error between sending via float and ASCII import serial import struct ser = serial.Serial('/dev/ttyUSB0', 9600) // Change this line to your port (this is for linux ('COM7' or similar for windows)) while True: if(ser.inWaiting() > 2): command = ser.read(1) #read the first byte if (command == 'm'): vS = ser.readline() # ser.read(1) data = ser.read(4) ser.readline() vF, = struct.unpack('<f',data) vSf = float(vS) diff = vF-vSf if (diff < 0): diff = 0-diff if (diff < 1e-11): diff = 0 print "Str:", vSf, " Fl: ", vF, " Dif:", diff 

References: Sending a floating-point number from python to arduino and How to send a float through a serial port

0
source

I do not know Python, however, what is wrong with Arduino, sending the number as follows:

 value= 1.234; Serial.println(value); 

For Arduino to get a float:

 #include <stdio.h> #include <stdlib.h> void loop() { char data[10], *end; char indata; int i=0; float value; while ((indata!=13) & (i<10)) { if (Serial.available() > 0) { indata = Serial.read(); data[i] = indata; i++; } } i-=1; data[i] = 0; // replace carriage return with 0 value = strtof(data,&end); } 

Please note that this code is untested, although it is very similar to the code I used in the past.

-1
source

Source: https://habr.com/ru/post/1437076/


All Articles