械臂控制實戰(zhàn):從URDF建模到MoveIt規(guī)劃)
簡介這是一份基于ROS的六自由度機(jī)械臂控制項目源碼包面向機(jī)器人開發(fā)者、ROS學(xué)習(xí)者及機(jī)械臂應(yīng)用工程師幫助解決從運動學(xué)建模、正逆解計算到鍵盤遙操作、軌跡復(fù)現(xiàn)等實際控制問題。壓縮包共35個文件大小約776KB涵蓋cpp源碼、URDF模型、STL網(wǎng)格、launch啟動文件、Python腳本、YAML參數(shù)配置等并附帶RViz配置與Gazebo仿真所需的模型文件便于快速導(dǎo)入工程進(jìn)行二次開發(fā)。項目采用Orocos KDL庫實現(xiàn)正逆向運動學(xué)支持沿各軸線性移動或旋轉(zhuǎn)的遙操作模式可記錄、刪除與播放機(jī)械臂姿態(tài)序列還內(nèi)置G代碼解析與執(zhí)行能力源碼預(yù)覽中可見完整的功能模塊劃分與可運行demo設(shè)計。通過閱讀源碼與URDF模型讀者能掌握ROS下機(jī)械臂控制項目的工程結(jié)構(gòu)、KDL運動學(xué)調(diào)用流程以及仿真調(diào)試方法適合作為課程設(shè)計或入門進(jìn)階的參考資料。目前已有123人學(xué)習(xí)下載。 這幾天在整理手頭的機(jī)器人項目檔案翻出去年折騰過的一個基于ROS的六自由度機(jī)械臂控制項目正好把源碼結(jié)構(gòu)、核心原理和實操過程一起做個復(fù)盤。這個項目包叫CobotArm6DOF.zip名字里信息量其實挺大Cobot表明協(xié)作式機(jī)械臂定位6DOF指六個自由度底層控制全部跑在ROS框架里。對于剛?cè)腴TROS機(jī)械臂開發(fā)的同學(xué)或者手頭有一臺六軸機(jī)械臂但不知道如何從零搭建控制的工程師這個項目的可參考價值都很高。我沒有把它當(dāng)成一個普通的demo看待而是把URDF建模、MoveIt配置、控制器參數(shù)、仿真驗證到實機(jī)遷移這條鏈路的每個環(huán)節(jié)都拆開過一遍。這篇內(nèi)容我會按“整體設(shè)計 - 核心原理 - 實操步驟 - 問題排查 - 后續(xù)擴(kuò)展”的順序來講盡量把那些文檔里不會寫、但實際開發(fā)中一定會遇到的細(xì)節(jié)也一并交代清楚。1. 項目整體思路與設(shè)計拆解拿到一個源碼包先別急著編譯。第一件事是搞清楚作者的意圖和整體架構(gòu)否則一旦編譯報錯你連問題出在哪里都判斷不了。CobotArm6DOF這個項目光看目錄結(jié)構(gòu)就能看出作者是有意做成一套“可遷移”的機(jī)械臂控制框架而不是只為了炫一個仿真動畫。1.1 六自由度到底意味著什么六自由度機(jī)械臂通俗說就是機(jī)械臂末端在三維空間里有6個獨立的運動方向沿X、Y、Z三個軸的平移以及繞這三個軸的旋轉(zhuǎn)。為什么是6而不是7因為一個剛體在三維空間中的完整位姿恰好是6個自由度6個關(guān)節(jié)的串聯(lián)機(jī)械臂理論上就能實現(xiàn)末端到達(dá)工作空間內(nèi)的任意位姿。人手其實也是這個邏輯肩部提供3個旋轉(zhuǎn)、肘部提供1個旋轉(zhuǎn)、腕部提供2個旋轉(zhuǎn)加起來正好覆蓋全部姿態(tài)能力。CobotArm6DOF的關(guān)節(jié)構(gòu)型基本采用的是經(jīng)典的“3個肩關(guān)節(jié) 1個肘關(guān)節(jié) 2個腕關(guān)節(jié)”布置方案。這種構(gòu)型的好處是數(shù)學(xué)上容易做解析逆解、工作空間呈球殼狀末端靈活性比較高非常適合做抓取、裝配、軌跡示教這類典型任務(wù)。關(guān)節(jié)多了反而會引入冗余自由度帶來的自運動問題控制難度會顯著上升。1.2 為什么選ROS而不是其他控制框架這個項目選擇ROS作為底層框架我覺得是很合理的一個決策。ROS雖然不是實時操作系統(tǒng)但它的節(jié)點通信模型、話題發(fā)布訂閱機(jī)制、以及龐大的機(jī)器人算法生態(tài)讓“快速搭建一套完整機(jī)械臂控制原型”變成了可能。尤其是MoveIt這個社區(qū)它已經(jīng)把運動規(guī)劃、碰撞檢測、逆解、軌跡執(zhí)行這些復(fù)雜模塊整合成了一套標(biāo)準(zhǔn)工具開發(fā)者不需要從底層數(shù)學(xué)開始造輪子。用生活化的方式來理解ROS就像是機(jī)械臂開發(fā)里的“操作系統(tǒng)標(biāo)準(zhǔn)接口”。你在仿真環(huán)境里寫的控制器、規(guī)劃器代碼換到實機(jī)上只需要改硬件驅(qū)動層上層邏輯可以完全復(fù)用。這在工業(yè)現(xiàn)場可能還不夠硬實時但對于教學(xué)、科研和原型驗證來說性價比極高。1.3 源碼目錄怎么讀解開壓縮包后正常會看到若干個功能包大致可以分成三類機(jī)械臂描述包包含URDF模型文件、網(wǎng)格模型文件以及加載模型的launch腳本負(fù)責(zé)告訴系統(tǒng)這臺機(jī)械臂長什么樣、關(guān)節(jié)怎么運動。MoveIt配置包由MoveIt Setup Assistant生成包含SRDF、規(guī)劃組定義、運動學(xué)插件、OMPL規(guī)劃器配置等。控制器配置文件定義關(guān)節(jié)控制器類型、PID參數(shù)、關(guān)節(jié)限位等信息連接MoveIt指令和硬件的橋梁。我強(qiáng)烈建議先花十分鐘把每個包的CMakeLists.txt和package.xml過一遍看看依賴了哪些庫。這樣即使后面修改代碼也能快速判斷哪些是核心依賴、哪些只是可選插件。2. 核心模塊與原理淺析機(jī)械臂控制在技術(shù)層面可以濃縮成三個核心問題它長得什么樣建模、它該怎么動運動學(xué)、它怎么避開障礙到達(dá)目標(biāo)規(guī)劃。這一章我會把這三個問題的原理講透并對應(yīng)到項目里的具體實現(xiàn)。2.1 URDF機(jī)械臂的“骨骼”URDFUnified Robot Description Format是ROS里描述機(jī)器人幾何結(jié)構(gòu)和運動關(guān)系的標(biāo)準(zhǔn)格式。URDF里的每個link就是機(jī)械臂的一節(jié)“骨頭”用于定義視覺形狀、碰撞體積和慣性參數(shù)每個joint則是連接兩塊骨骼的“關(guān)節(jié)”負(fù)責(zé)定義關(guān)節(jié)類型、旋轉(zhuǎn)軸、限位角度等。一個典型的URDF片段看起來是這樣link namelink2 visual geometry mesh filenamepackage://cobotarm6dof_description/meshes/link2.stl/ /geometry origin xyz0 0 0.15 rpy0 0 0/ /visual collision geometry mesh filenamepackage://cobotarm6dof_description/meshes/link2.stl/ /geometry /collision /link joint namejoint2 typerevolute parent linklink1/ child linklink2/ origin xyz0 0 0.14 rpy0 0 0/ axis xyz0 0 1/ limit lower-2.9 upper2.9 effort100 velocity3.14/ /joint這里最容易犯的錯誤是link的坐標(biāo)系和網(wǎng)格模型的原點沒有對齊。URDF里的visual和collision都需要指定相對父坐標(biāo)系的位置與姿態(tài)rpy很多新手拿了別人的STL模型直接填上去結(jié)果機(jī)械臂的視覺模型和數(shù)學(xué)模型錯位后面的TF變換和運動學(xué)計算全被帶偏。在迭代修改URDF時建議每改一次就在RViz里加載一遍把Fixed Frame設(shè)為base_link然后逐個檢查每個link的坐標(biāo)系朝向是否正確。坐標(biāo)系方向不對到真機(jī)階段就是災(zāi)難。2.2 運動學(xué)正解和逆解運動學(xué)分為正解和逆解。正解就是已知6個關(guān)節(jié)角求末端位姿逆解則是已知末端目標(biāo)位姿反推6個關(guān)節(jié)角。整個過程可以用DH參數(shù)Denavit-Hartenberg來建模。DH參數(shù)表有4個關(guān)鍵變量連桿長度a、連桿偏距d、連桿扭角alpha、關(guān)節(jié)角theta。簡化版六軸機(jī)械臂的DH表大致會呈現(xiàn)這種規(guī)律關(guān)節(jié)adalphatheta100.10-pi/2變量20.3000變量30.030-pi/2變量400.30pi/2變量500-pi/2變量600.070變量有了DH參數(shù)表正解就是標(biāo)準(zhǔn)的齊次變換矩陣連乘幾行代碼就能寫出來。逆解則麻煩得多常見有兩種方案數(shù)值迭代解法和解析解法。MoveIt默認(rèn)使用KDL插件做數(shù)值逆解它在遠(yuǎn)離奇異點時表現(xiàn)不錯但到了奇異點附近迭代容易發(fā)散。如果目標(biāo)項目對逆解速度和穩(wěn)定性要求高可以考慮用IKFast生成解析解速度能快一個數(shù)量級但需要額外做配置。2.3 運動規(guī)劃器怎么選MoveIt里集成的OMPL提供了多種采樣規(guī)劃算法。默認(rèn)情況下的RRTConnect已經(jīng)能應(yīng)對大多數(shù)規(guī)劃場景它的原理是從起點和終點同時向外生長兩棵樹直到相遇適合高維空間快速搜索。如果任務(wù)場景是靜態(tài)環(huán)境下反復(fù)規(guī)劃PRM這類概率路線圖算法可以提前構(gòu)建路線圖規(guī)劃速度更快如果要做軌跡優(yōu)化可以考慮STOMP或CHOMP但它們的參數(shù)調(diào)節(jié)比較敏感對新手不友好。項目里通常會把這些規(guī)劃器參數(shù)放在ompl_planning.yaml里。如果發(fā)現(xiàn)規(guī)劃經(jīng)常失敗優(yōu)先檢查規(guī)劃器的timeout設(shè)置以及目標(biāo)位姿本身是否在工作空間內(nèi)。規(guī)劃器再強(qiáng)也不可能把末端弄到物理上夠不著的地方。3. 從零到一完整實操流程這一章我按自己實際跑通項目的順序來寫包含環(huán)境準(zhǔn)備、編譯啟動、仿真調(diào)試、真機(jī)遷移四個階段。每一步都寫清楚命令和預(yù)期結(jié)果你可以照著操作。3.1 環(huán)境準(zhǔn)備與依賴安裝這個項目基于ROS Noetic開發(fā)最省心的搭配是Ubuntu 20.04 ROS Noetic。如果你用的是Ubuntu 22.04也可以跑ROS 2 Humble但launch文件、controller工具鏈都要相應(yīng)修改不建議新手一上來就跨版本折騰。ROS環(huán)境鋪好之后需要確保安裝了以下依賴sudo apt install ros-noetic-moveit ros-noetic-gazebo-ros-pkgs ros-noetic-ros-control ros-noetic-ros-controllers ros-noetic-joint-state-publisher ros-noetic-robot-state-publisher如果機(jī)器上rosdep update一直不穩(wěn)定可以先把rosdistro源切到國內(nèi)鏡像或者直接用一鍵安裝腳本先把ROS基礎(chǔ)環(huán)境鋪好再繼續(xù)。我在實際項目中用了魚香ROS的一鍵安裝腳本一次配好之后確實省去很多折騰的精力。3.2 編譯與啟動仿真依賴裝好之后把源碼包解壓到工作空間進(jìn)入src目錄然后編譯cd ~/cobotarm6dof_ws catkin_make source devel/setup.bash編譯過程中如果遇到缺庫的報錯缺什么就補(bǔ)什么通常都是某個package.xml里聲明的依賴沒裝全。編譯通過后啟動完整仿真環(huán)境roslaunch cobotarm6dof_description gazebo.launch另一個終端啟動MoveIt的demoroslaunch cobotarm6dof_moveit_config demo.launch在RViz里用MoveIt的拖拽工具把末端目標(biāo)位姿拉到另一個位置點擊Plan可以看到規(guī)劃的軌跡動畫點擊Execute機(jī)械臂就會在Gazebo里執(zhí)行運動。這一步跑通說明整個框架的鏈路是通的。3.3 控制器配置與真機(jī)遷移準(zhǔn)備仿真跑通后如果需要遷移到實機(jī)重點就在控制器配置。MoveIt發(fā)出的軌跡指令是一系列帶時間戳的關(guān)節(jié)位置點需要由ros_control框架真正的關(guān)節(jié)控制器來接。在config/controller.yaml里通常會有這樣的配置joint_state_controller: type: joint_state_controller/JointStateController publish_rate: 50 arm_controller: type: position_controllers/JointTrajectoryController joints: - joint1 - joint2 - joint3 - joint4 - joint5 - joint6 constraints: goal_time: 0.6JointTrajectoryController接收MoveIt發(fā)布的/arm_controller/command話題把軌跡點平滑地轉(zhuǎn)換成底層位置指令。如果底層電機(jī)驅(qū)動器支持速度或力矩模式也可以換成effort_controllers/JointTrajectoryController但需要PID調(diào)參的工作量會明顯增加。我自己的工程建議是第一個版本先用位置控制器把軌跡跟蹤調(diào)穩(wěn)再考慮力矩控制。4. 常見問題與排查技巧實錄在跑項目過程中我遇到過不少問題很多問題并不在官方文檔里。這里把最有代表性的幾個整理出來按現(xiàn)象、原因、解決方式的順序?qū)懬宄?.1 TF樹缺失導(dǎo)致MoveIt無法規(guī)劃現(xiàn)象MoveIt界面能打開但RViz里看不到機(jī)械臂模型或者模型翻滾錯亂Plan按鈕是灰色。原因TF樹不完整。MoveIt依賴完整的TF樹才能計算機(jī)械臂當(dāng)前狀態(tài)。如果robot_state_publisher沒有正確發(fā)布關(guān)節(jié)變換/tf里就只有base_link和map缺了后續(xù)的link1到link6。排查方法rosrun tf view_frames生成的frames.pdf可以看到當(dāng)前TF樹結(jié)構(gòu)。缺失的環(huán)節(jié)通常是因為URDF里joint定義錯誤或者robot_state_publisher節(jié)點沒有啟動。修復(fù)URDF后重新加載問題基本能解決。4.2 規(guī)劃器提示無有效運動規(guī)劃現(xiàn)象Plan時控制臺頻繁出現(xiàn)No valid solution found之類的報錯或者規(guī)劃嘗試了幾秒鐘后放棄。原因目標(biāo)位姿不可達(dá)、當(dāng)前機(jī)械臂狀態(tài)發(fā)送有問題、碰撞環(huán)境設(shè)置過于保守三種都可能導(dǎo)致規(guī)劃失敗。排查順序先檢查目標(biāo)位姿是否在機(jī)械臂工作空間內(nèi)。最簡單的辦法是手動把末端拖到目標(biāo)點附近位置看看是否進(jìn)得去。再檢查MoveIt的PlanningScene里是否無意中添加了不該有的障礙物。最后可以把OMPL的超時時間調(diào)大再試一次。4.3 仿真里能跑、實機(jī)上關(guān)節(jié)抖動劇烈現(xiàn)象仿真環(huán)境下一切正常但同樣的控制器和軌跡下到真機(jī)機(jī)械臂某個關(guān)節(jié)出現(xiàn)明顯抖動甚至嘯叫。原因仿真中默認(rèn)忽略了摩擦、齒隙、驅(qū)動器帶寬等非線性因素。實機(jī)上如果PID增益調(diào)得過高輕微的關(guān)節(jié)反饋噪聲就會被放大導(dǎo)致抖動。解決思路先檢查關(guān)節(jié)的effort和velocity限位是否與物理樣機(jī)一致。在控制器里把速度和加速度限制下調(diào)到50%再測試很多抖動問題會消失。如果還抖給目標(biāo)軌跡加平滑濾波或者降低位置環(huán)KP值。六軸機(jī)械臂的關(guān)節(jié)從靜止到運動起步瞬間最忌諱階躍式位置指令。我在實機(jī)調(diào)試時踩過的坑是以為仿真里調(diào)好的軌跡可以直接下給樣機(jī)結(jié)果前臂關(guān)節(jié)在起步時瘋狂震蕩后來發(fā)現(xiàn)是加速度限制沒設(shè)置驅(qū)動板直接報過流。這個教訓(xùn)很深刻。5. 后續(xù)擴(kuò)展與個人實戰(zhàn)心得項目跑通只是開始。一個基于ROS的六自由度機(jī)械臂控制框架可以向很多方向做二次開發(fā)。5.1 可以往哪些方向擴(kuò)展如果手頭有深度相機(jī)比如Realsense或Orbbec可以加一個視覺抓取模塊。步驟大致是相機(jī)標(biāo)定、手眼標(biāo)定、目標(biāo)物體檢測與位姿估計、把物體位姿發(fā)送給MoveIt規(guī)劃抓取軌跡。整個流程在ROS生態(tài)里都有現(xiàn)成工具核心工作量主要集中在手眼標(biāo)定和坐標(biāo)系變換上這部分一定要親自動手做一遍。如果下一步計劃轉(zhuǎn)向工業(yè)/商用可以考慮把上位機(jī)框架遷移到ROS 2 Humble或更正式的工業(yè)控制器上。URDF和運動學(xué)部分可以復(fù)用但launch體系、控制器工具、參數(shù)配置方式要重寫這個遷移過程本身就是對整體框架理解的最好檢驗。另外六軸機(jī)械臂還有一個很常用的功能叫“拖動示教”在末端裝一個六維力/力矩傳感器用導(dǎo)納控制算法實現(xiàn)人手直接拖動機(jī)器臂運動。CobotArm6DOF的底層控制結(jié)構(gòu)完全可以在此基礎(chǔ)上擴(kuò)展只需要把位置指令換成力控指令再在控制器里增加導(dǎo)納舊算法即可。5.2 三個值得記住的工程原則結(jié)合這個項目和之前做過的其他機(jī)器人開源項目有三條原則是我覺得可以長期受用的第一先簡化再復(fù)雜。上手任何機(jī)械臂項目第一步不是把所有傳感器、視覺、力控全部接上而是讓機(jī)械臂在RViz里能顯示、能規(guī)劃、能運動先把最小閉環(huán)跑通再逐步疊加外設(shè)。每一步只改一個變量出了問題能立刻定位。第二記錄每一個參數(shù)的變化。控制器參數(shù)、URDF參數(shù)、規(guī)劃器參數(shù)每一次修改都記錄原始值和修改原因。這個習(xí)慣能在遇到“以前還好好的現(xiàn)在壞了”這類問題時幫你快速回退。我自己在調(diào)PID的時候就吃過虧改了Kp忘了記出了問題只能從零開始重調(diào)。第三仿真和實機(jī)之間的鴻溝要正視。仿真里能跑通不代表真機(jī)一定沒問題。先把仿真里的運動限位、加速度、速度和實機(jī)對齊再考慮更高階的控制策略。機(jī)械臂一旦失控修復(fù)成本遠(yuǎn)不止時間。這次復(fù)盤CobotArm6DOF我最大的體會是六自由度機(jī)械臂控制并不神秘它的核心就是建模、運動學(xué)、規(guī)劃和控制這幾個環(huán)節(jié)的耦合。只要把每條鏈路都理解透、把每份配置都搞清楚剩下的就是耐心調(diào)試。希望這份拆解對你有用也歡迎在實際操作中隨時來聊聊你遇到的問題。本文還有配套的精品資源點擊獲取