張睿 董伊龍 張豪福 尚慶松
(河南工業(yè)大學(xué)電氣工程學(xué)院,河南 鄭州 450001)
計(jì)算機(jī)聯(lián)鎖是保證車站作業(yè)安全、提高車站通過能力的一種信號系統(tǒng),隨著軌道交通的不斷建設(shè),車站計(jì)算機(jī)聯(lián)鎖系統(tǒng)得到了空前的發(fā)展,對信號專業(yè)的學(xué)生了解和學(xué)習(xí)計(jì)算聯(lián)鎖技術(shù)也變得尤為重要[1]。然而傳統(tǒng)單機(jī)版計(jì)算機(jī)聯(lián)鎖仿真系統(tǒng)只能模擬站場且站場改建后無法對仿真系統(tǒng)及時(shí)修改,影響培訓(xùn)效果。對于計(jì)算機(jī)聯(lián)鎖教學(xué),需要一種可多人參與培訓(xùn),又能對站場進(jìn)行仿真,同時(shí)還能反映現(xiàn)場設(shè)備狀態(tài),并需要隨著站場改建的同時(shí)可做出相應(yīng)修改,部署和實(shí)施成本較低的仿真系統(tǒng)[2]。
本文采用Web 技術(shù)實(shí)現(xiàn)計(jì)算機(jī)聯(lián)鎖系統(tǒng)培訓(xùn),使學(xué)生不再掣肘于空間與時(shí)間??梢詴r(shí)時(shí)進(jìn)行計(jì)算機(jī)聯(lián)鎖的仿真學(xué)習(xí)。降低學(xué)習(xí)成本,提升學(xué)習(xí)效率。擺脫了硬件仿真,則教學(xué)系統(tǒng)可以幾近于零成本地部署在各處的服務(wù)器上,降低了安裝部署的成本。
系統(tǒng)設(shè)計(jì)內(nèi)容除滿足計(jì)算機(jī)聯(lián)鎖系統(tǒng)的基本功能:車站圖形渲染、用戶交互、進(jìn)路操作、車輛模擬等功能的同時(shí),主要考慮教學(xué)和培訓(xùn)需要,進(jìn)行了車站通用性和聯(lián)鎖表自動(dòng)生成設(shè)計(jì)。用戶可以自定義車站,車站定義完成后導(dǎo)入系統(tǒng),系統(tǒng)自動(dòng)實(shí)現(xiàn)計(jì)算機(jī)聯(lián)鎖系統(tǒng)的基本功能和滿足并行多個(gè)用戶培訓(xùn)的能力。系統(tǒng)定義過程簡單易懂,不需要用戶輸入多余的內(nèi)容。同時(shí)采用圖論算法來驅(qū)動(dòng)進(jìn)路的動(dòng)態(tài)查找。
為提高并發(fā),提升應(yīng)用性能,系統(tǒng)采用分布式設(shè)計(jì),如圖1所示。
圖1 系統(tǒng)架構(gòu)組織圖
系統(tǒng)采用web 應(yīng)用層次結(jié)構(gòu),分為數(shù)據(jù)訪問層,業(yè)務(wù)邏輯層,接入層,表現(xiàn)層。數(shù)據(jù)訪問層采用Rustcrate 作為ORM。業(yè)務(wù)邏輯層分為Auth、API、Runtime 等數(shù)個(gè)服務(wù),每個(gè)服務(wù)都是獨(dú)立的應(yīng)用,可以橫向擴(kuò)展組成集群。接入層使用Apollo作為網(wǎng)關(guān),向外暴露所有的服務(wù)接口。表現(xiàn)層使用Node.js 作為Web 的運(yùn)行時(shí),使用React 作為GUI 框架。
本系統(tǒng)的元素圍繞實(shí)例構(gòu)成,一個(gè)典型的練習(xí)和考試實(shí)例生命周期由以下幾部分組成:(1)創(chuàng)建車站;(2)用戶創(chuàng)建練習(xí)實(shí)例;(3)初始化實(shí)例;(4)訪問實(shí)例;(5)結(jié)束實(shí)例。
創(chuàng)建好車站后,就可以創(chuàng)建這個(gè)車站的實(shí)例。實(shí)例是用戶與系統(tǒng)交互的直接對象,也是系統(tǒng)的業(yè)務(wù)核心。一個(gè)用戶的一次練習(xí)就是一個(gè)實(shí)例,一個(gè)用戶的一次考試也是一個(gè)實(shí)例。
支持預(yù)約開始實(shí)例,在開始之前若用戶嘗試在executor 初始化一個(gè)實(shí)例,就會(huì)報(bào)錯(cuò),當(dāng)時(shí)間到后用戶就可以在創(chuàng)建實(shí)例時(shí)指定的executor 上初始化實(shí)例-executor 從數(shù)據(jù)庫中讀入實(shí)例并運(yùn)行。實(shí)例初始化后用戶就可以在該實(shí)例中進(jìn)行進(jìn)路車輛的各種操作。最后實(shí)例會(huì)被結(jié)束。
在系統(tǒng)的架構(gòu)中,runtime 服務(wù)的作用是實(shí)例運(yùn)行的容器。其提供了實(shí)例運(yùn)行所需要的環(huán)境,一個(gè)容器可以同時(shí)讓多個(gè)實(shí)例在其中運(yùn)行。一個(gè)車站可以創(chuàng)造無限個(gè)實(shí)例,這也是本設(shè)計(jì)通用性的一大體現(xiàn)。
和練習(xí)實(shí)例不同之處在于考試是有考題的。同一場考試無論考試有多少,考題都是相同的。通過班級結(jié)構(gòu),可以在配置考試實(shí)例時(shí)指定班級,系統(tǒng)自動(dòng)為班級所有的學(xué)生創(chuàng)建配置信息完全相同(即開始時(shí)間、結(jié)束時(shí)間、考題、車站等等)的實(shí)例。
正是通過對于考題、車站等配置信息的高效復(fù)用以實(shí)現(xiàn)通用性的。
API 服務(wù)主要負(fù)責(zé)耦合data 層和view層,上承用戶的請求,下接數(shù)據(jù)庫,從數(shù)據(jù)庫讀寫數(shù)據(jù)并呈遞給前端。在API 服務(wù)中,Station 數(shù)據(jù)是最完備的靜態(tài)數(shù)據(jù),其直接來源于用戶的輸入。Station 數(shù)據(jù)直接來源于車站描述文件。API 服務(wù)提供車站、實(shí)例、考試、用戶和班級四個(gè)類型的服務(wù)。在此著重介紹車站。
3.1.1 車站屬性。車站屬性從性質(zhì)上可以分為圖形屬性和邏輯屬性,圖形屬性用于表現(xiàn)層初始化時(shí)正確地渲染出車站底平面圖,邏輯屬性用于Runtime 初始化實(shí)例時(shí)正確地描述車站的拓?fù)潢P(guān)系和耦合邏輯。只需要輸入可以獨(dú)自或和其他屬性一起提供渲染或系統(tǒng)所需信息的車站屬性。也就是一個(gè)車站由完整描述車站的最小屬性集合所描述,一個(gè)車站是由Signal 和Node構(gòu)成的,車站屬性從組件上可分為Signal 屬性和Node 屬性。表1 為Node 的屬性,表2 為Signal 的屬性。
表1 Node 屬性
表2 Signal屬性
3.1.2 車站描述文件。車站屬性并非直接存儲(chǔ)于數(shù)據(jù)庫之中,而是由用戶編寫成車站描述文件,將描述文件存儲(chǔ)在數(shù)據(jù)庫內(nèi)。車站描述文件用于描述車站,即使用上述屬性來定義一個(gè)車站,車站描述文件作為用戶向的輸入,是用戶唯一定義車站的方式。因此,為兼顧可讀性和文件體積需求,采用JSON作為車站的描述語言。
這里給出一個(gè)非典型的車站描述文件作為例子并在注釋中說明上述內(nèi)容,見圖2。
圖2
運(yùn)行時(shí)是供實(shí)例執(zhí)行的運(yùn)行時(shí)環(huán)境,一個(gè)運(yùn)行時(shí)可以執(zhí)行多個(gè)實(shí)例,所有的實(shí)例會(huì)被管理在一個(gè)HashMap 中。實(shí)例在初始化時(shí)被插入該HashMap,在結(jié)束時(shí)移除。
3.2.1 實(shí)例。實(shí)例是運(yùn)行時(shí)中運(yùn)行的基本單位,運(yùn)行時(shí)服務(wù)的含義就是運(yùn)行實(shí)例的服務(wù)。一個(gè)實(shí)例由某個(gè)車站所實(shí)例化而來,在運(yùn)行時(shí)中和表現(xiàn)層可以直接與相應(yīng)的實(shí)例進(jìn)行交互。
3.2.2 狀態(tài)對象。狀態(tài)對象是狀態(tài)機(jī)的組件,由Signal(信號機(jī)狀態(tài)對象),Node(結(jié)點(diǎn)狀態(tài)對象)組成,狀態(tài)對象中保存著相應(yīng)車站信號設(shè)備的實(shí)時(shí)狀態(tài)。
(1)信號狀態(tài)。Signal 中的state 屬性表征信號機(jī)點(diǎn)燈狀態(tài),其可如表3 所列。
表3 信號機(jī)狀態(tài)定義表
(2)節(jié)點(diǎn)狀態(tài)。與信號的狀態(tài)類似,結(jié)點(diǎn)狀態(tài)枚舉參見表4。
表4 軌道區(qū)段狀態(tài)定義
3.2.3 實(shí)例組成。一個(gè)實(shí)例基本由FSM、topo、layout 三個(gè)獨(dú)立的部分構(gòu)成。在實(shí)例初始化時(shí)會(huì)通過Station 信息同時(shí)生成這三個(gè)部分。
(1)topo。topo保存一個(gè)實(shí)例所有的拓?fù)潢P(guān)系,包括車站圖(包含R 關(guān)系和S關(guān)系),并置信號機(jī)映射,差置信號機(jī)映射,以及獨(dú)立按鈕映射,topo能表征一個(gè)實(shí)例的各種組件(信號機(jī)、節(jié)點(diǎn)和按鈕)在聯(lián)鎖邏輯上是如何耦合的。通過topo,運(yùn)行時(shí)可以靜態(tài)地從車站的拓?fù)潢P(guān)系上找到一條可能的進(jìn)路。再通過后續(xù)的判斷,來確定這條可能的進(jìn)路是不是進(jìn)路。
(2)狀態(tài)機(jī)(FSM)。FSM即有限狀態(tài)機(jī),保存了一個(gè)實(shí)例所有的狀態(tài)對象,包括上述的信號機(jī)、節(jié)點(diǎn)和車輛,并且管理整個(gè)車站的狀態(tài)。
(3)布局(Layout)。實(shí)例中的布局對象是車站布局的載荷,即在用戶請求車站布局時(shí)向表示層發(fā)送的車站布局信息。布局在實(shí)例初始化時(shí)會(huì)和狀態(tài)機(jī)同時(shí)生成,在實(shí)例初始化時(shí)同步計(jì)算布局信息并保存,當(dāng)用戶請求時(shí)直接返回布局信息。
3.2.4 獲取實(shí)例信息。用戶能從實(shí)例上取得的信息,有布局信息、考題信息和狀態(tài)信息三種,布局信息和考題信息是靜態(tài)的、一次性的。而狀態(tài)信息是實(shí)時(shí)的,動(dòng)態(tài)的。布局信息用來正確地繪制車站的布局,考題信息用于向用戶下達(dá)考試實(shí)例的題目,狀態(tài)信息用來更新車站上信號設(shè)備的狀態(tài)。布局信息透過布局對象(layout)來傳遞,考試信息通過考試管理器發(fā)送,狀態(tài)信息透過狀態(tài)幀來傳遞。系統(tǒng)的運(yùn)行時(shí),無論在哪一層,布局和狀態(tài)都是無耦合的。這意味著表現(xiàn)層需要單獨(dú)地查詢車站的布局和訂閱實(shí)例狀態(tài)的更新。
3.2.5 實(shí)例初始化與運(yùn)行。無論用戶是想要進(jìn)行前文提到的請求車站布局或更新車站狀態(tài),最大的一個(gè)前提是實(shí)例要處于運(yùn)行狀態(tài)。要想運(yùn)行實(shí)例,用戶需要輸入實(shí)例ID。而后運(yùn)行時(shí)會(huì)通過數(shù)據(jù)訪問層在Instance 表中查找相應(yīng)的實(shí)例。如果未找到,則說明訪問的實(shí)例ID不合法。如果尋到對應(yīng)的實(shí)例,則會(huì)驗(yàn)證實(shí)例的相關(guān)信息:如果訪問實(shí)例的用戶沒有權(quán)限(沒有Guest、Player 或Operator 權(quán)限),則返回forbidden 禁止訪問。若用戶有權(quán)限。那么還需要驗(yàn)證開始時(shí)間。因?yàn)樵诒憩F(xiàn)層,未滿足開始時(shí)間要求的實(shí)例根本不會(huì)渲染開始入口(相關(guān)按鈕)。當(dāng)一切驗(yàn)證完成,運(yùn)行時(shí)便會(huì)將系統(tǒng)反序列化成RawStation 對象,用數(shù)據(jù)庫中查到的實(shí)例信息,和RawStation 對象在運(yùn)行時(shí)中新建實(shí)例。
3.2.6 結(jié)束實(shí)例。結(jié)束實(shí)例分為兩種,自動(dòng)結(jié)束和手動(dòng)結(jié)束。對于考試實(shí)例而言,可以自動(dòng)結(jié)束或手動(dòng)結(jié)束。對于練習(xí)實(shí)例則只能手動(dòng)結(jié)束。對于考試實(shí)例而言,結(jié)束實(shí)例時(shí)會(huì)將考試管理器的問題成績同步至數(shù)據(jù)庫系統(tǒng)中。對于練習(xí)實(shí)例沒有什么額外的操作。
3.2.7 搜索進(jìn)路。在站場中查找路徑中采用了A*算法,將起點(diǎn)和終點(diǎn)輸入,便可能在有向圖R 中找到一條路徑。但這條路徑不一定是我們要找的進(jìn)路,為了使路徑滿足進(jìn)路鏈的定義。還需要保證路徑中的所有結(jié)點(diǎn)都互相沒有S 關(guān)系,即任意兩結(jié)點(diǎn)在S圖中都不存在邊。若滿足這一點(diǎn),則稱這條路徑為“可能的路”。
顯然可能的路比較多,為解決該問題,引入方向約束,方向約束的含義是:對于一條可能進(jìn)路的始/終端方向必須和欲建立進(jìn)路的列車行進(jìn)始/終端方向相同,故而方向約束由兩個(gè)約束構(gòu)成:始端方向約束和終端方向約束。顯然地,欲建立進(jìn)路的列車行進(jìn)始端方向總是始端信號機(jī)的朝向的反向(稱為信號機(jī)的防護(hù)方向),在查找進(jìn)路時(shí)我們把站場圖中尋到的路徑成為可能進(jìn)路。一條可能進(jìn)路的始終端方向必須同時(shí)滿足始端方向約束和終端方向約束,那么這條可能進(jìn)路才能成為進(jìn)路。
web 端以deno 為服務(wù)器,使用Apollo提供的上下文包裝器和ReactHook 來進(jìn)行GraphQL通信。主要包括主頁面、車站列表頁面和車站頁面等。
3.3.1 主頁面。主頁面分上下兩部分,上部分為目前最新的實(shí)例信息,下部分為本周的實(shí)例統(tǒng)計(jì)。本頁面會(huì)檢索到數(shù)據(jù)庫中所有的實(shí)例,并以表格的形式、以開始時(shí)間排序,顯示在最新實(shí)例信息中。
3.3.2 車站列表頁面。本頁面中會(huì)查詢所有的車站,并顯示其簡要信息:名稱、作者、創(chuàng)建時(shí)間。如果某個(gè)車站是草稿(draft)則只有作者和管理員能看到該車站。
3.3.3 車站頁面。本頁面是車站的詳細(xì)信息頁面,其中展示了該這站的所有信息。包括車站簡介、創(chuàng)建時(shí)間、修改時(shí)間、作者、是否為草稿,以及車站描述文件。其中車站描述文件采用了可交互的顯示,為JSON增加了代碼高亮、以及層次展開功能。
用戶需要從本頁面新建實(shí)例,點(diǎn)擊本頁面上的新建實(shí)例按鈕或新建考試按鈕,彈出對話框在對話框中輸入實(shí)例名稱、注釋(介紹),選擇實(shí)例的運(yùn)行時(shí)和用戶。如此可以創(chuàng)建新實(shí)例(圖3)。
圖3 車站頁面
該系統(tǒng)實(shí)現(xiàn)了自定義車站、多人參與培訓(xùn)等功能,既能對站場進(jìn)行仿真,同時(shí)還能反映現(xiàn)場設(shè)備狀態(tài),并需要隨著站場改建的同時(shí)可做出相應(yīng)修改和部署,實(shí)施成本較低。
采用純web 技術(shù)讓計(jì)算機(jī)聯(lián)鎖系統(tǒng)不再掣肘于空間與時(shí)間,學(xué)生可以處處進(jìn)行計(jì)算機(jī)聯(lián)鎖的仿真學(xué)習(xí)。降低學(xué)習(xí)成本,提升學(xué)習(xí)效率。擺脫了硬件仿真,則教學(xué)系統(tǒng)可以幾近于零成本地部署在各處的服務(wù)器上,降低了安裝部署的成本。因此計(jì)算機(jī)聯(lián)鎖邏輯結(jié)合網(wǎng)絡(luò)技術(shù)的應(yīng)用,在計(jì)算機(jī)聯(lián)鎖培訓(xùn)領(lǐng)域內(nèi)是十分重要的發(fā)展方向。