一种基于Ros的AGV调度系统设计与实现
2022-06-30魏庆栋
魏庆栋,王 忠
(火箭军工程大学 基础系,陕西 西安 710038)
1 问题描述
典型的竞赛类AGV需要在规定场地内完成一系列规定工作。以大学生智能汽车竞赛航天智慧物流组为例[1],场地如图1所示。该比赛为模拟工业转运无人车在实际生产中的应用,AGV要完成启动、指定位置的停靠与重启、识别红绿灯、装载和卸载货物等一些规定动作,并按照相应的标准获取或者扣掉一定分数。
按照上述比赛要求,上位机需要在和AGV完成通信的基础上,依靠调度系统对AGV进行监控。操控人员通过调度系统的界面与下位机建立连接,如果连接成功,界面将自动开始显示AGV的一些运动参数,操控人员随后向AGV 发送位置坐标等指令,AGV 在接收到指令后开始自主导航,之后的动作除接收下一个坐标外均由AGV自主完成。如果长时间连接不成功,系统将自动弹出连接失败,并显示原因。任务流程图如图2所示。
图1 比赛场地图
2 功能分析
按照上述的比赛流程和任务要求,本文所要设计实现的AGV调度系统需要实现以下几个功能:
(1)通信管理功能:通过调度系统,上位机能与AGV 建立通信连接,从而实现上位机和AGV 的实时数据交换。
图2 调度系统任务流程图
(2)车辆控制功能:调度系统可以对AGV的启动和停止进行控制,还可以下发位置坐标,控制AGV的停靠位置。
(3)比赛进程监控功能:调度系统可以实时监视AGV的运行状态,以便及时发现AGV行进中的问题。
(4)人机交互界面:为操控人员提供操作窗口,能够显示通信连接状况、车辆运行状况等信息,并提供对AGV的控制功能。
通过对上述功能的分析可以得出,调度系统在比赛中发挥着重要作用,比赛的最终结果除了取决于AGV本身的性能,更要依靠一个操作流畅、运行稳定的调度系统软件。调度系统的功能结构图如图3 所示。
图3 功能结构示意图
3 系统设计
3.1 总体框架与设计思路
整个调度系统的运行环节如图4所示,分为以下几个层次:人机交互层是为用户提供的操作界面,主要用来为操控人员提供使用窗口;通信层用来实现上位机和AGV的连接与通信。为了便于开发,客户端可以结合在用C#编写的界面中,服务端则使用Python编写,结合在Ros节点中;执行层是借助Ros自定义的控制节点,通过Ros的通信机制实现系统对AGV的控制和监视。
3.2 设计方案
图4 总体框架
3.2.1 交互层设计。为了方便界面设计开发,本文采用了Microsoft Visual Studio 2019开发平台框架的C#语言进行软件开发,设计实现一个能满足比赛要求的人机交互界面。使用C#进行编程时,会自动产生代码框架,这使得编程大大减少了工作量。同时作为面向对象编程的语言,C#具有继承性、封装性和多态性等特点,使得代码结构清晰,可读性强,利于扩展和调用[2]。
根据上一节可知,界面由三个模块组成,分别是AGV的控制模块、监控模块以及通信管理模块。通信管理模块负责管理与AGV的通信连接,控制模块负责向AGV发送指令,而监控模块负责实时显示AGV的运动参数。
3.2.2 通信层设计。根据比赛需求,上位机和下位机之间的距离不会太远,但在比赛过程中AGV会经常处于运动状态,因此为了方便通信,可以选择无线组网的方式,将二者连接在同一路由器上,组建成简易局域网。
在编程开发上,选择使用Socket 通信,它是一种网络中不同主机上的应用进程之间进行双向通信的协议机制,作为支持TCP/IP 协议的API,可以避免考虑具体的三次握手连接过程[3],只需要调用Socket 抽象类的connect接口函数,即可完成通信连接。在使用Socket通信时,需要将通信的一端作为服务端,绑定自身IP地址和一个端口号,另一端则作为客户端,通过服务端的IP地址和端口号与服务端进行连接。在连接成功后,两端开始传输数据。在通信结束后,调用Close函数,关闭套接字连接,释放资源[4]。
3.2.3 执行层设计。机器人系统作为一种多模块集成的复杂系统,需要不同功能模块和进程之间相互联系、相互配合才能发挥系统的正常功能。Ros是用于机器人领域的一套通用软件框架,机器人的不同进程和模块在Ros中通常以节点的形式存在,通过Ros的通信机制实现它们的协作和配合[5]。
Ros节点间的基本通信机制主要有三种方式,话题通信(发布订阅模式)、服务通信(请求响应模式)和参数服务器(参数共享模式)[6]。为实现对AGV的监控,主要采用的是话题通信机制和服务通信机制。
话题通信的过程主要是订阅和发布。通信的两方分别作为发布者和订阅者,双方在节点管理器中完成注册后,发布者声明发布(Publish)话题(Topic),而订阅者声明订阅该话题,话题中的数据即为需要通信的内容[7]。在比赛中,为获取到AGV的运行数据,可以自定义订阅节点,订阅比赛所需运动参数的话题。具体如图5所示。
图5 话题通信机制
服务通信机制是Ros通信中基于请求响应模式的一种常见通信机制,一个节点向另一个节点发送请求,另一个节点收到请求后进行处理,再将响应结果发送回原节点[8]。在比赛中,为实现AGV的自主导航而使用的Navigation功能包,其中的move_base包会通过actionlib机制获取目标点坐标后进行路径规划。而actionlib通信机制实际上就是一种特殊的服务通信机制。与一般的服务通信机制相比,增加了中断和反馈的机制。在复杂的基于Ros的系统中,如果某个响应的过程相对比较复杂,服务端处理时间较长,使用actionlib通信机制,可以使得客户端实时获取到服务端的任务处理进度状态,或者选择中断处理进程[9]。具体如图6所示。
图6 actionlib通信机制
4 调度系统软件实现
以本文第一节给出的智能车竞赛为例,结合前面的设计方案,给出具体的软件实现过程。
4.1 交互层的实现
根据比赛需要,本文设计的人机交互界面如图7所示,界面中包含了对AGV的控制模块、监控模块以及通信管理模块。
图7 人机交互界面
(1)通信管理模块。通信管理模块通过输入AGV的IP 地址和端口号尝试与AGV 建立连接,并在消息列表中显示连接状况。运行效果如图8所示。
(2)AGV 控制模块。控制模块在上位机与AGV建立连接后,负责向AGV发送指令,包括位置坐标和停车方向,随后AGV开始运动,并在规定位置完成停靠。运行效果如图9所示。
图8 通信管理模块交互界面
图9 AGV控制模块界面
(3)AGV监视模块。监视模块在比赛开始后,会实时显示AGV的运行状态和位置信息,为操控人员提供参考。运行效果如图10所示。
图10 AGV监视模块界面
4.2 通信层和执行层的实现
按照系统层次分析,Socket通信的两端需要分别与Ros节点和界面进行数据交互,因此两个层次可以一起实现。
4.2.1 客户端的开发。使用C#进行客户端的开发时,在界面中找到相应的按钮,添加点击事件,调用Socket类的Connect()、Send()和Receive()等方法进行通信的连接、发送和接收。在使用Receive()方法时,为保证在连接完成后,Socket的接收状态随即开启并且能一直保持,同时接收到的信息能在控件中显示出来,需要做如下处理:
(1)将接收程序作为子线程进行抽象,并设置为后台程序[10],保证在点击动作完成后,可以一直保持接收状态。
(2)由于在抽象出的子线程中无法直接调用窗口中的控件,因此需要将工作线程中涉及更新界面的代码封装为一个方法,通过Invoke 方法进行调用,这样可以大大减少UI线程更新界面的负担[11]。
(3)完成上述动作后,点击“连接”按钮,窗口程序会随之陷入死循环,无法正常连接,所以需要设置全局变量flag,初始设置为0,在完成连接后,flag设为1,此时接收线程中的循环才开启。
4.2.2 服务端的开发。使用Python 进行服务端的开发时,同样是调用Socket类创建Socket服务端,绑定相应的IP地址和端口号,设置监听;与客户端类似,服务端需要将“接收”和“发送”两个过程抽象为两个线程,在主程序中同时并发运行。
两个线程的设计思路为:
(1)发送线程中,定义Ros节点,根据3.2.3节中介绍的Ros话题通信机制,订阅需要发送的AGV参数。sub=rospy.Subscriber("/amcl_pose",PoseWithCovariance Stamped,doPose,queue_size=1000)
其中doPose为回调函数,获得订阅的坐标后的处理动作由该回调函数进行定义[12]。按照功能分析,回调函数的功能应该定义为使用Socket通信的Send方法将信息发送至上位机。
(2)接收线程在接收到上位机发送的坐标信息后,将坐标信息设置为导航目标点,然后通过actionlib通信机制发送至导航的服务端,AGV随即开始自主导航。为了简化代码结构,可以将发布导航点的代码抽象为类,在接收线程中使用该类即可。
5 结语
根据本文设计实现的调度系统在智能车比赛中运行稳定,操作简单,可以满足比赛要求。同时在现行技术的基础上,还可以根据比赛要求进行一系列的改进,比如增加订阅的话题,获取AGV摄像头的视频数据,以及对AGV发送更多的控制指令等。本文所介绍的AGV调度系统,应用到的技术相对简单,操作方便,对之后类似比赛中的调度系统具有一定的参考和借鉴意义。