Modbus-RTU控制匯川伺服:從通訊協(xié)議到實(shí)戰(zhàn)調(diào)試全指南)
1. 方案背景與選型思路為什么用Modbus-RTU拖匯川伺服先說(shuō)一個(gè)我自己的判斷不是所有伺服現(xiàn)場(chǎng)都值得上EtherCAT也不是所有項(xiàng)目都有條件用PROFINET。很多中小型單機(jī)設(shè)備、舊產(chǎn)線改造、或者“PLC加兩三臺(tái)軸”的工況用Modbus-RTU反而是最省事、最穩(wěn)妥的路線。我接手過(guò)一臺(tái)老式包裝機(jī)PLC是西門子S7-1200伺服用的是匯川MS1H4系列現(xiàn)場(chǎng)沒(méi)有PN從站模塊也沒(méi)有額外預(yù)算上總線耦合器最后就是靠驅(qū)動(dòng)器自帶的RS-485口跑Modbus-RTU把位置和狀態(tài)全部拉進(jìn)了博途。匯川伺服對(duì)Modbus-RTU的支持其實(shí)很完整。大部分匯川伺服驅(qū)動(dòng)器都內(nèi)置了RS-485通訊口支持標(biāo)準(zhǔn)的03讀保持寄存器、06寫單個(gè)寄存器、10十六進(jìn)制0x10寫多個(gè)寄存器等功能碼。這意味著你完全不用額外買通訊卡一根雙絞線就能把PLC和伺服串起來(lái)。相比EtherCAT動(dòng)輒幾百上千的從站模塊費(fèi)用Modbus-RTU的硬件成本幾乎可以忽略而且調(diào)試思路非常直觀——你能在電腦上用一個(gè)串口調(diào)試助手把每一個(gè)指令都看得清清楚楚。當(dāng)然Modbus-RTU不是萬(wàn)能的。它只能實(shí)現(xiàn)“間歇式”的主從問(wèn)答做不到EtherCAT那種同步性。如果你的項(xiàng)目要求多軸插補(bǔ)、高速位置同步、或者周期在1ms以內(nèi)的實(shí)時(shí)控制那直接上EtherCAT或PROFINET IRT別糾結(jié)。但如果只是單軸定位、速度給定、狀態(tài)讀取或者對(duì)同步要求不苛刻的場(chǎng)合Modbus-RTU完全能打而且后期維護(hù)成本低車間電工也能看懂。寫在前面幾個(gè)核心結(jié)論避免你走彎路通訊角色上西門子PLC永遠(yuǎn)做主站匯川伺服做從站這是定死的不存在對(duì)調(diào)的情況。幀結(jié)構(gòu)不搞清楚后面所有配置都是空中樓閣CRC算錯(cuò)一個(gè)字節(jié)伺服就給你回個(gè)異常碼。匯川伺服側(cè)的通訊參數(shù)組站地址、波特率、數(shù)據(jù)格式和西門子側(cè)必須嚴(yán)格一致“9600,8,N,1”這五個(gè)字符一個(gè)都不能錯(cuò)。編碼器線數(shù)262144這個(gè)數(shù)值它是編碼器硬件分辨率不是通訊參數(shù)原樣保留就對(duì)了不要試圖去改。這篇文章我從Modbus-RTU幀結(jié)構(gòu)講起一路講到博途里面的MB_COMM_LOAD和MB_MASTER組態(tài)最后把我的踩坑記錄和排查套路也整理出來(lái)。適合新手照著一步步做也適合給那些“通訊通了一半、狀態(tài)碼亂跳”的兄弟做個(gè)排錯(cuò)參考。2. Modbus-RTU幀結(jié)構(gòu)拆解從字節(jié)序列到CRC校驗(yàn)Modbus-RTU的本質(zhì)就是主站把一段二進(jìn)制數(shù)據(jù)發(fā)給從站從站處理完以后再回一段二進(jìn)制數(shù)據(jù)。這段數(shù)據(jù)不是隨便發(fā)的它有嚴(yán)格的格式要求任何一幀不合法從站都不會(huì)搭理你。2.1 標(biāo)準(zhǔn)幀格式地址碼、功能碼、數(shù)據(jù)域、CRC一個(gè)完整的主站請(qǐng)求幀長(zhǎng)這樣字段長(zhǎng)度說(shuō)明從站地址1字節(jié)范圍1~247對(duì)應(yīng)伺服驅(qū)動(dòng)器設(shè)置的站地址功能碼1字節(jié)03讀寄存器06寫單寄存器0x10寫多寄存器數(shù)據(jù)域N字節(jié)寄存器起始地址、寄存器數(shù)量、寫入值等CRC校驗(yàn)2字節(jié)CRC16低位在前高位在后從站返回的應(yīng)答幀結(jié)構(gòu)更簡(jiǎn)單字段長(zhǎng)度說(shuō)明從站地址1字節(jié)和請(qǐng)求幀的地址一致功能碼1字節(jié)正常情況下原樣返回如果出錯(cuò)最高位置1比如0x83數(shù)據(jù)域N字節(jié)返回的數(shù)據(jù)或異常碼CRC校驗(yàn)2字節(jié)同樣低位在前這里有一個(gè)特別容易翻車的點(diǎn)就是字節(jié)序。Modbus-RTU在傳輸多字節(jié)數(shù)據(jù)時(shí)寄存器地址和寄存器值是“高字節(jié)在前低字節(jié)在后”也就是大端模式。比如你要讀0x0200這個(gè)寄存器報(bào)文里寫的是02 00而不是00 02。但CRC字節(jié)又是“低字節(jié)在前高字節(jié)在后”這兩個(gè)正好相反我第一次調(diào)的時(shí)候就把CRC的順序搞反了在調(diào)試助手里看怎么都對(duì)不上。還有一個(gè)物理層要求幀與幀之間必須要有至少3.5個(gè)字符時(shí)間的靜默間隔。如果兩個(gè)字節(jié)之間的間隔超過(guò)1.5個(gè)字符時(shí)間從站就認(rèn)為一幀結(jié)束了后面再來(lái)的字節(jié)會(huì)被當(dāng)成下一幀處理。這個(gè)時(shí)間換算下來(lái)在9600波特率下大約是3.6ms在115200波特率下大約只有0.3ms。實(shí)際調(diào)試時(shí)我的習(xí)慣是在PLC側(cè)配合TIA的發(fā)送間隔建議保持50~100ms的最小輪詢間隔別圖快。2.2 CRC16校驗(yàn)怎么算給小白一個(gè)能直接抄的算法CRC校驗(yàn)的作用是保證一幀數(shù)據(jù)從主站到從站的過(guò)程中沒(méi)有被干擾破壞。Modbus-RTU使用的是CRC16多項(xiàng)式是0xA001初始值是0xFFFF。計(jì)算邏輯不復(fù)雜但手算是真的累現(xiàn)場(chǎng)調(diào)試你不可能拿筆算一般直接用調(diào)試助手的自動(dòng)CRC功能或者用PLC里現(xiàn)成的庫(kù)函數(shù)。如果你要在單片機(jī)或者自寫上位機(jī)里做可以直接用這個(gè)標(biāo)準(zhǔn)實(shí)現(xiàn)unsigned int crc16_modbus(unsigned char *data, unsigned int len) { unsigned int crc 0xFFFF; unsigned int i, j; for (i 0; i len; i) { crc ^ data[i]; for (j 0; j 8; j) { if (crc 0x0001) { crc (crc 1) ^ 0xA001; } else { crc 1; } } } return crc; }這個(gè)函數(shù)返回的crc值低字節(jié)在前發(fā)出去就對(duì)了。很多初學(xué)者用網(wǎng)上在線CRC計(jì)算工具算出來(lái)的是一個(gè)規(guī)范值但傳輸?shù)臅r(shí)候必須把低字節(jié)寫在前面否則伺服收到以后校驗(yàn)不通過(guò)直接丟棄這一幀表現(xiàn)為“從站完全無(wú)響應(yīng)”。2.3 一個(gè)具體報(bào)文示例讀伺服參數(shù)寄存器以匯川伺服常見(jiàn)的“參數(shù)寄存器映射法”為例很多系列的驅(qū)動(dòng)器會(huì)把H0D-00這類參數(shù)映射到0x0D00寄存器。假設(shè)我手頭這臺(tái)MS1H4驅(qū)動(dòng)器站地址設(shè)置為1波特率設(shè)為96008位數(shù)據(jù)位無(wú)校驗(yàn)1位停止位。我要讀取它的H0D-00參數(shù)值請(qǐng)求幀就是01 03 0D 00 00 01 [CRC低字節(jié)] [CRC高字節(jié)]拆開(kāi)解讀01從站地址103讀保持寄存器0D 00起始寄存器地址0x0D0000 01讀1個(gè)寄存器如果一切正常從站返回01 03 02 00 03 [CRC低字節(jié)] [CRC高字節(jié)]01從站地址回顯03功能碼回顯02返回?cái)?shù)據(jù)的字節(jié)數(shù)2個(gè)字節(jié)00 03寄存器值也就是H0D-00當(dāng)前值為3只要你能在串口調(diào)試助手里看到這一問(wèn)一答說(shuō)明物理鏈路通了驅(qū)動(dòng)器和PLC的串口參數(shù)沒(méi)問(wèn)題。很多現(xiàn)場(chǎng)調(diào)不通第一步就卡在這——建議你在接PLC之前一定先用USB轉(zhuǎn)485串口模塊加一個(gè)網(wǎng)線調(diào)試助手把伺服這一頭調(diào)通再往PLC方向走。這里要特別強(qiáng)調(diào)一下不同型號(hào)的匯川伺服寄存器映射表不完全一樣。IS系列是一種規(guī)則MS1H4系列可能又是另一種規(guī)則還有一部分新系列走的是CiA402對(duì)象字典映射。所以不要死記我上面給的0x0D00動(dòng)手之前先打開(kāi)你手頭那臺(tái)驅(qū)動(dòng)器對(duì)應(yīng)的《通訊協(xié)議手冊(cè)》查一下“Modbus寄存器地址映射表”再把具體地址套進(jìn)幀結(jié)構(gòu)里。幀格式是通用的地址映射才是每個(gè)型號(hào)獨(dú)有的東西。3. 匯川伺服驅(qū)動(dòng)器側(cè)參數(shù)設(shè)置與接線準(zhǔn)備3.1 硬件接線RS-485端口與終端電阻RS-485是半雙工差分通訊兩根線分別叫A和B也有叫和-的現(xiàn)場(chǎng)最常用的接法是屏蔽雙絞線。匯川伺服驅(qū)動(dòng)器上通常提供一個(gè)DB9或者RJ45形式的通訊口具體針腳定義必須查手冊(cè)不要想當(dāng)然。我手頭這臺(tái)MS1H4通訊口是DB9母頭標(biāo)準(zhǔn)定義通常包括3腳RS-485 BD-4腳RS-485 AD5腳GND其他腳位可能涉及CAN或模擬量不要亂接注意A和B千萬(wàn)別接反。接反的典型現(xiàn)象是一問(wèn)一答完全沒(méi)響應(yīng)但在示波器上又能看到波形。如果你把A、B對(duì)調(diào)以后通訊通了說(shuō)明不是波特率問(wèn)題就是線序問(wèn)題。終端電阻RS-485總線要求在物理鏈路的兩端各接一個(gè)120Ω終端電阻用來(lái)消除信號(hào)反射。如果只有一臺(tái)PLC和一臺(tái)伺服點(diǎn)對(duì)點(diǎn)通訊那么干脆兩個(gè)都接上如果有好幾臺(tái)伺服掛在一條總線上那么只在最末端那一臺(tái)上接120Ω電阻中間的設(shè)備都不要接。終端電阻接太多的后果是總線負(fù)載過(guò)重通訊誤碼率會(huì)明顯上升別小看這個(gè)小電阻現(xiàn)場(chǎng)通訊不穩(wěn)定十有八九和它有關(guān)。另外布線方面我的經(jīng)驗(yàn)是RS-485線盡量遠(yuǎn)離變頻器輸出線、動(dòng)力電纜這些強(qiáng)電干擾源。特別是伺服驅(qū)動(dòng)器本身就在變頻器旁邊電氣柜里排線的時(shí)候通訊線務(wù)必單獨(dú)走線槽屏蔽層單端接地。我見(jiàn)過(guò)一個(gè)現(xiàn)場(chǎng)通訊時(shí)好時(shí)壞最后發(fā)現(xiàn)就是通訊線和伺服電機(jī)動(dòng)力線捆在同一個(gè)線管里長(zhǎng)達(dá)兩米分開(kāi)以后問(wèn)題立馬消失。3.2 驅(qū)動(dòng)器通訊參數(shù)配置站地址、波特率、數(shù)據(jù)格式匯川伺服驅(qū)動(dòng)器的參數(shù)通常用面板按鍵來(lái)設(shè)置。雖然不同系列菜單結(jié)構(gòu)略有差異但通訊參數(shù)組一般集中在“H0D”這個(gè)組里分別是參數(shù)號(hào)功能常見(jiàn)取值我的建議H0D-00通訊站地址1~127單臺(tái)設(shè)為1多臺(tái)按1、2、3遞增H0D-01通訊波特率9600/19200/38400/115200推薦38400以上但S7-1200通訊穩(wěn)定性優(yōu)先選9600H0D-02數(shù)據(jù)格式8-N-1 / 8-E-1 / 8-O-1S7-1200默認(rèn)推薦8-N-1H0D-03通訊協(xié)議Modbus-RTU / 自定義必須選Modbus-RTUH0D-04通訊超時(shí)時(shí)間0~255ms保持默認(rèn)或設(shè)100ms以上有一個(gè)非常關(guān)鍵的容易踩的坑修改完通訊參數(shù)以后大多數(shù)匯川伺服需要斷點(diǎn)重啟或者確認(rèn)參數(shù)生效否則面板上顯示的值變了但實(shí)際通訊協(xié)議棧還是舊的。我遇到過(guò)客戶說(shuō)“波特率明明改成115200了怎么調(diào)試助手收不到”的情況其實(shí)就是改完沒(méi)重啟參數(shù)只在RAM里生效一斷電又變回去了。還有一點(diǎn)有的系列通訊參數(shù)組不叫H0D可能叫“CN組”或者“通訊組”面板菜單里翻到帶“通訊”字樣的那一組就對(duì)了。實(shí)在找不到直接在驅(qū)動(dòng)器的用戶手冊(cè)里搜索“Modbus”或者“RS-485”先把參數(shù)清單打印出來(lái)再操作比瞎猜快得多。3.3 編碼器線數(shù)262144是什么為什么不要想著改題主提到的匯川伺服MS1H4在驅(qū)動(dòng)器里顯示默認(rèn)編碼器線數(shù)262144問(wèn)能不能改。這個(gè)數(shù)字其實(shí)是2的18次方意味著電機(jī)編碼器的物理分辨率是每轉(zhuǎn)262144個(gè)脈沖也就是18位絕對(duì)式編碼器。這個(gè)值是編碼器硬件本身決定的由光柵/磁柵的刻線數(shù)和內(nèi)部細(xì)分電路共同固化出來(lái)的不是用戶參數(shù)。你試圖去改這個(gè)值要么發(fā)現(xiàn)參數(shù)是只讀的要么改了之后位置反饋全亂套。那為什么驅(qū)動(dòng)器的參數(shù)列表里會(huì)出現(xiàn)類似“編碼器線數(shù)”的設(shè)置項(xiàng)這里要區(qū)分兩個(gè)概念編碼器內(nèi)部分辨率固定262144不可改獨(dú)立于任何通訊協(xié)議。編碼器輸出分頻/倍頻也就是從驅(qū)動(dòng)器的ABZ脈沖輸出口向外發(fā)送的脈沖數(shù)這個(gè)是可以設(shè)置的。如果你通過(guò)驅(qū)動(dòng)器后面的位置脈沖輸出口把位置反饋分頻成每轉(zhuǎn)10000個(gè)脈沖送給上位機(jī)改動(dòng)的是“輸出分頻”不是編碼器物理分辨率。此時(shí)你通過(guò)Modbus去讀編碼器位置反饋?zhàn)x回來(lái)的還是基于262144計(jì)數(shù)的原始值。所以這兩個(gè)東西千萬(wàn)別混為一談。在Modbus通訊中262144這個(gè)數(shù)值對(duì)應(yīng)到PLC側(cè)的數(shù)據(jù)類型換算很關(guān)鍵。262144大于16位的最大帶符號(hào)整數(shù)32767所以在讀取位置反饋時(shí)通常需要連續(xù)讀兩個(gè)寄存器組成32位數(shù)據(jù)。如果你只用單寄存器讀讀出來(lái)的數(shù)會(huì)莫名其妙地“跳變”甚至出現(xiàn)負(fù)數(shù)。這就是為什么通訊幀里讀位置一次要讀2個(gè)寄存器、4個(gè)字節(jié)而不是1個(gè)寄存器2個(gè)字節(jié)。很多新人在這一步掉進(jìn)坑里以為是數(shù)據(jù)讀錯(cuò)了其實(shí)是32位拆分合并沒(méi)處理對(duì)。3.4 關(guān)鍵參數(shù)核對(duì)表我在每次上電調(diào)試之前都會(huì)列一張核對(duì)表防止漏配、錯(cuò)配。這里分享出來(lái)驅(qū)動(dòng)器的Modbus站地址是否唯一如果是多臺(tái)掛一條總線絕對(duì)不能有兩個(gè)相同地址。波特率、數(shù)據(jù)位、校驗(yàn)位、停止位是否和PLC側(cè)設(shè)置完全一致通訊協(xié)議是否選到了Modbus-RTU而不是匯川私有協(xié)議通訊超時(shí)時(shí)間是否設(shè)置合理太短的話驅(qū)動(dòng)器會(huì)頻繁報(bào)通訊錯(cuò)誤太長(zhǎng)的話故障響應(yīng)慢。伺服是否已經(jīng)處于“待機(jī)”狀態(tài)很多驅(qū)助在報(bào)HAL報(bào)警硬件過(guò)流或者急停狀態(tài)下通訊棧是不會(huì)正常響應(yīng)主站指令的。編碼器線數(shù)參數(shù)是否保持默認(rèn)值確認(rèn)沒(méi)有人動(dòng)過(guò)“編碼器線數(shù)”或“反饋分頻”相關(guān)參數(shù)。這一套檢查下來(lái)能過(guò)濾掉絕大多數(shù)“通訊不通”的初級(jí)問(wèn)題。4. 西門子PLC側(cè)配置實(shí)戰(zhàn)以S7-1200為例西門子S7-1200跑Modbus-RTU主站核心就是博途軟件里的兩個(gè)指令MB_COMM_LOAD和MB_MASTER。前者負(fù)責(zé)初始化串口參數(shù)后者負(fù)責(zé)發(fā)起一次讀寫請(qǐng)求。下面我按從易到難的順序把每一步拆開(kāi)講。4.1 硬件組態(tài)先讓CPU認(rèn)識(shí)你的RS-485口S7-1200本身不帶RS-485物理接口一般通過(guò)兩種方式擴(kuò)展通訊模塊CM1241 RS-422/485這也是最常用的一種。西門子CB1241這個(gè)是以RS-485為主的板載通訊板緊湊型CPU可以插。組態(tài)的時(shí)候把CM1241模塊拖到CPU左側(cè)的導(dǎo)軌上博途會(huì)自動(dòng)分配一個(gè)硬件標(biāo)識(shí)符。這個(gè)標(biāo)識(shí)符在MB_COMM_LOAD里要用到具體值不用背在指令里拖拽Port口的時(shí)候直接選擇硬件標(biāo)識(shí)符即可。很多新手容易漏掉的一步是CM1241模塊的接口類型要在設(shè)備視圖里確認(rèn)選成“RS-485”而不是“RS-422”。RS-422是全雙工四線制RS-485是半雙工兩線制選錯(cuò)了通訊肯定廢。還有如果通訊模塊上帶撥碼開(kāi)關(guān)或DIP開(kāi)關(guān)檢查工作模式要撥到RS-485側(cè)有的模塊出廠默認(rèn)是RS-422不撥過(guò)來(lái)后面的工作全白搭。4.2 MB_COMM_LOAD端口初始化MB_COMM_LOAD負(fù)責(zé)把CM1241的串口初始化成Modbus-RTU模式。把指令拖進(jìn)OB1之后輸入?yún)?shù)這么設(shè)置參數(shù)意義推薦值PORT通訊模塊硬件標(biāo)識(shí)符拖拽硬件標(biāo)識(shí)符BAUD波特率和伺服側(cè)一致比如9600PARITY校驗(yàn)方式0表示無(wú)校驗(yàn)1為奇校驗(yàn)2為偶校驗(yàn)MB_DB連接數(shù)據(jù)塊留空或新建空DBRTS_ON_DLY發(fā)送RTS延遲0RTS_OFF_DLY發(fā)送后RTS釋放延遲0RESP_TO應(yīng)答超時(shí)時(shí)間100ms左右多從站建議加大有一點(diǎn)值得注意MB_COMM_LOAD的使能端REQ要接一個(gè)常ON信號(hào)也就是說(shuō)這個(gè)指令要一直保持啟用狀態(tài)。很多新手用一個(gè)邊沿觸發(fā)去初始化端口結(jié)果發(fā)現(xiàn)只有第一個(gè)掃描周期端口被初始化了一下后面通訊全斷。RESP_TO這個(gè)參數(shù)是主站等待從站應(yīng)答的超時(shí)時(shí)間。如果從站比較多或者走線比較長(zhǎng)應(yīng)答延時(shí)也會(huì)變大建議設(shè)到200ms以上。設(shè)太短會(huì)誤報(bào)超時(shí)設(shè)太長(zhǎng)又會(huì)拖慢輪詢周期需要根據(jù)現(xiàn)場(chǎng)實(shí)測(cè)來(lái)權(quán)衡。4.3 MB_MASTER讀寫指令地址換算與觸發(fā)方式初始化完成以后真正干活的是MB_MASTER。它的幾個(gè)關(guān)鍵參數(shù)參數(shù)意義使用建議REQ觸發(fā)請(qǐng)求用一個(gè)周期脈沖或定時(shí)器脈沖不能一直常ONMB_MODE功能選擇0表示讀1表示寫MB_DATA_ADDR寄存器地址用40001偏移的方式MB_DATA_LEN數(shù)據(jù)長(zhǎng)度單位是字Word讀32位數(shù)據(jù)請(qǐng)?jiān)O(shè)2MB_DATA_PTR數(shù)據(jù)存放指針指向一個(gè)數(shù)組或DB變量DONE完成標(biāo)志完成一次讀寫后置TRUE一個(gè)周期ERROR錯(cuò)誤標(biāo)志有錯(cuò)誤時(shí)置TRUESTATUS錯(cuò)誤代碼需要監(jiān)控的重點(diǎn)關(guān)鍵中的關(guān)鍵MB_DATA_ADDR的換算方法。S7-1200的MB_MASTER秉承Modbus傳統(tǒng)尋址習(xí)慣如果你要讀保持寄存器4區(qū)地址從40001開(kāi)始。我前面寫的寄存器0x0200換算成十進(jìn)制是512那么在MB_DATA_ADDR這一欄你應(yīng)該填40001 512 40513如果你想一次讀兩個(gè)寄存器組成32位位置值那么MB_DATA_LEN就填2MB_DATA_PTR指向的數(shù)組至少要有2個(gè)字長(zhǎng)的空間。博途里比較推薦的做法是新建一個(gè)全局?jǐn)?shù)據(jù)塊里面放一個(gè)包含若干Word元素的數(shù)組比如DATA_BLOCK ModbusData {VERSION: 0.1, NON_RETAIN} VAR HoldingRegs : Array[0..31] of Word; ReadPos : DInt; // 用DInt接收32位位置值 CtrlWord : Word; StatusWord : Word; END_VAR讀回來(lái)的原始數(shù)據(jù)通過(guò)“合并字”操作高位字左移16位再或上低位字就能得到完整的32位位置。如果你用的是SCL可以直接這樣寫#ReadPos : WORD_TO_DINT(#HoldingRegs[0]) * 256 * 256 WORD_TO_DINT(#HoldingRegs[1]);這里的HoldingRegs[0]是高16位HoldingRegs[1]是低16位。有些驅(qū)動(dòng)器回讀的時(shí)候寄存器排列順序可能相反如果算出來(lái)的位置值在跳變、數(shù)值不對(duì)把這兩個(gè)字的順序?qū)φ{(diào)就行。這個(gè)“字節(jié)序/字序不一致”的問(wèn)題是Modbus調(diào)試?yán)镒钫勰ト说囊粋€(gè)坑后面我會(huì)專門展開(kāi)說(shuō)。4.4 用監(jiān)控表驗(yàn)證通訊狀態(tài)程序?qū)懞昧瞬⒉淮砣f(wàn)事大吉。打開(kāi)博途的監(jiān)控表把MB_MASTER的DONE、ERROR、STATUS變量拖進(jìn)去實(shí)時(shí)監(jiān)控DONE置TRUE說(shuō)明本次讀寫正常完成。ERROR置TRUE說(shuō)明本次請(qǐng)求出錯(cuò)看STATUS代碼定位問(wèn)題。STATUS顯示16#8180經(jīng)典錯(cuò)誤表示“從站無(wú)響應(yīng)”優(yōu)先排查接線、站地址、波特率。STATUS顯示16#8185通常是“從站返回異常響應(yīng)”需要去查伺服側(cè)的功能碼是否支持、寄存器地址是否存在。另外建議在MB_MASTER的REQ端用定時(shí)器做一個(gè)周期脈沖。最簡(jiǎn)單的做法是用TON搭一個(gè)自復(fù)位定時(shí)器例如IF #timer.Q THEN #req : TRUE; #timer(IN : FALSE); ELSE #req : FALSE; #timer(IN : TRUE, PT : T#200MS); END_IF;這樣每200ms觸發(fā)一次MB_MASTER請(qǐng)求。200ms這個(gè)周期對(duì)于絕大多數(shù)定位控制來(lái)說(shuō)足夠用了。如果你有急停、報(bào)警這類需要快速響應(yīng)的信號(hào)建議不要靠Modbus輪詢來(lái)實(shí)現(xiàn)還是接硬線或者走PN口安全等級(jí)完全不是一個(gè)層面。MB_MODE的使用也不復(fù)雜讀操作填0寫操作填1。寫單個(gè)寄存器用功能碼06由塊內(nèi)部根據(jù)參數(shù)自動(dòng)選擇寫多個(gè)寄存器的時(shí)候MB_DATA_LEN填要寫的字?jǐn)?shù)即可。常見(jiàn)的應(yīng)用比如把位置給定值連續(xù)寫兩個(gè)寄存器或者通過(guò)寫控制字去觸發(fā)伺服使能、復(fù)位報(bào)警。5. 聯(lián)調(diào)過(guò)程中踩過(guò)的坑與排查鏈路這一部分是我最想分享的因?yàn)槲乙?jiàn)過(guò)太多人在通訊聯(lián)調(diào)階段卡上兩三天最后發(fā)現(xiàn)都是些很基礎(chǔ)但容易被忽略的問(wèn)題。5.1 從站無(wú)響應(yīng)8180錯(cuò)誤的完整排查順序當(dāng)STATUS出現(xiàn)16#8180時(shí)我的排查順序是這樣先看一眼伺服驅(qū)動(dòng)器面板有沒(méi)有報(bào)通訊錯(cuò)誤或者通訊超時(shí)報(bào)警。如果伺服側(cè)報(bào)警了大概率是驅(qū)動(dòng)器根本沒(méi)收到有效幀問(wèn)題在幀格式或者物理連線上。第二步用電腦接串口調(diào)試助手替代PLC去發(fā)一幀標(biāo)準(zhǔn)的03讀寄存器報(bào)文。如果串口助手也得不到應(yīng)答那么問(wèn)題一定在伺服側(cè)和通訊線路上基本可以排除PLC的配置問(wèn)題。這時(shí)候重點(diǎn)檢查三件事A/B是否接反、波特率數(shù)據(jù)格式是否一致、驅(qū)動(dòng)器是否要重新上電才生效參數(shù)。如果串口助手能正常應(yīng)答但PLC通訊依然是8180那么問(wèn)題回到PLC側(cè)檢查MB_COMM_LOAD的PORT參數(shù)是否選對(duì)硬件標(biāo)識(shí)符。檢查MB_COMM_LOAD的BAUD、PARITY是否和伺服完全一致。檢查MB_MASTER的MB_DATA_ADDR換算是否正確。很多人填了個(gè)40513結(jié)果寫成40531這種低級(jí)錯(cuò)誤也會(huì)導(dǎo)致報(bào)錯(cuò)。檢查REQ觸發(fā)方式如果REQ一直是TRUE而不產(chǎn)生邊沿MB_MASTER是不會(huì)發(fā)起請(qǐng)求的。8180這個(gè)錯(cuò)誤在西門子的官方文檔里叫“無(wú)應(yīng)答從站在應(yīng)答時(shí)間窗內(nèi)未響應(yīng)”。它不會(huì)告訴你從站在哪里斷的所以一定要配合串口調(diào)試助手做“雙端驗(yàn)證”——一頭PLC發(fā)一頭電腦看RS-485線上到底有沒(méi)有數(shù)據(jù)在走。5.2 數(shù)據(jù)錯(cuò)位或者說(shuō)數(shù)據(jù)總是跳變的根因數(shù)據(jù)類型與字節(jié)序通訊通了數(shù)據(jù)卻有異常這比通訊不通更讓人頭疼。最常見(jiàn)的一種現(xiàn)象是讀回來(lái)的位置值一會(huì)兒是一個(gè)巨大正數(shù)一會(huì)兒是一個(gè)負(fù)數(shù)一會(huì)兒又是0。十有八九是32位數(shù)據(jù)拆成兩個(gè)16位寄存器后合并順序不對(duì)。PLC里Modbus寄存器默認(rèn)按字處理。伺服保存一個(gè)32位位置值高16位在一個(gè)寄存器低16位在下一個(gè)寄存器。你用MB_MASTER連續(xù)讀兩個(gè)字返回的順序是先高后低。但問(wèn)題是不同的驅(qū)動(dòng)器和不同的PLC庫(kù)對(duì)于“哪個(gè)寄存器是高字”的規(guī)定偶爾會(huì)相反。所以我的做法是讀回來(lái)以后先不解釋成人眼看得懂的值直接把兩個(gè)原始字打印出來(lái)算一下實(shí)際電機(jī)轉(zhuǎn)一圈看變化的是哪個(gè)寄存器——如果轉(zhuǎn)一圈后高字寄存器有變化說(shuō)明當(dāng)前順序沒(méi)問(wèn)題如果是低字寄存器在快速變化而高字幾乎不動(dòng)說(shuō)明這其實(shí)是一個(gè)32位數(shù)據(jù)的低位部分順序沒(méi)錯(cuò)只是你沒(méi)把它和高字合起來(lái)。另外還有一個(gè)非常隱蔽的坑西門子自身的數(shù)據(jù)存儲(chǔ)是大端格式而有些伺服在寄存器里存數(shù)據(jù)時(shí)用的是小端格式。你讀回來(lái)一個(gè)字比如16#1234在PLC里顯示的是1234但實(shí)際物理意義可能是34 12。這就要在PLC側(cè)做“字節(jié)交換”處理。圖形化編程里可以用SWAP指令SCL里可以這樣寫#rawValue : SWAP(WORD_TO_BYTE(#HoldingRegs[0]), 1);更通用一點(diǎn)的做法是寫一個(gè)小的轉(zhuǎn)換函數(shù)把所有讀回來(lái)的字都過(guò)一遍字節(jié)交換除非你能確認(rèn)驅(qū)動(dòng)器手冊(cè)里明確寫了“高字節(jié)在前”。在匯川的協(xié)議手冊(cè)里通常會(huì)說(shuō)Modbus寄存器默認(rèn)為高字節(jié)在前但有些功能碼里嵌套的數(shù)據(jù)區(qū)會(huì)有特殊規(guī)則所以“先驗(yàn)證再固化邏輯”才是正解。5.3 通訊抖動(dòng)的元兇波特率、終端電阻與地電位如果你發(fā)現(xiàn)通訊時(shí)好時(shí)壞有一個(gè)規(guī)律性的“讀幾幀正常隔一會(huì)兒就失敗一幀”先別急著懷疑PLC程序。這類間歇性通訊問(wèn)題絕大多數(shù)出在物理層。第一個(gè)要懷疑的就是終端電阻。兩根線之間沒(méi)接終端電阻信號(hào)在末端會(huì)反射造成波形畸變。你可以在RS-485總線兩端并上120Ω電阻試試很多“偶發(fā)通訊超時(shí)”立刻就好了。第二是波特率9600和115200在短距離點(diǎn)對(duì)點(diǎn)的情況下區(qū)別不大但如果線纜長(zhǎng)度超過(guò)50米或者現(xiàn)場(chǎng)干擾源多建議保守選用9600或19200代價(jià)只是輪詢慢一點(diǎn)換來(lái)的是穩(wěn)定。第三個(gè)是地電位差。不同設(shè)備的GND如果沒(méi)有可靠共地A、B線之間存在較大的共模電壓超過(guò)收發(fā)器承受范圍通訊就會(huì)不正常。解決辦法是把PLC的M端和伺服驅(qū)動(dòng)器的GND用一根線連起來(lái)。注意不是把保護(hù)地PE和信號(hào)地混為一談而是在設(shè)備之間接通信號(hào)參考地。我還遇到過(guò)一種情況通訊線屏蔽層兩端接地結(jié)果形成了地環(huán)路反而引入干擾。正確的做法是屏蔽層“單端接地”通常是靠近PLC那一端接地。這個(gè)話題在工控現(xiàn)場(chǎng)討論很多我的經(jīng)驗(yàn)是先把“不接地、兩端都接地、單端接地”三種狀態(tài)都試一遍用示波器看效果哪種最干凈就保留哪種。5.4 伺服報(bào)警導(dǎo)致的通訊假正常還有一種現(xiàn)象特別迷惑人PLC和伺服之間通訊正常讀寫都返回成功但驅(qū)動(dòng)就是不動(dòng)或者一使能就報(bào)錯(cuò)。這種情況多半不是通訊問(wèn)題而是伺服本身的報(bào)警狀態(tài)沒(méi)有復(fù)位。匯川伺服的使能/停機(jī)一般通過(guò)控制字來(lái)控制常見(jiàn)的控制字包括伺服使能、清除報(bào)警、啟動(dòng)正轉(zhuǎn)、啟動(dòng)反轉(zhuǎn)。如果你通過(guò)Modbus寫了控制字但伺服沒(méi)反應(yīng)先看驅(qū)動(dòng)器面板有沒(méi)有報(bào)警碼。常見(jiàn)的報(bào)警比如HAL硬件過(guò)流、Et過(guò)載、SEr編碼器異常等這些報(bào)警不消除你不管寫什么控制字伺服都不會(huì)進(jìn)入可運(yùn)行狀態(tài)。清除報(bào)警的通用做法在控制字里把“故障復(fù)位”位置1保持一段時(shí)間后再?gòu)?fù)位為0。具體是哪一位取決于你用的是匯川私有控制字還是CiA402對(duì)象字典的0x6040控制字。如果是標(biāo)準(zhǔn)CiA402bit7是故障復(fù)位bit3是使能運(yùn)行——操作順序一般是先給一個(gè)“上電”狀態(tài)的組合0x0006或0x0007再置位bit3然后保持。不要一上來(lái)就先把所有位都寫滿那樣很多驅(qū)動(dòng)器會(huì)直接報(bào)控制字錯(cuò)誤。6. 提速與穩(wěn)定性優(yōu)化建議通訊調(diào)通了能讀寫數(shù)據(jù)了只算完成了50%。剩下的一半是怎么讓系統(tǒng)在產(chǎn)線上穩(wěn)定跑幾個(gè)月不出幺蛾子。這里分享幾個(gè)我在現(xiàn)場(chǎng)總結(jié)的優(yōu)化思路。6.1 輪詢周期與寄存器批量讀取Modbus-RTU是半雙工一問(wèn)一答通訊耗時(shí)主要取決于報(bào)文長(zhǎng)度和波特率。在115200波特率下一個(gè)簡(jiǎn)單的6字節(jié)請(qǐng)求幀加9字節(jié)應(yīng)答幀傳輸時(shí)間大約在1.3ms左右加上驅(qū)動(dòng)器的處理延遲和PLC的掃描周期實(shí)際一個(gè)完整問(wèn)答大概要10~20ms。如果你有多個(gè)數(shù)據(jù)要讀千萬(wàn)不要一次只讀一個(gè)寄存器。比如你要同時(shí)讀狀態(tài)字、當(dāng)前位置、當(dāng)前速度這三個(gè)數(shù)據(jù)如果分布在連續(xù)寄存器段就一次讀3個(gè)寄存器把MB_DATA_LEN設(shè)成3。這樣一次問(wèn)答就把三個(gè)值全部拿回來(lái)效率翻倍還不起沖突。反過(guò)來(lái)寫入操作也要合并。比如設(shè)備啟動(dòng)時(shí)既要給目標(biāo)位置又要給速度、加速度如果這幾個(gè)寄存器是連續(xù)的優(yōu)先用寫多個(gè)寄存器的方式一次寫入而不是一條一條寫。這樣不僅通訊效率高更重要的是多個(gè)數(shù)據(jù)在伺服側(cè)是同一幀里被接收處理的不存在“先更了位置、后更了速度”這種中間狀態(tài)導(dǎo)致的誤動(dòng)作。6.2 掉電重啟與故障恢復(fù)機(jī)制Modbus-RTU有個(gè)特性從站掉電再上電以后通訊棧可能需要幾百毫秒才能重新就緒。如果PLC在驅(qū)動(dòng)器還在初始化的時(shí)候就開(kāi)始發(fā)讀寫請(qǐng)求很可能會(huì)得到異常響應(yīng)。因此我的程序里通常會(huì)加一個(gè)上電等待邏輯PLC啟動(dòng)后先延遲1~2秒再開(kāi)始正常的Modbus輪詢。這個(gè)邏輯雖然簡(jiǎn)單但在冷啟動(dòng)現(xiàn)場(chǎng)非常管用。另一個(gè)容易被忽略的是故障恢復(fù)。當(dāng)通訊連續(xù)失敗幾次時(shí)程序里要有計(jì)數(shù)。超過(guò)閾值就置一個(gè)“通訊故障”標(biāo)志讓設(shè)備進(jìn)入安全狀態(tài)而不是一直盲目重試。因?yàn)镸odbus的請(qǐng)求重試會(huì)占用PLC的掃描周期重試期間你可能其他邏輯都卡住了。我習(xí)慣的恢復(fù)策略是連續(xù)失敗5次置故障故障后每500ms重試一次連續(xù)成功2次后自動(dòng)清除故障。這樣就避免了“偶爾一幀超時(shí)就必須人工復(fù)位”的尷尬情況又能保證真斷線時(shí)設(shè)備能停下來(lái)。6.3 從Modbus到EtherCAT這個(gè)方案的上限與下一步最后說(shuō)句大實(shí)話Modbus-RTU這套方案解決的是“夠用”的問(wèn)題不是“最優(yōu)”的問(wèn)題。當(dāng)你開(kāi)始追求更短的周期、更小的通訊抖動(dòng)、或者需要多軸聯(lián)動(dòng)時(shí)就應(yīng)該考慮切換到EtherCAT或者PROFINET了。但是切換到高速總線并不意味著Modbus的經(jīng)驗(yàn)全部作廢。你在匯川伺服上設(shè)的站地址、編碼器分辨率、控制字邏輯在EtherCAT里依然存在只是訪問(wèn)方式從“寄存器的03/06功能碼”變成了“對(duì)象字典的SDO/PDO映射”。你在Modbus階段把寄存器地址、控制字、狀態(tài)字的邏輯理清楚了到EtherCAT階段基本上就是把同樣的東西換個(gè)皮來(lái)做。以我個(gè)人的經(jīng)驗(yàn)一臺(tái)匯川伺服從Modbus-RTU順利遷移到EtherCAT如果之前的基礎(chǔ)資料齊全整個(gè)改造大概只要半天。真正消耗時(shí)間的是物理接線和同步參數(shù)學(xué)調(diào)而不是那些控制邏輯。所以如果你的設(shè)備現(xiàn)在只是單軸定位、速度給定這種輕量級(jí)應(yīng)用就放心用Modbus-RTU跑如果未來(lái)有明確的多軸同步規(guī)劃那從一開(kāi)始選型就要考慮帶EtherCAT口的伺服別為了省一點(diǎn)硬件成本把后面的擴(kuò)展路堵死。做設(shè)備選型的時(shí)候看得稍微遠(yuǎn)一點(diǎn)后面會(huì)省很多事。