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