[{"data":1,"prerenderedAt":8642},["ShallowReactive",2],{"wiki-page-/zh-hk/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control":3,"wiki-doc-items-/zh-hk/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control":8277,"language-switcher-data-/zh-hk/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control":8626,"wiki-i18n-paths-/zh-hk/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control":8641},{"id":4,"title":5,"body":6,"canonicalPath":8258,"chapter":8259,"chapterSort":8260,"date":8261,"description":82,"docI18nKey":8262,"docKey":8263,"docRoot":8264,"docTitle":8265,"extension":8266,"i18nKey":8267,"isBlogPost":8268,"isWikiDoc":1568,"isWikiIndex":8268,"layout":8269,"legacyPath":8269,"locale":8270,"localeSlug":8271,"meta":8272,"navigation":1568,"path":8258,"seo":8273,"sourcePath":8274,"sourceStem":8267,"stem":8275,"wikiDepth":89,"__hash__":8276},"content/_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch15-ROS2_Control.md","ROS2_Control",{"type":7,"value":8,"toc":8242},"minimark",[9,14,19,26,33,63,73,76,93,96,220,224,230,254,260,279,282,286,289,292,325,328,406,421,424,437,440,443,472,475,505,508,530,533,601,604,901,923,926,948,951,991,996,1013,1016,1049,1052,1082,1095,1099,1103,1106,1120,1123,1132,1135,1206,1209,1295,1308,1311,1316,1324,1327,1382,1385,1407,1410,1413,1466,1469,1475,1486,1490,1493,1500,1503,1631,1637,1698,1702,1708,1717,1720,1729,1732,1735,1940,1943,1968,1975,1982,2077,2088,2092,2096,2101,2117,2124,2197,2202,2292,2296,2299,2454,2461,2467,2470,2472,2477,2509,2520,2544,2547,2644,2647,2652,2689,2691,2733,2737,2746,2749,2764,2767,2784,2787,2801,2804,2829,2832,2846,2849,2875,2878,2894,2897,2911,2914,2918,2923,2932,2934,2942,2945,2993,2996,3042,3048,3052,3057,3066,3068,3076,3079,3103,3106,3140,3146,3155,3158,3223,3226,3344,3347,3424,3427,3481,3495,3499,3504,3513,3515,3524,3527,3571,3574,3655,3658,3728,3741,3745,3750,3759,3762,3777,3780,3783,3830,3833,3855,3859,3866,4213,4239,4242,4253,4256,4260,4264,4468,4472,4668,4671,4674,4708,4711,4765,4768,4771,4774,4794,4803,4807,4810,4903,4913,4965,4970,4973,4976,5717,5720,5758,5761,5852,5855,5907,5910,5913,5970,5973,5976,5979,6056,6059,6063,6066,6078,6081,6163,6168,6188,6198,6201,6207,6255,6258,6641,6644,6648,6651,6748,6751,6808,6812,6815,6971,6974,7058,7061,7127,7130,7133,7175,7178,7184,7187,7199,7202,7206,7213,7216,7235,7238,7257,7267,7273,7282,7285,7294,7300,7499,7502,7569,7575,7659,7662,7671,7674,7737,7740,7765,7768,7782,7785,7788,7791,7794,7806,7809,7833,7845,7848,7851,7876,7879,7896,7902,7905,7939,7941,7963,7969,7976,7992,7995,8004,8007,8043,8046,8048,8073,8077,8086,8111,8114,8117,8165,8168,8171,8238],[10,11,13],"h3",{"id":12},"ros2-control-概述","ROS2 Control 概述",[15,16,18],"h4",{"id":17},"ros2-control-簡述","ROS2 Control 簡述",[20,21,22],"p",{},[23,24,25],"strong",{},"概念",[20,27,28,32],{},[29,30,31],"code",{},"ros2_control"," 是 ROS 2 中用於機器人控制的標準框架。它的核心思想是把機器人控制拆成三層：",[34,35,36,47,57],"ul",{},[37,38,39,42,43,46],"li",{},[23,40,41],{},"控制器（Controller）"," ：負責控制算法。例如差速底盤控制器把 ",[29,44,45],{},"cmd_vel"," 轉成左右輪速度，軌跡控制器把關節軌跡轉成關節命令。",[37,48,49,52,53,56],{},[23,50,51],{},"控制器管理器（Controller Manager）"," ：負責加載、配置、激活、停止控制器，並在固定頻率下執行 ",[29,54,55],{},"read -> update -> write"," 控制循環。",[37,58,59,62],{},[23,60,61],{},"硬件接口（Hardware Interface）"," ：負責和真實硬件、仿真硬件或模擬硬件通信，讓控制器不用關心底層串口、CAN、EtherCAT、Gazebo 或自定義驅動。",[20,64,65,66,68,69,72],{},"簡單説，",[29,67,31],{}," 是 ROS 2 中“控制器”和“硬件”之間的標準插座。控制器只面對標準接口，硬件只暴露標準接口，中間由 ",[29,70,71],{},"controller_manager"," 管理。",[20,74,75],{},"在 Ubuntu 24.04 + ROS 2 Jazzy 中，ROS 2 的默認安裝路徑是：",[77,78,83],"pre",{"className":79,"code":80,"language":81,"meta":82,"style":82},"language-bash shiki shiki-themes github-light github-dark","/opt/ros/jazzy\n","bash","",[29,84,85],{"__ignoreMap":82},[86,87,90],"span",{"class":88,"line":89},"line",1,[86,91,80],{"class":92},"sScJk",[20,94,95],{},"常見 ros2_control 包路徑如下：",[97,98,99,116],"table",{},[100,101,102],"thead",{},[103,104,105,110,113],"tr",{},[106,107,109],"th",{"align":108},"left","軟件包",[106,111,112],{"align":108},"路徑",[106,114,115],{"align":108},"説明",[117,118,119,134,156,171,186,201],"tbody",{},[103,120,121,126,131],{},[122,123,124],"td",{"align":108},[29,125,31],{},[122,127,128],{"align":108},[29,129,130],{},"/opt/ros/jazzy/share/ros2_control",[122,132,133],{"align":108},"ros2_control 元包",[103,135,136,140,145],{},[122,137,138],{"align":108},[29,139,71],{},[122,141,142],{"align":108},[29,143,144],{},"/opt/ros/jazzy/share/controller_manager",[122,146,147,148,151,152,155],{"align":108},"控制器管理器，提供 ",[29,149,150],{},"ros2_control_node","、",[29,153,154],{},"spawner"," 等工具",[103,157,158,163,168],{},[122,159,160],{"align":108},[29,161,162],{},"controller_interface",[122,164,165],{"align":108},[29,166,167],{},"/opt/ros/jazzy/share/controller_interface",[122,169,170],{"align":108},"自定義控制器要繼承的基礎接口",[103,172,173,178,183],{},[122,174,175],{"align":108},[29,176,177],{},"hardware_interface",[122,179,180],{"align":108},[29,181,182],{},"/opt/ros/jazzy/share/hardware_interface",[122,184,185],{"align":108},"自定義硬件接口要繼承的基礎接口",[103,187,188,193,198],{},[122,189,190],{"align":108},[29,191,192],{},"ros2_controllers",[122,194,195],{"align":108},[29,196,197],{},"/opt/ros/jazzy/share/ros2_controllers",[122,199,200],{"align":108},"官方常用控制器元包",[103,202,203,208,213],{},[122,204,205],{"align":108},[29,206,207],{},"ros2controlcli",[122,209,210],{"align":108},[29,211,212],{},"/opt/ros/jazzy/share/ros2controlcli",[122,214,215,216,219],{"align":108},"提供 ",[29,217,218],{},"ros2 control ..."," 命令",[15,221,223],{"id":222},"ros2-control-解決了什麼問題","ROS2 Control 解決了什麼問題",[20,225,226,227,229],{},"如果不用 ",[29,228,31],{},"，機器人控制程序很容易寫成這樣：",[34,231,232,239,242,245,248,251],{},[37,233,234,235,238],{},"節點直接訂閲 ",[29,236,237],{},"/cmd_vel","；",[37,240,241],{},"節點自己計算左右輪速度；",[37,243,244],{},"節點自己讀編碼器；",[37,246,247],{},"節點自己寫串口或 CAN；",[37,249,250],{},"換硬件時整套控制節點都要改；",[37,252,253],{},"從仿真遷移到真機時還要再改一遍。",[20,255,256,257,259],{},"使用 ",[29,258,31],{}," 後，推薦的結構是：",[34,261,262,265,268,271,274],{},[37,263,264],{},"控制器負責算法，例如差速運動學、機械臂軌跡插值、PID、夾爪控制。",[37,266,267],{},"硬件接口負責通信，例如串口協議、CAN 報文、驅動板寄存器、Gazebo 插件。",[37,269,270],{},"URDF 負責聲明機器人有哪些 joint、command interface 和 state interface。",[37,272,273],{},"YAML 負責聲明加載哪些控制器以及控制器參數。",[37,275,276,278],{},[29,277,71],{}," 負責把它們組合起來。",[20,280,281],{},"這樣做的好處是：控制器可以複用，硬件可以替換，仿真和真機可以共用大部分上層配置。",[10,283,285],{"id":284},"ros2-control-安裝","ROS2 Control 安裝",[15,287,288],{"id":288},"基礎安裝",[20,290,291],{},"Ubuntu 24.04 使用 ROS 2 Jazzy 時，安裝命令如下：",[77,293,295],{"className":79,"code":294,"language":81,"meta":82,"style":82},"sudo apt update\nsudo apt install ros-jazzy-ros2-control ros-jazzy-ros2-controllers\n",[29,296,297,309],{"__ignoreMap":82},[86,298,299,302,306],{"class":88,"line":89},[86,300,301],{"class":92},"sudo",[86,303,305],{"class":304},"sZZnC"," apt",[86,307,308],{"class":304}," update\n",[86,310,312,314,316,319,322],{"class":88,"line":311},2,[86,313,301],{"class":92},[86,315,305],{"class":304},[86,317,318],{"class":304}," install",[86,320,321],{"class":304}," ros-jazzy-ros2-control",[86,323,324],{"class":304}," ros-jazzy-ros2-controllers\n",[20,326,327],{},"這兩個包已經能滿足大多數真機控制、控制器開發和基礎學習。如果想把本章的調試工具、Gazebo Sim 示例、測試輔助包也裝齊，建議繼續安裝：",[77,329,331],{"className":79,"code":330,"language":81,"meta":82,"style":82},"sudo apt install \\\n  ros-jazzy-gz-ros2-control \\\n  ros-jazzy-gz-ros2-control-demos \\\n  ros-jazzy-rqt-controller-manager \\\n  ros-jazzy-rqt-joint-trajectory-controller \\\n  ros-jazzy-ros2-controllers-test-nodes \\\n  ros-jazzy-hardware-interface-testing \\\n  ros-jazzy-joint-state-topic-hardware-interface \\\n  ros-jazzy-battery-state-broadcaster\n",[29,332,333,345,352,360,368,376,384,392,400],{"__ignoreMap":82},[86,334,335,337,339,341],{"class":88,"line":89},[86,336,301],{"class":92},[86,338,305],{"class":304},[86,340,318],{"class":304},[86,342,344],{"class":343},"sj4cs"," \\\n",[86,346,347,350],{"class":88,"line":311},[86,348,349],{"class":304},"  ros-jazzy-gz-ros2-control",[86,351,344],{"class":343},[86,353,355,358],{"class":88,"line":354},3,[86,356,357],{"class":304},"  ros-jazzy-gz-ros2-control-demos",[86,359,344],{"class":343},[86,361,363,366],{"class":88,"line":362},4,[86,364,365],{"class":304},"  ros-jazzy-rqt-controller-manager",[86,367,344],{"class":343},[86,369,371,374],{"class":88,"line":370},5,[86,372,373],{"class":304},"  ros-jazzy-rqt-joint-trajectory-controller",[86,375,344],{"class":343},[86,377,379,382],{"class":88,"line":378},6,[86,380,381],{"class":304},"  ros-jazzy-ros2-controllers-test-nodes",[86,383,344],{"class":343},[86,385,387,390],{"class":88,"line":386},7,[86,388,389],{"class":304},"  ros-jazzy-hardware-interface-testing",[86,391,344],{"class":343},[86,393,395,398],{"class":88,"line":394},8,[86,396,397],{"class":304},"  ros-jazzy-joint-state-topic-hardware-interface",[86,399,344],{"class":343},[86,401,403],{"class":88,"line":402},9,[86,404,405],{"class":304},"  ros-jazzy-battery-state-broadcaster\n",[20,407,408,409,412,413,416,417,420],{},"其中 ",[29,410,411],{},"ros-jazzy-gz-ros2-control"," 是 Gazebo Sim 接入 ros2_control 的核心包，",[29,414,415],{},"ros-jazzy-gz-ros2-control-demos"," 提供官方可運行示例，兩個 ",[29,418,419],{},"rqt"," 包提供圖形化控制器管理和軌跡發送工具。後面幾個包不是寫普通機器人必需的，但對閲讀示例、測試硬件接口、學習 broadcaster 很有幫助。",[20,422,423],{},"每次打開新終端後，都需要 source ROS 2 環境：",[77,425,427],{"className":79,"code":426,"language":81,"meta":82,"style":82},"source /opt/ros/jazzy/setup.bash\n",[29,428,429],{"__ignoreMap":82},[86,430,431,434],{"class":88,"line":89},[86,432,433],{"class":343},"source",[86,435,436],{"class":304}," /opt/ros/jazzy/setup.bash\n",[15,438,439],{"id":439},"驗證安裝",[20,441,442],{},"可以查看基礎包：",[77,444,446],{"className":79,"code":445,"language":81,"meta":82,"style":82},"ros2 pkg list | grep -E '^(ros2_control|controller_manager|hardware_interface|controller_interface|ros2controlcli)$'\n",[29,447,448],{"__ignoreMap":82},[86,449,450,453,456,459,463,466,469],{"class":88,"line":89},[86,451,452],{"class":92},"ros2",[86,454,455],{"class":304}," pkg",[86,457,458],{"class":304}," list",[86,460,462],{"class":461},"szBVR"," |",[86,464,465],{"class":92}," grep",[86,467,468],{"class":343}," -E",[86,470,471],{"class":304}," '^(ros2_control|controller_manager|hardware_interface|controller_interface|ros2controlcli)$'\n",[20,473,474],{},"正常情況下可以看到：",[77,476,478],{"className":79,"code":477,"language":81,"meta":82,"style":82},"controller_interface\ncontroller_manager\nhardware_interface\nros2_control\nros2controlcli\n",[29,479,480,485,490,495,500],{"__ignoreMap":82},[86,481,482],{"class":88,"line":89},[86,483,484],{"class":92},"controller_interface\n",[86,486,487],{"class":88,"line":311},[86,488,489],{"class":92},"controller_manager\n",[86,491,492],{"class":88,"line":354},[86,493,494],{"class":92},"hardware_interface\n",[86,496,497],{"class":88,"line":362},[86,498,499],{"class":92},"ros2_control\n",[86,501,502],{"class":88,"line":370},[86,503,504],{"class":92},"ros2controlcli\n",[20,506,507],{},"可以查看常用控制器：",[77,509,511],{"className":79,"code":510,"language":81,"meta":82,"style":82},"ros2 pkg list | grep -E '^(joint_state_broadcaster|diff_drive_controller|joint_trajectory_controller|forward_command_controller|position_controllers|velocity_controllers|effort_controllers|pid_controller|mecanum_drive_controller|ackermann_steering_controller|tricycle_controller|omni_wheel_drive_controller)$'\n",[29,512,513],{"__ignoreMap":82},[86,514,515,517,519,521,523,525,527],{"class":88,"line":89},[86,516,452],{"class":92},[86,518,455],{"class":304},[86,520,458],{"class":304},[86,522,462],{"class":461},[86,524,465],{"class":92},[86,526,468],{"class":343},[86,528,529],{"class":304}," '^(joint_state_broadcaster|diff_drive_controller|joint_trajectory_controller|forward_command_controller|position_controllers|velocity_controllers|effort_controllers|pid_controller|mecanum_drive_controller|ackermann_steering_controller|tricycle_controller|omni_wheel_drive_controller)$'\n",[20,531,532],{},"常用輸出包括：",[77,534,536],{"className":79,"code":535,"language":81,"meta":82,"style":82},"ackermann_steering_controller\ndiff_drive_controller\neffort_controllers\nforward_command_controller\njoint_state_broadcaster\njoint_trajectory_controller\nmecanum_drive_controller\nomni_wheel_drive_controller\npid_controller\nposition_controllers\ntricycle_controller\nvelocity_controllers\n",[29,537,538,543,548,553,558,563,568,573,578,583,589,595],{"__ignoreMap":82},[86,539,540],{"class":88,"line":89},[86,541,542],{"class":92},"ackermann_steering_controller\n",[86,544,545],{"class":88,"line":311},[86,546,547],{"class":92},"diff_drive_controller\n",[86,549,550],{"class":88,"line":354},[86,551,552],{"class":92},"effort_controllers\n",[86,554,555],{"class":88,"line":362},[86,556,557],{"class":92},"forward_command_controller\n",[86,559,560],{"class":88,"line":370},[86,561,562],{"class":92},"joint_state_broadcaster\n",[86,564,565],{"class":88,"line":378},[86,566,567],{"class":92},"joint_trajectory_controller\n",[86,569,570],{"class":88,"line":386},[86,571,572],{"class":92},"mecanum_drive_controller\n",[86,574,575],{"class":88,"line":394},[86,576,577],{"class":92},"omni_wheel_drive_controller\n",[86,579,580],{"class":88,"line":402},[86,581,582],{"class":92},"pid_controller\n",[86,584,586],{"class":88,"line":585},10,[86,587,588],{"class":92},"position_controllers\n",[86,590,592],{"class":88,"line":591},11,[86,593,594],{"class":92},"tricycle_controller\n",[86,596,598],{"class":88,"line":597},12,[86,599,600],{"class":92},"velocity_controllers\n",[20,602,603],{},"這些包名第一次看會比較抽象，可以先按下面這樣理解：",[97,605,606,625],{},[100,607,608],{},[103,609,610,613,616,619,622],{},[106,611,612],{"align":108},"包名",[106,614,615],{"align":108},"中文理解",[106,617,618],{"align":108},"主要用途",[106,620,621],{"align":108},"典型輸入",[106,623,624],{"align":108},"典型輸出",[117,626,627,663,688,720,741,763,783,803,822,843,862,881],{},[103,628,629,634,637,647,660],{},[122,630,631],{"align":108},[29,632,633],{},"joint_state_broadcaster",[122,635,636],{"align":108},"關節狀態發佈器",[122,638,639,640,643,644],{"align":108},"讀取硬件 state interfaces，發佈 ",[29,641,642],{},"/joint_states"," 和 ",[29,645,646],{},"/dynamic_joint_states",[122,648,649,650,151,653,151,656,659],{"align":108},"硬件中的 ",[29,651,652],{},"position",[29,654,655],{},"velocity",[29,657,658],{},"effort"," 等狀態接口",[122,661,662],{"align":108},"ROS 話題，不寫硬件命令",[103,664,665,670,673,676,682],{},[122,666,667],{"align":108},[29,668,669],{},"diff_drive_controller",[122,671,672],{"align":108},"差速底盤控制器",[122,674,675],{"align":108},"控制兩側輪子差速運動的小車",[122,677,678,681],{"align":108},[29,679,680],{},"geometry_msgs/msg/TwistStamped"," 速度命令",[122,683,684,685,687],{"align":108},"左右輪 ",[29,686,655],{}," command interface，另發佈 odom",[103,689,690,695,698,701,711],{},[122,691,692],{"align":108},[29,693,694],{},"joint_trajectory_controller",[122,696,697],{"align":108},"關節軌跡控制器",[122,699,700],{"align":108},"執行機械臂、雲台、多關節機構的關節空間軌跡",[122,702,703,706,707,710],{"align":108},[29,704,705],{},"trajectory_msgs/msg/JointTrajectory"," 或 ",[29,708,709],{},"FollowJointTrajectory"," action",[122,712,713,714,151,716,706,718,219],{"align":108},"一組關節的 ",[29,715,652],{},[29,717,655],{},[29,719,658],{},[103,721,722,727,730,733,738],{},[122,723,724],{"align":108},[29,725,726],{},"forward_command_controller",[122,728,729],{"align":108},"命令轉發控制器",[122,731,732],{"align":108},"把收到的數組命令直接轉發到硬件接口，適合測試硬件",[122,734,735],{"align":108},[29,736,737],{},"std_msgs/msg/Float64MultiArray",[122,739,740],{"align":108},"指定 joint 的指定 command interface",[103,742,743,748,751,754,757],{},[122,744,745],{"align":108},[29,746,747],{},"position_controllers",[122,749,750],{"align":108},"位置命令組控制器",[122,752,753],{"align":108},"對多個關節直接下發位置目標",[122,755,756],{"align":108},"位置數組",[122,758,759,760,762],{"align":108},"多個 joint 的 ",[29,761,652],{}," command interface",[103,764,765,770,773,776,779],{},[122,766,767],{"align":108},[29,768,769],{},"velocity_controllers",[122,771,772],{"align":108},"速度命令組控制器",[122,774,775],{"align":108},"對多個關節直接下發速度目標",[122,777,778],{"align":108},"速度數組",[122,780,759,781,762],{"align":108},[29,782,655],{},[103,784,785,790,793,796,799],{},[122,786,787],{"align":108},[29,788,789],{},"effort_controllers",[122,791,792],{"align":108},"力/力矩命令組控制器",[122,794,795],{"align":108},"對多個關節直接下發 effort 目標",[122,797,798],{"align":108},"effort 數組",[122,800,759,801,762],{"align":108},[29,802,658],{},[103,804,805,810,813,816,819],{},[122,806,807],{"align":108},[29,808,809],{},"pid_controller",[122,811,812],{"align":108},"PID 控制器",[122,814,815],{"align":108},"在 ros2_control 鏈路中做 PID 閉環控制",[122,817,818],{"align":108},"reference interface 或控制器鏈輸入",[122,820,821],{"align":108},"PID 計算後的 command interface",[103,823,824,829,832,835,838],{},[122,825,826],{"align":108},[29,827,828],{},"mecanum_drive_controller",[122,830,831],{"align":108},"麥克納姆輪底盤控制器",[122,833,834],{"align":108},"控制四輪麥克納姆底盤，實現前後、橫移、旋轉",[122,836,837],{"align":108},"通常是底盤速度命令",[122,839,840,841,762],{"align":108},"四個麥克納姆輪的 ",[29,842,655],{},[103,844,845,850,853,856,859],{},[122,846,847],{"align":108},[29,848,849],{},"ackermann_steering_controller",[122,851,852],{"align":108},"阿克曼轉向控制器",[122,854,855],{"align":108},"控制汽車式前輪轉向、後輪驅動結構",[122,857,858],{"align":108},"底盤速度/轉向相關命令",[122,860,861],{"align":108},"轉向關節位置命令和驅動輪速度命令",[103,863,864,869,872,875,878],{},[122,865,866],{"align":108},[29,867,868],{},"tricycle_controller",[122,870,871],{"align":108},"三輪車控制器",[122,873,874],{"align":108},"控制一個轉向輪加驅動輪的三輪底盤",[122,876,877],{"align":108},"底盤速度命令",[122,879,880],{"align":108},"轉向關節和驅動輪命令",[103,882,883,888,891,894,896],{},[122,884,885],{"align":108},[29,886,887],{},"omni_wheel_drive_controller",[122,889,890],{"align":108},"全向輪底盤控制器",[122,892,893],{"align":108},"控制三個或更多全向輪組成的全向底盤",[122,895,877],{"align":108},[122,897,898,899,762],{"align":108},"多個全向輪的 ",[29,900,655],{},[20,902,903,904,906,907,151,909,151,911,913,914,151,916,151,918,643,920,922],{},"這裏有一個很重要的區別：",[29,905,633],{}," 是 broadcaster，它只發布狀態，不負責讓機器人動；",[29,908,669],{},[29,910,694],{},[29,912,828],{}," 這類才是 controller，會佔用 command interface 並向硬件寫命令。",[29,915,747],{},[29,917,769],{},[29,919,789],{},[29,921,726],{}," 更像“直接轉發命令”的工具，適合調試硬件接口，但不會替你計算複雜運動學。",[20,924,925],{},"如果安裝了 Gazebo Sim 和調試輔助包，還可以檢查：",[77,927,929],{"className":79,"code":928,"language":81,"meta":82,"style":82},"ros2 pkg list | grep -E '^(gz_ros2_control|gz_ros2_control_demos|rqt_controller_manager|rqt_joint_trajectory_controller|hardware_interface_testing|joint_state_topic_hardware_interface|battery_state_broadcaster)$'\n",[29,930,931],{"__ignoreMap":82},[86,932,933,935,937,939,941,943,945],{"class":88,"line":89},[86,934,452],{"class":92},[86,936,455],{"class":304},[86,938,458],{"class":304},[86,940,462],{"class":461},[86,942,465],{"class":92},[86,944,468],{"class":343},[86,946,947],{"class":304}," '^(gz_ros2_control|gz_ros2_control_demos|rqt_controller_manager|rqt_joint_trajectory_controller|hardware_interface_testing|joint_state_topic_hardware_interface|battery_state_broadcaster)$'\n",[20,949,950],{},"正常會看到：",[77,952,954],{"className":79,"code":953,"language":81,"meta":82,"style":82},"battery_state_broadcaster\ngz_ros2_control\ngz_ros2_control_demos\nhardware_interface_testing\njoint_state_topic_hardware_interface\nrqt_controller_manager\nrqt_joint_trajectory_controller\n",[29,955,956,961,966,971,976,981,986],{"__ignoreMap":82},[86,957,958],{"class":88,"line":89},[86,959,960],{"class":92},"battery_state_broadcaster\n",[86,962,963],{"class":88,"line":311},[86,964,965],{"class":92},"gz_ros2_control\n",[86,967,968],{"class":88,"line":354},[86,969,970],{"class":92},"gz_ros2_control_demos\n",[86,972,973],{"class":88,"line":362},[86,974,975],{"class":92},"hardware_interface_testing\n",[86,977,978],{"class":88,"line":370},[86,979,980],{"class":92},"joint_state_topic_hardware_interface\n",[86,982,983],{"class":88,"line":378},[86,984,985],{"class":92},"rqt_controller_manager\n",[86,987,988],{"class":88,"line":386},[86,989,990],{"class":92},"rqt_joint_trajectory_controller\n",[20,992,993,995],{},[29,994,71],{}," 包提供了四個常用可執行文件：",[77,997,999],{"className":79,"code":998,"language":81,"meta":82,"style":82},"ros2 pkg executables controller_manager\n",[29,1000,1001],{"__ignoreMap":82},[86,1002,1003,1005,1007,1010],{"class":88,"line":89},[86,1004,452],{"class":92},[86,1006,455],{"class":304},[86,1008,1009],{"class":304}," executables",[86,1011,1012],{"class":304}," controller_manager\n",[20,1014,1015],{},"輸出應包含：",[77,1017,1019],{"className":79,"code":1018,"language":81,"meta":82,"style":82},"controller_manager hardware_spawner\ncontroller_manager ros2_control_node\ncontroller_manager spawner\ncontroller_manager unspawner\n",[29,1020,1021,1028,1035,1042],{"__ignoreMap":82},[86,1022,1023,1025],{"class":88,"line":89},[86,1024,71],{"class":92},[86,1026,1027],{"class":304}," hardware_spawner\n",[86,1029,1030,1032],{"class":88,"line":311},[86,1031,71],{"class":92},[86,1033,1034],{"class":304}," ros2_control_node\n",[86,1036,1037,1039],{"class":88,"line":354},[86,1038,71],{"class":92},[86,1040,1041],{"class":304}," spawner\n",[86,1043,1044,1046],{"class":88,"line":362},[86,1045,71],{"class":92},[86,1047,1048],{"class":304}," unspawner\n",[20,1050,1051],{},"圖形化調試工具可以這樣啓動：",[77,1053,1055],{"className":79,"code":1054,"language":81,"meta":82,"style":82},"ros2 run rqt_controller_manager rqt_controller_manager\nros2 run rqt_joint_trajectory_controller rqt_joint_trajectory_controller\n",[29,1056,1057,1070],{"__ignoreMap":82},[86,1058,1059,1061,1064,1067],{"class":88,"line":89},[86,1060,452],{"class":92},[86,1062,1063],{"class":304}," run",[86,1065,1066],{"class":304}," rqt_controller_manager",[86,1068,1069],{"class":304}," rqt_controller_manager\n",[86,1071,1072,1074,1076,1079],{"class":88,"line":311},[86,1073,452],{"class":92},[86,1075,1063],{"class":304},[86,1077,1078],{"class":304}," rqt_joint_trajectory_controller",[86,1080,1081],{"class":304}," rqt_joint_trajectory_controller\n",[20,1083,1084,1087,1088,1091,1092,1094],{},[29,1085,1086],{},"rqt_controller_manager"," 適合查看、加載、配置、激活和停止控制器；",[29,1089,1090],{},"rqt_joint_trajectory_controller"," 適合給 ",[29,1093,694],{}," 手動發送簡單關節軌跡。",[10,1096,1098],{"id":1097},"ros2-control-核心概念","ROS2 Control 核心概念",[15,1100,1102],{"id":1101},"command-interface-和-state-interface","command interface 和 state interface",[20,1104,1105],{},"學習 ros2_control 最重要的是理解接口。",[34,1107,1108,1114],{},[37,1109,1110,1113],{},[23,1111,1112],{},"command interface"," ：控制器寫入的目標值。例如電機目標速度、關節目標位置、關節目標力矩。",[37,1115,1116,1119],{},[23,1117,1118],{},"state interface"," ：硬件讀回來的狀態值。例如編碼器位置、當前速度、力矩、電流、温度。",[20,1121,1122],{},"Jazzy 中標準接口名定義在：",[77,1124,1126],{"className":79,"code":1125,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/include/hardware_interface/hardware_interface/types/hardware_interface_type_values.hpp\n",[29,1127,1128],{"__ignoreMap":82},[86,1129,1130],{"class":88,"line":89},[86,1131,1125],{"class":92},[20,1133,1134],{},"常用接口如下：",[97,1136,1137,1147],{},[100,1138,1139],{},[103,1140,1141,1144],{},[106,1142,1143],{"align":108},"接口名",[106,1145,1146],{"align":108},"含義",[117,1148,1149,1158,1167,1176,1186,1196],{},[103,1150,1151,1155],{},[122,1152,1153],{"align":108},[29,1154,652],{},[122,1156,1157],{"align":108},"位置，常用於關節角度或直線位移",[103,1159,1160,1164],{},[122,1161,1162],{"align":108},[29,1163,655],{},[122,1165,1166],{"align":108},"速度，常用於輪速或關節速度",[103,1168,1169,1173],{},[122,1170,1171],{"align":108},[29,1172,658],{},[122,1174,1175],{"align":108},"力或力矩，常用於力矩控制",[103,1177,1178,1183],{},[122,1179,1180],{"align":108},[29,1181,1182],{},"acceleration",[122,1184,1185],{"align":108},"加速度",[103,1187,1188,1193],{},[122,1189,1190],{"align":108},[29,1191,1192],{},"current",[122,1194,1195],{"align":108},"電流",[103,1197,1198,1203],{},[122,1199,1200],{"align":108},[29,1201,1202],{},"temperature",[122,1204,1205],{"align":108},"温度",[20,1207,1208],{},"例如一個輪子關節可以這樣聲明：",[77,1210,1214],{"className":1211,"code":1212,"language":1213,"meta":82,"style":82},"language-xml shiki shiki-themes github-light github-dark","\u003Cjoint name=\"left_wheel_joint\">\n  \u003Ccommand_interface name=\"velocity\"/>\n  \u003Cstate_interface name=\"position\"/>\n  \u003Cstate_interface name=\"velocity\"/>\n\u003C/joint>\n","xml",[29,1215,1216,1238,1256,1272,1286],{"__ignoreMap":82},[86,1217,1218,1222,1226,1229,1232,1235],{"class":88,"line":89},[86,1219,1221],{"class":1220},"sVt8B","\u003C",[86,1223,1225],{"class":1224},"s9eBZ","joint",[86,1227,1228],{"class":92}," name",[86,1230,1231],{"class":1220},"=",[86,1233,1234],{"class":304},"\"left_wheel_joint\"",[86,1236,1237],{"class":1220},">\n",[86,1239,1240,1243,1246,1248,1250,1253],{"class":88,"line":311},[86,1241,1242],{"class":1220},"  \u003C",[86,1244,1245],{"class":1224},"command_interface",[86,1247,1228],{"class":92},[86,1249,1231],{"class":1220},[86,1251,1252],{"class":304},"\"velocity\"",[86,1254,1255],{"class":1220},"/>\n",[86,1257,1258,1260,1263,1265,1267,1270],{"class":88,"line":354},[86,1259,1242],{"class":1220},[86,1261,1262],{"class":1224},"state_interface",[86,1264,1228],{"class":92},[86,1266,1231],{"class":1220},[86,1268,1269],{"class":304},"\"position\"",[86,1271,1255],{"class":1220},[86,1273,1274,1276,1278,1280,1282,1284],{"class":88,"line":362},[86,1275,1242],{"class":1220},[86,1277,1262],{"class":1224},[86,1279,1228],{"class":92},[86,1281,1231],{"class":1220},[86,1283,1252],{"class":304},[86,1285,1255],{"class":1220},[86,1287,1288,1291,1293],{"class":88,"line":370},[86,1289,1290],{"class":1220},"\u003C/",[86,1292,1225],{"class":1224},[86,1294,1237],{"class":1220},[20,1296,1297,1298,1301,1302,643,1305,1307],{},"含義是：控制器可以給 ",[29,1299,1300],{},"left_wheel_joint/velocity"," 寫速度命令；硬件接口要能讀回 ",[29,1303,1304],{},"left_wheel_joint/position",[29,1306,1300],{},"。",[15,1309,1310],{"id":1310},"控制循環",[20,1312,1313,1315],{},[29,1314,71],{}," 的核心循環是：",[77,1317,1322],{"className":1318,"code":1320,"language":1321,"meta":82},[1319],"language-text","read() -> update() -> write()\n","text",[29,1323,1320],{"__ignoreMap":82},[20,1325,1326],{},"具體含義如下：",[97,1328,1329,1342],{},[100,1330,1331],{},[103,1332,1333,1336,1339],{},[106,1334,1335],{"align":108},"階段",[106,1337,1338],{"align":108},"執行者",[106,1340,1341],{"align":108},"作用",[117,1343,1344,1357,1370],{},[103,1345,1346,1351,1354],{},[122,1347,1348],{"align":108},[29,1349,1350],{},"read()",[122,1352,1353],{"align":108},"硬件接口",[122,1355,1356],{"align":108},"從電機、編碼器、傳感器或仿真器讀取狀態",[103,1358,1359,1364,1367],{},[122,1360,1361],{"align":108},[29,1362,1363],{},"update()",[122,1365,1366],{"align":108},"控制器",[122,1368,1369],{"align":108},"根據狀態和目標計算新的命令",[103,1371,1372,1377,1379],{},[122,1373,1374],{"align":108},[29,1375,1376],{},"write()",[122,1378,1353],{"align":108},[122,1380,1381],{"align":108},"把命令寫給電機驅動器、仿真器或底層硬件",[20,1383,1384],{},"例如差速底盤：",[34,1386,1387,1392,1402],{},[37,1388,1389,1391],{},[29,1390,1350],{}," 讀取左右輪編碼器，更新左右輪 position/velocity。",[37,1393,1394,1397,1398,1401],{},[29,1395,1396],{},"diff_drive_controller.update()"," 根據 ",[29,1399,1400],{},"/diff_drive_controller/cmd_vel"," 和輪子反饋計算左右輪目標速度，併發布里程計。",[37,1403,1404,1406],{},[29,1405,1376],{}," 把左右輪目標速度寫到電機驅動板。",[15,1408,1409],{"id":1409},"生命週期狀態",[20,1411,1412],{},"ros2_control 的控制器和硬件組件都有生命週期。常見狀態如下：",[97,1414,1415,1424],{},[100,1416,1417],{},[103,1418,1419,1422],{},[106,1420,1421],{"align":108},"狀態",[106,1423,1146],{"align":108},[117,1425,1426,1436,1446,1456],{},[103,1427,1428,1433],{},[122,1429,1430],{"align":108},[29,1431,1432],{},"unconfigured",[122,1434,1435],{"align":108},"已加載，但還沒有配置",[103,1437,1438,1443],{},[122,1439,1440],{"align":108},[29,1441,1442],{},"inactive",[122,1444,1445],{"align":108},"已配置，但不參與控制循環輸出",[103,1447,1448,1453],{},[122,1449,1450],{"align":108},[29,1451,1452],{},"active",[122,1454,1455],{"align":108},"已激活，參與控制循環",[103,1457,1458,1463],{},[122,1459,1460],{"align":108},[29,1461,1462],{},"finalized",[122,1464,1465],{"align":108},"已結束",[20,1467,1468],{},"常用流程是：",[77,1470,1473],{"className":1471,"code":1472,"language":1321,"meta":82},[1319],"load -> configure -> activate\n",[29,1474,1472],{"__ignoreMap":82},[20,1476,1477,1479,1480,706,1483,1307],{},[29,1478,154],{}," 默認會幫控制器完成加載、配置和激活。如果只想加載不激活，可以使用 ",[29,1481,1482],{},"--load-only",[29,1484,1485],{},"--inactive",[10,1487,1489],{"id":1488},"urdf-中的-ros2_control-標籤","URDF 中的 ros2_control 標籤",[15,1491,1492],{"id":1492},"基本結構",[20,1494,1495,1496,1499],{},"ros2_control 的硬件描述寫在 URDF 或 xacro 的 ",[29,1497,1498],{},"\u003Cros2_control>"," 標籤中。",[20,1501,1502],{},"最小結構如下：",[77,1504,1506],{"className":1211,"code":1505,"language":1213,"meta":82,"style":82},"\u003Cros2_control name=\"MyRobotSystem\" type=\"system\">\n  \u003Chardware>\n    \u003Cplugin>硬件插件名\u003C/plugin>\n  \u003C/hardware>\n\n  \u003Cjoint name=\"关节名\">\n    \u003Ccommand_interface name=\"命令接口名\"/>\n    \u003Cstate_interface name=\"状态接口名\"/>\n  \u003C/joint>\n\u003C/ros2_control>\n",[29,1507,1508,1531,1540,1555,1564,1570,1585,1600,1615,1623],{"__ignoreMap":82},[86,1509,1510,1512,1514,1516,1518,1521,1524,1526,1529],{"class":88,"line":89},[86,1511,1221],{"class":1220},[86,1513,31],{"class":1224},[86,1515,1228],{"class":92},[86,1517,1231],{"class":1220},[86,1519,1520],{"class":304},"\"MyRobotSystem\"",[86,1522,1523],{"class":92}," type",[86,1525,1231],{"class":1220},[86,1527,1528],{"class":304},"\"system\"",[86,1530,1237],{"class":1220},[86,1532,1533,1535,1538],{"class":88,"line":311},[86,1534,1242],{"class":1220},[86,1536,1537],{"class":1224},"hardware",[86,1539,1237],{"class":1220},[86,1541,1542,1545,1548,1551,1553],{"class":88,"line":354},[86,1543,1544],{"class":1220},"    \u003C",[86,1546,1547],{"class":1224},"plugin",[86,1549,1550],{"class":1220},">硬件插件名\u003C/",[86,1552,1547],{"class":1224},[86,1554,1237],{"class":1220},[86,1556,1557,1560,1562],{"class":88,"line":362},[86,1558,1559],{"class":1220},"  \u003C/",[86,1561,1537],{"class":1224},[86,1563,1237],{"class":1220},[86,1565,1566],{"class":88,"line":370},[86,1567,1569],{"emptyLinePlaceholder":1568},true,"\n",[86,1571,1572,1574,1576,1578,1580,1583],{"class":88,"line":378},[86,1573,1242],{"class":1220},[86,1575,1225],{"class":1224},[86,1577,1228],{"class":92},[86,1579,1231],{"class":1220},[86,1581,1582],{"class":304},"\"关节名\"",[86,1584,1237],{"class":1220},[86,1586,1587,1589,1591,1593,1595,1598],{"class":88,"line":386},[86,1588,1544],{"class":1220},[86,1590,1245],{"class":1224},[86,1592,1228],{"class":92},[86,1594,1231],{"class":1220},[86,1596,1597],{"class":304},"\"命令接口名\"",[86,1599,1255],{"class":1220},[86,1601,1602,1604,1606,1608,1610,1613],{"class":88,"line":394},[86,1603,1544],{"class":1220},[86,1605,1262],{"class":1224},[86,1607,1228],{"class":92},[86,1609,1231],{"class":1220},[86,1611,1612],{"class":304},"\"状态接口名\"",[86,1614,1255],{"class":1220},[86,1616,1617,1619,1621],{"class":88,"line":402},[86,1618,1559],{"class":1220},[86,1620,1225],{"class":1224},[86,1622,1237],{"class":1220},[86,1624,1625,1627,1629],{"class":88,"line":585},[86,1626,1290],{"class":1220},[86,1628,31],{"class":1224},[86,1630,1237],{"class":1220},[20,1632,1633,1636],{},[29,1634,1635],{},"type"," 有三種常用取值：",[97,1638,1639,1651],{},[100,1640,1641],{},[103,1642,1643,1645,1648],{},[106,1644,1635],{"align":108},[106,1646,1647],{"align":108},"對應 C++ 基類",[106,1649,1650],{"align":108},"適用對象",[117,1652,1653,1668,1683],{},[103,1654,1655,1660,1665],{},[122,1656,1657],{"align":108},[29,1658,1659],{},"system",[122,1661,1662],{"align":108},[29,1663,1664],{},"hardware_interface::SystemInterface",[122,1666,1667],{"align":108},"多關節機器人、底盤、機械臂",[103,1669,1670,1675,1680],{},[122,1671,1672],{"align":108},[29,1673,1674],{},"sensor",[122,1676,1677],{"align":108},[29,1678,1679],{},"hardware_interface::SensorInterface",[122,1681,1682],{"align":108},"只讀傳感器",[103,1684,1685,1690,1695],{},[122,1686,1687],{"align":108},[29,1688,1689],{},"actuator",[122,1691,1692],{"align":108},[29,1693,1694],{},"hardware_interface::ActuatorInterface",[122,1696,1697],{"align":108},"單個執行器",[15,1699,1701],{"id":1700},"使用-mock_components-測試","使用 mock_components 測試",[20,1703,1704,1705,1707],{},"Jazzy 的 ",[29,1706,177],{}," 包提供了一個測試用 mock 硬件插件：",[77,1709,1711],{"className":79,"code":1710,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/share/hardware_interface/mock_components_plugin_description.xml\n",[29,1712,1713],{"__ignoreMap":82},[86,1714,1715],{"class":88,"line":89},[86,1716,1710],{"class":92},[20,1718,1719],{},"插件名是：",[77,1721,1723],{"className":79,"code":1722,"language":81,"meta":82,"style":82},"mock_components/GenericSystem\n",[29,1724,1725],{"__ignoreMap":82},[86,1726,1727],{"class":88,"line":89},[86,1728,1722],{"class":92},[20,1730,1731],{},"可以用它先驗證控制器配置，而不用立即接真實硬件。",[20,1733,1734],{},"差速底盤示例：",[77,1736,1738],{"className":1211,"code":1737,"language":1213,"meta":82,"style":82},"\u003Cros2_control name=\"DiffBotSystem\" type=\"system\">\n  \u003Chardware>\n    \u003Cplugin>mock_components/GenericSystem\u003C/plugin>\n  \u003C/hardware>\n\n  \u003Cjoint name=\"left_wheel_joint\">\n    \u003Ccommand_interface name=\"velocity\"/>\n    \u003Cstate_interface name=\"position\"/>\n    \u003Cstate_interface name=\"velocity\"/>\n  \u003C/joint>\n\n  \u003Cjoint name=\"right_wheel_joint\">\n    \u003Ccommand_interface name=\"velocity\"/>\n    \u003Cstate_interface name=\"position\"/>\n    \u003Cstate_interface name=\"velocity\"/>\n  \u003C/joint>\n\u003C/ros2_control>\n",[29,1739,1740,1761,1769,1782,1790,1794,1808,1822,1836,1850,1858,1862,1877,1892,1907,1922,1931],{"__ignoreMap":82},[86,1741,1742,1744,1746,1748,1750,1753,1755,1757,1759],{"class":88,"line":89},[86,1743,1221],{"class":1220},[86,1745,31],{"class":1224},[86,1747,1228],{"class":92},[86,1749,1231],{"class":1220},[86,1751,1752],{"class":304},"\"DiffBotSystem\"",[86,1754,1523],{"class":92},[86,1756,1231],{"class":1220},[86,1758,1528],{"class":304},[86,1760,1237],{"class":1220},[86,1762,1763,1765,1767],{"class":88,"line":311},[86,1764,1242],{"class":1220},[86,1766,1537],{"class":1224},[86,1768,1237],{"class":1220},[86,1770,1771,1773,1775,1778,1780],{"class":88,"line":354},[86,1772,1544],{"class":1220},[86,1774,1547],{"class":1224},[86,1776,1777],{"class":1220},">mock_components/GenericSystem\u003C/",[86,1779,1547],{"class":1224},[86,1781,1237],{"class":1220},[86,1783,1784,1786,1788],{"class":88,"line":362},[86,1785,1559],{"class":1220},[86,1787,1537],{"class":1224},[86,1789,1237],{"class":1220},[86,1791,1792],{"class":88,"line":370},[86,1793,1569],{"emptyLinePlaceholder":1568},[86,1795,1796,1798,1800,1802,1804,1806],{"class":88,"line":378},[86,1797,1242],{"class":1220},[86,1799,1225],{"class":1224},[86,1801,1228],{"class":92},[86,1803,1231],{"class":1220},[86,1805,1234],{"class":304},[86,1807,1237],{"class":1220},[86,1809,1810,1812,1814,1816,1818,1820],{"class":88,"line":386},[86,1811,1544],{"class":1220},[86,1813,1245],{"class":1224},[86,1815,1228],{"class":92},[86,1817,1231],{"class":1220},[86,1819,1252],{"class":304},[86,1821,1255],{"class":1220},[86,1823,1824,1826,1828,1830,1832,1834],{"class":88,"line":394},[86,1825,1544],{"class":1220},[86,1827,1262],{"class":1224},[86,1829,1228],{"class":92},[86,1831,1231],{"class":1220},[86,1833,1269],{"class":304},[86,1835,1255],{"class":1220},[86,1837,1838,1840,1842,1844,1846,1848],{"class":88,"line":402},[86,1839,1544],{"class":1220},[86,1841,1262],{"class":1224},[86,1843,1228],{"class":92},[86,1845,1231],{"class":1220},[86,1847,1252],{"class":304},[86,1849,1255],{"class":1220},[86,1851,1852,1854,1856],{"class":88,"line":585},[86,1853,1559],{"class":1220},[86,1855,1225],{"class":1224},[86,1857,1237],{"class":1220},[86,1859,1860],{"class":88,"line":591},[86,1861,1569],{"emptyLinePlaceholder":1568},[86,1863,1864,1866,1868,1870,1872,1875],{"class":88,"line":597},[86,1865,1242],{"class":1220},[86,1867,1225],{"class":1224},[86,1869,1228],{"class":92},[86,1871,1231],{"class":1220},[86,1873,1874],{"class":304},"\"right_wheel_joint\"",[86,1876,1237],{"class":1220},[86,1878,1880,1882,1884,1886,1888,1890],{"class":88,"line":1879},13,[86,1881,1544],{"class":1220},[86,1883,1245],{"class":1224},[86,1885,1228],{"class":92},[86,1887,1231],{"class":1220},[86,1889,1252],{"class":304},[86,1891,1255],{"class":1220},[86,1893,1895,1897,1899,1901,1903,1905],{"class":88,"line":1894},14,[86,1896,1544],{"class":1220},[86,1898,1262],{"class":1224},[86,1900,1228],{"class":92},[86,1902,1231],{"class":1220},[86,1904,1269],{"class":304},[86,1906,1255],{"class":1220},[86,1908,1910,1912,1914,1916,1918,1920],{"class":88,"line":1909},15,[86,1911,1544],{"class":1220},[86,1913,1262],{"class":1224},[86,1915,1228],{"class":92},[86,1917,1231],{"class":1220},[86,1919,1252],{"class":304},[86,1921,1255],{"class":1220},[86,1923,1925,1927,1929],{"class":88,"line":1924},16,[86,1926,1559],{"class":1220},[86,1928,1225],{"class":1224},[86,1930,1237],{"class":1220},[86,1932,1934,1936,1938],{"class":88,"line":1933},17,[86,1935,1290],{"class":1220},[86,1937,31],{"class":1224},[86,1939,1237],{"class":1220},[20,1941,1942],{},"注意三點：",[34,1944,1945,1954,1957],{},[37,1946,1947,643,1950,1953],{},[29,1948,1949],{},"left_wheel_joint",[29,1951,1952],{},"right_wheel_joint"," 必須是 URDF 中真實存在的關節名。",[37,1955,1956],{},"控制器 YAML 裏的關節名必須和 URDF 完全一致。",[37,1958,1959,1961,1962,1964,1965,1967],{},[29,1960,669],{}," 輸出輪子 ",[29,1963,655],{}," 命令，所以輪關節必須有 ",[29,1966,655],{}," command interface。",[15,1969,1971,1974],{"id":1970},"param-傳硬件參數",[29,1972,1973],{},"\u003Cparam>"," 傳硬件參數",[20,1976,1977,1978,1981],{},"真實硬件通常需要串口名、波特率、CAN 設備名、減速比等參數，可以寫在 ",[29,1979,1980],{},"\u003Chardware>"," 中：",[77,1983,1985],{"className":1211,"code":1984,"language":1213,"meta":82,"style":82},"\u003Chardware>\n  \u003Cplugin>my_robot_hardware/MyRobotSystem\u003C/plugin>\n  \u003Cparam name=\"serial_port\">/dev/ttyUSB0\u003C/param>\n  \u003Cparam name=\"baud_rate\">115200\u003C/param>\n  \u003Cparam name=\"gear_ratio\">30.0\u003C/param>\n\u003C/hardware>\n",[29,1986,1987,1995,2008,2029,2049,2069],{"__ignoreMap":82},[86,1988,1989,1991,1993],{"class":88,"line":89},[86,1990,1221],{"class":1220},[86,1992,1537],{"class":1224},[86,1994,1237],{"class":1220},[86,1996,1997,1999,2001,2004,2006],{"class":88,"line":311},[86,1998,1242],{"class":1220},[86,2000,1547],{"class":1224},[86,2002,2003],{"class":1220},">my_robot_hardware/MyRobotSystem\u003C/",[86,2005,1547],{"class":1224},[86,2007,1237],{"class":1220},[86,2009,2010,2012,2015,2017,2019,2022,2025,2027],{"class":88,"line":354},[86,2011,1242],{"class":1220},[86,2013,2014],{"class":1224},"param",[86,2016,1228],{"class":92},[86,2018,1231],{"class":1220},[86,2020,2021],{"class":304},"\"serial_port\"",[86,2023,2024],{"class":1220},">/dev/ttyUSB0\u003C/",[86,2026,2014],{"class":1224},[86,2028,1237],{"class":1220},[86,2030,2031,2033,2035,2037,2039,2042,2045,2047],{"class":88,"line":362},[86,2032,1242],{"class":1220},[86,2034,2014],{"class":1224},[86,2036,1228],{"class":92},[86,2038,1231],{"class":1220},[86,2040,2041],{"class":304},"\"baud_rate\"",[86,2043,2044],{"class":1220},">115200\u003C/",[86,2046,2014],{"class":1224},[86,2048,1237],{"class":1220},[86,2050,2051,2053,2055,2057,2059,2062,2065,2067],{"class":88,"line":370},[86,2052,1242],{"class":1220},[86,2054,2014],{"class":1224},[86,2056,1228],{"class":92},[86,2058,1231],{"class":1220},[86,2060,2061],{"class":304},"\"gear_ratio\"",[86,2063,2064],{"class":1220},">30.0\u003C/",[86,2066,2014],{"class":1224},[86,2068,1237],{"class":1220},[86,2070,2071,2073,2075],{"class":88,"line":378},[86,2072,1290],{"class":1220},[86,2074,1537],{"class":1224},[86,2076,1237],{"class":1220},[20,2078,2079,2080,2083,2084,2087],{},"在自定義硬件接口的 ",[29,2081,2082],{},"on_init(const hardware_interface::HardwareInfo & info)"," 中，可以通過 ",[29,2085,2086],{},"info.hardware_parameters"," 讀取這些參數。",[10,2089,2091],{"id":2090},"controller-manager","Controller Manager",[15,2093,2095],{"id":2094},"controller_manager-配置","controller_manager 配置",[20,2097,2098,2100],{},[29,2099,71],{}," 是 ros2_control 的核心節點。它的默認可執行文件是：",[77,2102,2104],{"className":79,"code":2103,"language":81,"meta":82,"style":82},"ros2 run controller_manager ros2_control_node\n",[29,2105,2106],{"__ignoreMap":82},[86,2107,2108,2110,2112,2115],{"class":88,"line":89},[86,2109,452],{"class":92},[86,2111,1063],{"class":304},[86,2113,2114],{"class":304}," controller_manager",[86,2116,1034],{"class":304},[20,2118,2119,2120,2123],{},"在實際工程中通常通過 launch 啓動。控制器配置一般寫在 YAML 文件中，例如 ",[29,2121,2122],{},"config/controllers.yaml","：",[77,2125,2129],{"className":2126,"code":2127,"language":2128,"meta":82,"style":82},"language-yaml shiki shiki-themes github-light github-dark","controller_manager:\n  ros__parameters:\n    update_rate: 100\n\n    joint_state_broadcaster:\n      type: joint_state_broadcaster/JointStateBroadcaster\n\n    diff_drive_controller:\n      type: diff_drive_controller/DiffDriveController\n","yaml",[29,2130,2131,2138,2145,2156,2160,2167,2177,2181,2188],{"__ignoreMap":82},[86,2132,2133,2135],{"class":88,"line":89},[86,2134,71],{"class":1224},[86,2136,2137],{"class":1220},":\n",[86,2139,2140,2143],{"class":88,"line":311},[86,2141,2142],{"class":1224},"  ros__parameters",[86,2144,2137],{"class":1220},[86,2146,2147,2150,2153],{"class":88,"line":354},[86,2148,2149],{"class":1224},"    update_rate",[86,2151,2152],{"class":1220},": ",[86,2154,2155],{"class":343},"100\n",[86,2157,2158],{"class":88,"line":362},[86,2159,1569],{"emptyLinePlaceholder":1568},[86,2161,2162,2165],{"class":88,"line":370},[86,2163,2164],{"class":1224},"    joint_state_broadcaster",[86,2166,2137],{"class":1220},[86,2168,2169,2172,2174],{"class":88,"line":378},[86,2170,2171],{"class":1224},"      type",[86,2173,2152],{"class":1220},[86,2175,2176],{"class":304},"joint_state_broadcaster/JointStateBroadcaster\n",[86,2178,2179],{"class":88,"line":386},[86,2180,1569],{"emptyLinePlaceholder":1568},[86,2182,2183,2186],{"class":88,"line":394},[86,2184,2185],{"class":1224},"    diff_drive_controller",[86,2187,2137],{"class":1220},[86,2189,2190,2192,2194],{"class":88,"line":402},[86,2191,2171],{"class":1224},[86,2193,2152],{"class":1220},[86,2195,2196],{"class":304},"diff_drive_controller/DiffDriveController\n",[20,2198,2199,2201],{},[29,2200,71],{}," 常用參數：",[97,2203,2204,2216],{},[100,2205,2206],{},[103,2207,2208,2211,2214],{},[106,2209,2210],{"align":108},"參數",[106,2212,2213],{"align":108},"默認值",[106,2215,115],{"align":108},[117,2217,2218,2233,2248,2263,2278],{},[103,2219,2220,2225,2230],{},[122,2221,2222],{"align":108},[29,2223,2224],{},"update_rate",[122,2226,2227],{"align":108},[29,2228,2229],{},"100",[122,2231,2232],{"align":108},"控制循環頻率，單位 Hz",[103,2234,2235,2240,2245],{},[122,2236,2237],{"align":108},[29,2238,2239],{},"enforce_command_limits",[122,2241,2242],{"align":108},[29,2243,2244],{},"false",[122,2246,2247],{"align":108},"是否根據機器人描述中的關節限制約束命令",[103,2249,2250,2255,2260],{},[122,2251,2252],{"align":108},[29,2253,2254],{},"handle_exceptions",[122,2256,2257],{"align":108},[29,2258,2259],{},"true",[122,2261,2262],{"align":108},"是否捕獲控制器和硬件組件操作中的異常",[103,2264,2265,2270,2275],{},[122,2266,2267],{"align":108},[29,2268,2269],{},"hardware_components_initial_state.unconfigured",[122,2271,2272],{"align":108},[29,2273,2274],{},"[]",[122,2276,2277],{"align":108},"指定啓動後停留在 unconfigured 的硬件組件",[103,2279,2280,2285,2289],{},[122,2281,2282],{"align":108},[29,2283,2284],{},"hardware_components_initial_state.inactive",[122,2286,2287],{"align":108},[29,2288,2274],{},[122,2290,2291],{"align":108},"指定啓動後停留在 inactive 的硬件組件",[15,2293,2295],{"id":2294},"launch-啓動方式","launch 啓動方式",[20,2297,2298],{},"典型 launch 寫法如下：",[77,2300,2304],{"className":2301,"code":2302,"language":2303,"meta":82,"style":82},"language-python shiki shiki-themes github-light github-dark","from launch import LaunchDescription\nfrom launch_ros.actions import Node\n\n\ndef generate_launch_description():\n    control_node = Node(\n        package=\"controller_manager\",\n        executable=\"ros2_control_node\",\n        parameters=[\n            {\"robot_description\": \"\u003C这里传入完整 URDF 字符串>\"},\n            \"config/controllers.yaml\",\n        ],\n        output=\"both\",\n    )\n\n    return LaunchDescription([control_node])\n","python",[29,2305,2306,2320,2332,2336,2340,2351,2361,2375,2387,2397,2413,2420,2425,2437,2442,2446],{"__ignoreMap":82},[86,2307,2308,2311,2314,2317],{"class":88,"line":89},[86,2309,2310],{"class":461},"from",[86,2312,2313],{"class":1220}," launch ",[86,2315,2316],{"class":461},"import",[86,2318,2319],{"class":1220}," LaunchDescription\n",[86,2321,2322,2324,2327,2329],{"class":88,"line":311},[86,2323,2310],{"class":461},[86,2325,2326],{"class":1220}," launch_ros.actions ",[86,2328,2316],{"class":461},[86,2330,2331],{"class":1220}," Node\n",[86,2333,2334],{"class":88,"line":354},[86,2335,1569],{"emptyLinePlaceholder":1568},[86,2337,2338],{"class":88,"line":362},[86,2339,1569],{"emptyLinePlaceholder":1568},[86,2341,2342,2345,2348],{"class":88,"line":370},[86,2343,2344],{"class":461},"def",[86,2346,2347],{"class":92}," generate_launch_description",[86,2349,2350],{"class":1220},"():\n",[86,2352,2353,2356,2358],{"class":88,"line":378},[86,2354,2355],{"class":1220},"    control_node ",[86,2357,1231],{"class":461},[86,2359,2360],{"class":1220}," Node(\n",[86,2362,2363,2367,2369,2372],{"class":88,"line":386},[86,2364,2366],{"class":2365},"s4XuR","        package",[86,2368,1231],{"class":461},[86,2370,2371],{"class":304},"\"controller_manager\"",[86,2373,2374],{"class":1220},",\n",[86,2376,2377,2380,2382,2385],{"class":88,"line":394},[86,2378,2379],{"class":2365},"        executable",[86,2381,1231],{"class":461},[86,2383,2384],{"class":304},"\"ros2_control_node\"",[86,2386,2374],{"class":1220},[86,2388,2389,2392,2394],{"class":88,"line":402},[86,2390,2391],{"class":2365},"        parameters",[86,2393,1231],{"class":461},[86,2395,2396],{"class":1220},"[\n",[86,2398,2399,2402,2405,2407,2410],{"class":88,"line":585},[86,2400,2401],{"class":1220},"            {",[86,2403,2404],{"class":304},"\"robot_description\"",[86,2406,2152],{"class":1220},[86,2408,2409],{"class":304},"\"\u003C这里传入完整 URDF 字符串>\"",[86,2411,2412],{"class":1220},"},\n",[86,2414,2415,2418],{"class":88,"line":591},[86,2416,2417],{"class":304},"            \"config/controllers.yaml\"",[86,2419,2374],{"class":1220},[86,2421,2422],{"class":88,"line":597},[86,2423,2424],{"class":1220},"        ],\n",[86,2426,2427,2430,2432,2435],{"class":88,"line":1879},[86,2428,2429],{"class":2365},"        output",[86,2431,1231],{"class":461},[86,2433,2434],{"class":304},"\"both\"",[86,2436,2374],{"class":1220},[86,2438,2439],{"class":88,"line":1894},[86,2440,2441],{"class":1220},"    )\n",[86,2443,2444],{"class":88,"line":1909},[86,2445,1569],{"emptyLinePlaceholder":1568},[86,2447,2448,2451],{"class":88,"line":1924},[86,2449,2450],{"class":461},"    return",[86,2452,2453],{"class":1220}," LaunchDescription([control_node])\n",[20,2455,2456,2457,2460],{},"實際項目中，",[29,2458,2459],{},"robot_description"," 通常由 xacro 生成。一般流程是：",[77,2462,2465],{"className":2463,"code":2464,"language":1321,"meta":82},[1319],"xacro 文件 -> robot_description 参数 -> robot_state_publisher\n                                  -> ros2_control_node\n",[29,2466,2464],{"__ignoreMap":82},[10,2468,2469],{"id":2469},"控制器加載與調試命令",[15,2471,154],{"id":154},[20,2473,2474,2476],{},[29,2475,154],{}," 用於加載控制器。默認會完成加載、配置、激活三步：",[77,2478,2480],{"className":79,"code":2479,"language":81,"meta":82,"style":82},"ros2 run controller_manager spawner joint_state_broadcaster\nros2 run controller_manager spawner diff_drive_controller\n",[29,2481,2482,2496],{"__ignoreMap":82},[86,2483,2484,2486,2488,2490,2493],{"class":88,"line":89},[86,2485,452],{"class":92},[86,2487,1063],{"class":304},[86,2489,2114],{"class":304},[86,2491,2492],{"class":304}," spawner",[86,2494,2495],{"class":304}," joint_state_broadcaster\n",[86,2497,2498,2500,2502,2504,2506],{"class":88,"line":311},[86,2499,452],{"class":92},[86,2501,1063],{"class":304},[86,2503,2114],{"class":304},[86,2505,2492],{"class":304},[86,2507,2508],{"class":304}," diff_drive_controller\n",[20,2510,2511,2512,2515,2516,2519],{},"如果 controller manager 名字不是默認的 ",[29,2513,2514],{},"/controller_manager","，可以用 ",[29,2517,2518],{},"-c"," 指定：",[77,2521,2523],{"className":79,"code":2522,"language":81,"meta":82,"style":82},"ros2 run controller_manager spawner joint_state_broadcaster -c /controller_manager\n",[29,2524,2525],{"__ignoreMap":82},[86,2526,2527,2529,2531,2533,2535,2538,2541],{"class":88,"line":89},[86,2528,452],{"class":92},[86,2530,1063],{"class":304},[86,2532,2114],{"class":304},[86,2534,2492],{"class":304},[86,2536,2537],{"class":304}," joint_state_broadcaster",[86,2539,2540],{"class":343}," -c",[86,2542,2543],{"class":304}," /controller_manager\n",[20,2545,2546],{},"常用選項如下：",[97,2548,2549,2558],{},[100,2550,2551],{},[103,2552,2553,2556],{},[106,2554,2555],{"align":108},"選項",[106,2557,1341],{"align":108},[117,2559,2560,2573,2586,2595,2604,2614,2624,2634],{},[103,2561,2562,2570],{},[122,2563,2564,2566,2567],{"align":108},[29,2565,2518],{}," / ",[29,2568,2569],{},"--controller-manager",[122,2571,2572],{"align":108},"指定 controller manager 節點名",[103,2574,2575,2583],{},[122,2576,2577,2566,2580],{"align":108},[29,2578,2579],{},"-p",[29,2581,2582],{},"--param-file",[122,2584,2585],{"align":108},"給控制器加載參數文件",[103,2587,2588,2592],{},[122,2589,2590],{"align":108},[29,2591,1482],{},[122,2593,2594],{"align":108},"只加載，不配置、不激活",[103,2596,2597,2601],{},[122,2598,2599],{"align":108},[29,2600,1485],{},[122,2602,2603],{"align":108},"加載並配置，但不激活",[103,2605,2606,2611],{},[122,2607,2608],{"align":108},[29,2609,2610],{},"--activate-as-group",[122,2612,2613],{"align":108},"一組控制器一起激活，適合鏈式控制器",[103,2615,2616,2621],{},[122,2617,2618],{"align":108},[29,2619,2620],{},"--controller-manager-timeout",[122,2622,2623],{"align":108},"等待 controller manager 服務的超時時間",[103,2625,2626,2631],{},[122,2627,2628],{"align":108},[29,2629,2630],{},"--switch-timeout",[122,2632,2633],{"align":108},"等待控制器切換完成的超時時間",[103,2635,2636,2641],{},[122,2637,2638],{"align":108},[29,2639,2640],{},"--unload-on-kill",[122,2642,2643],{"align":108},"spawner 退出時卸載控制器",[15,2645,2646],{"id":2646},"hardware_spawner",[20,2648,2649,2651],{},[29,2650,2646],{}," 用於配置或激活硬件組件：",[77,2653,2655],{"className":79,"code":2654,"language":81,"meta":82,"style":82},"ros2 run controller_manager hardware_spawner DiffBotSystem --configure\nros2 run controller_manager hardware_spawner DiffBotSystem --activate\n",[29,2656,2657,2674],{"__ignoreMap":82},[86,2658,2659,2661,2663,2665,2668,2671],{"class":88,"line":89},[86,2660,452],{"class":92},[86,2662,1063],{"class":304},[86,2664,2114],{"class":304},[86,2666,2667],{"class":304}," hardware_spawner",[86,2669,2670],{"class":304}," DiffBotSystem",[86,2672,2673],{"class":343}," --configure\n",[86,2675,2676,2678,2680,2682,2684,2686],{"class":88,"line":311},[86,2677,452],{"class":92},[86,2679,1063],{"class":304},[86,2681,2114],{"class":304},[86,2683,2667],{"class":304},[86,2685,2670],{"class":304},[86,2687,2688],{"class":343}," --activate\n",[20,2690,2546],{},[97,2692,2693,2701],{},[100,2694,2695],{},[103,2696,2697,2699],{},[106,2698,2555],{"align":108},[106,2700,1341],{"align":108},[117,2702,2703,2713,2723],{},[103,2704,2705,2710],{},[122,2706,2707],{"align":108},[29,2708,2709],{},"--configure",[122,2711,2712],{"align":108},"把硬件組件配置到 inactive",[103,2714,2715,2720],{},[122,2716,2717],{"align":108},[29,2718,2719],{},"--activate",[122,2721,2722],{"align":108},"配置並激活硬件組件",[103,2724,2725,2731],{},[122,2726,2727,2566,2729],{"align":108},[29,2728,2518],{},[29,2730,2569],{},[122,2732,2572],{"align":108},[15,2734,2736],{"id":2735},"ros2-control-命令","ros2 control 命令",[20,2738,2739,2741,2742,2745],{},[29,2740,207],{}," 提供了 ",[29,2743,2744],{},"ros2 control"," 命令。",[20,2747,2748],{},"查看控制器：",[77,2750,2752],{"className":79,"code":2751,"language":81,"meta":82,"style":82},"ros2 control list_controllers\n",[29,2753,2754],{"__ignoreMap":82},[86,2755,2756,2758,2761],{"class":88,"line":89},[86,2757,452],{"class":92},[86,2759,2760],{"class":304}," control",[86,2762,2763],{"class":304}," list_controllers\n",[20,2765,2766],{},"查看控制器詳細接口：",[77,2768,2770],{"className":79,"code":2769,"language":81,"meta":82,"style":82},"ros2 control list_controllers --verbose\n",[29,2771,2772],{"__ignoreMap":82},[86,2773,2774,2776,2778,2781],{"class":88,"line":89},[86,2775,452],{"class":92},[86,2777,2760],{"class":304},[86,2779,2780],{"class":304}," list_controllers",[86,2782,2783],{"class":343}," --verbose\n",[20,2785,2786],{},"查看硬件組件：",[77,2788,2790],{"className":79,"code":2789,"language":81,"meta":82,"style":82},"ros2 control list_hardware_components\n",[29,2791,2792],{"__ignoreMap":82},[86,2793,2794,2796,2798],{"class":88,"line":89},[86,2795,452],{"class":92},[86,2797,2760],{"class":304},[86,2799,2800],{"class":304}," list_hardware_components\n",[20,2802,2803],{},"查看硬件接口：",[77,2805,2807],{"className":79,"code":2806,"language":81,"meta":82,"style":82},"ros2 control list_hardware_interfaces\nros2 control list_hardware_interfaces --verbose\n",[29,2808,2809,2818],{"__ignoreMap":82},[86,2810,2811,2813,2815],{"class":88,"line":89},[86,2812,452],{"class":92},[86,2814,2760],{"class":304},[86,2816,2817],{"class":304}," list_hardware_interfaces\n",[86,2819,2820,2822,2824,2827],{"class":88,"line":311},[86,2821,452],{"class":92},[86,2823,2760],{"class":304},[86,2825,2826],{"class":304}," list_hardware_interfaces",[86,2828,2783],{"class":343},[20,2830,2831],{},"查看可用控制器類型：",[77,2833,2835],{"className":79,"code":2834,"language":81,"meta":82,"style":82},"ros2 control list_controller_types\n",[29,2836,2837],{"__ignoreMap":82},[86,2838,2839,2841,2843],{"class":88,"line":89},[86,2840,452],{"class":92},[86,2842,2760],{"class":304},[86,2844,2845],{"class":304}," list_controller_types\n",[20,2847,2848],{},"切換控制器：",[77,2850,2852],{"className":79,"code":2851,"language":81,"meta":82,"style":82},"ros2 control switch_controllers --activate diff_drive_controller --deactivate old_controller\n",[29,2853,2854],{"__ignoreMap":82},[86,2855,2856,2858,2860,2863,2866,2869,2872],{"class":88,"line":89},[86,2857,452],{"class":92},[86,2859,2760],{"class":304},[86,2861,2862],{"class":304}," switch_controllers",[86,2864,2865],{"class":343}," --activate",[86,2867,2868],{"class":304}," diff_drive_controller",[86,2870,2871],{"class":343}," --deactivate",[86,2873,2874],{"class":304}," old_controller\n",[20,2876,2877],{},"卸載控制器：",[77,2879,2881],{"className":79,"code":2880,"language":81,"meta":82,"style":82},"ros2 control unload_controller diff_drive_controller\n",[29,2882,2883],{"__ignoreMap":82},[86,2884,2885,2887,2889,2892],{"class":88,"line":89},[86,2886,452],{"class":92},[86,2888,2760],{"class":304},[86,2890,2891],{"class":304}," unload_controller",[86,2893,2508],{"class":304},[20,2895,2896],{},"生成鏈式控制器圖：",[77,2898,2900],{"className":79,"code":2899,"language":81,"meta":82,"style":82},"ros2 control view_controller_chains\n",[29,2901,2902],{"__ignoreMap":82},[86,2903,2904,2906,2908],{"class":88,"line":89},[86,2905,452],{"class":92},[86,2907,2760],{"class":304},[86,2909,2910],{"class":304}," view_controller_chains\n",[10,2912,2913],{"id":2913},"常用控制器",[15,2915,2917],{"id":2916},"joint-state-broadcaster","Joint State Broadcaster",[20,2919,2920,2922],{},[29,2921,633],{}," 用於發佈機器人關節狀態。插件描述文件是：",[77,2924,2926],{"className":79,"code":2925,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/share/joint_state_broadcaster/joint_state_plugin.xml\n",[29,2927,2928],{"__ignoreMap":82},[86,2929,2930],{"class":88,"line":89},[86,2931,2925],{"class":92},[20,2933,1719],{},[77,2935,2936],{"className":79,"code":2176,"language":81,"meta":82,"style":82},[29,2937,2938],{"__ignoreMap":82},[86,2939,2940],{"class":88,"line":89},[86,2941,2176],{"class":92},[20,2943,2944],{},"它會讀取 state interfaces，併發布：",[97,2946,2947,2959],{},[100,2948,2949],{},[103,2950,2951,2954,2957],{},[106,2952,2953],{"align":108},"話題",[106,2955,2956],{"align":108},"類型",[106,2958,115],{"align":108},[117,2960,2961,2979],{},[103,2962,2963,2967,2972],{},[122,2964,2965],{"align":108},[29,2966,642],{},[122,2968,2969],{"align":108},[29,2970,2971],{},"sensor_msgs/msg/JointState",[122,2973,2974,2975,2978],{"align":108},"標準關節狀態，常被 ",[29,2976,2977],{},"robot_state_publisher"," 和 RViz 使用",[103,2980,2981,2985,2990],{},[122,2982,2983],{"align":108},[29,2984,646],{},[122,2986,2987],{"align":108},[29,2988,2989],{},"control_msgs/msg/DynamicJointState",[122,2991,2992],{"align":108},"發佈所有可用 state interfaces，包括自定義接口",[20,2994,2995],{},"常用配置：",[77,2997,2999],{"className":2126,"code":2998,"language":2128,"meta":82,"style":82},"joint_state_broadcaster:\n  ros__parameters:\n    use_local_topics: false\n    use_urdf_to_filter: true\n    publish_dynamic_joint_states: true\n",[29,3000,3001,3007,3013,3023,3033],{"__ignoreMap":82},[86,3002,3003,3005],{"class":88,"line":89},[86,3004,633],{"class":1224},[86,3006,2137],{"class":1220},[86,3008,3009,3011],{"class":88,"line":311},[86,3010,2142],{"class":1224},[86,3012,2137],{"class":1220},[86,3014,3015,3018,3020],{"class":88,"line":354},[86,3016,3017],{"class":1224},"    use_local_topics",[86,3019,2152],{"class":1220},[86,3021,3022],{"class":343},"false\n",[86,3024,3025,3028,3030],{"class":88,"line":362},[86,3026,3027],{"class":1224},"    use_urdf_to_filter",[86,3029,2152],{"class":1220},[86,3031,3032],{"class":343},"true\n",[86,3034,3035,3038,3040],{"class":88,"line":370},[86,3036,3037],{"class":1224},"    publish_dynamic_joint_states",[86,3039,2152],{"class":1220},[86,3041,3032],{"class":343},[20,3043,3044,3045,3047],{},"建議幾乎所有機器人都啓動 ",[29,3046,633],{},"，否則 RViz 中機器人模型通常不會動。",[15,3049,3051],{"id":3050},"diff-drive-controller","Diff Drive Controller",[20,3053,3054,3056],{},[29,3055,669],{}," 用於差速移動機器人。插件描述文件是：",[77,3058,3060],{"className":79,"code":3059,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/share/diff_drive_controller/diff_drive_plugin.xml\n",[29,3061,3062],{"__ignoreMap":82},[86,3063,3064],{"class":88,"line":89},[86,3065,3059],{"class":92},[20,3067,1719],{},[77,3069,3070],{"className":79,"code":2196,"language":81,"meta":82,"style":82},[29,3071,3072],{"__ignoreMap":82},[86,3073,3074],{"class":88,"line":89},[86,3075,2196],{"class":92},[20,3077,3078],{},"它的作用是：",[34,3080,3081,3084,3087,3093,3096],{},[37,3082,3083],{},"訂閲速度命令；",[37,3085,3086],{},"根據差速運動學計算左右輪目標速度；",[37,3088,3089,3090,3092],{},"向左右輪關節的 ",[29,3091,655],{}," command interface 寫命令；",[37,3094,3095],{},"根據左右輪反饋計算里程計；",[37,3097,3098,3099,3102],{},"可選發佈 ",[29,3100,3101],{},"odom -> base_link"," TF。",[20,3104,3105],{},"訂閲話題：",[97,3107,3108,3118],{},[100,3109,3110],{},[103,3111,3112,3114,3116],{},[106,3113,2953],{"align":108},[106,3115,2956],{"align":108},[106,3117,115],{"align":108},[117,3119,3120],{},[103,3121,3122,3127,3131],{},[122,3123,3124],{"align":108},[29,3125,3126],{},"~/cmd_vel",[122,3128,3129],{"align":108},[29,3130,680],{},[122,3132,3133,3134,643,3137],{"align":108},"速度命令，使用 ",[29,3135,3136],{},"linear.x",[29,3138,3139],{},"angular.z",[20,3141,3142,3143,3145],{},"如果控制器名是 ",[29,3144,669],{},"，默認命令話題一般是：",[77,3147,3149],{"className":79,"code":3148,"language":81,"meta":82,"style":82},"/diff_drive_controller/cmd_vel\n",[29,3150,3151],{"__ignoreMap":82},[86,3152,3153],{"class":88,"line":89},[86,3154,3148],{"class":92},[20,3156,3157],{},"發佈話題：",[97,3159,3160,3170],{},[100,3161,3162],{},[103,3163,3164,3166,3168],{},[106,3165,2953],{"align":108},[106,3167,2956],{"align":108},[106,3169,115],{"align":108},[117,3171,3172,3187,3206],{},[103,3173,3174,3179,3184],{},[122,3175,3176],{"align":108},[29,3177,3178],{},"~/odom",[122,3180,3181],{"align":108},[29,3182,3183],{},"nav_msgs/msg/Odometry",[122,3185,3186],{"align":108},"里程計",[103,3188,3189,3194,3199],{},[122,3190,3191],{"align":108},[29,3192,3193],{},"/tf",[122,3195,3196],{"align":108},[29,3197,3198],{},"tf2_msgs/msg/TFMessage",[122,3200,3201,3202,3205],{"align":108},"當 ",[29,3203,3204],{},"enable_odom_tf=true"," 時發佈",[103,3207,3208,3213,3217],{},[122,3209,3210],{"align":108},[29,3211,3212],{},"~/cmd_vel_out",[122,3214,3215],{"align":108},[29,3216,680],{},[122,3218,3201,3219,3222],{"align":108},[29,3220,3221],{},"publish_limited_velocity=true"," 時發佈限幅後的速度",[20,3224,3225],{},"最小配置：",[77,3227,3229],{"className":2126,"code":3228,"language":2128,"meta":82,"style":82},"diff_drive_controller:\n  ros__parameters:\n    left_wheel_names: [\"left_wheel_joint\"]\n    right_wheel_names: [\"right_wheel_joint\"]\n    wheel_separation: 0.40\n    wheel_radius: 0.05\n    odom_frame_id: odom\n    base_frame_id: base_link\n    position_feedback: true\n    open_loop: false\n    enable_odom_tf: true\n    publish_rate: 50.0\n",[29,3230,3231,3237,3243,3256,3267,3277,3287,3297,3307,3316,3325,3334],{"__ignoreMap":82},[86,3232,3233,3235],{"class":88,"line":89},[86,3234,669],{"class":1224},[86,3236,2137],{"class":1220},[86,3238,3239,3241],{"class":88,"line":311},[86,3240,2142],{"class":1224},[86,3242,2137],{"class":1220},[86,3244,3245,3248,3251,3253],{"class":88,"line":354},[86,3246,3247],{"class":1224},"    left_wheel_names",[86,3249,3250],{"class":1220},": [",[86,3252,1234],{"class":304},[86,3254,3255],{"class":1220},"]\n",[86,3257,3258,3261,3263,3265],{"class":88,"line":362},[86,3259,3260],{"class":1224},"    right_wheel_names",[86,3262,3250],{"class":1220},[86,3264,1874],{"class":304},[86,3266,3255],{"class":1220},[86,3268,3269,3272,3274],{"class":88,"line":370},[86,3270,3271],{"class":1224},"    wheel_separation",[86,3273,2152],{"class":1220},[86,3275,3276],{"class":343},"0.40\n",[86,3278,3279,3282,3284],{"class":88,"line":378},[86,3280,3281],{"class":1224},"    wheel_radius",[86,3283,2152],{"class":1220},[86,3285,3286],{"class":343},"0.05\n",[86,3288,3289,3292,3294],{"class":88,"line":386},[86,3290,3291],{"class":1224},"    odom_frame_id",[86,3293,2152],{"class":1220},[86,3295,3296],{"class":304},"odom\n",[86,3298,3299,3302,3304],{"class":88,"line":394},[86,3300,3301],{"class":1224},"    base_frame_id",[86,3303,2152],{"class":1220},[86,3305,3306],{"class":304},"base_link\n",[86,3308,3309,3312,3314],{"class":88,"line":402},[86,3310,3311],{"class":1224},"    position_feedback",[86,3313,2152],{"class":1220},[86,3315,3032],{"class":343},[86,3317,3318,3321,3323],{"class":88,"line":585},[86,3319,3320],{"class":1224},"    open_loop",[86,3322,2152],{"class":1220},[86,3324,3022],{"class":343},[86,3326,3327,3330,3332],{"class":88,"line":591},[86,3328,3329],{"class":1224},"    enable_odom_tf",[86,3331,2152],{"class":1220},[86,3333,3032],{"class":343},[86,3335,3336,3339,3341],{"class":88,"line":597},[86,3337,3338],{"class":1224},"    publish_rate",[86,3340,2152],{"class":1220},[86,3342,3343],{"class":343},"50.0\n",[20,3345,3346],{},"如果只是用 mock 硬件學習，可以先用開環：",[77,3348,3350],{"className":2126,"code":3349,"language":2128,"meta":82,"style":82},"diff_drive_controller:\n  ros__parameters:\n    left_wheel_names: [\"left_wheel_joint\"]\n    right_wheel_names: [\"right_wheel_joint\"]\n    wheel_separation: 0.40\n    wheel_radius: 0.05\n    position_feedback: false\n    open_loop: true\n    enable_odom_tf: true\n",[29,3351,3352,3358,3364,3374,3384,3392,3400,3408,3416],{"__ignoreMap":82},[86,3353,3354,3356],{"class":88,"line":89},[86,3355,669],{"class":1224},[86,3357,2137],{"class":1220},[86,3359,3360,3362],{"class":88,"line":311},[86,3361,2142],{"class":1224},[86,3363,2137],{"class":1220},[86,3365,3366,3368,3370,3372],{"class":88,"line":354},[86,3367,3247],{"class":1224},[86,3369,3250],{"class":1220},[86,3371,1234],{"class":304},[86,3373,3255],{"class":1220},[86,3375,3376,3378,3380,3382],{"class":88,"line":362},[86,3377,3260],{"class":1224},[86,3379,3250],{"class":1220},[86,3381,1874],{"class":304},[86,3383,3255],{"class":1220},[86,3385,3386,3388,3390],{"class":88,"line":370},[86,3387,3271],{"class":1224},[86,3389,2152],{"class":1220},[86,3391,3276],{"class":343},[86,3393,3394,3396,3398],{"class":88,"line":378},[86,3395,3281],{"class":1224},[86,3397,2152],{"class":1220},[86,3399,3286],{"class":343},[86,3401,3402,3404,3406],{"class":88,"line":386},[86,3403,3311],{"class":1224},[86,3405,2152],{"class":1220},[86,3407,3022],{"class":343},[86,3409,3410,3412,3414],{"class":88,"line":394},[86,3411,3320],{"class":1224},[86,3413,2152],{"class":1220},[86,3415,3032],{"class":343},[86,3417,3418,3420,3422],{"class":88,"line":402},[86,3419,3329],{"class":1224},[86,3421,2152],{"class":1220},[86,3423,3032],{"class":343},[20,3425,3426],{},"發送速度命令：",[77,3428,3430],{"className":79,"code":3429,"language":81,"meta":82,"style":82},"ros2 topic pub /diff_drive_controller/cmd_vel geometry_msgs/msg/TwistStamped \"{\n  header: {frame_id: base_link},\n  twist: {\n    linear: {x: 0.2, y: 0.0, z: 0.0},\n    angular: {x: 0.0, y: 0.0, z: 0.5}\n  }\n}\"\n",[29,3431,3432,3451,3456,3461,3466,3471,3476],{"__ignoreMap":82},[86,3433,3434,3436,3439,3442,3445,3448],{"class":88,"line":89},[86,3435,452],{"class":92},[86,3437,3438],{"class":304}," topic",[86,3440,3441],{"class":304}," pub",[86,3443,3444],{"class":304}," /diff_drive_controller/cmd_vel",[86,3446,3447],{"class":304}," geometry_msgs/msg/TwistStamped",[86,3449,3450],{"class":304}," \"{\n",[86,3452,3453],{"class":88,"line":311},[86,3454,3455],{"class":304},"  header: {frame_id: base_link},\n",[86,3457,3458],{"class":88,"line":354},[86,3459,3460],{"class":304},"  twist: {\n",[86,3462,3463],{"class":88,"line":362},[86,3464,3465],{"class":304},"    linear: {x: 0.2, y: 0.0, z: 0.0},\n",[86,3467,3468],{"class":88,"line":370},[86,3469,3470],{"class":304},"    angular: {x: 0.0, y: 0.0, z: 0.5}\n",[86,3472,3473],{"class":88,"line":378},[86,3474,3475],{"class":304},"  }\n",[86,3477,3478],{"class":88,"line":386},[86,3479,3480],{"class":304},"}\"\n",[20,3482,3483,3484,3486,3487,3490,3491,3494],{},"注意：Jazzy 的 ",[29,3485,669],{}," 使用 ",[29,3488,3489],{},"TwistStamped","。如果舊教程使用 ",[29,3492,3493],{},"geometry_msgs/msg/Twist","，在 Jazzy 中可能無法直接工作。",[15,3496,3498],{"id":3497},"joint-trajectory-controller","Joint Trajectory Controller",[20,3500,3501,3503],{},[29,3502,694],{}," 常用於機械臂、雲台、多關節機器人。插件描述文件是：",[77,3505,3507],{"className":79,"code":3506,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/share/joint_trajectory_controller/joint_trajectory_plugin.xml\n",[29,3508,3509],{"__ignoreMap":82},[86,3510,3511],{"class":88,"line":89},[86,3512,3506],{"class":92},[20,3514,1719],{},[77,3516,3518],{"className":79,"code":3517,"language":81,"meta":82,"style":82},"joint_trajectory_controller/JointTrajectoryController\n",[29,3519,3520],{"__ignoreMap":82},[86,3521,3522],{"class":88,"line":89},[86,3523,3517],{"class":92},[20,3525,3526],{},"它執行的是關節空間軌跡。常見輸入是：",[97,3528,3529,3540],{},[100,3530,3531],{},[103,3532,3533,3536,3538],{},[106,3534,3535],{"align":108},"輸入",[106,3537,2956],{"align":108},[106,3539,115],{"align":108},[117,3541,3542,3556],{},[103,3543,3544,3549,3553],{},[122,3545,3546],{"align":108},[29,3547,3548],{},"~/joint_trajectory",[122,3550,3551],{"align":108},[29,3552,705],{},[122,3554,3555],{"align":108},"軌跡話題",[103,3557,3558,3563,3568],{},[122,3559,3560],{"align":108},[29,3561,3562],{},"~/follow_joint_trajectory",[122,3564,3565],{"align":108},[29,3566,3567],{},"control_msgs/action/FollowJointTrajectory",[122,3569,3570],{"align":108},"標準軌跡 action，MoveIt2 常用",[20,3572,3573],{},"常見配置：",[77,3575,3577],{"className":2126,"code":3576,"language":2128,"meta":82,"style":82},"arm_controller:\n  ros__parameters:\n    joints:\n      - joint1\n      - joint2\n      - joint3\n    command_interfaces:\n      - position\n    state_interfaces:\n      - position\n      - velocity\n",[29,3578,3579,3586,3592,3599,3607,3614,3621,3628,3635,3642,3648],{"__ignoreMap":82},[86,3580,3581,3584],{"class":88,"line":89},[86,3582,3583],{"class":1224},"arm_controller",[86,3585,2137],{"class":1220},[86,3587,3588,3590],{"class":88,"line":311},[86,3589,2142],{"class":1224},[86,3591,2137],{"class":1220},[86,3593,3594,3597],{"class":88,"line":354},[86,3595,3596],{"class":1224},"    joints",[86,3598,2137],{"class":1220},[86,3600,3601,3604],{"class":88,"line":362},[86,3602,3603],{"class":1220},"      - ",[86,3605,3606],{"class":304},"joint1\n",[86,3608,3609,3611],{"class":88,"line":370},[86,3610,3603],{"class":1220},[86,3612,3613],{"class":304},"joint2\n",[86,3615,3616,3618],{"class":88,"line":378},[86,3617,3603],{"class":1220},[86,3619,3620],{"class":304},"joint3\n",[86,3622,3623,3626],{"class":88,"line":386},[86,3624,3625],{"class":1224},"    command_interfaces",[86,3627,2137],{"class":1220},[86,3629,3630,3632],{"class":88,"line":394},[86,3631,3603],{"class":1220},[86,3633,3634],{"class":304},"position\n",[86,3636,3637,3640],{"class":88,"line":402},[86,3638,3639],{"class":1224},"    state_interfaces",[86,3641,2137],{"class":1220},[86,3643,3644,3646],{"class":88,"line":585},[86,3645,3603],{"class":1220},[86,3647,3634],{"class":304},[86,3649,3650,3652],{"class":88,"line":591},[86,3651,3603],{"class":1220},[86,3653,3654],{"class":304},"velocity\n",[20,3656,3657],{},"URDF 中對應 joint 至少要有：",[77,3659,3661],{"className":1211,"code":3660,"language":1213,"meta":82,"style":82},"\u003Cjoint name=\"joint1\">\n  \u003Ccommand_interface name=\"position\"/>\n  \u003Cstate_interface name=\"position\"/>\n  \u003Cstate_interface name=\"velocity\"/>\n\u003C/joint>\n",[29,3662,3663,3678,3692,3706,3720],{"__ignoreMap":82},[86,3664,3665,3667,3669,3671,3673,3676],{"class":88,"line":89},[86,3666,1221],{"class":1220},[86,3668,1225],{"class":1224},[86,3670,1228],{"class":92},[86,3672,1231],{"class":1220},[86,3674,3675],{"class":304},"\"joint1\"",[86,3677,1237],{"class":1220},[86,3679,3680,3682,3684,3686,3688,3690],{"class":88,"line":311},[86,3681,1242],{"class":1220},[86,3683,1245],{"class":1224},[86,3685,1228],{"class":92},[86,3687,1231],{"class":1220},[86,3689,1269],{"class":304},[86,3691,1255],{"class":1220},[86,3693,3694,3696,3698,3700,3702,3704],{"class":88,"line":354},[86,3695,1242],{"class":1220},[86,3697,1262],{"class":1224},[86,3699,1228],{"class":92},[86,3701,1231],{"class":1220},[86,3703,1269],{"class":304},[86,3705,1255],{"class":1220},[86,3707,3708,3710,3712,3714,3716,3718],{"class":88,"line":362},[86,3709,1242],{"class":1220},[86,3711,1262],{"class":1224},[86,3713,1228],{"class":92},[86,3715,1231],{"class":1220},[86,3717,1252],{"class":304},[86,3719,1255],{"class":1220},[86,3721,3722,3724,3726],{"class":88,"line":370},[86,3723,1290],{"class":1220},[86,3725,1225],{"class":1224},[86,3727,1237],{"class":1220},[20,3729,3730,3731,3734,3735,3737,3738,3740],{},"如果機器人底層只接收速度命令，可以把 ",[29,3732,3733],{},"command_interfaces"," 改成 ",[29,3736,655],{},"。如果底層是力矩控制，可以使用 ",[29,3739,658],{},"，但這要求硬件接口和控制器參數都匹配。",[15,3742,3744],{"id":3743},"forward-command-controller","Forward Command Controller",[20,3746,3747,3749],{},[29,3748,726],{}," 是一個很適合初學者調試硬件接口的控制器。插件描述文件是：",[77,3751,3753],{"className":79,"code":3752,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/share/forward_command_controller/forward_command_plugin.xml\n",[29,3754,3755],{"__ignoreMap":82},[86,3756,3757],{"class":88,"line":89},[86,3758,3752],{"class":92},[20,3760,3761],{},"插件名包括：",[77,3763,3765],{"className":79,"code":3764,"language":81,"meta":82,"style":82},"forward_command_controller/ForwardCommandController\nforward_command_controller/MultiInterfaceForwardCommandController\n",[29,3766,3767,3772],{"__ignoreMap":82},[86,3768,3769],{"class":88,"line":89},[86,3770,3771],{"class":92},"forward_command_controller/ForwardCommandController\n",[86,3773,3774],{"class":88,"line":311},[86,3775,3776],{"class":92},"forward_command_controller/MultiInterfaceForwardCommandController\n",[20,3778,3779],{},"它不會做複雜控制，只是把收到的數組命令直接寫到指定 joint 的指定 command interface。",[20,3781,3782],{},"示例配置：",[77,3784,3786],{"className":2126,"code":3785,"language":2128,"meta":82,"style":82},"forward_velocity_controller:\n  ros__parameters:\n    joints:\n      - left_wheel_joint\n      - right_wheel_joint\n    interface_name: velocity\n",[29,3787,3788,3795,3801,3807,3814,3821],{"__ignoreMap":82},[86,3789,3790,3793],{"class":88,"line":89},[86,3791,3792],{"class":1224},"forward_velocity_controller",[86,3794,2137],{"class":1220},[86,3796,3797,3799],{"class":88,"line":311},[86,3798,2142],{"class":1224},[86,3800,2137],{"class":1220},[86,3802,3803,3805],{"class":88,"line":354},[86,3804,3596],{"class":1224},[86,3806,2137],{"class":1220},[86,3808,3809,3811],{"class":88,"line":362},[86,3810,3603],{"class":1220},[86,3812,3813],{"class":304},"left_wheel_joint\n",[86,3815,3816,3818],{"class":88,"line":370},[86,3817,3603],{"class":1220},[86,3819,3820],{"class":304},"right_wheel_joint\n",[86,3822,3823,3826,3828],{"class":88,"line":378},[86,3824,3825],{"class":1224},"    interface_name",[86,3827,2152],{"class":1220},[86,3829,3654],{"class":304},[20,3831,3832],{},"對於剛寫完硬件接口的人來説，推薦先用 forward controller 測試：",[34,3834,3835,3841,3846,3849],{},[37,3836,3837,3840],{},[29,3838,3839],{},"ros2 control list_hardware_interfaces"," 確認接口存在；",[37,3842,3843,3844,238],{},"啓動 ",[29,3845,3792],{},[37,3847,3848],{},"發送簡單速度數組；",[37,3850,3851,3852,3854],{},"看硬件接口的 ",[29,3853,1376],{}," 是否收到命令。",[15,3856,3858],{"id":3857},"ros2_controllers-中的其他控制器","ros2_controllers 中的其他控制器",[20,3860,3861,3862,3865],{},"安裝 ",[29,3863,3864],{},"ros-jazzy-ros2-controllers"," 後，還會帶很多控制器。常見類型如下：",[97,3867,3868,3883],{},[100,3869,3870],{},[103,3871,3872,3874,3877,3880],{},[106,3873,1366],{"align":108},[106,3875,3876],{"align":108},"插件名",[106,3878,3879],{"align":108},"用途",[106,3881,3882],{"align":108},"常見硬件接口",[117,3884,3885,3908,3935,3952,3969,3986,4006,4022,4041,4062,4080,4095,4113,4133,4149,4165,4181,4197],{},[103,3886,3887,3890,3895,3898],{},[122,3888,3889],{"align":108},"差速底盤",[122,3891,3892],{"align":108},[29,3893,3894],{},"diff_drive_controller/DiffDriveController",[122,3896,3897],{"align":108},"雙輪或兩側多輪差速機器人，負責從底盤速度計算左右輪速度，併發布里程計",[122,3899,3900,3901,3903,3904,3907],{"align":108},"輪關節 ",[29,3902,655],{}," 命令，輪關節 ",[29,3905,3906],{},"position/velocity"," 狀態",[103,3909,3910,3913,3918,3923],{},[122,3911,3912],{"align":108},"機械臂軌跡",[122,3914,3915],{"align":108},[29,3916,3917],{},"joint_trajectory_controller/JointTrajectoryController",[122,3919,3920,3921],{"align":108},"多關節軌跡執行，MoveIt2 常用它執行 ",[29,3922,709],{},[122,3924,3925,3926,151,3928,706,3930,3932,3933,3907],{"align":108},"關節 ",[29,3927,652],{},[29,3929,655],{},[29,3931,658],{}," 命令，通常讀取 ",[29,3934,3906],{},[103,3936,3937,3940,3945,3948],{},[122,3938,3939],{"align":108},"位置組控制",[122,3941,3942],{"align":108},[29,3943,3944],{},"position_controllers/JointGroupPositionController",[122,3946,3947],{"align":108},"直接把位置數組寫給多個關節，不做軌跡規劃和運動學",[122,3949,759,3950,219],{"align":108},[29,3951,652],{},[103,3953,3954,3957,3962,3965],{},[122,3955,3956],{"align":108},"速度組控制",[122,3958,3959],{"align":108},[29,3960,3961],{},"velocity_controllers/JointGroupVelocityController",[122,3963,3964],{"align":108},"直接把速度數組寫給多個關節，常用於輪子或速度型執行器測試",[122,3966,759,3967,219],{"align":108},[29,3968,655],{},[103,3970,3971,3974,3979,3982],{},[122,3972,3973],{"align":108},"力矩組控制",[122,3975,3976],{"align":108},[29,3977,3978],{},"effort_controllers/JointGroupEffortController",[122,3980,3981],{"align":108},"直接把 effort 數組寫給多個關節，適合力矩控制或簡單測試",[122,3983,759,3984,219],{"align":108},[29,3985,658],{},[103,3987,3988,3991,3996,3999],{},[122,3989,3990],{"align":108},"命令轉發",[122,3992,3993],{"align":108},[29,3994,3995],{},"forward_command_controller/ForwardCommandController",[122,3997,3998],{"align":108},"通用命令轉發器，可以選擇某一種 command interface",[122,4000,4001,4002,4005],{"align":108},"由 ",[29,4003,4004],{},"interface_name"," 參數決定",[103,4007,4008,4011,4016,4019],{},[122,4009,4010],{"align":108},"多接口命令轉發",[122,4012,4013],{"align":108},[29,4014,4015],{},"forward_command_controller/MultiInterfaceForwardCommandController",[122,4017,4018],{"align":108},"同時向多個接口轉發命令，適合複雜硬件調試",[122,4020,4021],{"align":108},"多個 joint 的多個 command interfaces",[103,4023,4024,4027,4032,4035],{},[122,4025,4026],{"align":108},"夾爪",[122,4028,4029],{"align":108},[29,4030,4031],{},"parallel_gripper_action_controller/GripperActionController",[122,4033,4034],{"align":108},"平行夾爪 action 控制，適合兩個手指聯動的夾爪",[122,4036,4037,4038,4040],{"align":108},"夾爪關節 ",[29,4039,652],{}," 或相關接口",[103,4042,4043,4046,4051,4054],{},[122,4044,4045],{"align":108},"Ackermann",[122,4047,4048],{"align":108},[29,4049,4050],{},"ackermann_steering_controller/AckermannSteeringController",[122,4052,4053],{"align":108},"汽車式阿克曼底盤，通常前輪轉向、後輪驅動",[122,4055,4056,4057,4059,4060,219],{"align":108},"轉向關節 ",[29,4058,652],{}," 命令，驅動輪 ",[29,4061,655],{},[103,4063,4064,4067,4072,4075],{},[122,4065,4066],{"align":108},"Mecanum",[122,4068,4069],{"align":108},[29,4070,4071],{},"mecanum_drive_controller/MecanumDriveController",[122,4073,4074],{"align":108},"四輪麥克納姆底盤，可前後、橫移、旋轉",[122,4076,4077,4078,219],{"align":108},"四個輪關節 ",[29,4079,655],{},[103,4081,4082,4085,4090,4093],{},[122,4083,4084],{"align":108},"三輪車",[122,4086,4087],{"align":108},[29,4088,4089],{},"tricycle_controller/TricycleController",[122,4091,4092],{"align":108},"三輪底盤，通常一個轉向輪加驅動輪",[122,4094,880],{"align":108},[103,4096,4097,4100,4105,4108],{},[122,4098,4099],{"align":108},"全向輪",[122,4101,4102],{"align":108},[29,4103,4104],{},"omni_wheel_drive_controller/OmniWheelDriveController",[122,4106,4107],{"align":108},"三個或更多全向輪底盤，支持平面全向運動",[122,4109,4110,4111,219],{"align":108},"多個輪關節 ",[29,4112,655],{},[103,4114,4115,4118,4123,4130],{},[122,4116,4117],{"align":108},"PID",[122,4119,4120],{"align":108},[29,4121,4122],{},"pid_controller/PidController",[122,4124,4125,4126,4129],{"align":108},"基於 ",[29,4127,4128],{},"control_toolbox"," 的 PID 控制器，可用於控制器鏈",[122,4131,4132],{"align":108},"讀取狀態/參考，輸出 PID 後的命令",[103,4134,4135,4138,4143,4146],{},[122,4136,4137],{"align":108},"IMU 發佈",[122,4139,4140],{"align":108},[29,4141,4142],{},"imu_sensor_broadcaster/IMUSensorBroadcaster",[122,4144,4145],{"align":108},"把硬件狀態接口發佈成 IMU 消息",[122,4147,4148],{"align":108},"讀取 IMU 相關 state interfaces",[103,4150,4151,4154,4159,4162],{},[122,4152,4153],{"align":108},"力/力矩發佈",[122,4155,4156],{"align":108},[29,4157,4158],{},"force_torque_sensor_broadcaster/ForceTorqueSensorBroadcaster",[122,4160,4161],{"align":108},"發佈六維力傳感器數據",[122,4163,4164],{"align":108},"讀取 force/torque state interfaces",[103,4166,4167,4170,4175,4178],{},[122,4168,4169],{"align":108},"距離傳感器發佈",[122,4171,4172],{"align":108},[29,4173,4174],{},"range_sensor_broadcaster/RangeSensorBroadcaster",[122,4176,4177],{"align":108},"發佈距離傳感器數據",[122,4179,4180],{"align":108},"讀取 range state interface",[103,4182,4183,4186,4191,4194],{},[122,4184,4185],{"align":108},"電池狀態發佈",[122,4187,4188],{"align":108},[29,4189,4190],{},"battery_state_broadcaster/BatteryStateBroadcaster",[122,4192,4193],{"align":108},"發佈電池電壓、電流、電量等狀態",[122,4195,4196],{"align":108},"讀取電池相關 state interfaces",[103,4198,4199,4202,4207,4210],{},[122,4200,4201],{"align":108},"通用狀態發佈",[122,4203,4204],{"align":108},[29,4205,4206],{},"state_interfaces_broadcaster/StateInterfacesBroadcaster",[122,4208,4209],{"align":108},"發佈指定 state interfaces，適合調試自定義狀態",[122,4211,4212],{"align":108},"讀取用户指定 state interfaces",[20,4214,4215,4216,151,4218,151,4220,706,4222,4224,4225,151,4227,151,4229,151,4231,706,4233,4235,4236,4238],{},"如果只是想確認硬件接口能不能收到命令，優先用 ",[29,4217,726],{},[29,4219,747],{},[29,4221,769],{},[29,4223,789],{},"。如果已經有明確運動學模型，再選擇 ",[29,4226,669],{},[29,4228,828],{},[29,4230,849],{},[29,4232,868],{},[29,4234,887],{},"。機械臂和多關節機構通常先從 ",[29,4237,694],{}," 學起。",[20,4240,4241],{},"選控制器時先問自己三個問題：",[34,4243,4244,4247,4250],{},[37,4245,4246],{},"我的機器人運動學是不是官方已經支持？",[37,4248,4249],{},"我的硬件接收的是 position、velocity 還是 effort？",[37,4251,4252],{},"我需要控制器自己算運動學，還是隻需要把命令轉發給硬件？",[20,4254,4255],{},"如果官方控制器能滿足需求，就優先使用官方控制器。只有在運動學特殊、控制律特殊、需要融合特殊傳感器時，才建議寫自定義控制器。",[10,4257,4259],{"id":4258},"一個差速底盤最小-bringup","一個差速底盤最小 Bringup",[15,4261,4263],{"id":4262},"controllersyaml","controllers.yaml",[77,4265,4267],{"className":2126,"code":4266,"language":2128,"meta":82,"style":82},"controller_manager:\n  ros__parameters:\n    update_rate: 100\n\n    joint_state_broadcaster:\n      type: joint_state_broadcaster/JointStateBroadcaster\n\n    diff_drive_controller:\n      type: diff_drive_controller/DiffDriveController\n\njoint_state_broadcaster:\n  ros__parameters:\n    use_local_topics: false\n    publish_dynamic_joint_states: true\n\ndiff_drive_controller:\n  ros__parameters:\n    left_wheel_names: [\"left_wheel_joint\"]\n    right_wheel_names: [\"right_wheel_joint\"]\n    wheel_separation: 0.40\n    wheel_radius: 0.05\n    odom_frame_id: odom\n    base_frame_id: base_link\n    position_feedback: false\n    open_loop: true\n    enable_odom_tf: true\n    publish_limited_velocity: true\n",[29,4268,4269,4275,4281,4289,4293,4299,4307,4311,4317,4325,4329,4335,4341,4349,4357,4361,4367,4373,4384,4395,4404,4413,4422,4431,4440,4449,4458],{"__ignoreMap":82},[86,4270,4271,4273],{"class":88,"line":89},[86,4272,71],{"class":1224},[86,4274,2137],{"class":1220},[86,4276,4277,4279],{"class":88,"line":311},[86,4278,2142],{"class":1224},[86,4280,2137],{"class":1220},[86,4282,4283,4285,4287],{"class":88,"line":354},[86,4284,2149],{"class":1224},[86,4286,2152],{"class":1220},[86,4288,2155],{"class":343},[86,4290,4291],{"class":88,"line":362},[86,4292,1569],{"emptyLinePlaceholder":1568},[86,4294,4295,4297],{"class":88,"line":370},[86,4296,2164],{"class":1224},[86,4298,2137],{"class":1220},[86,4300,4301,4303,4305],{"class":88,"line":378},[86,4302,2171],{"class":1224},[86,4304,2152],{"class":1220},[86,4306,2176],{"class":304},[86,4308,4309],{"class":88,"line":386},[86,4310,1569],{"emptyLinePlaceholder":1568},[86,4312,4313,4315],{"class":88,"line":394},[86,4314,2185],{"class":1224},[86,4316,2137],{"class":1220},[86,4318,4319,4321,4323],{"class":88,"line":402},[86,4320,2171],{"class":1224},[86,4322,2152],{"class":1220},[86,4324,2196],{"class":304},[86,4326,4327],{"class":88,"line":585},[86,4328,1569],{"emptyLinePlaceholder":1568},[86,4330,4331,4333],{"class":88,"line":591},[86,4332,633],{"class":1224},[86,4334,2137],{"class":1220},[86,4336,4337,4339],{"class":88,"line":597},[86,4338,2142],{"class":1224},[86,4340,2137],{"class":1220},[86,4342,4343,4345,4347],{"class":88,"line":1879},[86,4344,3017],{"class":1224},[86,4346,2152],{"class":1220},[86,4348,3022],{"class":343},[86,4350,4351,4353,4355],{"class":88,"line":1894},[86,4352,3037],{"class":1224},[86,4354,2152],{"class":1220},[86,4356,3032],{"class":343},[86,4358,4359],{"class":88,"line":1909},[86,4360,1569],{"emptyLinePlaceholder":1568},[86,4362,4363,4365],{"class":88,"line":1924},[86,4364,669],{"class":1224},[86,4366,2137],{"class":1220},[86,4368,4369,4371],{"class":88,"line":1933},[86,4370,2142],{"class":1224},[86,4372,2137],{"class":1220},[86,4374,4376,4378,4380,4382],{"class":88,"line":4375},18,[86,4377,3247],{"class":1224},[86,4379,3250],{"class":1220},[86,4381,1234],{"class":304},[86,4383,3255],{"class":1220},[86,4385,4387,4389,4391,4393],{"class":88,"line":4386},19,[86,4388,3260],{"class":1224},[86,4390,3250],{"class":1220},[86,4392,1874],{"class":304},[86,4394,3255],{"class":1220},[86,4396,4398,4400,4402],{"class":88,"line":4397},20,[86,4399,3271],{"class":1224},[86,4401,2152],{"class":1220},[86,4403,3276],{"class":343},[86,4405,4407,4409,4411],{"class":88,"line":4406},21,[86,4408,3281],{"class":1224},[86,4410,2152],{"class":1220},[86,4412,3286],{"class":343},[86,4414,4416,4418,4420],{"class":88,"line":4415},22,[86,4417,3291],{"class":1224},[86,4419,2152],{"class":1220},[86,4421,3296],{"class":304},[86,4423,4425,4427,4429],{"class":88,"line":4424},23,[86,4426,3301],{"class":1224},[86,4428,2152],{"class":1220},[86,4430,3306],{"class":304},[86,4432,4434,4436,4438],{"class":88,"line":4433},24,[86,4435,3311],{"class":1224},[86,4437,2152],{"class":1220},[86,4439,3022],{"class":343},[86,4441,4443,4445,4447],{"class":88,"line":4442},25,[86,4444,3320],{"class":1224},[86,4446,2152],{"class":1220},[86,4448,3032],{"class":343},[86,4450,4452,4454,4456],{"class":88,"line":4451},26,[86,4453,3329],{"class":1224},[86,4455,2152],{"class":1220},[86,4457,3032],{"class":343},[86,4459,4461,4464,4466],{"class":88,"line":4460},27,[86,4462,4463],{"class":1224},"    publish_limited_velocity",[86,4465,2152],{"class":1220},[86,4467,3032],{"class":343},[15,4469,4471],{"id":4470},"urdf-關鍵片段","URDF 關鍵片段",[77,4473,4474],{"className":1211,"code":1737,"language":1213,"meta":82,"style":82},[29,4475,4476,4496,4504,4516,4524,4528,4542,4556,4570,4584,4592,4596,4610,4624,4638,4652,4660],{"__ignoreMap":82},[86,4477,4478,4480,4482,4484,4486,4488,4490,4492,4494],{"class":88,"line":89},[86,4479,1221],{"class":1220},[86,4481,31],{"class":1224},[86,4483,1228],{"class":92},[86,4485,1231],{"class":1220},[86,4487,1752],{"class":304},[86,4489,1523],{"class":92},[86,4491,1231],{"class":1220},[86,4493,1528],{"class":304},[86,4495,1237],{"class":1220},[86,4497,4498,4500,4502],{"class":88,"line":311},[86,4499,1242],{"class":1220},[86,4501,1537],{"class":1224},[86,4503,1237],{"class":1220},[86,4505,4506,4508,4510,4512,4514],{"class":88,"line":354},[86,4507,1544],{"class":1220},[86,4509,1547],{"class":1224},[86,4511,1777],{"class":1220},[86,4513,1547],{"class":1224},[86,4515,1237],{"class":1220},[86,4517,4518,4520,4522],{"class":88,"line":362},[86,4519,1559],{"class":1220},[86,4521,1537],{"class":1224},[86,4523,1237],{"class":1220},[86,4525,4526],{"class":88,"line":370},[86,4527,1569],{"emptyLinePlaceholder":1568},[86,4529,4530,4532,4534,4536,4538,4540],{"class":88,"line":378},[86,4531,1242],{"class":1220},[86,4533,1225],{"class":1224},[86,4535,1228],{"class":92},[86,4537,1231],{"class":1220},[86,4539,1234],{"class":304},[86,4541,1237],{"class":1220},[86,4543,4544,4546,4548,4550,4552,4554],{"class":88,"line":386},[86,4545,1544],{"class":1220},[86,4547,1245],{"class":1224},[86,4549,1228],{"class":92},[86,4551,1231],{"class":1220},[86,4553,1252],{"class":304},[86,4555,1255],{"class":1220},[86,4557,4558,4560,4562,4564,4566,4568],{"class":88,"line":394},[86,4559,1544],{"class":1220},[86,4561,1262],{"class":1224},[86,4563,1228],{"class":92},[86,4565,1231],{"class":1220},[86,4567,1269],{"class":304},[86,4569,1255],{"class":1220},[86,4571,4572,4574,4576,4578,4580,4582],{"class":88,"line":402},[86,4573,1544],{"class":1220},[86,4575,1262],{"class":1224},[86,4577,1228],{"class":92},[86,4579,1231],{"class":1220},[86,4581,1252],{"class":304},[86,4583,1255],{"class":1220},[86,4585,4586,4588,4590],{"class":88,"line":585},[86,4587,1559],{"class":1220},[86,4589,1225],{"class":1224},[86,4591,1237],{"class":1220},[86,4593,4594],{"class":88,"line":591},[86,4595,1569],{"emptyLinePlaceholder":1568},[86,4597,4598,4600,4602,4604,4606,4608],{"class":88,"line":597},[86,4599,1242],{"class":1220},[86,4601,1225],{"class":1224},[86,4603,1228],{"class":92},[86,4605,1231],{"class":1220},[86,4607,1874],{"class":304},[86,4609,1237],{"class":1220},[86,4611,4612,4614,4616,4618,4620,4622],{"class":88,"line":1879},[86,4613,1544],{"class":1220},[86,4615,1245],{"class":1224},[86,4617,1228],{"class":92},[86,4619,1231],{"class":1220},[86,4621,1252],{"class":304},[86,4623,1255],{"class":1220},[86,4625,4626,4628,4630,4632,4634,4636],{"class":88,"line":1894},[86,4627,1544],{"class":1220},[86,4629,1262],{"class":1224},[86,4631,1228],{"class":92},[86,4633,1231],{"class":1220},[86,4635,1269],{"class":304},[86,4637,1255],{"class":1220},[86,4639,4640,4642,4644,4646,4648,4650],{"class":88,"line":1909},[86,4641,1544],{"class":1220},[86,4643,1262],{"class":1224},[86,4645,1228],{"class":92},[86,4647,1231],{"class":1220},[86,4649,1252],{"class":304},[86,4651,1255],{"class":1220},[86,4653,4654,4656,4658],{"class":88,"line":1924},[86,4655,1559],{"class":1220},[86,4657,1225],{"class":1224},[86,4659,1237],{"class":1220},[86,4661,4662,4664,4666],{"class":88,"line":1933},[86,4663,1290],{"class":1220},[86,4665,31],{"class":1224},[86,4667,1237],{"class":1220},[15,4669,4670],{"id":4670},"啓動順序",[20,4672,4673],{},"推薦順序如下：",[4675,4676,4677,4681,4685,4689,4693,4698],"ol",{},[37,4678,3843,4679,1307],{},[29,4680,2977],{},[37,4682,3843,4683,1307],{},[29,4684,150],{},[37,4686,3843,4687,1307],{},[29,4688,633],{},[37,4690,3843,4691,1307],{},[29,4692,669],{},[37,4694,4695,4696,1307],{},"發佈 ",[29,4697,1400],{},[37,4699,4700,4701,151,4703,643,4706,1307],{},"查看 ",[29,4702,642],{},[29,4704,4705],{},"/diff_drive_controller/odom",[29,4707,3193],{},[20,4709,4710],{},"調試命令如下：",[77,4712,4714],{"className":79,"code":4713,"language":81,"meta":82,"style":82},"ros2 control list_hardware_components\nros2 control list_hardware_interfaces\nros2 control list_controllers --verbose\nros2 topic echo /joint_states\nros2 topic echo /diff_drive_controller/odom\n",[29,4715,4716,4724,4732,4742,4754],{"__ignoreMap":82},[86,4717,4718,4720,4722],{"class":88,"line":89},[86,4719,452],{"class":92},[86,4721,2760],{"class":304},[86,4723,2800],{"class":304},[86,4725,4726,4728,4730],{"class":88,"line":311},[86,4727,452],{"class":92},[86,4729,2760],{"class":304},[86,4731,2817],{"class":304},[86,4733,4734,4736,4738,4740],{"class":88,"line":354},[86,4735,452],{"class":92},[86,4737,2760],{"class":304},[86,4739,2780],{"class":304},[86,4741,2783],{"class":343},[86,4743,4744,4746,4748,4751],{"class":88,"line":362},[86,4745,452],{"class":92},[86,4747,3438],{"class":304},[86,4749,4750],{"class":304}," echo",[86,4752,4753],{"class":304}," /joint_states\n",[86,4755,4756,4758,4760,4762],{"class":88,"line":370},[86,4757,452],{"class":92},[86,4759,3438],{"class":304},[86,4761,4750],{"class":304},[86,4763,4764],{"class":304}," /diff_drive_controller/odom\n",[10,4766,4767],{"id":4767},"自定義硬件接口",[15,4769,4770],{"id":4770},"什麼時候需要寫硬件接口",[20,4772,4773],{},"如果你的機器人使用真實電機驅動板，通常需要寫硬件接口。典型場景包括：",[34,4775,4776,4779,4782,4785,4788,4791],{},[37,4777,4778],{},"串口電機驅動板；",[37,4780,4781],{},"CAN 總線電機；",[37,4783,4784],{},"EtherCAT 驅動器；",[37,4786,4787],{},"自研 STM32 下位機；",[37,4789,4790],{},"自定義傳感器數據；",[37,4792,4793],{},"非 Gazebo 的自定義仿真器。",[20,4795,4796,4797,4800,4801,1307],{},"如果你只是想驗證控制器配置，可以先用 ",[29,4798,4799],{},"mock_components/GenericSystem","。如果你要接真機，就需要繼承 ",[29,4802,1664],{},[15,4804,4806],{"id":4805},"systeminterface-生命週期","SystemInterface 生命週期",[20,4808,4809],{},"Jazzy 中系統硬件接口的常用函數如下：",[97,4811,4812,4824],{},[100,4813,4814],{},[103,4815,4816,4819,4822],{},[106,4817,4818],{"align":108},"函數",[106,4820,4821],{"align":108},"調用時機",[106,4823,1341],{"align":108},[117,4825,4826,4839,4852,4865,4878,4891],{},[103,4827,4828,4833,4836],{},[122,4829,4830],{"align":108},[29,4831,4832],{},"on_init(const HardwareInfo & info)",[122,4834,4835],{"align":108},"加載硬件時",[122,4837,4838],{"align":108},"讀取 URDF 中的 joint、interface、param",[103,4840,4841,4846,4849],{},[122,4842,4843],{"align":108},[29,4844,4845],{},"on_configure(...)",[122,4847,4848],{"align":108},"配置硬件時",[122,4850,4851],{"align":108},"打開串口、初始化驅動板、分配資源",[103,4853,4854,4859,4862],{},[122,4855,4856],{"align":108},[29,4857,4858],{},"on_activate(...)",[122,4860,4861],{"align":108},"激活硬件時",[122,4863,4864],{"align":108},"使能電機，清零命令",[103,4866,4867,4872,4875],{},[122,4868,4869],{"align":108},[29,4870,4871],{},"on_deactivate(...)",[122,4873,4874],{"align":108},"停用硬件時",[122,4876,4877],{"align":108},"失能電機，停止輸出",[103,4879,4880,4885,4888],{},[122,4881,4882],{"align":108},[29,4883,4884],{},"read(const rclcpp::Time &, const rclcpp::Duration &)",[122,4886,4887],{"align":108},"每個控制週期",[122,4889,4890],{"align":108},"讀取硬件狀態並寫入 state interfaces",[103,4892,4893,4898,4900],{},[122,4894,4895],{"align":108},[29,4896,4897],{},"write(const rclcpp::Time &, const rclcpp::Duration &)",[122,4899,4887],{"align":108},[122,4901,4902],{"align":108},"讀取 command interfaces 並寫給硬件",[20,4904,4905,4906,4908,4909,4912],{},"在 Jazzy 中，如果接口已經在 URDF 的 ",[29,4907,1498],{}," 中聲明，",[29,4910,4911],{},"SystemInterface"," 默認會根據 URDF 創建接口。自定義硬件裏可以使用：",[77,4914,4918],{"className":4915,"code":4916,"language":4917,"meta":82,"style":82},"language-cpp shiki shiki-themes github-light github-dark","set_state(\"left_wheel_joint/position\", value);\nset_state(\"left_wheel_joint/velocity\", value);\ndouble cmd = get_command(\"left_wheel_joint/velocity\");\n","cpp",[29,4919,4920,4934,4945],{"__ignoreMap":82},[86,4921,4922,4925,4928,4931],{"class":88,"line":89},[86,4923,4924],{"class":92},"set_state",[86,4926,4927],{"class":1220},"(",[86,4929,4930],{"class":304},"\"left_wheel_joint/position\"",[86,4932,4933],{"class":1220},", value);\n",[86,4935,4936,4938,4940,4943],{"class":88,"line":311},[86,4937,4924],{"class":92},[86,4939,4927],{"class":1220},[86,4941,4942],{"class":304},"\"left_wheel_joint/velocity\"",[86,4944,4933],{"class":1220},[86,4946,4947,4950,4953,4955,4958,4960,4962],{"class":88,"line":354},[86,4948,4949],{"class":461},"double",[86,4951,4952],{"class":1220}," cmd ",[86,4954,1231],{"class":461},[86,4956,4957],{"class":92}," get_command",[86,4959,4927],{"class":1220},[86,4961,4942],{"class":304},[86,4963,4964],{"class":1220},");\n",[20,4966,4967,4968,1307],{},"這些函數來自 Jazzy 的 ",[29,4969,1664],{},[15,4971,4972],{"id":4972},"最小硬件接口框架",[20,4974,4975],{},"下面是一個用於差速底盤的硬件接口骨架。它展示結構，不包含具體串口協議：",[77,4977,4979],{"className":4915,"code":4978,"language":4917,"meta":82,"style":82},"#include \u003Cstring>\n\n#include \"hardware_interface/system_interface.hpp\"\n#include \"hardware_interface/types/hardware_interface_return_values.hpp\"\n#include \"rclcpp/rclcpp.hpp\"\n\nnamespace my_robot_hardware\n{\n\nclass MyDiffBotSystem : public hardware_interface::SystemInterface\n{\npublic:\n  hardware_interface::CallbackReturn on_init(const hardware_interface::HardwareInfo & info) override\n  {\n    if (hardware_interface::SystemInterface::on_init(info) !=\n      hardware_interface::CallbackReturn::SUCCESS)\n    {\n      return hardware_interface::CallbackReturn::ERROR;\n    }\n\n    serial_port_ = info_.hardware_parameters.at(\"serial_port\");\n    return hardware_interface::CallbackReturn::SUCCESS;\n  }\n\n  hardware_interface::CallbackReturn on_configure(const rclcpp_lifecycle::State &) override\n  {\n    // 在这里打开串口、CAN 或网络连接。\n    return hardware_interface::CallbackReturn::SUCCESS;\n  }\n\n  hardware_interface::CallbackReturn on_activate(const rclcpp_lifecycle::State &) override\n  {\n    set_command(\"left_wheel_joint/velocity\", 0.0);\n    set_command(\"right_wheel_joint/velocity\", 0.0);\n    return hardware_interface::CallbackReturn::SUCCESS;\n  }\n\n  hardware_interface::return_type read(\n    const rclcpp::Time &, const rclcpp::Duration &) override\n  {\n    // 从编码器读取真实位置和速度。\n    set_state(\"left_wheel_joint/position\", left_position_);\n    set_state(\"left_wheel_joint/velocity\", left_velocity_);\n    set_state(\"right_wheel_joint/position\", right_position_);\n    set_state(\"right_wheel_joint/velocity\", right_velocity_);\n    return hardware_interface::return_type::OK;\n  }\n\n  hardware_interface::return_type write(\n    const rclcpp::Time &, const rclcpp::Duration &) override\n  {\n    const double left_cmd = get_command(\"left_wheel_joint/velocity\");\n    const double right_cmd = get_command(\"right_wheel_joint/velocity\");\n\n    // 把 left_cmd 和 right_cmd 写给电机驱动板。\n    return hardware_interface::return_type::OK;\n  }\n\nprivate:\n  std::string serial_port_;\n  double left_position_ = 0.0;\n  double left_velocity_ = 0.0;\n  double right_position_ = 0.0;\n  double right_velocity_ = 0.0;\n};\n\n}  // namespace my_robot_hardware\n",[29,4980,4981,4989,4993,5000,5007,5014,5018,5026,5031,5035,5058,5062,5067,5104,5109,5134,5146,5151,5165,5170,5174,5193,5206,5210,5214,5243,5247,5253,5266,5271,5276,5304,5309,5327,5343,5356,5361,5366,5382,5415,5420,5426,5439,5451,5464,5476,5490,5495,5500,5514,5543,5548,5569,5589,5594,5600,5613,5618,5623,5629,5638,5655,5669,5683,5697,5703,5708],{"__ignoreMap":82},[86,4982,4983,4986],{"class":88,"line":89},[86,4984,4985],{"class":461},"#include",[86,4987,4988],{"class":304}," \u003Cstring>\n",[86,4990,4991],{"class":88,"line":311},[86,4992,1569],{"emptyLinePlaceholder":1568},[86,4994,4995,4997],{"class":88,"line":354},[86,4996,4985],{"class":461},[86,4998,4999],{"class":304}," \"hardware_interface/system_interface.hpp\"\n",[86,5001,5002,5004],{"class":88,"line":362},[86,5003,4985],{"class":461},[86,5005,5006],{"class":304}," \"hardware_interface/types/hardware_interface_return_values.hpp\"\n",[86,5008,5009,5011],{"class":88,"line":370},[86,5010,4985],{"class":461},[86,5012,5013],{"class":304}," \"rclcpp/rclcpp.hpp\"\n",[86,5015,5016],{"class":88,"line":378},[86,5017,1569],{"emptyLinePlaceholder":1568},[86,5019,5020,5023],{"class":88,"line":386},[86,5021,5022],{"class":461},"namespace",[86,5024,5025],{"class":92}," my_robot_hardware\n",[86,5027,5028],{"class":88,"line":394},[86,5029,5030],{"class":1220},"{\n",[86,5032,5033],{"class":88,"line":402},[86,5034,1569],{"emptyLinePlaceholder":1568},[86,5036,5037,5040,5043,5046,5049,5052,5055],{"class":88,"line":585},[86,5038,5039],{"class":461},"class",[86,5041,5042],{"class":92}," MyDiffBotSystem",[86,5044,5045],{"class":1220}," : ",[86,5047,5048],{"class":461},"public",[86,5050,5051],{"class":92}," hardware_interface",[86,5053,5054],{"class":1220},"::",[86,5056,5057],{"class":92},"SystemInterface\n",[86,5059,5060],{"class":88,"line":591},[86,5061,5030],{"class":1220},[86,5063,5064],{"class":88,"line":597},[86,5065,5066],{"class":461},"public:\n",[86,5068,5069,5072,5074,5077,5080,5082,5085,5087,5089,5092,5095,5098,5101],{"class":88,"line":1879},[86,5070,5071],{"class":92},"  hardware_interface",[86,5073,5054],{"class":1220},[86,5075,5076],{"class":92},"CallbackReturn",[86,5078,5079],{"class":92}," on_init",[86,5081,4927],{"class":1220},[86,5083,5084],{"class":461},"const",[86,5086,5051],{"class":92},[86,5088,5054],{"class":1220},[86,5090,5091],{"class":92},"HardwareInfo",[86,5093,5094],{"class":461}," &",[86,5096,5097],{"class":2365}," info",[86,5099,5100],{"class":1220},") ",[86,5102,5103],{"class":461},"override\n",[86,5105,5106],{"class":88,"line":1894},[86,5107,5108],{"class":1220},"  {\n",[86,5110,5111,5114,5117,5119,5121,5123,5125,5128,5131],{"class":88,"line":1909},[86,5112,5113],{"class":461},"    if",[86,5115,5116],{"class":1220}," (",[86,5118,177],{"class":92},[86,5120,5054],{"class":1220},[86,5122,4911],{"class":92},[86,5124,5054],{"class":1220},[86,5126,5127],{"class":92},"on_init",[86,5129,5130],{"class":1220},"(info) ",[86,5132,5133],{"class":461},"!=\n",[86,5135,5136,5139,5141,5143],{"class":88,"line":1924},[86,5137,5138],{"class":92},"      hardware_interface",[86,5140,5054],{"class":1220},[86,5142,5076],{"class":92},[86,5144,5145],{"class":1220},"::SUCCESS)\n",[86,5147,5148],{"class":88,"line":1933},[86,5149,5150],{"class":1220},"    {\n",[86,5152,5153,5156,5158,5160,5162],{"class":88,"line":4375},[86,5154,5155],{"class":461},"      return",[86,5157,5051],{"class":92},[86,5159,5054],{"class":1220},[86,5161,5076],{"class":92},[86,5163,5164],{"class":1220},"::ERROR;\n",[86,5166,5167],{"class":88,"line":4386},[86,5168,5169],{"class":1220},"    }\n",[86,5171,5172],{"class":88,"line":4397},[86,5173,1569],{"emptyLinePlaceholder":1568},[86,5175,5176,5179,5181,5184,5187,5189,5191],{"class":88,"line":4406},[86,5177,5178],{"class":1220},"    serial_port_ ",[86,5180,1231],{"class":461},[86,5182,5183],{"class":1220}," info_.hardware_parameters.",[86,5185,5186],{"class":92},"at",[86,5188,4927],{"class":1220},[86,5190,2021],{"class":304},[86,5192,4964],{"class":1220},[86,5194,5195,5197,5199,5201,5203],{"class":88,"line":4415},[86,5196,2450],{"class":461},[86,5198,5051],{"class":92},[86,5200,5054],{"class":1220},[86,5202,5076],{"class":92},[86,5204,5205],{"class":1220},"::SUCCESS;\n",[86,5207,5208],{"class":88,"line":4424},[86,5209,3475],{"class":1220},[86,5211,5212],{"class":88,"line":4433},[86,5213,1569],{"emptyLinePlaceholder":1568},[86,5215,5216,5218,5220,5222,5225,5227,5229,5232,5234,5237,5239,5241],{"class":88,"line":4442},[86,5217,5071],{"class":92},[86,5219,5054],{"class":1220},[86,5221,5076],{"class":92},[86,5223,5224],{"class":92}," on_configure",[86,5226,4927],{"class":1220},[86,5228,5084],{"class":461},[86,5230,5231],{"class":92}," rclcpp_lifecycle",[86,5233,5054],{"class":1220},[86,5235,5236],{"class":92},"State",[86,5238,5094],{"class":461},[86,5240,5100],{"class":1220},[86,5242,5103],{"class":461},[86,5244,5245],{"class":88,"line":4451},[86,5246,5108],{"class":1220},[86,5248,5249],{"class":88,"line":4460},[86,5250,5252],{"class":5251},"sJ8bj","    // 在这里打开串口、CAN 或网络连接。\n",[86,5254,5256,5258,5260,5262,5264],{"class":88,"line":5255},28,[86,5257,2450],{"class":461},[86,5259,5051],{"class":92},[86,5261,5054],{"class":1220},[86,5263,5076],{"class":92},[86,5265,5205],{"class":1220},[86,5267,5269],{"class":88,"line":5268},29,[86,5270,3475],{"class":1220},[86,5272,5274],{"class":88,"line":5273},30,[86,5275,1569],{"emptyLinePlaceholder":1568},[86,5277,5279,5281,5283,5285,5288,5290,5292,5294,5296,5298,5300,5302],{"class":88,"line":5278},31,[86,5280,5071],{"class":92},[86,5282,5054],{"class":1220},[86,5284,5076],{"class":92},[86,5286,5287],{"class":92}," on_activate",[86,5289,4927],{"class":1220},[86,5291,5084],{"class":461},[86,5293,5231],{"class":92},[86,5295,5054],{"class":1220},[86,5297,5236],{"class":92},[86,5299,5094],{"class":461},[86,5301,5100],{"class":1220},[86,5303,5103],{"class":461},[86,5305,5307],{"class":88,"line":5306},32,[86,5308,5108],{"class":1220},[86,5310,5312,5315,5317,5319,5322,5325],{"class":88,"line":5311},33,[86,5313,5314],{"class":92},"    set_command",[86,5316,4927],{"class":1220},[86,5318,4942],{"class":304},[86,5320,5321],{"class":1220},", ",[86,5323,5324],{"class":343},"0.0",[86,5326,4964],{"class":1220},[86,5328,5330,5332,5334,5337,5339,5341],{"class":88,"line":5329},34,[86,5331,5314],{"class":92},[86,5333,4927],{"class":1220},[86,5335,5336],{"class":304},"\"right_wheel_joint/velocity\"",[86,5338,5321],{"class":1220},[86,5340,5324],{"class":343},[86,5342,4964],{"class":1220},[86,5344,5346,5348,5350,5352,5354],{"class":88,"line":5345},35,[86,5347,2450],{"class":461},[86,5349,5051],{"class":92},[86,5351,5054],{"class":1220},[86,5353,5076],{"class":92},[86,5355,5205],{"class":1220},[86,5357,5359],{"class":88,"line":5358},36,[86,5360,3475],{"class":1220},[86,5362,5364],{"class":88,"line":5363},37,[86,5365,1569],{"emptyLinePlaceholder":1568},[86,5367,5369,5371,5373,5376,5379],{"class":88,"line":5368},38,[86,5370,5071],{"class":92},[86,5372,5054],{"class":1220},[86,5374,5375],{"class":92},"return_type",[86,5377,5378],{"class":92}," read",[86,5380,5381],{"class":1220},"(\n",[86,5383,5385,5388,5391,5393,5396,5398,5400,5402,5404,5406,5409,5411,5413],{"class":88,"line":5384},39,[86,5386,5387],{"class":461},"    const",[86,5389,5390],{"class":92}," rclcpp",[86,5392,5054],{"class":1220},[86,5394,5395],{"class":92},"Time",[86,5397,5094],{"class":461},[86,5399,5321],{"class":1220},[86,5401,5084],{"class":461},[86,5403,5390],{"class":92},[86,5405,5054],{"class":1220},[86,5407,5408],{"class":92},"Duration",[86,5410,5094],{"class":461},[86,5412,5100],{"class":1220},[86,5414,5103],{"class":461},[86,5416,5418],{"class":88,"line":5417},40,[86,5419,5108],{"class":1220},[86,5421,5423],{"class":88,"line":5422},41,[86,5424,5425],{"class":5251},"    // 从编码器读取真实位置和速度。\n",[86,5427,5429,5432,5434,5436],{"class":88,"line":5428},42,[86,5430,5431],{"class":92},"    set_state",[86,5433,4927],{"class":1220},[86,5435,4930],{"class":304},[86,5437,5438],{"class":1220},", left_position_);\n",[86,5440,5442,5444,5446,5448],{"class":88,"line":5441},43,[86,5443,5431],{"class":92},[86,5445,4927],{"class":1220},[86,5447,4942],{"class":304},[86,5449,5450],{"class":1220},", left_velocity_);\n",[86,5452,5454,5456,5458,5461],{"class":88,"line":5453},44,[86,5455,5431],{"class":92},[86,5457,4927],{"class":1220},[86,5459,5460],{"class":304},"\"right_wheel_joint/position\"",[86,5462,5463],{"class":1220},", right_position_);\n",[86,5465,5467,5469,5471,5473],{"class":88,"line":5466},45,[86,5468,5431],{"class":92},[86,5470,4927],{"class":1220},[86,5472,5336],{"class":304},[86,5474,5475],{"class":1220},", right_velocity_);\n",[86,5477,5479,5481,5483,5485,5487],{"class":88,"line":5478},46,[86,5480,2450],{"class":461},[86,5482,5051],{"class":92},[86,5484,5054],{"class":1220},[86,5486,5375],{"class":92},[86,5488,5489],{"class":1220},"::OK;\n",[86,5491,5493],{"class":88,"line":5492},47,[86,5494,3475],{"class":1220},[86,5496,5498],{"class":88,"line":5497},48,[86,5499,1569],{"emptyLinePlaceholder":1568},[86,5501,5503,5505,5507,5509,5512],{"class":88,"line":5502},49,[86,5504,5071],{"class":92},[86,5506,5054],{"class":1220},[86,5508,5375],{"class":92},[86,5510,5511],{"class":92}," write",[86,5513,5381],{"class":1220},[86,5515,5517,5519,5521,5523,5525,5527,5529,5531,5533,5535,5537,5539,5541],{"class":88,"line":5516},50,[86,5518,5387],{"class":461},[86,5520,5390],{"class":92},[86,5522,5054],{"class":1220},[86,5524,5395],{"class":92},[86,5526,5094],{"class":461},[86,5528,5321],{"class":1220},[86,5530,5084],{"class":461},[86,5532,5390],{"class":92},[86,5534,5054],{"class":1220},[86,5536,5408],{"class":92},[86,5538,5094],{"class":461},[86,5540,5100],{"class":1220},[86,5542,5103],{"class":461},[86,5544,5546],{"class":88,"line":5545},51,[86,5547,5108],{"class":1220},[86,5549,5551,5553,5556,5559,5561,5563,5565,5567],{"class":88,"line":5550},52,[86,5552,5387],{"class":461},[86,5554,5555],{"class":461}," double",[86,5557,5558],{"class":1220}," left_cmd ",[86,5560,1231],{"class":461},[86,5562,4957],{"class":92},[86,5564,4927],{"class":1220},[86,5566,4942],{"class":304},[86,5568,4964],{"class":1220},[86,5570,5572,5574,5576,5579,5581,5583,5585,5587],{"class":88,"line":5571},53,[86,5573,5387],{"class":461},[86,5575,5555],{"class":461},[86,5577,5578],{"class":1220}," right_cmd ",[86,5580,1231],{"class":461},[86,5582,4957],{"class":92},[86,5584,4927],{"class":1220},[86,5586,5336],{"class":304},[86,5588,4964],{"class":1220},[86,5590,5592],{"class":88,"line":5591},54,[86,5593,1569],{"emptyLinePlaceholder":1568},[86,5595,5597],{"class":88,"line":5596},55,[86,5598,5599],{"class":5251},"    // 把 left_cmd 和 right_cmd 写给电机驱动板。\n",[86,5601,5603,5605,5607,5609,5611],{"class":88,"line":5602},56,[86,5604,2450],{"class":461},[86,5606,5051],{"class":92},[86,5608,5054],{"class":1220},[86,5610,5375],{"class":92},[86,5612,5489],{"class":1220},[86,5614,5616],{"class":88,"line":5615},57,[86,5617,3475],{"class":1220},[86,5619,5621],{"class":88,"line":5620},58,[86,5622,1569],{"emptyLinePlaceholder":1568},[86,5624,5626],{"class":88,"line":5625},59,[86,5627,5628],{"class":461},"private:\n",[86,5630,5632,5635],{"class":88,"line":5631},60,[86,5633,5634],{"class":92},"  std",[86,5636,5637],{"class":1220},"::string serial_port_;\n",[86,5639,5641,5644,5647,5649,5652],{"class":88,"line":5640},61,[86,5642,5643],{"class":461},"  double",[86,5645,5646],{"class":1220}," left_position_ ",[86,5648,1231],{"class":461},[86,5650,5651],{"class":343}," 0.0",[86,5653,5654],{"class":1220},";\n",[86,5656,5658,5660,5663,5665,5667],{"class":88,"line":5657},62,[86,5659,5643],{"class":461},[86,5661,5662],{"class":1220}," left_velocity_ ",[86,5664,1231],{"class":461},[86,5666,5651],{"class":343},[86,5668,5654],{"class":1220},[86,5670,5672,5674,5677,5679,5681],{"class":88,"line":5671},63,[86,5673,5643],{"class":461},[86,5675,5676],{"class":1220}," right_position_ ",[86,5678,1231],{"class":461},[86,5680,5651],{"class":343},[86,5682,5654],{"class":1220},[86,5684,5686,5688,5691,5693,5695],{"class":88,"line":5685},64,[86,5687,5643],{"class":461},[86,5689,5690],{"class":1220}," right_velocity_ ",[86,5692,1231],{"class":461},[86,5694,5651],{"class":343},[86,5696,5654],{"class":1220},[86,5698,5700],{"class":88,"line":5699},65,[86,5701,5702],{"class":1220},"};\n",[86,5704,5706],{"class":88,"line":5705},66,[86,5707,1569],{"emptyLinePlaceholder":1568},[86,5709,5711,5714],{"class":88,"line":5710},67,[86,5712,5713],{"class":1220},"}",[86,5715,5716],{"class":5251},"  // namespace my_robot_hardware\n",[20,5718,5719],{},"插件導出：",[77,5721,5723],{"className":4915,"code":5722,"language":4917,"meta":82,"style":82},"#include \"pluginlib/class_list_macros.hpp\"\n\nPLUGINLIB_EXPORT_CLASS(\n  my_robot_hardware::MyDiffBotSystem,\n  hardware_interface::SystemInterface)\n",[29,5724,5725,5732,5736,5743,5751],{"__ignoreMap":82},[86,5726,5727,5729],{"class":88,"line":89},[86,5728,4985],{"class":461},[86,5730,5731],{"class":304}," \"pluginlib/class_list_macros.hpp\"\n",[86,5733,5734],{"class":88,"line":311},[86,5735,1569],{"emptyLinePlaceholder":1568},[86,5737,5738,5741],{"class":88,"line":354},[86,5739,5740],{"class":92},"PLUGINLIB_EXPORT_CLASS",[86,5742,5381],{"class":1220},[86,5744,5745,5748],{"class":88,"line":362},[86,5746,5747],{"class":92},"  my_robot_hardware",[86,5749,5750],{"class":1220},"::MyDiffBotSystem,\n",[86,5752,5753,5755],{"class":88,"line":370},[86,5754,5071],{"class":92},[86,5756,5757],{"class":1220},"::SystemInterface)\n",[20,5759,5760],{},"對應插件 XML：",[77,5762,5764],{"className":1211,"code":5763,"language":1213,"meta":82,"style":82},"\u003Clibrary path=\"my_robot_hardware\">\n  \u003Cclass\n    name=\"my_robot_hardware/MyDiffBotSystem\"\n    type=\"my_robot_hardware::MyDiffBotSystem\"\n    base_class_type=\"hardware_interface::SystemInterface\">\n    \u003Cdescription>My differential drive robot hardware interface.\u003C/description>\n  \u003C/class>\n\u003C/library>\n",[29,5765,5766,5783,5790,5800,5810,5822,5836,5844],{"__ignoreMap":82},[86,5767,5768,5770,5773,5776,5778,5781],{"class":88,"line":89},[86,5769,1221],{"class":1220},[86,5771,5772],{"class":1224},"library",[86,5774,5775],{"class":92}," path",[86,5777,1231],{"class":1220},[86,5779,5780],{"class":304},"\"my_robot_hardware\"",[86,5782,1237],{"class":1220},[86,5784,5785,5787],{"class":88,"line":311},[86,5786,1242],{"class":1220},[86,5788,5789],{"class":1224},"class\n",[86,5791,5792,5795,5797],{"class":88,"line":354},[86,5793,5794],{"class":92},"    name",[86,5796,1231],{"class":1220},[86,5798,5799],{"class":304},"\"my_robot_hardware/MyDiffBotSystem\"\n",[86,5801,5802,5805,5807],{"class":88,"line":362},[86,5803,5804],{"class":92},"    type",[86,5806,1231],{"class":1220},[86,5808,5809],{"class":304},"\"my_robot_hardware::MyDiffBotSystem\"\n",[86,5811,5812,5815,5817,5820],{"class":88,"line":370},[86,5813,5814],{"class":92},"    base_class_type",[86,5816,1231],{"class":1220},[86,5818,5819],{"class":304},"\"hardware_interface::SystemInterface\"",[86,5821,1237],{"class":1220},[86,5823,5824,5826,5829,5832,5834],{"class":88,"line":378},[86,5825,1544],{"class":1220},[86,5827,5828],{"class":1224},"description",[86,5830,5831],{"class":1220},">My differential drive robot hardware interface.\u003C/",[86,5833,5828],{"class":1224},[86,5835,1237],{"class":1220},[86,5837,5838,5840,5842],{"class":88,"line":386},[86,5839,1559],{"class":1220},[86,5841,5039],{"class":1224},[86,5843,1237],{"class":1220},[86,5845,5846,5848,5850],{"class":88,"line":394},[86,5847,1290],{"class":1220},[86,5849,5772],{"class":1224},[86,5851,1237],{"class":1220},[20,5853,5854],{},"URDF 中使用：",[77,5856,5858],{"className":1211,"code":5857,"language":1213,"meta":82,"style":82},"\u003Chardware>\n  \u003Cplugin>my_robot_hardware/MyDiffBotSystem\u003C/plugin>\n  \u003Cparam name=\"serial_port\">/dev/ttyUSB0\u003C/param>\n\u003C/hardware>\n",[29,5859,5860,5868,5881,5899],{"__ignoreMap":82},[86,5861,5862,5864,5866],{"class":88,"line":89},[86,5863,1221],{"class":1220},[86,5865,1537],{"class":1224},[86,5867,1237],{"class":1220},[86,5869,5870,5872,5874,5877,5879],{"class":88,"line":311},[86,5871,1242],{"class":1220},[86,5873,1547],{"class":1224},[86,5875,5876],{"class":1220},">my_robot_hardware/MyDiffBotSystem\u003C/",[86,5878,1547],{"class":1224},[86,5880,1237],{"class":1220},[86,5882,5883,5885,5887,5889,5891,5893,5895,5897],{"class":88,"line":354},[86,5884,1242],{"class":1220},[86,5886,2014],{"class":1224},[86,5888,1228],{"class":92},[86,5890,1231],{"class":1220},[86,5892,2021],{"class":304},[86,5894,2024],{"class":1220},[86,5896,2014],{"class":1224},[86,5898,1237],{"class":1220},[86,5900,5901,5903,5905],{"class":88,"line":362},[86,5902,1290],{"class":1220},[86,5904,1537],{"class":1224},[86,5906,1237],{"class":1220},[15,5908,5909],{"id":5909},"硬件接口調試順序",[20,5911,5912],{},"寫硬件接口時建議按這個順序調試：",[4675,5914,5915,5922,5930,5935,5942,5947,5953,5956,5963],{},[37,5916,5917,5918,5921],{},"先不用真實電機，確認 ",[29,5919,5920],{},"pluginlib"," 能加載硬件插件。",[37,5923,3843,5924,5926,5927,1307],{},[29,5925,150],{},"，運行 ",[29,5928,5929],{},"ros2 control list_hardware_components",[37,5931,5932,5933,1307],{},"確認硬件組件能進入 ",[29,5934,1442],{},[37,5936,5937,5938,5941],{},"確認 ",[29,5939,5940],{},"list_hardware_interfaces"," 中有期望的 command/state interfaces。",[37,5943,256,5944,5946],{},[29,5945,726],{}," 直接給 command interface 發命令。",[37,5948,5949,5950,5952],{},"在 ",[29,5951,1376],{}," 中打印一次命令，確認控制器確實寫入。",[37,5954,5955],{},"接真實電機，但先架空輪子或關閉高功率輸出。",[37,5957,5937,5958,5960,5961,1307],{},[29,5959,1350],{}," 能正確更新 ",[29,5962,642],{},[37,5964,5965,5966,706,5968,1307],{},"最後再接 ",[29,5967,669],{},[29,5969,694],{},[10,5971,5972],{"id":5972},"自定義運動學控制器",[15,5974,5975],{"id":5975},"什麼時候需要寫控制器",[20,5977,5978],{},"不建議一開始就寫自定義控制器。優先判斷官方控制器是否夠用：",[97,5980,5981,5991],{},[100,5982,5983],{},[103,5984,5985,5988],{},[106,5986,5987],{"align":108},"需求",[106,5989,5990],{"align":108},"推薦方案",[117,5992,5993,6001,6009,6018,6027,6036,6044],{},[103,5994,5995,5997],{},[122,5996,3889],{"align":108},[122,5998,5999],{"align":108},[29,6000,669],{},[103,6002,6003,6005],{},[122,6004,3912],{"align":108},[122,6006,6007],{"align":108},[29,6008,694],{},[103,6010,6011,6014],{},[122,6012,6013],{"align":108},"只想直接寫關節位置",[122,6015,6016],{"align":108},[29,6017,3944],{},[103,6019,6020,6023],{},[122,6021,6022],{"align":108},"只想直接寫關節速度",[122,6024,6025],{"align":108},[29,6026,3961],{},[103,6028,6029,6032],{},[122,6030,6031],{"align":108},"只想測試硬件命令",[122,6033,6034],{"align":108},[29,6035,726],{},[103,6037,6038,6041],{},[122,6039,6040],{"align":108},"特殊底盤運動學",[122,6042,6043],{"align":108},"自定義 controller",[103,6045,6046,6049],{},[122,6047,6048],{"align":108},"自定義阻抗、導納、力控策略",[122,6050,6051,6052,6055],{"align":108},"自定義 controller 或基於 ",[29,6053,6054],{},"admittance_controller"," 擴展",[20,6057,6058],{},"如果你的機器人是四輪差速、麥克納姆輪、舵輪、特殊並聯機構、腿式機器人，官方控制器不一定完全匹配，這時就需要寫自定義控制器。",[15,6060,6062],{"id":6061},"controllerinterface-關鍵函數","ControllerInterface 關鍵函數",[20,6064,6065],{},"Jazzy 中普通控制器繼承：",[77,6067,6069],{"className":4915,"code":6068,"language":4917,"meta":82,"style":82},"controller_interface::ControllerInterface\n",[29,6070,6071],{"__ignoreMap":82},[86,6072,6073,6075],{"class":88,"line":89},[86,6074,162],{"class":92},[86,6076,6077],{"class":1220},"::ControllerInterface\n",[20,6079,6080],{},"必須關注這些函數：",[97,6082,6083,6091],{},[100,6084,6085],{},[103,6086,6087,6089],{},[106,6088,4818],{"align":108},[106,6090,1341],{"align":108},[117,6092,6093,6103,6113,6123,6133,6143,6153],{},[103,6094,6095,6100],{},[122,6096,6097],{"align":108},[29,6098,6099],{},"on_init()",[122,6101,6102],{"align":108},"聲明參數，初始化非實時對象",[103,6104,6105,6110],{},[122,6106,6107],{"align":108},[29,6108,6109],{},"command_interface_configuration()",[122,6111,6112],{"align":108},"聲明要佔用哪些 command interfaces",[103,6114,6115,6120],{},[122,6116,6117],{"align":108},[29,6118,6119],{},"state_interface_configuration()",[122,6121,6122],{"align":108},"聲明要讀取哪些 state interfaces",[103,6124,6125,6130],{},[122,6126,6127],{"align":108},[29,6128,6129],{},"on_configure()",[122,6131,6132],{"align":108},"讀取參數、創建訂閲者、初始化緩存",[103,6134,6135,6140],{},[122,6136,6137],{"align":108},[29,6138,6139],{},"on_activate()",[122,6141,6142],{"align":108},"激活前檢查接口、清零命令",[103,6144,6145,6150],{},[122,6146,6147],{"align":108},[29,6148,6149],{},"on_deactivate()",[122,6151,6152],{"align":108},"停止控制器、釋放狀態",[103,6154,6155,6160],{},[122,6156,6157],{"align":108},[29,6158,6159],{},"update(time, period)",[122,6161,6162],{"align":108},"實時控制循環，計算並寫入命令",[20,6164,408,6165,6167],{},[29,6166,1363],{}," 在實時控制循環中執行，不應該做這些事：",[34,6169,6170,6173,6176,6179,6182,6185],{},[37,6171,6172],{},"不要動態分配大量內存；",[37,6174,6175],{},"不要訪問阻塞 I/O；",[37,6177,6178],{},"不要等待鎖；",[37,6180,6181],{},"不要頻繁打印日誌；",[37,6183,6184],{},"不要在裏面創建 publisher/subscriber；",[37,6186,6187],{},"不要做可能阻塞的參數讀取。",[20,6189,6190,6191,6194,6195,6197],{},"訂閲 ROS 話題時，常用做法是普通回調寫入 ",[29,6192,6193],{},"realtime_tools::RealtimeBuffer","，",[29,6196,1363],{}," 中只讀這個 buffer。",[15,6199,6200],{"id":6200},"一個自定義底盤控制器的思路",[20,6202,6203,6204,6206],{},"假設要寫一個自定義底盤控制器，輸入是 ",[29,6205,45],{},"，輸出是四個輪子的速度命令。核心步驟是：",[4675,6208,6209,6212,6220,6230,6238,6241,6246,6249],{},[37,6210,6211],{},"參數中聲明四個輪子的 joint 名。",[37,6213,6214,6216,6217,1307],{},[29,6215,6109],{}," 返回四個 ",[29,6218,6219],{},"\u003Cjoint>/velocity",[37,6221,6222,6224,6225,706,6228,1307],{},[29,6223,6119],{}," 返回需要讀取的 ",[29,6226,6227],{},"\u003Cjoint>/position",[29,6229,6219],{},[37,6231,6232,6234,6235,6237],{},[29,6233,6129],{}," 創建 ",[29,6236,45],{}," 訂閲者。",[37,6239,6240],{},"訂閲者把最新速度命令寫入實時 buffer。",[37,6242,6243,6245],{},[29,6244,1363],{}," 讀取最新速度命令。",[37,6247,6248],{},"根據運動學模型計算各輪速度。",[37,6250,6251,6252,1307],{},"把結果寫入 ",[29,6253,6254],{},"command_interfaces_",[20,6256,6257],{},"偽代碼如下：",[77,6259,6261],{"className":4915,"code":6260,"language":4917,"meta":82,"style":82},"controller_interface::InterfaceConfiguration\nMyKinematicsController::command_interface_configuration() const\n{\n  controller_interface::InterfaceConfiguration config;\n  config.type = controller_interface::interface_configuration_type::INDIVIDUAL;\n  config.names = {\n    \"front_left_wheel_joint/velocity\",\n    \"front_right_wheel_joint/velocity\",\n    \"rear_left_wheel_joint/velocity\",\n    \"rear_right_wheel_joint/velocity\"\n  };\n  return config;\n}\n\ncontroller_interface::return_type MyKinematicsController::update(\n  const rclcpp::Time &, const rclcpp::Duration &)\n{\n  const auto cmd = *command_buffer_.readFromRT();\n\n  const double vx = cmd.linear.x;\n  const double wz = cmd.angular.z;\n\n  const double left = vx - wz * wheel_separation_ * 0.5;\n  const double right = vx + wz * wheel_separation_ * 0.5;\n\n  command_interfaces_[0].set_value(left / wheel_radius_);\n  command_interfaces_[1].set_value(right / wheel_radius_);\n  command_interfaces_[2].set_value(left / wheel_radius_);\n  command_interfaces_[3].set_value(right / wheel_radius_);\n\n  return controller_interface::return_type::OK;\n}\n",[29,6262,6263,6270,6286,6290,6298,6316,6326,6333,6340,6347,6352,6357,6365,6370,6374,6392,6420,6424,6447,6451,6465,6479,6483,6514,6542,6546,6569,6587,6604,6621,6625,6637],{"__ignoreMap":82},[86,6264,6265,6267],{"class":88,"line":89},[86,6266,162],{"class":92},[86,6268,6269],{"class":1220},"::InterfaceConfiguration\n",[86,6271,6272,6275,6277,6280,6283],{"class":88,"line":311},[86,6273,6274],{"class":92},"MyKinematicsController",[86,6276,5054],{"class":1220},[86,6278,6279],{"class":92},"command_interface_configuration",[86,6281,6282],{"class":1220},"() ",[86,6284,6285],{"class":461},"const\n",[86,6287,6288],{"class":88,"line":354},[86,6289,5030],{"class":1220},[86,6291,6292,6295],{"class":88,"line":362},[86,6293,6294],{"class":92},"  controller_interface",[86,6296,6297],{"class":1220},"::InterfaceConfiguration config;\n",[86,6299,6300,6303,6305,6308,6310,6313],{"class":88,"line":370},[86,6301,6302],{"class":1220},"  config.type ",[86,6304,1231],{"class":461},[86,6306,6307],{"class":92}," controller_interface",[86,6309,5054],{"class":1220},[86,6311,6312],{"class":92},"interface_configuration_type",[86,6314,6315],{"class":1220},"::INDIVIDUAL;\n",[86,6317,6318,6321,6323],{"class":88,"line":378},[86,6319,6320],{"class":1220},"  config.names ",[86,6322,1231],{"class":461},[86,6324,6325],{"class":1220}," {\n",[86,6327,6328,6331],{"class":88,"line":386},[86,6329,6330],{"class":304},"    \"front_left_wheel_joint/velocity\"",[86,6332,2374],{"class":1220},[86,6334,6335,6338],{"class":88,"line":394},[86,6336,6337],{"class":304},"    \"front_right_wheel_joint/velocity\"",[86,6339,2374],{"class":1220},[86,6341,6342,6345],{"class":88,"line":402},[86,6343,6344],{"class":304},"    \"rear_left_wheel_joint/velocity\"",[86,6346,2374],{"class":1220},[86,6348,6349],{"class":88,"line":585},[86,6350,6351],{"class":304},"    \"rear_right_wheel_joint/velocity\"\n",[86,6353,6354],{"class":88,"line":591},[86,6355,6356],{"class":1220},"  };\n",[86,6358,6359,6362],{"class":88,"line":597},[86,6360,6361],{"class":461},"  return",[86,6363,6364],{"class":1220}," config;\n",[86,6366,6367],{"class":88,"line":1879},[86,6368,6369],{"class":1220},"}\n",[86,6371,6372],{"class":88,"line":1894},[86,6373,1569],{"emptyLinePlaceholder":1568},[86,6375,6376,6378,6380,6382,6385,6387,6390],{"class":88,"line":1909},[86,6377,162],{"class":92},[86,6379,5054],{"class":1220},[86,6381,5375],{"class":92},[86,6383,6384],{"class":92}," MyKinematicsController",[86,6386,5054],{"class":1220},[86,6388,6389],{"class":92},"update",[86,6391,5381],{"class":1220},[86,6393,6394,6397,6399,6401,6403,6405,6407,6409,6411,6413,6415,6417],{"class":88,"line":1924},[86,6395,6396],{"class":461},"  const",[86,6398,5390],{"class":92},[86,6400,5054],{"class":1220},[86,6402,5395],{"class":92},[86,6404,5094],{"class":461},[86,6406,5321],{"class":1220},[86,6408,5084],{"class":461},[86,6410,5390],{"class":92},[86,6412,5054],{"class":1220},[86,6414,5408],{"class":92},[86,6416,5094],{"class":461},[86,6418,6419],{"class":1220},")\n",[86,6421,6422],{"class":88,"line":1933},[86,6423,5030],{"class":1220},[86,6425,6426,6428,6431,6433,6435,6438,6441,6444],{"class":88,"line":4375},[86,6427,6396],{"class":461},[86,6429,6430],{"class":461}," auto",[86,6432,4952],{"class":1220},[86,6434,1231],{"class":461},[86,6436,6437],{"class":461}," *",[86,6439,6440],{"class":1220},"command_buffer_.",[86,6442,6443],{"class":92},"readFromRT",[86,6445,6446],{"class":1220},"();\n",[86,6448,6449],{"class":88,"line":4386},[86,6450,1569],{"emptyLinePlaceholder":1568},[86,6452,6453,6455,6457,6460,6462],{"class":88,"line":4397},[86,6454,6396],{"class":461},[86,6456,5555],{"class":461},[86,6458,6459],{"class":1220}," vx ",[86,6461,1231],{"class":461},[86,6463,6464],{"class":1220}," cmd.linear.x;\n",[86,6466,6467,6469,6471,6474,6476],{"class":88,"line":4406},[86,6468,6396],{"class":461},[86,6470,5555],{"class":461},[86,6472,6473],{"class":1220}," wz ",[86,6475,1231],{"class":461},[86,6477,6478],{"class":1220}," cmd.angular.z;\n",[86,6480,6481],{"class":88,"line":4415},[86,6482,1569],{"emptyLinePlaceholder":1568},[86,6484,6485,6487,6489,6492,6494,6496,6499,6501,6504,6507,6509,6512],{"class":88,"line":4424},[86,6486,6396],{"class":461},[86,6488,5555],{"class":461},[86,6490,6491],{"class":1220}," left ",[86,6493,1231],{"class":461},[86,6495,6459],{"class":1220},[86,6497,6498],{"class":461},"-",[86,6500,6473],{"class":1220},[86,6502,6503],{"class":461},"*",[86,6505,6506],{"class":1220}," wheel_separation_ ",[86,6508,6503],{"class":461},[86,6510,6511],{"class":343}," 0.5",[86,6513,5654],{"class":1220},[86,6515,6516,6518,6520,6523,6525,6527,6530,6532,6534,6536,6538,6540],{"class":88,"line":4433},[86,6517,6396],{"class":461},[86,6519,5555],{"class":461},[86,6521,6522],{"class":1220}," right ",[86,6524,1231],{"class":461},[86,6526,6459],{"class":1220},[86,6528,6529],{"class":461},"+",[86,6531,6473],{"class":1220},[86,6533,6503],{"class":461},[86,6535,6506],{"class":1220},[86,6537,6503],{"class":461},[86,6539,6511],{"class":343},[86,6541,5654],{"class":1220},[86,6543,6544],{"class":88,"line":4442},[86,6545,1569],{"emptyLinePlaceholder":1568},[86,6547,6548,6551,6554,6557,6560,6563,6566],{"class":88,"line":4451},[86,6549,6550],{"class":1220},"  command_interfaces_[",[86,6552,6553],{"class":343},"0",[86,6555,6556],{"class":1220},"].",[86,6558,6559],{"class":92},"set_value",[86,6561,6562],{"class":1220},"(left ",[86,6564,6565],{"class":461},"/",[86,6567,6568],{"class":1220}," wheel_radius_);\n",[86,6570,6571,6573,6576,6578,6580,6583,6585],{"class":88,"line":4460},[86,6572,6550],{"class":1220},[86,6574,6575],{"class":343},"1",[86,6577,6556],{"class":1220},[86,6579,6559],{"class":92},[86,6581,6582],{"class":1220},"(right ",[86,6584,6565],{"class":461},[86,6586,6568],{"class":1220},[86,6588,6589,6591,6594,6596,6598,6600,6602],{"class":88,"line":5255},[86,6590,6550],{"class":1220},[86,6592,6593],{"class":343},"2",[86,6595,6556],{"class":1220},[86,6597,6559],{"class":92},[86,6599,6562],{"class":1220},[86,6601,6565],{"class":461},[86,6603,6568],{"class":1220},[86,6605,6606,6608,6611,6613,6615,6617,6619],{"class":88,"line":5268},[86,6607,6550],{"class":1220},[86,6609,6610],{"class":343},"3",[86,6612,6556],{"class":1220},[86,6614,6559],{"class":92},[86,6616,6582],{"class":1220},[86,6618,6565],{"class":461},[86,6620,6568],{"class":1220},[86,6622,6623],{"class":88,"line":5273},[86,6624,1569],{"emptyLinePlaceholder":1568},[86,6626,6627,6629,6631,6633,6635],{"class":88,"line":5278},[86,6628,6361],{"class":461},[86,6630,6307],{"class":92},[86,6632,5054],{"class":1220},[86,6634,5375],{"class":92},[86,6636,5489],{"class":1220},[86,6638,6639],{"class":88,"line":5306},[86,6640,6369],{"class":1220},[20,6642,6643],{},"這段代碼只是運動學控制器核心邏輯。完整控制器還需要參數聲明、訂閲者、接口排序檢查、超時保護、插件導出和 CMake 配置。",[15,6645,6647],{"id":6646},"自定義控制器-packagexml","自定義控制器 package.xml",[20,6649,6650],{},"常見依賴如下：",[77,6652,6654],{"className":1211,"code":6653,"language":1213,"meta":82,"style":82},"\u003Cdepend>controller_interface\u003C/depend>\n\u003Cdepend>hardware_interface\u003C/depend>\n\u003Cdepend>pluginlib\u003C/depend>\n\u003Cdepend>rclcpp\u003C/depend>\n\u003Cdepend>rclcpp_lifecycle\u003C/depend>\n\u003Cdepend>realtime_tools\u003C/depend>\n\u003Cdepend>geometry_msgs\u003C/depend>\n",[29,6655,6656,6670,6683,6696,6709,6722,6735],{"__ignoreMap":82},[86,6657,6658,6660,6663,6666,6668],{"class":88,"line":89},[86,6659,1221],{"class":1220},[86,6661,6662],{"class":1224},"depend",[86,6664,6665],{"class":1220},">controller_interface\u003C/",[86,6667,6662],{"class":1224},[86,6669,1237],{"class":1220},[86,6671,6672,6674,6676,6679,6681],{"class":88,"line":311},[86,6673,1221],{"class":1220},[86,6675,6662],{"class":1224},[86,6677,6678],{"class":1220},">hardware_interface\u003C/",[86,6680,6662],{"class":1224},[86,6682,1237],{"class":1220},[86,6684,6685,6687,6689,6692,6694],{"class":88,"line":354},[86,6686,1221],{"class":1220},[86,6688,6662],{"class":1224},[86,6690,6691],{"class":1220},">pluginlib\u003C/",[86,6693,6662],{"class":1224},[86,6695,1237],{"class":1220},[86,6697,6698,6700,6702,6705,6707],{"class":88,"line":362},[86,6699,1221],{"class":1220},[86,6701,6662],{"class":1224},[86,6703,6704],{"class":1220},">rclcpp\u003C/",[86,6706,6662],{"class":1224},[86,6708,1237],{"class":1220},[86,6710,6711,6713,6715,6718,6720],{"class":88,"line":370},[86,6712,1221],{"class":1220},[86,6714,6662],{"class":1224},[86,6716,6717],{"class":1220},">rclcpp_lifecycle\u003C/",[86,6719,6662],{"class":1224},[86,6721,1237],{"class":1220},[86,6723,6724,6726,6728,6731,6733],{"class":88,"line":378},[86,6725,1221],{"class":1220},[86,6727,6662],{"class":1224},[86,6729,6730],{"class":1220},">realtime_tools\u003C/",[86,6732,6662],{"class":1224},[86,6734,1237],{"class":1220},[86,6736,6737,6739,6741,6744,6746],{"class":88,"line":386},[86,6738,1221],{"class":1220},[86,6740,6662],{"class":1224},[86,6742,6743],{"class":1220},">geometry_msgs\u003C/",[86,6745,6662],{"class":1224},[86,6747,1237],{"class":1220},[20,6749,6750],{},"如果要發佈里程計，還需要：",[77,6752,6754],{"className":1211,"code":6753,"language":1213,"meta":82,"style":82},"\u003Cdepend>nav_msgs\u003C/depend>\n\u003Cdepend>tf2\u003C/depend>\n\u003Cdepend>tf2_msgs\u003C/depend>\n\u003Cdepend>tf2_ros\u003C/depend>\n",[29,6755,6756,6769,6782,6795],{"__ignoreMap":82},[86,6757,6758,6760,6762,6765,6767],{"class":88,"line":89},[86,6759,1221],{"class":1220},[86,6761,6662],{"class":1224},[86,6763,6764],{"class":1220},">nav_msgs\u003C/",[86,6766,6662],{"class":1224},[86,6768,1237],{"class":1220},[86,6770,6771,6773,6775,6778,6780],{"class":88,"line":311},[86,6772,1221],{"class":1220},[86,6774,6662],{"class":1224},[86,6776,6777],{"class":1220},">tf2\u003C/",[86,6779,6662],{"class":1224},[86,6781,1237],{"class":1220},[86,6783,6784,6786,6788,6791,6793],{"class":88,"line":354},[86,6785,1221],{"class":1220},[86,6787,6662],{"class":1224},[86,6789,6790],{"class":1220},">tf2_msgs\u003C/",[86,6792,6662],{"class":1224},[86,6794,1237],{"class":1220},[86,6796,6797,6799,6801,6804,6806],{"class":88,"line":362},[86,6798,1221],{"class":1220},[86,6800,6662],{"class":1224},[86,6802,6803],{"class":1220},">tf2_ros\u003C/",[86,6805,6662],{"class":1224},[86,6807,1237],{"class":1220},[15,6809,6811],{"id":6810},"自定義控制器-cmakelists","自定義控制器 CMakeLists",[20,6813,6814],{},"核心寫法如下：",[77,6816,6820],{"className":6817,"code":6818,"language":6819,"meta":82,"style":82},"language-cmake shiki shiki-themes github-light github-dark","add_library(my_kinematics_controller SHARED\n  src/my_kinematics_controller.cpp\n)\n\nament_target_dependencies(my_kinematics_controller\n  controller_interface\n  hardware_interface\n  pluginlib\n  rclcpp\n  rclcpp_lifecycle\n  realtime_tools\n  geometry_msgs\n)\n\npluginlib_export_plugin_description_file(\n  controller_interface\n  my_kinematics_controller.xml\n)\n\ninstall(\n  TARGETS my_kinematics_controller\n  ARCHIVE DESTINATION lib\n  LIBRARY DESTINATION lib\n  RUNTIME DESTINATION bin\n)\n\ninstall(\n  FILES my_kinematics_controller.xml\n  DESTINATION share/${PROJECT_NAME}\n)\n","cmake",[29,6821,6822,6830,6835,6839,6843,6848,6853,6858,6863,6868,6873,6878,6883,6887,6891,6896,6900,6905,6909,6913,6920,6925,6930,6935,6940,6944,6948,6954,6959,6967],{"__ignoreMap":82},[86,6823,6824,6827],{"class":88,"line":89},[86,6825,6826],{"class":461},"add_library",[86,6828,6829],{"class":1220},"(my_kinematics_controller SHARED\n",[86,6831,6832],{"class":88,"line":311},[86,6833,6834],{"class":1220},"  src/my_kinematics_controller.cpp\n",[86,6836,6837],{"class":88,"line":354},[86,6838,6419],{"class":1220},[86,6840,6841],{"class":88,"line":362},[86,6842,1569],{"emptyLinePlaceholder":1568},[86,6844,6845],{"class":88,"line":370},[86,6846,6847],{"class":1220},"ament_target_dependencies(my_kinematics_controller\n",[86,6849,6850],{"class":88,"line":378},[86,6851,6852],{"class":1220},"  controller_interface\n",[86,6854,6855],{"class":88,"line":386},[86,6856,6857],{"class":1220},"  hardware_interface\n",[86,6859,6860],{"class":88,"line":394},[86,6861,6862],{"class":1220},"  pluginlib\n",[86,6864,6865],{"class":88,"line":402},[86,6866,6867],{"class":1220},"  rclcpp\n",[86,6869,6870],{"class":88,"line":585},[86,6871,6872],{"class":1220},"  rclcpp_lifecycle\n",[86,6874,6875],{"class":88,"line":591},[86,6876,6877],{"class":1220},"  realtime_tools\n",[86,6879,6880],{"class":88,"line":597},[86,6881,6882],{"class":1220},"  geometry_msgs\n",[86,6884,6885],{"class":88,"line":1879},[86,6886,6419],{"class":1220},[86,6888,6889],{"class":88,"line":1894},[86,6890,1569],{"emptyLinePlaceholder":1568},[86,6892,6893],{"class":88,"line":1909},[86,6894,6895],{"class":1220},"pluginlib_export_plugin_description_file(\n",[86,6897,6898],{"class":88,"line":1924},[86,6899,6852],{"class":1220},[86,6901,6902],{"class":88,"line":1933},[86,6903,6904],{"class":1220},"  my_kinematics_controller.xml\n",[86,6906,6907],{"class":88,"line":4375},[86,6908,6419],{"class":1220},[86,6910,6911],{"class":88,"line":4386},[86,6912,1569],{"emptyLinePlaceholder":1568},[86,6914,6915,6918],{"class":88,"line":4397},[86,6916,6917],{"class":461},"install",[86,6919,5381],{"class":1220},[86,6921,6922],{"class":88,"line":4406},[86,6923,6924],{"class":1220},"  TARGETS my_kinematics_controller\n",[86,6926,6927],{"class":88,"line":4415},[86,6928,6929],{"class":1220},"  ARCHIVE DESTINATION lib\n",[86,6931,6932],{"class":88,"line":4424},[86,6933,6934],{"class":1220},"  LIBRARY DESTINATION lib\n",[86,6936,6937],{"class":88,"line":4433},[86,6938,6939],{"class":1220},"  RUNTIME DESTINATION bin\n",[86,6941,6942],{"class":88,"line":4442},[86,6943,6419],{"class":1220},[86,6945,6946],{"class":88,"line":4451},[86,6947,1569],{"emptyLinePlaceholder":1568},[86,6949,6950,6952],{"class":88,"line":4460},[86,6951,6917],{"class":461},[86,6953,5381],{"class":1220},[86,6955,6956],{"class":88,"line":5255},[86,6957,6958],{"class":1220},"  FILES my_kinematics_controller.xml\n",[86,6960,6961,6964],{"class":88,"line":5268},[86,6962,6963],{"class":1220},"  DESTINATION share/",[86,6965,6966],{"class":461},"${PROJECT_NAME}\n",[86,6968,6969],{"class":88,"line":5273},[86,6970,6419],{"class":1220},[20,6972,6973],{},"插件 XML：",[77,6975,6977],{"className":1211,"code":6976,"language":1213,"meta":82,"style":82},"\u003Clibrary path=\"my_kinematics_controller\">\n  \u003Cclass\n    name=\"my_kinematics_controller/MyKinematicsController\"\n    type=\"my_kinematics_controller::MyKinematicsController\"\n    base_class_type=\"controller_interface::ControllerInterface\">\n    \u003Cdescription>My custom mobile robot kinematics controller.\u003C/description>\n  \u003C/class>\n\u003C/library>\n",[29,6978,6979,6994,7000,7009,7018,7029,7042,7050],{"__ignoreMap":82},[86,6980,6981,6983,6985,6987,6989,6992],{"class":88,"line":89},[86,6982,1221],{"class":1220},[86,6984,5772],{"class":1224},[86,6986,5775],{"class":92},[86,6988,1231],{"class":1220},[86,6990,6991],{"class":304},"\"my_kinematics_controller\"",[86,6993,1237],{"class":1220},[86,6995,6996,6998],{"class":88,"line":311},[86,6997,1242],{"class":1220},[86,6999,5789],{"class":1224},[86,7001,7002,7004,7006],{"class":88,"line":354},[86,7003,5794],{"class":92},[86,7005,1231],{"class":1220},[86,7007,7008],{"class":304},"\"my_kinematics_controller/MyKinematicsController\"\n",[86,7010,7011,7013,7015],{"class":88,"line":362},[86,7012,5804],{"class":92},[86,7014,1231],{"class":1220},[86,7016,7017],{"class":304},"\"my_kinematics_controller::MyKinematicsController\"\n",[86,7019,7020,7022,7024,7027],{"class":88,"line":370},[86,7021,5814],{"class":92},[86,7023,1231],{"class":1220},[86,7025,7026],{"class":304},"\"controller_interface::ControllerInterface\"",[86,7028,1237],{"class":1220},[86,7030,7031,7033,7035,7038,7040],{"class":88,"line":378},[86,7032,1544],{"class":1220},[86,7034,5828],{"class":1224},[86,7036,7037],{"class":1220},">My custom mobile robot kinematics controller.\u003C/",[86,7039,5828],{"class":1224},[86,7041,1237],{"class":1220},[86,7043,7044,7046,7048],{"class":88,"line":386},[86,7045,1559],{"class":1220},[86,7047,5039],{"class":1224},[86,7049,1237],{"class":1220},[86,7051,7052,7054,7056],{"class":88,"line":394},[86,7053,1290],{"class":1220},[86,7055,5772],{"class":1224},[86,7057,1237],{"class":1220},[20,7059,7060],{},"YAML 中加載：",[77,7062,7064],{"className":2126,"code":7063,"language":2128,"meta":82,"style":82},"controller_manager:\n  ros__parameters:\n    my_kinematics_controller:\n      type: my_kinematics_controller/MyKinematicsController\n\nmy_kinematics_controller:\n  ros__parameters:\n    wheel_radius: 0.05\n    wheel_separation: 0.40\n",[29,7065,7066,7072,7078,7085,7094,7098,7105,7111,7119],{"__ignoreMap":82},[86,7067,7068,7070],{"class":88,"line":89},[86,7069,71],{"class":1224},[86,7071,2137],{"class":1220},[86,7073,7074,7076],{"class":88,"line":311},[86,7075,2142],{"class":1224},[86,7077,2137],{"class":1220},[86,7079,7080,7083],{"class":88,"line":354},[86,7081,7082],{"class":1224},"    my_kinematics_controller",[86,7084,2137],{"class":1220},[86,7086,7087,7089,7091],{"class":88,"line":362},[86,7088,2171],{"class":1224},[86,7090,2152],{"class":1220},[86,7092,7093],{"class":304},"my_kinematics_controller/MyKinematicsController\n",[86,7095,7096],{"class":88,"line":370},[86,7097,1569],{"emptyLinePlaceholder":1568},[86,7099,7100,7103],{"class":88,"line":378},[86,7101,7102],{"class":1224},"my_kinematics_controller",[86,7104,2137],{"class":1220},[86,7106,7107,7109],{"class":88,"line":386},[86,7108,2142],{"class":1224},[86,7110,2137],{"class":1220},[86,7112,7113,7115,7117],{"class":88,"line":394},[86,7114,3281],{"class":1224},[86,7116,2152],{"class":1220},[86,7118,3286],{"class":343},[86,7120,7121,7123,7125],{"class":88,"line":402},[86,7122,3271],{"class":1224},[86,7124,2152],{"class":1220},[86,7126,3276],{"class":343},[15,7128,7129],{"id":7129},"普通控制器還是鏈式控制器",[20,7131,7132],{},"Jazzy 中控制器分兩類：",[97,7134,7135,7147],{},[100,7136,7137],{},[103,7138,7139,7141,7144],{},[106,7140,2956],{"align":108},[106,7142,7143],{"align":108},"基類",[106,7145,7146],{"align":108},"適用場景",[117,7148,7149,7162],{},[103,7150,7151,7154,7159],{},[122,7152,7153],{"align":108},"普通控制器",[122,7155,7156],{"align":108},[29,7157,7158],{},"controller_interface::ControllerInterface",[122,7160,7161],{"align":108},"從 ROS 話題/action 接收命令，直接寫硬件 command interface",[103,7163,7164,7167,7172],{},[122,7165,7166],{"align":108},"鏈式控制器",[122,7168,7169],{"align":108},[29,7170,7171],{},"controller_interface::ChainableControllerInterface",[122,7173,7174],{"align":108},"上游控制器輸出 reference interface，下游控制器繼續處理",[20,7176,7177],{},"初學者建議先寫普通控制器。只有當你需要多個控制器串聯時，再研究鏈式控制器。例如：",[77,7179,7182],{"className":7180,"code":7181,"language":1321,"meta":82},[1319],"导航速度命令 -> 运动学控制器 -> PID 控制器 -> 硬件接口\n",[29,7183,7181],{"__ignoreMap":82},[20,7185,7186],{},"鏈式控制器可以用：",[77,7188,7189],{"className":79,"code":2899,"language":81,"meta":82,"style":82},[29,7190,7191],{"__ignoreMap":82},[86,7192,7193,7195,7197],{"class":88,"line":89},[86,7194,452],{"class":92},[86,7196,2760],{"class":304},[86,7198,2910],{"class":304},[20,7200,7201],{},"查看控制器鏈路。",[10,7203,7205],{"id":7204},"gazebo-與-ros2-control","Gazebo 與 ROS2 Control",[20,7207,7208,7209,7212],{},"ros2_control 本身不是仿真器。它只是控制框架。要在 Gazebo Sim 中使用，需要 ",[29,7210,7211],{},"gz_ros2_control"," 插件。",[20,7214,7215],{},"安裝：",[77,7217,7219],{"className":79,"code":7218,"language":81,"meta":82,"style":82},"sudo apt install ros-jazzy-gz-ros2-control ros-jazzy-gz-ros2-control-demos\n",[29,7220,7221],{"__ignoreMap":82},[86,7222,7223,7225,7227,7229,7232],{"class":88,"line":89},[86,7224,301],{"class":92},[86,7226,305],{"class":304},[86,7228,318],{"class":304},[86,7230,7231],{"class":304}," ros-jazzy-gz-ros2-control",[86,7233,7234],{"class":304}," ros-jazzy-gz-ros2-control-demos\n",[20,7236,7237],{},"Gazebo 集成時仍然需要：",[34,7239,7240,7245,7248,7252],{},[37,7241,7242,7243,238],{},"URDF 中的 ",[29,7244,1498],{},[37,7246,7247],{},"控制器 YAML；",[37,7249,7250,238],{},[29,7251,71],{},[37,7253,7254,7256],{},[29,7255,633],{}," 和具體控制器。",[20,7258,7259,7260,7263,7264,7266],{},"區別在於 ",[29,7261,7262],{},"\u003Chardware>\u003Cplugin>...\u003C/plugin>\u003C/hardware>"," 通常換成 Gazebo 對應硬件插件，而不是 ",[29,7265,4799],{}," 或你的真實硬件插件。",[20,7268,7269,7270,7272],{},"Jazzy 中 ",[29,7271,7211],{}," 的硬件插件描述文件是：",[77,7274,7276],{"className":79,"code":7275,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/share/gz_ros2_control/gz_hardware_plugins.xml\n",[29,7277,7278],{"__ignoreMap":82},[86,7279,7280],{"class":88,"line":89},[86,7281,7275],{"class":92},[20,7283,7284],{},"Gazebo Sim 系統硬件插件名是：",[77,7286,7288],{"className":79,"code":7287,"language":81,"meta":82,"style":82},"gz_ros2_control/GazeboSimSystem\n",[29,7289,7290],{"__ignoreMap":82},[86,7291,7292],{"class":88,"line":89},[86,7293,7287],{"class":92},[20,7295,7296,7297,7299],{},"URDF 或 xacro 中的 ",[29,7298,1498],{}," 關鍵片段通常寫成：",[77,7301,7303],{"className":1211,"code":7302,"language":1213,"meta":82,"style":82},"\u003Cros2_control name=\"GazeboSimSystem\" type=\"system\">\n  \u003Chardware>\n    \u003Cplugin>gz_ros2_control/GazeboSimSystem\u003C/plugin>\n  \u003C/hardware>\n\n  \u003Cjoint name=\"left_wheel_joint\">\n    \u003Ccommand_interface name=\"velocity\"/>\n    \u003Cstate_interface name=\"position\"/>\n    \u003Cstate_interface name=\"velocity\"/>\n  \u003C/joint>\n\n  \u003Cjoint name=\"right_wheel_joint\">\n    \u003Ccommand_interface name=\"velocity\"/>\n    \u003Cstate_interface name=\"position\"/>\n    \u003Cstate_interface name=\"velocity\"/>\n  \u003C/joint>\n\u003C/ros2_control>\n",[29,7304,7305,7326,7334,7347,7355,7359,7373,7387,7401,7415,7423,7427,7441,7455,7469,7483,7491],{"__ignoreMap":82},[86,7306,7307,7309,7311,7313,7315,7318,7320,7322,7324],{"class":88,"line":89},[86,7308,1221],{"class":1220},[86,7310,31],{"class":1224},[86,7312,1228],{"class":92},[86,7314,1231],{"class":1220},[86,7316,7317],{"class":304},"\"GazeboSimSystem\"",[86,7319,1523],{"class":92},[86,7321,1231],{"class":1220},[86,7323,1528],{"class":304},[86,7325,1237],{"class":1220},[86,7327,7328,7330,7332],{"class":88,"line":311},[86,7329,1242],{"class":1220},[86,7331,1537],{"class":1224},[86,7333,1237],{"class":1220},[86,7335,7336,7338,7340,7343,7345],{"class":88,"line":354},[86,7337,1544],{"class":1220},[86,7339,1547],{"class":1224},[86,7341,7342],{"class":1220},">gz_ros2_control/GazeboSimSystem\u003C/",[86,7344,1547],{"class":1224},[86,7346,1237],{"class":1220},[86,7348,7349,7351,7353],{"class":88,"line":362},[86,7350,1559],{"class":1220},[86,7352,1537],{"class":1224},[86,7354,1237],{"class":1220},[86,7356,7357],{"class":88,"line":370},[86,7358,1569],{"emptyLinePlaceholder":1568},[86,7360,7361,7363,7365,7367,7369,7371],{"class":88,"line":378},[86,7362,1242],{"class":1220},[86,7364,1225],{"class":1224},[86,7366,1228],{"class":92},[86,7368,1231],{"class":1220},[86,7370,1234],{"class":304},[86,7372,1237],{"class":1220},[86,7374,7375,7377,7379,7381,7383,7385],{"class":88,"line":386},[86,7376,1544],{"class":1220},[86,7378,1245],{"class":1224},[86,7380,1228],{"class":92},[86,7382,1231],{"class":1220},[86,7384,1252],{"class":304},[86,7386,1255],{"class":1220},[86,7388,7389,7391,7393,7395,7397,7399],{"class":88,"line":394},[86,7390,1544],{"class":1220},[86,7392,1262],{"class":1224},[86,7394,1228],{"class":92},[86,7396,1231],{"class":1220},[86,7398,1269],{"class":304},[86,7400,1255],{"class":1220},[86,7402,7403,7405,7407,7409,7411,7413],{"class":88,"line":402},[86,7404,1544],{"class":1220},[86,7406,1262],{"class":1224},[86,7408,1228],{"class":92},[86,7410,1231],{"class":1220},[86,7412,1252],{"class":304},[86,7414,1255],{"class":1220},[86,7416,7417,7419,7421],{"class":88,"line":585},[86,7418,1559],{"class":1220},[86,7420,1225],{"class":1224},[86,7422,1237],{"class":1220},[86,7424,7425],{"class":88,"line":591},[86,7426,1569],{"emptyLinePlaceholder":1568},[86,7428,7429,7431,7433,7435,7437,7439],{"class":88,"line":597},[86,7430,1242],{"class":1220},[86,7432,1225],{"class":1224},[86,7434,1228],{"class":92},[86,7436,1231],{"class":1220},[86,7438,1874],{"class":304},[86,7440,1237],{"class":1220},[86,7442,7443,7445,7447,7449,7451,7453],{"class":88,"line":1879},[86,7444,1544],{"class":1220},[86,7446,1245],{"class":1224},[86,7448,1228],{"class":92},[86,7450,1231],{"class":1220},[86,7452,1252],{"class":304},[86,7454,1255],{"class":1220},[86,7456,7457,7459,7461,7463,7465,7467],{"class":88,"line":1894},[86,7458,1544],{"class":1220},[86,7460,1262],{"class":1224},[86,7462,1228],{"class":92},[86,7464,1231],{"class":1220},[86,7466,1269],{"class":304},[86,7468,1255],{"class":1220},[86,7470,7471,7473,7475,7477,7479,7481],{"class":88,"line":1909},[86,7472,1544],{"class":1220},[86,7474,1262],{"class":1224},[86,7476,1228],{"class":92},[86,7478,1231],{"class":1220},[86,7480,1252],{"class":304},[86,7482,1255],{"class":1220},[86,7484,7485,7487,7489],{"class":88,"line":1924},[86,7486,1559],{"class":1220},[86,7488,1225],{"class":1224},[86,7490,1237],{"class":1220},[86,7492,7493,7495,7497],{"class":88,"line":1933},[86,7494,1290],{"class":1220},[86,7496,31],{"class":1224},[86,7498,1237],{"class":1220},[20,7500,7501],{},"同時還要在機器人描述中加入 Gazebo 系統插件，讓 Gazebo Sim 創建 ros2_control 資源管理器並加載控制器參數：",[77,7503,7505],{"className":1211,"code":7504,"language":1213,"meta":82,"style":82},"\u003Cgazebo>\n  \u003Cplugin filename=\"gz_ros2_control-system\" name=\"gz_ros2_control::GazeboSimROS2ControlPlugin\">\n    \u003Cparameters>$(find my_robot_bringup)/config/controllers.yaml\u003C/parameters>\n  \u003C/plugin>\n\u003C/gazebo>\n",[29,7506,7507,7516,7539,7553,7561],{"__ignoreMap":82},[86,7508,7509,7511,7514],{"class":88,"line":89},[86,7510,1221],{"class":1220},[86,7512,7513],{"class":1224},"gazebo",[86,7515,1237],{"class":1220},[86,7517,7518,7520,7522,7525,7527,7530,7532,7534,7537],{"class":88,"line":311},[86,7519,1242],{"class":1220},[86,7521,1547],{"class":1224},[86,7523,7524],{"class":92}," filename",[86,7526,1231],{"class":1220},[86,7528,7529],{"class":304},"\"gz_ros2_control-system\"",[86,7531,1228],{"class":92},[86,7533,1231],{"class":1220},[86,7535,7536],{"class":304},"\"gz_ros2_control::GazeboSimROS2ControlPlugin\"",[86,7538,1237],{"class":1220},[86,7540,7541,7543,7546,7549,7551],{"class":88,"line":354},[86,7542,1544],{"class":1220},[86,7544,7545],{"class":1224},"parameters",[86,7547,7548],{"class":1220},">$(find my_robot_bringup)/config/controllers.yaml\u003C/",[86,7550,7545],{"class":1224},[86,7552,1237],{"class":1220},[86,7554,7555,7557,7559],{"class":88,"line":362},[86,7556,1559],{"class":1220},[86,7558,1547],{"class":1224},[86,7560,1237],{"class":1220},[86,7562,7563,7565,7567],{"class":88,"line":370},[86,7564,1290],{"class":1220},[86,7566,7513],{"class":1224},[86,7568,1237],{"class":1220},[20,7570,3861,7571,7574],{},[29,7572,7573],{},"gz_ros2_control_demos"," 後，可以直接參考官方示例：",[77,7576,7578],{"className":79,"code":7577,"language":81,"meta":82,"style":82},"ros2 launch gz_ros2_control_demos diff_drive_example.launch.py\nros2 launch gz_ros2_control_demos cart_example_position.launch.py\nros2 launch gz_ros2_control_demos cart_example_velocity.launch.py\nros2 launch gz_ros2_control_demos cart_example_effort.launch.py\nros2 launch gz_ros2_control_demos mecanum_drive_example.launch.py\nros2 launch gz_ros2_control_demos ackermann_drive_example.launch.py\nros2 launch gz_ros2_control_demos tricycle_drive_example.launch.py\n",[29,7579,7580,7593,7604,7615,7626,7637,7648],{"__ignoreMap":82},[86,7581,7582,7584,7587,7590],{"class":88,"line":89},[86,7583,452],{"class":92},[86,7585,7586],{"class":304}," launch",[86,7588,7589],{"class":304}," gz_ros2_control_demos",[86,7591,7592],{"class":304}," diff_drive_example.launch.py\n",[86,7594,7595,7597,7599,7601],{"class":88,"line":311},[86,7596,452],{"class":92},[86,7598,7586],{"class":304},[86,7600,7589],{"class":304},[86,7602,7603],{"class":304}," cart_example_position.launch.py\n",[86,7605,7606,7608,7610,7612],{"class":88,"line":354},[86,7607,452],{"class":92},[86,7609,7586],{"class":304},[86,7611,7589],{"class":304},[86,7613,7614],{"class":304}," cart_example_velocity.launch.py\n",[86,7616,7617,7619,7621,7623],{"class":88,"line":362},[86,7618,452],{"class":92},[86,7620,7586],{"class":304},[86,7622,7589],{"class":304},[86,7624,7625],{"class":304}," cart_example_effort.launch.py\n",[86,7627,7628,7630,7632,7634],{"class":88,"line":370},[86,7629,452],{"class":92},[86,7631,7586],{"class":304},[86,7633,7589],{"class":304},[86,7635,7636],{"class":304}," mecanum_drive_example.launch.py\n",[86,7638,7639,7641,7643,7645],{"class":88,"line":378},[86,7640,452],{"class":92},[86,7642,7586],{"class":304},[86,7644,7589],{"class":304},[86,7646,7647],{"class":304}," ackermann_drive_example.launch.py\n",[86,7649,7650,7652,7654,7656],{"class":88,"line":386},[86,7651,452],{"class":92},[86,7653,7586],{"class":304},[86,7655,7589],{"class":304},[86,7657,7658],{"class":304}," tricycle_drive_example.launch.py\n",[20,7660,7661],{},"這些示例文件安裝在：",[77,7663,7665],{"className":79,"code":7664,"language":81,"meta":82,"style":82},"/opt/ros/jazzy/share/gz_ros2_control_demos\n",[29,7666,7667],{"__ignoreMap":82},[86,7668,7669],{"class":88,"line":89},[86,7670,7664],{"class":92},[20,7672,7673],{},"比較重要的文件包括：",[97,7675,7676,7685],{},[100,7677,7678],{},[103,7679,7680,7683],{},[106,7681,7682],{"align":108},"文件",[106,7684,1341],{"align":108},[117,7686,7687,7697,7707,7717,7727],{},[103,7688,7689,7694],{},[122,7690,7691],{"align":108},[29,7692,7693],{},"urdf/test_diff_drive.xacro.urdf",[122,7695,7696],{"align":108},"Gazebo 差速底盤 URDF/xacro 示例",[103,7698,7699,7704],{},[122,7700,7701],{"align":108},[29,7702,7703],{},"config/diff_drive_controller.yaml",[122,7705,7706],{"align":108},"差速控制器參數示例",[103,7708,7709,7714],{},[122,7710,7711],{"align":108},[29,7712,7713],{},"launch/diff_drive_example.launch.py",[122,7715,7716],{"align":108},"差速底盤完整啓動示例",[103,7718,7719,7724],{},[122,7720,7721],{"align":108},[29,7722,7723],{},"urdf/test_mecanum_drive.xacro.urdf",[122,7725,7726],{"align":108},"麥克納姆底盤示例",[103,7728,7729,7734],{},[122,7730,7731],{"align":108},[29,7732,7733],{},"config/mecanum_drive_controller.yaml",[122,7735,7736],{"align":108},"麥克納姆控制器參數示例",[20,7738,7739],{},"學習 Gazebo 集成時，不要只看 launch 文件。更推薦按這個順序讀：",[4675,7741,7742,7753,7759],{},[37,7743,7744,7745,7747,7748,643,7750,7212],{},"先看 ",[29,7746,7693],{}," 中 ",[29,7749,1498],{},[29,7751,7752],{},"\u003Cgazebo>",[37,7754,7755,7756,7758],{},"再看 ",[29,7757,7703],{}," 中控制器參數。",[37,7760,7761,7762,7764],{},"最後看 ",[29,7763,7713],{}," 如何把機器人描述、Gazebo 和 spawner 連起來。",[20,7766,7767],{},"建議學習順序是：",[4675,7769,7770,7776,7779],{},[37,7771,7772,7773,7775],{},"先用 ",[29,7774,4799],{}," 跑通控制器。",[37,7777,7778],{},"再接 Gazebo。",[37,7780,7781],{},"最後接真實硬件。",[20,7783,7784],{},"這樣出錯時更容易定位問題。",[10,7786,7787],{"id":7787},"常見問題",[15,7789,7790],{"id":7790},"控制器加載失敗",[20,7792,7793],{},"優先檢查：",[77,7795,7796],{"className":79,"code":2834,"language":81,"meta":82,"style":82},[29,7797,7798],{"__ignoreMap":82},[86,7799,7800,7802,7804],{"class":88,"line":89},[86,7801,452],{"class":92},[86,7803,2760],{"class":304},[86,7805,2845],{"class":304},[20,7807,7808],{},"如果你的控制器類型不在列表裏，通常是：",[34,7810,7811,7814,7820,7830],{},[37,7812,7813],{},"插件 XML 沒有安裝；",[37,7815,7816,7819],{},[29,7817,7818],{},"pluginlib_export_plugin_description_file()"," 寫錯；",[37,7821,7822,7823,7825,7826,7829],{},"YAML 中 ",[29,7824,1635],{}," 字段和插件 XML 中的 ",[29,7827,7828],{},"name"," 不一致；",[37,7831,7832],{},"沒有 source 工作空間：",[77,7834,7836],{"className":79,"code":7835,"language":81,"meta":82,"style":82},"source install/setup.bash\n",[29,7837,7838],{"__ignoreMap":82},[86,7839,7840,7842],{"class":88,"line":89},[86,7841,433],{"class":343},[86,7843,7844],{"class":304}," install/setup.bash\n",[15,7846,7847],{"id":7847},"控制器激活失敗",[20,7849,7850],{},"查看接口：",[77,7852,7854],{"className":79,"code":7853,"language":81,"meta":82,"style":82},"ros2 control list_hardware_interfaces --verbose\nros2 control list_controllers --verbose\n",[29,7855,7856,7866],{"__ignoreMap":82},[86,7857,7858,7860,7862,7864],{"class":88,"line":89},[86,7859,452],{"class":92},[86,7861,2760],{"class":304},[86,7863,2826],{"class":304},[86,7865,2783],{"class":343},[86,7867,7868,7870,7872,7874],{"class":88,"line":311},[86,7869,452],{"class":92},[86,7871,2760],{"class":304},[86,7873,2780],{"class":304},[86,7875,2783],{"class":343},[20,7877,7878],{},"常見原因：",[34,7880,7881,7884,7887,7890,7893],{},[37,7882,7883],{},"控制器要的 command interface 不存在；",[37,7885,7886],{},"控制器要的 state interface 不存在；",[37,7888,7889],{},"另一個控制器已經佔用了同一個 command interface；",[37,7891,7892],{},"URDF 裏的 joint 名和 YAML 裏的 joint 名不一致；",[37,7894,7895],{},"硬件組件還沒有激活。",[15,7897,7899,7901],{"id":7898},"joint_states-沒有數據",[29,7900,642],{}," 沒有數據",[20,7903,7904],{},"檢查：",[77,7906,7908],{"className":79,"code":7907,"language":81,"meta":82,"style":82},"ros2 control list_controllers\nros2 topic echo /dynamic_joint_states\nros2 topic echo /joint_states\n",[29,7909,7910,7918,7929],{"__ignoreMap":82},[86,7911,7912,7914,7916],{"class":88,"line":89},[86,7913,452],{"class":92},[86,7915,2760],{"class":304},[86,7917,2763],{"class":304},[86,7919,7920,7922,7924,7926],{"class":88,"line":311},[86,7921,452],{"class":92},[86,7923,3438],{"class":304},[86,7925,4750],{"class":304},[86,7927,7928],{"class":304}," /dynamic_joint_states\n",[86,7930,7931,7933,7935,7937],{"class":88,"line":354},[86,7932,452],{"class":92},[86,7934,3438],{"class":304},[86,7936,4750],{"class":304},[86,7938,4753],{"class":304},[20,7940,7878],{},[34,7942,7943,7948,7951,7957],{},[37,7944,7945,7946,238],{},"沒有啓動 ",[29,7947,633],{},[37,7949,7950],{},"硬件接口沒有 state interfaces；",[37,7952,7953,7956],{},[29,7954,7955],{},"use_urdf_to_filter=true"," 時，URDF 中沒有對應 joint；",[37,7958,7959,7960,7962],{},"硬件 ",[29,7961,1350],{}," 沒有更新 state。",[15,7964,7966,7968],{"id":7965},"cmd_vel-發了但底盤不動",[29,7967,45],{}," 發了但底盤不動",[20,7970,1704,7971,7973,7974,2123],{},[29,7972,669],{}," 默認訂閲 ",[29,7975,3489],{},[77,7977,7979],{"className":79,"code":7978,"language":81,"meta":82,"style":82},"ros2 topic info /diff_drive_controller/cmd_vel\n",[29,7980,7981],{"__ignoreMap":82},[86,7982,7983,7985,7987,7989],{"class":88,"line":89},[86,7984,452],{"class":92},[86,7986,3438],{"class":304},[86,7988,5097],{"class":304},[86,7990,7991],{"class":304}," /diff_drive_controller/cmd_vel\n",[20,7993,7994],{},"確認消息類型是：",[77,7996,7998],{"className":79,"code":7997,"language":81,"meta":82,"style":82},"geometry_msgs/msg/TwistStamped\n",[29,7999,8000],{"__ignoreMap":82},[86,8001,8002],{"class":88,"line":89},[86,8003,7997],{"class":92},[20,8005,8006],{},"還要檢查：",[34,8008,8009,8014,8017,8022,8031,8037],{},[37,8010,8011,8012,238],{},"話題名是不是 ",[29,8013,1400],{},[37,8015,8016],{},"控制器是否 active；",[37,8018,3900,8019,8021],{},[29,8020,655],{}," command interface 是否存在；",[37,8023,8024,151,8027,8030],{},[29,8025,8026],{},"left_wheel_names",[29,8028,8029],{},"right_wheel_names"," 是否寫對；",[37,8032,8033,8036],{},[29,8034,8035],{},"cmd_vel_timeout"," 是否太短；",[37,8038,8039,8040,8042],{},"真機硬件接口 ",[29,8041,1376],{}," 是否真的把命令發給電機。",[15,8044,8045],{"id":8045},"里程計方向不對",[20,8047,7793],{},[34,8049,8050,8053,8056,8062,8067,8070],{},[37,8051,8052],{},"左右輪 joint 是否寫反；",[37,8054,8055],{},"輪子正方向是否與 URDF 軸方向一致；",[37,8057,8058,8061],{},[29,8059,8060],{},"wheel_radius"," 是否正確；",[37,8063,8064,8061],{},[29,8065,8066],{},"wheel_separation",[37,8068,8069],{},"編碼器位置單位是否是弧度；",[37,8071,8072],{},"硬件接口中的速度單位是否是 rad/s。",[15,8074,8076],{"id":8075},"tf-衝突","TF 衝突",[20,8078,8079,8080,8082,8083,8085],{},"如果系統中已有其他節點發布 ",[29,8081,3101],{},"，不要再讓 ",[29,8084,669],{}," 發佈同一段 TF：",[77,8087,8089],{"className":2126,"code":8088,"language":2128,"meta":82,"style":82},"diff_drive_controller:\n  ros__parameters:\n    enable_odom_tf: false\n",[29,8090,8091,8097,8103],{"__ignoreMap":82},[86,8092,8093,8095],{"class":88,"line":89},[86,8094,669],{"class":1224},[86,8096,2137],{"class":1220},[86,8098,8099,8101],{"class":88,"line":311},[86,8100,2142],{"class":1224},[86,8102,2137],{"class":1220},[86,8104,8105,8107,8109],{"class":88,"line":354},[86,8106,3329],{"class":1224},[86,8108,2152],{"class":1220},[86,8110,3022],{"class":343},[10,8112,8113],{"id":8113},"學習路線建議",[20,8115,8116],{},"建議按下面順序學習：",[4675,8118,8119,8122,8130,8135,8140,8145,8151,8159,8162],{},[37,8120,8121],{},"看懂 command interface 和 state interface。",[37,8123,8124,8125,8127,8128,1307],{},"用 ",[29,8126,4799],{}," 跑通 ",[29,8129,633],{},[37,8131,8124,8132,8134],{},[29,8133,726],{}," 直接寫關節命令。",[37,8136,8124,8137,8139],{},[29,8138,669],{}," 跑通差速底盤。",[37,8141,8124,8142,8144],{},[29,8143,694],{}," 跑通機械臂或多關節模型。",[37,8146,8147,8148,8150],{},"寫一個最小 ",[29,8149,4911],{},"，先只打印命令。",[37,8152,8153,8154,8156,8157,1307],{},"接真實串口/CAN，讓 ",[29,8155,1350],{}," 更新 ",[29,8158,642],{},[37,8160,8161],{},"再接官方控制器。",[37,8163,8164],{},"最後再寫自定義運動學控制器。",[20,8166,8167],{},"不要一開始就同時寫硬件接口、運動學控制器、仿真插件和導航。這樣一旦出錯，很難判斷是 URDF、YAML、控制器、硬件接口還是底層通信的問題。",[10,8169,8170],{"id":8170},"參考資料",[34,8172,8173,8182,8189,8196,8203,8210,8217,8224,8231],{},[37,8174,8175,8176],{},"ROS2 Control Jazzy 官方文檔：",[8177,8178,8179],"a",{"href":8179,"rel":8180},"https://control.ros.org/jazzy/index.html",[8181],"nofollow",[37,8183,8184,8185],{},"Getting Started：",[8177,8186,8187],{"href":8187,"rel":8188},"https://control.ros.org/jazzy/doc/getting_started/getting_started.html",[8181],[37,8190,8191,8192],{},"Controller Manager：",[8177,8193,8194],{"href":8194,"rel":8195},"https://control.ros.org/jazzy/doc/ros2_control/controller_manager/doc/userdoc.html",[8181],[37,8197,8198,8199],{},"Hardware Interface：",[8177,8200,8201],{"href":8201,"rel":8202},"https://control.ros.org/jazzy/doc/ros2_control/hardware_interface/doc/hardware_interface_types_userdoc.html",[8181],[37,8204,8205,8206],{},"Joint State Broadcaster：",[8177,8207,8208],{"href":8208,"rel":8209},"https://control.ros.org/jazzy/doc/ros2_controllers/joint_state_broadcaster/doc/userdoc.html",[8181],[37,8211,8212,8213],{},"Diff Drive Controller：",[8177,8214,8215],{"href":8215,"rel":8216},"https://control.ros.org/jazzy/doc/ros2_controllers/diff_drive_controller/doc/userdoc.html",[8181],[37,8218,8219,8220],{},"Joint Trajectory Controller：",[8177,8221,8222],{"href":8222,"rel":8223},"https://control.ros.org/jazzy/doc/ros2_controllers/joint_trajectory_controller/doc/userdoc.html",[8181],[37,8225,8226,8227],{},"ros2_control GitHub：",[8177,8228,8229],{"href":8229,"rel":8230},"https://github.com/ros-controls/ros2_control",[8181],[37,8232,8233,8234],{},"ros2_controllers GitHub：",[8177,8235,8236],{"href":8236,"rel":8237},"https://github.com/ros-controls/ros2_controllers",[8181],[8239,8240,8241],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":82,"searchDepth":311,"depth":311,"links":8243},[8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257],{"id":12,"depth":354,"text":13},{"id":284,"depth":354,"text":285},{"id":1097,"depth":354,"text":1098},{"id":1488,"depth":354,"text":1489},{"id":2090,"depth":354,"text":2091},{"id":2469,"depth":354,"text":2469},{"id":2913,"depth":354,"text":2913},{"id":4258,"depth":354,"text":4259},{"id":4767,"depth":354,"text":4767},{"id":5972,"depth":354,"text":5972},{"id":7204,"depth":354,"text":7205},{"id":7787,"depth":354,"text":7787},{"id":8113,"depth":354,"text":8113},{"id":8170,"depth":354,"text":8170},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control","15",15000000,"2023-12-30","wiki/2023-12-30-ros2-tutorial","zh-hk:2023-12-30-ros2-tutorial","/zh-hk/wiki/2023-12-30-ros2-tutorial","Ros2 Tutorial","md","wiki/2023-12-30-ros2-tutorial/ch15-ROS2_Control",false,null,"zh-HK","zh-hk",{},{"title":5,"description":82},"/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch15-ROS2_Control","sdfMVm3MgdGdvwLz5V8so2-sT_jjeMFn5ngre-FuRiA",[8278,8283,8289,8295,8301,8307,8313,8319,8325,8331,8337,8343,8349,8355,8361,8367,8373,8379,8384,8390,8395,8401,8407,8413,8419,8425,8431,8437,8443,8449,8455,8461,8467,8473,8479,8485,8491,8497,8503,8509,8515,8521,8527,8533,8539,8545,8546,8552,8558,8564,8570,8575,8581,8586,8592,8598,8604,8610,8616,8622],{"path":8279,"stem":8280,"title":8281,"date":8261,"chapter":6575,"chapterSort":8282,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch1-ros2-jie-shao","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch1-ROS2介绍","ROS2介紹",1000000,{"path":8284,"stem":8285,"title":8286,"date":8261,"chapter":8287,"chapterSort":8288,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch10-stage-ros2-fang-zhen-ping-tai","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch10-Stage_Ros2仿真平台","Stage_Ros2仿真平台","10",10000000,{"path":8290,"stem":8291,"title":8292,"date":8261,"chapter":8293,"chapterSort":8294,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-1-gazeboclassic","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-1-GazeboClassic","Gezebo Classic","11.1",11010000,{"path":8296,"stem":8297,"title":8298,"date":8261,"chapter":8299,"chapterSort":8300,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-2-ignitiongazebo","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-2-IgnitionGazebo","Ignition Gazebo（Gazebo Fortress）","11.2",11020000,{"path":8302,"stem":8303,"title":8304,"date":8261,"chapter":8305,"chapterSort":8306,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-3-gazebosim","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-3-GazeboSim","Gz Sim（Gazebo Harmonic）","11.3",11030000,{"path":8308,"stem":8309,"title":8310,"date":8261,"chapter":8311,"chapterSort":8312,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-4-igngz2gzsim","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-4-Igngz2gzsim","將Ign Gazebo遷移至Gz Sim","11.4",11040000,{"path":8314,"stem":8315,"title":8316,"date":8261,"chapter":8317,"chapterSort":8318,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-gezebo-fang-zhen-ping-tai","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch11-Gezebo仿真平台","Gezebo仿真平台","11",11000000,{"path":8320,"stem":8321,"title":8322,"date":8261,"chapter":8323,"chapterSort":8324,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-1-humble-ban-ben","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-1-Humble版本","Humble導航仿真","12.1",12010000,{"path":8326,"stem":8327,"title":8328,"date":8261,"chapter":8329,"chapterSort":8330,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-2-jazzy-ban-ben","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-2-Jazzy版本","Jazzy導航仿真","12.2",12020000,{"path":8332,"stem":8333,"title":8334,"date":8261,"chapter":8335,"chapterSort":8336,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-3-humble2jazzy","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-3-Humble2Jazzy","Humble與Jazzy導航的差異","12.3",12030000,{"path":8338,"stem":8339,"title":8340,"date":8261,"chapter":8341,"chapterSort":8342,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-ji-qi-ren-dao-hang-navigation2-fang-zhen-pian","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch12-机器人导航Navigation2(仿真篇)","機器人導航Navigation2(仿真篇)","12",12000000,{"path":8344,"stem":8345,"title":8346,"date":8261,"chapter":8347,"chapterSort":8348,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-1-1-boost-aiso","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-1-1-Boost.Aiso","Boost.Asio庫","13.1.1",13010100,{"path":8350,"stem":8351,"title":8352,"date":8261,"chapter":8353,"chapterSort":8354,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-1-2-ros2-serial-driver","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-1-2-ros2_serial_driver","ROS2 Serial Driver庫","13.1.2",13010200,{"path":8356,"stem":8357,"title":8358,"date":8261,"chapter":8359,"chapterSort":8360,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-1-chuan-kou-tong-xin","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-1-串口通信","UART串口通信","13.1",13010000,{"path":8362,"stem":8363,"title":8364,"date":8261,"chapter":8365,"chapterSort":8366,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-2-1-socketcan","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-2-1-socketcan","SocketCAN","13.2.1",13020100,{"path":8368,"stem":8369,"title":8370,"date":8261,"chapter":8371,"chapterSort":8372,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-2-2-ros2-socketcan","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-2-2-ros2_socketcan","ROS2_SocketCAN","13.2.2",13020200,{"path":8374,"stem":8375,"title":8376,"date":8261,"chapter":8377,"chapterSort":8378,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-2-can-tong-xin","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-2-CAN通信","CAN通信","13.2",13020000,{"path":8380,"stem":8381,"title":8346,"date":8261,"chapter":8382,"chapterSort":8383,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-3-1-boost-aiso","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-3-1-Boost.Aiso","13.3.1",13030100,{"path":8385,"stem":8386,"title":8387,"date":8261,"chapter":8388,"chapterSort":8389,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-3-tcp-tong-xin","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-3-TCP通信","TCP通信","13.3",13030000,{"path":8391,"stem":8392,"title":8346,"date":8261,"chapter":8393,"chapterSort":8394,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-4-1-boost-aiso","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-4-1-Boost.Aiso","13.4.1",13040100,{"path":8396,"stem":8397,"title":8398,"date":8261,"chapter":8399,"chapterSort":8400,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-4-udp-tong-xin","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-4-UDP通信","UDP通信","13.4",13040000,{"path":8402,"stem":8403,"title":8404,"date":8261,"chapter":8405,"chapterSort":8406,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-linux-ying-jian-tong-xin","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch13-Linux硬件通信","Linux硬件通信","13",13000000,{"path":8408,"stem":8409,"title":8410,"date":8261,"chapter":8411,"chapterSort":8412,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-1-ji-qi-ren-zu-cheng","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-1-机器人组成","機器人組成","14.1",14010000,{"path":8414,"stem":8415,"title":8416,"date":8261,"chapter":8417,"chapterSort":8418,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-2-1-yuan-cheng-kai-fa-ssh","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-2-1-远程开发SSH","遠程開發SSH","14.2.1",14020100,{"path":8420,"stem":8421,"title":8422,"date":8261,"chapter":8423,"chapterSort":8424,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-2-2-yuan-cheng-fang-wen-zhuo-mian","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-2-2-远程访问桌面","遠程訪問桌面","14.2.2",14020200,{"path":8426,"stem":8427,"title":8428,"date":8261,"chapter":8429,"chapterSort":8430,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-2-gong-kong-ji-zhi-yuan-cheng-kai-fa-huan-jing","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-2-工控机之远程开发环境","工控機之遠程開發環境","14.2",14020000,{"path":8432,"stem":8433,"title":8434,"date":8261,"chapter":8435,"chapterSort":8436,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-3-gong-kong-ji-zhi-wai-jie-usb-she-bei","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-3-工控机之外接USB设备","工控機之外接USB設備","14.3",14030000,{"path":8438,"stem":8439,"title":8440,"date":8261,"chapter":8441,"chapterSort":8442,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-4-fen-bu-shi-da-jian","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-4-分布式搭建","分佈式搭建","14.4",14040000,{"path":8444,"stem":8445,"title":8446,"date":8261,"chapter":8447,"chapterSort":8448,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-5-you-hua-ri-zhi","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-5-优化日志","優化日誌","14.5",14050000,{"path":8450,"stem":8451,"title":8452,"date":8261,"chapter":8453,"chapterSort":8454,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-1-li-cheng-ji-odom","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-1-里程计Odom","里程計Odom","14.6.1",14060100,{"path":8456,"stem":8457,"title":8458,"date":8261,"chapter":8459,"chapterSort":8460,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-2-guan-xing-ji-imu","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-2-惯性计IMU","慣性計IMU","14.6.2",14060200,{"path":8462,"stem":8463,"title":8464,"date":8261,"chapter":8465,"chapterSort":8466,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-3-ji-guang-lei-da-lidar","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-3-激光雷达LiDAR","激光雷達LiDAR","14.6.3",14060300,{"path":8468,"stem":8469,"title":8470,"date":8261,"chapter":8471,"chapterSort":8472,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-4-xiang-ji-camera","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-4-相机Camera","相機Camera","14.6.4",14060400,{"path":8474,"stem":8475,"title":8476,"date":8261,"chapter":8477,"chapterSort":8478,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-5-quan-qiu-ding-wei-gnss","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-5-全球定位GNSS","全球定位GNSS","14.6.5",14060500,{"path":8480,"stem":8481,"title":8482,"date":8261,"chapter":8483,"chapterSort":8484,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-6-shou-bing-joy","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-6-手柄joy","手柄JOY","14.6.6",14060600,{"path":8486,"stem":8487,"title":8488,"date":8261,"chapter":8489,"chapterSort":8490,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-7-jian-pan-kong-zhi-jie-dian","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-7-键盘控制节点","鍵盤控制節點","14.6.7",14060700,{"path":8492,"stem":8493,"title":8494,"date":8261,"chapter":8495,"chapterSort":8496,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-ying-jian-ping-tai","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-6-硬件平台","硬件平台","14.6",14060000,{"path":8498,"stem":8499,"title":8500,"date":8261,"chapter":8501,"chapterSort":8502,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-7-zuo-biao-xi-yu-hua-ti-guan-xi","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-7-坐标系与话题关系","座標系與話題關係","14.7",14070000,{"path":8504,"stem":8505,"title":8506,"date":8261,"chapter":8507,"chapterSort":8508,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-1-1-lun-shi-li-cheng-ji-biao-ding","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-1-1-轮式里程计标定","輪式里程計標定","14.8.1.1",14080101,{"path":8510,"stem":8511,"title":8512,"date":8261,"chapter":8513,"chapterSort":8514,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-1-2-lun-shi-li-cheng-ji-yu-imu-rong-he","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-1-2-轮式里程计与IMU融合","輪式里程計與IMU融合","14.8.1.2",14080102,{"path":8516,"stem":8517,"title":8518,"date":8261,"chapter":8519,"chapterSort":8520,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-1-lun-shi-li-cheng-ji-biao-ding-yu-rong-he","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-1-轮式里程计标定与融合","輪式里程計標定與融合","14.8.1",14080100,{"path":8522,"stem":8523,"title":8524,"date":8261,"chapter":8525,"chapterSort":8526,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-2-ji-guang-lei-da-gong-ju","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-2-激光雷达工具","激光雷達工具","14.8.2",14080200,{"path":8528,"stem":8529,"title":8530,"date":8261,"chapter":8531,"chapterSort":8532,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-3-xiang-ji-shi-yong-jin-jie","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-3-相机使用进阶","相機使用進階","14.8.3",14080300,{"path":8534,"stem":8535,"title":8536,"date":8261,"chapter":8537,"chapterSort":8538,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-ying-jian-ping-tai-jin-jie","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-8-硬件平台进阶","硬件平台進階","14.8",14080000,{"path":8540,"stem":8541,"title":8542,"date":8261,"chapter":8543,"chapterSort":8544,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-ji-qi-ren-ying-jian","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch14-机器人硬件","機器人硬件","14",14000000,{"path":8258,"stem":8275,"title":5,"date":8261,"chapter":8259,"chapterSort":8260,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},{"path":8547,"stem":8548,"title":8549,"date":8261,"chapter":8550,"chapterSort":8551,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch16-moveit2-gong-ye-ji-qi-ren-ji-xie-bi","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch16-Moveit2工业机器人机械臂","Moveit2工業機器人機械臂","16",16000000,{"path":8553,"stem":8554,"title":8555,"date":8261,"chapter":8556,"chapterSort":8557,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch17-ji-qi-ren-dao-hang-navigation2-shi-ti-pian","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch17-机器人导航Navigation2(实体篇)","機器人導航Navigation2(實體篇)","17",17000000,{"path":8559,"stem":8560,"title":8561,"date":8261,"chapter":8562,"chapterSort":8563,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch18-microros","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch18-MicroROS","MicroROS","18",18000000,{"path":8565,"stem":8566,"title":8567,"date":8261,"chapter":8568,"chapterSort":8569,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch19-webots-fang-zhen-ping-tai","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch19-Webots仿真平台","Webots仿真平台","19",19000000,{"path":8571,"stem":8572,"title":8573,"date":8261,"chapter":6593,"chapterSort":8574,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch2-ru-men-cao-zuo","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch2-入门操作","入門操作",2000000,{"path":8576,"stem":8577,"title":8578,"date":8261,"chapter":8579,"chapterSort":8580,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch20-opencv","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch20-OpenCV","OpenCV","20",20000000,{"path":8582,"stem":8583,"title":8584,"date":8261,"chapter":6610,"chapterSort":8585,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch3-gong-zuo-kong-jian-yu-gong-neng-bao","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch3-工作空间与功能包","工作空間與功能包",3000000,{"path":8587,"stem":8588,"title":8589,"date":8261,"chapter":8590,"chapterSort":8591,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch4-si-da-tong-xin","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch4-四大通信","四大通信","4",4000000,{"path":8593,"stem":8594,"title":8595,"date":8261,"chapter":8596,"chapterSort":8597,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch5-ros2-qi-ta-tong-xin-ji-zhi","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch5-ROS2其他通信机制","ROS2其他通信機制","5",5000000,{"path":8599,"stem":8600,"title":8601,"date":8261,"chapter":8602,"chapterSort":8603,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch6-launch","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch6-Launch","Launch","6",6000000,{"path":8605,"stem":8606,"title":8607,"date":8261,"chapter":8608,"chapterSort":8609,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch7-hui-su-rosbag2","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch7-回溯rosbag2","回溯rosbag2","7",7000000,{"path":8611,"stem":8612,"title":8613,"date":8261,"chapter":8614,"chapterSort":8615,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch8-坐标变换TF","座標變換TF","8",8000000,{"path":8617,"stem":8618,"title":8619,"date":8261,"chapter":8620,"chapterSort":8621,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":8268},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch9-ke-shi-hua-ping-tai-rviz2-yu-urdf-jian-mo-yu-yan","_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/ch9-可视化平台RVIZ2与URDF建模语言","可視化平台RVIZ2與URDF建模語言","9",9000000,{"path":8264,"stem":8623,"title":8624,"date":8261,"chapter":8269,"chapterSort":8625,"docKey":8263,"docRoot":8264,"docTitle":8265,"isWikiDoc":1568,"isWikiIndex":1568},"_i18n/zh-hk/wiki/2023-12-30-ros2-tutorial/index","ROS2機器人操作系統教程",0,{"variants":8627},[8628,8631,8634,8635,8638],{"path":8629,"localeSlug":8630,"i18nKey":8267},"/en-us/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control","en-us",{"path":8632,"localeSlug":8633,"i18nKey":8267},"/zh-hant/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control","zh-hant",{"path":8258,"localeSlug":8271,"i18nKey":8267},{"path":8636,"localeSlug":8637,"i18nKey":8267},"/zh-tw/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control","zh-tw",{"path":8639,"localeSlug":8640,"i18nKey":8267},"/zh-cn/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control","zh-cn",[8629,8274,8632,8274,8258,8274,8636,8274,8639,8274],1780671867114]