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