上位機(jī)主界面設(shè)計(jì):從思路到落地)
VisionPro視覺檢測(cè)軟件的主界面設(shè)計(jì)是很多用康耐視這套視覺庫的工程師遲早都會(huì)碰到的活。不管你是用C#、VB.NET還是別的語言做上位機(jī)做視覺檢測(cè)項(xiàng)目時(shí)總繞不開一個(gè)問題程序跑起來之后操作工人面前那塊屏幕上到底顯示什么。說白了主界面就是現(xiàn)場(chǎng)操作員每天盯著看的窗口它的信息組織、操作邏輯、顯示效率直接決定產(chǎn)線上的檢測(cè)體驗(yàn)。我做了幾年視覺檢測(cè)設(shè)備從QuickBuild簡(jiǎn)單試運(yùn)到C#全套二次開發(fā)都折騰過踩過不少坑這篇就把VisionPro視覺檢測(cè)主界面設(shè)計(jì)從思路到落地完整梳理一遍給正在做視覺檢測(cè)上位機(jī)的朋友做個(gè)參考。這篇內(nèi)容主要適合三類人一是正在做視覺檢測(cè)上位機(jī)開發(fā)的工程師想了解VisionPro的界面怎么和檢測(cè)邏輯銜接二是準(zhǔn)備學(xué)VisionPro二次開發(fā)的新手需要一個(gè)整體認(rèn)知框架三是已經(jīng)在用QuickBuild做檢測(cè)、想把界面升級(jí)成自定義界面的朋友。不管是哪一類這篇都會(huì)從方案選型、模塊設(shè)計(jì)、核心實(shí)現(xiàn)到常見問題一條線講清楚。1. 主界面設(shè)計(jì)前的方案選型1.1 明確視覺檢測(cè)主界面要解決的三個(gè)問題主界面不是把控件堆上去那么簡(jiǎn)單。設(shè)計(jì)之前先想清楚這個(gè)界面給誰用、用來干什么。我在實(shí)際項(xiàng)目里會(huì)把需求拆成三個(gè)視角操作員、調(diào)試工程師、管理者三個(gè)視角對(duì)界面的訴求完全不同。操作員層面核心訴求是一鍵操作和狀態(tài)直覺。產(chǎn)線上的操作工往往沒有太多軟件基礎(chǔ)他們要的是“放料、按啟動(dòng)、看綠燈或紅燈”界面上的按鈕要夠大狀態(tài)要夠直觀檢測(cè)結(jié)果不要藏太深。調(diào)試工程師層面他們要的是快速定位問題比如某個(gè)產(chǎn)品突然過不了能馬上看到圖像、找到是哪個(gè)工具輸出異常、參數(shù)是否漂移所以界面必須保留圖像查看和參數(shù)調(diào)試的入口。管理者層面他們要的是產(chǎn)量、良率、節(jié)拍時(shí)間這些數(shù)據(jù)要能一眼看到今天的生產(chǎn)情況甚至要能導(dǎo)出報(bào)表。所以我在設(shè)計(jì)主界面時(shí)從來不會(huì)一開始就打開VS拖控件而是先畫一張界面草圖把三個(gè)角色的需求擺上去再?zèng)Q定哪些信息放在主界面、哪些放進(jìn)二級(jí)頁面。主界面上信息太多反而會(huì)讓操作員無所適從信息太少調(diào)試時(shí)又要到處翻菜單效率極低。合理的做法是主界面永遠(yuǎn)為操作員服務(wù)調(diào)試和管理功能通過權(quán)限控制收進(jìn)二級(jí)界面或彈出窗口。1.2 界面框架選型WinForms還是WPFVisionPro二次開發(fā)里最常見的界面框架是WinForms和WPF選哪個(gè)直接影響后續(xù)開發(fā)效率尤其如果你要嵌入VisionPro自帶的顯示控件。先說結(jié)論我絕大多數(shù)項(xiàng)目都用WinForms。原因很直接VisionPro的SDK里核心顯示控件CogRecordDisplay是基于WinForms的拖到WinForms窗體上直接就能用而放到WPF里需要轉(zhuǎn)成WindowsFormsHost承載一是顯示性能有損耗二是視覺工具運(yùn)行過程中的圖像刷新、圖形疊加偶爾會(huì)出現(xiàn)刷新不及時(shí)的問題排查起來很花時(shí)間。如果項(xiàng)目對(duì)界面視覺要求極高、需要大量自定義動(dòng)畫效果可以考慮WPF但前提是你對(duì)WindowsFormsHost的兼容性坑有心理準(zhǔn)備。另一個(gè)需要考慮的因素是開發(fā)團(tuán)隊(duì)的熟悉程度。WinForms的學(xué)習(xí)曲線更平緩資料也多剛接手VisionPro的工程師半天就能上手WPF的MVVM模式雖然適合復(fù)雜業(yè)務(wù)但工業(yè)現(xiàn)場(chǎng)軟件很少需要那么復(fù)雜的界面邏輯為了一個(gè)簡(jiǎn)潔界面引入額外復(fù)雜度反而拖慢項(xiàng)目進(jìn)度。我的經(jīng)驗(yàn)是視覺檢測(cè)上位機(jī)穩(wěn)定優(yōu)先、界面效率優(yōu)先WinForms足夠用了。1.3 界面布局的兩種經(jīng)典結(jié)構(gòu)定好框架之后接下來是整體布局。我做過的大小項(xiàng)目中主界面布局歸根結(jié)底是兩種結(jié)構(gòu)單畫面布局和多畫面布局。單畫面布局適合檢測(cè)工位相對(duì)單一的場(chǎng)景。界面中央是一塊大圖像顯示區(qū)顯示當(dāng)前工位的檢測(cè)圖像和圖形結(jié)果左側(cè)放參數(shù)面板右側(cè)放結(jié)果列表底部是狀態(tài)欄。這種布局的優(yōu)點(diǎn)是焦點(diǎn)集中操作員只需盯住一塊屏幕就能掌握所有信息適合裝配線、單工位質(zhì)量檢測(cè)這類場(chǎng)景。多畫面布局適合相機(jī)數(shù)量多、檢測(cè)工位多的項(xiàng)目比如一條產(chǎn)線有上相機(jī)、下相機(jī)、側(cè)相機(jī)或者同一工位多角度檢測(cè)。此時(shí)界面會(huì)切成多塊圖像顯示區(qū)每塊綁定一路檢測(cè)源切換頁簽或分屏顯示。畫面數(shù)量超過四個(gè)時(shí)我不建議繼續(xù)切割主界面否則每塊圖像太小操作員根本看不清缺陷。更合理的做法是主界面保留一塊主圖像區(qū)其余相機(jī)結(jié)果以縮略圖加狀態(tài)色的方式列出操作員點(diǎn)擊某一路縮略圖再在主圖像區(qū)放大查看。這個(gè)細(xì)節(jié)看起來不起眼但實(shí)際產(chǎn)線上操作員反饋“界面看不清”往往就出在圖像被切得太碎這個(gè)設(shè)計(jì)失誤上。2. 主界面模塊劃分與設(shè)計(jì)原則2.1 圖像顯示區(qū)從CogDisplay到CogRecordDisplayVisionPro早期版本提供CogDisplay控件用于顯示圖像后面新版SDK推薦使用CogRecordDisplay這主要是為了和CogRecord這套數(shù)據(jù)結(jié)構(gòu)統(tǒng)一。CogRecordDisplay不只是顯示一張圖片它還能疊加顯示檢測(cè)過程中的所有圖形結(jié)果比如定位框、邊緣線、測(cè)量尺寸、Blob區(qū)域、讀碼結(jié)果文本等相當(dāng)于把視覺工具在QuickBuild里看到的那些圖形化結(jié)果全部搬到你的自定義界面上。圖像顯示區(qū)的設(shè)計(jì)有幾個(gè)點(diǎn)一定要關(guān)照到第一圖像比例縮放要默認(rèn)適配窗口不要讓圖像超出視野但也要提供跟隨鼠標(biāo)滾輪放大的能力否則調(diào)試時(shí)想看清一個(gè)微小缺陷就非常痛苦。第二灰度圖像的顯示效果工業(yè)相機(jī)出來的通常是8位或12位灰度圖直接顯示可能偏暗或?qū)Ρ榷鹊虲ogRecordDisplay提供了亮度、對(duì)比度的調(diào)節(jié)屬性主界面上要預(yù)留調(diào)節(jié)入口。第三圖形疊加的開關(guān)要可控產(chǎn)品正常時(shí)可以不顯示工具圖形讓操作員只看到清晰產(chǎn)品圖產(chǎn)品異常時(shí)又能一鍵把所有檢測(cè)圖形拉出來方便分析問題原因。我自己在項(xiàng)目里習(xí)慣把圖像顯示區(qū)做成“雙擊放大全屏”的交互操作員雙擊圖像區(qū)域窗口進(jìn)入全屏放大模式再雙擊退出。這個(gè)功能代碼量不大但現(xiàn)場(chǎng)非常實(shí)用很多質(zhì)量異常在正常尺寸下看不清楚放大后才能確認(rèn)是劃傷還是臟污。2.2 參數(shù)配置區(qū)與工具鏈聯(lián)動(dòng)主界面上的參數(shù)配置區(qū)主要目的是讓現(xiàn)場(chǎng)調(diào)試人員能夠調(diào)整檢測(cè)參數(shù)而不用每次都打開QuickBuild工程文件去改。但這里有個(gè)很容易犯的錯(cuò)誤把CogToolBlock里所有工具的所有輸入?yún)?shù)全部暴露到界面上。工具鏈里可能有十幾個(gè)工具每個(gè)工具十多個(gè)參數(shù)全丟到界面上既難看又危險(xiǎn)操作員誤改一個(gè)參數(shù)整條產(chǎn)線都可能誤判。我的做法是“三層參數(shù)設(shè)計(jì)”第一層是常調(diào)參數(shù)顯示在主界面上比如檢測(cè)閾值、上下限規(guī)格值、產(chǎn)品切換型號(hào)等這些參數(shù)操作員和工程師都經(jīng)常動(dòng)第二層是進(jìn)階參數(shù)放在獨(dú)立的調(diào)試窗口中需要輸入工程師密碼才能進(jìn)入比如Blob面積范圍、卡尺邊緣極性這類第三層是固化參數(shù)只在QuickBuild工程里修改。通過這種分層既保證現(xiàn)場(chǎng)調(diào)試靈活又避免誤操作導(dǎo)致的質(zhì)量事故。參數(shù)修改之后必須設(shè)計(jì)“生效”機(jī)制。VisionPro里最直接的做法是當(dāng)參數(shù)值改變時(shí)調(diào)用對(duì)應(yīng)工具所在CogToolBlock的Run方法重新執(zhí)行一次檢測(cè)然后把新結(jié)果推送到界面。但這個(gè)操作不能每條參數(shù)都觸發(fā)否則拖動(dòng)一個(gè)滑塊界面就會(huì)卡死。我通常會(huì)給參數(shù)控件加上延遲觸發(fā)比如TextBox在用戶停止輸入500毫秒后才自動(dòng)運(yùn)行一次檢測(cè)既反饋及時(shí)又不拖累性能。2.3 結(jié)果統(tǒng)計(jì)區(qū)與狀態(tài)欄結(jié)果統(tǒng)計(jì)區(qū)體現(xiàn)的是產(chǎn)線當(dāng)天、當(dāng)班的整體檢測(cè)情況。我用得最多的是“總數(shù)、OK數(shù)、NG數(shù)、良率、節(jié)拍時(shí)間”五個(gè)指標(biāo)再用一個(gè)實(shí)時(shí)刷新的一次性記錄列表列出最近幾十條的檢測(cè)結(jié)果、時(shí)間戳、缺陷類型。統(tǒng)計(jì)區(qū)放在界面右側(cè)偏下的位置因?yàn)椴僮鲉T最主要的視線焦點(diǎn)在圖像區(qū)統(tǒng)計(jì)區(qū)只需要余光掃到即可。這里有一個(gè)容易被忽略的細(xì)節(jié)NG記錄要能點(diǎn)擊回溯。也就是說結(jié)果列表里每一條NG記錄雙擊后能在圖像顯示區(qū)回放出當(dāng)時(shí)的檢測(cè)圖像和圖形結(jié)果。這個(gè)功能在現(xiàn)場(chǎng)質(zhì)量追溯時(shí)特別重要很多時(shí)候客戶要的不是“這個(gè)產(chǎn)品是NG的”而是“這個(gè)產(chǎn)品為什么NG、當(dāng)時(shí)圖像長什么樣”。VisionPro里可以通過保存每次運(yùn)行時(shí)的CogRecord來實(shí)現(xiàn)后面我會(huì)詳細(xì)說到具體實(shí)現(xiàn)方式。狀態(tài)欄主要承擔(dān)三類狀態(tài)顯示當(dāng)前連接的是哪個(gè)相機(jī)/哪套視覺系統(tǒng)、視覺作業(yè)是否正在運(yùn)行、通信是否正常。狀態(tài)欄里我還會(huì)放一個(gè)“最近一次檢測(cè)耗時(shí)”的實(shí)時(shí)顯示單位毫秒??蓜e小看這個(gè)數(shù)字它就是產(chǎn)線節(jié)拍分析的底層數(shù)據(jù)如果某天產(chǎn)線突然變慢看一眼這個(gè)數(shù)值就能快速判斷是視覺檢測(cè)變慢了還是機(jī)械機(jī)構(gòu)卡頓了。2.4 菜單欄與權(quán)限體系主界面的菜單欄我通常只保留文件、運(yùn)行、調(diào)試、幫助四個(gè)模塊其他功能都收進(jìn)工具欄按鈕或快捷按鍵里。菜單欄的作用是“兜底”確保所有功能都有入口而不是讓操作員通過記憶快捷鍵去操作尤其是非技術(shù)人員菜單的樹狀結(jié)構(gòu)是最容易理解的操作方式。權(quán)限體系是工業(yè)視覺軟件容易忽略但實(shí)際很重要的部分。我用Window用戶名或密碼登錄的方式區(qū)分操作員權(quán)限和工程師權(quán)限。操作員權(quán)限默認(rèn)隱藏調(diào)試相關(guān)的菜單按鈕只保留啟動(dòng)、停止、復(fù)位、切換產(chǎn)品型號(hào)這些基礎(chǔ)功能工程師權(quán)限打開后才能顯示參數(shù)配置、工具鏈調(diào)試、相機(jī)標(biāo)定入口等關(guān)鍵功能。這樣做不是防操作員而是防止非本意誤操作——現(xiàn)場(chǎng)人多手雜有時(shí)候一個(gè)不經(jīng)意的點(diǎn)擊就能讓整個(gè)檢測(cè)程序停止運(yùn)行。3. 核心功能實(shí)現(xiàn)細(xì)節(jié)3.1 CogJobManager、CogJob與作業(yè)運(yùn)行機(jī)制VisionPro二次開發(fā)最核心的對(duì)象就是CogJobManager。它負(fù)責(zé)管理所有CogJob作業(yè)的創(chuàng)建、加載、啟停和狀態(tài)查詢。一套視覺系統(tǒng)可以同時(shí)跑多個(gè)CogJob比如一個(gè)工位同時(shí)檢測(cè)正面和側(cè)面但從主界面設(shè)計(jì)角度來看我建議一個(gè)主界面至少對(duì)應(yīng)一個(gè)CogJobManager實(shí)例這樣邏輯清楚出問題也好排查。在C#里加載作業(yè)并運(yùn)行的核心邏輯大概是這樣using Cognex.VisionPro; // 創(chuàng)建或加載作業(yè)管理器 CogJobManager jobManager new CogJobManager(); // 加載之前用QuickBuild保存的工程文件 jobManager.Load(C:\\VisionJob\\MyJob.vpp, true); // 獲取作業(yè) CogJob myJob jobManager.Jobs[0]; // 單次運(yùn)行 myJob.Run(); // 連續(xù)運(yùn)行模式 myJob.RunContinuous(); // 停止 myJob.Stop();這里有個(gè)很重要的經(jīng)驗(yàn)RunContinuous()是異步的意思是它會(huì)立即返回VisionPro內(nèi)部在后臺(tái)線程里不斷采集和檢測(cè)所以千萬不能在UI線程里調(diào)用它然后立刻去讀取結(jié)果那樣讀到的永遠(yuǎn)是上一個(gè)狀態(tài)。正確做法是把RunContinuous()和結(jié)果獲取邏輯通過事件機(jī)制銜接起來VisionPro里對(duì)應(yīng)的事件是CogJobManager的JobAsyncRunCompleted或者每個(gè)CogJob的RunCompleted。事件回調(diào)里再通過委托封送回UI線程更新界面。還有一點(diǎn)要牢記作業(yè)文件.vpp加載后占用的是進(jìn)程內(nèi)資源程序關(guān)閉時(shí)要記得釋放否則下次啟動(dòng)可能出現(xiàn)作業(yè)文件被占用、相機(jī)連接失敗的怪問題。ApplicationClosing事件里把jobManager.Dispose()調(diào)一遍是很多老工程師都會(huì)做的收尾工作。3.2 從CogToolBlock中取出檢測(cè)結(jié)果CogJob運(yùn)行之后檢測(cè)結(jié)果一般保存在CogToolBlock的輸出里。VisionPro的CogToolBlock是一種把多個(gè)視覺工具串聯(lián)起來的容器前一工具的輸出可以作為后一工具的輸入最頂層的輸出就是我們要讀的檢測(cè)結(jié)果。取出結(jié)果的代碼思路大致如下using Cognex.VisionPro.ToolBlock; // 從作業(yè)中拿到ToolBlock對(duì)象 CogToolBlock toolBlock myJob.ToolBlock as CogToolBlock; // 讀取輸出值比如定位結(jié)果 CogFixtureTool fixture toolBlock.Tools[CogFixtureTool1] as CogFixtureTool; double x fixture.Outputs[X].Value; double y fixture.Outputs[Y].Value; // 讀取測(cè)量值 CogPMAlignTool pmAlign toolBlock.Tools[CogPMAlignTool1] as CogPMAlignTool; double score pmAlign.Outputs[Score].Value;讀結(jié)果的方式有兩種一種是通過工具對(duì)象直接取它的Outputs屬性適合調(diào)試階段精確定位某個(gè)工具另一種是通過ToolBlock的Outputs集合按名稱取值適合量產(chǎn)階段理解整個(gè)工具鏈的輸出。我實(shí)際項(xiàng)目里兩種都會(huì)用但推薦把結(jié)果讀取封裝成一個(gè)單獨(dú)類讓主界面只跟這個(gè)類打交道不要直接散落引用各個(gè)工具對(duì)象。這樣以后工具鏈改了名字或調(diào)整了順序主界面代碼不用跟著大改。另外要注意ToolBlock的輸出在每次Run之后都是最新的但如果在主界面上讀取結(jié)果時(shí)正好趕上下一次Run開始讀取到的可能是新舊混合狀態(tài)。保險(xiǎn)的做法是只有在RunCompleted事件回調(diào)里才讀取結(jié)果讀取過程用鎖保護(hù)確保同一時(shí)刻只有一個(gè)邏輯在訪問ToolBlock的輸出。3.3 圖像顯示與檢測(cè)圖形疊加主界面上圖像顯示區(qū)的核心任務(wù)是把CogJob運(yùn)行時(shí)的圖像和檢測(cè)圖形完整、實(shí)時(shí)地呈現(xiàn)出來。CogRecordDisplay的綁定方式有幾種我最常用的是在RunCompleted事件里把CogJob的RunRecord直接顯示出來因?yàn)镽unRecord包含了整條工具鏈通知要顯示的所有圖形。private void job_RunCompleted(object sender, CogJobCompletedEventArgs e) { if (InvokeRequired) { BeginInvoke(new Action(() UpdateDisplay(sender, e))); return; } CogJob job sender as CogJob; cogRecordDisplay1.Record job.RunRecord; cogRecordDisplay1.Refresh(); }這里有一個(gè)新手容易踩的坑cogRecordDisplay1.Record job.RunRecord這句話的賦值時(shí)機(jī)非常講究。如果在作業(yè)還沒完成時(shí)就賦值顯示區(qū)會(huì)刷新成空白或者上一個(gè)狀態(tài)如果在完成事件里賦值又要注意委托封送。上面的代碼用BeginInvoke把界面更新封送回UI線程基本能保證顯示與事件不同步問題。圖形疊加的透明度、線寬、顏色可以通過CogRecordDisplay里的圖層屬性調(diào)整。比如NG產(chǎn)品用紅色粗線框出缺陷區(qū)域OK產(chǎn)品用綠色線條顯示定位框操作員即使不仔細(xì)讀數(shù)值也能 через顏色快速判斷。這個(gè)視覺反饋的優(yōu)化現(xiàn)場(chǎng)體驗(yàn)提升非常明顯。3.4 本地日志、數(shù)據(jù)保存與通信接口主界面除了視覺顯示還要承擔(dān)數(shù)據(jù)落盤和通信的責(zé)任否則檢測(cè)結(jié)果只停留在內(nèi)存里后續(xù)很難追溯和統(tǒng)計(jì)。我做的視覺檢測(cè)上位機(jī)日志至少分兩類運(yùn)行日志和質(zhì)量數(shù)據(jù)。運(yùn)行日志記錄程序啟動(dòng)、停止、相機(jī)連接、作業(yè)加載、異常等信息主要給工程師排查問題用質(zhì)量數(shù)據(jù)記錄每一條檢測(cè)結(jié)果的具體數(shù)值、缺陷類型、時(shí)間戳、產(chǎn)品型號(hào)主要給MES系統(tǒng)和質(zhì)量追溯用。本地保存我建議用SQLite部署簡(jiǎn)單不需要額外安裝數(shù)據(jù)庫服務(wù)。數(shù)據(jù)表按天分表或者加日期字段視項(xiàng)目數(shù)據(jù)量而定。通信接口方面工業(yè)現(xiàn)場(chǎng)最常見的是通過TCP/IP或Modbus TCP與PLC、MES通信VisionPro檢測(cè)出的OK/NG結(jié)果要實(shí)時(shí)發(fā)給PLC控制下料機(jī)構(gòu)。通信發(fā)送必須放在后臺(tái)線程界面上只顯示最近一次發(fā)送結(jié)果的狀態(tài)否則高頻檢測(cè)幾十毫秒一次同步發(fā)送會(huì)卡死界面。這里插一句我很深的體會(huì)很多視覺項(xiàng)目在實(shí)驗(yàn)室跑得好好的到了產(chǎn)線天天出問題八成是通信穩(wěn)定性沒有做足。我會(huì)在主界面的狀態(tài)欄里增加一個(gè)“通信幀計(jì)數(shù)”顯示讓現(xiàn)場(chǎng)人員能直觀看到PLC通信是否正常。只是單純?cè)诖a里try-catch問題出了很難定位。4. 從零搭建主界面的實(shí)操記錄4.1 新建工程并添加VisionPro SDK引用在Visual Studio里新建WinForms項(xiàng)目后第一步是添加VisionPro相關(guān)程序集引用。打開“引用管理器”在瀏覽中找到Cognex VisionPro安裝目錄下的這些DLL默認(rèn)在C:\Program Files\Cognex\VisionPro\Cognex.VisionPro.dllCognex.VisionPro.ToolBlock.dllCognex.VisionPro.Display.dllCognex.VisionPro.CalibFix.dll標(biāo)定相關(guān)按需添加添加引用后工具箱里會(huì)出現(xiàn)CogRecordDisplay、CogJobManager這些控件直接拖到窗體上就完成了界面骨架的一半。這里有個(gè)建議VisionPro安裝目錄是crack敏感的盡量不要引用那些帶Cognex.VisionPro.Controls.dll之類的界面庫除非你確認(rèn)目標(biāo)電腦都裝了對(duì)應(yīng)VisionPro運(yùn)行時(shí)。否則程序在客戶現(xiàn)場(chǎng)一跑報(bào)找不到DLL的問題會(huì)非常頭疼。工程屬性里目標(biāo)框架建議選.NET Framework 4.6.1或4.7.2。我吃過虧客戶現(xiàn)場(chǎng)電腦裝的是.NET Framework 4.0程序跑不起來后面把所有項(xiàng)目統(tǒng)一降到4.6.1兼容性好了很多。雖然新版VisionPro開始支持.NET 6/8但工業(yè)現(xiàn)場(chǎng)電腦很多還是老系統(tǒng)兼容性比新潮更重要。4.2 核心代碼與事件鏈搭建從零搭主界面時(shí)我會(huì)先把事件鏈理清楚再逐個(gè)實(shí)現(xiàn)功能。事件鏈的順序是窗體加載完成之后加載視覺作業(yè)視覺作業(yè)加載完成之后啟動(dòng)連續(xù)運(yùn)行連續(xù)運(yùn)行過程中每檢測(cè)完一次觸發(fā)RunCompleted事件事件里做結(jié)果顯示、數(shù)據(jù)統(tǒng)計(jì)、通信發(fā)送。事件鏈的搭建邏輯可以參考下面的偽代碼結(jié)構(gòu)private void MainForm_Load(object sender, EventArgs e) { // 初始化CogJobManager加載作業(yè)文件 InitVisionJob(); } private void InitVisionJob() { jobManager new CogJobManager(); jobManager.Load(vppPath, true); myJob jobManager.Jobs[0]; myJob.RunCompleted OnJobRunCompleted; myJob.RunContinuous(); } private void OnJobRunCompleted(object sender, CogJobCompletedEventArgs e) { // UI線程封送、讀取結(jié)果、刷新圖像、更新統(tǒng)計(jì)、發(fā)送PLC }這個(gè)結(jié)構(gòu)看似簡(jiǎn)單但實(shí)際項(xiàng)目里很多問題出在細(xì)節(jié)比如RunContinuous()在窗體還沒顯示時(shí)就調(diào)用導(dǎo)致控件還沒初始化完成就去刷新拋異常比如沒有處理相機(jī)斷線重連作業(yè)一停止就再也跑不起來。這些都是我在現(xiàn)場(chǎng)反復(fù)調(diào)試中踩出來的經(jīng)驗(yàn)。4.3 界面布局參數(shù)與配色參考界面配色是一個(gè)容易被工程師忽略但實(shí)際很重要的模塊。我把主界面的配色方案固定為深色背景加高亮狀態(tài)色原因很簡(jiǎn)單產(chǎn)線上的操作環(huán)境通常光線復(fù)雜淺色界面在強(qiáng)光下反光嚴(yán)重眼睛容易疲勞而深色界面在明亮環(huán)境中對(duì)比度更好。推薦一套經(jīng)過現(xiàn)場(chǎng)驗(yàn)證的配色參考背景色用深灰#2B2B2B面板底色用中灰#3C3C3C文字用淺灰白#F0F0F0OK狀態(tài)用綠色#33CC66NG狀態(tài)用紅色#FF5555運(yùn)行中狀態(tài)用藍(lán)色#3399FF。這套配色在普通辦公環(huán)境和強(qiáng)光車間里都有不錯(cuò)的辨識(shí)度。按鈕尺寸方面操作員常用的“啟動(dòng)”“停止”按鈕建議至少做到60×60像素保證帶上手套也能準(zhǔn)確點(diǎn)擊觸發(fā)面積太小現(xiàn)場(chǎng)誤觸概率會(huì)明顯上升。字體大小我也要提醒一下主界面上核心數(shù)值的字號(hào)至少14pt輔助信息12pt不要讓操作員瞇著眼睛找數(shù)字。字號(hào)過小是很多工程師自己開發(fā)的界面被現(xiàn)場(chǎng)吐槽的重要原因。4.4 上線前的主界面自檢清單每次項(xiàng)目上線前我都會(huì)拿一份自檢清單過一遍主界面比如啟動(dòng)軟件后相機(jī)是否自動(dòng)連接不連接時(shí)是否有清晰提示作業(yè)加載失敗時(shí)是崩潰還是彈窗停止?fàn)顟B(tài)下操作員誤點(diǎn)運(yùn)行會(huì)不會(huì)報(bào)錯(cuò)斷網(wǎng)/相機(jī)掉線后能否自動(dòng)恢復(fù)累計(jì)檢測(cè)數(shù)量是否準(zhǔn)確重啟后是否丟失日志文件夾是否自動(dòng)創(chuàng)建磁盤滿時(shí)是否會(huì)有異常權(quán)限密碼是否存在明文文件里這些都是我踩坑積累出來的經(jīng)驗(yàn)列出來供大家參考。我尤其想強(qiáng)調(diào)一個(gè)項(xiàng)目里實(shí)際發(fā)生過的案例一臺(tái)視覺檢測(cè)設(shè)備上線后操作員報(bào)告“軟件時(shí)不時(shí)卡死”排查了一整天才發(fā)現(xiàn)是因?yàn)槿罩疚募]有做大小限制運(yùn)行兩個(gè)月后日志達(dá)到了幾個(gè)GB程序?qū)懭罩緯r(shí)IO阻塞了UI線程。后來加了日志輪轉(zhuǎn)機(jī)制卡死問題再?zèng)]出現(xiàn)過。所以說自檢清單不是形式主義是真能救命的東西。5. 常見問題與排查技巧實(shí)錄5.1 界面卡頓、圖像刷新不及時(shí)視覺檢測(cè)上位機(jī)最常見的問題就是界面卡頓。我遇到過的原因主要有三種第一種是在UI線程里執(zhí)行了耗時(shí)操作比如直接在按鈕Click事件里同步運(yùn)行myJob.Run()檢測(cè)要幾百毫秒界面就卡幾百毫秒第二種是圖像顯示控件不停刷新CogRecordDisplay綁定的圖像數(shù)據(jù)量太大或者刷新頻率超過了顯示器刷新能力第三種是有后臺(tái)線程頻繁訪問UI控件導(dǎo)致界面響應(yīng)變慢。排查思路首先是確認(rèn)卡頓是否和檢測(cè)頻率相關(guān)。如果檢測(cè)一次卡一次優(yōu)先懷疑UI線程阻塞如果界面長期不流暢檢查是否有無限循環(huán)定時(shí)器在刷新界面。解決手段是堅(jiān)持一條原則檢測(cè)在后臺(tái)線程跑結(jié)果通過事件回傳界面只用BeginInvoke更新。圖像刷新可以做節(jié)流比如檢測(cè)頻率是每秒10次界面刷新只需要每秒5次用一個(gè)定時(shí)器統(tǒng)一刷新顯示即可。5.2 圖像顯示區(qū)黑屏或不顯示圖像這個(gè)問題的出現(xiàn)率非常高主要原因也有幾類CogRecordDisplay沒綁定Record綁定的Record是null作業(yè)還沒跑起來沒有任何圖像數(shù)據(jù)產(chǎn)生多媒體顯示控件被窗體遮擋或者尺寸為0。判斷方法很直接——在RunCompleted事件里加一個(gè)斷點(diǎn)查看job.RunRecord是否為null。如果是null說明視覺作業(yè)本身沒有產(chǎn)生輸出記錄要去檢查QuickBuild工程里工具鏈?zhǔn)悄膫€(gè)環(huán)節(jié)斷了如果不是null但界面還是不顯示檢查控件綁定代碼是否在正確的時(shí)間點(diǎn)執(zhí)行。還有一個(gè)隱蔽坑如果你在主界面上放了多個(gè)CogRecordDisplay并且在不同線程里給它們分別賦值Record偶爾會(huì)出現(xiàn)圖像顯示串位也就是A畫面顯示B相機(jī)的圖像。這個(gè)現(xiàn)象和CogRecordDisplay的緩存機(jī)制有關(guān)我的解決辦法是每個(gè)顯示控件只綁定固定的CogJob不在代碼里頻繁切換綁定源要切換就通過頁簽隱藏顯隱來實(shí)現(xiàn)而不是動(dòng)態(tài)修改Record綁定關(guān)系。5.3 檢測(cè)良率統(tǒng)計(jì)與實(shí)際產(chǎn)量對(duì)不上良率統(tǒng)計(jì)不準(zhǔn)是工廠里最容易引發(fā)扯皮的問題。常見原因包括事件回調(diào)里有重復(fù)統(tǒng)計(jì)比如RunCompleted觸發(fā)了兩次啟停過程中檢測(cè)了一半的產(chǎn)品也被統(tǒng)計(jì)進(jìn)去了程序重啟后計(jì)數(shù)清零但產(chǎn)線實(shí)際產(chǎn)出還在增長。我的做法是在主界面維護(hù)一個(gè)生產(chǎn)數(shù)據(jù)模型類所有計(jì)數(shù)操作集中到這個(gè)類里通過加鎖保證線程安全并在每次統(tǒng)計(jì)時(shí)增加序號(hào)判斷防止同一幀圖像重復(fù)計(jì)數(shù)。另外要明確“有效檢測(cè)”和“無效檢測(cè)”的邊界。相機(jī)采到空料盤、料件擺放歪斜導(dǎo)致圖像異常這些不能直接算NG否則會(huì)虛高不良率。我的建議是視覺作業(yè)里先加一個(gè)“是否有料”的判斷工具輸出一個(gè)布爾量只有檢測(cè)到有料時(shí)才計(jì)入總數(shù)和OK/NG統(tǒng)計(jì)。這個(gè)邏輯不復(fù)雜但能讓統(tǒng)計(jì)數(shù)字真正反映產(chǎn)線質(zhì)量而不是一堆噪音數(shù)據(jù)。5.4 其他容易被忽視的小問題除了上面幾個(gè)大問題還有一些小問題容易讓人焦頭爛額中文亂碼一般是因?yàn)殚_發(fā)機(jī)和現(xiàn)場(chǎng)電腦的區(qū)域語言設(shè)置不一致字體模糊WinForms在高DPI顯示器上默認(rèn)不縮放需要在配置文件里啟用DPI感知VisionPro授權(quán)失效導(dǎo)致作業(yè)加載失敗很隱蔽界面上一會(huì)兒能用一會(huì)兒不能用多半是授權(quán)服務(wù)不穩(wěn)定。這些小問題不會(huì)讓系統(tǒng)崩潰但在現(xiàn)場(chǎng)會(huì)非常消耗排查精力提前了解能少走很多彎路。高DPI問題我多說一句現(xiàn)在不少現(xiàn)場(chǎng)電腦已經(jīng)換成了1080P甚至2K顯示器WinForms程序如果不做DPI適配界面會(huì)變得又小又糊操作員反饋強(qiáng)烈。解決辦法是在app.manifest文件里啟用PerMonitorV2DPI感知再配合LayoutOptions自動(dòng)縮放基本能解決大部分顯示問題。做完這個(gè)適配之后主界面在不同分辨率上的體驗(yàn)都會(huì)一致。6. 關(guān)于界面設(shè)計(jì)的一些個(gè)人體會(huì)做了這么多個(gè)視覺檢測(cè)項(xiàng)目我最大的體會(huì)是主界面設(shè)計(jì)的成敗往往不在技術(shù)上而在你對(duì)現(xiàn)場(chǎng)需求的把握上。技術(shù)上的東西——控件拖拽、事件綁定、圖像顯示——花時(shí)間誰都能學(xué)會(huì)難的是知道操作員想要什么、調(diào)試時(shí)缺什么、管理者關(guān)心什么。一塊界面如果只是工程師覺得“好看”但操作員用起來別扭、調(diào)試時(shí)信息不夠全、管理者看報(bào)表要導(dǎo)來導(dǎo)去那上線之后一定會(huì)被反復(fù)吐槽。我個(gè)人在設(shè)計(jì)主界面時(shí)現(xiàn)在養(yǎng)成了一個(gè)習(xí)慣初版界面做完之后先讓自己在工位上“模擬操作員”連續(xù)運(yùn)行一整天去感受每個(gè)按鈕的使用頻率、每個(gè)信息的可讀性。很多問題在模擬使用中就會(huì)提前暴露比如某個(gè)需要頻繁點(diǎn)擊的按鈕藏在二級(jí)菜單里、某個(gè)關(guān)鍵數(shù)值字體太小看不清、某個(gè)狀態(tài)顏色和正常的指示燈容易混淆。把這些體驗(yàn)問題在上線前改掉比上線后到客戶現(xiàn)場(chǎng)救火要省心太多了。視覺檢測(cè)主界面這個(gè)東西看起來只是整套視覺系統(tǒng)里最外面的一層皮但它其實(shí)是操作員直接接觸的部分是整套系統(tǒng)在人們眼中的“全部”。與其在視覺算法上花了一百分的功夫最后卻因?yàn)榻缑娼换ゲ钭尙F(xiàn)場(chǎng)懷疑你的系統(tǒng)不行不如一開始就把主界面當(dāng)一個(gè)正經(jīng)產(chǎn)品來設(shè)計(jì)讓算法、穩(wěn)定性和交互體驗(yàn)三者真正一體化這才是視覺檢測(cè)設(shè)備能順利交付、穩(wěn)定運(yùn)行的關(guān)鍵所在。