当我使用自定义固件时,我注意到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/
答案 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控制器芯片或其固件的问题。