ROS 学习笔记之三:无线连接 Arduino

    在准备过程中,实现了基于 rosserial 和 Arduino 的通讯,确定了单片机系统也可以作为 ROS 的一个 Node ,融入 ROS 机器人系统。
    但按目前我的理解和水平,似乎 ROS 的 Master 必须在 PC 上运行,而且是安装了 ubuntu 相应系统的 PC。
    如果通过串口线(USB线)和 Arduino 板相连才能实现 rosserial ,那局限性太大了。因为作为学习用的小车平台不会做的很大,否则成本太高。这样就无法将笔记本电脑放置在小车上,如果选择性能够跑 ROS 的单板电脑,似乎价格不菲。
    所以,在实现 rosserial 后,第一步想验证的就是:可否将有线连接变为无线?

    利用我自己做的两个USB无线适配器(可以支持USB转无线或者UART转无线,用 STM32F103C8实现,USB虚拟串口是用 STM32 的USB库实现的),一个通过USB连接到电脑上,一个通过UART口连接到 Arduino Nano 板。

 
    因为我是在虚拟机上安装的 ubuntu,STM32 虚拟串口驱动安装在 win10 下 ubuntu 系统就应该能识别,实际上似乎有点问题,我 Linux 不熟悉,目前主要目的不是琢磨 STM32 的USB虚拟串口,所以绕开,用一个 CH340的 USB转TTL串口模块接入PC,这样在 ubuntu 中就认识了。
    依次在 ubuntu 中启动终端,运行 roscore 、rosrun rosserial_python serial_node.py /dev/ttyUSB0 ,发现连接不上,显示同步失败。
https://github.com/ros-drivers/rosserial/blob/melodic-devel/rosserial_arduino/src/rosserial_arduino/SerialClient.py    ;担心是 Arduino 的 USB 串口连接产生的复位信号没有,导致同步失败。用 USB转TTL串口模块直接接到 Arduino 芯片的 TXD、RXD端,结果正常工作,看来不是复位信号问题。

    再次按照前述接线,用两个无线透传模块代替 UART 连线,这次成功了!



    又试了几次,发现可能和复位有一定关系。 
    PC 上的 rosserial 运行必须在 Arduino 模块可靠复位后,否则似乎是由于串口缓冲中有数据,通讯的同步就无法实现。感觉库程序中有点问题,通讯帧的处理不能从连续的数据流中找到有效的同步帧,而是从复位开始检测。
    这个以后在具体实施时再说吧,至少验证了通过无线实现 rosserial 的可能性,这样可以发挥的空间就大多了。

补白:
    查阅了github 上的 roserial_arduino 源代码,是在请求通讯时通过 DTR 信号给 Arduino 板提供复位信号了:
https://github.com/ros-drivers/rosserial/blob/melodic-devel/rosserial_arduino/src/rosserial_arduino/SerialClient.py
……

import time
   
 

import rospy

 

from std_srvs.srv import Empty, EmptyResponse

   
 

from serial import Serial

   
 

from rosserial_python import SerialClient as _SerialClient

   
 

MINIMUM_RESET_TIME = 30

   
 

class SerialClient(_SerialClient):

   
 

def __init__(self, *args, **kwargs):

 

# The number of seconds to wait after a sync failure for a sync success before automatically performing a reset.

 

# If 0, no reset is performed.

 

self.auto_reset_timeout = kwargs.pop('auto_reset_timeout', 0)

 

self.lastsync_reset = rospy.Time.now()

 

rospy.Service('~reset_arduino', Empty, self.resetArduino)

 

super(SerialClient, self).__init__(*args, **kwargs)

   
 

def resetArduino(self, *args, **kwargs):

 

"""

 

Forces the Arduino to perform a reset, as though its reset button was pressed.

 

"""

 

with self.read_lock, self.write_lock:

 

rospy.loginfo('Beginning Arduino reset on port %s. Closing serial port...' % self.port.portstr)

 

self.port.close()

 

with Serial(self.port.portstr) as arduino:

 

arduino.setDTR(False)

 

time.sleep(3)

 

arduino.flushInput()

 

arduino.setDTR(True)

 

time.sleep(5)

 

rospy.loginfo('Reopening serial port...')

 

self.port.open()

 

rospy.loginfo('Arduino reset complete.')

 

self.lastsync_reset = rospy.Time.now()

 

self.requestTopics()

 

return EmptyResponse()

   
 

def sendDiagnostics(self, level, msg_text):

 

super(SerialClient, self).sendDiagnostics(level, msg_text)

 

# Reset when we haven't received any data from the Arduino in over N seconds.

 

if self.auto_reset_timeout and (rospy.Time.now() - self.last_read).secs >= self.auto_reset_timeout:

 

if (rospy.Time.now() - self.lastsync_reset).secs < MINIMUM_RESET_TIME:

 

rospy.loginfo('Sync has failed, but waiting for last reset to complete.')

 

else:

 

rospy.loginfo('Sync has failed for over %s seconds. Initiating automatic reset.' % self.auto_reset_timeout)

 

self.resetArduino()

猜你喜欢

转载自blog.csdn.net/embedream/article/details/91819927