我需要从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接收浮点数据之外的任何其他想法?
答案 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 arduino和 How 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);
}
请注意,此代码未经测试,但与我过去使用过的代码非常相似。