几次串行写入后的Arduino串行超时

时间:2013-12-03 19:57:02

标签: python c serial-port usb arduino

当我使用自定义固件时,我注意到DIY无人机的电路板出现了奇怪的行为。 这是一个在Arduino板上运行的固件中调用的示例函数:

void send_attitude(float roll, float pitch, float yaw) {
  hal.console->printf("{\"type\":\"sens_attitude\",\"roll\":%.4f,\"pitch\":%.4f,\"yaw\":%.4f}\n",
                      roll, pitch, yaw);
}

如您所见,代码只是在setup(hal.uartA)中设置的串口中写入消息。 我每0.5秒调用一次这个函数:

 inline void medium_loop() {
  static int timer = 0;
  int time = hal.scheduler->millis() - timer;

  // send every 0.5 s
  if(time > 500) {  
    send_attitude(OUT_PIT, OUT_ROL, OUT_YAW);

    timer = hal.scheduler->millis();
  }
}

现在到了奇怪的事情。如果我使用串行监视器或用其他程序或脚本读取电路板,一切都很好。每隔0.5秒,正确的LED闪烁并显示消息。但是,如果我不读出来,经过appr。 10s LED连续冲洗,不再可能进行连接/通信。我必须拔下电路板。反过来也观察到相同的行为。如果我通过串口发送到我的主板(在我的情况下是USB)并且没有刷新输入缓冲器,LED会持续冲洗并且我会超时。以下代码有效:

def send_data(line):
  # calc checksum
  chk = chksum(line)
  # concatenate msg and chksum
  output = "%s*%x\r\n" % (line, chk)
  try:
    bytes = ser.write(output)
  except serial.SerialTimeoutException as e:
    logging.error("Write timeout on serial port '{}': {}".format(com_port, e))
  # Flush input buffer, if there is still some unprocessed data left
  # Otherwise the APM 2.5 control boards stucks after some command
  ser.flush()       # Try to send old message
  ser.flushInput()  # Delete what is still inside the buffer

如果我注释掉这一行:

ser.flushInput()  # Delete what is still inside the buffer

我没有使用更多设置。 我迟早会得到(取决于消息间隔)超时。在我的情况下,我每20ms发送一个信号,导致约10秒后超时。还取决于消息的长度。更大的消息比较小的消息更快。

我的设置显示在以下代码段中。客户端python代码:

com_port  = '/dev/ttyACM0'
baud_rate = '115200'
try:
  ser = serial.Serial(com_port, baud_rate, timeout=0.1, writeTimeout=0.1, rtscts=1)

如果这些超时发生,那么如果我将超时设置为2s,我也会得到一个。在我的情况下,我需要一个非常低的延迟,如果我继续阅读和刷新,这确实是可能的。我的Arduino的固件代码:

void setup() {
  // Set baud rate when connected to RPi
  hal.uartA->begin(115200);
  hal.console->printf("Setup device ..\n");
  // Followed by motor, compass, barometer initialization

我的问题是:

  • 我的主板究竟发生了什么?

  • 如果我只是在没有读取或刷新缓冲区的情况下写入串口,为什么它不再响应?

  • 它是否真的是一个与这种奇怪行为相关的缓冲区或驱动程序问题,这个问题与所有Arduino主板相关,还是仅仅是来自DIY无人机的APM 2.5?

  • 最后但并非最不重要:我发现图书馆中没有针对此类问题的任何功能。可能有任何我不知道的事情吗?

完整的源代码是@google代码:https://code.google.com/p/rpicopter/source/browse/

3 个答案:

答案 0 :(得分:2)

您使用的是哪种主板以及它具有哪些处理器?我的猜测是你的主板是基于ATmega32U4,或其他一些内置USB模块的微控制器。如果是这样,我在此之前就已经看到了类似的行为,这就是我认为正在发生的事情:

微控制器上有一个缓冲区,用于存储连接到计算机的串行数据。计算机的USB串行驱动程序中有一个缓冲区,用于保存从芯片接收的串行信号。由于您没有从COM端口读取字节,计算机上的缓冲区将填满。一旦计算机上的缓冲区填满,它就会停止向微控制器请求数据。因此,微控制器上的缓冲区最终会填满。

一旦微控制器的缓冲区已满,您对printf命令的表现如何?为简单起见,您正在使用的printf可能只是在阻塞循环中等待,直到缓冲区空间可用,然后发送下一个字符,直到消息完成。由于缓冲区空间永远不可用,因此程序会陷入无限循环。

更好的策略是在调用printf之前检查是否有足够的缓冲区空间可用。代码可能如下所示:

if(console_buffer_space() > 80)
{
    hal.console->printf(...);
}

我不知道这是否可以在DIY无人机固件中使用,而且我不知道最大缓冲区空间是否真的可以达到80,所以你必须对此进行一些研究。

答案 1 :(得分:0)

我不明白使用:

ser.flush()       # Try to send old message
ser.flushInput()  # Delete what is still inside the buffer

假设您的设备已连接到PC并且python代码正在编写(line, chk)

ser.flush() - 你为什么要用它? ser.flushInput() - 将“删除”PC上的串行输入缓冲区

答案 2 :(得分:0)

看起来其他人也有同样的问题。感谢Mod-Braniac删除了我的最小例子。我敢打赌,这是Arduino USB控制器芯片或其固件的问题。