戰(zhàn):modbus.json配置與排錯(cuò)指南)
如果你正手拿一臺(tái)帶串口的工業(yè)設(shè)備準(zhǔn)備把它上面的Modbus RTU數(shù)據(jù)接到ThingsBoard平臺(tái)那么在ThingsBoard-GateWay上配置modbus串口總線幾乎是你繞不開的一步。我前前后后給好幾組現(xiàn)場(chǎng)設(shè)備做過這類接入最深的感受是真正的難點(diǎn)不在平臺(tái)側(cè)而在網(wǎng)關(guān)側(cè)的modbus.json配置。波特率、從站地址、寄存器類型、字節(jié)序任何一個(gè)參數(shù)不對(duì)整個(gè)鏈路就靜悄悄。這篇內(nèi)容就是把我實(shí)際配置和排錯(cuò)的過程完整梳理一遍適合剛開始接觸物聯(lián)網(wǎng)網(wǎng)關(guān)、或者已經(jīng)在ThingsBoard-GateWay上被串口Modbus折騰到?jīng)]脾氣的開發(fā)者。1. 網(wǎng)關(guān)接入modbus串口設(shè)備的整體設(shè)計(jì)思路1.1 為什么偏偏選ThingsBoard-GateWay很多人在邊緣側(cè)接過Modbus設(shè)備時(shí)第一反應(yīng)是自己寫個(gè)腳本用pymodbus或者libmodbus定時(shí)去讀儀表然后把數(shù)據(jù)用MQTT推到ThingsBoard。這個(gè)思路本身沒有錯(cuò)但一旦設(shè)備數(shù)量多起來、現(xiàn)場(chǎng)又要遠(yuǎn)程改配置、還得保證斷線自動(dòng)恢復(fù)自己寫的腳本就會(huì)變成維護(hù)負(fù)擔(dān)。ThingsBoard-GateWay本身就是為這個(gè)場(chǎng)景做的它在本地運(yùn)行專門負(fù)責(zé)把各種工業(yè)協(xié)議轉(zhuǎn)換成ThingsBoard平臺(tái)能理解的數(shù)據(jù)模型。網(wǎng)關(guān)接管協(xié)議轉(zhuǎn)換之后Modbus的一堆寄存器、從站地址、字節(jié)序細(xì)節(jié)全部被隱藏在后端ThingsBoard側(cè)只需要關(guān)心設(shè)備名稱和遙測(cè)字段。我甚至不需要預(yù)先在平臺(tái)側(cè)創(chuàng)建設(shè)備網(wǎng)關(guān)聯(lián)調(diào)時(shí)會(huì)自動(dòng)建立對(duì)應(yīng)設(shè)備等配置對(duì)了數(shù)據(jù)就直接出現(xiàn)在設(shè)備面板里。這套機(jī)制讓我在現(xiàn)場(chǎng)少干了很多重復(fù)勞動(dòng)。還有一點(diǎn)容易被忽略網(wǎng)關(guān)支持多個(gè)協(xié)議擴(kuò)展并存。同一個(gè)網(wǎng)關(guān)上我可以同時(shí)跑Modbus、OPC-UA、MQTT、BLE等多個(gè)連接器各自獨(dú)立配置互不干擾。這意味著未來往現(xiàn)場(chǎng)加設(shè)備不需要改架構(gòu)只需要多開一個(gè)配置段。1.2 modbus串口總線的場(chǎng)景特質(zhì)Modbus串口總線準(zhǔn)確說通常是Modbus RTU over RS-485。RS-485是物理層標(biāo)準(zhǔn)特點(diǎn)是差分信號(hào)、抗干擾強(qiáng)、傳輸距離能到上千米非常適合工廠車間和戶外配電房這類環(huán)境。Modbus RTU則定義了鏈路層的數(shù)據(jù)幀格式設(shè)備地址、功能碼、數(shù)據(jù)區(qū)、CRC校驗(yàn)。一套總線上可以掛多個(gè)從站設(shè)備從站地址從1到247主站通過輪詢方式和每個(gè)從站交互。這種結(jié)構(gòu)決定了配置思路上三個(gè)要點(diǎn)。第一串口參數(shù)必須和每臺(tái)從站設(shè)備完全一致波特率、數(shù)據(jù)位、停止位、校驗(yàn)位一個(gè)都不能錯(cuò)。第二主站輪詢是順序發(fā)生的同一時(shí)刻總線上只能有一個(gè)請(qǐng)求所以不能指望同時(shí)對(duì)一堆設(shè)備做高頻并發(fā)采集。第三從站設(shè)備是“被動(dòng)響應(yīng)型”網(wǎng)關(guān)不主動(dòng)發(fā)問儀表絕不多說一句話。這意味著配置里的輪詢周期、超時(shí)時(shí)間直接決定了數(shù)據(jù)刷新速度和總線負(fù)載。實(shí)際現(xiàn)場(chǎng)里RS-485的接線還經(jīng)常出幺蛾子A/B線接反、屏蔽層沒接地、終端電阻缺失這些物理層問題會(huì)在網(wǎng)關(guān)配置時(shí)表現(xiàn)為莫名的超時(shí)和亂碼。所以做串口Modbus接入一定要有“配置問題硬件問題同時(shí)排查”的思維。1.3 配置文件里藏著的核心邏輯ThingsBoard-GateWay的Modbus擴(kuò)展核心配置在網(wǎng)關(guān)config目錄下的modbus.json里。整個(gè)文件的結(jié)構(gòu)可以理解成三層第一層masterConfig定義網(wǎng)關(guān)行為比如用串口還是TCP、輪詢周期、串口參數(shù)第二層devices數(shù)組定義總線上每個(gè)Modbus從站如何映射成一個(gè)ThingsBoard設(shè)備第三層attributes和timeseries定義從站的哪些寄存器數(shù)據(jù)點(diǎn)對(duì)應(yīng)平臺(tái)設(shè)備的什么字段。把這套結(jié)構(gòu)想清楚了后面填參數(shù)就不會(huì)慌。我見過不少人一上來就復(fù)制網(wǎng)上的片段結(jié)果跑不通原因就是沒搞懂每一層到底在干嘛。特別是deviceNodeId和targetSlaveID的區(qū)別前者是網(wǎng)關(guān)內(nèi)部的設(shè)備節(jié)點(diǎn)標(biāo)識(shí)后者才是總線上真正的Modbus從站地址兩者弄混設(shè)備名會(huì)直接亂掉。在進(jìn)入具體字段之前建議先做一件事把你手頭從站設(shè)備的手冊(cè)打開找到Modbus寄存器表和通信參數(shù)頁把波特率、地址、寄存器地址、數(shù)據(jù)類型、字節(jié)序都抄到一張紙上。配置就能少走一半彎路。2. modbus串口配置詳解一個(gè)字段一個(gè)坑2.1 transportType和serialSettings先把串口參數(shù)對(duì)齊masterConfig里最關(guān)鍵的是transportType串口場(chǎng)景固定填serial。它決定了下面走哪一組連接參數(shù)如果填成tcp網(wǎng)關(guān)就會(huì)去找TCP配置段導(dǎo)致串口永遠(yuǎn)沒反應(yīng)。對(duì)應(yīng)串口參數(shù)用的是serialSettings塊字段并不復(fù)雜但每一個(gè)都值得較真port串口設(shè)備路徑Linux下通常是/dev/ttyUSB0、/dev/ttyS0這類。USB轉(zhuǎn)485的適配器一般叫ttyUSB0主板原生串口叫ttyS0。填錯(cuò)路徑網(wǎng)關(guān)也能啟動(dòng)但日志會(huì)一直刷設(shè)備打不開。baudRate波特率常見9600、19200、38400、115200。這個(gè)必須和設(shè)備側(cè)完全一致差一個(gè)數(shù)字都白搭。dataBits數(shù)據(jù)位Modbus RTU固定8位。stopBits停止位絕大多數(shù)設(shè)備是1。parity校驗(yàn)位可選NONE、EVEN、ODD。工業(yè)老設(shè)備偶校驗(yàn)和奇校驗(yàn)都比較常見強(qiáng)烈建議先看手冊(cè)。舉個(gè)例子我接一臺(tái)老款電表時(shí)手冊(cè)上寫著9600, 8, 1, EVEN我默認(rèn)填了NONE結(jié)果讀數(shù)據(jù)時(shí)有一半請(qǐng)求超時(shí)。后來用串口監(jiān)聽工具看了總線上的報(bào)文才意識(shí)到校驗(yàn)位不對(duì)。校驗(yàn)位這種參數(shù)光看報(bào)錯(cuò)很難看出來因?yàn)樗粫?huì)導(dǎo)致完全黑屏只是偶發(fā)丟包和讀錯(cuò)值。還有一個(gè)容易忽略的問題serialSettings里的port如果是數(shù)值而不是字符串網(wǎng)關(guān)解析JSON時(shí)可能會(huì)直接報(bào)類型錯(cuò)誤。我習(xí)慣把所有字段都寫成字符串或整數(shù)后走一遍JSON格式檢查再讓網(wǎng)關(guān)加載。2.2 serverConfig輪詢周期和串口獨(dú)占serialSettings下面是serverConfig里面最重要的兩個(gè)字段是pollPeriod和disableOtherSerialInput。pollPeriod是網(wǎng)關(guān)對(duì)總線上從站發(fā)起輪詢的周期單位毫秒。它決定數(shù)據(jù)延遲但不是說設(shè)得越小越好。Modbus是半雙工總線一個(gè)請(qǐng)求發(fā)出后必須等從站回應(yīng)超時(shí)之后才能處理下一個(gè)請(qǐng)求。如果pollPeriod設(shè)得太小網(wǎng)關(guān)會(huì)把大量時(shí)間耗在等待超時(shí)上反而降低有效采集率。我的習(xí)慣是先從大往小調(diào)比如先設(shè)3000ms跑通再逐步降到500ms觀察日志里沒有超時(shí)再收手。disableOtherSerialInput這個(gè)字段表示網(wǎng)關(guān)是否獨(dú)占這個(gè)串口。如果設(shè)為true網(wǎng)關(guān)會(huì)停止監(jiān)聽其他程序?qū)Υ诘妮斎胫苯影汛谧鳛镸odbus主站通道使用。在同時(shí)跑調(diào)試軟件的場(chǎng)景下這個(gè)開關(guān)容易被忽略。我調(diào)試時(shí)習(xí)慣先用一個(gè)獨(dú)立串口工具驗(yàn)證設(shè)備能正常回包確認(rèn)后再交給網(wǎng)關(guān)獨(dú)占。serverConfig里的timeout和retries字段雖然沒有在默認(rèn)配置中強(qiáng)制出現(xiàn)但如果你遇到復(fù)雜總線上偶發(fā)超時(shí)可以給請(qǐng)求加一個(gè)超時(shí)毫秒數(shù)并指定重試次數(shù)。這有點(diǎn)像在網(wǎng)絡(luò)請(qǐng)求里做超時(shí)重傳既能容忍偶發(fā)抖動(dòng)又不會(huì)因?yàn)橐恢彼赖饶骋粋€(gè)掉線從站卡住整條總線。2.3 devices數(shù)組從站映射到網(wǎng)關(guān)設(shè)備devices數(shù)組里每個(gè)元素代表總線上一個(gè)Modbus從站在平臺(tái)側(cè)對(duì)應(yīng)的一臺(tái)設(shè)備。舉例來說如果總線上掛著3臺(tái)溫濕度表地址分別是1、2、3那這里就至少要有3個(gè)對(duì)象每個(gè)對(duì)象里的targetSlaveID分別填對(duì)應(yīng)地址。重要的字段是deviceNodeId、deviceName、deviceType和transport.targetSlaveID。deviceNodeId是網(wǎng)關(guān)內(nèi)部的節(jié)點(diǎn)標(biāo)識(shí)必須唯一它可以和deviceName無關(guān)。網(wǎng)關(guān)最終上報(bào)到ThingsBoard時(shí)會(huì)自動(dòng)組合deviceNodeId和目標(biāo)從站地址生成一條設(shè)備標(biāo)識(shí)通過控制臺(tái)日志能看到生成的設(shè)備名。deviceName則是你希望平臺(tái)側(cè)顯示的名字比如“車間溫濕度1號(hào)”。這里的配置坑我踩過一次deviceNodeId里帶中文或特殊字符網(wǎng)關(guān)雖然能創(chuàng)建但某些版本的日志和設(shè)備匹配會(huì)出問題。后來我統(tǒng)一用項(xiàng)目縮寫加數(shù)字編號(hào)比如tmp_hum_01干凈且好排查。transport塊里目前主要是targetSlaveID也就是Modbus從站地址。不要把這個(gè)地址理解成寄存器地址它對(duì)應(yīng)的是總線上每臺(tái)設(shè)備的“門牌號(hào)”。部分儀表的設(shè)備地址還可以在面板上改配置前最好確認(rèn)一下儀表當(dāng)前實(shí)際地址而不是只看手冊(cè)默認(rèn)值。2.4 attributes、timeseries和數(shù)據(jù)類型轉(zhuǎn)換attributes和timeseries是兩個(gè)數(shù)組分別描述網(wǎng)關(guān)要把哪些寄存器數(shù)據(jù)作為設(shè)備屬性哪些作為時(shí)序遙測(cè)數(shù)據(jù)上報(bào)。差別很簡單屬性是“不太變的信息”比如設(shè)備序列號(hào)、固件版本、量程范圍時(shí)序數(shù)據(jù)是“高頻變化的值”比如溫度、濕度、壓力、電流。每個(gè)數(shù)據(jù)點(diǎn)的關(guān)鍵字段有這些typeModbus功能碼。3代表讀保持寄存器4代表讀輸入寄存器。選擇依據(jù)是設(shè)備手冊(cè)里的寄存器類型。保持寄存器一般存配置類和可寫參數(shù)輸入寄存器則多存只讀測(cè)量值。address寄存器起始地址。注意Modbus協(xié)議里的地址是從0開始的而很多設(shè)備手冊(cè)里寫的是40001、40002這種PLC風(fēng)格的地址需要做換算40001對(duì)應(yīng)地址040002對(duì)應(yīng)地址1。換算錯(cuò)了數(shù)據(jù)會(huì)整體錯(cuò)位。registerCount讀取的寄存器個(gè)數(shù)。16位整數(shù)讀1個(gè)寄存器32位整數(shù)或浮點(diǎn)數(shù)讀2個(gè)寄存器。數(shù)量不對(duì)邊界就會(huì)對(duì)不上。byteOrder字節(jié)序。Modbus協(xié)議本身是大端傳輸?shù)行┰O(shè)備的32位數(shù)據(jù)會(huì)把低字放到前面這里需要按手冊(cè)設(shè)置BIG、LITTLE等選項(xiàng)。multiplier和offset數(shù)據(jù)縮放和平移。比如儀表原始值是整數(shù)1234實(shí)際代表12.34℃那么multiplier設(shè)0.01網(wǎng)關(guān)上報(bào)前會(huì)做value raw * multiplier offset的換算。attributes和timeseries里還可以嵌套一層自定義屬性對(duì)象用來給數(shù)據(jù)點(diǎn)打標(biāo)簽也就是上報(bào)到平臺(tái)時(shí)附帶的額外元信息。實(shí)際應(yīng)用里我常用它標(biāo)記數(shù)據(jù)點(diǎn)的工程單位、位置編號(hào)方便在儀表板里做篩選和展示。3. 從零配置一個(gè)Modbus-RTU溫度傳感器3.1 場(chǎng)景與準(zhǔn)備我用一個(gè)最常見的場(chǎng)景來演示現(xiàn)場(chǎng)某設(shè)備柜內(nèi)裝了一個(gè)溫濕度變送器支持Modbus RTU掛在RS-485總線上從站地址是1波特率9600數(shù)據(jù)位8停止位1無校驗(yàn)。寄存器表里保持寄存器地址0是溫度值放大10倍的整數(shù)實(shí)際分辨率0.1℃保持寄存器地址1是濕度值同樣放大10倍地址2是我的傳感器序列號(hào)。準(zhǔn)備工作有幾件。一臺(tái)Linux主機(jī)或ARM開發(fā)板一個(gè)USB轉(zhuǎn)RS-485適配器一根雙絞線連到變送器的A/B端子。接線時(shí)務(wù)必確認(rèn)A對(duì)A、B對(duì)B。物理連接處理好之后用系統(tǒng)命令先確認(rèn)串口被識(shí)別比如在Linux下ls /dev/ttyUSB*能看到設(shè)備節(jié)點(diǎn)就說明驅(qū)動(dòng)正常。此時(shí)如果用普通用戶打開串口大概率會(huì)遇到Permission denied解決辦法是把當(dāng)前用戶加進(jìn)串口設(shè)備所屬的用戶組然后重新登錄會(huì)話。為了不讓第一輪配置變成抓瞎我會(huì)先用一個(gè)小腳本測(cè)試設(shè)備能不能正常應(yīng)答Modbus請(qǐng)求確認(rèn)物理鏈路和寄存器地址都對(duì)再改網(wǎng)關(guān)配置。這樣排查問題時(shí)可以清晰劃分硬件問題和軟件問題。3.2 完整的modbus.json配置示例下面這份配置可以直接套用。它定義了一臺(tái)ThingsBoard設(shè)備“TH Sensor 01”通過串口讀兩個(gè)保持寄存器作為實(shí)時(shí)溫度、濕度遙測(cè)同時(shí)把一個(gè)輸入寄存器數(shù)據(jù)作為設(shè)備的modbus_id屬性。{ masterConfig: { transportType: serial, serialSettings: { port: /dev/ttyUSB0, baudRate: 9600, dataBits: 8, stopBits: 1, parity: NONE }, serverConfig: { pollPeriod: 2000, disableOtherSerialInput: true }, devices: [ { deviceNodeId: th_sensor_01, deviceName: TH Sensor 01, deviceType: default, transport: { targetSlaveID: 1 }, attributes: [ { tag: modbus_id, type: 4, address: 2, registerCount: 1, byteOrder: BIG, attributes: { label: Modbus ID } } ], timeseries: [ { tag: temperature, type: 3, address: 0, registerCount: 1, byteOrder: BIG, multiplier: 0.1, timeseries: { label: Temperature } }, { tag: humidity, type: 3, address: 1, registerCount: 1, byteOrder: BIG, multiplier: 0.1, timeseries: { label: Humidity } } ] } ] } }我把溫濕度都放在保持寄存器里所以type填3modbus_id放在輸入寄存器里type填4。如果設(shè)備手冊(cè)里溫度是浮點(diǎn)數(shù)那registerCount就得改成2并確認(rèn)byteOrder。千萬別小看multiplier的作用很多儀表都把浮點(diǎn)數(shù)放大成整數(shù)存儲(chǔ)不加縮放系數(shù)平臺(tái)上的讀數(shù)直接多兩位小數(shù)。3.3 配置驗(yàn)證和啟動(dòng)步驟配置寫好之后不要直接扔給網(wǎng)關(guān)。我的習(xí)慣是先做兩步預(yù)檢。用python跑一個(gè)小腳本驗(yàn)證從站應(yīng)答這樣做的好處是隔離問題。如果腳本也讀不到數(shù)據(jù)就說明問題出在串口參數(shù)或物理鏈路跟網(wǎng)關(guān)配置無關(guān)。from pymodbus.client import ModbusSerialClient client ModbusSerialClient( methodrtu, port/dev/ttyUSB0, baudrate9600, parityN, stopbits1, bytesize8, timeout1 ) client.connect() rr client.read_holding_registers(0, 2, slave1) if not rr.isError(): print(rr.registers) client.close()如果腳本返回了寄存器值就可以把modbus.json放到網(wǎng)關(guān)的config目錄替換原有文件。改文件前務(wù)必先備份比如執(zhí)行cp modbus.json modbus.json.bak。網(wǎng)關(guān)在Linux下通常以服務(wù)方式運(yùn)行改完配置需要重啟進(jìn)程常見命令是systemctl restart thingsboard-gatewayDocker部署則重啟容器。啟動(dòng)之后立刻看日志。日志路徑一般在網(wǎng)關(guān)目錄下的logs/thingsboard-gateway.log重點(diǎn)看Modbus擴(kuò)展的啟動(dòng)日志有沒有類似“Modbus connector started”的記錄。如果看到超時(shí)、緩存讀取失敗之類的錯(cuò)誤多半是配置參數(shù)有偏差。一切正常的話去ThingsBoard平臺(tái)刷新設(shè)備列表能看到網(wǎng)關(guān)自動(dòng)創(chuàng)建了設(shè)備稍等一兩個(gè)輪詢周期temperature和humidity兩個(gè)遙測(cè)鍵就會(huì)開始有數(shù)據(jù)。3.4 輪詢周期與串口負(fù)載估算配置里的pollPeriod到底填多少這里有一個(gè)很實(shí)用的估算方法。以9600波特率為例串口上每個(gè)字符的傳輸時(shí)間約等于10位除以波特率大概1.04毫秒。一個(gè)標(biāo)準(zhǔn)的Modbus RTU讀請(qǐng)求幀是8字節(jié)其中包含地址、功能碼、寄存器地址、寄存器數(shù)量、CRC校驗(yàn)。如果從站響應(yīng)2個(gè)寄存器響應(yīng)幀大約是9字節(jié)。加上Modbus協(xié)議要求的幀間隔時(shí)間整個(gè)請(qǐng)求-響應(yīng)周期大約在25到30毫秒。所以說就算總線上掛了5臺(tái)設(shè)備每個(gè)設(shè)備各讀2個(gè)寄存器pollPeriod設(shè)成1000毫秒總線負(fù)載也遠(yuǎn)沒有到瓶頸。但如果設(shè)備數(shù)量多或者每個(gè)設(shè)備要讀幾十個(gè)寄存器響應(yīng)幀變長總耗時(shí)就會(huì)明顯增加。舉例來說單臺(tái)設(shè)備讀取20個(gè)保持寄存器時(shí)請(qǐng)求幀8字節(jié)響應(yīng)幀變成45字節(jié)加幀間隔約55毫秒??偩€上掛10臺(tái)這樣的設(shè)備一輪輪詢就要550毫秒。這時(shí)pollPeriod設(shè)1500毫秒或2000毫秒才比較穩(wěn)。理解了這一點(diǎn)就不會(huì)盲目把pollPeriod調(diào)到幾百毫秒。半雙工總線的帶寬就那么多請(qǐng)求越密等待超時(shí)的概率越大。我在現(xiàn)場(chǎng)通常先用3000毫秒跑通再根據(jù)總線上設(shè)備數(shù)量和日志里的超時(shí)次數(shù)慢慢往下壓。4. 常見問題排查與調(diào)試實(shí)錄4.1 典型故障速查表下面這張表是我?guī)状维F(xiàn)場(chǎng)排錯(cuò)里總結(jié)出來的按“現(xiàn)象 → 原因 → 解決”組織適合遇到問題時(shí)直接對(duì)號(hào)入座?,F(xiàn)象常見原因排查與解決網(wǎng)關(guān)日志報(bào)串口打開失敗串口路徑錯(cuò)誤或權(quán)限不足確認(rèn)/dev/ttyUSB*存在把用戶加入串口設(shè)備組并重新登錄日志頻繁出現(xiàn)讀取超時(shí)波特率、校驗(yàn)位與設(shè)備不一致對(duì)照設(shè)備手冊(cè)核對(duì)serialSettings必要時(shí)用串口監(jiān)聽工具抓幀設(shè)備數(shù)據(jù)全是0或極大值寄存器地址、類型或字節(jié)序錯(cuò)用modbus調(diào)試腳本逐寄存器讀確認(rèn)實(shí)際值和數(shù)據(jù)類型后再改配置設(shè)備在平臺(tái)側(cè)創(chuàng)建了但沒有遙測(cè)timeseries字段的tag或功能碼不對(duì)檢查type是3還是4tag名是否含特殊字符個(gè)別從站始終無響應(yīng)其他從站正常從站地址沖突或該設(shè)備掉線檢查targetSlaveID是否唯一用Modbus Poll等工具單獨(dú)測(cè)試該地址修改配置后網(wǎng)關(guān)報(bào)JSON解析錯(cuò)誤多寫了逗號(hào)或字段類型不對(duì)用JSON格式化工具校驗(yàn)確認(rèn)port寫成字符串、pollPeriod寫成整數(shù)這些場(chǎng)景里讀超時(shí)是最常見的也是最讓人頭疼的。因?yàn)樗澈罂赡茈[藏著三種不同的問題串口參數(shù)不匹配、接線接觸不良、從站地址不對(duì)。我的經(jīng)驗(yàn)是先抓幀再猜用邏輯排除。4.2 幾個(gè)只有踩坑才知道的串口技巧第一串口權(quán)限問題比你想象中更常見。很多新手在Linux下用主用戶啟動(dòng)網(wǎng)關(guān)以為權(quán)限沒問題結(jié)果某個(gè)插件進(jìn)程以不同用戶身份運(yùn)行打不開串口。建議先確認(rèn)啟動(dòng)網(wǎng)關(guān)的用戶身份并確保該用戶對(duì)串口設(shè)備有讀寫權(quán)限。一般來說把用戶加入串口設(shè)備所屬組重新登錄一次就能解決。第二RS-485是半雙工總線同一時(shí)刻只允許一個(gè)主站發(fā)起請(qǐng)求。調(diào)試時(shí)如果用兩個(gè)工具同時(shí)輪詢總線上會(huì)產(chǎn)生沖突表現(xiàn)為一個(gè)工具正常、一個(gè)工具瘋狂超時(shí)。所以網(wǎng)關(guān)配置的disableOtherSerialInput要開調(diào)試軟件也得在網(wǎng)關(guān)跑起來之前退出。不會(huì)總線上有主站去訪問已經(jīng)被網(wǎng)關(guān)占用的串口設(shè)備。第三抓幀是排查利器。用一個(gè)USB轉(zhuǎn)串口工具并聯(lián)到RS-485的A/B線上監(jiān)聽總線上的Raw數(shù)據(jù)用任意支持串口監(jiān)聽的十六進(jìn)制工具抓包。如果看到網(wǎng)關(guān)發(fā)了請(qǐng)求幀但從站沒回問題大概率在從站側(cè)或地址匹配如果請(qǐng)求幀都沒發(fā)出來問題在網(wǎng)關(guān)配置或串口占用。這樣做判斷比靠猜快得多。第四寄存器地址的起點(diǎn)經(jīng)常誤導(dǎo)人。設(shè)備手冊(cè)標(biāo)注40001對(duì)應(yīng)地址0這是PLC習(xí)慣的標(biāo)識(shí)法。配置里address要填0不填40001。這個(gè)錯(cuò)誤我犯過一次讀出來的數(shù)據(jù)全部錯(cuò)位還帶著異常值后來用腳本從地址0開始挨個(gè)讀才反推出手冊(cè)的對(duì)應(yīng)關(guān)系。第五字節(jié)序遇到32位數(shù)據(jù)時(shí)一定要看設(shè)備手冊(cè)。Modbus RTU標(biāo)準(zhǔn)本身是低字后發(fā)還是高字后發(fā)沒有統(tǒng)一規(guī)定完全看廠商實(shí)現(xiàn)。byteOrder配錯(cuò)不會(huì)報(bào)錯(cuò)只是數(shù)值變得很離譜。懷疑字節(jié)序不對(duì)時(shí)可以把讀到兩個(gè)寄存器的原始值打出來手動(dòng)組合成高字低字對(duì)比實(shí)際工程值很快能確認(rèn)順序。最后再分享一點(diǎn)個(gè)人習(xí)慣。每次改完modbus.json我都不會(huì)直接翻到最后看結(jié)果而是先在配置目錄下用JSON校驗(yàn)工具確認(rèn)格式再啟動(dòng)網(wǎng)關(guān)看日志最后去平臺(tái)看數(shù)據(jù)。這套流程看起來多花了幾分鐘實(shí)際上避開了大量“改了配置沒生效”的無效加班。串口Modbus接入只是物聯(lián)網(wǎng)網(wǎng)關(guān)的起步技能跑通了這一塊后面再接觸TCP從站、多設(shè)備輪詢、斷線重連這些高級(jí)玩法思路都是相通的。至少我在折騰完這套配置之后再看ThingsBoard-GateWay的其他協(xié)議擴(kuò)展明顯感覺配置文件那套“連接參數(shù)設(shè)備映射點(diǎn)位定義”的思維模型是通用的。希望這篇配置方法說明能幫你少走我之前走過的彎路。