夏繼強(qiáng), 董彥威, 王帆
(北京航空航天大學(xué) 機(jī)械工程及自動(dòng)化學(xué)院 ,北京 100191)
目前,我國(guó)已經(jīng)成為世界上第一大機(jī)床產(chǎn)銷(xiāo)國(guó),但是由于高檔數(shù)控機(jī)床可靠性方面的差距,導(dǎo)致國(guó)產(chǎn)高檔數(shù)控系統(tǒng)和機(jī)床在市場(chǎng)競(jìng)爭(zhēng)中處于劣勢(shì),由于缺乏批量的第三方數(shù)據(jù),嚴(yán)重阻礙了對(duì)國(guó)產(chǎn)數(shù)控系統(tǒng)可靠性的研究[1]。目前我國(guó)對(duì)于數(shù)控系統(tǒng)數(shù)據(jù)采集的研究大多是通過(guò)有線(xiàn)的方式進(jìn)行,主要是為了實(shí)現(xiàn)車(chē)間信息聯(lián)網(wǎng),這種方式要求在復(fù)雜的工廠環(huán)境中進(jìn)行布線(xiàn),安裝本地服務(wù)器等一些列配套設(shè)備,方案實(shí)施復(fù)雜,成本高[2]。為了實(shí)現(xiàn)便捷采集,選用Android系統(tǒng)作為開(kāi)發(fā)平臺(tái),運(yùn)用4G移動(dòng)網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)發(fā)送,并通過(guò)數(shù)控系統(tǒng)基于TCP/IP協(xié)議的DNC接口采集數(shù)據(jù)[3]。這種嵌入式無(wú)線(xiàn)采集方案具有更多優(yōu)勢(shì):?jiǎn)闻_(tái)采集終端自成一套系統(tǒng),可自主完成數(shù)據(jù)采集和發(fā)送任務(wù),配置靈活,適合復(fù)雜工況下進(jìn)行數(shù)據(jù)采集;采用4G無(wú)線(xiàn)傳輸,降低了機(jī)床地理位置約束,可以實(shí)現(xiàn)分布式采集;將數(shù)據(jù)采集協(xié)議封裝到.so動(dòng)態(tài)庫(kù)中,更安全,且移植方便[4-6]。
系統(tǒng)主要由數(shù)控設(shè)備、嵌入式采集終端、服務(wù)器和數(shù)據(jù)庫(kù)組成,采用C/S架構(gòu),結(jié)構(gòu)如圖1所示。采集終端直接與數(shù)控系統(tǒng)支持TCP/IP協(xié)議的DNC接口連接,機(jī)床通信API(Application Programming Interface)以C++語(yǔ)言實(shí)現(xiàn),并封裝到.so動(dòng)態(tài)庫(kù)中,數(shù)據(jù)采集軟件通過(guò)Android JNI(Java Native Interface)接口調(diào)用.so庫(kù)中本地代碼完成數(shù)據(jù)采集,把采集到的數(shù)據(jù)存到本地SQLite數(shù)據(jù)庫(kù),同時(shí)把數(shù)據(jù)以JSON格式通過(guò)4G網(wǎng)絡(luò)發(fā)送的遠(yuǎn)端服務(wù)器,服務(wù)器接收并校驗(yàn)通過(guò)后,保存到數(shù)據(jù)庫(kù)。
圖1 信息采集系統(tǒng)總體框架
嵌入式采集終端采用Freescale Cortex-A9四核處理器,內(nèi)置Android 4.4原生系統(tǒng),支持USB2.0、RS485、以太網(wǎng)等輸入輸出接口,搭載WiFi模塊和華為4G全網(wǎng)通移動(dòng)通信模塊。
采集機(jī)床的數(shù)據(jù)種類(lèi)主要包括:報(bào)警信息、報(bào)警時(shí)間、進(jìn)給軸指令位置、實(shí)際位置、轉(zhuǎn)速、負(fù)載電流、G代碼模態(tài)、開(kāi)機(jī)時(shí)間和運(yùn)行時(shí)長(zhǎng)等,能夠全面反映機(jī)床的運(yùn)行狀態(tài)。
圖2 嵌入式采集終端軟件架構(gòu)
Android數(shù)據(jù)采集軟件要求同步實(shí)現(xiàn)數(shù)據(jù)的采集和發(fā)送功能,由于4G信號(hào)強(qiáng)弱會(huì)有波動(dòng),存在數(shù)據(jù)采集和發(fā)送速率不匹配問(wèn)題,為了能夠連續(xù)、穩(wěn)定地采集數(shù)據(jù),不造成數(shù)據(jù)丟失,數(shù)據(jù)采集軟件采用了多線(xiàn)程架構(gòu),如圖2所示。數(shù)據(jù)采集軟件有三個(gè)線(xiàn)程,包括一個(gè)主線(xiàn)程和兩個(gè)子線(xiàn)程,并使用了SQLite數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)緩存。數(shù)據(jù)采集服務(wù)運(yùn)行于Android UI主線(xiàn)程,由開(kāi)機(jī)廣播接收者啟動(dòng),實(shí)現(xiàn)開(kāi)機(jī)自啟。數(shù)據(jù)采集線(xiàn)程把采集到的數(shù)據(jù)通過(guò)線(xiàn)程間通信發(fā)送給主線(xiàn)程的數(shù)據(jù)采集服務(wù),數(shù)據(jù)采集服務(wù)對(duì)數(shù)據(jù)進(jìn)行過(guò)濾、封裝處理,并保存到本地SQLite數(shù)據(jù)庫(kù)。與此同時(shí)數(shù)據(jù)發(fā)送線(xiàn)程不斷地檢測(cè)SQLite數(shù)據(jù)庫(kù)中是否有數(shù)據(jù)需要發(fā)送,如果有,則把數(shù)據(jù)取出,直接通過(guò)4G網(wǎng)絡(luò)發(fā)送給遠(yuǎn)端服務(wù)器。兩個(gè)線(xiàn)程獨(dú)立工作,互不干擾。
數(shù)據(jù)采集軟件主線(xiàn)程的數(shù)據(jù)采集服務(wù),主要負(fù)責(zé)協(xié)調(diào)數(shù)據(jù)采集子線(xiàn)程和網(wǎng)絡(luò)傳輸子線(xiàn)程工作,對(duì)整個(gè)軟件起調(diào)度和管理的作用,Android 服務(wù)無(wú)需為用戶(hù)提供操作界面,并且能夠長(zhǎng)時(shí)間在后臺(tái)運(yùn)行,占用系統(tǒng)資源少。數(shù)據(jù)采集服務(wù)開(kāi)機(jī)自啟,在服務(wù)中分別開(kāi)啟數(shù)據(jù)采集和發(fā)送子線(xiàn)程。
數(shù)據(jù)采集子線(xiàn)程通過(guò)JNI接口調(diào)用.so動(dòng)態(tài)庫(kù)中的通信API采集數(shù)控系統(tǒng)的運(yùn)行數(shù)據(jù),并把采集到的數(shù)據(jù)封裝成數(shù)據(jù)對(duì)象,通過(guò)Handler異步消息傳遞給主線(xiàn)程服務(wù)。數(shù)據(jù)采集使用基于Socket的TCP/IP協(xié)議,機(jī)床作為服務(wù)端,采集終端作為客戶(hù)端。主線(xiàn)程對(duì)數(shù)據(jù)進(jìn)行分類(lèi)、校驗(yàn)、過(guò)濾,保存到本地SQLite數(shù)據(jù)庫(kù)。SQLite數(shù)據(jù)庫(kù)是Android系統(tǒng)自帶的一個(gè)微型數(shù)據(jù)庫(kù)[7],數(shù)據(jù)庫(kù)本身是安全的,程序中使用單例模式,保證了數(shù)據(jù)讀/寫(xiě)安全。
使用SQLite數(shù)據(jù)庫(kù)進(jìn)行數(shù)據(jù)緩存,這樣有效解決了數(shù)據(jù)的采集和發(fā)送速率不匹配的問(wèn)題,特別是在網(wǎng)絡(luò)狀態(tài)不佳的情況下,依然能夠保持?jǐn)?shù)據(jù)采集線(xiàn)程不受干擾,SQLite數(shù)據(jù)庫(kù)有3 GB容量,可容納至少兩周的數(shù)據(jù)量,保證采集到的數(shù)據(jù)不丟失,等網(wǎng)絡(luò)狀況恢復(fù)之后繼續(xù)發(fā)送。
網(wǎng)絡(luò)傳輸子線(xiàn)程的主要任務(wù)是把采集到的數(shù)據(jù)通過(guò)4G移動(dòng)網(wǎng)絡(luò)發(fā)送到遠(yuǎn)程服務(wù)器,使用HTTP(HyperText Transfer Protocol)超文本傳輸協(xié)議。網(wǎng)絡(luò)傳輸子線(xiàn)程循環(huán)檢測(cè)本地SQLite數(shù)據(jù)庫(kù)中是否有可發(fā)送數(shù)據(jù),如果有數(shù)據(jù)需要發(fā)送,將數(shù)據(jù)轉(zhuǎn)化為Json格式發(fā)送給遠(yuǎn)程服務(wù)器,收到服務(wù)器的確認(rèn)信息后,從SQLite數(shù)據(jù)庫(kù)中刪除該條數(shù)據(jù)[8-9]。
Android是一款以L(fǎng)inux為核心的開(kāi)源操作系統(tǒng)[10],Android操作系統(tǒng)的框架如圖3所示。因?yàn)锳ndroid平臺(tái)的底層是用C/C++寫(xiě)的核心庫(kù)函數(shù)與Linux內(nèi)核,所以在理論上可以運(yùn)行C/C++代碼[11]。
圖3 Android系統(tǒng)架構(gòu)
Android NDK是一套工具集合,允許開(kāi)發(fā)者能夠使用C/C++語(yǔ)言實(shí)現(xiàn)Android應(yīng)用程序的功能,而在NDK開(kāi)發(fā)過(guò)程使用JNI機(jī)制實(shí)現(xiàn)Java語(yǔ)言與C/C++語(yǔ)言中函數(shù)的相互調(diào)用。Android NDK將開(kāi)發(fā)者編寫(xiě)的C/C++代碼編譯成能夠被Linux內(nèi)核加載執(zhí)行的動(dòng)態(tài)庫(kù)(后綴名為so),開(kāi)發(fā)者可以通過(guò)JNI接口在Java代碼中調(diào)用這個(gè)動(dòng)態(tài)庫(kù)中的C/C++函數(shù)。這個(gè)庫(kù)文件也被打包到最終的應(yīng)用程序安裝包中[12-13]。
雖然機(jī)床廠商提供了數(shù)據(jù)采集動(dòng)態(tài)庫(kù),庫(kù)中封裝了與數(shù)控系統(tǒng)通信的數(shù)據(jù),但是庫(kù)里面的C/C++函數(shù)并不滿(mǎn)足JNI規(guī)則,因此Android Javanative函數(shù)無(wú)法直接調(diào)用庫(kù)中的API。此外,庫(kù)里面的大多數(shù)函數(shù)在執(zhí)行之后返回值指針,而在Android中是沒(méi)有指針概念的,自然也無(wú)法讀取指針類(lèi)型數(shù)據(jù)的具體內(nèi)容。
圖4 DNC動(dòng)態(tài)庫(kù)二次開(kāi)發(fā)方案
為了解決以上兩個(gè)問(wèn)題,決定在原有動(dòng)態(tài)庫(kù)的基礎(chǔ)上進(jìn)行二次開(kāi)發(fā)。在原動(dòng)態(tài)庫(kù)中函數(shù)不滿(mǎn)足JNI機(jī)制的情況下,Android程序無(wú)法直接調(diào)用,但是C/C++函數(shù)調(diào)用原動(dòng)態(tài)庫(kù)的函數(shù)時(shí)卻不必遵守JNI機(jī)制,針對(duì)這一特點(diǎn)本文提出了如圖4所示的解決方案:開(kāi)發(fā)一個(gè)符合JNI規(guī)則的新動(dòng)態(tài)庫(kù),通過(guò)新庫(kù)中的本地代碼調(diào)用原動(dòng)態(tài)庫(kù)中的接口函數(shù),由于新庫(kù)中的函數(shù)符合JNI機(jī)制,能夠和Javanative函數(shù)建立一對(duì)一映射關(guān)系,這樣就能實(shí)現(xiàn)在Java函數(shù)層間接調(diào)用原動(dòng)態(tài)庫(kù)中接口函數(shù)的目的,這也是能夠?qū)崿F(xiàn)機(jī)床數(shù)據(jù)采集的關(guān)鍵。
開(kāi)發(fā)新動(dòng)態(tài)庫(kù),首先要建一個(gè)Java類(lèi)來(lái)封裝用于與機(jī)床通信的函數(shù),這些函數(shù)必須用“native”關(guān)鍵字修飾,表明該函數(shù)是通過(guò)本地代碼實(shí)現(xiàn)的。代碼格式下所示,只需要聲明函數(shù)參數(shù)類(lèi)型、返回值類(lèi)型,沒(méi)有函數(shù)體。
public staticnativeint GSKRM_Initialization(String addr,int port);
然后,在C文件中,用C/C++代碼實(shí)現(xiàn)Java代碼中聲明的native函數(shù),在函數(shù)體中調(diào)用原動(dòng)態(tài)庫(kù)接口函數(shù),代碼格式如下所示,函數(shù)名前必須有關(guān)鍵字“JNIEXPORT”和“JNICALL”,這是JNI機(jī)制規(guī)定的格式,表示該函數(shù)與Java中的native函數(shù)有對(duì)應(yīng)關(guān)系。函數(shù)前兩個(gè)是默認(rèn)參數(shù),“JNIEnv”表示JNI運(yùn)行環(huán)境指針,通過(guò)該指針可以調(diào)用JNI工具函數(shù),“jobject”表示調(diào)用該函數(shù)的java對(duì)象,通過(guò)該參數(shù)可以使用Java反射機(jī)制在C/C++代碼中調(diào)用Java對(duì)象,其他參數(shù)為Javanative函數(shù)原有參數(shù)。
JNIEXPORTjintJNICALL//函數(shù)C++實(shí)現(xiàn)
Java__GSKNativeApi_GSKRM_1Initialization
(JNIEnv * env,
jobject obj,
jstring ipaddr, jint port){
//函數(shù)體,調(diào)用原動(dòng)態(tài)庫(kù)中接口函數(shù)
}
當(dāng)兩個(gè)層函數(shù)完成之后,需要把這兩層函數(shù)建立一對(duì)一的映射關(guān)系,這樣調(diào)用Java類(lèi)的native函數(shù)才會(huì)映射到本地代碼層函數(shù)。這種使用新動(dòng)態(tài)庫(kù)調(diào)用原動(dòng)態(tài)庫(kù)的方案不僅可以解決無(wú)法直接調(diào)用的難題,還能夠?qū)崿F(xiàn)數(shù)據(jù)格式轉(zhuǎn)化,JNI機(jī)制提供了完整數(shù)據(jù)格式轉(zhuǎn)化方法。
使用Tomcat搭建數(shù)據(jù)服務(wù)器,數(shù)據(jù)保存到Mysql數(shù)據(jù)庫(kù),并為服務(wù)器配備了公網(wǎng)IP地址,數(shù)據(jù)可以通過(guò)4G直接發(fā)送到數(shù)據(jù)服務(wù)器。按照?qǐng)D1所示的整體技術(shù)方案部署好整個(gè)系統(tǒng),開(kāi)始驗(yàn)證系統(tǒng)的功能,系統(tǒng)驗(yàn)證結(jié)果如圖5所示。
圖5為注冊(cè)信息表內(nèi)容,注冊(cè)信息主要記錄機(jī)床的特征信息,其中:“id”表示數(shù)控系統(tǒng)ID號(hào);“tp”表示數(shù)控系統(tǒng)型號(hào);“ver”表示版本號(hào);“time”表示時(shí)間。
圖6為運(yùn)行信息表內(nèi)容,運(yùn)行信息主要記錄機(jī)床加工過(guò)程中各軸的參數(shù)信息以及G代碼執(zhí)行信息等,主要反映機(jī)床的運(yùn)行狀態(tài),其中:“cas”表示主軸實(shí)際轉(zhuǎn)速;“ccs”表示主軸指令轉(zhuǎn)速;“aload”表示主軸負(fù)載電流;“aspdx”表示進(jìn)給軸實(shí)際轉(zhuǎn)速;“apstx”表示進(jìn)給軸實(shí)際位置;“cpstx”表示進(jìn)給軸指令位置;“l(fā)oadx”表示進(jìn)給軸負(fù)載電流。信息采集系統(tǒng)會(huì)周期性采集數(shù)控系統(tǒng)的運(yùn)行信息。
圖5 注冊(cè)信息表數(shù)據(jù)內(nèi)容
圖6 運(yùn)行信息表數(shù)據(jù)內(nèi)容
通過(guò)對(duì)信息采集系統(tǒng)進(jìn)行測(cè)試,驗(yàn)證了整個(gè)信息采集系統(tǒng)的功能,數(shù)據(jù)采集穩(wěn)定,網(wǎng)絡(luò)傳輸適應(yīng)性較高,信息采集系統(tǒng)滿(mǎn)足了設(shè)計(jì)之初提出的要求。
基于Android嵌入式平臺(tái)采集系統(tǒng)的設(shè)計(jì)使得對(duì)數(shù)控系統(tǒng)進(jìn)行數(shù)據(jù)采集更加便捷、高效,使用了Android軟件開(kāi)發(fā)的多項(xiàng)技術(shù),軟件功能更強(qiáng),開(kāi)發(fā)效率更高,Android NDK展示了Android 平臺(tái)強(qiáng)大的兼容性。利用4G網(wǎng)絡(luò)高帶寬、覆蓋廣的優(yōu)勢(shì),數(shù)據(jù)傳輸更加便捷,實(shí)現(xiàn)了數(shù)控系統(tǒng)可靠性數(shù)據(jù)的多地域、分布式采集功能。