2018年12月3日 星期一

HMI 回憶錄 (9)

軟體篇 PART4

前篇的補充與一些雜七雜八的東西

n = ?

前篇有張圖如下:

假設 n 單位為 ms,那應該是 30ms,20ms,10ms 還是 1ms?

筆者的答案是 1ms,原因如下:
  • 現行 PLC scan time 大都 < 1ms
  • 客人一定會給你讀好讀滿 PLC 位址
  • 目前流行 OS 大都能提供 1ms 精度
  • RS232/422/485 受限於 baudrate (很多 PLC 不支援 115200bps),所以必須從 interval 補一些回來。
當然第三點如 Modbus 這種明確規範 interval 的 protocol 來說,也不是你想多快就有多快,當然以 spec 為優先。不過整體而言,interval 越小越好。

很多人搞不好會說這些不是廢話嗎!?

為何筆者會提出來?這一點大家在 PC 上比較沒有感覺,但是如果在 Embedded System 上,如果一筆資料一秒鐘變化一百次,那畫面跟著變化 100 次 = 100FPS(100 frames per second),你覺得會發生什麼事?

大家都知道 PC 上有 3D 顯示卡,隨便都幫你加速到 60FPS,100FPS 也有可能。那您覺得 Embedded System 上那顆不到 10 USD 的 SoC 效能有可能這麼好嗎?就算 HMI 畫的只是簡單的 2D 圖,這樣玩也很傷。那你總不能說 ARM9 跑不動我換 ARM10 -> ARM11 -> Cortex A8 -> A9 這樣一路上去吧!?

會有這種事情發生,是因為大部分的 GUI framework 都是 event driven,將資料變化視為一種 event,資料變化 GUI 也跟著一起變化

對於一般的 GUI App 來說問題不大,比如 Word、PowerPoint 這些軟體不會一直接收大量的資料更新 UI,多半是與 keyboard, mouse 這些互動比較多。人能產生多快多大的資料呢?加上 PC 驚人的效能,所以大多數人沒感覺。結果不少 PC 軟體工程師把這個習慣也一併帶到 Embedded System 上,結果 CPU Loading 一路往上衝,然後就吵著說 CPU 爛,記憶體不夠要往上加,老闆聽起來覺得怪怪的但也不知道怎麼反駁!?

如果要修正這個問題:
  1. 把 GUI 更新這件事跟 PLC 取得資料這件事斷開鎖鏈,斷開魂結...
  2. FPS 只要有 15FPS 即可
1. 斷開後 GUI 何時更新畫面?很簡單,用個 timer 每 67ms (1000ms / 15 = 67ms) update 一次就好。

2. 為何 15FPS 就好?
  • 以筆者這 1 年多來搞 IPcam 的經驗,video streaming 來說 15FPS 以上就算堪用
  • 既然是做自動化,盯著螢幕看的機會會很多嗎?又不是打電動拿根搖桿盯著螢幕好幾個小時,那 30FPS, 60FPS, 100FPS 有意義嗎?何不把 CPU loading 省下來做更多事?以前一點 67ms 來說,如果更新畫面需要 5ms,剩下 62ms 多補啊!
關於 2. 還有個小故事,有天筆者跟同樣做自動化的同學閒聊(PC based喔!),我問他軟體有沒有弄什麼動畫? 他說沒有就放張底圖而已,他說既然做自動化怎麼會沒事就去碰螢幕呢,越自動化人不是越少介入越好?真是當頭棒喝阿! 

筆者依稀記得筆者接觸的初代 HMI 才 10FPS 而已!但客人覺得好用,一路長賣到現在還有人用,CPU 停產了想辦法去對岸掃貨。反而第二代 CPU 更強,記憶體更大,用 Qt + Linux,結果客人三不五時客訴,說通訊不夠快,畫面卡卡的,然後筆者就被叫去罰站。

當時犯的錯誤,就是把 GUI update 跟 PLC 通訊放在同一個 thread:
  • 由上述可知 GUI 本身沒辦法到 100FPS,就假設降到 30FPS 好了
  • PLC 33ms 才更新一次(1000ms/30 = 33ms),對於 GUI 或許很夠了,但對於 Alarm, Macro, Data Logger 就有問題
當時的日子真的很辛苦,反正客戶就覺得是你通訊的問題,就叫筆者去罰站,客戶就罵同樣的畫面設計在其他家 HMI 都沒問題,你們怎麼問題一堆 !@#^&*...筆者也只能靠些 work around 的手段解決,一邊說服自己出差是當作賺經驗。好在當時業務與FAE大哥也算明理沒有跟著一起落井下石(當然這兩位大哥也是業界老手有 sense 的,每家 HMI spec 比筆者還清楚)。

其實這篇的內容跟筆者 2015 年另外一篇精神是一樣的,因為很重要所以講兩次。

科幻電影的預言與真實這本書中提到科學家曾經做過實驗,想要驗證人類在遇到壓力時能否獲得「子彈時間」的能力,也就是動態視覺變強,實驗的方式是先在一般情況下量測每個人的上限,在壓力下再把影像的變化調快,結果發現沒有一個參與實驗的人能夠打破自己的極限。


書中提到,人類的大腦會把小於 0.1sec 的兩張影像合成,所以一般人看到小於 0.1sec 的影像會覺得有殘影。換句話說,一般人平均動態視覺能力就是 10FPS,小於這個值大多數人就無法分辨。所以您覺得把 HMI 設計成 30FPS,有幾個作業員能夠用肉眼看到數值變化做出反應呢?就算是極限運動愛好者,動態視力也只提昇了 20% - 變成 12FPS,就算加碼到 15FPS 好了,也離很多人先入為主認為要 30FPS 還很遠。
 
那為何一堆 youtube 開箱文都在炫耀自己的顯示卡能夠 60FPS ~ 1xxFPS? 兩者目的不同,高檔 3D 加速卡是為了讓遊戲進行中更加平滑,遊戲中的物件移動速率是固定不變的,就好比 60FPS 的電影跟 30FPS 的電影比起來並不會像快轉播放。
(2019/3/17 補充)

如何判斷 HMI/SCADA 的設計好壞?

以台達 DOPSoft 為例,首先在畫面上放個數值顯示:


至於要讀取的位址呢?以三菱 FX3U 為例,設定為 RTC Second Data:



接下來想辦法在 Data Logger, Macro, Alarm... 放滿資料,以一秒能讀取的 PLC 資料大小為上限。一些比較流行的 PLC 網路上都查得到 protocol,甚至還有出書,例如 Mitsubishi FX 系列

接下來的步驟:
  1. 編輯好的畫面上傳到 HMI
  2. 開始執行
  3. 打開手機開始錄影
如果你計算發現 PLC 資料 500ms 就能傳完,但是錄影顯示 RTC 的秒數卻不是一秒更新一次,那可以跟 HMI 業務說不好意思下次再聯絡。或是秒數雖然一秒更新一次,但是 HMI 操作起來卻變得十分卡頓,這也是不及格的設計,跟業務說請你們家 RD 回家再練練。相信這招可以讓將煩人的業務一刀斃命,節省您寶貴的時間。

要不要用 multithreading?

multithreading 這東西很奇妙,剛出來時大家說不會用,到現在變成沒有它說我不會寫程式的人一堆。

筆者所見過使用 multithreading 的程式,99% 都是為了做 blocking I/O 時把CPU 資源釋放出來。

這樣的程式很直覺,剛開始很好寫,寫著寫著寫到一堆 threads 共享資料時就開始出事了,mutex、semaphore,乃至於更複雜的 condition variable、reader/writer lock 貼的跟狗皮藥膏一樣,不用說這樣的程式很難 debug 也很難維護。

另外一個麻煩的地方是你並不知道 OS 如何 schedule thread,在 The Art of Concurrency 這本書就有提到一個鐵則:"Never assume a particular order of execution",假設你希望 A 與 B 事件同時發生時 A 優先被處理,然後才是 B,但 A 與 B 兩個事件分別由 2 個 thread 偵測,除非打上 Linux real-time patch,原生 Linux 就不好說了。但是如果是用 Linux epoll(),就可以透過安排事件順序輕鬆達到目的。

現在業界普遍的看法,就是 thread 最多只能等於 CPU 核心數或是某個整數倍而已,不管是美國 Optimized C++: Proven Techniques for Heightened Performance,還是強國 Linux多线程服务端编程一書都有類似的說法。

現在當紅的 Node.js、Redis 等軟體都是 single thread 搭配 async IO API,如 Linux epoll()。在這種模型下的難點:是所有的 IO 都是非同步,所以你必須把你的程式規劃成 state machine,當 state machine 收到 async IO event 時 change state。(state machine 可以用 design pattern 中的 state pattern 實作)

這樣的程式不太容易寫,你必須對你的系統架構與行為了解透徹才能予以分解。不過只要你作過一次,就彷彿倒吃甘蔗一般越做越順,因為所有的 mutex, semaphore ooxx...此時已經不太需要,即使發生 core dump 用 gdb 也能輕鬆抓出來。

筆者其實已經用 libevent(將 Linux epoll(), FreeBSD kqueue 封裝的 lib)實作了一個 Modbus RTU/ASCII to Modbus TCP gateway,本想寫一系列教學文,礙於工作繁忙一直沒機會發表。

真正的難點是,如果要寫成跨平台,尤其是 Linux 跨 Windows,因為 Windows 缺乏設計良好的 async IO API,你很難像 Linux 一樣用一隻 epoll() 統整所有的 IO,變成還是得依靠 multithreading。或者另外一種常見的想法是,找一個包山包海的 framework(e.g Qt)幫我 cover 掉這種跨平台的問題。不過筆者想要指出的是,工具不能替代人思考,尤其是思考問題的本質。

(2018/12/8 補充)
關於 multithreading 還有個值得一提的小故事,筆者在前前前...公司時老闆曾經一度想引進某德國製造的控制器,該控制器支援 IEEE61131-3 Structured Text(ST)語法,可以產生幾十個幾百個 task 跑 ST,其實說穿了也是一種 multithreading,不過在場資深 FAE 很嚴肅的說這在台灣很難推廣,要教育客戶從 Ladder 轉向 ST,尤其是 multi-tasking ST 的難度很高。在我們旁敲側擊之下,德商 FAE 也表示他們大都是整廠輸出,很少客人會自己下去 coding。這不禁讓筆者想到筆者 n 年前玩過的 FxxA,當時有客人表示這應該是 Microchip 才能搞的事吧?當時聽不懂他的言外之意,多年後才想通如果是 Microchip 這種跨國大公司才有足夠的銀彈做教育訓練改變消費者習慣,消費者知道是 Microchip 推出也才有信心投資源學習,大家都很怕學了 3-5 年後變成孤兒,人生有幾個 3-5 年呢?

To be continued...

沒有留言:

張貼留言