这篇文章中散布着多个问题。请仔细阅读并回答您可以获得的内容。
创建压力读数的时间序列csv文件。这些读取需要具有最大频率,但我只需要它持续不到10秒左右。
识别并修复瓶颈,防止最大读数频率。
void setup() {
//speed over the usb serial interface
Serial.begin(450000);
}
void loop() {
//get sensor data: read the input on analog pin 0:
int sensorValue = analogRead(A0); //returns value 0-1023
//send over serial
Serial.println(sensorValue);
}
...
ser.serial()
ser.baudrate=450000
ser.open()
while True:
try:
serialData = float(ser.readline().decode().replace('\n', ''))
except(ValueError):
continue #I ran the code without this try/except and got 100 reads higher than when this is included in here. Caused no change in order of magnitude.
now = datetime.datetime.now()
serialData2 = serialData * voltageOffset #a couple of these happen
outfile.write(now+', '+str(serialData2)+'\n')
except(KeyboardInterrupt):
...
os.sys.exit(0)
进行一些计算以找出瓶颈所处的位置。
1包= 10位
串行线速度:450000/10 = 45000包/秒
Arduino sample-into-serial / second rate:
100μs* 1s /(10 ^-6μs)= 1 x 10 ^ 4个样本/秒
arduino硅适配器:便宜的克隆芯片。假设表现不佳,因为它不是arduino许可的产品,但这被认为是可接受的损失,这将在后面解释。假设有无限的带宽,虽然这显然会使性能提高一个数量级。USB 2.0
包/ s = 480 mb / s * 10 ^ 6 b / mb * 1包/ 10 b = 48 x 10 ^ 6包/秒
PC文件写入速度
400 MB / s = 320 x 10 ^ 6包/ s
PC python脚本
未知。推定是无限的?已知datetime.now()
查询需要约8μs。
结论:瓶颈是串行波特率。
调整波特率确认了这一点。我发现el-cheapo arduino uno只支持最大450000波特率,当arduino actually supports 2-7 million来自我可以在线收集时。话虽如此,还是有些不对劲。
回想一下,在这个波特率下,我们应该看到压力读数产生理论上的45000包/秒。
波特率 - 数据长度 - 不存在奇偶校验1结束位:450000-8-n-1
让sensorValue = 1023
。数据看起来像println
:1023\n
当我在arduino中运行serial.println(sensorValue)
时,有多少数据包通过线路发送到PC?如何将其序列化为数据包?通过线路发送多少个数据包?以下哪一项是正确的:
一个。 16位int
需要传输2个数据包。 \n
还有2个。总数= 4
B中。 sensorValue
被转换为字符串并通过网络发送,包含单独的数据包:1
为1,0
为1,2
为1,3
为1 ,\
为1,n
为1。总计= 6
℃。其他(帮我优化?? )
我没有像我期望的那样看到结果。
让baud = 450000
。
更改arduino代码value
中的serial.println(value)
会在我的txt文件中产生不同的读数/秒:
value = readPin\n
>> 5417压力读数/ s
value = 1
>> 10201读取/ s
value = 1023
>> 4279读/秒
这告诉了我一些事情。读取analogPin的值时会有开销。我还可以得出结论,当arduino必须(1> 8位数据,1023> 16位数据)时,它也仅发送多个数据包。 等等,什么?这没有多大意义。 这是怎么发生的?
调整波特率会导致读数变化,直到arduino最大化为止。但是让我们找到我应该期待的吞吐量。
450000 b / s *(1包/ 10b)* [1读/(4或6包)] = 11250读数或7500理论读数/ s
实际= 5417读/秒
2,000个读数在哪里消失?
答案 0 :(得分:2)
你是对的,瓶颈是串口(在某种意义上说,你无法有效地传输数据)。但是,您的大多数其他假设都是错误的。
波特率代表什么
波特率是每秒不同符号变化的数量。这里它等效于每秒位数。波特率将包括所有传输的比特,而不仅仅是数据(开始,停止,奇偶校验)。
如何传输10位值
由于您有8n1传输,因此无法准确发送10位数据。它必须是8的倍数,因此8位,16位,24位等10位将在两个8位部分中发送,就像它们作为int存储在Arduino存储器中一样。
println()如何运作
println()
将数字转换为字符串。您可以为此转换指定基数(DEC,BIN,HEX,OCT) - 默认为DEC,因此1023将作为4字节+ \n
传输,这是一个字节(ASCII 10)和\r
(ASCII 13)也是一个字节。总共6个字节。 1将需要3个字节 - 1表示数据,2表示换行和回车。
如何加快速度
println(val, HEX)
- 对于大于255的数字,最多需要5个字节。Serial.write()
- 此函数将原始二进制数据放入串行,因此如果要发送值10,它将只发送一个字节值10.但是,当您要发送10位变量时事情变得复杂 - 你需要2个字节,PC需要知道哪个是第一个部分,哪个是第二个将它拼接在一起。你需要提出某种形式的简单传输协议来处理这个问题,所以可能需要一些启动/停止字符。如果仍然使用10位,我建议使用3字节帧:1个起始字节和2个字节的数据。这样理论上你可以达到每秒约18 000帧,高于最大analogRead()
频率。
答案 1 :(得分:1)
一种选择是采样x次,然后在发送回PC之前对其进行平均。或者接受压缩328p的挑战!如果你的压力读数基本一致,你可能对某些RLE没问题。
不要使用10位。 ADC可能具有10位分辨率,但精度为+/- 2 LSB,并且非常依赖于稳定的vref。因此,降低2 LSB并使用前8位进行快速Arduino到PC读数或多样本并平均噪声。
这是一款嘈杂,共享,低分辨率的ADC。所以不要让其他模拟引脚悬空,因为它会产生噪声(只需将它们接地)。如果可能的话,也可以在接地外壳中运行Arduino,因为ADC有一个MUX,导致它有更长的走线。切换ADC模式或引脚也会产生一些噪声(这不是你在这里做的)。如果您可以保持稳定的输入电压,则电池电量很大,否则AC / DC噪声可能会导致意外的电压波动。
Arduino上的主循环运行328p和8u之间的串行IO以及模拟读取。所以时间瓶颈有点复杂。
UNO串口转USB由ATMEGA8u2(板上另一个芯片)处理,可以115.2kbaud(而不是450000)进行通信。
8u和328p上有缓冲区只是为了增加复杂性。两个芯片运行在不同的时钟上。 ATMEGA8u2从晶振运行,ATMEGA328p(主处理器)从谐振器运行(均为16MHz)。
根据您的需要,Teensy具有稍微更准确的ADC(外部更好的读取)和更快的CPU,更多的RAM等,并且它可以最大化USB端口速度。加上保罗在一些低级技术方面有很好的信息,可以让事情变得非常快。