遲 穎,何 杰,耿 斌,周 剛,張 楊
(1.中國環(huán)境監(jiān)測總站,北京 100012;2.光大城鄉(xiāng)再生能源(淮安)有限公司,江蘇 淮安 223001;3.南京柯普士儀器科技有限公司,江蘇 南京 210012)
隨著網(wǎng)絡(luò)技術(shù)的不斷發(fā)展,移動(dòng)應(yīng)用端越來越多地被人們認(rèn)可,Android平臺(tái)所開發(fā)的APP應(yīng)用軟件更是被應(yīng)用到了各個(gè)場合。由于工業(yè)控制領(lǐng)域具有特殊性,考慮到其穩(wěn)定性、安全性、復(fù)雜性,一直少有相關(guān)方面的應(yīng)用。積極開展移動(dòng)設(shè)備在工業(yè)控制方面的應(yīng)用,在未來5G平臺(tái)下,將有非常廣闊的前景[1]。
連續(xù)排放氣態(tài)污染物監(jiān)測系統(tǒng)(Continuous Emission Monitoring System,CEMS),應(yīng)用于垃圾發(fā)電企業(yè)的煙氣監(jiān)測,為核對(duì)該系統(tǒng)的數(shù)據(jù)準(zhǔn)確性,企業(yè)需要接受各級(jí)主管部門比對(duì)檢查。受委托的檢測機(jī)構(gòu)持便攜式檢測儀進(jìn)行采樣比對(duì),會(huì)涉及兩套系統(tǒng)數(shù)據(jù)的對(duì)比,對(duì)比工作的流程如下:(1)同步。同步兩套系統(tǒng)的時(shí)間;(2)采集。在線實(shí)時(shí)采集數(shù)據(jù);(3)比對(duì)。比對(duì)兩套系統(tǒng)同一時(shí)間段內(nèi)的各項(xiàng)數(shù)據(jù)。由于兩套系統(tǒng)的輸出設(shè)備(數(shù)據(jù)顯示終端)距離較遠(yuǎn),一方在0 m層的分析小屋內(nèi),另一方在煙囪約35 m處的采樣口,數(shù)據(jù)的實(shí)時(shí)核對(duì)必須兩地要有人員通過通信工具進(jìn)行有效溝通。探討拉近一端數(shù)據(jù),實(shí)現(xiàn)單人單地即時(shí)比對(duì),提高工作效率,減少人員數(shù)量,具有顯著的效果。
Modbus是一種通信協(xié)議,廣泛應(yīng)用于工業(yè)控制領(lǐng)域各個(gè)系統(tǒng)間,其協(xié)議版本較常見的有串口和以太網(wǎng)兩大類,是一個(gè)主站master/從站slave架構(gòu)的協(xié)議。基于該協(xié)議的設(shè)備之間進(jìn)行互連互通,首先,要確定主站與從站。根據(jù)協(xié)議約定,Modbus協(xié)議中主從站的關(guān)系為一對(duì)多型,即主站只能有一臺(tái),而從站可以擁有地址范圍在0~247(其中0為廣播地址)的多臺(tái)設(shè)備(通信點(diǎn)),主站發(fā)出數(shù)據(jù)請(qǐng)求消息(查詢代碼),從站對(duì)主站發(fā)送的命令做出響應(yīng)。主站接收從站響應(yīng)過來的數(shù)據(jù),完成一次數(shù)據(jù)通信。
Modbus RTU與Modbus TCP同屬于Modbus通信協(xié)議,但RTU通信更多地在傳輸介質(zhì)上采用雙絞線、光纖,同時(shí),以二進(jìn)制數(shù)據(jù)方式直接傳送數(shù)據(jù),而TCP通信采用的傳輸介質(zhì)更多的是常見的網(wǎng)線,也可以通過無線傳輸,將每字節(jié)二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為固定兩位16進(jìn)制字符串,再依次串聯(lián)在一起,以TCP碼形式進(jìn)行數(shù)據(jù)傳送?,F(xiàn)場的工業(yè)應(yīng)用中,常見于RTU轉(zhuǎn)TCP的應(yīng)用,以便于搭載網(wǎng)絡(luò)通信[2]。
OSI開放系統(tǒng)互連參考模型,定位于應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層就是Socket通信接口,將復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面。Socket的服務(wù)端(Server)建立服務(wù)傾聽socket,同時(shí),等待并接收請(qǐng)求,Socket的客戶端(Client)創(chuàng)建連接socket向服務(wù)端發(fā)送請(qǐng)求,此時(shí),服務(wù)端接收到客戶端的請(qǐng)求創(chuàng)建連接socket。通信時(shí),客戶端OutputStrean輸出流到服務(wù)端輸入InputStream,服務(wù)端OutputStream輸出流到客戶端的輸入流InputStream。結(jié)束通信只需要關(guān)閉雙方的socket即可。依靠該協(xié)議,Modbus的通信可以搭建完成一個(gè)數(shù)據(jù)交互的鏈接,完成雙方的通信過程。
Android平臺(tái)的通信基于無線網(wǎng)絡(luò)技術(shù),通信網(wǎng)絡(luò)可以是基于路由器的互聯(lián)網(wǎng),可以借助于互聯(lián)網(wǎng)實(shí)現(xiàn)數(shù)據(jù)的超遠(yuǎn)距離訪問;也可以是基于AP熱點(diǎn)的點(diǎn)對(duì)點(diǎn)的網(wǎng)絡(luò)(或者藍(lán)牙方式),可以在有限定的條件下確保數(shù)據(jù)安全的訪問。
系統(tǒng)分為三大模塊:(1)系統(tǒng)配置模塊,用于配置和存儲(chǔ)通信用IP地址、端口號(hào)、數(shù)據(jù)地址、數(shù)據(jù)長度、數(shù)據(jù)內(nèi)容等信息,并保存在本地?cái)?shù)據(jù)庫中,以備下次應(yīng)用時(shí)直接使用。(2)柱狀圖顯示模塊,清晰、直觀地顯示可以實(shí)時(shí)比對(duì)各組分在同一時(shí)間內(nèi)的差異。(3)折線圖顯示模塊,根據(jù)實(shí)際現(xiàn)場的比對(duì)需求,可以定義折線圖的采集時(shí)間間隔和采集數(shù)據(jù)量,折線圖針對(duì)單一組分的總體趨勢具有很好的顯示效果,增加了計(jì)算平均值、最大值和最小值的功能,完全貼合現(xiàn)場所要參比的數(shù)據(jù)。
系統(tǒng)的硬件搭配:現(xiàn)場數(shù)據(jù)的采集,需要通過CEMS系統(tǒng)自帶的modbus協(xié)議端口進(jìn)行二次打包轉(zhuǎn)發(fā),一般為PLC通信口。為實(shí)現(xiàn)無線組網(wǎng)通信,還必須將雙方置于該網(wǎng)絡(luò)環(huán)境中,本研究采用西門子S7-200 SMART SR40 CPU模塊卡,485通信端口直接連接了一款串口轉(zhuǎn)無線WiFi的工業(yè)通信設(shè)備,在配置時(shí)采用默認(rèn)的AP模式,設(shè)置好串口協(xié)議、AP熱點(diǎn)狀態(tài)下所需要的通信IP和端口,完成硬件配置[3]。
數(shù)據(jù)庫以原始DB數(shù)據(jù)庫為基礎(chǔ),單獨(dú)一個(gè)配置界面(見圖1),用以存儲(chǔ)、更改、調(diào)用通信所涉及的各項(xiàng)參數(shù)。為適配現(xiàn)場的無線通信設(shè)備,增加了通信方式的選擇,在選擇Serial串口方式通信時(shí),只是代表該通信查詢代碼是以RTU方式發(fā)送的16進(jìn)制字符串,該字符串查詢代碼以及返回的數(shù)據(jù)代碼不同于TCP/IP格式,需要注意的是該方式并不表示要去接一個(gè)真正的串口。
圖1 配置界面
Android平臺(tái)下,以手機(jī)為適配機(jī),需要做Modbus主機(jī)的響應(yīng)機(jī)制。根據(jù)協(xié)議規(guī)定,以傳送8個(gè)有效浮點(diǎn)數(shù)據(jù)為例,發(fā)送16進(jìn)制的查詢代碼:00 01 00 00 00 06 02 03 00 00 00 10,其中,02表示為從站號(hào)是2,03表示modbus功能碼03,即讀取保持寄存器地址,10表示是查詢的數(shù)據(jù)長度為十進(jìn)制的16。將其定義為一個(gè)byte字節(jié)數(shù)組發(fā)送出去,客戶端響應(yīng)該查詢得到的也是一個(gè)16進(jìn)制的字符串:00 01 00 00 00 23 02 03 20 00 00 40 00 00 00 40 40 00 00 40 A0 00 00 40 E0 00 00 41 00 00 00 41 40 00 00 40 40 00 00 42 84,其中,20表示是后面的數(shù)據(jù)長度為10進(jìn)制的32個(gè),是實(shí)際的數(shù)據(jù)內(nèi)容。
在獲取返回的數(shù)據(jù)串后,需要進(jìn)行數(shù)據(jù)的轉(zhuǎn)換,將其轉(zhuǎn)換為浮點(diǎn)數(shù)。Modbus浮點(diǎn)數(shù)的存儲(chǔ)格式為SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM,S是符號(hào)位,1表示負(fù)值;EEE EEEE E表示為指數(shù)冪;MMM MMMM MMMM MMMM MMMM MMMM表示為數(shù)據(jù)位,該數(shù)據(jù)位缺省了1.需要補(bǔ)上。此時(shí),小數(shù)位可以按指數(shù)調(diào)整:得到一個(gè)負(fù)的指數(shù)就向左移動(dòng)小數(shù)點(diǎn),得到一個(gè)正的指數(shù)向右移動(dòng)小數(shù)點(diǎn)。算出小數(shù)點(diǎn)左邊和小數(shù)點(diǎn)右邊的數(shù),最后得到該浮點(diǎn)數(shù)。
核心代碼:
StringbinStr = hex2Bin(hexstr);
Stringsign = binStr.substring(0, 1);
Stringex = binStr.substring(1, 9);
int exint = Integer.parseInt(ex, 2);
Stringmdatastr = binStr.substring(9);
int movebit = exint - 127;
StringBuffersb = new StringBuffer();
for (int i = 0; i < 23; i++) {
if (i == movebit)
sb.append(".");
char b = mdatastr.charAt(i);
sb.append(b);
}
Stringaddstr = "1" + sb.toString();
int sint = addstr.indexOf(".") - 1;
Doubledoublevalue = 0.0d;
for (int i = 0; i < addstr.length(); i++) {
if (addstr.charAt(i) == '.')
continue;
Doubledtmp = Math.pow(2, sint);
int itmp = Integer.valueOf(addstr.charAt(i) + "");
dtmp = dtmp * itmp;
sint = sint - 1;
doublevalue = doublevalue + dtmp;
}
if (sign.equals("1")) {
doublevalue = 0 - doublevalue;
}
}
以上轉(zhuǎn)換如果得不到實(shí)際對(duì)應(yīng)的數(shù)值,那就應(yīng)該考慮浮點(diǎn)數(shù)據(jù)的翻轉(zhuǎn)。按照數(shù)據(jù)存儲(chǔ)的約定:字節(jié)順序模式分為大端數(shù)據(jù)模式和小端數(shù)據(jù)模式,是根據(jù)數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式來區(qū)分的。小端字節(jié)順序的數(shù)據(jù)存儲(chǔ)模式是按內(nèi)存增大的方向存儲(chǔ)的,即低位在前高位在后;大端字節(jié)順序的數(shù)據(jù)存儲(chǔ)方向恰恰相反,即高位在前,低位在后。據(jù)此,只需要重新排列一下一個(gè)浮點(diǎn)數(shù)所占用兩個(gè)寄存器地址位的前后順序,就可以完成數(shù)據(jù)翻轉(zhuǎn)。
柱狀圖表的顯示比文字更具有簡潔性,也更加直觀,具體如圖2所示。將讀取到的遠(yuǎn)端數(shù)據(jù)以圖表的形式呈現(xiàn)出來,應(yīng)用MPAndroidChart的柱狀圖顯示功能,引入該控件的com.github.mikephil.charting.charts.BarChart包,對(duì)其X軸Y軸進(jìn)行自定義,同時(shí),增加一個(gè)以時(shí)間為刷新內(nèi)容的描述項(xiàng)。核心代碼如下:
x軸的定義
xAxis.setValueFormatter (new ValueFormatter () {
private String[] xStrs = new String[]{"CO", "HCL", "NO", "NO2", "SO2", "H2O", "Temp", "FlOW"};
@Override
public String getFormattedValue(float value) {
int position = (int) value;
if (position >= 8) {
position = 0;
}
return xStrs[position];
}
});
時(shí)間描述
Description description = new Description ();
description.setEnabled (true);
t = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss");
description.setText (t.format (new Date ()));
chart.setDescription (description);
圖2 柱狀圖表的顯示
相較于柱狀圖,折線圖可以突出一組數(shù)據(jù)的變化趨勢,將各組數(shù)據(jù)以不同的顏色標(biāo)注出,既可以單組數(shù)據(jù)顯示,又可以多組數(shù)據(jù)比對(duì)顯示,實(shí)際第三方比對(duì)數(shù)據(jù)時(shí)常常會(huì)取一個(gè)時(shí)間段內(nèi)的數(shù)據(jù),以下拉框選擇的方式將所需時(shí)間段以及數(shù)據(jù)量展現(xiàn)出來,減少人工輸入錯(cuò)誤,具體如圖3所示。應(yīng)用引入控件的com.github.mikephil.charting.charts.LineChart包,對(duì)其X軸Y軸進(jìn)行自定義,同時(shí),增加一個(gè)數(shù)據(jù)點(diǎn)位的標(biāo)記,用以記錄該條數(shù)據(jù)的詳細(xì)信息:當(dāng)前組分名稱、當(dāng)前數(shù)值、總采集數(shù)、當(dāng)前條數(shù)、平均值、最大值、最小值。核心代碼如下:
java.util.Set
String valName = entry.getKey ().trim ();
switch (valName) {
case "co":
coMax = (Double) Collections.max ((List) entry.getValue ());
coMin = (Double) Collections.min ((List) entry.getValue ());
coAverage = getAverage ((List) entry.getValue (), xCount);
break;
case "hcl":
……
}
}
采用java.util.Set
圖3 折線圖顯示
該客戶端應(yīng)用APP主要基于無線通信,網(wǎng)絡(luò)質(zhì)量好壞直接影響數(shù)據(jù)的傳輸,實(shí)際使用過程中,采用了點(diǎn)對(duì)點(diǎn)的通信方式,數(shù)據(jù)刷新周期為每30 s一次,完全可以滿足現(xiàn)場通信監(jiān)控比對(duì)的需求。工業(yè)現(xiàn)場端Modbus通信是常規(guī)通信協(xié)議,無論是集控室DCS端,還是現(xiàn)場儀表端,都有此類接口,在確保數(shù)據(jù)安全的情況下,充分利用此類接口與移動(dòng)端對(duì)接,提高了整體的工作質(zhì)量和效率,具有極大的實(shí)用價(jià)值。