最大化Arduino串行输出 [英] Maximize Arduino serial output

查看:132
本文介绍了最大化Arduino串行输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇文章中有多个问题.请仔细阅读并回答您可以提出的建议.

用例

创建压力读数的时间序列csv文件.这些读取必须具有最高频率,但我只需要持续不到10秒左右即可.

材料

  1. Arduino Uno克隆(不可更改)
  2. 通过USB 2.0串行(可更改)
  3. pyserial(Python 3)
  4. SSD

问题

识别并修复瓶颈,以防止最大读取/秒的频率发生.

代码

Arduino

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

Python

...
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)

带宽

一些计算可以找出瓶颈所在.

100 µs读取模拟引脚

1个数据包= 10位

串行线速度:450000/10 = 45000包/秒

Arduino的串行采样率/秒速率:

100 µs * 1s/(10 ^ -6 µs)= 1 x 10 ^ 4个样本/秒

arduino硅适配器:便宜的克隆芯片.由于它不是arduino许可的产品,因此表现不佳,但这被认为是可以接受的损失,将在后面进行解释.假定具有无限带宽,尽管这显然将使性能提高一个数量级.

USB 2.0

packets/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.

结论:瓶颈是串行波特率.

调整波特率可以确认这一点.我发现,当解决方案

您是正确的,瓶颈是串行端口(从某种意义上讲,数据传输效率很低).但是,您的其他大多数假设都是错误的.

波特率代表什么

波特率是每秒不同符号更改的次数.在这里,这等同于每秒位数.波特率将包括所有传输的比特,而不仅仅是数据(开始,停止,奇偶校验).

如何传输10位值

由于传输为8n1,因此无法精确发送10位数据.它必须是8的倍数,所以8、16、24等.10位将分两个8位发送,就像它们作为一个整数存储在Arduino内存中一样.

println()如何工作

println()将数字转换为字符串.您可以指定此转换的基数(DEC,BIN,HEX,OCT)-默认为DEC,因此1023将作为4个字节+ \n传输,这是一个字节(ASCII 10)和\r(ASCII 13)这也是一个字节.总共6个字节. 1将需要3个字节-1个用于数据,2个用于换行和回车.

如何使其更快

  1. 几乎不更改任何内容-使用println(val, HEX)-对于大于255的数字,您最多需要5个字节.
  2. 使用Serial.write()-此函数将原始二进制数据放入串行,因此,如果要发送值10,它将仅发送值10的一个字节.但是,当您要发送10位变量时,变得很复杂-为此您需要2个字节,PC需要知道哪个是第一部分,第二个是将其缝合在一起.您将需要提出某种形式的简单传输协议来处理此问题,因此可能需要一些开始/停止字符.
  3. 您需要10位分辨率吗?如果可以使用8位,则可以只传输纯数据,而无需任何其他字符.另外,如注释中所建议,您可以使用更快的ADC时钟.
  4. KIIV还建议-您可以使用ADC转换中断,该中断将在测量完成后立即触发.

如果仍然使用10位,我建议使用3字节的帧:1个起始字节和2个字节的数据.这样一来,理论上您可以达到每秒约18 000帧,这高于最大analogRead()频率.

There are a multiple questions intersperced throughout this post. Kindly read carefully and answer the pieces you can for an upvote.

Use Case

Create a time series csv file of pressure reads. These reads need to be of maximum frequency, but I only need it to last less than 10 seconds or so.

Material

  1. Arduino Uno Clone (unalterable)
  2. serial over USB 2.0 (alterable)
  3. pyserial (Python 3)
  4. SSD

Problem

Identify and fix the bottleneck preventing frequency from maximum reads/s.

The code

Arduino

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

Python

...
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)

Bandwidths

Some calculations to figure out where the bottleneck resides.

100 µs to read analog pin

1 packet = 10 bits

serial wire speed: 450000/10 = 45000 packets / second

Arduino samples-into-serial/second rate:

100 µs * 1s/(10^-6 µs) = 1 x 10^4 samples / second

arduino silicon adapter: cheap cloned chip. Assumed to be underperforming as it is not an arduino-licensed product, but this is deemed acceptable loss as will be explained later. Assumed to have unlimited bandwidth, though this obviously will increase performance by an order of magnitude.

USB 2.0

packets/s = 480 mb/s * 10^6 b/mb * 1 packet/10 b = 48 x 10^6 packets / second

PC file write speed

400 MB/s = 320 x 10^6 packets/s

PC python script

Unknown. Presumed to be infinite? the datetime.now() query is known to take ~ 8 µs.

Conclusion: The bottleneck is the serial baud rate.

Adjusting the baud rate confirms this. I'm finding that el-cheapo arduino uno only supports a maximum 450000 baud rate, when the arduino actually supports 2-7 million from what I can gather online. That being said, something is still wrong.

The linchpin question

Recall that at this baud rate, we should be seeing pressure reads generated at a theoretical 45000 packets / second.

baudrate-data length-no parity-1 end bit present: 450000-8-n-1

Let sensorValue = 1023. Data looks like this going into println: 1023\n

When I run serial.println(sensorValue) in the arduino, how many packets are sent over the wire to the PC? How is this serialized into packets? How many packets will be sent over the wire? Which one of the following is true:

A. 16 bit int requires 2 packets to be transmitted. The \n exacts 2 more. Total = 4

B. sensorValue is converted to a string and sent over the wire with separate packets: 1 for 1, 1 for 0, 1 for 2, 1 for 3, 1 for \, and 1 for n. Total = 6

C. Other (help me optimize??)

Tests

I'm not seeing results as I would expect.

Let baud = 450000.

Changing value in the arduino code serial.println(value) produces different reads/second in my txt file:

value = readPin\n >> 5417 pressure reads/s

value = 1 >> 10201 reads/s

value = 1023 >> 4279 reads/s

This tells me a couple things. There is overhead when reading the analogPin's value. I can also conclude the arduino also only sends over multiple packets of data when it has to (1 > 8 bit of data, 1023 > 16 bit of data). Wait, what? That doesn't make very much sense. How does that happen?

Adjusting the baud rate causes the number of reads to change until the arduino maxes out. But lets find the throughput I should be expecting.

450000 b/s * (1 packet / 10b) * [1 read / (4 or 6 packets)] = 11250 reads OR 7500 theoretical reads/s

Actual = 5417 reads/s

Where did 2,000 reads disappear to?

解决方案

You are right that the bottleneck is the serial port (in the sense that you transmit data inefficiently). However, most of your other assumptions are wrong.

What does baud rate stand for

Baud rate is the number of distinct symbol changes per second. Here it would be equivalent for bits per second. The baud rate would include all bits transmitted, not only data (start, stop, parity).

How 10-bit value is transmitted

As you have 8n1 transmission, you cannot send exactly 10 bits of data. It must be a multiple of 8, so 8, 16, 24, etc. 10 bits will be sent in two 8 bit parts, just like they are stored in Arduino memory as an int.

How does println() work

println() converts numbers to string. You can specify base for this conversion (DEC, BIN, HEX, OCT) - default is DEC, so 1023 will be transmitted as 4 bytes + \n which is a single byte (ASCII 10) and \r (ASCII 13) which is also a single byte. Total of 6 bytes. 1 will require 3 bytes - 1 for data and 2 for newline and carriage return.

How to make it faster

  1. Without changing almost anything - use println(val, HEX) - you will need 5 bytes maximum for numbers greater than 255.
  2. Using Serial.write() - this function puts raw binary data into serial, so if you want to send a value 10, it will send just one byte of value 10. However, when you want to send 10-bit variable, things get complicated - you need 2 bytes for that, and PC needs to know which is the first part and which is second to stitch it back together. You will need to come up with some form of simple transmission protocol to handle this, so probably some start/stop character.
  3. Do you need 10-bits resolution? If you could get on with 8-bits you could transmit just plain data, without any additional characters. Also, as suggested in the comments, you could use faster ADC clock then.
  4. Also suggested by KIIV - you could use ADC conversion interrupt that would trigger instantly when the measurement is completed.

If you still go with 10-bit, I would suggest 3-byte frame: 1 start byte, and 2 bytes of data. This way you could theoretically reach ~18 000 frames per second, which is above the maximum analogRead() frequency.

这篇关于最大化Arduino串行输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆