議的在線監(jiān)控網(wǎng)關(guān)方案:從輪詢機(jī)制到數(shù)據(jù)采集實(shí)踐)
先別急著談技術(shù)選型說(shuō)說(shuō)我當(dāng)時(shí)為什么一定要做這個(gè)基于Modbus的在線監(jiān)控網(wǎng)關(guān)方案。工廠改造那陣子現(xiàn)場(chǎng)設(shè)備品牌雜得很PLC有西門(mén)子的、臺(tái)達(dá)的儀表有七八種不同協(xié)議的變頻器更是國(guó)產(chǎn)進(jìn)口混著來(lái)。你要是每個(gè)設(shè)備單獨(dú)拉一套監(jiān)控軟件光驅(qū)動(dòng)就夠你喝一壺的。但也別慌這些設(shè)備里絕大多數(shù)都留了一個(gè)統(tǒng)一的“后門(mén)”——Modbus通訊接口。不管是RS485走M(jìn)odbus RTU還是網(wǎng)口走M(jìn)odbus TCP只要把這個(gè)口子利用好就能用一個(gè)網(wǎng)關(guān)把所有設(shè)備的數(shù)據(jù)統(tǒng)一采集上來(lái)再轉(zhuǎn)發(fā)到上層監(jiān)控平臺(tái)。我做的這個(gè)方案本質(zhì)上就是一臺(tái)邊緣計(jì)算網(wǎng)關(guān)加一套數(shù)據(jù)采集轉(zhuǎn)發(fā)服務(wù)用Modbus協(xié)議把分散在各車(chē)間的設(shè)備數(shù)據(jù)匯聚起來(lái)再通過(guò)MQTT或者HTTP接口推到在線監(jiān)控平臺(tái)。這套方案解決的最大痛點(diǎn)就是不用挨個(gè)設(shè)備找廠商要私有協(xié)議不用給每臺(tái)設(shè)備單獨(dú)配上位機(jī)軟件一套網(wǎng)關(guān)通吃現(xiàn)場(chǎng)所有帶Modbus接口的設(shè)備。文章的后半部分我會(huì)把協(xié)議適配、輪詢策略、數(shù)據(jù)建模、斷線重連這些核心細(xì)節(jié)全部拆開(kāi)講包括參數(shù)怎么定、坑在哪里、現(xiàn)場(chǎng)怎么調(diào)非常適合正在做設(shè)備數(shù)據(jù)采集、產(chǎn)線數(shù)字化改造的朋友參考也適合剛接觸Modbus協(xié)議、想快速搭一套可落地監(jiān)控系統(tǒng)的開(kāi)發(fā)者。1. 內(nèi)容整體設(shè)計(jì)與思路拆解1.1 為什么是Modbus而不是OPC UA或者M(jìn)QTT聊在線監(jiān)控其實(shí)繞不開(kāi)一個(gè)底層問(wèn)題數(shù)據(jù)從哪來(lái)用什么方式拿。我之前見(jiàn)過(guò)不少團(tuán)隊(duì)一上來(lái)就要上OPC UA覺(jué)得先進(jìn)、功能強(qiáng)、安全。但到現(xiàn)場(chǎng)一看老設(shè)備根本不支持要么加網(wǎng)關(guān)轉(zhuǎn)換要么換儀表成本直接翻好幾倍。對(duì)于大多數(shù)工廠來(lái)說(shuō)Modbus依然是覆蓋度最高的協(xié)議從幾塊錢(qián)的溫度傳感器到幾十萬(wàn)的進(jìn)口設(shè)備十有八九都帶Modbus接口。這個(gè)方案選擇Modbus還有一個(gè)非?,F(xiàn)實(shí)的理由調(diào)試點(diǎn)位極其方便。Modbus的報(bào)文是明文寄存器讀寫(xiě)用Modbus Poll、Modbus Slave這類工具就能直接對(duì)著設(shè)備調(diào)試地址對(duì)不上分分鐘就能查出來(lái)。不像某些私有協(xié)議還得逆向抓包分析一個(gè)點(diǎn)位半天都調(diào)不通。但我也得說(shuō)句公道話Modbus本身沒(méi)有主動(dòng)上報(bào)能力全靠主站一遍遍輪詢。所以網(wǎng)關(guān)方案里輪詢策略設(shè)計(jì)得合不合理直接決定了系統(tǒng)能不能在設(shè)備數(shù)量多的時(shí)候扛得住。1.2 方案整體架構(gòu)是怎么搭的這套在線監(jiān)控網(wǎng)關(guān)方案我把它分成三層采集層網(wǎng)關(guān)通過(guò)RS485總線或者以太網(wǎng)口按照Modbus RTU/TCP協(xié)議定時(shí)輪詢現(xiàn)場(chǎng)設(shè)備讀取寄存器數(shù)據(jù)。轉(zhuǎn)發(fā)層網(wǎng)關(guān)內(nèi)部跑數(shù)據(jù)采集服務(wù)把拿到的原始寄存器值按照設(shè)備點(diǎn)表做解析、換算、單位轉(zhuǎn)換然后整理成統(tǒng)一格式的JSON數(shù)據(jù)。應(yīng)用層通過(guò)MQTT或HTTP接口把數(shù)據(jù)推送到在線監(jiān)控平臺(tái)實(shí)現(xiàn)實(shí)時(shí)曲線、歷史查詢、異常告警、大屏展示。網(wǎng)關(guān)硬件我用的是一臺(tái)工業(yè)級(jí)邊緣網(wǎng)關(guān)雙串口加雙網(wǎng)口支持DC 9-36V寬壓供電。選這個(gè)型號(hào)不是因?yàn)樗F而是因?yàn)樗垢蓴_能力強(qiáng)能在車(chē)間那種電機(jī)啟停頻繁、電磁環(huán)境惡劣的場(chǎng)合穩(wěn)定跑。軟件部分采集服務(wù)我選的Node-RED當(dāng)然你也可以用Python寫(xiě)個(gè)守護(hù)腳本后面我詳細(xì)說(shuō)但Node-RED做原型驗(yàn)證和后期維護(hù)確實(shí)太方便了。1.3 選型時(shí)需要考慮的幾個(gè)重要問(wèn)題在定方案之前有幾個(gè)關(guān)鍵問(wèn)題必須想清楚否則后面返工很麻煩?,F(xiàn)場(chǎng)設(shè)備分布和通訊距離。RS485總線理論傳輸距離是1200米實(shí)際用下來(lái)超過(guò)800米就得考慮加中繼器。如果你的設(shè)備分布在不同車(chē)間、不同樓層最好是每層放一臺(tái)采集網(wǎng)關(guān)再通過(guò)網(wǎng)絡(luò)統(tǒng)一上送而不是硬拉一條超長(zhǎng)RS485總線。采集點(diǎn)位的數(shù)量和實(shí)時(shí)性要求。Modbus是輪詢機(jī)制網(wǎng)關(guān)向每臺(tái)設(shè)備發(fā)起請(qǐng)求設(shè)備應(yīng)答一來(lái)一回是有時(shí)間開(kāi)銷(xiāo)的。假設(shè)一臺(tái)設(shè)備有20個(gè)點(diǎn)位單次輪詢耗時(shí)100ms那光這一臺(tái)設(shè)備就得2秒鐘才能采完一輪。點(diǎn)位太多了實(shí)時(shí)性必然下降。我一般建議單臺(tái)網(wǎng)關(guān)監(jiān)控不超過(guò)32臺(tái)設(shè)備采樣周期在1-5秒之間比較合理。斷線重連和數(shù)據(jù)補(bǔ)傳策略。車(chē)間環(huán)境不可能保證網(wǎng)絡(luò)100%穩(wěn)定網(wǎng)關(guān)和設(shè)備之間、網(wǎng)關(guān)和平臺(tái)之間任何一段斷了數(shù)據(jù)都會(huì)丟。所以選型時(shí)一定要確認(rèn)網(wǎng)關(guān)支持本地緩存和斷線補(bǔ)傳不然網(wǎng)絡(luò)一抖動(dòng)就丟數(shù)據(jù)后期做數(shù)據(jù)分析的時(shí)候你會(huì)非常痛苦。2. 核心細(xì)節(jié)解析與實(shí)操要點(diǎn)2.1 Modbus協(xié)議的現(xiàn)場(chǎng)理解和寄存器分類要做Modbus采集協(xié)議本身還是得稍微過(guò)一遍不用背報(bào)文但要知道數(shù)據(jù)存在哪里。Modbus協(xié)議里數(shù)據(jù)主要存在四個(gè)區(qū)域線圈Coil、離散輸入Discrete Input、保持寄存器Holding Register、輸入寄存器Input Register。前兩個(gè)是按位操作的單位是bit一般用來(lái)讀設(shè)備啟停狀態(tài)、報(bào)警狀態(tài)后兩個(gè)是16位為一個(gè)寄存器用來(lái)存模擬量數(shù)據(jù)比如溫度、壓力、頻率、電流這些。其中線圈支持讀和寫(xiě)離散輸入只支持讀保持寄存器支持讀和寫(xiě)輸入寄存器只支持讀。這個(gè)劃分特別重要因?yàn)槟阍谧霰O(jiān)控的時(shí)候有的數(shù)據(jù)是要讀出來(lái)展示有的數(shù)據(jù)可能還需要遠(yuǎn)程下發(fā)控制比如遠(yuǎn)程啟停設(shè)備、遠(yuǎn)程修改設(shè)定值。這就得認(rèn)清楚你要控制的那個(gè)參數(shù)到底在哪個(gè)區(qū)域功能碼用錯(cuò)了設(shè)備直接給你回異常碼。常見(jiàn)的功能碼我需要現(xiàn)場(chǎng)用得最多的幾個(gè)功能碼含義使用場(chǎng)景0x01讀線圈讀取設(shè)備啟停狀態(tài)、運(yùn)行狀態(tài)0x02讀離散輸入讀取設(shè)備故障輸入、開(kāi)關(guān)狀態(tài)0x03讀保持寄存器讀取設(shè)定值、運(yùn)行參數(shù)、累計(jì)量0x04讀輸入寄存器讀取實(shí)時(shí)測(cè)量值如溫度、壓力0x05寫(xiě)單個(gè)線圈遠(yuǎn)程啟停設(shè)備0x06寫(xiě)單個(gè)寄存器遠(yuǎn)程修改設(shè)定值0x10寫(xiě)多個(gè)寄存器批量下發(fā)參數(shù)2.2 串口參數(shù)和報(bào)文解析的實(shí)操細(xì)節(jié)Modbus RTU走的是RS485串口現(xiàn)場(chǎng)調(diào)通的第一步就是串口參數(shù)要配對(duì)。波特率、數(shù)據(jù)位、校驗(yàn)位、停止位這四個(gè)參數(shù)必須和從站設(shè)備保持一致否則報(bào)文發(fā)過(guò)去就是雞同鴨講。最常見(jiàn)的配置是9600波特率、8數(shù)據(jù)位、無(wú)校驗(yàn)、1停止位簡(jiǎn)寫(xiě)就是9600 8N1。但不同廠家默認(rèn)值不一樣有的設(shè)備出廠是19200還有的是9600 8E1偶校驗(yàn)所以你接上一臺(tái)新設(shè)備第一件事就是查它的說(shuō)明書(shū)確認(rèn)串口參數(shù)不要想當(dāng)然。報(bào)文層面Modbus RTU的幀結(jié)構(gòu)是從站地址1字節(jié) 功能碼1字節(jié) 數(shù)據(jù)N字節(jié) CRC校驗(yàn)2字節(jié)。CRC校驗(yàn)是Modbus RTU特有的低字節(jié)在前。如果你自己寫(xiě)解析代碼CRC算不對(duì)設(shè)備數(shù)據(jù)就永遠(yuǎn)解析不出來(lái)。我自己在方案里直接把Modbus的解析邏輯封裝成了函數(shù)庫(kù)從站地址、功能碼、起始地址、寄存器數(shù)量全部做成配置項(xiàng)。這樣現(xiàn)場(chǎng)加設(shè)備就只是改配置不用改代碼后面維護(hù)省了很多事。2.3 數(shù)據(jù)采集服務(wù)的實(shí)現(xiàn)思路網(wǎng)關(guān)側(cè)的數(shù)據(jù)采集服務(wù)我強(qiáng)烈建議用Node-RED來(lái)做。很多人一聽(tīng)可視化編程就覺(jué)得不靠譜但實(shí)際上Node-RED在工業(yè)物聯(lián)網(wǎng)場(chǎng)景里已經(jīng)非常成熟了它對(duì)Modbus有現(xiàn)成的節(jié)點(diǎn)支持你只需要配置好串口或TCP連接然后把輪詢邏輯拖出來(lái)就能跑。如果不想用Node-RED用Python寫(xiě)采集服務(wù)也完全可行核心就是用pymodbus庫(kù)。我提供一下我當(dāng)時(shí)的設(shè)計(jì)思路啟動(dòng)時(shí)加載設(shè)備點(diǎn)表配置包括設(shè)備ID、串口參數(shù)、寄存器地址、數(shù)據(jù)類型、縮放系數(shù)。按照設(shè)備分組用獨(dú)立的異步任務(wù)循環(huán)執(zhí)行輪詢。每輪輪詢結(jié)束把采集結(jié)果發(fā)布到MQTT主題主題按設(shè)備編碼命名。采集任務(wù)之間用信號(hào)量控制并發(fā)避免多個(gè)串口請(qǐng)求同時(shí)發(fā)送導(dǎo)致數(shù)據(jù)沖突。2.4 告警機(jī)制的簡(jiǎn)單實(shí)現(xiàn)在線監(jiān)控不只是看數(shù)據(jù)更是要能發(fā)現(xiàn)問(wèn)題。我在方案里做了一個(gè)輕量級(jí)的告警引擎支持兩種告警規(guī)則閾值告警比如某臺(tái)空壓機(jī)的排氣溫度超過(guò)85度就觸發(fā)告警。狀態(tài)告警比如設(shè)備通訊斷開(kāi)、連續(xù)N次輪詢無(wú)響應(yīng)說(shuō)明設(shè)備離線了也要告警。告警觸發(fā)后通過(guò)釘釘機(jī)器人或者微信企業(yè)號(hào)推送給對(duì)應(yīng)負(fù)責(zé)人。這里我不建議用短信費(fèi)用高而且很多時(shí)候現(xiàn)場(chǎng)值班人員看微信比看短信還勤。3. 實(shí)操過(guò)程與核心環(huán)節(jié)實(shí)現(xiàn)3.1 設(shè)備點(diǎn)表的整理和規(guī)劃做在線監(jiān)控網(wǎng)關(guān)第一步不是接線路而是整理點(diǎn)表。點(diǎn)表就是一張表列清楚每臺(tái)設(shè)備有哪些數(shù)據(jù)要采集、數(shù)據(jù)存在哪個(gè)地址、什么類型、單位是什么、怎么換算。點(diǎn)表整理清楚了后面寫(xiě)配置也好調(diào)試也好都能省很多力。我拿一個(gè)實(shí)際項(xiàng)目舉例現(xiàn)場(chǎng)有12臺(tái)注塑機(jī)每臺(tái)設(shè)備需要采集的數(shù)據(jù)包括運(yùn)行狀態(tài)線圈地址0故障報(bào)警離散輸入地址0當(dāng)前模溫輸入寄存器地址0單位0.1度需要除以10當(dāng)前壓力輸入寄存器地址1單位0.1MPa需要除以10累計(jì)產(chǎn)量保持寄存器地址10-1132位無(wú)符號(hào)整數(shù)高16位在前這個(gè)點(diǎn)表整理好之后你在網(wǎng)關(guān)里的配置就一目了然。每個(gè)數(shù)據(jù)項(xiàng)對(duì)應(yīng)一個(gè)數(shù)據(jù)點(diǎn)ID比如INJ-001-RUN代表1號(hào)注塑機(jī)運(yùn)行狀態(tài)INJ-001-TEMP代表1號(hào)注塑機(jī)模溫。平臺(tái)端展示的時(shí)候直接用這些數(shù)據(jù)點(diǎn)ID做映射就行。注意寄存器地址的單位是“寄存器號(hào)”不是字節(jié)。32位數(shù)據(jù)占兩個(gè)寄存器64位占四個(gè)。而且不同廠家對(duì)于32位數(shù)據(jù)的字節(jié)序定義不一樣有的高16位在前有的低16位在前一定要通過(guò)實(shí)際讀取驗(yàn)證后再定配置。3.2 Modbus RTU現(xiàn)場(chǎng)接線與通訊測(cè)試接線這塊雖然沒(méi)有多復(fù)雜但細(xì)節(jié)決定成敗。RS485通訊用兩根線A和B也叫D和D-接線的時(shí)候特別注意A接A、B接B不要交叉。很多現(xiàn)場(chǎng)調(diào)試不通最后發(fā)現(xiàn)就是A/B接反了報(bào)文發(fā)出去設(shè)備根本沒(méi)收到??偩€兩端需要接120歐姆終端電阻。如果通訊距離短、設(shè)備少不接可能也能跑但設(shè)備多了、距離長(zhǎng)了不接終端電阻會(huì)出現(xiàn)信號(hào)反射導(dǎo)致通訊時(shí)好時(shí)壞。我建議總線兩端各接一個(gè)終端電阻別省這個(gè)事。接好線之后先用Modbus Poll工具熱搜詞里也有人問(wèn)這個(gè)的密鑰其實(shí)官方有試用版?zhèn)€人調(diào)試用足夠了正式用建議買(mǎi)授權(quán)也不貴測(cè)試一下通訊。把串口參數(shù)填進(jìn)去從站地址填1功能碼選03起始地址填0寄存器數(shù)量填10點(diǎn)擊連接如果能看到數(shù)據(jù)在跳動(dòng)說(shuō)明通訊鏈路通了。Modbus Poll是主站模擬工具還有一個(gè)配套的Modbus Slave是從站模擬工具。調(diào)試的時(shí)候你可以用Modbus Slave模擬一臺(tái)設(shè)備用Modbus Poll或者你自己的采集服務(wù)去讀它先把雙方邏輯調(diào)通再接真實(shí)設(shè)備這樣能大大縮短調(diào)試時(shí)間。3.3 MQTT數(shù)據(jù)上云和平臺(tái)展示數(shù)據(jù)到了網(wǎng)關(guān)解析成標(biāo)準(zhǔn)JSON格式之后下一步就是推送到在線監(jiān)控平臺(tái)。MQTT是物聯(lián)網(wǎng)場(chǎng)景里最常見(jiàn)的消息協(xié)議網(wǎng)關(guān)作為MQTT客戶端把采集數(shù)據(jù)發(fā)布到特定主題平臺(tái)端訂閱這些主題實(shí)時(shí)入庫(kù)。我推薦用EMQX作為MQTT Broker開(kāi)源版部署簡(jiǎn)單性能也夠用。平臺(tái)端如果用現(xiàn)成的物聯(lián)網(wǎng)平臺(tái)比如ThingsBoard那它自帶MQTT接入能力配置一下就能把數(shù)據(jù)展示成大屏看板。如果不想用現(xiàn)成平臺(tái)自己寫(xiě)個(gè)后端定時(shí)從MQTT拉數(shù)據(jù)入庫(kù)前端用ECharts畫(huà)曲線也完全可行。關(guān)鍵一點(diǎn)是數(shù)據(jù)入庫(kù)的時(shí)候要帶好設(shè)備編碼、數(shù)據(jù)點(diǎn)ID、時(shí)間戳三個(gè)字段缺一不可。設(shè)備編碼用來(lái)定位是哪臺(tái)設(shè)備數(shù)據(jù)點(diǎn)ID用來(lái)定位是哪個(gè)參數(shù)時(shí)間戳用來(lái)定位是哪一刻的數(shù)據(jù)。沒(méi)有時(shí)間戳的歷史數(shù)據(jù)就是一堆垃圾。3.4 輪詢參數(shù)的計(jì)算和優(yōu)化輪詢周期是多長(zhǎng)很多新手上來(lái)直接設(shè)100毫秒覺(jué)得越快越好。實(shí)際上這要看設(shè)備能夠承受的通訊頻率。有些老PLC的Modbus通訊處理能力很弱你高頻輪詢它它反而會(huì)通訊超時(shí)甚至影響PLC本身的掃描周期。我一般按這個(gè)思路來(lái)算單臺(tái)設(shè)備數(shù)據(jù)讀取耗時(shí) 請(qǐng)求發(fā)送時(shí)間 設(shè)備處理時(shí)間 響應(yīng)返回時(shí)間RS485在9600波特率下1個(gè)字節(jié)大約1ms讀10個(gè)寄存器請(qǐng)求幀8字節(jié)響應(yīng)幀25字節(jié)左右加上設(shè)備處理時(shí)間單次大約40-60ms。如果總線上掛了10臺(tái)設(shè)備每臺(tái)讀一次一輪下來(lái)大概0.5秒。那輪詢周期就設(shè)置在1-2秒既能保證實(shí)時(shí)性又不會(huì)給總線造成壓力。如果監(jiān)控平臺(tái)需要每秒鐘刷新一次數(shù)據(jù)單臺(tái)網(wǎng)關(guān)下面的設(shè)備就不能太多或者要分多條RS485總線每條總線掛一部分設(shè)備并行輪詢。4. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄4.1 Modbus Poll報(bào)02 Illegal Data Address怎么處理熱詞里有人專門(mén)搜“modbus poll 02 illegal”這個(gè)問(wèn)題現(xiàn)場(chǎng)出現(xiàn)率極高。02是Modbus的異常碼含義是“非法的數(shù)據(jù)地址”說(shuō)白了就是你請(qǐng)求的寄存器地址在這個(gè)設(shè)備上不存在。排查思路就三步第一確認(rèn)你的起始地址填對(duì)了。很多設(shè)備的寄存器地址在文檔里是“40001”這種PLC風(fēng)格的地址對(duì)應(yīng)協(xié)議里的地址其實(shí)是0差了一個(gè)偏移。你在工具里填的時(shí)候要么直接填協(xié)議地址要么注意工具軟件里有沒(méi)有加1的選項(xiàng)。第二確認(rèn)寄存器數(shù)量別越界。你從地址0開(kāi)始讀數(shù)量填100但設(shè)備實(shí)際只有50個(gè)寄存器超過(guò)的部分就會(huì)報(bào)02。第三確認(rèn)你用的功能碼對(duì)應(yīng)正確的數(shù)據(jù)區(qū)域。比如設(shè)備的溫度數(shù)據(jù)在輸入寄存器你讀保持寄存器肯定讀不到反過(guò)來(lái)你要寫(xiě)設(shè)定值寫(xiě)的是保持寄存器卻用讀線圈的功能碼去操作也會(huì)報(bào)錯(cuò)。4.2 能Ping通但Modbus TCP不通是什么原因熱詞里也有“modbus tcp 能pin通,但modscan不通什么原因”這個(gè)問(wèn)題我也遇到過(guò)。Ping通說(shuō)明網(wǎng)絡(luò)層是通的Modbus TCP不通問(wèn)題基本出在端口或者設(shè)備本身。Modbus TCP的默認(rèn)端口是502很多設(shè)備支持自定義端口你得確認(rèn)設(shè)備上的端口到底是多少。另外有些設(shè)備的Modbus TCP服務(wù)默認(rèn)是關(guān)閉的需要在設(shè)備參數(shù)里打開(kāi)或者需要配置訪問(wèn)白名單。還有一種情況是防火墻攔了502端口。Windows自帶的防火墻有時(shí)候會(huì)攔掉來(lái)自局域網(wǎng)的502訪問(wèn)排查時(shí)可以先臨時(shí)關(guān)掉防火墻試試確認(rèn)是防火墻問(wèn)題再添加放行規(guī)則。最后還有一種可能就是設(shè)備支持多個(gè)連接但連接數(shù)被占滿了。Modbus TCP允許同時(shí)建立的連接數(shù)有限如果之前有調(diào)試工具或者監(jiān)控軟件一直連著沒(méi)斷開(kāi)新連接就會(huì)失敗。這個(gè)用TCP工具看連接狀態(tài)就能發(fā)現(xiàn)。4.3 數(shù)據(jù)亂跳、偶爾讀到0或者負(fù)數(shù)怎么辦Modbus讀到亂數(shù)據(jù)多半是數(shù)據(jù)類型配錯(cuò)了。比如設(shè)備存的是16位有符號(hào)整數(shù)你按無(wú)符號(hào)整數(shù)解析負(fù)值就會(huì)變成一個(gè)很大的正數(shù)設(shè)備存的是32位浮點(diǎn)數(shù)你按兩個(gè)16位整數(shù)解析得到的數(shù)就是亂的。解決辦法是讀幾個(gè)寄存器的原始值用計(jì)算器按16進(jìn)制轉(zhuǎn)10進(jìn)制、按浮點(diǎn)數(shù)格式轉(zhuǎn)一下看看和設(shè)備實(shí)際顯示值對(duì)不對(duì)得上。對(duì)得上說(shuō)明解析方式正確對(duì)不上就換字節(jié)序、換數(shù)據(jù)類型再試。至于偶爾讀到0可能是輪詢和設(shè)備正在更新的數(shù)據(jù)撞上了。有些設(shè)備在更新內(nèi)部數(shù)據(jù)時(shí)如果你正好去讀讀到的是半新半舊的數(shù)據(jù)。這種情況可以在采集服務(wù)里做一次數(shù)據(jù)有效性校驗(yàn)比如溫度值如果超出-50到200度的物理范圍就丟棄這一幀等下一輪再讀。4.4 網(wǎng)關(guān)長(zhǎng)期運(yùn)行后數(shù)據(jù)不更新了系統(tǒng)跑了一兩個(gè)月突然發(fā)現(xiàn)平臺(tái)上某個(gè)設(shè)備的數(shù)據(jù)不刷了但設(shè)備本身明明是好的。這個(gè)我在線下項(xiàng)目里排查過(guò)原因基本就兩類。第一類是網(wǎng)關(guān)側(cè)Modbus通訊線程卡死了。設(shè)備長(zhǎng)時(shí)間無(wú)響應(yīng)如果超時(shí)處理寫(xiě)得不完善通訊狀態(tài)機(jī)可能一直卡在等待響應(yīng)的狀態(tài)后續(xù)請(qǐng)求全部發(fā)不出去。解決辦法是給每次請(qǐng)求都加超時(shí)時(shí)間超時(shí)后強(qiáng)制重置連接。我一般設(shè)超時(shí)為500ms連續(xù)超時(shí)3次就斷開(kāi)重連。第二類是MQTT連接斷開(kāi)了但沒(méi)重連。網(wǎng)關(guān)和MQTT Broker之間的長(zhǎng)連接中間經(jīng)過(guò)交換機(jī)或者路由器偶爾會(huì)有連接假死的情況——TCP連接看似還在實(shí)際數(shù)據(jù)已經(jīng)不走了。解決方法是啟用MQTT的KeepAlive機(jī)制客戶端定時(shí)發(fā)心跳包服務(wù)端在超時(shí)未收到心跳時(shí)主動(dòng)斷開(kāi)連接客戶端隨即發(fā)起重連。我在網(wǎng)關(guān)服務(wù)里加了一個(gè)看門(mén)狗邏輯每隔5分鐘檢查一次MQTT連接狀態(tài)和最近數(shù)據(jù)更新時(shí)間如果發(fā)現(xiàn)超過(guò)2分鐘沒(méi)有新數(shù)據(jù)上報(bào)就自動(dòng)重啟采集任務(wù)實(shí)測(cè)下來(lái)系統(tǒng)穩(wěn)定性提升非常明顯。4.5 調(diào)試小工具推薦最后分享一下我平時(shí)調(diào)試Modbus網(wǎng)關(guān)方案的工具箱工具用途Modbus Poll主站模擬讀取從站設(shè)備數(shù)據(jù)時(shí)首選Modbus Slave從站模擬調(diào)試采集服務(wù)時(shí)當(dāng)假設(shè)備VSPD虛擬串口電腦上虛擬出一對(duì)互聯(lián)串口方便調(diào)試串口程序MQTTXMQTT客戶端調(diào)試工具查看消息發(fā)布訂閱非常方便Wireshark抓包分析Modbus TCP報(bào)文一眼就能看清這里有個(gè)小技巧調(diào)試RS485總線上的設(shè)備時(shí)我經(jīng)常用USB轉(zhuǎn)RS485模塊把設(shè)備掛到電腦上用Modbus Poll直接讀。如果設(shè)備數(shù)量多那就在每個(gè)設(shè)備旁邊臨時(shí)接一個(gè)RS485轉(zhuǎn)RJ45的轉(zhuǎn)換器把總線拓?fù)淅砬宄俳y(tǒng)一接到網(wǎng)關(guān)會(huì)輕松很多。5. 關(guān)于協(xié)議深度測(cè)試的幾點(diǎn)補(bǔ)充做在線監(jiān)控網(wǎng)關(guān)不僅要讓正常情況跑得通還要考慮異常情況怎么處理?,F(xiàn)場(chǎng)調(diào)試完一塊邏輯后一定要模擬設(shè)備掉線、寄存器越界、數(shù)據(jù)異常等場(chǎng)景驗(yàn)證網(wǎng)關(guān)和平臺(tái)的容錯(cuò)能力。很多項(xiàng)目的需求書(shū)上都會(huì)寫(xiě)“系統(tǒng)應(yīng)具備高可靠性”但可靠性真不是靠寫(xiě)代碼寫(xiě)出來(lái)的是靠一輪一輪故障測(cè)試測(cè)出來(lái)的。我習(xí)慣的做法是每個(gè)通訊周期增加一個(gè)狀態(tài)計(jì)數(shù)連續(xù)幾個(gè)周期通訊失敗就標(biāo)記設(shè)備離線同時(shí)觸發(fā)告警恢復(fù)后自動(dòng)清除離線狀態(tài)。這樣網(wǎng)絡(luò)抖動(dòng)的時(shí)候不會(huì)誤報(bào)但設(shè)備真的掛了也能及時(shí)通知到人。再提一個(gè)LabVIEW讀Modbus的場(chǎng)景熱詞里也有“l(fā)abview 讀modbus rtu從站信息”。LabVIEW有現(xiàn)成的Modbus庫(kù)用事件結(jié)構(gòu)加定時(shí)器做輪詢就能實(shí)現(xiàn)底層原理和我上面講的完全一樣只不過(guò)采集程序跑在PC上而不是網(wǎng)關(guān)上。如果你只是做實(shí)驗(yàn)室驗(yàn)證或者小規(guī)模監(jiān)控用LabVIEW完全可以但現(xiàn)場(chǎng)環(huán)境惡劣、要求長(zhǎng)期穩(wěn)定運(yùn)行的場(chǎng)景還是建議用工業(yè)網(wǎng)關(guān)。這套基于Modbus的在線監(jiān)控網(wǎng)關(guān)方案我實(shí)際部署到產(chǎn)線之后最大的感受就是方案本身不復(fù)雜難的是把每一個(gè)細(xì)微的環(huán)節(jié)做成可配置、可維護(hù)、可故障恢復(fù)的機(jī)制。Modbus協(xié)議像一根針把散落的設(shè)備串了起來(lái)網(wǎng)關(guān)像大腦把枯燥的寄存器數(shù)據(jù)變成了業(yè)務(wù)價(jià)值。如果你正在做類似的數(shù)據(jù)采集改造別貪大求全先把單臺(tái)設(shè)備的通訊和解析跑通再擴(kuò)展到整條產(chǎn)線穩(wěn)扎穩(wěn)打比什么都重要。最后再分享一個(gè)小技巧所有設(shè)備的通訊參數(shù)和點(diǎn)表配置一定要用同一個(gè)配置文件統(tǒng)一管理現(xiàn)場(chǎng)加設(shè)備、改參數(shù)改完配置重啟服務(wù)就生效這比每次去改代碼重新部署要省一百倍的時(shí)間。