PS. 基本 RS485 通訊原理在 RS232 轉 RS485 演進史 一文已經提過,這邊不再贅述,不過該文對於 Linux 的描述已經過時,現行 Linux kernel 已經支援 RS485 通訊。
Single Master/Multi-Slaves
網路拓樸如圖 1 所示,這是最常見也是最簡單的形式,他的原理很簡單,所有 Slaves 都是被動的角色,只有 Master 可以主動送出命令(Request),Slave 只有在收到命令時依據 Station ID(如上圖中 Station#1-#3,業界稱為站號)決定要不要做出回應(Response),如下圖所示:
這種通訊協議,在工控中以 Modbus RTU 最為常見,在 Modbus RTU 中恰好也如圖 2 所示,把站號放在 frame 的第一個 byte,本文後續也會以 Modbus RTU 作為範例。
Modbus RTU 看似簡單,在實作上與實務中卻隱藏了不少問題。
問題 1: Slave 如何處理不屬於自己的命令?
由圖 1 可以發現,所有的 RS485 傳輸線都並聯在一起,所以 Master 送出命令之後所有 Slave 都會收到,前面講過 Slave 是依據站號決定要不要回應,但如果您以為 Slave 收到第一個 byte 發現站號不屬於自己,就後續就直接不理會,您就大錯特錯了。
正確的處理方式是這樣,以前面三台 Slave 為例,如果 Master 發出命令要與 Station#1 通訊,Station#2 與 3 必須接收 Master 與 Station ID#1 的 Request/Response frame 如下圖所示,否則您的程式會精神錯亂。
Station#2, #3 的流程如下:
- 接收 Master Request -> Station#1 Request 但不處理(需要做一定程度的 frame parsing,否則不知道 Request 的長度)
- 等待 Station#1 Response -> Master
- 接收 Station#1 Response -> Master 但不處理,與 1. 同樣要做某種程度的 frame parsing,否則無法得知正確長度。
libmodbus 是一份很好的參考資料,其中 _modbus_rtu_receive() 用了一個狀態變數 confirmation_to_ignore 紀錄是否收到一個不屬於自己的 request frame,當收到不屬於自己的 request frame,就會把 confirmation_to_ignore 設成 TRUE,接著呼叫 _modbus_receive_msg() 進行前述的步驟 2-3。
問題 2: 回應特別慢的 Slave 會拖垮通訊速度
以前面三台 Slave 為例,假設 Station#3 在收到 Request 與回應 Response 間有很大的延遲(如下圖所示),這個延遲時間就會拖垮整體通訊速度,Station#1 與 #3 就要花很久的時間等待 Station#3 。雖然說 Modbus spec 規定至少要延遲 3.5 char 的時間,但筆者碰過很多設備的延遲時間早就是 3.5 的 n 倍了。
(為了對付這個問題,libmodbus 還提供了 response_timeout 這個變數用來調校)
(為了對付這個問題,libmodbus 還提供了 response_timeout 這個變數用來調校)
依筆者過去的經驗,最常碰到的是溫控器回應慢、PLC or Remote I/O 回應快,在過去做 HMI 的日子裡,通常就是請客人接到不同的 COM Port,避開這樣的問題。
不過有次碰到一位做真空燒烤爐的客戶,他的溫控器特多,印象中好像是 6-8 台吧?一般 HMI 不可能有那麼多 COM Port 讓他一台接一個 COM Port(一般 HMI 最多 3 個 COM Port)。
後來這位客人自己去買了一台 M 牌還是 A 牌的 Modbus Gateway,網路拓樸變成如下:
那為何透過一台 Modbus Gateway 就能增加通訊速度呢?除了原本需要從第1 台輪詢到第 8 台,變成因為有 8 個 COM Port 可以一次讀 8 台(平行讀取),Modbus Gateway 通常還提供一種功能,在 M 牌稱為 Agent Mode:
簡單來說,Modbus TCP Master 讀取的是 Modbus Gateway 的內部記憶體(Cache),這樣帶來的好處是如果有多台 Master,也不會感覺到通訊速度下降:
圖 7、圖 8 中的 Cache 還可以玩出很多花樣,比方圖 8 中兩台 HMI 要讀取的 Modbus Holding Register、Coil... 通常位址會重疊,這時候 Agent 還可以把位址加以拼接,減少左側 RS485 通訊時的 round-trip time,筆者在一篇文章中也提到了相關演算法,有興趣的朋友可以看看。
順帶一提,這也不是這些 Modbus Gateway 廠商的獨創發明,早在 1x 年前這就是 HMI 的標準功能,因為 HMI 有太多背景服務都想讀取控制器的資料,如果放任這些背景服務直接跟控制器要資料,鐵定會大塞車,所以只能放在 cache,當然這會創造出另外一個問題「如果控制器的某個位址內的值被某個背景服務更改了怎麼辦?」事實上這個問題正是各家 HMI 廠商最難突破的點,也就是如何同時在效能與資料不同步的機率間取得平衡,筆者在某篇文章中也涉獵了這個問題。
尾聲
以現在 LoRa、NB-IoT 等等的聲勢來看...討論 RS485 似乎有點落伍?但事實上 RS485 仍有成本超低,需要零組件極少,抗干擾強,超長傳送距離等優點,不少廠商仍靠著他賺得盆滿缽滿,除非哪天 LoRa 變成白菜價,也沒有資安等問題才可能威脅到 RS485 吧?
本以為一篇就能寫完,後來發現得寫成兩篇,在後續篇章中各位會發現 RS485 這兩根線居然能搞出這麼多花樣,敬請期待...
很好。
回覆刪除有些東西老是死握著不放,也沒有代表你就比較高明。
因為時代技術演變是瞬息萬變的,你所說的LoRa 或NB-IoT 會不會成為新
標準?我也不確定,但我確定的是:只要有需求,而傳統的規格跟不上,
那肯定就會一直出現新規格來突破。這個時代,已經不像以前那樣子,
一個老東西還可以讓少數人,可以慢慢地吃個十年或二十年的啦。
不是嗎?
非常同意~這是一種時機財,早就沒小弟的機會了
刪除很多新東西很花俏,實際上能用的場合還是有限...工控做久就會知道有些經典通訊協議是死不了的。老東西簡單,但穩定性都經過時間驗證。新東西給零售市場試水溫是不錯,能不能用看普及度就是最好的證明了。
刪除你好,
回覆刪除一般來說,geteway ModbusTCP端的ip是例如192.168.1.3等等的區域網域ip.
在處處講求IoT應用的現今環境,透過ModbusTCP geteway的機制,雖然已能將設備device的ModbusRTU格式"打包"上網(例如大大曾提過的mbusd),但卻也只能應用於區域網域內.
如果客戶的需求是希望geteway的ModbusTCP能由"Server"成為"client"身份,主動connect到遠方主機(例如AWS cloud主機).
這樣的需求情況下,是否已違反了ModbusTCP的架構機制?(例如mbusd就無法設為client,只能是server).
怎樣才能讓geteway端的ModbusTCP能連上遠端?進入IoT的應用.
"...gateway 的 Modbus TCP 能由 "Server"成為"client" 身份
刪除..."
Modbus RTU Master->Modbus TCP client->Modbus TCP server
是 modbus gateway 標準功能,mbusd 只是還沒做進去而已,筆者也也有寫一套,只是沒時間整理放到 github(否則就可以跟 mbusd 合體了,哈哈哈)
不過您應該不是問這個,如果您是想問「有哪家大廠已經有Modbus to AWS 解決方案?我只要照著山寨,老闆跟客戶都不會來質疑我」,抱歉我沒有答案,我相信這不是技術問題,您絕對有辦法把 Modbus 轉成 AWS 接受的格式拋上去(資料同步可能會是個技術問題),或是做個 proxy 串接。
至於有沒有違反 Modbus spec?這樣說好了,Modbus 是 20-30 年前就定下來的通訊協議,您說20-30年前有可能未卜先知今日會有 IoT or AWS?而且市面上早有一堆 Modbus to Ethernet/IP,Modbus to BACnet,Modbus to SNMP...一堆把Modbus轉成XXX的gateway,照這樣說來連上AWS又何錯之有?
所以我想真正的問題應該是...「要怎麼說服老闆/主管/客戶,我的Modbus to AWS方案不需要什麼維護成本,就能解決客戶的問題?」
把最外層路由的Port指定到下面你的Gateway就上網際網路了阿 這跟是不是Modbus一點關係都沒 是MIS的知識吧 你跑到南極也能Scan到的你的Slave 問題是你的設備控制權可能會裸露在外 有資安風險
刪除