魏慶棟,王 忠
(火箭軍工程大學 基礎系,陜西 西安 710038)
典型的競賽類AGV需要在規定場地內完成一系列規定工作。以大學生智能汽車競賽航天智慧物流組為例[1],場地如圖1所示。該比賽為模擬工業轉運無人車在實際生產中的應用,AGV要完成啟動、指定位置的停靠與重啟、識別紅綠燈、裝載和卸載貨物等一些規定動作,并按照相應的標準獲取或者扣掉一定分數。
按照上述比賽要求,上位機需要在和AGV完成通信的基礎上,依靠調度系統對AGV進行監控。操控人員通過調度系統的界面與下位機建立連接,如果連接成功,界面將自動開始顯示AGV的一些運動參數,操控人員隨后向AGV 發送位置坐標等指令,AGV 在接收到指令后開始自主導航,之后的動作除接收下一個坐標外均由AGV自主完成。如果長時間連接不成功,系統將自動彈出連接失敗,并顯示原因。任務流程圖如圖2所示。

圖1 比賽場地圖
按照上述的比賽流程和任務要求,本文所要設計實現的AGV調度系統需要實現以下幾個功能:
(1)通信管理功能:通過調度系統,上位機能與AGV 建立通信連接,從而實現上位機和AGV 的實時數據交換。

圖2 調度系統任務流程圖
(2)車輛控制功能:調度系統可以對AGV的啟動和停止進行控制,還可以下發位置坐標,控制AGV的停靠位置。
(3)比賽進程監控功能:調度系統可以實時監視AGV的運行狀態,以便及時發現AGV行進中的問題。
(4)人機交互界面:為操控人員提供操作窗口,能夠顯示通信連接狀況、車輛運行狀況等信息,并提供對AGV的控制功能。
通過對上述功能的分析可以得出,調度系統在比賽中發揮著重要作用,比賽的最終結果除了取決于AGV本身的性能,更要依靠一個操作流暢、運行穩定的調度系統軟件。調度系統的功能結構圖如圖3 所示。

圖3 功能結構示意圖
整個調度系統的運行環節如圖4所示,分為以下幾個層次:人機交互層是為用戶提供的操作界面,主要用來為操控人員提供使用窗口;通信層用來實現上位機和AGV的連接與通信。為了便于開發,客戶端可以結合在用C#編寫的界面中,服務端則使用Python編寫,結合在Ros節點中;執行層是借助Ros自定義的控制節點,通過Ros的通信機制實現系統對AGV的控制和監視。

圖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通信機制
以本文第一節給出的智能車競賽為例,結合前面的設計方案,給出具體的軟件實現過程。
根據比賽需要,本文設計的人機交互界面如圖7所示,界面中包含了對AGV的控制模塊、監控模塊以及通信管理模塊。

圖7 人機交互界面
(1)通信管理模塊。通信管理模塊通過輸入AGV的IP 地址和端口號嘗試與AGV 建立連接,并在消息列表中顯示連接狀況。運行效果如圖8所示。
(2)AGV 控制模塊。控制模塊在上位機與AGV建立連接后,負責向AGV發送指令,包括位置坐標和停車方向,隨后AGV開始運動,并在規定位置完成停靠。運行效果如圖9所示。

圖8 通信管理模塊交互界面

圖9 AGV控制模塊界面
(3)AGV監視模塊。監視模塊在比賽開始后,會實時顯示AGV的運行狀態和位置信息,為操控人員提供參考。運行效果如圖10所示。

圖10 AGV監視模塊界面
按照系統層次分析,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隨即開始自主導航。為了簡化代碼結構,可以將發布導航點的代碼抽象為類,在接收線程中使用該類即可。
根據本文設計實現的調度系統在智能車比賽中運行穩定,操作簡單,可以滿足比賽要求。同時在現行技術的基礎上,還可以根據比賽要求進行一系列的改進,比如增加訂閱的話題,獲取AGV攝像頭的視頻數據,以及對AGV發送更多的控制指令等。本文所介紹的AGV調度系統,應用到的技術相對簡單,操作方便,對之后類似比賽中的調度系統具有一定的參考和借鑒意義。