如何用PySerial重新连接蓝牙(算法问题)Raspberry Pi-蓝牙设备

时间:2020-09-08 15:35:32

标签: python multithreading bluetooth raspberry-pi pyserial

Goodday程序员,

我正在研究Raspberry Pi 3B +与多个蓝牙设备之间的连接,目前每个Pi最多5个。我能够建立连接,可以与设备进行所有交互,但是在设备失去连接较长时间后,很难重新连接。请借给我您很大的帮助,并协助我制作防弹脚本,该脚本始终有效地连接设备。

一些信息:

  • 运行Raspbian Buster的Pi 3B +
  • 使用bluetoothctl将蓝牙设备配对并绑定到rc.local中的rfcomm [x](sudo绑定...)
  • Python脚本使用PySerial连接到设备,使用线程和队列进行读写。
  • 启动脚本时所有设备均已连接
  • 主脚本以.config / lxsession / LXDE-pi / autostart启动
  • 使用PySerial连接到蓝牙设备会导致连接时间过长,大约需要2-3秒。

每个设备有3个线程运行,即看门狗,读取和写入。看门狗大约每5秒钟向写队列添加一条伪消息(通过写线程发送到设备),如果它做出反应(使用错误的命令响应),我知道它仍然存在。如果它在30秒钟内没有反应,我知道它已断开连接,我必须尝试重新连接。我有一个指示connectionstatus(connectionAlive)的变量,可以是0、1或2。0是不活动的,1是重新连接的,2是连接的。仅当connectionAlive> 0时,读和写线程才处于活动状态。 问题在于,当设备通过待机或关闭为电池充电而失去连接时。读写线程非常简单,因此我认为重新连接的算法就是问题所在。我在下面添加了看门狗代码:

def Watchdog(self):
        logging.info('Start watchdog thread for: {}'.format(self.tool_id))
        while(True):
            if self.connectionAlive == 0:
                self.ChangeAlive(1)
                time.sleep(0.2)
            if self.wq.qsize() < 3:
                self.wq.put(['ping', ''])
            time.sleep(0.5)
            #if last alive longer than 20 ticks
            if (time.time() - self.last_alive) > 30: #or self.errorQ.qsize() > 0
                last_tick = time.time() - self.last_alive
                #if it was alive, tell thread its dead.
                if self.connectionAlive == 2 and self.com != False:
                    logging.error('Tool {} is taking longer to respond'.format(self.tool_id))
                self.ChangeAlive(0)
                if self.com != False:
                    try:
                        self.com.close()
                        time.sleep(0.1)
                    except:
                        #com wasnt alive (never connected since thread started)
                        pass
                self.connectionTryCount += 1
                try:
                    self.com = serial.Serial(port=self.comport, baudrate=9600, timeout=5, write_timeout=5)
                    #time.sleep(3)
                except:
                    if self.connectionTryCount < 2:
                        logging.error('Tool {} is unable to connect!'.format(self.tool_id)) #com port not available
                        #time.sleep(5)
            else:
                if self.connectionTryCount > 0:
                    logging.info('Tool {} connected after {} tries'.format(self.tool_id, self.connectionTryCount))
                    self.connectionTryCount = 0
                if self.connectionAlive != 2:
                    self.ChangeAlive(2)
                while self.errorQ.qsize() > 0:
                    self.errorQ.get()
                    time.sleep(0.05)

            time.sleep(4)

我认为线程休眠存在问题,并且以某种方式使连接窗口和读取“活动”消息的窗口过小而无法保持连接,结果导致断开连接的速度过快而无法尝试重新连接。读线程的睡眠为0.1,写线程的睡眠为0.05。

编辑:蓝牙设备已连接至需要向其发送参数的测量设备。在蓝牙部分仍处于连接状态时,测量设备可以处于待机状态,但这意味着该设备尚未运行并且尚未准备好接收参数,该设备没有内置队列。

我的脚本编写不佳还是从一开始就注定要使用PySerial或Pi?

任何意见或建议都将不胜感激!

1 个答案:

答案 0 :(得分:0)

rfcomm是BlueZ开发人员的8 tools that has been deprecated之一,因此我建议您不要在rc.local中使用rfcomm。

在Linux上,可以使用标准Python套接字库建立蓝牙串行连接,如本博客中所述:http://blog.kevindoran.co/bluetooth-programming-with-python-3/

Bluedot library中还有一些功能可能会有所帮助。除了文档外,还有一些examples

根据脚本的作用,您可能需要考虑使用systemd在启动时运行程序。我发现以下博客是有用的参考:https://blog.usedbytes.com/2019/11/run-at-startup-without-rc.local/