定實(shí)戰(zhàn):從原理到避坑的完整流程)
做視覺項(xiàng)目的人基本都躲不開手眼標(biāo)定這一關(guān)。尤其是用Halcon做機(jī)器人引導(dǎo)項(xiàng)目時(shí)手眼標(biāo)定往往是整個(gè)系統(tǒng)能否跑起來的第一道門檻。我見過不少人卡在這一步要么標(biāo)出來的矩陣精度差得沒法用要么程序報(bào)錯(cuò)半天查不出原因要么明明標(biāo)定了但實(shí)際抓取就是偏。老實(shí)說手眼標(biāo)定本身的原理并不復(fù)雜真正的坑全藏在數(shù)據(jù)采集、坐標(biāo)系轉(zhuǎn)換和參數(shù)設(shè)置這些細(xì)節(jié)里。這篇博文我會從零開始完整拆解一遍Halcon手眼標(biāo)定的實(shí)戰(zhàn)流程。內(nèi)容包括兩種安裝方式的選擇、標(biāo)定板選型、機(jī)器人位姿記錄、Halcon算子調(diào)用順序、結(jié)果驗(yàn)證方法以及我這些年踩過的各種坑。準(zhǔn)備做視覺引導(dǎo)、上下料、裝配定位或者正在被標(biāo)定結(jié)果折磨的朋友這篇文章應(yīng)該能幫你省下不少時(shí)間。1. 先搞懂手眼標(biāo)定到底在算什么1.1 眼在手上和眼在手外兩種安裝方式的坐標(biāo)系邏輯手眼標(biāo)定核心就是解決一個(gè)問題相機(jī)看到的物體坐標(biāo)怎么換算成機(jī)器人能用的坐標(biāo)。根據(jù)相機(jī)安裝位置不同分成了兩大類一個(gè)是眼在手上Eye-in-Hand一個(gè)是眼在手外Eye-to-Hand。眼在手上就是相機(jī)裝在機(jī)械臂末端法蘭上跟著機(jī)械臂一起動。這種方式的優(yōu)勢是視野靈活機(jī)械臂動到哪里相機(jī)就能看到哪里適合大范圍、多工位、需要移動拍照的場景。缺點(diǎn)是相機(jī)跟著動每次拍照時(shí)相機(jī)位姿都在變化標(biāo)定結(jié)果要能適應(yīng)不同機(jī)械臂姿態(tài)下的坐標(biāo)轉(zhuǎn)換。眼在手外就是相機(jī)固定安裝在一個(gè)位置機(jī)械臂在相機(jī)視野范圍內(nèi)干活。這種方案穩(wěn)定不會因?yàn)闄C(jī)械臂運(yùn)動產(chǎn)生振動和視野變化適合精度要求高、工位固定、拍照位置不變的應(yīng)用。缺點(diǎn)是需要保證機(jī)械臂工作區(qū)域始終在相機(jī)視野內(nèi)視野范圍可能受限。這兩種方式在Halcon里的標(biāo)定流程幾乎一樣但內(nèi)部計(jì)算邏輯和結(jié)果的含義不同。眼在手解出來的矩陣是相機(jī)坐標(biāo)系和機(jī)械臂末端坐標(biāo)系之間的固定變換眼在手外解出來的是相機(jī)坐標(biāo)系和機(jī)械臂基座坐標(biāo)系之間的固定變換。這個(gè)區(qū)別一定要清楚不然后面驗(yàn)證結(jié)果時(shí)容易張冠李戴。1.2 手眼矩陣和機(jī)器人位姿之間的關(guān)系手眼標(biāo)定本質(zhì)上是求解一個(gè)矩陣方程AX XB。A是機(jī)械臂末端位姿的變化B是標(biāo)定板在相機(jī)坐標(biāo)系下位姿的變化X就是我們要的手眼變換矩陣。具體展開來說眼在手上的場景里標(biāo)定板固定不動機(jī)械臂帶著相機(jī)在不同位置拍照。每一組數(shù)據(jù)包含兩個(gè)信息機(jī)械臂末端的位姿tool_in_base_pose以及標(biāo)定板在相機(jī)坐標(biāo)系下的位姿image_pose。這兩個(gè)位姿之間通過一個(gè)固定不變的手眼矩陣關(guān)聯(lián)起來。當(dāng)機(jī)械臂運(yùn)動到不同位置時(shí)這個(gè)固定矩陣都不會變聯(lián)立多組數(shù)據(jù)就能把它解出來。眼在手外的場景稍有不同標(biāo)定板裝在機(jī)械臂末端相機(jī)固定不動。機(jī)械臂帶著標(biāo)定板在相機(jī)視野里擺出不同姿態(tài)每一組數(shù)據(jù)也包含兩個(gè)信息機(jī)械臂末端的位姿以及此時(shí)標(biāo)定板在相機(jī)坐標(biāo)系下的位姿。同樣手眼矩陣是不變的它可以被多組數(shù)據(jù)聯(lián)合求解出來。Halcon里用自定義的數(shù)據(jù)結(jié)構(gòu)來管理這些數(shù)據(jù)其中create_calib_data創(chuàng)建標(biāo)定數(shù)據(jù)對象然后用set_calib_data錄入相機(jī)參數(shù)、標(biāo)定板參數(shù)、機(jī)器人位姿和圖像位姿最后用calibrate_hand_eye求解。整個(gè)過程的編程思路很清晰但每一步的細(xì)節(jié)都會影響最終精度。1.3 為什么選擇Halcon做手眼標(biāo)定市面上能做手眼標(biāo)定的方案不少最常見的有OpenCV、Halcon還有國內(nèi)一些視覺平臺比如Vision Master。我自己的項(xiàng)目里三種都嘗試過簡單聊聊各自特點(diǎn)。OpenCV的優(yōu)勢是免費(fèi)開源跨平臺社區(qū)資料豐富。cv2.calibrateHandEye接口用起來也不難適合成本敏感、對許可要求不高的項(xiàng)目。但OpenCV的標(biāo)定板識別、亞像素提取這些前置步驟需要自己寫代碼調(diào)試成本高對于沒有專門視覺工程師的團(tuán)隊(duì)來說上手偏慢。Halcon的優(yōu)勢在于算子封裝完整標(biāo)定板識別、位姿計(jì)算、手眼標(biāo)定都是一條龍開發(fā)效率極高。尤其find_calib_object這個(gè)算子對標(biāo)定板的識別幾乎是傻瓜式的打光不太理想的情況下也能穩(wěn)定提取。缺點(diǎn)當(dāng)然就是貴License費(fèi)用不低但這對于工業(yè)級項(xiàng)目來說通常是可以接受的成本。Vision Master之類的國產(chǎn)平臺一般內(nèi)置了標(biāo)定流程界面化操作鼠標(biāo)點(diǎn)一點(diǎn)就能完成。它的優(yōu)點(diǎn)是上手最快不需要寫代碼。但靈活性差遇到非標(biāo)準(zhǔn)場景比如特殊標(biāo)定板、特殊相機(jī)模型時(shí)容易卡住。選哪個(gè)取決于項(xiàng)目實(shí)際情況但如果你是做工業(yè)視覺項(xiàng)目、需要穩(wěn)定的精度和較高的開發(fā)效率Halcon依然是值得優(yōu)先考慮的選擇。2. 標(biāo)定前的準(zhǔn)備工作硬件的坑比軟件多2.1 確定相機(jī)安裝方式和標(biāo)定板選型很多人一上來就寫代碼結(jié)果到后面才發(fā)現(xiàn)硬件安裝方式跟代碼假設(shè)不一致整個(gè)標(biāo)定推倒重來。所以標(biāo)定前的第一件事是確認(rèn)相機(jī)安裝方式到底是eye-in-hand還是eye-to-hand。這個(gè)確認(rèn)不是看一眼就行的要考慮實(shí)際應(yīng)用場景。如果機(jī)械臂抓取時(shí)需要對準(zhǔn)來料位置相機(jī)裝在手上可以實(shí)現(xiàn)“走過去看”的效果對視覺系統(tǒng)的靈活性要求高如果工位固定、來料位置固定相機(jī)裝在外面更穩(wěn)定標(biāo)定后精度也會更好。我個(gè)人的原則是能裝固定就裝固定需要靈活再看手上。標(biāo)定板的選擇也有講究。Halcon標(biāo)定板是圓點(diǎn)陣列式每顆圓點(diǎn)之間的間距有嚴(yán)格標(biāo)準(zhǔn)對應(yīng)一個(gè)描述文件.cpd。這個(gè)描述文件在標(biāo)定時(shí)必須傳給Halcon因?yàn)樗枋隽藰?biāo)定板的物理尺寸和點(diǎn)陣布局。選擇標(biāo)定板大小主要看相機(jī)視野。標(biāo)定板在視野里最好不要小于視野的三分之一也不要大于三分之二。太小了圓點(diǎn)提取數(shù)量不夠標(biāo)定結(jié)果容易飄太大了邊緣圓點(diǎn)變形嚴(yán)重反而影響精度。比如500萬像素相機(jī)配16mm鏡頭視野大概300mm見方用100mm左右的標(biāo)定板就挺合適。還有個(gè)容易忽略的點(diǎn)標(biāo)定板要平整、干凈、不反光。最好用玻璃基板的陶瓷標(biāo)定板熱穩(wěn)定性好不容易變形。廉價(jià)亞克力板用久了會彎標(biāo)定結(jié)果會慢慢漂移。2.2 機(jī)器人位姿怎么記錄手眼標(biāo)定需要的機(jī)器人數(shù)據(jù)是機(jī)械臂末端的位姿在Halcon里叫tool_in_base_pose也就是工具坐標(biāo)系在機(jī)器人基座坐標(biāo)系下的位置和姿態(tài)。這個(gè)數(shù)據(jù)從哪來從機(jī)器人控制器里讀。讀取方式通常有兩種。一種是在示教器上人工記錄機(jī)械臂每擺一個(gè)姿態(tài)把當(dāng)前位姿抄下來然后跟圖像對應(yīng)起來錄入程序。這種方式適合手動標(biāo)定數(shù)據(jù)量少十來組但效率低容易抄錯(cuò)。另一種是寫一個(gè)上位機(jī)程序通過TCP/IP或者M(jìn)odbus等協(xié)議自動讀取機(jī)器人當(dāng)前位姿然后跟相機(jī)拍照同步記錄下來效率和準(zhǔn)確率都高得多。無論哪種方式單位一定要統(tǒng)一。Halcon里位姿默認(rèn)單位是米角度是弧度。而很多機(jī)器人示教器上顯示的是毫米和度這就要在記錄時(shí)做換算或者機(jī)器人端直接輸出轉(zhuǎn)換后的數(shù)據(jù)。旋轉(zhuǎn)部分更要注意。機(jī)器人輸出的姿態(tài)表示方式五花八門歐拉角、四元數(shù)、旋轉(zhuǎn)矩陣都有。Halcon的位姿類型支持多種旋轉(zhuǎn)表示常用的是gba繞固定軸的全局旋轉(zhuǎn)和abg歐拉角。我在項(xiàng)目里的做法是讓機(jī)器人端把姿態(tài)轉(zhuǎn)成四元數(shù)或者歐拉角傳上來再在Halcon里統(tǒng)一轉(zhuǎn)成gba類型避免不同表示方式之間的混淆。2.3 標(biāo)定數(shù)據(jù)對象與相機(jī)參數(shù)準(zhǔn)備真正開始標(biāo)定前需要先把相機(jī)的內(nèi)參標(biāo)定好。如果相機(jī)是固定焦距的工業(yè)相機(jī)可以用Halcon的標(biāo)定助手采集十來張不同角度的標(biāo)定板圖像自動算出一組內(nèi)參。如果相機(jī)是自動變焦的先鎖死焦距再做標(biāo)定不然內(nèi)參一變手眼矩陣全部作廢。內(nèi)參準(zhǔn)備好后在代碼里創(chuàng)建標(biāo)定數(shù)據(jù)對象并設(shè)置參數(shù)。以眼在手上為例代碼大概是這樣的* 創(chuàng)建手眼標(biāo)定數(shù)據(jù)對象moving_cam表示眼在手上 create_calib_data (hand_eye_moving_cam, 1, 1, CalibDataID) * 設(shè)置相機(jī)內(nèi)參使用division模型 set_calib_data_cam_param (CalibDataID, 0, area_scan_division, CameraParam) * 設(shè)置標(biāo)定板描述文件 set_calib_data_calib_object (CalibDataID, 0, calplate_100mm.cpd)注意如果是眼在手外創(chuàng)建數(shù)據(jù)對象時(shí)要用hand_eye_stationary_cam。這兩個(gè)模式對應(yīng)的數(shù)據(jù)管理方式一樣但最后求解出來的手眼矩陣含義不同千萬別搞混。還有一個(gè)點(diǎn)標(biāo)定板描述文件和實(shí)際標(biāo)定板必須完全匹配包括圓點(diǎn)數(shù)量、間距、板子尺寸。如果用了不匹配的文件find_calib_object即使能識別出來計(jì)算出來的位姿也不對手眼標(biāo)定結(jié)果會差到離譜。3. 實(shí)操全程從采集圖像到輸出手眼矩陣3.1 圖像采集與標(biāo)定板識別接下來的操作流程我按眼在手上的場景來演示眼在手外的邏輯完全對稱區(qū)別只在數(shù)據(jù)對象創(chuàng)建和結(jié)果含義。首先把標(biāo)定板固定在工作區(qū)域內(nèi)的某個(gè)穩(wěn)定位置比如用臺鉗夾住或者用雙面膠固定在工作臺上。確保標(biāo)定板在機(jī)械臂運(yùn)動的所有拍照位置都能被相機(jī)完整看到且視野邊緣不要出現(xiàn)標(biāo)定板切邊的情況。然后控制機(jī)械臂移動到第一個(gè)拍照位置機(jī)械臂穩(wěn)定后觸發(fā)相機(jī)拍照。拍照后對圖像調(diào)用find_calib_object提取標(biāo)定板的位姿* 查找標(biāo)定板提取位姿 find_calib_object (Image, CalibDataID, 0, 0, StartHandle, []) get_calib_data (CalibDataID, calib_obj, 0, pose, PoseCalib)這里PoseCalib就是標(biāo)定板在相機(jī)坐標(biāo)系下的位姿也就是前面說的image_pose。每組圖像都要對應(yīng)記錄這個(gè)位姿。幾個(gè)拍照時(shí)的注意事項(xiàng)第一對焦一定要準(zhǔn)。標(biāo)定板圓點(diǎn)邊緣如果模糊亞像素提取精度會下降最終影響手眼標(biāo)定的旋轉(zhuǎn)精度。第二曝光要合適不能過曝。圓點(diǎn)內(nèi)部如果出現(xiàn)高光飽和提取出的圓心位置會偏移。最好讓圓點(diǎn)區(qū)域和背景的灰度差明顯但高光區(qū)不溢出。第三盡量避免反光。標(biāo)定板表面如果有鏡面反光find_calib_object可能識別失敗或者識別出的圓點(diǎn)位置出現(xiàn)偏移??梢哉{(diào)整光源角度或者用偏振片消除反光。3.2 采集位姿的姿勢策略手眼標(biāo)定不是隨便擺幾個(gè)位置就能標(biāo)好的機(jī)械臂的姿態(tài)要有足夠的變化。我見過不少人為了省事只讓機(jī)械臂在幾個(gè)固定位置平移姿態(tài)幾乎不變結(jié)果標(biāo)出來的矩陣精度非常差。為什么姿態(tài)變化這么重要因?yàn)槭盅蹣?biāo)定本質(zhì)上是聯(lián)立方程求解如果所有數(shù)據(jù)都來自同一姿態(tài)方程之間的信息冗余嚴(yán)重解出來的矩陣在某個(gè)方向上約束不足精度就會很差。具體操作上我建議每個(gè)拍照位置要包含平移和旋轉(zhuǎn)兩方面的變化。平移方面讓機(jī)械臂末端在相機(jī)視野的不同位置移動覆蓋視野的左上、右上、中心、左下、右下盡量把視野的各個(gè)區(qū)域都走到。旋轉(zhuǎn)方面讓機(jī)械臂末端繞著不同方向轉(zhuǎn)動每次轉(zhuǎn)動角度建議在30度左右大幅度轉(zhuǎn)動更有助于約束旋轉(zhuǎn)部分。一組比較典型的數(shù)據(jù)采集流程是先在當(dāng)前位置拍照然后平移一段距離再拍接著轉(zhuǎn)一個(gè)角度再拍再回到中間位置換一個(gè)方向轉(zhuǎn)就這樣來回組合采集15到20組數(shù)據(jù)。少于10組數(shù)據(jù)時(shí)標(biāo)定結(jié)果不穩(wěn)定多于30組收益也不明顯。我實(shí)際項(xiàng)目里一般控制在20組左右精度和效率都比較理想。3.3 手眼標(biāo)定的執(zhí)行與結(jié)果輸出數(shù)據(jù)全部采集完成后把每組圖像對應(yīng)的標(biāo)定板位姿和機(jī)器人位姿錄入標(biāo)定數(shù)據(jù)對象然后執(zhí)行標(biāo)定* 設(shè)置當(dāng)前圖像對應(yīng)的標(biāo)定板位姿 set_calib_data (CalibDataID, hand_eye, image_pose, PoseCalib) * 設(shè)置對應(yīng)的機(jī)器人末端位姿 set_calib_data (CalibDataID, hand_eye, tool_in_base_pose, PoseRobot) * 全部數(shù)據(jù)錄入完成后執(zhí)行標(biāo)定 calibrate_hand_eye (CalibDataID, PoseHandEye) * 獲取手眼矩陣 get_calib_data (CalibDataID, hand_eye, hand_eye_transform, PoseHandEye)注意set_calib_data調(diào)用時(shí)image_pose和tool_in_base_pose要一組一組配對錄入。順序不能亂第一組圖像對應(yīng)第一組機(jī)器人位姿第二組對應(yīng)第二組一旦錯(cuò)位標(biāo)定出來的矩陣完全不對。PoseHandEye就是最終得到的手眼矩陣。對于眼在手上它表示相機(jī)坐標(biāo)系相對于機(jī)械臂末端坐標(biāo)系的變換可以理解為相機(jī)在機(jī)械臂末端坐標(biāo)系下的位姿。實(shí)際應(yīng)用時(shí)要把圖像坐標(biāo)先轉(zhuǎn)成相機(jī)坐標(biāo)再乘上這個(gè)手眼矩陣轉(zhuǎn)到末端坐標(biāo)再乘上機(jī)器人基座到末端的變換就能得到物體在機(jī)器人基座坐標(biāo)系下的坐標(biāo)。PoseHandEye的單位和格式跟錄入的機(jī)器人位姿有關(guān)。如果機(jī)器人位姿用的都是米那這個(gè)位姿的平移部分也是米。如果錄入的是毫米結(jié)果就是毫米。建議統(tǒng)一使用米跟Halcon默認(rèn)一致省去換算的麻煩。3.4 標(biāo)定結(jié)果的驗(yàn)證方法標(biāo)定完不能直接上線要先驗(yàn)證精度。驗(yàn)證的方法很簡單讓機(jī)械臂帶著相機(jī)眼在手上或者帶著標(biāo)定板眼在手外運(yùn)動到一個(gè)新位置拍照識別標(biāo)定板位姿把標(biāo)定板上的某個(gè)已知點(diǎn)反投到機(jī)器人基座坐標(biāo)系下跟實(shí)際位置比較。以眼在手上為例驗(yàn)證步驟是這樣的第一固定標(biāo)定板不動控制機(jī)械臂移動到某個(gè)新位置拍照用find_calib_object獲取標(biāo)定板在相機(jī)坐標(biāo)系下的位姿PoseCalib。第二取標(biāo)定板上某個(gè)標(biāo)記點(diǎn)的坐標(biāo)比如標(biāo)定板左上角第一個(gè)圓點(diǎn)在標(biāo)定板坐標(biāo)系下坐標(biāo)已知把它從標(biāo)定板坐標(biāo)系轉(zhuǎn)到相機(jī)坐標(biāo)系再乘手眼矩陣轉(zhuǎn)到末端坐標(biāo)系再乘機(jī)器人基座到末端的變換轉(zhuǎn)到基座坐標(biāo)系。第三把這個(gè)計(jì)算出來的基座坐標(biāo)跟實(shí)測的標(biāo)準(zhǔn)值比較看看偏差是多少。一般平移偏差在1mm以內(nèi)就算不錯(cuò)0.3mm以內(nèi)算優(yōu)秀。如果偏差很大基本可以斷定前面某個(gè)環(huán)節(jié)出了問題。Halcon里做矩陣變換常用這組算子* 位姿轉(zhuǎn)矩陣 pose_to_hom_mat3d (PoseCalib, HomMat3DCalib) pose_to_hom_mat3d (PoseHandEye, HomMat3DHandEye) pose_to_hom_mat3d (PoseRobot, HomMat3DRobot) * 點(diǎn)從標(biāo)定板坐標(biāo)系轉(zhuǎn)到相機(jī)坐標(biāo)系 affine_trans_point_3d (HomMat3DCalib, Px, Py, Pz, Cx, Cy, Cz) * 從相機(jī)坐標(biāo)系轉(zhuǎn)到末端坐標(biāo)系 affine_trans_point_3d (HomMat3DHandEye, Cx, Cy, Cz, Tx, Ty, Tz) * 從末端坐標(biāo)系轉(zhuǎn)到基座坐標(biāo)系 affine_trans_point_3d (HomMat3DRobot, Tx, Ty, Tz, Bx, By, Bz)如果驗(yàn)證結(jié)果不理想別急著懷疑算法先檢查數(shù)據(jù)采集過程。絕大部分精度問題都出在數(shù)據(jù)質(zhì)量上而不是Halcon的標(biāo)定算法本身。4. 避坑指南這些坑我基本都踩過4.1 采集位姿的六個(gè)關(guān)鍵原則我踩過不少坑其中最深的幾次都和數(shù)據(jù)采集有關(guān)??偨Y(jié)下來采集位姿時(shí)有六個(gè)原則基本能保證標(biāo)定結(jié)果不會太差。第一數(shù)據(jù)量要夠。至少12組推薦20組左右。太少不行太多也沒必要算力開銷大精度提升有限。第二姿態(tài)要多樣。平移和旋轉(zhuǎn)都要有而且旋轉(zhuǎn)角度要大一點(diǎn)不要只做小角度微調(diào)。很多項(xiàng)目標(biāo)定結(jié)果不好就是因?yàn)樵诓杉瘯r(shí)機(jī)械臂姿態(tài)太接近約束不足。第三位置要分散。標(biāo)定板或相機(jī)在視野里的位置要覆蓋各個(gè)區(qū)域不要只集中在中心附近活動。第四姿態(tài)變化不要雷同。每一組數(shù)據(jù)都要有“新意”不要機(jī)械地重復(fù)同一類型的動作。第五采集時(shí)機(jī)械臂要穩(wěn)定。等機(jī)械臂完全停穩(wěn)抖動消失后再拍照否則圖像模糊會導(dǎo)致位姿提取不準(zhǔn)。第六記錄位姿要和圖像嚴(yán)格同步。如果是自動采集拍照觸發(fā)和機(jī)器人位姿讀取之間不能有太大時(shí)間差否則機(jī)械臂還在動位姿就對不上。4.2 標(biāo)定結(jié)果不準(zhǔn)的排查清單標(biāo)定完成驗(yàn)證精度不合格時(shí)不要慌按下面這個(gè)表逐項(xiàng)排查大部分問題都能找到原因。排查項(xiàng)常見原因解決辦法標(biāo)定板識別失敗對焦模糊、反光、曝光過強(qiáng)調(diào)整光源、對焦、減少反光旋轉(zhuǎn)部分誤差大姿態(tài)變化不足增加旋轉(zhuǎn)變化量避免重復(fù)姿態(tài)平移部分誤差大數(shù)據(jù)量太少或視野覆蓋不足增加數(shù)據(jù)量分散標(biāo)定板位置結(jié)果方向不對手眼矩陣用反了方向驗(yàn)證時(shí)用變換順序糾正單位不對機(jī)器人位姿未統(tǒng)一單位統(tǒng)一使用米或毫米并換算相機(jī)內(nèi)參不準(zhǔn)標(biāo)定助手采集圖像不夠重新標(biāo)定相機(jī)內(nèi)參標(biāo)定板參數(shù)不匹配cpd文件和實(shí)物不一致確認(rèn)標(biāo)定板型號與描述文件匹配這個(gè)表是我做標(biāo)定問題排查時(shí)的標(biāo)準(zhǔn)動作。每次標(biāo)定結(jié)果有問題先過一遍表基本上都能定位到問題環(huán)節(jié)。4.3 坐標(biāo)系和旋轉(zhuǎn)類型的坑坐標(biāo)系搞反是手眼標(biāo)定里最隱蔽的問題。因?yàn)榇a不報(bào)錯(cuò)數(shù)據(jù)也能跑出來但最終用起來就是不對甚至有時(shí)部分對部分錯(cuò)讓人一頭霧水。最常見的錯(cuò)誤是手眼矩陣的方向用反了。Halcon返回的PoseHandEye表示的是相機(jī)在末端坐標(biāo)系下的位姿眼在手上場景。有些機(jī)器人通訊協(xié)議里要的是末端在相機(jī)坐標(biāo)系下的位姿這時(shí)候要把矩陣求逆再傳給機(jī)器人。求逆用hom_mat3d_invert或者把位姿取反旋轉(zhuǎn)角度再轉(zhuǎn)換。另一個(gè)常見問題是旋轉(zhuǎn)類型不一致。Halcon的位姿支持多種旋轉(zhuǎn)類型包括gba、abg、xyz等。如果機(jī)器人端給的是abg歐拉角而Halcon里按gba理解結(jié)果會出現(xiàn)明顯誤差。最穩(wěn)妥的做法是在錄入機(jī)器人位姿前統(tǒng)一用convert_pose_type轉(zhuǎn)成同一種類型再錄入標(biāo)定數(shù)據(jù)對象。還有個(gè)容易忽略的點(diǎn)機(jī)械臂的零位和坐標(biāo)方向要確認(rèn)。不同廠家的機(jī)器人基座坐標(biāo)系定義不一樣有的X軸朝前有的Y軸朝前如果跟視覺系統(tǒng)的坐標(biāo)系定義不一致標(biāo)定結(jié)果也會偏差。處理辦法是在標(biāo)定前先約定好坐標(biāo)系方向或者用一根校準(zhǔn)棒做一次粗略的手動驗(yàn)證確認(rèn)坐標(biāo)系映射關(guān)系沒錯(cuò)再繼續(xù)。4.4 深度圖轉(zhuǎn)點(diǎn)云和3D手眼標(biāo)定的延伸前面講的主要是2D相機(jī)標(biāo)定但很多項(xiàng)目做到后面會升級到3D視覺。Halcon里深度圖轉(zhuǎn)點(diǎn)云相關(guān)的話題和手眼標(biāo)定經(jīng)常一起出現(xiàn)這里也稍微提一下。如果是3D相機(jī)比如結(jié)構(gòu)光、線激光做手眼標(biāo)定原理和2D是類似的區(qū)別在于從深度圖轉(zhuǎn)出的點(diǎn)云數(shù)據(jù)里如何提取標(biāo)定板的3D位姿。Halcon支持用點(diǎn)云做標(biāo)定板匹配算子流程復(fù)雜一些但標(biāo)定思路完全一致。如果用的是2D相機(jī)加額外深度傳感器那就要做2D相機(jī)和深度相機(jī)之間的外參標(biāo)定再配合手眼標(biāo)定鏈路更長坑也更多。我建議這類項(xiàng)目盡量選成熟的3D視覺方案減少自己拼裝標(biāo)定的麻煩。反過來如果項(xiàng)目還在評估階段先用2D相機(jī)做做看后續(xù)再升級3D那在相機(jī)安裝支架、光源、標(biāo)定板選型這些環(huán)節(jié)就要提前考慮兼容性避免后期改造大動干戈。4.5 與OpenCV、Vision Master方案的對比取舍最后聊聊方案選型。很多人問Halcon手眼標(biāo)定和OpenCV比到底好在哪里我自己的體會是Halcon的標(biāo)定工具鏈更完整從標(biāo)定板識別到位姿優(yōu)化集成度高出問題的概率低OpenCV則更靈活可以跟深度學(xué)習(xí)、自定義算法無縫集成但工程量翻倍。舉個(gè)例子用OpenCV做手眼標(biāo)定你得自己處理aruco棋盤格的角點(diǎn)提取、位姿解算還要解決相機(jī)畸變模型差異。這些步驟每一步都有坑中間任何一步出錯(cuò)都會讓最終結(jié)果很奇怪。Halcon從find_calib_object到calibrate_hand_eye是同一套數(shù)據(jù)管理標(biāo)定板參數(shù)、相機(jī)參數(shù)、位姿錄入全部在CalibData對象里流程清晰不容易半路出錯(cuò)。至于Vision Master這類平臺拿來跑標(biāo)準(zhǔn)應(yīng)用確實(shí)省事但它的自定義能力有限。如果你需要把標(biāo)定結(jié)果嵌入到自己寫的Qt或者C#上位機(jī)里Halcon的二次開發(fā)接口就方便多了。Halcon不僅可以在HDevelop里操作也可以用export導(dǎo)出代碼到C/C#直接集成進(jìn)自己的程序框架。我個(gè)人在每個(gè)項(xiàng)目里做視覺方案選型時(shí)會綜合評估三點(diǎn)項(xiàng)目精度要求、團(tuán)隊(duì)視覺開發(fā)能力、預(yù)算。預(yù)算充足且對精度有硬指標(biāo)直接上Halcon預(yù)算有限但團(tuán)隊(duì)有人寫過OpenCV用OpenCV也能做出來完全不想寫代碼上現(xiàn)成的視覺平臺是最穩(wěn)的選擇。最后再分享一點(diǎn)小經(jīng)驗(yàn)手眼標(biāo)定這個(gè)事原理在紙面上看都挺簡單真正做起來卻總有意外。我做過的項(xiàng)目里標(biāo)定一次就完美通過的情況很少大多數(shù)都要經(jīng)過數(shù)據(jù)補(bǔ)采、參數(shù)調(diào)整、重新標(biāo)定的循環(huán)。這很正常不用因此懷疑自己。我給你一個(gè)建議每次標(biāo)定前把相機(jī)內(nèi)參、機(jī)器人位姿、標(biāo)定板描述文件這三樣?xùn)|西單獨(dú)保存好做好版本管理。一旦標(biāo)定結(jié)果有問題可以快速復(fù)盤而不是一頭扎進(jìn)代碼里找原因。另外標(biāo)定板不要隨手亂放更不要拿手摸圓點(diǎn)區(qū)域保持表面清潔標(biāo)定板的物理精度會直接傳遞到最終結(jié)果里。如果你正準(zhǔn)備做Halcon手眼標(biāo)定照著這篇文章的流程走一遍遇到問題再對著排查表逐項(xiàng)檢查大概率能順利解決。做完之后你會發(fā)現(xiàn)手眼標(biāo)定其實(shí)是個(gè)熟能生巧的活第二次做就快很多了。