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