将浮点类型数据从Arduino发送到Python

时间:2012-09-30 20:24:37

标签: python c arduino atmega

我需要从Python向Arduino发送浮点数据并获得相同的值。我想先从Arduino发送一些浮点数据。数据以4个连续字节发送。我正在试图弄清楚如何收集这些连续的字节并在Python端将其转换为正确的格式(系统结束)

Arduino代码:

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代码(系统结束):

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)

使用上面代码中显示的struct模块可以打印浮点值。

50%的时间,数据打印正确。但是,如果我弄乱time.sleep()或停止传输并重新启动它,则打印出不正确的值。我认为在这种情况下,解压缩了4个字节的错误集合。关于我们在这里可以做什么的任何想法?

除了使用struct模块向Arduino发送和从Arduino接收浮点数据之外的任何其他想法?

3 个答案:

答案 0 :(得分:0)

嗯,简短的回答是软件和硬件之间存在一些互动。我不确定你是怎么停止传输的。我怀疑你正在做的事情实际上是停止在字节中间发送的字节,因此当你开始备份时会注入一个新的字节。 time.sleep()部分可能是某些硬件缓冲区溢出而你丢失了导致对齐偏移的字节。一旦你开始从一个浮点数中获取几个字节,从另一个浮点数中获取几个字节,你就会开始得到错误的答案。

我注意到的一件事是你没有任何对齐机制。这对于UART来说通常很难做到,因为您可以发送的只是字节数。一种方法是来回发送握手。计算机说重新启动,硬件重新启动连接(停止发送内容,清除它有的缓冲区等)并发送一些魔法,如0xDEADBEEF。然后计算机可以找到这个0xDEADBEEF并知道下一条消息将从何处开始。您仍然需要了解硬件/操作系统中存在的任何缓冲区,并采取预防措施以防止它们溢出。有许多流量控制方法适用于XON / XOFF到实际的硬件流控制。

答案 1 :(得分:0)

因为这个问题在搜索引擎上排名很高,所以我已经制定了一个可行的解决方案。

警告:除非您需要完全浮点精度,否则转换为字符串并发送(使用sprintf或dtostrf,或使用 Serial.print(value,NumberOfDecimalPlaces) (documentation) )。这是因为以下解决方案a)不适用于不同endianess的机器和b)某些字节可能被误解为控制字符。

解决方案:获取浮点数的指针,然后将其作为字节数组传递给Serial.write()。

e.g。

/*
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);

}

然后在python中接收到这个,我使用了你的解决方案,并添加了一个函数来比较两个输出以进行验证。

# 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 

参考文献: Sending a floating point number from python to arduinoHow to send float over serial

答案 2 :(得分:-1)

我不知道Python,但是,Arduino发送这样的数字出了什么问题:

value= 1.234;
Serial.println(value);

让Arduino获得一个浮动:

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

请注意,此代码未经测试,但与我过去使用过的代码非常相似。