[{"data":1,"prerenderedAt":7319},["ShallowReactive",2],{"wiki-page-/en-us/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf":3,"wiki-doc-items-/en-us/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf":6959,"language-switcher-data-/en-us/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf":7303,"wiki-i18n-paths-/en-us/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf":7318},{"id":4,"title":5,"body":6,"canonicalPath":6941,"chapter":1880,"chapterSort":6942,"date":6943,"description":25,"docI18nKey":6944,"docKey":6945,"docRoot":6946,"docTitle":6947,"extension":6948,"i18nKey":6949,"isBlogPost":6950,"isWikiDoc":143,"isWikiIndex":6950,"layout":6951,"legacyPath":6951,"locale":6952,"localeSlug":6953,"meta":6954,"navigation":143,"path":6941,"seo":6955,"sourcePath":6956,"sourceStem":6949,"stem":6957,"wikiDepth":140,"__hash__":6958},"content/_i18n/en-us/wiki/2023-12-30-ros2-tutorial/ch8-坐标变换TF.md","Coordinate Transformation TF",{"type":7,"value":8,"toc":6933},"minimark",[9,14,19,27,36,43,50,57,60,65,70,73,76,81,84,88,93,100,108,113,118,121,125,128,204,209,220,278,283,286,305,308,311,329,336,341,344,348,358,361,365,368,386,389,560,563,566,569,572,575,578,581,584,594,597,603,608,613,618,621,626,629,634,637,639,655,657,734,737,741,745,754,757,760,763,768,771,775,781,786,792,797,801,804,814,818,821,838,841,844,848,855,897,900,903,906,913,917,921,932,937,940,1000,1005,1008,1013,1016,1019,1026,1029,1034,1037,1096,1107,1111,1114,1139,1144,1149,1152,1155,1158,1162,1169,1187,1190,1195,1198,1201,1252,1255,1304,1309,1313,1317,1446,1450,2339,2344,2349,2352,2357,2360,2365,2368,2373,2376,2381,2384,2389,2392,2395,2400,2403,2422,2425,2467,2474,2479,2484,2487,2492,2495,2500,2505,2508,2513,2516,2521,2524,2528,2531,2534,2579,2585,2608,2611,3342,3347,3350,3353,3356,3359,3364,3369,3374,3377,3382,3386,3390,3395,3401,3406,3411,3417,3422,3425,3439,3441,3443,3488,3492,3519,3523,4058,4063,4070,4075,4080,4082,4120,4123,4147,4152,4159,4164,4169,4172,4176,4181,4184,4187,4190,4194,4197,4206,4211,4219,4224,4228,4231,4235,4238,4250,4252,4257,4262,4298,4306,4309,4314,4317,4322,4325,4328,4331,4334,4339,4342,4345,4348,4351,5025,5030,5033,5038,5043,5049,5052,5055,5058,5063,5066,5071,5074,5079,5082,5087,5094,5099,5104,5107,5110,5143,5145,5176,5179,5202,5205,5210,5215,5218,5223,5228,5231,5237,5241,5246,5249,5254,5259,5266,5269,5280,5286,5374,5377,5536,5539,6323,6328,6331,6336,6341,6346,6349,6354,6357,6360,6365,6368,6406,6408,6430,6433,6457,6460,6463,6468,6473,6477,6485,6491,6503,6508,6513,6525,6530,6540,6543,6589,6592,6638,6641,6657,6660,6674,6677,6701,6706,6709,6713,6718,6721,6737,6742,6747,6750,6753,6756,6760,6762,6782,6786,6791,6794,6798,6801,6803,6825,6829,6834,6837,6845,6850,6853,6857,6860,6862,6879,6893,6898,6901,6906,6911,6914,6918,6922,6926,6929],[10,11,13],"h3",{"id":12},"coordinate-transformation","coordinate transformation",[15,16,18],"h4",{"id":17},"introduction-and-application-scenarios","Introduction and Application Scenarios",[20,21,22],"p",{},[23,24],"img",{"alt":25,"src":26},"","https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1264.webp",[20,28,29],{},[30,31,32],"strong",{},[33,34,35],"code",{},"里程计ODOM",[20,37,38],{},[30,39,40],{},[33,41,42],{},"惯性计IMU",[20,44,45],{},[30,46,47],{},[33,48,49],{},"激光雷达Laser",[20,51,52],{},[30,53,54],{},[33,55,56],{},"摄像头Camera",[20,58,59],{},"Scenario 1: There is a mobile robot chassis with a radar installed on it. The offset of the radar relative to the chassis is known. The radar detects an obstacle and obtains coordinates (x, y, z), which are in the radar's reference frame. How can these coordinates be transformed into the chassis's reference frame?",[20,61,62],{},[23,63],{"alt":25,"src":64},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1265.webp",[20,66,67],{},[23,68],{"alt":25,"src":69},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1266.webp",[20,71,72],{},"The horizontal and vertical distances between the LiDAR and the center or edge of the car, as well as the distance from the LiDAR to the wall and the distance from the car to the wall.",[20,74,75],{},"Scenario 2: There is a robot with a robotic arm (e.g., PR2) that needs to grasp a target object. Currently, the robot's head-mounted camera can detect the coordinates (x, y, z) of the target object, but these coordinates are relative to the camera's reference frame. The actual operation of grasping the target object is performed by the gripper of the robotic arm. We need to convert these coordinates into coordinates relative to the robotic arm's gripper. How can this process be implemented?",[20,77,78],{},[23,79],{"alt":25,"src":80},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1267.webp",[20,82,83],{},"The above can be calculated using TF.",[15,85,87],{"id":86},"concept-and-function","Concept and Function",[20,89,90],{},[23,91],{"alt":25,"src":92},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1268.webp",[20,94,95,96,99],{},"TF uses a ",[30,97,98],{},"right-handed coordinate system",".",[20,101,102,105],{},[23,103],{"alt":25,"src":104},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1269.webp",[23,106],{"alt":25,"src":107},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1270.webp",[20,109,110],{},[23,111],{"alt":25,"src":112},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1271.webp",[20,114,115],{},[23,116],{"alt":25,"src":117},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1272.webp",[20,119,120],{},"What matters is the relative position and time — at a certain moment, a certain object is located at a certain position. (If the time difference is too large, the data will be discarded.)",[15,122,124],{"id":123},"case-installation-and-running","Case Installation and Running",[20,126,127],{},"Install the Turtle example:",[129,130,134],"pre",{"className":131,"code":132,"language":133,"meta":25,"style":25},"language-bash shiki shiki-themes github-light github-dark","\n# Humble版本安装\nsudo apt-get install ros-humble-turtle-tf2-py ros-humble-tf2-tools ros-humble-tf-transformations\n\n# Jazzy版本安装\nsudo apt-get install ros-jazzy-turtle-tf2-py ros-jazzy-tf2-tools ros-jazzy-tf-transformations\n","bash",[33,135,136,145,152,175,180,186],{"__ignoreMap":25},[137,138,141],"span",{"class":139,"line":140},"line",1,[137,142,144],{"emptyLinePlaceholder":143},true,"\n",[137,146,148],{"class":139,"line":147},2,[137,149,151],{"class":150},"sJ8bj","# Humble版本安装\n",[137,153,155,159,163,166,169,172],{"class":139,"line":154},3,[137,156,158],{"class":157},"sScJk","sudo",[137,160,162],{"class":161},"sZZnC"," apt-get",[137,164,165],{"class":161}," install",[137,167,168],{"class":161}," ros-humble-turtle-tf2-py",[137,170,171],{"class":161}," ros-humble-tf2-tools",[137,173,174],{"class":161}," ros-humble-tf-transformations\n",[137,176,178],{"class":139,"line":177},4,[137,179,144],{"emptyLinePlaceholder":143},[137,181,183],{"class":139,"line":182},5,[137,184,185],{"class":150},"# Jazzy版本安装\n",[137,187,189,191,193,195,198,201],{"class":139,"line":188},6,[137,190,158],{"class":157},[137,192,162],{"class":161},[137,194,165],{"class":161},[137,196,197],{"class":161}," ros-jazzy-turtle-tf2-py",[137,199,200],{"class":161}," ros-jazzy-tf2-tools",[137,202,203],{"class":161}," ros-jazzy-tf-transformations\n",[20,205,206],{},[23,207],{"alt":25,"src":208},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1273.webp",[20,210,211,212,215,216,219],{},"Additionally, you need to install a Python package called ",[33,213,214],{},"transforms3d",", which provides quaternion and Euler angle transformation functions for the ",[33,217,218],{},"tf_transformations"," package. The installation command is as follows:",[129,221,223],{"className":131,"code":222,"language":133,"meta":25,"style":25},"\n# 方式一（不推荐）\nsudo apt intall python3-pip\npip3 install transforms3d\n\n#方式二（推荐）\nsudo apt install python3-transforms3d\n",[33,224,225,229,234,247,257,261,266],{"__ignoreMap":25},[137,226,227],{"class":139,"line":140},[137,228,144],{"emptyLinePlaceholder":143},[137,230,231],{"class":139,"line":147},[137,232,233],{"class":150},"# 方式一（不推荐）\n",[137,235,236,238,241,244],{"class":139,"line":154},[137,237,158],{"class":157},[137,239,240],{"class":161}," apt",[137,242,243],{"class":161}," intall",[137,245,246],{"class":161}," python3-pip\n",[137,248,249,252,254],{"class":139,"line":177},[137,250,251],{"class":157},"pip3",[137,253,165],{"class":161},[137,255,256],{"class":161}," transforms3d\n",[137,258,259],{"class":139,"line":182},[137,260,144],{"emptyLinePlaceholder":143},[137,262,263],{"class":139,"line":188},[137,264,265],{"class":150},"#方式二（推荐）\n",[137,267,269,271,273,275],{"class":139,"line":268},7,[137,270,158],{"class":157},[137,272,240],{"class":161},[137,274,165],{"class":161},[137,276,277],{"class":161}," python3-transforms3d\n",[20,279,280],{},[23,281],{"alt":25,"src":282},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1274.webp",[20,284,285],{},"Open two terminals. In terminal 1, enter the following command:",[129,287,289],{"className":131,"code":288,"language":133,"meta":25,"style":25},"ros2 launch turtle_tf2_py turtle_tf2_demo.launch.py\n",[33,290,291],{"__ignoreMap":25},[137,292,293,296,299,302],{"class":139,"line":140},[137,294,295],{"class":157},"ros2",[137,297,298],{"class":161}," launch",[137,300,301],{"class":161}," turtle_tf2_py",[137,303,304],{"class":161}," turtle_tf2_demo.launch.py\n",[20,306,307],{},"This command will start the turtlesim_node node, which comes with a small turtle named turtle1. In addition, it will spawn a new turtle named turtle2, and turtle2 will move to turtle1's position.",[20,309,310],{},"Enter the following command in terminal 2:",[129,312,314],{"className":131,"code":313,"language":133,"meta":25,"style":25},"ros2 run turtlesim turtle_teleop_key\n",[33,315,316],{"__ignoreMap":25},[137,317,318,320,323,326],{"class":139,"line":140},[137,319,295],{"class":157},[137,321,322],{"class":161}," run",[137,324,325],{"class":161}," turtlesim",[137,327,328],{"class":161}," turtle_teleop_key\n",[20,330,331,332,335],{},"In this terminal, you can control the movement of turtle1 using the keyboard, and turtle2 will follow turtle1's movement (refer to ",[30,333,334],{},"Case 1"," in the introduction section).",[20,337,338],{},[23,339],{"alt":25,"src":340},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1275.webp",[20,342,343],{},"A male turtle 🐢🚹 will follow the movement of the turtle ahead 🐢.",[15,345,347],{"id":346},"coordinate-transformation-related-messages","Coordinate transformation related messages",[20,349,350,351,354,355,99],{},"The implementation of coordinate transformation is essentially based on the publish-subscribe model of topic communication. The publisher can publish the relative relationships between coordinate frames, while the subscriber can listen to these messages and perform transformations between different coordinate frames. Clearly, as introduced earlier, interface messages serve as the data carrier and play a crucial role in the topic communication model. This section will introduce two commonly used interface messages in coordinate transformation: ",[33,352,353],{},"geometry_msgs/msg/TransformStamped"," and ",[33,356,357],{},"geometry_msgs/msg/PointStamped",[20,359,360],{},"The former is an interface used to describe the relative relationship between two coordinate systems at a given moment, while the latter is an interface used to describe the position of a coordinate point within a coordinate system at a given moment. In coordinate transformations, the relative relationships between coordinate systems and coordinate point information are frequently used.",[362,363,353],"h5",{"id":364},"geometry_msgsmsgtransformstamped",[20,366,367],{},"View the interface definition using the following command:",[129,369,371],{"className":131,"code":370,"language":133,"meta":25,"style":25},"ros2 interface show geometry_msgs/msg/TransformStamped\n",[33,372,373],{"__ignoreMap":25},[137,374,375,377,380,383],{"class":139,"line":140},[137,376,295],{"class":157},[137,378,379],{"class":161}," interface",[137,381,382],{"class":161}," show",[137,384,385],{"class":161}," geometry_msgs/msg/TransformStamped\n",[20,387,388],{},"Interface Definition Explanation:",[129,390,392],{"className":131,"code":391,"language":133,"meta":25,"style":25},"std_msgs/Header header\n    builtin_interfaces/Time stamp     # 时间戳\n        int32 sec         #秒\n        uint32 nanosec    #纳秒\n    string frame_id                   # 父级坐标系\nstring child_frame_id                 # 子级坐标系\nTransform transform                   # 子级坐标系相对于父级坐标系的位姿\n    Vector3 translation               # 三维偏移量\n        float64 x\n        float64 y\n        float64 z\n    Quaternion rotation               # 四元数\n        float64 x 0\n        float64 y 0\n        float64 z 0\n        float64 w 1\n",[33,393,394,402,413,424,435,446,457,468,480,489,497,505,517,529,539,549],{"__ignoreMap":25},[137,395,396,399],{"class":139,"line":140},[137,397,398],{"class":157},"std_msgs/Header",[137,400,401],{"class":161}," header\n",[137,403,404,407,410],{"class":139,"line":147},[137,405,406],{"class":157},"    builtin_interfaces/Time",[137,408,409],{"class":161}," stamp",[137,411,412],{"class":150},"     # 时间戳\n",[137,414,415,418,421],{"class":139,"line":154},[137,416,417],{"class":157},"        int32",[137,419,420],{"class":161}," sec",[137,422,423],{"class":150},"         #秒\n",[137,425,426,429,432],{"class":139,"line":177},[137,427,428],{"class":157},"        uint32",[137,430,431],{"class":161}," nanosec",[137,433,434],{"class":150},"    #纳秒\n",[137,436,437,440,443],{"class":139,"line":182},[137,438,439],{"class":157},"    string",[137,441,442],{"class":161}," frame_id",[137,444,445],{"class":150},"                   # 父级坐标系\n",[137,447,448,451,454],{"class":139,"line":188},[137,449,450],{"class":157},"string",[137,452,453],{"class":161}," child_frame_id",[137,455,456],{"class":150},"                 # 子级坐标系\n",[137,458,459,462,465],{"class":139,"line":268},[137,460,461],{"class":157},"Transform",[137,463,464],{"class":161}," transform",[137,466,467],{"class":150},"                   # 子级坐标系相对于父级坐标系的位姿\n",[137,469,471,474,477],{"class":139,"line":470},8,[137,472,473],{"class":157},"    Vector3",[137,475,476],{"class":161}," translation",[137,478,479],{"class":150},"               # 三维偏移量\n",[137,481,483,486],{"class":139,"line":482},9,[137,484,485],{"class":157},"        float64",[137,487,488],{"class":161}," x\n",[137,490,492,494],{"class":139,"line":491},10,[137,493,485],{"class":157},[137,495,496],{"class":161}," y\n",[137,498,500,502],{"class":139,"line":499},11,[137,501,485],{"class":157},[137,503,504],{"class":161}," z\n",[137,506,508,511,514],{"class":139,"line":507},12,[137,509,510],{"class":157},"    Quaternion",[137,512,513],{"class":161}," rotation",[137,515,516],{"class":150},"               # 四元数\n",[137,518,520,522,525],{"class":139,"line":519},13,[137,521,485],{"class":157},[137,523,524],{"class":161}," x",[137,526,528],{"class":527},"sj4cs"," 0\n",[137,530,532,534,537],{"class":139,"line":531},14,[137,533,485],{"class":157},[137,535,536],{"class":161}," y",[137,538,528],{"class":527},[137,540,542,544,547],{"class":139,"line":541},15,[137,543,485],{"class":157},[137,545,546],{"class":161}," z",[137,548,528],{"class":527},[137,550,552,554,557],{"class":139,"line":551},16,[137,553,485],{"class":157},[137,555,556],{"class":161}," w",[137,558,559],{"class":527}," 1\n",[20,561,562],{},"Describing the motion of an object generally involves six degrees of freedom: X, Y, Z, Yaw, Pitch, and Roll.",[20,564,565],{},"Three translations, three rotations:",[20,567,568],{},"Vector3 translation represents 3 translations",[20,570,571],{},"A quaternion rotation can be converted into three Euler angles (yaw, pitch, roll).",[20,573,574],{},"(Q: Why use quaternions instead of Euler angles? A: Because calculations with Euler angles can lead to gimbal lock, quaternions are chosen instead to avoid that drawback.)",[20,576,577],{},"3 translations in meters",[20,579,580],{},"3 rotations in radians",[20,582,583],{},"Quaternions, similar to Euler angles, are used to represent the relative orientation of coordinate systems.",[20,585,586,587,99],{},"For specific conversion details, see Section 18.3 of the ",[588,589,593],"a",{"href":590,"rel":591},"https://sdutvincirobot.feishu.cn/wiki/PVS8wQzRgiTRqpko9l4cEK33nhw",[592],"nofollow","DJI Development Board Type C Embedded Software Tutorial Document.pdf",[20,595,596],{},"Specific transformation algorithm (Mahony algorithm) (the TF2 library in ROS2 also has a specific transformation algorithm):",[20,598,599],{},[588,600,601],{"href":601,"rel":602},"https://x-io.co.uk/open-source-imu-and-ahrs-algorithms/",[592],[20,604,605],{},[23,606],{"alt":25,"src":607},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1276.webp",[20,609,610],{},[23,611],{"alt":25,"src":612},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1277.webp",[20,614,615],{},[23,616],{"alt":25,"src":617},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1278.webp",[20,619,620],{},"From the perspective of the right-hand coordinate system, N2 is translated 1m along the X-axis relative to N1 (one grid represents 1 meter).",[20,622,623],{},[23,624],{"alt":25,"src":625},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1279.webp",[20,627,628],{},"Rotation",[20,630,631],{},[23,632],{"alt":25,"src":633},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1280.webp",[362,635,357],{"id":636},"geometry_msgsmsgpointstamped",[20,638,367],{},[129,640,642],{"className":131,"code":641,"language":133,"meta":25,"style":25},"ros2 interface show geometry_msgs/msg/PointStamped\n",[33,643,644],{"__ignoreMap":25},[137,645,646,648,650,652],{"class":139,"line":140},[137,647,295],{"class":157},[137,649,379],{"class":161},[137,651,382],{"class":161},[137,653,654],{"class":161}," geometry_msgs/msg/PointStamped\n",[20,656,388],{},[129,658,660],{"className":131,"code":659,"language":133,"meta":25,"style":25},"std_msgs/Header header\n    builtin_interfaces/Time stamp    # 时间戳\n        int32 sec   #秒\n        uint32 nanosec   #纳秒\n    string frame_id                  # 参考系\nPoint point                          # 三维坐标\n    float64 x\n    float64 y\n    float64 z\n",[33,661,662,668,677,686,695,704,715,722,728],{"__ignoreMap":25},[137,663,664,666],{"class":139,"line":140},[137,665,398],{"class":157},[137,667,401],{"class":161},[137,669,670,672,674],{"class":139,"line":147},[137,671,406],{"class":157},[137,673,409],{"class":161},[137,675,676],{"class":150},"    # 时间戳\n",[137,678,679,681,683],{"class":139,"line":154},[137,680,417],{"class":157},[137,682,420],{"class":161},[137,684,685],{"class":150},"   #秒\n",[137,687,688,690,692],{"class":139,"line":177},[137,689,428],{"class":157},[137,691,431],{"class":161},[137,693,694],{"class":150},"   #纳秒\n",[137,696,697,699,701],{"class":139,"line":182},[137,698,439],{"class":157},[137,700,442],{"class":161},[137,702,703],{"class":150},"                  # 参考系\n",[137,705,706,709,712],{"class":139,"line":188},[137,707,708],{"class":157},"Point",[137,710,711],{"class":161}," point",[137,713,714],{"class":150},"                          # 三维坐标\n",[137,716,717,720],{"class":139,"line":268},[137,718,719],{"class":157},"    float64",[137,721,488],{"class":161},[137,723,724,726],{"class":139,"line":470},[137,725,719],{"class":157},[137,727,496],{"class":161},[137,729,730,732],{"class":139,"line":482},[137,731,719],{"class":157},[137,733,504],{"class":161},[20,735,736],{},"Coordinate point in three dimensions",[10,738,740],{"id":739},"coordinate-transformation-broadcast","Coordinate transformation broadcast",[15,742,744],{"id":743},"introduction-and-case-studies-and-analysis","Introduction and Case Studies and Analysis",[20,746,747,748,354,751,99],{},"There are two main types of coordinate system relationships: ",[30,749,750],{},"static coordinate system relationships",[30,752,753],{},"dynamic coordinate system relationships",[20,755,756],{},"The so-called static coordinate system relationship refers to a fixed relative position between two coordinate systems. For example, components such as radar and cameras on a vehicle are typically fixed, so the radar coordinate system relative to the vehicle chassis coordinate system, or the camera coordinate system relative to the vehicle chassis coordinate system, represents a static relationship.",[20,758,759],{},"The so-called dynamic coordinate system relative relationship refers to the relative positional relationship between two coordinate systems that changes dynamically. For example, the joints or grippers of a robotic arm on a vehicle, or different vehicles in a multi-vehicle formation, can all move. In such cases, the relative relationship between the coordinate system of a robotic arm's joint or gripper and the vehicle chassis coordinate system, or between different vehicle coordinate systems, is a dynamic relationship.",[20,761,762],{},"This section will primarily introduce how to implement static coordinate transform broadcasting and dynamic coordinate transform broadcasting. Additionally, this section will also demonstrate how to publish coordinate point messages.",[20,764,765],{},[23,766],{"alt":25,"src":767},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1281.webp",[20,769,770],{},"The LiDAR laser and camera are statically positioned relative to the chassis, while the robot arm's end effector and the robot's position are dynamic.",[362,772,774],{"id":773},"_1-case-requirements","1. Case Requirements",[20,776,777,780],{},[30,778,779],{},"Case 1:"," There is an unmanned vehicle with a fixed radar and camera mounted on its chassis. The vehicle chassis, radar, and camera each have their own coordinate systems, with the origin of each system located at its geometric center. It is known that the three-dimensional translation of the radar coordinate system relative to the chassis coordinate system is: 0.4 meters in the x-direction, 0 meters in the y-direction, and 0.2 meters in the z-direction, with no rotation. The three-dimensional translation of the camera coordinate system relative to the chassis coordinate system is: -0.5 meters in the x-direction, 0 meters in the y-direction, and 0.4 meters in the z-direction, with no rotation. Broadcast the relative coordinate relationships between the radar and the chassis, and between the camera and the chassis, and view the broadcast results in rviz2.",[20,782,783],{},[23,784],{"alt":25,"src":785},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1282.webp",[20,787,788,791],{},[30,789,790],{},"Case 2:"," Start turtlesim_node, where the window has a world coordinate system (origin at the bottom-left corner), and the turtle is another coordinate system. The turtle can be controlled via keyboard. Dynamically publish the relative relationship between the turtle's coordinate system and the world coordinate system.",[20,793,794],{},[23,795],{"alt":25,"src":796},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1283.webp",[362,798,800],{"id":799},"_2-case-analysis","2. Case Analysis",[20,802,803],{},"In the above cases, Case 1 requires the use of static coordinate transformation, while Case 2 requires dynamic coordinate transformation. Regardless of the implementation, there are two key elements to focus on:",[805,806,807,811],"ol",{},[808,809,810],"li",{},"How to broadcast coordinate frame relationships;",[808,812,813],{},"How to display coordinate frame relationships using rviz2.",[362,815,817],{"id":816},"_3-process-overview","3. Process Overview",[20,819,820],{},"The process for implementing static or dynamic coordinate transformations through coding is similar, with the main steps as follows:",[805,822,823,826,829,832,835],{},[808,824,825],{},"Write the broadcast implementation.",[808,827,828],{},"Edit the configuration file.",[808,830,831],{},"Compile;",[808,833,834],{},"execute",[808,836,837],{},"View the coordinate frame relationships in rviz2.",[20,839,840],{},"We will implement the case using C++ and Python separately, both following the implementation process described above.",[20,842,843],{},"Additionally: It should be noted that, besides being implemented programmatically, static broadcasters also have built-in tools in tf2 that allow publishing static coordinate frame relationships without coding — simply by running a node and passing parameters that represent the relative relationships between coordinate frames (i.e., via the command line; if a command-line option is available, it should be preferred). Dynamic broadcasters, however, do not offer similar tools (meaning they must be implemented in code).",[362,845,847],{"id":846},"_4-preparation","4. Preparation",[20,849,850,851,854],{},"In the terminal, navigate to the ",[33,852,853],{},"src"," directory of the workspace and run the following two commands to create C++ packages respectively.",[129,856,858],{"className":131,"code":857,"language":133,"meta":25,"style":25},"ros2 pkg create cpp03_tf_broadcaster --build-type ament_cmake --dependencies rclcpp tf2 tf2_ros geometry_msgs turtlesim\n",[33,859,860],{"__ignoreMap":25},[137,861,862,864,867,870,873,876,879,882,885,888,891,894],{"class":139,"line":140},[137,863,295],{"class":157},[137,865,866],{"class":161}," pkg",[137,868,869],{"class":161}," create",[137,871,872],{"class":161}," cpp03_tf_broadcaster",[137,874,875],{"class":527}," --build-type",[137,877,878],{"class":161}," ament_cmake",[137,880,881],{"class":527}," --dependencies",[137,883,884],{"class":161}," rclcpp",[137,886,887],{"class":161}," tf2",[137,889,890],{"class":161}," tf2_ros",[137,892,893],{"class":161}," geometry_msgs",[137,895,896],{"class":161}," turtlesim\n",[20,898,899],{},"The tf2 package contains conversion algorithms between quaternions and Euler angles.",[20,901,902],{},"The tf2_ros package contains broadcast objects.",[20,904,905],{},"geometry_msgs message carriers",[20,907,908,909,912],{},"The ",[33,910,911],{},"turtlesim"," package is used to obtain the turtle's 🐢 pose.",[15,914,916],{"id":915},"static-broadcaster-command-line-implementation","Static Broadcaster Command Line Implementation",[362,918,920],{"id":919},"_1-static-broadcaster-tool","1. Static Broadcaster Tool",[20,922,923,924,927,928,931],{},"In the ",[33,925,926],{},"tf2_ros"," package, an executable file named ",[33,929,930],{},"static_transform_publisher"," is provided. This file can be used to directly broadcast static coordinate frame relationships, and its usage syntax is as follows.",[20,933,934],{},[30,935,936],{},"Format 1:",[20,938,939],{},"Publish a static coordinate transform to tf2 using x/y/z offsets in meters and roll/pitch/yaw in radians (which refer to rotations around the x/y/z axes, respectively).",[129,941,943],{"className":131,"code":942,"language":133,"meta":25,"style":25},"ros2 run tf2_ros static_transform_publisher --x x --y y --z z --yaw yaw --pitch pitch --roll roll --frame-id frame_id --child-frame-id child_frame_id\n",[33,944,945],{"__ignoreMap":25},[137,946,947,949,951,953,956,959,961,964,966,969,971,974,977,980,983,986,989,992,994,997],{"class":139,"line":140},[137,948,295],{"class":157},[137,950,322],{"class":161},[137,952,890],{"class":161},[137,954,955],{"class":161}," static_transform_publisher",[137,957,958],{"class":527}," --x",[137,960,524],{"class":161},[137,962,963],{"class":527}," --y",[137,965,536],{"class":161},[137,967,968],{"class":527}," --z",[137,970,546],{"class":161},[137,972,973],{"class":527}," --yaw",[137,975,976],{"class":161}," yaw",[137,978,979],{"class":527}," --pitch",[137,981,982],{"class":161}," pitch",[137,984,985],{"class":527}," --roll",[137,987,988],{"class":161}," roll",[137,990,991],{"class":527}," --frame-id",[137,993,442],{"class":161},[137,995,996],{"class":527}," --child-frame-id",[137,998,999],{"class":161}," child_frame_id\n",[20,1001,1002],{},[23,1003],{"alt":25,"src":1004},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1284.webp",[20,1006,1007],{},"The parent coordinate system and the child coordinate system are mandatory.",[20,1009,1010],{},[23,1011],{"alt":25,"src":1012},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1285.webp",[20,1014,1015],{},"If these optional parameters are not selected, the default parent coordinate system and child coordinate system coincide, meaning both the offset and rotation are 0.",[20,1017,1018],{},"Offset: X, Y, Z",[20,1020,1021,1022,1025],{},"Rotation: QX, QY, QZ, QW ",[30,1023,1024],{},"or"," ROLL, PITCH, YAW (in radians)",[20,1027,1028],{},"Timestamp: No need to set it; it will start from the time of publication.",[20,1030,1031],{},[30,1032,1033],{},"Format 2:",[20,1035,1036],{},"Publish a static coordinate transform to tf2 using x/y/z offsets in meters and a qx/qy/qz/qw quaternion.",[129,1038,1040],{"className":131,"code":1039,"language":133,"meta":25,"style":25},"ros2 run tf2_ros static_transform_publisher --x x --y y --z z --qx qx --qy qy --qz qz --qw qw --frame-id frame_id --child-frame-id child_frame_id\n",[33,1041,1042],{"__ignoreMap":25},[137,1043,1044,1046,1048,1050,1052,1054,1056,1058,1060,1062,1064,1067,1070,1073,1076,1079,1082,1085,1088,1090,1092,1094],{"class":139,"line":140},[137,1045,295],{"class":157},[137,1047,322],{"class":161},[137,1049,890],{"class":161},[137,1051,955],{"class":161},[137,1053,958],{"class":527},[137,1055,524],{"class":161},[137,1057,963],{"class":527},[137,1059,536],{"class":161},[137,1061,968],{"class":527},[137,1063,546],{"class":161},[137,1065,1066],{"class":527}," --qx",[137,1068,1069],{"class":161}," qx",[137,1071,1072],{"class":527}," --qy",[137,1074,1075],{"class":161}," qy",[137,1077,1078],{"class":527}," --qz",[137,1080,1081],{"class":161}," qz",[137,1083,1084],{"class":527}," --qw",[137,1086,1087],{"class":161}," qw",[137,1089,991],{"class":527},[137,1091,442],{"class":161},[137,1093,996],{"class":527},[137,1095,999],{"class":161},[20,1097,1098,1099,1102,1103,1106],{},"Note: In the two formats above, aside from ",[33,1100,1101],{},"--frame-id"," used to represent the parent coordinate system and ",[33,1104,1105],{},"--child-frame-id"," used to represent the child coordinate system, all other parameters are optional. If a specific option is not specified, the default value will be used directly.",[362,1108,1110],{"id":1109},"_2-using-the-static-broadcaster-tool","2. Using the Static Broadcaster Tool",[20,1112,1113],{},"Open two terminals. In terminal 1, run the following command to publish the static coordinate transform of the laser relative to the base_link (coincident):",[129,1115,1117],{"className":131,"code":1116,"language":133,"meta":25,"style":25},"ros2 run tf2_ros static_transform_publisher --frame-id base_link --child-frame-id laser\n",[33,1118,1119],{"__ignoreMap":25},[137,1120,1121,1123,1125,1127,1129,1131,1134,1136],{"class":139,"line":140},[137,1122,295],{"class":157},[137,1124,322],{"class":161},[137,1126,890],{"class":161},[137,1128,955],{"class":161},[137,1130,991],{"class":527},[137,1132,1133],{"class":161}," base_link",[137,1135,996],{"class":527},[137,1137,1138],{"class":161}," laser\n",[20,1140,1141],{},[23,1142],{"alt":25,"src":1143},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1286.webp",[20,1145,1146],{},[23,1147],{"alt":25,"src":1148},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1287.webp",[20,1150,1151],{},"base_link is the parent reference frame",[20,1153,1154],{},"laser is a child reference frame",[20,1156,1157],{},"Generally, the parent reference frame is selected.",[362,1159,1161],{"id":1160},"_3-viewing-coordinate-frame-relationships-in-rviz2","3. Viewing coordinate frame relationships in rviz2",[20,1163,1164,1165,1168],{},"Open a new terminal, and use the command ",[33,1166,1167],{},"rviz2"," to launch rviz2 and configure the relevant plugins to view coordinate transform messages.",[805,1170,1171,1177,1184],{},[808,1172,1173,1174,99],{},"Set the Fixed Frame in Global Options to ",[33,1175,1176],{},"base_link",[808,1178,1179,1180,1183],{},"Click the ",[30,1181,1182],{},"Add"," button to add the TF plugin.",[808,1185,1186],{},"Check the \"show names\" option in the TF plugin.",[20,1188,1189],{},"The coordinate transformation relationships will be displayed graphically in the grid on the right.",[20,1191,1192],{},[23,1193],{"alt":25,"src":1194},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1288.webp",[20,1196,1197],{},"As shown in the figure, the two reference frames coincide.",[20,1199,1200],{},"Open two terminals. In terminal 1, enter the following command to publish the static coordinate transform of the laser relative to the base_link:",[129,1202,1204],{"className":131,"code":1203,"language":133,"meta":25,"style":25},"ros2 run tf2_ros static_transform_publisher --x 0.4 --y 0 --z 0.2 --yaw 0.5 --roll 0 --pitch 0 --frame-id base_link --child-frame-id laser\n",[33,1205,1206],{"__ignoreMap":25},[137,1207,1208,1210,1212,1214,1216,1218,1221,1223,1226,1228,1231,1233,1236,1238,1240,1242,1244,1246,1248,1250],{"class":139,"line":140},[137,1209,295],{"class":157},[137,1211,322],{"class":161},[137,1213,890],{"class":161},[137,1215,955],{"class":161},[137,1217,958],{"class":527},[137,1219,1220],{"class":527}," 0.4",[137,1222,963],{"class":527},[137,1224,1225],{"class":527}," 0",[137,1227,968],{"class":527},[137,1229,1230],{"class":527}," 0.2",[137,1232,973],{"class":527},[137,1234,1235],{"class":527}," 0.5",[137,1237,985],{"class":527},[137,1239,1225],{"class":527},[137,1241,979],{"class":527},[137,1243,1225],{"class":527},[137,1245,991],{"class":527},[137,1247,1133],{"class":161},[137,1249,996],{"class":527},[137,1251,1138],{"class":161},[20,1253,1254],{},"In terminal 2, enter the following command to publish the static coordinate transform of the camera relative to the base_link:",[129,1256,1258],{"className":131,"code":1257,"language":133,"meta":25,"style":25},"ros2 run tf2_ros static_transform_publisher --x -0.5 --y 0 --z 0.4 --yaw 0 --roll 0 --pitch 0 --frame-id base_link --child-frame-id camera\n",[33,1259,1260],{"__ignoreMap":25},[137,1261,1262,1264,1266,1268,1270,1272,1275,1277,1279,1281,1283,1285,1287,1289,1291,1293,1295,1297,1299,1301],{"class":139,"line":140},[137,1263,295],{"class":157},[137,1265,322],{"class":161},[137,1267,890],{"class":161},[137,1269,955],{"class":161},[137,1271,958],{"class":527},[137,1273,1274],{"class":527}," -0.5",[137,1276,963],{"class":527},[137,1278,1225],{"class":527},[137,1280,968],{"class":527},[137,1282,1220],{"class":527},[137,1284,973],{"class":527},[137,1286,1225],{"class":527},[137,1288,985],{"class":527},[137,1290,1225],{"class":527},[137,1292,979],{"class":527},[137,1294,1225],{"class":527},[137,1296,991],{"class":527},[137,1298,1133],{"class":161},[137,1300,996],{"class":527},[137,1302,1303],{"class":161}," camera\n",[20,1305,1306],{},[23,1307],{"alt":25,"src":1308},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1289.webp",[15,1310,1312],{"id":1311},"static-broadcaster_c-implementation","Static Broadcaster_C++ Implementation",[362,1314,1316],{"id":1315},"framework-setup","Framework setup",[129,1318,1322],{"className":1319,"code":1320,"language":1321,"meta":25,"style":25},"language-cmake shiki shiki-themes github-light github-dark","find_package(ament_cmake REQUIRED)\nfind_package(rclcpp REQUIRED)\nfind_package(tf2 REQUIRED)\nfind_package(tf2_ros REQUIRED)\nfind_package(geometry_msgs REQUIRED)\nfind_package(turtlesim REQUIRED)\n\nadd_executable(demo01_static_tf_broadcaster src/demo01_static_tf_broadcaster.cpp)\nament_target_dependencies(\n  demo01_static_tf_broadcaster\n  \"rclcpp\"\n  \"tf2\"\n  \"tf2_ros\"\n  \"geometry_msgs\"\n  \"turtlesim\"\n)\n\ninstall(TARGETS demo01_static_tf_broadcaster\n  DESTINATION lib/${PROJECT_NAME})\n","cmake",[33,1323,1324,1334,1341,1348,1355,1362,1369,1373,1381,1386,1391,1396,1401,1406,1411,1416,1421,1426,1435],{"__ignoreMap":25},[137,1325,1326,1330],{"class":139,"line":140},[137,1327,1329],{"class":1328},"szBVR","find_package",[137,1331,1333],{"class":1332},"sVt8B","(ament_cmake REQUIRED)\n",[137,1335,1336,1338],{"class":139,"line":147},[137,1337,1329],{"class":1328},[137,1339,1340],{"class":1332},"(rclcpp REQUIRED)\n",[137,1342,1343,1345],{"class":139,"line":154},[137,1344,1329],{"class":1328},[137,1346,1347],{"class":1332},"(tf2 REQUIRED)\n",[137,1349,1350,1352],{"class":139,"line":177},[137,1351,1329],{"class":1328},[137,1353,1354],{"class":1332},"(tf2_ros REQUIRED)\n",[137,1356,1357,1359],{"class":139,"line":182},[137,1358,1329],{"class":1328},[137,1360,1361],{"class":1332},"(geometry_msgs REQUIRED)\n",[137,1363,1364,1366],{"class":139,"line":188},[137,1365,1329],{"class":1328},[137,1367,1368],{"class":1332},"(turtlesim REQUIRED)\n",[137,1370,1371],{"class":139,"line":268},[137,1372,144],{"emptyLinePlaceholder":143},[137,1374,1375,1378],{"class":139,"line":470},[137,1376,1377],{"class":1328},"add_executable",[137,1379,1380],{"class":1332},"(demo01_static_tf_broadcaster src/demo01_static_tf_broadcaster.cpp)\n",[137,1382,1383],{"class":139,"line":482},[137,1384,1385],{"class":1332},"ament_target_dependencies(\n",[137,1387,1388],{"class":139,"line":491},[137,1389,1390],{"class":1332},"  demo01_static_tf_broadcaster\n",[137,1392,1393],{"class":139,"line":499},[137,1394,1395],{"class":161},"  \"rclcpp\"\n",[137,1397,1398],{"class":139,"line":507},[137,1399,1400],{"class":161},"  \"tf2\"\n",[137,1402,1403],{"class":139,"line":519},[137,1404,1405],{"class":161},"  \"tf2_ros\"\n",[137,1407,1408],{"class":139,"line":531},[137,1409,1410],{"class":161},"  \"geometry_msgs\"\n",[137,1412,1413],{"class":139,"line":541},[137,1414,1415],{"class":161},"  \"turtlesim\"\n",[137,1417,1418],{"class":139,"line":551},[137,1419,1420],{"class":1332},")\n",[137,1422,1424],{"class":139,"line":1423},17,[137,1425,144],{"emptyLinePlaceholder":143},[137,1427,1429,1432],{"class":139,"line":1428},18,[137,1430,1431],{"class":1328},"install",[137,1433,1434],{"class":1332},"(TARGETS demo01_static_tf_broadcaster\n",[137,1436,1438,1441,1444],{"class":139,"line":1437},19,[137,1439,1440],{"class":1332},"  DESTINATION lib/",[137,1442,1443],{"class":1328},"${PROJECT_NAME}",[137,1445,1420],{"class":1332},[362,1447,1449],{"id":1448},"broadcast-implementation","Broadcast Implementation",[129,1451,1455],{"className":1452,"code":1453,"language":1454,"meta":25,"style":25},"language-cpp shiki shiki-themes github-light github-dark","/*  \n  需求：编写静态坐标变换程序，执行时传入两个坐标系的相对位姿关系以及父子级坐标系id，\n       程序运行发布静态坐标变换。\n  步骤：\n    1.包含头文件；\n    2.判断终端传入的参数是否合法；\n    3.初始化 ROS 客户端；\n    4.定义节点类；\n      4-1.创建静态坐标变换发布方；\n      4-2.组织并发布消息。\n    5.调用 spin 函数，并传入对象指针；\n    6.释放资源。\n\n*/\n\n// 1.包含头文件；\n#include \u003Cgeometry_msgs/msg/transform_stamped.hpp>\n\n#include \u003Crclcpp/rclcpp.hpp>\n#include \u003Ctf2/LinearMath/Quaternion.h>\n#include \u003Ctf2_ros/static_transform_broadcaster.h>\n\nusing std::placeholders::_1;\n\n// 4.定义节点类；\nclass MinimalStaticFrameBroadcaster : public rclcpp::Node\n{\npublic:\n  explicit MinimalStaticFrameBroadcaster(char * transformation[]): Node(\"minimal_static_frame_broadcaster\")\n  {\n    // 4-1.创建静态坐标变换发布方；\n    tf_publisher_ = std::make_shared\u003Ctf2_ros::StaticTransformBroadcaster>(this);\n\n    this->make_transforms(transformation);\n  }\n\nprivate:\n  // 4-2.组织并发布消息。\n  void make_transforms(char * transformation[])\n  {\n    // 组织消息\n    geometry_msgs::msg::TransformStamped t;\n\n    rclcpp::Time now = this->get_clock()->now();\n    t.header.stamp = now;\n    t.header.frame_id = transformation[7];\n    t.child_frame_id = transformation[8];\n\n    t.transform.translation.x = atof(transformation[1]);\n    t.transform.translation.y = atof(transformation[2]);\n    t.transform.translation.z = atof(transformation[3]);\n    tf2::Quaternion q;\n    q.setRPY(\n      atof(transformation[4]),\n      atof(transformation[5]),\n      atof(transformation[6]));\n    t.transform.rotation.x = q.x();\n    t.transform.rotation.y = q.y();\n    t.transform.rotation.z = q.z();\n    t.transform.rotation.w = q.w();\n\n    // 发布消息\n    tf_publisher_->sendTransform(t);\n  }\n  std::shared_ptr\u003Ctf2_ros::StaticTransformBroadcaster> tf_publisher_;\n};\n\nint main(int argc, char * argv[])\n{\n  // 2.判断终端传入的参数是否合法；\n  auto logger = rclcpp::get_logger(\"logger\");\n\n  if (argc != 9) {\n    RCLCPP_INFO(\n      logger, \"运行程序时请按照：x y z roll pitch yaw frame_id child_frame_id 的格式传入参数\");\n    return 1;\n  }\n\n  // 3.初始化 ROS 客户端；\n  rclcpp::init(argc, argv);\n  // 5.调用 spin 函数，并传入对象指针；\n  rclcpp::spin(std::make_shared\u003CMinimalStaticFrameBroadcaster>(argv));\n  // 6.释放资源。\n  rclcpp::shutdown();\n  return 0;\n}\n","cpp",[33,1456,1457,1462,1467,1472,1477,1482,1487,1492,1497,1502,1507,1512,1517,1521,1526,1530,1535,1543,1547,1554,1562,1570,1575,1593,1598,1604,1626,1632,1638,1672,1678,1684,1719,1724,1739,1745,1750,1756,1762,1782,1787,1793,1807,1812,1840,1851,1868,1883,1888,1908,1925,1942,1951,1963,1977,1989,2002,2018,2033,2048,2063,2068,2074,2086,2091,2113,2119,2124,2152,2157,2163,2188,2193,2211,2219,2230,2242,2247,2252,2258,2272,2278,2305,2311,2323,2333],{"__ignoreMap":25},[137,1458,1459],{"class":139,"line":140},[137,1460,1461],{"class":150},"/*  \n",[137,1463,1464],{"class":139,"line":147},[137,1465,1466],{"class":150},"  需求：编写静态坐标变换程序，执行时传入两个坐标系的相对位姿关系以及父子级坐标系id，\n",[137,1468,1469],{"class":139,"line":154},[137,1470,1471],{"class":150},"       程序运行发布静态坐标变换。\n",[137,1473,1474],{"class":139,"line":177},[137,1475,1476],{"class":150},"  步骤：\n",[137,1478,1479],{"class":139,"line":182},[137,1480,1481],{"class":150},"    1.包含头文件；\n",[137,1483,1484],{"class":139,"line":188},[137,1485,1486],{"class":150},"    2.判断终端传入的参数是否合法；\n",[137,1488,1489],{"class":139,"line":268},[137,1490,1491],{"class":150},"    3.初始化 ROS 客户端；\n",[137,1493,1494],{"class":139,"line":470},[137,1495,1496],{"class":150},"    4.定义节点类；\n",[137,1498,1499],{"class":139,"line":482},[137,1500,1501],{"class":150},"      4-1.创建静态坐标变换发布方；\n",[137,1503,1504],{"class":139,"line":491},[137,1505,1506],{"class":150},"      4-2.组织并发布消息。\n",[137,1508,1509],{"class":139,"line":499},[137,1510,1511],{"class":150},"    5.调用 spin 函数，并传入对象指针；\n",[137,1513,1514],{"class":139,"line":507},[137,1515,1516],{"class":150},"    6.释放资源。\n",[137,1518,1519],{"class":139,"line":519},[137,1520,144],{"emptyLinePlaceholder":143},[137,1522,1523],{"class":139,"line":531},[137,1524,1525],{"class":150},"*/\n",[137,1527,1528],{"class":139,"line":541},[137,1529,144],{"emptyLinePlaceholder":143},[137,1531,1532],{"class":139,"line":551},[137,1533,1534],{"class":150},"// 1.包含头文件；\n",[137,1536,1537,1540],{"class":139,"line":1423},[137,1538,1539],{"class":1328},"#include",[137,1541,1542],{"class":161}," \u003Cgeometry_msgs/msg/transform_stamped.hpp>\n",[137,1544,1545],{"class":139,"line":1428},[137,1546,144],{"emptyLinePlaceholder":143},[137,1548,1549,1551],{"class":139,"line":1437},[137,1550,1539],{"class":1328},[137,1552,1553],{"class":161}," \u003Crclcpp/rclcpp.hpp>\n",[137,1555,1557,1559],{"class":139,"line":1556},20,[137,1558,1539],{"class":1328},[137,1560,1561],{"class":161}," \u003Ctf2/LinearMath/Quaternion.h>\n",[137,1563,1565,1567],{"class":139,"line":1564},21,[137,1566,1539],{"class":1328},[137,1568,1569],{"class":161}," \u003Ctf2_ros/static_transform_broadcaster.h>\n",[137,1571,1573],{"class":139,"line":1572},22,[137,1574,144],{"emptyLinePlaceholder":143},[137,1576,1578,1581,1584,1587,1590],{"class":139,"line":1577},23,[137,1579,1580],{"class":1328},"using",[137,1582,1583],{"class":157}," std",[137,1585,1586],{"class":1332},"::",[137,1588,1589],{"class":157},"placeholders",[137,1591,1592],{"class":1332},"::_1;\n",[137,1594,1596],{"class":139,"line":1595},24,[137,1597,144],{"emptyLinePlaceholder":143},[137,1599,1601],{"class":139,"line":1600},25,[137,1602,1603],{"class":150},"// 4.定义节点类；\n",[137,1605,1607,1610,1613,1616,1619,1621,1623],{"class":139,"line":1606},26,[137,1608,1609],{"class":1328},"class",[137,1611,1612],{"class":157}," MinimalStaticFrameBroadcaster",[137,1614,1615],{"class":1332}," : ",[137,1617,1618],{"class":1328},"public",[137,1620,884],{"class":157},[137,1622,1586],{"class":1332},[137,1624,1625],{"class":157},"Node\n",[137,1627,1629],{"class":139,"line":1628},27,[137,1630,1631],{"class":1332},"{\n",[137,1633,1635],{"class":139,"line":1634},28,[137,1636,1637],{"class":1328},"public:\n",[137,1639,1641,1644,1646,1649,1652,1655,1659,1662,1665,1667,1670],{"class":139,"line":1640},29,[137,1642,1643],{"class":1328},"  explicit",[137,1645,1612],{"class":157},[137,1647,1648],{"class":1332},"(",[137,1650,1651],{"class":1328},"char",[137,1653,1654],{"class":1328}," *",[137,1656,1658],{"class":1657},"s4XuR"," transformation",[137,1660,1661],{"class":1332},"[]): ",[137,1663,1664],{"class":157},"Node",[137,1666,1648],{"class":1332},[137,1668,1669],{"class":161},"\"minimal_static_frame_broadcaster\"",[137,1671,1420],{"class":1332},[137,1673,1675],{"class":139,"line":1674},30,[137,1676,1677],{"class":1332},"  {\n",[137,1679,1681],{"class":139,"line":1680},31,[137,1682,1683],{"class":150},"    // 4-1.创建静态坐标变换发布方；\n",[137,1685,1687,1690,1693,1695,1697,1700,1703,1705,1707,1710,1713,1716],{"class":139,"line":1686},32,[137,1688,1689],{"class":1332},"    tf_publisher_ ",[137,1691,1692],{"class":1328},"=",[137,1694,1583],{"class":157},[137,1696,1586],{"class":1332},[137,1698,1699],{"class":157},"make_shared",[137,1701,1702],{"class":1332},"\u003C",[137,1704,926],{"class":157},[137,1706,1586],{"class":1332},[137,1708,1709],{"class":157},"StaticTransformBroadcaster",[137,1711,1712],{"class":1332},">(",[137,1714,1715],{"class":527},"this",[137,1717,1718],{"class":1332},");\n",[137,1720,1722],{"class":139,"line":1721},33,[137,1723,144],{"emptyLinePlaceholder":143},[137,1725,1727,1730,1733,1736],{"class":139,"line":1726},34,[137,1728,1729],{"class":527},"    this",[137,1731,1732],{"class":1332},"->",[137,1734,1735],{"class":157},"make_transforms",[137,1737,1738],{"class":1332},"(transformation);\n",[137,1740,1742],{"class":139,"line":1741},35,[137,1743,1744],{"class":1332},"  }\n",[137,1746,1748],{"class":139,"line":1747},36,[137,1749,144],{"emptyLinePlaceholder":143},[137,1751,1753],{"class":139,"line":1752},37,[137,1754,1755],{"class":1328},"private:\n",[137,1757,1759],{"class":139,"line":1758},38,[137,1760,1761],{"class":150},"  // 4-2.组织并发布消息。\n",[137,1763,1765,1768,1771,1773,1775,1777,1779],{"class":139,"line":1764},39,[137,1766,1767],{"class":1328},"  void",[137,1769,1770],{"class":157}," make_transforms",[137,1772,1648],{"class":1332},[137,1774,1651],{"class":1328},[137,1776,1654],{"class":1328},[137,1778,1658],{"class":1657},[137,1780,1781],{"class":1332},"[])\n",[137,1783,1785],{"class":139,"line":1784},40,[137,1786,1677],{"class":1332},[137,1788,1790],{"class":139,"line":1789},41,[137,1791,1792],{"class":150},"    // 组织消息\n",[137,1794,1796,1799,1801,1804],{"class":139,"line":1795},42,[137,1797,1798],{"class":157},"    geometry_msgs",[137,1800,1586],{"class":1332},[137,1802,1803],{"class":157},"msg",[137,1805,1806],{"class":1332},"::TransformStamped t;\n",[137,1808,1810],{"class":139,"line":1809},43,[137,1811,144],{"emptyLinePlaceholder":143},[137,1813,1815,1818,1821,1823,1826,1828,1831,1834,1837],{"class":139,"line":1814},44,[137,1816,1817],{"class":157},"    rclcpp",[137,1819,1820],{"class":1332},"::Time now ",[137,1822,1692],{"class":1328},[137,1824,1825],{"class":527}," this",[137,1827,1732],{"class":1332},[137,1829,1830],{"class":157},"get_clock",[137,1832,1833],{"class":1332},"()->",[137,1835,1836],{"class":157},"now",[137,1838,1839],{"class":1332},"();\n",[137,1841,1843,1846,1848],{"class":139,"line":1842},45,[137,1844,1845],{"class":1332},"    t.header.stamp ",[137,1847,1692],{"class":1328},[137,1849,1850],{"class":1332}," now;\n",[137,1852,1854,1857,1859,1862,1865],{"class":139,"line":1853},46,[137,1855,1856],{"class":1332},"    t.header.frame_id ",[137,1858,1692],{"class":1328},[137,1860,1861],{"class":1332}," transformation[",[137,1863,1864],{"class":527},"7",[137,1866,1867],{"class":1332},"];\n",[137,1869,1871,1874,1876,1878,1881],{"class":139,"line":1870},47,[137,1872,1873],{"class":1332},"    t.child_frame_id ",[137,1875,1692],{"class":1328},[137,1877,1861],{"class":1332},[137,1879,1880],{"class":527},"8",[137,1882,1867],{"class":1332},[137,1884,1886],{"class":139,"line":1885},48,[137,1887,144],{"emptyLinePlaceholder":143},[137,1889,1891,1894,1896,1899,1902,1905],{"class":139,"line":1890},49,[137,1892,1893],{"class":1332},"    t.transform.translation.x ",[137,1895,1692],{"class":1328},[137,1897,1898],{"class":157}," atof",[137,1900,1901],{"class":1332},"(transformation[",[137,1903,1904],{"class":527},"1",[137,1906,1907],{"class":1332},"]);\n",[137,1909,1911,1914,1916,1918,1920,1923],{"class":139,"line":1910},50,[137,1912,1913],{"class":1332},"    t.transform.translation.y ",[137,1915,1692],{"class":1328},[137,1917,1898],{"class":157},[137,1919,1901],{"class":1332},[137,1921,1922],{"class":527},"2",[137,1924,1907],{"class":1332},[137,1926,1928,1931,1933,1935,1937,1940],{"class":139,"line":1927},51,[137,1929,1930],{"class":1332},"    t.transform.translation.z ",[137,1932,1692],{"class":1328},[137,1934,1898],{"class":157},[137,1936,1901],{"class":1332},[137,1938,1939],{"class":527},"3",[137,1941,1907],{"class":1332},[137,1943,1945,1948],{"class":139,"line":1944},52,[137,1946,1947],{"class":157},"    tf2",[137,1949,1950],{"class":1332},"::Quaternion q;\n",[137,1952,1954,1957,1960],{"class":139,"line":1953},53,[137,1955,1956],{"class":1332},"    q.",[137,1958,1959],{"class":157},"setRPY",[137,1961,1962],{"class":1332},"(\n",[137,1964,1966,1969,1971,1974],{"class":139,"line":1965},54,[137,1967,1968],{"class":157},"      atof",[137,1970,1901],{"class":1332},[137,1972,1973],{"class":527},"4",[137,1975,1976],{"class":1332},"]),\n",[137,1978,1980,1982,1984,1987],{"class":139,"line":1979},55,[137,1981,1968],{"class":157},[137,1983,1901],{"class":1332},[137,1985,1986],{"class":527},"5",[137,1988,1976],{"class":1332},[137,1990,1992,1994,1996,1999],{"class":139,"line":1991},56,[137,1993,1968],{"class":157},[137,1995,1901],{"class":1332},[137,1997,1998],{"class":527},"6",[137,2000,2001],{"class":1332},"]));\n",[137,2003,2005,2008,2010,2013,2016],{"class":139,"line":2004},57,[137,2006,2007],{"class":1332},"    t.transform.rotation.x ",[137,2009,1692],{"class":1328},[137,2011,2012],{"class":1332}," q.",[137,2014,2015],{"class":157},"x",[137,2017,1839],{"class":1332},[137,2019,2021,2024,2026,2028,2031],{"class":139,"line":2020},58,[137,2022,2023],{"class":1332},"    t.transform.rotation.y ",[137,2025,1692],{"class":1328},[137,2027,2012],{"class":1332},[137,2029,2030],{"class":157},"y",[137,2032,1839],{"class":1332},[137,2034,2036,2039,2041,2043,2046],{"class":139,"line":2035},59,[137,2037,2038],{"class":1332},"    t.transform.rotation.z ",[137,2040,1692],{"class":1328},[137,2042,2012],{"class":1332},[137,2044,2045],{"class":157},"z",[137,2047,1839],{"class":1332},[137,2049,2051,2054,2056,2058,2061],{"class":139,"line":2050},60,[137,2052,2053],{"class":1332},"    t.transform.rotation.w ",[137,2055,1692],{"class":1328},[137,2057,2012],{"class":1332},[137,2059,2060],{"class":157},"w",[137,2062,1839],{"class":1332},[137,2064,2066],{"class":139,"line":2065},61,[137,2067,144],{"emptyLinePlaceholder":143},[137,2069,2071],{"class":139,"line":2070},62,[137,2072,2073],{"class":150},"    // 发布消息\n",[137,2075,2077,2080,2083],{"class":139,"line":2076},63,[137,2078,2079],{"class":1332},"    tf_publisher_->",[137,2081,2082],{"class":157},"sendTransform",[137,2084,2085],{"class":1332},"(t);\n",[137,2087,2089],{"class":139,"line":2088},64,[137,2090,1744],{"class":1332},[137,2092,2094,2097,2100,2102,2104,2107,2110],{"class":139,"line":2093},65,[137,2095,2096],{"class":157},"  std",[137,2098,2099],{"class":1332},"::shared_ptr",[137,2101,1702],{"class":1328},[137,2103,926],{"class":157},[137,2105,2106],{"class":1332},"::StaticTransformBroadcaster",[137,2108,2109],{"class":1328},">",[137,2111,2112],{"class":1332}," tf_publisher_;\n",[137,2114,2116],{"class":139,"line":2115},66,[137,2117,2118],{"class":1332},"};\n",[137,2120,2122],{"class":139,"line":2121},67,[137,2123,144],{"emptyLinePlaceholder":143},[137,2125,2127,2130,2133,2135,2137,2140,2143,2145,2147,2150],{"class":139,"line":2126},68,[137,2128,2129],{"class":1328},"int",[137,2131,2132],{"class":157}," main",[137,2134,1648],{"class":1332},[137,2136,2129],{"class":1328},[137,2138,2139],{"class":1657}," argc",[137,2141,2142],{"class":1332},", ",[137,2144,1651],{"class":1328},[137,2146,1654],{"class":1328},[137,2148,2149],{"class":1657}," argv",[137,2151,1781],{"class":1332},[137,2153,2155],{"class":139,"line":2154},69,[137,2156,1631],{"class":1332},[137,2158,2160],{"class":139,"line":2159},70,[137,2161,2162],{"class":150},"  // 2.判断终端传入的参数是否合法；\n",[137,2164,2166,2169,2172,2174,2176,2178,2181,2183,2186],{"class":139,"line":2165},71,[137,2167,2168],{"class":1328},"  auto",[137,2170,2171],{"class":1332}," logger ",[137,2173,1692],{"class":1328},[137,2175,884],{"class":157},[137,2177,1586],{"class":1332},[137,2179,2180],{"class":157},"get_logger",[137,2182,1648],{"class":1332},[137,2184,2185],{"class":161},"\"logger\"",[137,2187,1718],{"class":1332},[137,2189,2191],{"class":139,"line":2190},72,[137,2192,144],{"emptyLinePlaceholder":143},[137,2194,2196,2199,2202,2205,2208],{"class":139,"line":2195},73,[137,2197,2198],{"class":1328},"  if",[137,2200,2201],{"class":1332}," (argc ",[137,2203,2204],{"class":1328},"!=",[137,2206,2207],{"class":527}," 9",[137,2209,2210],{"class":1332},") {\n",[137,2212,2214,2217],{"class":139,"line":2213},74,[137,2215,2216],{"class":157},"    RCLCPP_INFO",[137,2218,1962],{"class":1332},[137,2220,2222,2225,2228],{"class":139,"line":2221},75,[137,2223,2224],{"class":1332},"      logger, ",[137,2226,2227],{"class":161},"\"运行程序时请按照：x y z roll pitch yaw frame_id child_frame_id 的格式传入参数\"",[137,2229,1718],{"class":1332},[137,2231,2233,2236,2239],{"class":139,"line":2232},76,[137,2234,2235],{"class":1328},"    return",[137,2237,2238],{"class":527}," 1",[137,2240,2241],{"class":1332},";\n",[137,2243,2245],{"class":139,"line":2244},77,[137,2246,1744],{"class":1332},[137,2248,2250],{"class":139,"line":2249},78,[137,2251,144],{"emptyLinePlaceholder":143},[137,2253,2255],{"class":139,"line":2254},79,[137,2256,2257],{"class":150},"  // 3.初始化 ROS 客户端；\n",[137,2259,2261,2264,2266,2269],{"class":139,"line":2260},80,[137,2262,2263],{"class":157},"  rclcpp",[137,2265,1586],{"class":1332},[137,2267,2268],{"class":157},"init",[137,2270,2271],{"class":1332},"(argc, argv);\n",[137,2273,2275],{"class":139,"line":2274},81,[137,2276,2277],{"class":150},"  // 5.调用 spin 函数，并传入对象指针；\n",[137,2279,2281,2283,2285,2288,2290,2293,2295,2297,2299,2302],{"class":139,"line":2280},82,[137,2282,2263],{"class":157},[137,2284,1586],{"class":1332},[137,2286,2287],{"class":157},"spin",[137,2289,1648],{"class":1332},[137,2291,2292],{"class":157},"std",[137,2294,1586],{"class":1332},[137,2296,1699],{"class":157},[137,2298,1702],{"class":1332},[137,2300,2301],{"class":157},"MinimalStaticFrameBroadcaster",[137,2303,2304],{"class":1332},">(argv));\n",[137,2306,2308],{"class":139,"line":2307},83,[137,2309,2310],{"class":150},"  // 6.释放资源。\n",[137,2312,2314,2316,2318,2321],{"class":139,"line":2313},84,[137,2315,2263],{"class":157},[137,2317,1586],{"class":1332},[137,2319,2320],{"class":157},"shutdown",[137,2322,1839],{"class":1332},[137,2324,2326,2329,2331],{"class":139,"line":2325},85,[137,2327,2328],{"class":1328},"  return",[137,2330,1225],{"class":527},[137,2332,2241],{"class":1332},[137,2334,2336],{"class":139,"line":2335},86,[137,2337,2338],{"class":1332},"}\n",[20,2340,2341],{},[23,2342],{"alt":25,"src":2343},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1290.webp",[20,2345,2346],{},[23,2347],{"alt":25,"src":2348},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1291.webp",[20,2350,2351],{},"The parameters must be passed correctly, otherwise an error will be thrown.",[20,2353,2354],{},[23,2355],{"alt":25,"src":2356},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1292.webp",[20,2358,2359],{},"Function to create an organization and publish data.",[20,2361,2362],{},[23,2363],{"alt":25,"src":2364},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1293.webp",[20,2366,2367],{},"Use the simplest overload.",[20,2369,2370],{},[23,2371],{"alt":25,"src":2372},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1294.webp",[20,2374,2375],{},"Now it can be sent. Next, edit the content to be sent.",[20,2377,2378],{},[23,2379],{"alt":25,"src":2380},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1295.webp",[20,2382,2383],{},"Set the stamp timestamp to the current time; the now() function sets it to the current time.",[20,2385,2386],{},[23,2387],{"alt":25,"src":2388},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1296.webp",[20,2390,2391],{},"atof() converts to a float floating-point type.",[20,2393,2394],{},"x() and getx() both retrieve the x component of a quaternion. (The same applies to y, z, and w.)",[20,2396,2397],{},[23,2398],{"alt":25,"src":2399},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1297.webp",[20,2401,2402],{},"In the terminal, navigate to the current workspace and compile the package:",[129,2404,2406],{"className":131,"code":2405,"language":133,"meta":25,"style":25},"colcon build --packages-select cpp03_tf_broadcaster\n",[33,2407,2408],{"__ignoreMap":25},[137,2409,2410,2413,2416,2419],{"class":139,"line":140},[137,2411,2412],{"class":157},"colcon",[137,2414,2415],{"class":161}," build",[137,2417,2418],{"class":527}," --packages-select",[137,2420,2421],{"class":161}," cpp03_tf_broadcaster\n",[20,2423,2424],{},"In the current workspace, open two terminals. In Terminal 1, enter the following command to publish the static coordinate transform of the laser relative to the base_link:",[129,2426,2428],{"className":131,"code":2427,"language":133,"meta":25,"style":25},". install/setup.bash \nros2 run cpp03_tf_broadcaster demo01_static_tf_broadcaster 0.4 0 0.2 0 0 0 base_link laser\n",[33,2429,2430,2440],{"__ignoreMap":25},[137,2431,2432,2434,2437],{"class":139,"line":140},[137,2433,99],{"class":527},[137,2435,2436],{"class":161}," install/setup.bash",[137,2438,2439],{"class":1332}," \n",[137,2441,2442,2444,2446,2448,2451,2453,2455,2457,2459,2461,2463,2465],{"class":139,"line":147},[137,2443,295],{"class":157},[137,2445,322],{"class":161},[137,2447,872],{"class":161},[137,2449,2450],{"class":161}," demo01_static_tf_broadcaster",[137,2452,1220],{"class":527},[137,2454,1225],{"class":527},[137,2456,1230],{"class":527},[137,2458,1225],{"class":527},[137,2460,1225],{"class":527},[137,2462,1225],{"class":527},[137,2464,1133],{"class":161},[137,2466,1138],{"class":161},[20,2468,2469,2470,2473],{},"Refer to the ",[30,2471,2472],{},"Static Broadcaster (Command)"," content to launch and configure rviz2, with the final execution result similar to Case 1.",[20,2475,2476],{},[23,2477],{"alt":25,"src":2478},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1298.webp",[20,2480,2481],{},[23,2482],{"alt":25,"src":2483},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1299.webp",[20,2485,2486],{},"The essence is topic-based communication, but what exactly is the topic of this topic-based communication?",[20,2488,2489],{},[23,2490],{"alt":25,"src":2491},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1300.webp",[20,2493,2494],{},"By looking at the source code of this class, we can see that the topic is /tf_static.",[20,2496,2497],{},[23,2498],{"alt":25,"src":2499},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1301.webp",[20,2501,2502],{},[23,2503],{"alt":25,"src":2504},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1302.webp",[20,2506,2507],{},"There are two publishers and one subscriber.",[20,2509,2510],{},[23,2511],{"alt":25,"src":2512},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1303.webp",[20,2514,2515],{},"These two are the publishers.",[20,2517,2518],{},[23,2519],{"alt":25,"src":2520},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1304.webp",[20,2522,2523],{},"This is the subscriber.",[15,2525,2527],{"id":2526},"dynamic-broadcaster_c-implementation","Dynamic Broadcaster_C++ Implementation",[362,2529,1316],{"id":2530},"framework-setup-1",[20,2532,2533],{},"The CMakeLists.txt file needs to add the following content:",[129,2535,2537],{"className":1319,"code":2536,"language":1321,"meta":25,"style":25},"add_executable(demo02_dynamic_tf_broadcaster src/demo02_dynamic_tf_broadcaster.cpp)\nament_target_dependencies(\n  demo02_dynamic_tf_broadcaster\n  \"rclcpp\"\n  \"tf2\"\n  \"tf2_ros\"\n  \"geometry_msgs\"\n  \"turtlesim\"\n)\n",[33,2538,2539,2546,2550,2555,2559,2563,2567,2571,2575],{"__ignoreMap":25},[137,2540,2541,2543],{"class":139,"line":140},[137,2542,1377],{"class":1328},[137,2544,2545],{"class":1332},"(demo02_dynamic_tf_broadcaster src/demo02_dynamic_tf_broadcaster.cpp)\n",[137,2547,2548],{"class":139,"line":147},[137,2549,1385],{"class":1332},[137,2551,2552],{"class":139,"line":154},[137,2553,2554],{"class":1332},"  demo02_dynamic_tf_broadcaster\n",[137,2556,2557],{"class":139,"line":177},[137,2558,1395],{"class":161},[137,2560,2561],{"class":139,"line":182},[137,2562,1400],{"class":161},[137,2564,2565],{"class":139,"line":188},[137,2566,1405],{"class":161},[137,2568,2569],{"class":139,"line":268},[137,2570,1410],{"class":161},[137,2572,2573],{"class":139,"line":470},[137,2574,1415],{"class":161},[137,2576,2577],{"class":139,"line":482},[137,2578,1420],{"class":1332},[20,2580,2581,2582,2584],{},"Update the ",[33,2583,1431],{}," in the file to the following content:",[129,2586,2588],{"className":1319,"code":2587,"language":1321,"meta":25,"style":25},"install(TARGETS demo01_static_tf_broadcaster\n  demo02_dynamic_tf_broadcaster\n  DESTINATION lib/${PROJECT_NAME})\n",[33,2589,2590,2596,2600],{"__ignoreMap":25},[137,2591,2592,2594],{"class":139,"line":140},[137,2593,1431],{"class":1328},[137,2595,1434],{"class":1332},[137,2597,2598],{"class":139,"line":147},[137,2599,2554],{"class":1332},[137,2601,2602,2604,2606],{"class":139,"line":154},[137,2603,1440],{"class":1332},[137,2605,1443],{"class":1328},[137,2607,1420],{"class":1332},[362,2609,1449],{"id":2610},"broadcast-implementation-1",[129,2612,2614],{"className":1452,"code":2613,"language":1454,"meta":25,"style":25},"/*   \n  需求：编写动态坐标变换程序，启动 turtlesim_node 以及 turtle_teleop_key 后，该程序可以发布\n       乌龟坐标系到窗口坐标系的坐标变换，并且键盘控制乌龟运动时，乌龟坐标系与窗口坐标系的相对关系\n       也会实时更新。\n\n  步骤：\n    1.包含头文件；\n    2.初始化 ROS 客户端；\n    3.定义节点类；\n      3-1.创建动态坐标变换发布方；\n      3-2.创建乌龟位姿订阅方；\n      3-3.根据订阅到的乌龟位姿生成坐标帧并广播。\n    4.调用 spin 函数，并传入对象指针；\n    5.释放资源。\n\n*/\n// 1.包含头文件；\n#include \u003Cgeometry_msgs/msg/transform_stamped.hpp>\n\n#include \u003Crclcpp/rclcpp.hpp>\n#include \u003Ctf2/LinearMath/Quaternion.h>\n#include \u003Ctf2_ros/transform_broadcaster.h>\n#include \u003Cturtlesim/msg/pose.hpp>\n\nusing std::placeholders::_1;\n\n// 3.定义节点类；\nclass MinimalDynamicFrameBroadcaster : public rclcpp::Node\n{\npublic:\n  MinimalDynamicFrameBroadcaster(): Node(\"minimal_dynamic_frame_broadcaster\")\n  {\n    // 3-1.创建动态坐标变换发布方；\n    tf_broadcaster_ = std::make_unique\u003Ctf2_ros::TransformBroadcaster>(*this);\n\n    std::string topic_name = \"/turtle1/pose\";\n\n    // 3-2.创建乌龟位姿订阅方；\n    subscription_ = this->create_subscription\u003Cturtlesim::msg::Pose>(\n      topic_name, 10,\n      std::bind(&MinimalDynamicFrameBroadcaster::handle_turtle_pose, this, _1));\n  }\n\nprivate:\n  // 3-3.根据订阅到的乌龟位姿生成坐标帧并广播。   \n  void handle_turtle_pose(const turtlesim::msg::Pose & msg)\n  {\n    // 组织消息\n    geometry_msgs::msg::TransformStamped t;\n    rclcpp::Time now = this->get_clock()->now();\n\n    t.header.stamp = now;\n    t.header.frame_id = \"world\";   //窗体坐标系\n    t.child_frame_id = \"turtle1\";  //乌龟坐标系\n\n    t.transform.translation.x = msg.x;\n    t.transform.translation.y = msg.y;\n    t.transform.translation.z = 0.0;      //乌龟在平面内运动\n\n    //从欧拉角转换为四元数\n    tf2::Quaternion q;\n    q.setRPY(0, 0, msg.theta);        //乌龟只有Yaw\n    t.transform.rotation.x = q.x();\n    t.transform.rotation.y = q.y();\n    t.transform.rotation.z = q.z();\n    t.transform.rotation.w = q.w();\n    // 发布消息\n    tf_broadcaster_->sendTransform(t);\n  }\n  rclcpp::Subscription\u003Cturtlesim::msg::Pose>::SharedPtr subscription_;\n  std::unique_ptr\u003Ctf2_ros::TransformBroadcaster> tf_broadcaster_;\n};\n\nint main(int argc, char * argv[])\n{\n  // 2.初始化 ROS 客户端；\n  rclcpp::init(argc, argv);\n  // 4.调用 spin 函数，并传入对象指针；\n  rclcpp::spin(std::make_shared\u003CMinimalDynamicFrameBroadcaster>());\n  // 5.释放资源。\n  rclcpp::shutdown();\n  return 0;\n}\n",[33,2615,2616,2621,2626,2631,2636,2640,2644,2648,2653,2658,2663,2668,2673,2678,2683,2687,2691,2695,2701,2705,2711,2717,2724,2731,2735,2747,2751,2756,2773,2777,2781,2798,2802,2807,2839,2843,2858,2862,2867,2894,2905,2931,2935,2939,2943,2948,2979,2983,2987,2997,3017,3021,3029,3044,3058,3062,3071,3080,3094,3098,3103,3109,3130,3142,3154,3166,3178,3182,3191,3195,3219,3238,3242,3246,3268,3272,3277,3287,3292,3315,3320,3330,3338],{"__ignoreMap":25},[137,2617,2618],{"class":139,"line":140},[137,2619,2620],{"class":150},"/*   \n",[137,2622,2623],{"class":139,"line":147},[137,2624,2625],{"class":150},"  需求：编写动态坐标变换程序，启动 turtlesim_node 以及 turtle_teleop_key 后，该程序可以发布\n",[137,2627,2628],{"class":139,"line":154},[137,2629,2630],{"class":150},"       乌龟坐标系到窗口坐标系的坐标变换，并且键盘控制乌龟运动时，乌龟坐标系与窗口坐标系的相对关系\n",[137,2632,2633],{"class":139,"line":177},[137,2634,2635],{"class":150},"       也会实时更新。\n",[137,2637,2638],{"class":139,"line":182},[137,2639,144],{"emptyLinePlaceholder":143},[137,2641,2642],{"class":139,"line":188},[137,2643,1476],{"class":150},[137,2645,2646],{"class":139,"line":268},[137,2647,1481],{"class":150},[137,2649,2650],{"class":139,"line":470},[137,2651,2652],{"class":150},"    2.初始化 ROS 客户端；\n",[137,2654,2655],{"class":139,"line":482},[137,2656,2657],{"class":150},"    3.定义节点类；\n",[137,2659,2660],{"class":139,"line":491},[137,2661,2662],{"class":150},"      3-1.创建动态坐标变换发布方；\n",[137,2664,2665],{"class":139,"line":499},[137,2666,2667],{"class":150},"      3-2.创建乌龟位姿订阅方；\n",[137,2669,2670],{"class":139,"line":507},[137,2671,2672],{"class":150},"      3-3.根据订阅到的乌龟位姿生成坐标帧并广播。\n",[137,2674,2675],{"class":139,"line":519},[137,2676,2677],{"class":150},"    4.调用 spin 函数，并传入对象指针；\n",[137,2679,2680],{"class":139,"line":531},[137,2681,2682],{"class":150},"    5.释放资源。\n",[137,2684,2685],{"class":139,"line":541},[137,2686,144],{"emptyLinePlaceholder":143},[137,2688,2689],{"class":139,"line":551},[137,2690,1525],{"class":150},[137,2692,2693],{"class":139,"line":1423},[137,2694,1534],{"class":150},[137,2696,2697,2699],{"class":139,"line":1428},[137,2698,1539],{"class":1328},[137,2700,1542],{"class":161},[137,2702,2703],{"class":139,"line":1437},[137,2704,144],{"emptyLinePlaceholder":143},[137,2706,2707,2709],{"class":139,"line":1556},[137,2708,1539],{"class":1328},[137,2710,1553],{"class":161},[137,2712,2713,2715],{"class":139,"line":1564},[137,2714,1539],{"class":1328},[137,2716,1561],{"class":161},[137,2718,2719,2721],{"class":139,"line":1572},[137,2720,1539],{"class":1328},[137,2722,2723],{"class":161}," \u003Ctf2_ros/transform_broadcaster.h>\n",[137,2725,2726,2728],{"class":139,"line":1577},[137,2727,1539],{"class":1328},[137,2729,2730],{"class":161}," \u003Cturtlesim/msg/pose.hpp>\n",[137,2732,2733],{"class":139,"line":1595},[137,2734,144],{"emptyLinePlaceholder":143},[137,2736,2737,2739,2741,2743,2745],{"class":139,"line":1600},[137,2738,1580],{"class":1328},[137,2740,1583],{"class":157},[137,2742,1586],{"class":1332},[137,2744,1589],{"class":157},[137,2746,1592],{"class":1332},[137,2748,2749],{"class":139,"line":1606},[137,2750,144],{"emptyLinePlaceholder":143},[137,2752,2753],{"class":139,"line":1628},[137,2754,2755],{"class":150},"// 3.定义节点类；\n",[137,2757,2758,2760,2763,2765,2767,2769,2771],{"class":139,"line":1634},[137,2759,1609],{"class":1328},[137,2761,2762],{"class":157}," MinimalDynamicFrameBroadcaster",[137,2764,1615],{"class":1332},[137,2766,1618],{"class":1328},[137,2768,884],{"class":157},[137,2770,1586],{"class":1332},[137,2772,1625],{"class":157},[137,2774,2775],{"class":139,"line":1640},[137,2776,1631],{"class":1332},[137,2778,2779],{"class":139,"line":1674},[137,2780,1637],{"class":1328},[137,2782,2783,2786,2789,2791,2793,2796],{"class":139,"line":1680},[137,2784,2785],{"class":157},"  MinimalDynamicFrameBroadcaster",[137,2787,2788],{"class":1332},"(): ",[137,2790,1664],{"class":157},[137,2792,1648],{"class":1332},[137,2794,2795],{"class":161},"\"minimal_dynamic_frame_broadcaster\"",[137,2797,1420],{"class":1332},[137,2799,2800],{"class":139,"line":1686},[137,2801,1677],{"class":1332},[137,2803,2804],{"class":139,"line":1721},[137,2805,2806],{"class":150},"    // 3-1.创建动态坐标变换发布方；\n",[137,2808,2809,2812,2814,2816,2818,2821,2823,2825,2827,2830,2832,2835,2837],{"class":139,"line":1726},[137,2810,2811],{"class":1332},"    tf_broadcaster_ ",[137,2813,1692],{"class":1328},[137,2815,1583],{"class":157},[137,2817,1586],{"class":1332},[137,2819,2820],{"class":157},"make_unique",[137,2822,1702],{"class":1332},[137,2824,926],{"class":157},[137,2826,1586],{"class":1332},[137,2828,2829],{"class":157},"TransformBroadcaster",[137,2831,1712],{"class":1332},[137,2833,2834],{"class":1328},"*",[137,2836,1715],{"class":527},[137,2838,1718],{"class":1332},[137,2840,2841],{"class":139,"line":1741},[137,2842,144],{"emptyLinePlaceholder":143},[137,2844,2845,2848,2851,2853,2856],{"class":139,"line":1747},[137,2846,2847],{"class":157},"    std",[137,2849,2850],{"class":1332},"::string topic_name ",[137,2852,1692],{"class":1328},[137,2854,2855],{"class":161}," \"/turtle1/pose\"",[137,2857,2241],{"class":1332},[137,2859,2860],{"class":139,"line":1752},[137,2861,144],{"emptyLinePlaceholder":143},[137,2863,2864],{"class":139,"line":1758},[137,2865,2866],{"class":150},"    // 3-2.创建乌龟位姿订阅方；\n",[137,2868,2869,2872,2874,2876,2879,2881,2883,2885,2887,2890,2892],{"class":139,"line":1764},[137,2870,2871],{"class":1332},"    subscription_ ",[137,2873,1692],{"class":1328},[137,2875,1825],{"class":527},[137,2877,2878],{"class":1332},"->create_subscription",[137,2880,1702],{"class":1328},[137,2882,911],{"class":157},[137,2884,1586],{"class":1332},[137,2886,1803],{"class":157},[137,2888,2889],{"class":1332},"::Pose",[137,2891,2109],{"class":1328},[137,2893,1962],{"class":1332},[137,2895,2896,2899,2902],{"class":139,"line":1784},[137,2897,2898],{"class":1332},"      topic_name, ",[137,2900,2901],{"class":527},"10",[137,2903,2904],{"class":1332},",\n",[137,2906,2907,2910,2912,2915,2917,2920,2923,2926,2928],{"class":139,"line":1789},[137,2908,2909],{"class":157},"      std",[137,2911,1586],{"class":1332},[137,2913,2914],{"class":157},"bind",[137,2916,1648],{"class":1332},[137,2918,2919],{"class":1328},"&",[137,2921,2922],{"class":157},"MinimalDynamicFrameBroadcaster",[137,2924,2925],{"class":1332},"::handle_turtle_pose, ",[137,2927,1715],{"class":527},[137,2929,2930],{"class":1332},", _1));\n",[137,2932,2933],{"class":139,"line":1795},[137,2934,1744],{"class":1332},[137,2936,2937],{"class":139,"line":1809},[137,2938,144],{"emptyLinePlaceholder":143},[137,2940,2941],{"class":139,"line":1814},[137,2942,1755],{"class":1328},[137,2944,2945],{"class":139,"line":1842},[137,2946,2947],{"class":150},"  // 3-3.根据订阅到的乌龟位姿生成坐标帧并广播。   \n",[137,2949,2950,2952,2955,2957,2960,2962,2964,2966,2968,2971,2974,2977],{"class":139,"line":1853},[137,2951,1767],{"class":1328},[137,2953,2954],{"class":157}," handle_turtle_pose",[137,2956,1648],{"class":1332},[137,2958,2959],{"class":1328},"const",[137,2961,325],{"class":157},[137,2963,1586],{"class":1332},[137,2965,1803],{"class":157},[137,2967,1586],{"class":1332},[137,2969,2970],{"class":157},"Pose",[137,2972,2973],{"class":1328}," &",[137,2975,2976],{"class":1657}," msg",[137,2978,1420],{"class":1332},[137,2980,2981],{"class":139,"line":1870},[137,2982,1677],{"class":1332},[137,2984,2985],{"class":139,"line":1885},[137,2986,1792],{"class":150},[137,2988,2989,2991,2993,2995],{"class":139,"line":1890},[137,2990,1798],{"class":157},[137,2992,1586],{"class":1332},[137,2994,1803],{"class":157},[137,2996,1806],{"class":1332},[137,2998,2999,3001,3003,3005,3007,3009,3011,3013,3015],{"class":139,"line":1910},[137,3000,1817],{"class":157},[137,3002,1820],{"class":1332},[137,3004,1692],{"class":1328},[137,3006,1825],{"class":527},[137,3008,1732],{"class":1332},[137,3010,1830],{"class":157},[137,3012,1833],{"class":1332},[137,3014,1836],{"class":157},[137,3016,1839],{"class":1332},[137,3018,3019],{"class":139,"line":1927},[137,3020,144],{"emptyLinePlaceholder":143},[137,3022,3023,3025,3027],{"class":139,"line":1944},[137,3024,1845],{"class":1332},[137,3026,1692],{"class":1328},[137,3028,1850],{"class":1332},[137,3030,3031,3033,3035,3038,3041],{"class":139,"line":1953},[137,3032,1856],{"class":1332},[137,3034,1692],{"class":1328},[137,3036,3037],{"class":161}," \"world\"",[137,3039,3040],{"class":1332},";",[137,3042,3043],{"class":150},"   //窗体坐标系\n",[137,3045,3046,3048,3050,3053,3055],{"class":139,"line":1965},[137,3047,1873],{"class":1332},[137,3049,1692],{"class":1328},[137,3051,3052],{"class":161}," \"turtle1\"",[137,3054,3040],{"class":1332},[137,3056,3057],{"class":150},"  //乌龟坐标系\n",[137,3059,3060],{"class":139,"line":1979},[137,3061,144],{"emptyLinePlaceholder":143},[137,3063,3064,3066,3068],{"class":139,"line":1991},[137,3065,1893],{"class":1332},[137,3067,1692],{"class":1328},[137,3069,3070],{"class":1332}," msg.x;\n",[137,3072,3073,3075,3077],{"class":139,"line":2004},[137,3074,1913],{"class":1332},[137,3076,1692],{"class":1328},[137,3078,3079],{"class":1332}," msg.y;\n",[137,3081,3082,3084,3086,3089,3091],{"class":139,"line":2020},[137,3083,1930],{"class":1332},[137,3085,1692],{"class":1328},[137,3087,3088],{"class":527}," 0.0",[137,3090,3040],{"class":1332},[137,3092,3093],{"class":150},"      //乌龟在平面内运动\n",[137,3095,3096],{"class":139,"line":2035},[137,3097,144],{"emptyLinePlaceholder":143},[137,3099,3100],{"class":139,"line":2050},[137,3101,3102],{"class":150},"    //从欧拉角转换为四元数\n",[137,3104,3105,3107],{"class":139,"line":2065},[137,3106,1947],{"class":157},[137,3108,1950],{"class":1332},[137,3110,3111,3113,3115,3117,3120,3122,3124,3127],{"class":139,"line":2070},[137,3112,1956],{"class":1332},[137,3114,1959],{"class":157},[137,3116,1648],{"class":1332},[137,3118,3119],{"class":527},"0",[137,3121,2142],{"class":1332},[137,3123,3119],{"class":527},[137,3125,3126],{"class":1332},", msg.theta);",[137,3128,3129],{"class":150},"        //乌龟只有Yaw\n",[137,3131,3132,3134,3136,3138,3140],{"class":139,"line":2076},[137,3133,2007],{"class":1332},[137,3135,1692],{"class":1328},[137,3137,2012],{"class":1332},[137,3139,2015],{"class":157},[137,3141,1839],{"class":1332},[137,3143,3144,3146,3148,3150,3152],{"class":139,"line":2088},[137,3145,2023],{"class":1332},[137,3147,1692],{"class":1328},[137,3149,2012],{"class":1332},[137,3151,2030],{"class":157},[137,3153,1839],{"class":1332},[137,3155,3156,3158,3160,3162,3164],{"class":139,"line":2093},[137,3157,2038],{"class":1332},[137,3159,1692],{"class":1328},[137,3161,2012],{"class":1332},[137,3163,2045],{"class":157},[137,3165,1839],{"class":1332},[137,3167,3168,3170,3172,3174,3176],{"class":139,"line":2115},[137,3169,2053],{"class":1332},[137,3171,1692],{"class":1328},[137,3173,2012],{"class":1332},[137,3175,2060],{"class":157},[137,3177,1839],{"class":1332},[137,3179,3180],{"class":139,"line":2121},[137,3181,2073],{"class":150},[137,3183,3184,3187,3189],{"class":139,"line":2126},[137,3185,3186],{"class":1332},"    tf_broadcaster_->",[137,3188,2082],{"class":157},[137,3190,2085],{"class":1332},[137,3192,3193],{"class":139,"line":2154},[137,3194,1744],{"class":1332},[137,3196,3197,3199,3201,3204,3206,3208,3210,3212,3214,3216],{"class":139,"line":2159},[137,3198,2263],{"class":157},[137,3200,1586],{"class":1332},[137,3202,3203],{"class":157},"Subscription",[137,3205,1702],{"class":1332},[137,3207,911],{"class":157},[137,3209,1586],{"class":1332},[137,3211,1803],{"class":157},[137,3213,1586],{"class":1332},[137,3215,2970],{"class":157},[137,3217,3218],{"class":1332},">::SharedPtr subscription_;\n",[137,3220,3221,3223,3226,3228,3230,3233,3235],{"class":139,"line":2165},[137,3222,2096],{"class":157},[137,3224,3225],{"class":1332},"::unique_ptr",[137,3227,1702],{"class":1328},[137,3229,926],{"class":157},[137,3231,3232],{"class":1332},"::TransformBroadcaster",[137,3234,2109],{"class":1328},[137,3236,3237],{"class":1332}," tf_broadcaster_;\n",[137,3239,3240],{"class":139,"line":2190},[137,3241,2118],{"class":1332},[137,3243,3244],{"class":139,"line":2195},[137,3245,144],{"emptyLinePlaceholder":143},[137,3247,3248,3250,3252,3254,3256,3258,3260,3262,3264,3266],{"class":139,"line":2213},[137,3249,2129],{"class":1328},[137,3251,2132],{"class":157},[137,3253,1648],{"class":1332},[137,3255,2129],{"class":1328},[137,3257,2139],{"class":1657},[137,3259,2142],{"class":1332},[137,3261,1651],{"class":1328},[137,3263,1654],{"class":1328},[137,3265,2149],{"class":1657},[137,3267,1781],{"class":1332},[137,3269,3270],{"class":139,"line":2221},[137,3271,1631],{"class":1332},[137,3273,3274],{"class":139,"line":2232},[137,3275,3276],{"class":150},"  // 2.初始化 ROS 客户端；\n",[137,3278,3279,3281,3283,3285],{"class":139,"line":2244},[137,3280,2263],{"class":157},[137,3282,1586],{"class":1332},[137,3284,2268],{"class":157},[137,3286,2271],{"class":1332},[137,3288,3289],{"class":139,"line":2249},[137,3290,3291],{"class":150},"  // 4.调用 spin 函数，并传入对象指针；\n",[137,3293,3294,3296,3298,3300,3302,3304,3306,3308,3310,3312],{"class":139,"line":2254},[137,3295,2263],{"class":157},[137,3297,1586],{"class":1332},[137,3299,2287],{"class":157},[137,3301,1648],{"class":1332},[137,3303,2292],{"class":157},[137,3305,1586],{"class":1332},[137,3307,1699],{"class":157},[137,3309,1702],{"class":1332},[137,3311,2922],{"class":157},[137,3313,3314],{"class":1332},">());\n",[137,3316,3317],{"class":139,"line":2260},[137,3318,3319],{"class":150},"  // 5.释放资源。\n",[137,3321,3322,3324,3326,3328],{"class":139,"line":2274},[137,3323,2263],{"class":157},[137,3325,1586],{"class":1332},[137,3327,2320],{"class":157},[137,3329,1839],{"class":1332},[137,3331,3332,3334,3336],{"class":139,"line":2280},[137,3333,2328],{"class":1328},[137,3335,1225],{"class":527},[137,3337,2241],{"class":1332},[137,3339,3340],{"class":139,"line":2307},[137,3341,2338],{"class":1332},[20,3343,3344],{},[23,3345],{"alt":25,"src":3346},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1305.webp",[20,3348,3349],{},"Entry parameters:",[20,3351,3352],{},"Parameter 1: Topic Name",[20,3354,3355],{},"Parameter 2 QoS",[20,3357,3358],{},"Parameter 3 callback function",[20,3360,3361],{},[23,3362],{"alt":25,"src":3363},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1306.webp",[20,3365,3366],{},[23,3367],{"alt":25,"src":3368},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1307.webp",[20,3370,3371],{},[23,3372],{"alt":25,"src":3373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1308.webp",[20,3375,3376],{},"Controlling the turtle's movement will also make it move in Rviz2.",[20,3378,3379],{},[23,3380],{"alt":25,"src":3381},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1309.webp",[15,3383,3385],{"id":3384},"coordinate-point-publishing_c-implementation","Coordinate Point Publishing_C++ Implementation",[362,3387,3389],{"id":3388},"case-studies-and-analysis","Case Studies and Analysis",[20,3391,3392],{},[30,3393,3394],{},"Case Requirements",[20,3396,3397,3400],{},[30,3398,3399],{},"Case:"," An unmanned vehicle is equipped with a LiDAR sensor. The LiDAR scans a point-shaped obstacle and can locate its coordinates. Please publish the obstacle's coordinate point data in the LiDAR coordinate system and view the published result in rviz2.",[20,3402,3403],{},[23,3404],{"alt":25,"src":3405},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1310.webp",[20,3407,3408],{},[30,3409,3410],{},"Case Study",[20,3412,3413,3414,3416],{},"The above example is a simple topic publishing program. After understanding the coordinate point ",[33,3415,357],{}," interface message, the topic publisher can directly publish messages according to a certain logic.",[20,3418,3419],{},[30,3420,3421],{},"Process Overview",[20,3423,3424],{},"The main steps for program implementation are as follows:",[805,3426,3427,3430,3432,3434,3436],{},[808,3428,3429],{},"Write the topic publishing implementation.",[808,3431,828],{},[808,3433,831],{},[808,3435,834],{},[808,3437,3438],{},"View the running results in rviz2.",[20,3440,840],{},[20,3442,2533],{},[129,3444,3446],{"className":1319,"code":3445,"language":1321,"meta":25,"style":25},"add_executable(demo03_point_publisher src/demo03_point_publisher.cpp)\nament_target_dependencies(\n  demo03_point_publisher\n  \"rclcpp\"\n  \"tf2\"\n  \"tf2_ros\"\n  \"geometry_msgs\"\n  \"turtlesim\"\n)\n",[33,3447,3448,3455,3459,3464,3468,3472,3476,3480,3484],{"__ignoreMap":25},[137,3449,3450,3452],{"class":139,"line":140},[137,3451,1377],{"class":1328},[137,3453,3454],{"class":1332},"(demo03_point_publisher src/demo03_point_publisher.cpp)\n",[137,3456,3457],{"class":139,"line":147},[137,3458,1385],{"class":1332},[137,3460,3461],{"class":139,"line":154},[137,3462,3463],{"class":1332},"  demo03_point_publisher\n",[137,3465,3466],{"class":139,"line":177},[137,3467,1395],{"class":161},[137,3469,3470],{"class":139,"line":182},[137,3471,1400],{"class":161},[137,3473,3474],{"class":139,"line":188},[137,3475,1405],{"class":161},[137,3477,3478],{"class":139,"line":268},[137,3479,1410],{"class":161},[137,3481,3482],{"class":139,"line":470},[137,3483,1415],{"class":161},[137,3485,3486],{"class":139,"line":482},[137,3487,1420],{"class":1332},[20,3489,2581,3490,2584],{},[33,3491,1431],{},[129,3493,3495],{"className":1319,"code":3494,"language":1321,"meta":25,"style":25},"install(TARGETS demo01_static_tf_broadcaster\n  demo02_dynamic_tf_broadcaster\n  demo03_point_publisher\n  DESTINATION lib/${PROJECT_NAME})\n",[33,3496,3497,3503,3507,3511],{"__ignoreMap":25},[137,3498,3499,3501],{"class":139,"line":140},[137,3500,1431],{"class":1328},[137,3502,1434],{"class":1332},[137,3504,3505],{"class":139,"line":147},[137,3506,2554],{"class":1332},[137,3508,3509],{"class":139,"line":154},[137,3510,3463],{"class":1332},[137,3512,3513,3515,3517],{"class":139,"line":177},[137,3514,1440],{"class":1332},[137,3516,1443],{"class":1328},[137,3518,1420],{"class":1332},[362,3520,3522],{"id":3521},"implementation","Implementation",[129,3524,3526],{"className":1452,"code":3525,"language":1454,"meta":25,"style":25},"/*  \n    需求：发布雷达坐标系中某个坐标点相对于雷达（laser）坐标系的位姿。\n    步骤：\n        1.包含头文件；\n        2.初始化 ROS 客户端；\n        3.定义节点类；\n            3-1.创建坐标点发布方；\n            3-2.创建定时器；\n            3-3.组织并发布坐标点消息。\n        4.调用 spin 函数，并传入对象指针；\n        5.释放资源。\n\n*/\n// 1.包含头文件；\n#include \"rclcpp/rclcpp.hpp\"\n#include \"geometry_msgs/msg/point_stamped.hpp\"\n\nusing namespace std::chrono_literals;\n\n// 3.定义节点类；\nclass MinimalPointPublisher: public rclcpp::Node {\npublic:\n    MinimalPointPublisher(): Node(\"minimal_point_publisher\"),x(0.1){\n        // 3-1.创建坐标点发布方；\n        point_pub_ = this->create_publisher\u003Cgeometry_msgs::msg::PointStamped>(\"point\",10);\n        // 3-2.创建定时器；\n        timer_ = this->create_wall_timer(0.1s,std::bind(&MinimalPointPublisher::on_timer, this));\n    }\nprivate:\n    void on_timer(){\n        // 3-3.组织并发布坐标点消息。\n        geometry_msgs::msg::PointStamped point;\n        point.header.frame_id = \"laser\";\n        point.header.stamp = this->now();\n        x += 0.004;\n        point.point.x = x;\n        point.point.y = 0.0;\n        point.point.z = 0.1;        \n        point_pub_->publish(point);\n    }\n    rclcpp::Publisher\u003Cgeometry_msgs::msg::PointStamped>::SharedPtr point_pub_;\n    rclcpp::TimerBase::SharedPtr timer_;\n    double_t x;\n};\n\nint main(int argc, char const *argv[])\n{\n    // 2.初始化 ROS 客户端；\n    rclcpp::init(argc,argv);\n    // 4.调用 spin 函数，并传入对象指针；\n    rclcpp::spin(std::make_shared\u003CMinimalPointPublisher>());\n    // 5.释放资源。\n    rclcpp::shutdown();\n    return 0;\n}\n",[33,3527,3528,3532,3537,3542,3547,3552,3557,3562,3567,3572,3577,3582,3586,3590,3594,3601,3608,3612,3628,3632,3636,3657,3661,3688,3693,3731,3736,3780,3785,3789,3800,3805,3817,3829,3844,3857,3867,3878,3891,3902,3906,3931,3943,3950,3954,3958,3984,3988,3993,4004,4009,4031,4036,4046,4054],{"__ignoreMap":25},[137,3529,3530],{"class":139,"line":140},[137,3531,1461],{"class":150},[137,3533,3534],{"class":139,"line":147},[137,3535,3536],{"class":150},"    需求：发布雷达坐标系中某个坐标点相对于雷达（laser）坐标系的位姿。\n",[137,3538,3539],{"class":139,"line":154},[137,3540,3541],{"class":150},"    步骤：\n",[137,3543,3544],{"class":139,"line":177},[137,3545,3546],{"class":150},"        1.包含头文件；\n",[137,3548,3549],{"class":139,"line":182},[137,3550,3551],{"class":150},"        2.初始化 ROS 客户端；\n",[137,3553,3554],{"class":139,"line":188},[137,3555,3556],{"class":150},"        3.定义节点类；\n",[137,3558,3559],{"class":139,"line":268},[137,3560,3561],{"class":150},"            3-1.创建坐标点发布方；\n",[137,3563,3564],{"class":139,"line":470},[137,3565,3566],{"class":150},"            3-2.创建定时器；\n",[137,3568,3569],{"class":139,"line":482},[137,3570,3571],{"class":150},"            3-3.组织并发布坐标点消息。\n",[137,3573,3574],{"class":139,"line":491},[137,3575,3576],{"class":150},"        4.调用 spin 函数，并传入对象指针；\n",[137,3578,3579],{"class":139,"line":499},[137,3580,3581],{"class":150},"        5.释放资源。\n",[137,3583,3584],{"class":139,"line":507},[137,3585,144],{"emptyLinePlaceholder":143},[137,3587,3588],{"class":139,"line":519},[137,3589,1525],{"class":150},[137,3591,3592],{"class":139,"line":531},[137,3593,1534],{"class":150},[137,3595,3596,3598],{"class":139,"line":541},[137,3597,1539],{"class":1328},[137,3599,3600],{"class":161}," \"rclcpp/rclcpp.hpp\"\n",[137,3602,3603,3605],{"class":139,"line":551},[137,3604,1539],{"class":1328},[137,3606,3607],{"class":161}," \"geometry_msgs/msg/point_stamped.hpp\"\n",[137,3609,3610],{"class":139,"line":1423},[137,3611,144],{"emptyLinePlaceholder":143},[137,3613,3614,3616,3619,3621,3623,3626],{"class":139,"line":1428},[137,3615,1580],{"class":1328},[137,3617,3618],{"class":1328}," namespace",[137,3620,1583],{"class":157},[137,3622,1586],{"class":1332},[137,3624,3625],{"class":157},"chrono_literals",[137,3627,2241],{"class":1332},[137,3629,3630],{"class":139,"line":1437},[137,3631,144],{"emptyLinePlaceholder":143},[137,3633,3634],{"class":139,"line":1556},[137,3635,2755],{"class":150},[137,3637,3638,3640,3643,3646,3648,3650,3652,3654],{"class":139,"line":1564},[137,3639,1609],{"class":1328},[137,3641,3642],{"class":157}," MinimalPointPublisher",[137,3644,3645],{"class":1332},": ",[137,3647,1618],{"class":1328},[137,3649,884],{"class":157},[137,3651,1586],{"class":1332},[137,3653,1664],{"class":157},[137,3655,3656],{"class":1332}," {\n",[137,3658,3659],{"class":139,"line":1572},[137,3660,1637],{"class":1328},[137,3662,3663,3666,3668,3670,3672,3675,3678,3680,3682,3685],{"class":139,"line":1577},[137,3664,3665],{"class":157},"    MinimalPointPublisher",[137,3667,2788],{"class":1332},[137,3669,1664],{"class":157},[137,3671,1648],{"class":1332},[137,3673,3674],{"class":161},"\"minimal_point_publisher\"",[137,3676,3677],{"class":1332},"),",[137,3679,2015],{"class":157},[137,3681,1648],{"class":1332},[137,3683,3684],{"class":527},"0.1",[137,3686,3687],{"class":1332},"){\n",[137,3689,3690],{"class":139,"line":1595},[137,3691,3692],{"class":150},"        // 3-1.创建坐标点发布方；\n",[137,3694,3695,3698,3700,3702,3705,3707,3710,3712,3714,3717,3719,3721,3724,3727,3729],{"class":139,"line":1600},[137,3696,3697],{"class":1332},"        point_pub_ ",[137,3699,1692],{"class":1328},[137,3701,1825],{"class":527},[137,3703,3704],{"class":1332},"->create_publisher",[137,3706,1702],{"class":1328},[137,3708,3709],{"class":157},"geometry_msgs",[137,3711,1586],{"class":1332},[137,3713,1803],{"class":157},[137,3715,3716],{"class":1332},"::PointStamped",[137,3718,2109],{"class":1328},[137,3720,1648],{"class":1332},[137,3722,3723],{"class":161},"\"point\"",[137,3725,3726],{"class":1332},",",[137,3728,2901],{"class":527},[137,3730,1718],{"class":1332},[137,3732,3733],{"class":139,"line":1606},[137,3734,3735],{"class":150},"        // 3-2.创建定时器；\n",[137,3737,3738,3741,3743,3745,3747,3750,3752,3754,3757,3759,3761,3763,3765,3767,3769,3772,3775,3777],{"class":139,"line":1628},[137,3739,3740],{"class":1332},"        timer_ ",[137,3742,1692],{"class":1328},[137,3744,1825],{"class":527},[137,3746,1732],{"class":1332},[137,3748,3749],{"class":157},"create_wall_timer",[137,3751,1648],{"class":1332},[137,3753,3684],{"class":527},[137,3755,3756],{"class":1328},"s",[137,3758,3726],{"class":1332},[137,3760,2292],{"class":157},[137,3762,1586],{"class":1332},[137,3764,2914],{"class":157},[137,3766,1648],{"class":1332},[137,3768,2919],{"class":1328},[137,3770,3771],{"class":157},"MinimalPointPublisher",[137,3773,3774],{"class":1332},"::on_timer, ",[137,3776,1715],{"class":527},[137,3778,3779],{"class":1332},"));\n",[137,3781,3782],{"class":139,"line":1634},[137,3783,3784],{"class":1332},"    }\n",[137,3786,3787],{"class":139,"line":1640},[137,3788,1755],{"class":1328},[137,3790,3791,3794,3797],{"class":139,"line":1674},[137,3792,3793],{"class":1328},"    void",[137,3795,3796],{"class":157}," on_timer",[137,3798,3799],{"class":1332},"(){\n",[137,3801,3802],{"class":139,"line":1680},[137,3803,3804],{"class":150},"        // 3-3.组织并发布坐标点消息。\n",[137,3806,3807,3810,3812,3814],{"class":139,"line":1686},[137,3808,3809],{"class":157},"        geometry_msgs",[137,3811,1586],{"class":1332},[137,3813,1803],{"class":157},[137,3815,3816],{"class":1332},"::PointStamped point;\n",[137,3818,3819,3822,3824,3827],{"class":139,"line":1721},[137,3820,3821],{"class":1332},"        point.header.frame_id ",[137,3823,1692],{"class":1328},[137,3825,3826],{"class":161}," \"laser\"",[137,3828,2241],{"class":1332},[137,3830,3831,3834,3836,3838,3840,3842],{"class":139,"line":1726},[137,3832,3833],{"class":1332},"        point.header.stamp ",[137,3835,1692],{"class":1328},[137,3837,1825],{"class":527},[137,3839,1732],{"class":1332},[137,3841,1836],{"class":157},[137,3843,1839],{"class":1332},[137,3845,3846,3849,3852,3855],{"class":139,"line":1741},[137,3847,3848],{"class":1332},"        x ",[137,3850,3851],{"class":1328},"+=",[137,3853,3854],{"class":527}," 0.004",[137,3856,2241],{"class":1332},[137,3858,3859,3862,3864],{"class":139,"line":1747},[137,3860,3861],{"class":1332},"        point.point.x ",[137,3863,1692],{"class":1328},[137,3865,3866],{"class":1332}," x;\n",[137,3868,3869,3872,3874,3876],{"class":139,"line":1752},[137,3870,3871],{"class":1332},"        point.point.y ",[137,3873,1692],{"class":1328},[137,3875,3088],{"class":527},[137,3877,2241],{"class":1332},[137,3879,3880,3883,3885,3888],{"class":139,"line":1758},[137,3881,3882],{"class":1332},"        point.point.z ",[137,3884,1692],{"class":1328},[137,3886,3887],{"class":527}," 0.1",[137,3889,3890],{"class":1332},";        \n",[137,3892,3893,3896,3899],{"class":139,"line":1764},[137,3894,3895],{"class":1332},"        point_pub_->",[137,3897,3898],{"class":157},"publish",[137,3900,3901],{"class":1332},"(point);\n",[137,3903,3904],{"class":139,"line":1784},[137,3905,3784],{"class":1332},[137,3907,3908,3910,3912,3915,3917,3919,3921,3923,3925,3928],{"class":139,"line":1789},[137,3909,1817],{"class":157},[137,3911,1586],{"class":1332},[137,3913,3914],{"class":157},"Publisher",[137,3916,1702],{"class":1332},[137,3918,3709],{"class":157},[137,3920,1586],{"class":1332},[137,3922,1803],{"class":157},[137,3924,1586],{"class":1332},[137,3926,3927],{"class":157},"PointStamped",[137,3929,3930],{"class":1332},">::SharedPtr point_pub_;\n",[137,3932,3933,3935,3937,3940],{"class":139,"line":1795},[137,3934,1817],{"class":157},[137,3936,1586],{"class":1332},[137,3938,3939],{"class":157},"TimerBase",[137,3941,3942],{"class":1332},"::SharedPtr timer_;\n",[137,3944,3945,3948],{"class":139,"line":1809},[137,3946,3947],{"class":527},"    double_t",[137,3949,3866],{"class":1332},[137,3951,3952],{"class":139,"line":1814},[137,3953,2118],{"class":1332},[137,3955,3956],{"class":139,"line":1842},[137,3957,144],{"emptyLinePlaceholder":143},[137,3959,3960,3962,3964,3966,3968,3970,3972,3974,3977,3979,3982],{"class":139,"line":1853},[137,3961,2129],{"class":1328},[137,3963,2132],{"class":157},[137,3965,1648],{"class":1332},[137,3967,2129],{"class":1328},[137,3969,2139],{"class":1657},[137,3971,2142],{"class":1332},[137,3973,1651],{"class":1328},[137,3975,3976],{"class":1328}," const",[137,3978,1654],{"class":1328},[137,3980,3981],{"class":1657},"argv",[137,3983,1781],{"class":1332},[137,3985,3986],{"class":139,"line":1870},[137,3987,1631],{"class":1332},[137,3989,3990],{"class":139,"line":1885},[137,3991,3992],{"class":150},"    // 2.初始化 ROS 客户端；\n",[137,3994,3995,3997,3999,4001],{"class":139,"line":1890},[137,3996,1817],{"class":157},[137,3998,1586],{"class":1332},[137,4000,2268],{"class":157},[137,4002,4003],{"class":1332},"(argc,argv);\n",[137,4005,4006],{"class":139,"line":1910},[137,4007,4008],{"class":150},"    // 4.调用 spin 函数，并传入对象指针；\n",[137,4010,4011,4013,4015,4017,4019,4021,4023,4025,4027,4029],{"class":139,"line":1927},[137,4012,1817],{"class":157},[137,4014,1586],{"class":1332},[137,4016,2287],{"class":157},[137,4018,1648],{"class":1332},[137,4020,2292],{"class":157},[137,4022,1586],{"class":1332},[137,4024,1699],{"class":157},[137,4026,1702],{"class":1332},[137,4028,3771],{"class":157},[137,4030,3314],{"class":1332},[137,4032,4033],{"class":139,"line":1944},[137,4034,4035],{"class":150},"    // 5.释放资源。\n",[137,4037,4038,4040,4042,4044],{"class":139,"line":1953},[137,4039,1817],{"class":157},[137,4041,1586],{"class":1332},[137,4043,2320],{"class":157},[137,4045,1839],{"class":1332},[137,4047,4048,4050,4052],{"class":139,"line":1965},[137,4049,2235],{"class":1328},[137,4051,1225],{"class":527},[137,4053,2241],{"class":1332},[137,4055,4056],{"class":139,"line":1979},[137,4057,2338],{"class":1332},[20,4059,4060],{},[23,4061],{"alt":25,"src":4062},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1311.webp",[20,4064,4065,4066,4069],{},"To create a timer, use the ",[33,4067,4068],{},"create_wall_time()"," function, which requires a time interval and a corresponding callback function.",[20,4071,4072],{},[23,4073],{"alt":25,"src":4074},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1312.webp",[20,4076,4077],{},[30,4078,4079],{},"Execute",[20,4081,2424],{},[129,4083,4084],{"className":131,"code":2427,"language":133,"meta":25,"style":25},[33,4085,4086,4094],{"__ignoreMap":25},[137,4087,4088,4090,4092],{"class":139,"line":140},[137,4089,99],{"class":527},[137,4091,2436],{"class":161},[137,4093,2439],{"class":1332},[137,4095,4096,4098,4100,4102,4104,4106,4108,4110,4112,4114,4116,4118],{"class":139,"line":147},[137,4097,295],{"class":157},[137,4099,322],{"class":161},[137,4101,872],{"class":161},[137,4103,2450],{"class":161},[137,4105,1220],{"class":527},[137,4107,1225],{"class":527},[137,4109,1230],{"class":527},[137,4111,1225],{"class":527},[137,4113,1225],{"class":527},[137,4115,1225],{"class":527},[137,4117,1133],{"class":161},[137,4119,1138],{"class":161},[20,4121,4122],{},"In terminal 2, enter the following command to publish the coordinates of the obstacle relative to the radar (laser):",[129,4124,4126],{"className":131,"code":4125,"language":133,"meta":25,"style":25},". install/setup.bash \nros2 run cpp03_tf_broadcaster demo03_point_publisher\n",[33,4127,4128,4136],{"__ignoreMap":25},[137,4129,4130,4132,4134],{"class":139,"line":140},[137,4131,99],{"class":527},[137,4133,2436],{"class":161},[137,4135,2439],{"class":1332},[137,4137,4138,4140,4142,4144],{"class":139,"line":147},[137,4139,295],{"class":157},[137,4141,322],{"class":161},[137,4143,872],{"class":161},[137,4145,4146],{"class":161}," demo03_point_publisher\n",[20,4148,4149],{},[30,4150,4151],{},"Viewing coordinate frame relationships in rviz2",[20,4153,4154,4155,4158],{},"Refer to ",[30,4156,4157],{},"5.3.2 Static Broadcaster (Command)"," to launch and configure rviz2. After displaying the coordinate transform, add the PointStamped plugin and set its topic to /point. The final display result should be similar to the example demonstration.",[20,4160,4161],{},[23,4162],{"alt":25,"src":4163},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1313.webp",[20,4165,4166],{},[23,4167],{"alt":25,"src":4168},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1314.webp",[20,4170,4171],{},"You can change the ball's transparency and size here.",[15,4173,4175],{"id":4174},"summary","Summary",[20,4177,4178],{},[23,4179],{"alt":25,"src":4180},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1315.webp",[20,4182,4183],{},"A static broadcast is published only once.",[20,4185,4186],{},"Dynamic broadcasting and coordinate point broadcasting are both published multiple times.",[20,4188,4189],{},"But essentially, it's topic communication.",[10,4191,4193],{"id":4192},"coordinate-transformation-monitoring","Coordinate transformation monitoring",[15,4195,3389],{"id":4196},"case-studies-and-analysis-1",[20,4198,4199,4201,4202,4205],{},[30,4200,779],{}," In ",[30,4203,4204],{},"5.3 Coordinate Transformation Broadcasting",", the coordinate frame relationships of laser relative to base_link and camera relative to base_link are published. Solve for the coordinate frame relationship of laser relative to camera.",[20,4207,4208],{},[23,4209],{"alt":25,"src":4210},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1316.webp",[20,4212,4213,4201,4215,4218],{},[30,4214,790],{},[30,4216,4217],{},"5.3 Coordinate Transform Broadcast",", the coordinate relationship of laser relative to base_link was published, along with the coordinate point data of an obstacle in the laser coordinate system. Solve for the coordinates of that obstacle in the base_link coordinate system.",[20,4220,4221],{},[23,4222],{"alt":25,"src":4223},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1317.webp",[20,4225,4226],{},[30,4227,3410],{},[20,4229,4230],{},"In the above cases, Case 1 involves transformations between different coordinate systems in a multi-coordinate system scenario, while Case 2 requires transforming the same coordinate point under different coordinate systems. Although the requirements differ, the relevant algorithms are already encapsulated, so we only need to call the corresponding APIs.",[20,4232,4233],{},[30,4234,3421],{},[20,4236,4237],{},"The implementation process for both cases is similar, with the main steps as follows:",[805,4239,4240,4243,4245,4247],{},[808,4241,4242],{},"Write a coordinate transformation program to implement;",[808,4244,828],{},[808,4246,831],{},[808,4248,4249],{},"Execute.",[20,4251,840],{},[20,4253,4254],{},[30,4255,4256],{},"Preparation",[20,4258,850,4259,4261],{},[33,4260,853],{}," directory of your workspace and run the following two commands to create a C++ package and a Python package respectively.",[129,4263,4265],{"className":131,"code":4264,"language":133,"meta":25,"style":25},"ros2 pkg create cpp04_tf_listener --build-type ament_cmake --dependencies rclcpp tf2 tf2_ros geometry_msgs --node-name demo01_tf_listener\n",[33,4266,4267],{"__ignoreMap":25},[137,4268,4269,4271,4273,4275,4278,4280,4282,4284,4286,4288,4290,4292,4295],{"class":139,"line":140},[137,4270,295],{"class":157},[137,4272,866],{"class":161},[137,4274,869],{"class":161},[137,4276,4277],{"class":161}," cpp04_tf_listener",[137,4279,875],{"class":527},[137,4281,878],{"class":161},[137,4283,881],{"class":527},[137,4285,884],{"class":161},[137,4287,887],{"class":161},[137,4289,890],{"class":161},[137,4291,893],{"class":161},[137,4293,4294],{"class":527}," --node-name",[137,4296,4297],{"class":161}," demo01_tf_listener\n",[15,4299,4301,4302,4305],{"id":4300},"coordinate-system-transformation-listener_c","Coordinate ",[30,4303,4304],{},"System"," Transformation Listener_C++",[362,4307,3410],{"id":4308},"case-study",[20,4310,4311],{},[23,4312],{"alt":25,"src":4313},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1318.webp",[20,4315,4316],{},"Unlike the previous implementation, it needs to be saved into the buffer.",[20,4318,4319],{},[23,4320],{"alt":25,"src":4321},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1319.webp",[20,4323,4324],{},"Because the previous broadcast was publishing one and subscribing to one.",[20,4326,4327],{},"However, in coordinate transformation, it is implemented as many-to-one.",[20,4329,4330],{},"Multiple broadcast messages form a coordinate tree, from which transformations between different coordinate frames are obtained.",[20,4332,4333],{},"To assemble coordinate trees from multiple broadcaster messages, a buffer must be used to store all messages in the cache.",[20,4335,4336],{},[23,4337],{"alt":25,"src":4338},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1320.webp",[20,4340,4341],{},"Why is exception handling needed here?",[20,4343,4344],{},"Because the communication overhead between processes is relatively high and introduces latency, the program may need to start performing a transformation, but unfortunately the message hasn't been subscribed to yet.",[20,4346,4347],{},"No messages at all, just throwing exceptions. It won't stop throwing exceptions until there's data in the buffer and the coordinates have been successfully transformed.",[362,4349,3522],{"id":4350},"implementation-1",[129,4352,4354],{"className":1452,"code":4353,"language":1454,"meta":25,"style":25},"/*  \n  需求：订阅 laser 到 base_link 以及 camera 到 base_link 的坐标系关系，\n       并生成 laser 到 camera 的坐标变换。\n  步骤：\n    1.包含头文件；\n    2.初始化 ROS 客户端；\n    3.定义节点类；\n      3-1.创建tf缓存对象指针；融合多个坐标系相对关系为一棵坐标树。\n      3-2.创建tf监听器；指定缓存对象，会将所有广播器广播的数据写入缓存。\n      3-3.编写定时器，循环实现转换；按照条件查找符合条件的坐标系并生成变换后的坐标帧。\n    4.调用 spin 函数，并传入对象指针；\n    5.释放资源。\n\n*/\n#include \"rclcpp/rclcpp.hpp\"\n#include \"tf2_ros/transform_listener.h\"\n#include \"tf2_ros/buffer.h\"\n#include \"tf2/LinearMath/Quaternion.h\"\n\nusing namespace std::chrono_literals;\n\n// 3.定义节点类；\nclass MinimalFrameListener : public rclcpp::Node {\npublic:\n  MinimalFrameListener():Node(\"minimal_frame_listener\"){\n    tf_buffer_ = std::make_unique\u003Ctf2_ros::Buffer>(this->get_clock());\n    transform_listener_ = std::make_shared\u003Ctf2_ros::TransformListener>(*tf_buffer_);\n    timer_ = this->create_wall_timer(1s, std::bind(&MinimalFrameListener::on_timer,this));\n  }\n\nprivate:\n  void on_timer(){\n    try\n    {\n      auto transformStamped = tf_buffer_->lookupTransform(\"camera\",\"laser\",tf2::TimePointZero);\n      RCLCPP_INFO(this->get_logger(),\"----------------------转换结果----------------------\");\n      RCLCPP_INFO(this->get_logger(),\"frame_id:%s\",transformStamped.header.frame_id.c_str());\n      RCLCPP_INFO(this->get_logger(),\"child_frame_id:%s\",transformStamped.child_frame_id.c_str());\n      RCLCPP_INFO(this->get_logger(),\"坐标:(%.2f,%.2f,%.2f)\",\n                transformStamped.transform.translation.x,\n                transformStamped.transform.translation.y,\n                transformStamped.transform.translation.z);\n\n    }\n    catch(const tf2::LookupException& e)\n    {\n      RCLCPP_INFO(this->get_logger(),\"坐标变换异常：%s\",e.what());\n    }\n\n  }\n  rclcpp::TimerBase::SharedPtr timer_;\n  std::shared_ptr\u003Ctf2_ros::TransformListener> transform_listener_;\n  std::unique_ptr\u003Ctf2_ros::Buffer> tf_buffer_;\n};\n\nint main(int argc, char const *argv[])\n{\n  // 2.初始化 ROS 客户端；\n  rclcpp::init(argc,argv);\n  // 4.调用 spin 函数，并传入对象指针；\n  rclcpp::spin(std::make_shared\u003CMinimalFrameListener>());\n  // 5.释放资源。\n  rclcpp::shutdown();\n  return 0;\n}\n",[33,4355,4356,4360,4365,4370,4374,4378,4382,4386,4391,4396,4401,4405,4409,4413,4417,4423,4430,4437,4444,4448,4462,4466,4470,4489,4493,4510,4543,4572,4613,4617,4621,4625,4633,4638,4643,4677,4698,4729,4757,4790,4795,4800,4805,4809,4813,4832,4836,4865,4869,4873,4877,4887,4905,4923,4927,4931,4955,4959,4963,4973,4977,4999,5003,5013,5021],{"__ignoreMap":25},[137,4357,4358],{"class":139,"line":140},[137,4359,1461],{"class":150},[137,4361,4362],{"class":139,"line":147},[137,4363,4364],{"class":150},"  需求：订阅 laser 到 base_link 以及 camera 到 base_link 的坐标系关系，\n",[137,4366,4367],{"class":139,"line":154},[137,4368,4369],{"class":150},"       并生成 laser 到 camera 的坐标变换。\n",[137,4371,4372],{"class":139,"line":177},[137,4373,1476],{"class":150},[137,4375,4376],{"class":139,"line":182},[137,4377,1481],{"class":150},[137,4379,4380],{"class":139,"line":188},[137,4381,2652],{"class":150},[137,4383,4384],{"class":139,"line":268},[137,4385,2657],{"class":150},[137,4387,4388],{"class":139,"line":470},[137,4389,4390],{"class":150},"      3-1.创建tf缓存对象指针；融合多个坐标系相对关系为一棵坐标树。\n",[137,4392,4393],{"class":139,"line":482},[137,4394,4395],{"class":150},"      3-2.创建tf监听器；指定缓存对象，会将所有广播器广播的数据写入缓存。\n",[137,4397,4398],{"class":139,"line":491},[137,4399,4400],{"class":150},"      3-3.编写定时器，循环实现转换；按照条件查找符合条件的坐标系并生成变换后的坐标帧。\n",[137,4402,4403],{"class":139,"line":499},[137,4404,2677],{"class":150},[137,4406,4407],{"class":139,"line":507},[137,4408,2682],{"class":150},[137,4410,4411],{"class":139,"line":519},[137,4412,144],{"emptyLinePlaceholder":143},[137,4414,4415],{"class":139,"line":531},[137,4416,1525],{"class":150},[137,4418,4419,4421],{"class":139,"line":541},[137,4420,1539],{"class":1328},[137,4422,3600],{"class":161},[137,4424,4425,4427],{"class":139,"line":551},[137,4426,1539],{"class":1328},[137,4428,4429],{"class":161}," \"tf2_ros/transform_listener.h\"\n",[137,4431,4432,4434],{"class":139,"line":1423},[137,4433,1539],{"class":1328},[137,4435,4436],{"class":161}," \"tf2_ros/buffer.h\"\n",[137,4438,4439,4441],{"class":139,"line":1428},[137,4440,1539],{"class":1328},[137,4442,4443],{"class":161}," \"tf2/LinearMath/Quaternion.h\"\n",[137,4445,4446],{"class":139,"line":1437},[137,4447,144],{"emptyLinePlaceholder":143},[137,4449,4450,4452,4454,4456,4458,4460],{"class":139,"line":1556},[137,4451,1580],{"class":1328},[137,4453,3618],{"class":1328},[137,4455,1583],{"class":157},[137,4457,1586],{"class":1332},[137,4459,3625],{"class":157},[137,4461,2241],{"class":1332},[137,4463,4464],{"class":139,"line":1564},[137,4465,144],{"emptyLinePlaceholder":143},[137,4467,4468],{"class":139,"line":1572},[137,4469,2755],{"class":150},[137,4471,4472,4474,4477,4479,4481,4483,4485,4487],{"class":139,"line":1577},[137,4473,1609],{"class":1328},[137,4475,4476],{"class":157}," MinimalFrameListener",[137,4478,1615],{"class":1332},[137,4480,1618],{"class":1328},[137,4482,884],{"class":157},[137,4484,1586],{"class":1332},[137,4486,1664],{"class":157},[137,4488,3656],{"class":1332},[137,4490,4491],{"class":139,"line":1595},[137,4492,1637],{"class":1328},[137,4494,4495,4498,4501,4503,4505,4508],{"class":139,"line":1600},[137,4496,4497],{"class":157},"  MinimalFrameListener",[137,4499,4500],{"class":1332},"():",[137,4502,1664],{"class":157},[137,4504,1648],{"class":1332},[137,4506,4507],{"class":161},"\"minimal_frame_listener\"",[137,4509,3687],{"class":1332},[137,4511,4512,4515,4517,4519,4521,4523,4525,4527,4529,4532,4534,4536,4538,4540],{"class":139,"line":1606},[137,4513,4514],{"class":1332},"    tf_buffer_ ",[137,4516,1692],{"class":1328},[137,4518,1583],{"class":157},[137,4520,1586],{"class":1332},[137,4522,2820],{"class":157},[137,4524,1702],{"class":1332},[137,4526,926],{"class":157},[137,4528,1586],{"class":1332},[137,4530,4531],{"class":157},"Buffer",[137,4533,1712],{"class":1332},[137,4535,1715],{"class":527},[137,4537,1732],{"class":1332},[137,4539,1830],{"class":157},[137,4541,4542],{"class":1332},"());\n",[137,4544,4545,4548,4550,4552,4554,4556,4558,4560,4562,4565,4567,4569],{"class":139,"line":1628},[137,4546,4547],{"class":1332},"    transform_listener_ ",[137,4549,1692],{"class":1328},[137,4551,1583],{"class":157},[137,4553,1586],{"class":1332},[137,4555,1699],{"class":157},[137,4557,1702],{"class":1332},[137,4559,926],{"class":157},[137,4561,1586],{"class":1332},[137,4563,4564],{"class":157},"TransformListener",[137,4566,1712],{"class":1332},[137,4568,2834],{"class":1328},[137,4570,4571],{"class":1332},"tf_buffer_);\n",[137,4573,4574,4577,4579,4581,4583,4585,4587,4589,4591,4593,4595,4597,4599,4601,4603,4606,4609,4611],{"class":139,"line":1634},[137,4575,4576],{"class":1332},"    timer_ ",[137,4578,1692],{"class":1328},[137,4580,1825],{"class":527},[137,4582,1732],{"class":1332},[137,4584,3749],{"class":157},[137,4586,1648],{"class":1332},[137,4588,1904],{"class":527},[137,4590,3756],{"class":1328},[137,4592,2142],{"class":1332},[137,4594,2292],{"class":157},[137,4596,1586],{"class":1332},[137,4598,2914],{"class":157},[137,4600,1648],{"class":1332},[137,4602,2919],{"class":1328},[137,4604,4605],{"class":157},"MinimalFrameListener",[137,4607,4608],{"class":1332},"::on_timer,",[137,4610,1715],{"class":527},[137,4612,3779],{"class":1332},[137,4614,4615],{"class":139,"line":1640},[137,4616,1744],{"class":1332},[137,4618,4619],{"class":139,"line":1674},[137,4620,144],{"emptyLinePlaceholder":143},[137,4622,4623],{"class":139,"line":1680},[137,4624,1755],{"class":1328},[137,4626,4627,4629,4631],{"class":139,"line":1686},[137,4628,1767],{"class":1328},[137,4630,3796],{"class":157},[137,4632,3799],{"class":1332},[137,4634,4635],{"class":139,"line":1721},[137,4636,4637],{"class":1328},"    try\n",[137,4639,4640],{"class":139,"line":1726},[137,4641,4642],{"class":1332},"    {\n",[137,4644,4645,4648,4651,4653,4656,4659,4661,4664,4666,4669,4671,4674],{"class":139,"line":1741},[137,4646,4647],{"class":1328},"      auto",[137,4649,4650],{"class":1332}," transformStamped ",[137,4652,1692],{"class":1328},[137,4654,4655],{"class":1332}," tf_buffer_->",[137,4657,4658],{"class":157},"lookupTransform",[137,4660,1648],{"class":1332},[137,4662,4663],{"class":161},"\"camera\"",[137,4665,3726],{"class":1332},[137,4667,4668],{"class":161},"\"laser\"",[137,4670,3726],{"class":1332},[137,4672,4673],{"class":157},"tf2",[137,4675,4676],{"class":1332},"::TimePointZero);\n",[137,4678,4679,4682,4684,4686,4688,4690,4693,4696],{"class":139,"line":1747},[137,4680,4681],{"class":157},"      RCLCPP_INFO",[137,4683,1648],{"class":1332},[137,4685,1715],{"class":527},[137,4687,1732],{"class":1332},[137,4689,2180],{"class":157},[137,4691,4692],{"class":1332},"(),",[137,4694,4695],{"class":161},"\"----------------------转换结果----------------------\"",[137,4697,1718],{"class":1332},[137,4699,4700,4702,4704,4706,4708,4710,4712,4715,4718,4721,4724,4727],{"class":139,"line":1752},[137,4701,4681],{"class":157},[137,4703,1648],{"class":1332},[137,4705,1715],{"class":527},[137,4707,1732],{"class":1332},[137,4709,2180],{"class":157},[137,4711,4692],{"class":1332},[137,4713,4714],{"class":161},"\"frame_id:",[137,4716,4717],{"class":527},"%s",[137,4719,4720],{"class":161},"\"",[137,4722,4723],{"class":1332},",transformStamped.header.frame_id.",[137,4725,4726],{"class":157},"c_str",[137,4728,4542],{"class":1332},[137,4730,4731,4733,4735,4737,4739,4741,4743,4746,4748,4750,4753,4755],{"class":139,"line":1758},[137,4732,4681],{"class":157},[137,4734,1648],{"class":1332},[137,4736,1715],{"class":527},[137,4738,1732],{"class":1332},[137,4740,2180],{"class":157},[137,4742,4692],{"class":1332},[137,4744,4745],{"class":161},"\"child_frame_id:",[137,4747,4717],{"class":527},[137,4749,4720],{"class":161},[137,4751,4752],{"class":1332},",transformStamped.child_frame_id.",[137,4754,4726],{"class":157},[137,4756,4542],{"class":1332},[137,4758,4759,4761,4763,4765,4767,4769,4771,4774,4777,4779,4781,4783,4785,4788],{"class":139,"line":1764},[137,4760,4681],{"class":157},[137,4762,1648],{"class":1332},[137,4764,1715],{"class":527},[137,4766,1732],{"class":1332},[137,4768,2180],{"class":157},[137,4770,4692],{"class":1332},[137,4772,4773],{"class":161},"\"坐标:(",[137,4775,4776],{"class":527},"%.2f",[137,4778,3726],{"class":161},[137,4780,4776],{"class":527},[137,4782,3726],{"class":161},[137,4784,4776],{"class":527},[137,4786,4787],{"class":161},")\"",[137,4789,2904],{"class":1332},[137,4791,4792],{"class":139,"line":1784},[137,4793,4794],{"class":1332},"                transformStamped.transform.translation.x,\n",[137,4796,4797],{"class":139,"line":1789},[137,4798,4799],{"class":1332},"                transformStamped.transform.translation.y,\n",[137,4801,4802],{"class":139,"line":1795},[137,4803,4804],{"class":1332},"                transformStamped.transform.translation.z);\n",[137,4806,4807],{"class":139,"line":1809},[137,4808,144],{"emptyLinePlaceholder":143},[137,4810,4811],{"class":139,"line":1814},[137,4812,3784],{"class":1332},[137,4814,4815,4818,4820,4822,4824,4827,4829],{"class":139,"line":1842},[137,4816,4817],{"class":1328},"    catch",[137,4819,1648],{"class":1332},[137,4821,2959],{"class":1328},[137,4823,887],{"class":157},[137,4825,4826],{"class":1332},"::LookupException",[137,4828,2919],{"class":1328},[137,4830,4831],{"class":1332}," e)\n",[137,4833,4834],{"class":139,"line":1853},[137,4835,4642],{"class":1332},[137,4837,4838,4840,4842,4844,4846,4848,4850,4853,4855,4857,4860,4863],{"class":139,"line":1870},[137,4839,4681],{"class":157},[137,4841,1648],{"class":1332},[137,4843,1715],{"class":527},[137,4845,1732],{"class":1332},[137,4847,2180],{"class":157},[137,4849,4692],{"class":1332},[137,4851,4852],{"class":161},"\"坐标变换异常：",[137,4854,4717],{"class":527},[137,4856,4720],{"class":161},[137,4858,4859],{"class":1332},",e.",[137,4861,4862],{"class":157},"what",[137,4864,4542],{"class":1332},[137,4866,4867],{"class":139,"line":1885},[137,4868,3784],{"class":1332},[137,4870,4871],{"class":139,"line":1890},[137,4872,144],{"emptyLinePlaceholder":143},[137,4874,4875],{"class":139,"line":1910},[137,4876,1744],{"class":1332},[137,4878,4879,4881,4883,4885],{"class":139,"line":1927},[137,4880,2263],{"class":157},[137,4882,1586],{"class":1332},[137,4884,3939],{"class":157},[137,4886,3942],{"class":1332},[137,4888,4889,4891,4893,4895,4897,4900,4902],{"class":139,"line":1944},[137,4890,2096],{"class":157},[137,4892,2099],{"class":1332},[137,4894,1702],{"class":1328},[137,4896,926],{"class":157},[137,4898,4899],{"class":1332},"::TransformListener",[137,4901,2109],{"class":1328},[137,4903,4904],{"class":1332}," transform_listener_;\n",[137,4906,4907,4909,4911,4913,4915,4918,4920],{"class":139,"line":1953},[137,4908,2096],{"class":157},[137,4910,3225],{"class":1332},[137,4912,1702],{"class":1328},[137,4914,926],{"class":157},[137,4916,4917],{"class":1332},"::Buffer",[137,4919,2109],{"class":1328},[137,4921,4922],{"class":1332}," tf_buffer_;\n",[137,4924,4925],{"class":139,"line":1965},[137,4926,2118],{"class":1332},[137,4928,4929],{"class":139,"line":1979},[137,4930,144],{"emptyLinePlaceholder":143},[137,4932,4933,4935,4937,4939,4941,4943,4945,4947,4949,4951,4953],{"class":139,"line":1991},[137,4934,2129],{"class":1328},[137,4936,2132],{"class":157},[137,4938,1648],{"class":1332},[137,4940,2129],{"class":1328},[137,4942,2139],{"class":1657},[137,4944,2142],{"class":1332},[137,4946,1651],{"class":1328},[137,4948,3976],{"class":1328},[137,4950,1654],{"class":1328},[137,4952,3981],{"class":1657},[137,4954,1781],{"class":1332},[137,4956,4957],{"class":139,"line":2004},[137,4958,1631],{"class":1332},[137,4960,4961],{"class":139,"line":2020},[137,4962,3276],{"class":150},[137,4964,4965,4967,4969,4971],{"class":139,"line":2035},[137,4966,2263],{"class":157},[137,4968,1586],{"class":1332},[137,4970,2268],{"class":157},[137,4972,4003],{"class":1332},[137,4974,4975],{"class":139,"line":2050},[137,4976,3291],{"class":150},[137,4978,4979,4981,4983,4985,4987,4989,4991,4993,4995,4997],{"class":139,"line":2065},[137,4980,2263],{"class":157},[137,4982,1586],{"class":1332},[137,4984,2287],{"class":157},[137,4986,1648],{"class":1332},[137,4988,2292],{"class":157},[137,4990,1586],{"class":1332},[137,4992,1699],{"class":157},[137,4994,1702],{"class":1332},[137,4996,4605],{"class":157},[137,4998,3314],{"class":1332},[137,5000,5001],{"class":139,"line":2070},[137,5002,3319],{"class":150},[137,5004,5005,5007,5009,5011],{"class":139,"line":2076},[137,5006,2263],{"class":157},[137,5008,1586],{"class":1332},[137,5010,2320],{"class":157},[137,5012,1839],{"class":1332},[137,5014,5015,5017,5019],{"class":139,"line":2088},[137,5016,2328],{"class":1328},[137,5018,1225],{"class":527},[137,5020,2241],{"class":1332},[137,5022,5023],{"class":139,"line":2093},[137,5024,2338],{"class":1332},[20,5026,5027],{},[23,5028],{"alt":25,"src":5029},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1321.webp",[20,5031,5032],{},"To fill in the callback function.",[20,5034,5035],{},[23,5036],{"alt":25,"src":5037},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1322.webp",[20,5039,5040],{},[23,5041],{"alt":25,"src":5042},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1323.webp",[20,5044,5045,5046,99],{},"The core function for implementing coordinate transformation is ",[33,5047,5048],{},"lookuptransform()",[20,5050,5051],{},"target_frame is the parent frame.",[20,5053,5054],{},"The source_frame is the child level.",[20,5056,5057],{},"time refers to the current time, typically the most recent moment.",[20,5059,5060],{},[23,5061],{"alt":25,"src":5062},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1324.webp",[20,5064,5065],{},"If the buffer fails to capture, the function implementation that throws an exception.",[20,5067,5068],{},[23,5069],{"alt":25,"src":5070},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1325.webp",[20,5072,5073],{},"The coordinate conversion was successful, and the converted coordinates can be printed.",[20,5075,5076],{},[23,5077],{"alt":25,"src":5078},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1326.webp",[20,5080,5081],{},"In addition to using try-catch to handle conversion exceptions, you can also use the functions under buffer for conversion.",[20,5083,5084],{},[23,5085],{"alt":25,"src":5086},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1327.webp",[20,5088,5089,5090,5093],{},"For example, ",[33,5091,5092],{},"cantransform"," can determine whether a normal conversion is possible.",[20,5095,5096],{},[23,5097],{"alt":25,"src":5098},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1328.webp",[20,5100,5101],{},[23,5102],{"alt":25,"src":5103},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1329.webp",[20,5105,5106],{},"This type of error needs to be changed to a C-style string.",[20,5108,5109],{},"Open three terminals. In terminal 1, enter the following command to publish the static coordinate transform of the laser relative to the base_link:",[129,5111,5113],{"className":131,"code":5112,"language":133,"meta":25,"style":25},"ros2 run tf2_ros static_transform_publisher --frame-id base_link --child-frame-id camera --x -0.5 --z -0.4\n",[33,5114,5115],{"__ignoreMap":25},[137,5116,5117,5119,5121,5123,5125,5127,5129,5131,5134,5136,5138,5140],{"class":139,"line":140},[137,5118,295],{"class":157},[137,5120,322],{"class":161},[137,5122,890],{"class":161},[137,5124,955],{"class":161},[137,5126,991],{"class":527},[137,5128,1133],{"class":161},[137,5130,996],{"class":527},[137,5132,5133],{"class":161}," camera",[137,5135,958],{"class":527},[137,5137,1274],{"class":527},[137,5139,968],{"class":527},[137,5141,5142],{"class":527}," -0.4\n",[20,5144,1254],{},[129,5146,5148],{"className":131,"code":5147,"language":133,"meta":25,"style":25},"ros2 run tf2_ros static_transform_publisher --frame-id base_link --child-frame-id laser--x 0.4 --z 0.2\n",[33,5149,5150],{"__ignoreMap":25},[137,5151,5152,5154,5156,5158,5160,5162,5164,5166,5169,5171,5173],{"class":139,"line":140},[137,5153,295],{"class":157},[137,5155,322],{"class":161},[137,5157,890],{"class":161},[137,5159,955],{"class":161},[137,5161,991],{"class":527},[137,5163,1133],{"class":161},[137,5165,996],{"class":527},[137,5167,5168],{"class":161}," laser--x",[137,5170,1220],{"class":527},[137,5172,968],{"class":527},[137,5174,5175],{"class":527}," 0.2\n",[20,5177,5178],{},"In terminal 3, enter the following command to perform coordinate system transformation:",[129,5180,5182],{"className":131,"code":5181,"language":133,"meta":25,"style":25},". install/setup.bash \nros2 run cpp04_tf_listener demo01_tf_listener\n",[33,5183,5184,5192],{"__ignoreMap":25},[137,5185,5186,5188,5190],{"class":139,"line":140},[137,5187,99],{"class":527},[137,5189,2436],{"class":161},[137,5191,2439],{"class":1332},[137,5193,5194,5196,5198,5200],{"class":139,"line":147},[137,5195,295],{"class":157},[137,5197,322],{"class":161},[137,5199,4277],{"class":161},[137,5201,4297],{"class":161},[20,5203,5204],{},"Terminal 3 will output the coordinates of laser relative to camera. For specific results, please refer to Case 1.",[20,5206,5207],{},[23,5208],{"alt":25,"src":5209},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1330.webp",[20,5211,5212],{},[23,5213],{"alt":25,"src":5214},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1331.webp",[20,5216,5217],{},"When running only one broadcast, it throws an error.",[20,5219,5220],{},[23,5221],{"alt":25,"src":5222},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1332.webp",[20,5224,5225],{},[23,5226],{"alt":25,"src":5227},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1333.webp",[20,5229,5230],{},"Only when all broadcasts are running will the conversion proceed normally.",[15,5232,4301,5234,5236],{"id":5233},"coordinate-point-transform-listener_c",[30,5235,708],{}," Transform Listener_C++",[362,5238,5240],{"id":5239},"implementation-framework","Implementation framework",[20,5242,5243],{},[23,5244],{"alt":25,"src":5245},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1334.webp",[20,5247,5248],{},"Find the distance from the coordinate point measured by the laser to base_link.",[20,5250,5251],{},[23,5252],{"alt":25,"src":5253},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1335.webp",[20,5255,5256],{},[23,5257],{"alt":25,"src":5258},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1336.webp",[20,5260,5261,5262,5265],{},"The coordinates from laser to point use the ",[33,5263,5264],{},"point"," topic, which is different from the topic used by the listener, making it difficult to subscribe. A new subscription object needs to be created.",[362,5267,1316],{"id":5268},"framework-setup-2",[20,5270,5271,5272,5275,5276,5279],{},"When creating a functional package, some of the required dependencies are automatically configured in ",[33,5273,5274],{},"package.xml",". However, to implement coordinate point transformations, you still need to add the dependency packages ",[33,5277,5278],{},"tf2_geometry_msgs"," and",[20,5281,5282,5285],{},[33,5283,5284],{},"message_filters",", the modified configuration content is as follows:",[129,5287,5291],{"className":5288,"code":5289,"language":5290,"meta":25,"style":25},"language-xml shiki shiki-themes github-light github-dark","\u003Cdepend>rclcpp\u003C/depend>\n\u003Cdepend>tf2\u003C/depend>\n\u003Cdepend>tf2_ros\u003C/depend>\n\u003Cdepend>geometry_msgs\u003C/depend>\n\u003Cdepend>tf2_geometry_msgs\u003C/depend>\n\u003Cdepend>message_filters\u003C/depend>\n","xml",[33,5292,5293,5309,5322,5335,5348,5361],{"__ignoreMap":25},[137,5294,5295,5297,5301,5304,5306],{"class":139,"line":140},[137,5296,1702],{"class":1332},[137,5298,5300],{"class":5299},"s9eBZ","depend",[137,5302,5303],{"class":1332},">rclcpp\u003C/",[137,5305,5300],{"class":5299},[137,5307,5308],{"class":1332},">\n",[137,5310,5311,5313,5315,5318,5320],{"class":139,"line":147},[137,5312,1702],{"class":1332},[137,5314,5300],{"class":5299},[137,5316,5317],{"class":1332},">tf2\u003C/",[137,5319,5300],{"class":5299},[137,5321,5308],{"class":1332},[137,5323,5324,5326,5328,5331,5333],{"class":139,"line":154},[137,5325,1702],{"class":1332},[137,5327,5300],{"class":5299},[137,5329,5330],{"class":1332},">tf2_ros\u003C/",[137,5332,5300],{"class":5299},[137,5334,5308],{"class":1332},[137,5336,5337,5339,5341,5344,5346],{"class":139,"line":177},[137,5338,1702],{"class":1332},[137,5340,5300],{"class":5299},[137,5342,5343],{"class":1332},">geometry_msgs\u003C/",[137,5345,5300],{"class":5299},[137,5347,5308],{"class":1332},[137,5349,5350,5352,5354,5357,5359],{"class":139,"line":182},[137,5351,1702],{"class":1332},[137,5353,5300],{"class":5299},[137,5355,5356],{"class":1332},">tf2_geometry_msgs\u003C/",[137,5358,5300],{"class":5299},[137,5360,5308],{"class":1332},[137,5362,5363,5365,5367,5370,5372],{"class":139,"line":188},[137,5364,1702],{"class":1332},[137,5366,5300],{"class":5299},[137,5368,5369],{"class":1332},">message_filters\u003C/",[137,5371,5300],{"class":5299},[137,5373,5308],{"class":1332},[20,5375,5376],{},"The modified content of the CMakeLists.txt file is as follows:",[129,5378,5380],{"className":1319,"code":5379,"language":1321,"meta":25,"style":25},"find dependencies\nfind_package(ament_cmake REQUIRED)\nfind_package(rclcpp REQUIRED)\nfind_package(tf2 REQUIRED)\nfind_package(tf2_ros REQUIRED)\nfind_package(geometry_msgs REQUIRED)\nfind_package(tf2_geometry_msgs REQUIRED)\nfind_package(message_filters REQUIRED)\n\nadd_executable(demo01_tf_listener src/demo01_tf_listener.cpp)\nament_target_dependencies(\n  demo01_tf_listener\n  \"rclcpp\"\n  \"tf2\"\n  \"tf2_ros\"\n  \"geometry_msgs\"\n)\nadd_executable(demo02_message_filter src/demo02_message_filter.cpp)\nament_target_dependencies(\n  demo02_message_filter\n  \"rclcpp\"\n  \"tf2\"\n  \"tf2_ros\"\n  \"geometry_msgs\"\n  \"tf2_geometry_msgs\"\n  \"message_filters\"\n)\ninstall(TARGETS demo01_tf_listener\n  demo02_message_filter\n  DESTINATION lib/${PROJECT_NAME})\n",[33,5381,5382,5387,5393,5399,5405,5411,5417,5424,5431,5435,5442,5446,5451,5455,5459,5463,5467,5471,5478,5482,5487,5491,5495,5499,5503,5508,5513,5517,5524,5528],{"__ignoreMap":25},[137,5383,5384],{"class":139,"line":140},[137,5385,5386],{"class":1332},"find dependencies\n",[137,5388,5389,5391],{"class":139,"line":147},[137,5390,1329],{"class":1328},[137,5392,1333],{"class":1332},[137,5394,5395,5397],{"class":139,"line":154},[137,5396,1329],{"class":1328},[137,5398,1340],{"class":1332},[137,5400,5401,5403],{"class":139,"line":177},[137,5402,1329],{"class":1328},[137,5404,1347],{"class":1332},[137,5406,5407,5409],{"class":139,"line":182},[137,5408,1329],{"class":1328},[137,5410,1354],{"class":1332},[137,5412,5413,5415],{"class":139,"line":188},[137,5414,1329],{"class":1328},[137,5416,1361],{"class":1332},[137,5418,5419,5421],{"class":139,"line":268},[137,5420,1329],{"class":1328},[137,5422,5423],{"class":1332},"(tf2_geometry_msgs REQUIRED)\n",[137,5425,5426,5428],{"class":139,"line":470},[137,5427,1329],{"class":1328},[137,5429,5430],{"class":1332},"(message_filters REQUIRED)\n",[137,5432,5433],{"class":139,"line":482},[137,5434,144],{"emptyLinePlaceholder":143},[137,5436,5437,5439],{"class":139,"line":491},[137,5438,1377],{"class":1328},[137,5440,5441],{"class":1332},"(demo01_tf_listener src/demo01_tf_listener.cpp)\n",[137,5443,5444],{"class":139,"line":499},[137,5445,1385],{"class":1332},[137,5447,5448],{"class":139,"line":507},[137,5449,5450],{"class":1332},"  demo01_tf_listener\n",[137,5452,5453],{"class":139,"line":519},[137,5454,1395],{"class":161},[137,5456,5457],{"class":139,"line":531},[137,5458,1400],{"class":161},[137,5460,5461],{"class":139,"line":541},[137,5462,1405],{"class":161},[137,5464,5465],{"class":139,"line":551},[137,5466,1410],{"class":161},[137,5468,5469],{"class":139,"line":1423},[137,5470,1420],{"class":1332},[137,5472,5473,5475],{"class":139,"line":1428},[137,5474,1377],{"class":1328},[137,5476,5477],{"class":1332},"(demo02_message_filter src/demo02_message_filter.cpp)\n",[137,5479,5480],{"class":139,"line":1437},[137,5481,1385],{"class":1332},[137,5483,5484],{"class":139,"line":1556},[137,5485,5486],{"class":1332},"  demo02_message_filter\n",[137,5488,5489],{"class":139,"line":1564},[137,5490,1395],{"class":161},[137,5492,5493],{"class":139,"line":1572},[137,5494,1400],{"class":161},[137,5496,5497],{"class":139,"line":1577},[137,5498,1405],{"class":161},[137,5500,5501],{"class":139,"line":1595},[137,5502,1410],{"class":161},[137,5504,5505],{"class":139,"line":1600},[137,5506,5507],{"class":161},"  \"tf2_geometry_msgs\"\n",[137,5509,5510],{"class":139,"line":1606},[137,5511,5512],{"class":161},"  \"message_filters\"\n",[137,5514,5515],{"class":139,"line":1628},[137,5516,1420],{"class":1332},[137,5518,5519,5521],{"class":139,"line":1634},[137,5520,1431],{"class":1328},[137,5522,5523],{"class":1332},"(TARGETS demo01_tf_listener\n",[137,5525,5526],{"class":139,"line":1640},[137,5527,5486],{"class":1332},[137,5529,5530,5532,5534],{"class":139,"line":1674},[137,5531,1440],{"class":1332},[137,5533,1443],{"class":1328},[137,5535,1420],{"class":1332},[362,5537,3522],{"id":5538},"implementation-2",[129,5540,5542],{"className":1452,"code":5541,"language":1454,"meta":25,"style":25},"/*  \n  需求：将雷达感知到的障碍物的坐标点数据（相对于 laser 坐标系），\n       转换成相对于底盘坐标系（base_link）的坐标点。\n\n  步骤：\n    1.包含头文件；\n    2.初始化 ROS 客户端；\n    3.定义节点类；\n      3-1.创建tf缓存对象指针；\n      3-2.创建tf监听器；\n      3-3.创建坐标点订阅方并订阅指定话题；\n      3-4.创建消息过滤器过滤被处理的数据；\n      3-5.为消息过滤器注册转换坐标点数据的回调函数。\n    4.调用 spin 函数，并传入对象指针；\n    5.释放资源。\n\n*/// 1.包含头文件；#include \u003Cgeometry_msgs/msg/point_stamped.hpp>#include \u003Cmessage_filters/subscriber.h>#include \u003Crclcpp/rclcpp.hpp>#include \u003Ctf2_ros/buffer.h>#include \u003Ctf2_ros/create_timer_ros.h>#include \u003Ctf2_ros/message_filter.h>#include \u003Ctf2_ros/transform_listener.h>// #ifdef TF2_CPP_HEADERS//   #include \u003Ctf2_geometry_msgs/tf2_geometry_msgs.hpp>// #else//   #include \u003Ctf2_geometry_msgs/tf2_geometry_msgs.h>// #endif#include \u003Ctf2_geometry_msgs/tf2_geometry_msgs.hpp>using namespace std::chrono_literals;\n\n// 3.定义节点类；class MessageFilterPointListener : public rclcpp::Node\n{\npublic:\n  MessageFilterPointListener(): Node(\"message_filter_point_listener\")\n  {\n\n    target_frame_ = \"base_link\";\n\n    typedef std::chrono::duration\u003Cint> seconds_type;\n    seconds_type buffer_timeout(1);\n    // 3-1.创建tf缓存对象指针；\n    tf2_buffer_ = std::make_shared\u003Ctf2_ros::Buffer>(this->get_clock());\n    auto timer_interface = std::make_shared\u003Ctf2_ros::CreateTimerROS>(\n      this->get_node_base_interface(),\n      this->get_node_timers_interface());\n    tf2_buffer_->setCreateTimerInterface(timer_interface);\n    // 3-2.创建tf监听器；\n    tf2_listener_ = std::make_shared\u003Ctf2_ros::TransformListener>(*tf2_buffer_);\n\n    // 3-3.创建坐标点订阅方并订阅指定话题；\n    point_sub_.subscribe(this, \"point\");\n    // 3-4.创建消息过滤器过滤被处理的数据；\n    tf2_filter_ = std::make_shared\u003Ctf2_ros::MessageFilter\u003Cgeometry_msgs::msg::PointStamped>>(\n      point_sub_, *tf2_buffer_, target_frame_, 100, this->get_node_logging_interface(),\n      this->get_node_clock_interface(), buffer_timeout);\n    // 3-5.为消息过滤器注册转换坐标点数据的回调函数。\n    tf2_filter_->registerCallback(&MessageFilterPointListener::msgCallback, this);\n  }\n\nprivate:\n  void msgCallback(const geometry_msgs::msg::PointStamped::SharedPtr point_ptr){\n    geometry_msgs::msg::PointStamped point_out;\n    try {\n      tf2_buffer_->transform(*point_ptr, point_out, target_frame_);\n      RCLCPP_INFO(\n        this->get_logger(), \"坐标点相对于base_link的坐标:(%.2f,%.2f,%.2f)\",\n        point_out.point.x,\n        point_out.point.y,\n        point_out.point.z);\n    } catch (tf2::TransformException & ex) {\n      RCLCPP_WARN(\n        // Print exception which was caughtthis->get_logger(), \"Failure %s\\n\", ex.what());\n    }\n  }\n  std::string target_frame_;\n  std::shared_ptr\u003Ctf2_ros::Buffer> tf2_buffer_;\n  std::shared_ptr\u003Ctf2_ros::TransformListener> tf2_listener_;\n  message_filters::Subscriber\u003Cgeometry_msgs::msg::PointStamped> point_sub_;\n  std::shared_ptr\u003Ctf2_ros::MessageFilter\u003Cgeometry_msgs::msg::PointStamped>> tf2_filter_;\n};\n\nint main(int argc, char * argv[]){\n  // 2.初始化 ROS 客户端；\n  rclcpp::init(argc, argv);\n  // 4.调用 spin 函数，并传入对象指针；\n  rclcpp::spin(std::make_shared\u003CMessageFilterPointListener>());\n  // 5.释放资源。\n  rclcpp::shutdown();\n  return 0;\n}\n",[33,5543,5544,5548,5553,5558,5562,5566,5570,5574,5578,5583,5588,5593,5598,5603,5607,5611,5615,5620,5624,5629,5633,5637,5653,5657,5661,5673,5677,5698,5712,5717,5748,5776,5789,5800,5811,5816,5844,5848,5853,5871,5876,5913,5937,5949,5954,5976,5980,5984,5988,6012,6023,6030,6045,6051,6080,6085,6090,6095,6116,6123,6128,6132,6136,6143,6160,6177,6200,6229,6233,6237,6257,6261,6271,6275,6297,6301,6311,6319],{"__ignoreMap":25},[137,5545,5546],{"class":139,"line":140},[137,5547,1461],{"class":150},[137,5549,5550],{"class":139,"line":147},[137,5551,5552],{"class":150},"  需求：将雷达感知到的障碍物的坐标点数据（相对于 laser 坐标系），\n",[137,5554,5555],{"class":139,"line":154},[137,5556,5557],{"class":150},"       转换成相对于底盘坐标系（base_link）的坐标点。\n",[137,5559,5560],{"class":139,"line":177},[137,5561,144],{"emptyLinePlaceholder":143},[137,5563,5564],{"class":139,"line":182},[137,5565,1476],{"class":150},[137,5567,5568],{"class":139,"line":188},[137,5569,1481],{"class":150},[137,5571,5572],{"class":139,"line":268},[137,5573,2652],{"class":150},[137,5575,5576],{"class":139,"line":470},[137,5577,2657],{"class":150},[137,5579,5580],{"class":139,"line":482},[137,5581,5582],{"class":150},"      3-1.创建tf缓存对象指针；\n",[137,5584,5585],{"class":139,"line":491},[137,5586,5587],{"class":150},"      3-2.创建tf监听器；\n",[137,5589,5590],{"class":139,"line":499},[137,5591,5592],{"class":150},"      3-3.创建坐标点订阅方并订阅指定话题；\n",[137,5594,5595],{"class":139,"line":507},[137,5596,5597],{"class":150},"      3-4.创建消息过滤器过滤被处理的数据；\n",[137,5599,5600],{"class":139,"line":519},[137,5601,5602],{"class":150},"      3-5.为消息过滤器注册转换坐标点数据的回调函数。\n",[137,5604,5605],{"class":139,"line":531},[137,5606,2677],{"class":150},[137,5608,5609],{"class":139,"line":541},[137,5610,2682],{"class":150},[137,5612,5613],{"class":139,"line":551},[137,5614,144],{"emptyLinePlaceholder":143},[137,5616,5617],{"class":139,"line":1423},[137,5618,5619],{"class":150},"*/// 1.包含头文件；#include \u003Cgeometry_msgs/msg/point_stamped.hpp>#include \u003Cmessage_filters/subscriber.h>#include \u003Crclcpp/rclcpp.hpp>#include \u003Ctf2_ros/buffer.h>#include \u003Ctf2_ros/create_timer_ros.h>#include \u003Ctf2_ros/message_filter.h>#include \u003Ctf2_ros/transform_listener.h>// #ifdef TF2_CPP_HEADERS//   #include \u003Ctf2_geometry_msgs/tf2_geometry_msgs.hpp>// #else//   #include \u003Ctf2_geometry_msgs/tf2_geometry_msgs.h>// #endif#include \u003Ctf2_geometry_msgs/tf2_geometry_msgs.hpp>using namespace std::chrono_literals;\n",[137,5621,5622],{"class":139,"line":1428},[137,5623,144],{"emptyLinePlaceholder":143},[137,5625,5626],{"class":139,"line":1437},[137,5627,5628],{"class":150},"// 3.定义节点类；class MessageFilterPointListener : public rclcpp::Node\n",[137,5630,5631],{"class":139,"line":1556},[137,5632,1631],{"class":1332},[137,5634,5635],{"class":139,"line":1564},[137,5636,1637],{"class":1328},[137,5638,5639,5642,5644,5646,5648,5651],{"class":139,"line":1572},[137,5640,5641],{"class":157},"  MessageFilterPointListener",[137,5643,2788],{"class":1332},[137,5645,1664],{"class":157},[137,5647,1648],{"class":1332},[137,5649,5650],{"class":161},"\"message_filter_point_listener\"",[137,5652,1420],{"class":1332},[137,5654,5655],{"class":139,"line":1577},[137,5656,1677],{"class":1332},[137,5658,5659],{"class":139,"line":1595},[137,5660,144],{"emptyLinePlaceholder":143},[137,5662,5663,5666,5668,5671],{"class":139,"line":1600},[137,5664,5665],{"class":1332},"    target_frame_ ",[137,5667,1692],{"class":1328},[137,5669,5670],{"class":161}," \"base_link\"",[137,5672,2241],{"class":1332},[137,5674,5675],{"class":139,"line":1606},[137,5676,144],{"emptyLinePlaceholder":143},[137,5678,5679,5682,5684,5686,5689,5692,5695],{"class":139,"line":1628},[137,5680,5681],{"class":1328},"    typedef",[137,5683,1583],{"class":157},[137,5685,1586],{"class":1332},[137,5687,5688],{"class":157},"chrono",[137,5690,5691],{"class":1332},"::duration",[137,5693,5694],{"class":1328},"\u003Cint>",[137,5696,5697],{"class":1332}," seconds_type;\n",[137,5699,5700,5703,5706,5708,5710],{"class":139,"line":1634},[137,5701,5702],{"class":1332},"    seconds_type ",[137,5704,5705],{"class":157},"buffer_timeout",[137,5707,1648],{"class":1332},[137,5709,1904],{"class":527},[137,5711,1718],{"class":1332},[137,5713,5714],{"class":139,"line":1640},[137,5715,5716],{"class":150},"    // 3-1.创建tf缓存对象指针；\n",[137,5718,5719,5722,5724,5726,5728,5730,5732,5734,5736,5738,5740,5742,5744,5746],{"class":139,"line":1674},[137,5720,5721],{"class":1332},"    tf2_buffer_ ",[137,5723,1692],{"class":1328},[137,5725,1583],{"class":157},[137,5727,1586],{"class":1332},[137,5729,1699],{"class":157},[137,5731,1702],{"class":1332},[137,5733,926],{"class":157},[137,5735,1586],{"class":1332},[137,5737,4531],{"class":157},[137,5739,1712],{"class":1332},[137,5741,1715],{"class":527},[137,5743,1732],{"class":1332},[137,5745,1830],{"class":157},[137,5747,4542],{"class":1332},[137,5749,5750,5753,5756,5758,5760,5762,5764,5766,5768,5770,5773],{"class":139,"line":1680},[137,5751,5752],{"class":1328},"    auto",[137,5754,5755],{"class":1332}," timer_interface ",[137,5757,1692],{"class":1328},[137,5759,1583],{"class":157},[137,5761,1586],{"class":1332},[137,5763,1699],{"class":157},[137,5765,1702],{"class":1332},[137,5767,926],{"class":157},[137,5769,1586],{"class":1332},[137,5771,5772],{"class":157},"CreateTimerROS",[137,5774,5775],{"class":1332},">(\n",[137,5777,5778,5781,5783,5786],{"class":139,"line":1686},[137,5779,5780],{"class":527},"      this",[137,5782,1732],{"class":1332},[137,5784,5785],{"class":157},"get_node_base_interface",[137,5787,5788],{"class":1332},"(),\n",[137,5790,5791,5793,5795,5798],{"class":139,"line":1721},[137,5792,5780],{"class":527},[137,5794,1732],{"class":1332},[137,5796,5797],{"class":157},"get_node_timers_interface",[137,5799,4542],{"class":1332},[137,5801,5802,5805,5808],{"class":139,"line":1726},[137,5803,5804],{"class":1332},"    tf2_buffer_->",[137,5806,5807],{"class":157},"setCreateTimerInterface",[137,5809,5810],{"class":1332},"(timer_interface);\n",[137,5812,5813],{"class":139,"line":1741},[137,5814,5815],{"class":150},"    // 3-2.创建tf监听器；\n",[137,5817,5818,5821,5823,5825,5827,5829,5831,5833,5835,5837,5839,5841],{"class":139,"line":1747},[137,5819,5820],{"class":1332},"    tf2_listener_ ",[137,5822,1692],{"class":1328},[137,5824,1583],{"class":157},[137,5826,1586],{"class":1332},[137,5828,1699],{"class":157},[137,5830,1702],{"class":1332},[137,5832,926],{"class":157},[137,5834,1586],{"class":1332},[137,5836,4564],{"class":157},[137,5838,1712],{"class":1332},[137,5840,2834],{"class":1328},[137,5842,5843],{"class":1332},"tf2_buffer_);\n",[137,5845,5846],{"class":139,"line":1752},[137,5847,144],{"emptyLinePlaceholder":143},[137,5849,5850],{"class":139,"line":1758},[137,5851,5852],{"class":150},"    // 3-3.创建坐标点订阅方并订阅指定话题；\n",[137,5854,5855,5858,5861,5863,5865,5867,5869],{"class":139,"line":1764},[137,5856,5857],{"class":1332},"    point_sub_.",[137,5859,5860],{"class":157},"subscribe",[137,5862,1648],{"class":1332},[137,5864,1715],{"class":527},[137,5866,2142],{"class":1332},[137,5868,3723],{"class":161},[137,5870,1718],{"class":1332},[137,5872,5873],{"class":139,"line":1784},[137,5874,5875],{"class":150},"    // 3-4.创建消息过滤器过滤被处理的数据；\n",[137,5877,5878,5881,5883,5885,5887,5889,5891,5893,5895,5898,5900,5902,5904,5906,5908,5910],{"class":139,"line":1789},[137,5879,5880],{"class":1332},"    tf2_filter_ ",[137,5882,1692],{"class":1328},[137,5884,1583],{"class":157},[137,5886,1586],{"class":1332},[137,5888,1699],{"class":157},[137,5890,1702],{"class":1332},[137,5892,926],{"class":157},[137,5894,1586],{"class":1332},[137,5896,5897],{"class":157},"MessageFilter",[137,5899,1702],{"class":1332},[137,5901,3709],{"class":157},[137,5903,1586],{"class":1332},[137,5905,1803],{"class":157},[137,5907,1586],{"class":1332},[137,5909,3927],{"class":157},[137,5911,5912],{"class":1332},">>(\n",[137,5914,5915,5918,5920,5923,5926,5928,5930,5932,5935],{"class":139,"line":1795},[137,5916,5917],{"class":1332},"      point_sub_, ",[137,5919,2834],{"class":1328},[137,5921,5922],{"class":1332},"tf2_buffer_, target_frame_, ",[137,5924,5925],{"class":527},"100",[137,5927,2142],{"class":1332},[137,5929,1715],{"class":527},[137,5931,1732],{"class":1332},[137,5933,5934],{"class":157},"get_node_logging_interface",[137,5936,5788],{"class":1332},[137,5938,5939,5941,5943,5946],{"class":139,"line":1809},[137,5940,5780],{"class":527},[137,5942,1732],{"class":1332},[137,5944,5945],{"class":157},"get_node_clock_interface",[137,5947,5948],{"class":1332},"(), buffer_timeout);\n",[137,5950,5951],{"class":139,"line":1814},[137,5952,5953],{"class":150},"    // 3-5.为消息过滤器注册转换坐标点数据的回调函数。\n",[137,5955,5956,5959,5962,5964,5966,5969,5972,5974],{"class":139,"line":1842},[137,5957,5958],{"class":1332},"    tf2_filter_->",[137,5960,5961],{"class":157},"registerCallback",[137,5963,1648],{"class":1332},[137,5965,2919],{"class":1328},[137,5967,5968],{"class":157},"MessageFilterPointListener",[137,5970,5971],{"class":1332},"::msgCallback, ",[137,5973,1715],{"class":527},[137,5975,1718],{"class":1332},[137,5977,5978],{"class":139,"line":1853},[137,5979,1744],{"class":1332},[137,5981,5982],{"class":139,"line":1870},[137,5983,144],{"emptyLinePlaceholder":143},[137,5985,5986],{"class":139,"line":1885},[137,5987,1755],{"class":1328},[137,5989,5990,5992,5995,5997,5999,6001,6003,6005,6007,6009],{"class":139,"line":1890},[137,5991,1767],{"class":1328},[137,5993,5994],{"class":157}," msgCallback",[137,5996,1648],{"class":1332},[137,5998,2959],{"class":1328},[137,6000,893],{"class":157},[137,6002,1586],{"class":1332},[137,6004,1803],{"class":157},[137,6006,1586],{"class":1332},[137,6008,3927],{"class":157},[137,6010,6011],{"class":1332},"::SharedPtr point_ptr){\n",[137,6013,6014,6016,6018,6020],{"class":139,"line":1910},[137,6015,1798],{"class":157},[137,6017,1586],{"class":1332},[137,6019,1803],{"class":157},[137,6021,6022],{"class":1332},"::PointStamped point_out;\n",[137,6024,6025,6028],{"class":139,"line":1927},[137,6026,6027],{"class":1328},"    try",[137,6029,3656],{"class":1332},[137,6031,6032,6035,6038,6040,6042],{"class":139,"line":1944},[137,6033,6034],{"class":1332},"      tf2_buffer_->",[137,6036,6037],{"class":157},"transform",[137,6039,1648],{"class":1332},[137,6041,2834],{"class":1328},[137,6043,6044],{"class":1332},"point_ptr, point_out, target_frame_);\n",[137,6046,6047,6049],{"class":139,"line":1953},[137,6048,4681],{"class":157},[137,6050,1962],{"class":1332},[137,6052,6053,6056,6058,6060,6063,6066,6068,6070,6072,6074,6076,6078],{"class":139,"line":1965},[137,6054,6055],{"class":527},"        this",[137,6057,1732],{"class":1332},[137,6059,2180],{"class":157},[137,6061,6062],{"class":1332},"(), ",[137,6064,6065],{"class":161},"\"坐标点相对于base_link的坐标:(",[137,6067,4776],{"class":527},[137,6069,3726],{"class":161},[137,6071,4776],{"class":527},[137,6073,3726],{"class":161},[137,6075,4776],{"class":527},[137,6077,4787],{"class":161},[137,6079,2904],{"class":1332},[137,6081,6082],{"class":139,"line":1979},[137,6083,6084],{"class":1332},"        point_out.point.x,\n",[137,6086,6087],{"class":139,"line":1991},[137,6088,6089],{"class":1332},"        point_out.point.y,\n",[137,6091,6092],{"class":139,"line":2004},[137,6093,6094],{"class":1332},"        point_out.point.z);\n",[137,6096,6097,6100,6103,6106,6108,6111,6113],{"class":139,"line":2020},[137,6098,6099],{"class":1332},"    } ",[137,6101,6102],{"class":1328},"catch",[137,6104,6105],{"class":1332}," (",[137,6107,4673],{"class":157},[137,6109,6110],{"class":1332},"::TransformException ",[137,6112,2919],{"class":1328},[137,6114,6115],{"class":1332}," ex) {\n",[137,6117,6118,6121],{"class":139,"line":2035},[137,6119,6120],{"class":157},"      RCLCPP_WARN",[137,6122,1962],{"class":1332},[137,6124,6125],{"class":139,"line":2050},[137,6126,6127],{"class":150},"        // Print exception which was caughtthis->get_logger(), \"Failure %s\\n\", ex.what());\n",[137,6129,6130],{"class":139,"line":2065},[137,6131,3784],{"class":1332},[137,6133,6134],{"class":139,"line":2070},[137,6135,1744],{"class":1332},[137,6137,6138,6140],{"class":139,"line":2076},[137,6139,2096],{"class":157},[137,6141,6142],{"class":1332},"::string target_frame_;\n",[137,6144,6145,6147,6149,6151,6153,6155,6157],{"class":139,"line":2088},[137,6146,2096],{"class":157},[137,6148,2099],{"class":1332},[137,6150,1702],{"class":1328},[137,6152,926],{"class":157},[137,6154,4917],{"class":1332},[137,6156,2109],{"class":1328},[137,6158,6159],{"class":1332}," tf2_buffer_;\n",[137,6161,6162,6164,6166,6168,6170,6172,6174],{"class":139,"line":2093},[137,6163,2096],{"class":157},[137,6165,2099],{"class":1332},[137,6167,1702],{"class":1328},[137,6169,926],{"class":157},[137,6171,4899],{"class":1332},[137,6173,2109],{"class":1328},[137,6175,6176],{"class":1332}," tf2_listener_;\n",[137,6178,6179,6182,6185,6187,6189,6191,6193,6195,6197],{"class":139,"line":2115},[137,6180,6181],{"class":157},"  message_filters",[137,6183,6184],{"class":1332},"::Subscriber",[137,6186,1702],{"class":1328},[137,6188,3709],{"class":157},[137,6190,1586],{"class":1332},[137,6192,1803],{"class":157},[137,6194,3716],{"class":1332},[137,6196,2109],{"class":1328},[137,6198,6199],{"class":1332}," point_sub_;\n",[137,6201,6202,6204,6206,6208,6210,6213,6215,6217,6219,6221,6223,6226],{"class":139,"line":2121},[137,6203,2096],{"class":157},[137,6205,2099],{"class":1332},[137,6207,1702],{"class":1328},[137,6209,926],{"class":157},[137,6211,6212],{"class":1332},"::MessageFilter",[137,6214,1702],{"class":1328},[137,6216,3709],{"class":157},[137,6218,1586],{"class":1332},[137,6220,1803],{"class":157},[137,6222,3716],{"class":1332},[137,6224,6225],{"class":1328},">>",[137,6227,6228],{"class":1332}," tf2_filter_;\n",[137,6230,6231],{"class":139,"line":2126},[137,6232,2118],{"class":1332},[137,6234,6235],{"class":139,"line":2154},[137,6236,144],{"emptyLinePlaceholder":143},[137,6238,6239,6241,6243,6245,6247,6250,6252,6254],{"class":139,"line":2159},[137,6240,2129],{"class":1328},[137,6242,2132],{"class":157},[137,6244,1648],{"class":1332},[137,6246,2129],{"class":1328},[137,6248,6249],{"class":1332}," argc, ",[137,6251,1651],{"class":1328},[137,6253,1654],{"class":1328},[137,6255,6256],{"class":1332}," argv[]){\n",[137,6258,6259],{"class":139,"line":2165},[137,6260,3276],{"class":150},[137,6262,6263,6265,6267,6269],{"class":139,"line":2190},[137,6264,2263],{"class":157},[137,6266,1586],{"class":1332},[137,6268,2268],{"class":157},[137,6270,2271],{"class":1332},[137,6272,6273],{"class":139,"line":2195},[137,6274,3291],{"class":150},[137,6276,6277,6279,6281,6283,6285,6287,6289,6291,6293,6295],{"class":139,"line":2213},[137,6278,2263],{"class":157},[137,6280,1586],{"class":1332},[137,6282,2287],{"class":157},[137,6284,1648],{"class":1332},[137,6286,2292],{"class":157},[137,6288,1586],{"class":1332},[137,6290,1699],{"class":157},[137,6292,1702],{"class":1332},[137,6294,5968],{"class":157},[137,6296,3314],{"class":1332},[137,6298,6299],{"class":139,"line":2221},[137,6300,3319],{"class":150},[137,6302,6303,6305,6307,6309],{"class":139,"line":2232},[137,6304,2263],{"class":157},[137,6306,1586],{"class":1332},[137,6308,2320],{"class":157},[137,6310,1839],{"class":1332},[137,6312,6313,6315,6317],{"class":139,"line":2244},[137,6314,2328],{"class":1328},[137,6316,1225],{"class":527},[137,6318,2241],{"class":1332},[137,6320,6321],{"class":139,"line":2249},[137,6322,2338],{"class":1332},[20,6324,6325],{},[23,6326],{"alt":25,"src":6327},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1337.webp",[20,6329,6330],{},"Set the above parameter.",[20,6332,6333],{},[23,6334],{"alt":25,"src":6335},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1338.webp",[20,6337,6338],{},[23,6339],{"alt":25,"src":6340},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1339.webp",[20,6342,6343],{},[23,6344],{"alt":25,"src":6345},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1340.webp",[20,6347,6348],{},"Perform data parsing.",[20,6350,6351],{},[23,6352],{"alt":25,"src":6353},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1341.webp",[20,6355,6356],{},"Use the first overload.",[20,6358,6359],{},"The conversion process may throw an exception, but you can ignore it. If the conversion fails, an exception will be automatically thrown in the terminal.",[20,6361,6362],{},[23,6363],{"alt":25,"src":6364},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1342.webp",[20,6366,6367],{},"In the current workspace, open three terminals. In terminal 1, enter the following command to publish the static coordinate transform of the laser relative to the base_link:",[129,6369,6370],{"className":131,"code":2427,"language":133,"meta":25,"style":25},[33,6371,6372,6380],{"__ignoreMap":25},[137,6373,6374,6376,6378],{"class":139,"line":140},[137,6375,99],{"class":527},[137,6377,2436],{"class":161},[137,6379,2439],{"class":1332},[137,6381,6382,6384,6386,6388,6390,6392,6394,6396,6398,6400,6402,6404],{"class":139,"line":147},[137,6383,295],{"class":157},[137,6385,322],{"class":161},[137,6387,872],{"class":161},[137,6389,2450],{"class":161},[137,6391,1220],{"class":527},[137,6393,1225],{"class":527},[137,6395,1230],{"class":527},[137,6397,1225],{"class":527},[137,6399,1225],{"class":527},[137,6401,1225],{"class":527},[137,6403,1133],{"class":161},[137,6405,1138],{"class":161},[20,6407,4122],{},[129,6409,6410],{"className":131,"code":4125,"language":133,"meta":25,"style":25},[33,6411,6412,6420],{"__ignoreMap":25},[137,6413,6414,6416,6418],{"class":139,"line":140},[137,6415,99],{"class":527},[137,6417,2436],{"class":161},[137,6419,2439],{"class":1332},[137,6421,6422,6424,6426,6428],{"class":139,"line":147},[137,6423,295],{"class":157},[137,6425,322],{"class":161},[137,6427,872],{"class":161},[137,6429,4146],{"class":161},[20,6431,6432],{},"In terminal 3, execute the following command to perform coordinate point transformation:",[129,6434,6436],{"className":131,"code":6435,"language":133,"meta":25,"style":25},". install/setup.bash \nros2 run cpp04_tf_listener demo02_message_filter\n",[33,6437,6438,6446],{"__ignoreMap":25},[137,6439,6440,6442,6444],{"class":139,"line":140},[137,6441,99],{"class":527},[137,6443,2436],{"class":161},[137,6445,2439],{"class":1332},[137,6447,6448,6450,6452,6454],{"class":139,"line":147},[137,6449,295],{"class":157},[137,6451,322],{"class":161},[137,6453,4277],{"class":161},[137,6455,6456],{"class":161}," demo02_message_filter\n",[20,6458,6459],{},"Terminal 3 will output the coordinate point relative to base_link. For specific results, please refer to Case 2.",[20,6461,6462],{},"Publish in order.",[20,6464,6465],{},[23,6466],{"alt":25,"src":6467},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1343.webp",[20,6469,6470],{},[23,6471],{"alt":25,"src":6472},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1344.webp",[10,6474,6476],{"id":6475},"coordinate-transformation-tool","Coordinate Transformation Tool",[20,6478,6479,6480,354,6482,99],{},"In the ROS2 TF framework, in addition to encapsulating coordinate broadcasting and subscription functionality, it also provides some tools that can help us improve development and debugging efficiency. This section mainly introduces the use of these tools, which primarily involve two packages: ",[33,6481,926],{},[33,6483,6484],{},"tf2_tools",[20,6486,6487,6488,6490],{},"The commonly used nodes provided in the ",[33,6489,926],{}," package are as follows:",[6492,6493,6494,6497,6500],"ul",{},[808,6495,6496],{},"static_transform_publisher: This node is used to broadcast static coordinate transforms (used many times).",[808,6498,6499],{},"tf2_monitor: This node prints the publishing frequency and network latency for all or specific coordinate frames.",[808,6501,6502],{},"tf2_echo: This node is used to print the translation and rotation relationships of a specific coordinate frame.",[20,6504,6505,6506,6490],{},"The nodes provided in the ",[33,6507,6484],{},[6492,6509,6510],{},[808,6511,6512],{},"view_frames: This node can generate a PDF file that displays the relationship between coordinate frames. The file contains a tree-structured coordinate frame graph.",[20,6514,6515,6516,6518,6519,6521,6522,6524],{},"Among the many tools mentioned above, the ",[33,6517,930],{}," node in the ",[33,6520,926],{}," package has already been detailed in the ",[30,6523,2472],{}," section, so it will not be covered again in this section.",[20,6526,6527],{},[30,6528,6529],{},"Preparation:",[20,6531,6532,6533,6536,6537,99],{},"To better demonstrate the use of the tool, please start several coordinate frame broadcasting nodes first. For example, you can broadcast some coordinate frame messages using a ",[30,6534,6535],{},"static broadcaster (command)"," and a ",[30,6538,6539],{},"dynamic broadcaster (C++)",[20,6541,6542],{},"First terminal:",[129,6544,6545],{"className":131,"code":1203,"language":133,"meta":25,"style":25},[33,6546,6547],{"__ignoreMap":25},[137,6548,6549,6551,6553,6555,6557,6559,6561,6563,6565,6567,6569,6571,6573,6575,6577,6579,6581,6583,6585,6587],{"class":139,"line":140},[137,6550,295],{"class":157},[137,6552,322],{"class":161},[137,6554,890],{"class":161},[137,6556,955],{"class":161},[137,6558,958],{"class":527},[137,6560,1220],{"class":527},[137,6562,963],{"class":527},[137,6564,1225],{"class":527},[137,6566,968],{"class":527},[137,6568,1230],{"class":527},[137,6570,973],{"class":527},[137,6572,1235],{"class":527},[137,6574,985],{"class":527},[137,6576,1225],{"class":527},[137,6578,979],{"class":527},[137,6580,1225],{"class":527},[137,6582,991],{"class":527},[137,6584,1133],{"class":161},[137,6586,996],{"class":527},[137,6588,1138],{"class":161},[20,6590,6591],{},"Second terminal:",[129,6593,6594],{"className":131,"code":1257,"language":133,"meta":25,"style":25},[33,6595,6596],{"__ignoreMap":25},[137,6597,6598,6600,6602,6604,6606,6608,6610,6612,6614,6616,6618,6620,6622,6624,6626,6628,6630,6632,6634,6636],{"class":139,"line":140},[137,6599,295],{"class":157},[137,6601,322],{"class":161},[137,6603,890],{"class":161},[137,6605,955],{"class":161},[137,6607,958],{"class":527},[137,6609,1274],{"class":527},[137,6611,963],{"class":527},[137,6613,1225],{"class":527},[137,6615,968],{"class":527},[137,6617,1220],{"class":527},[137,6619,973],{"class":527},[137,6621,1225],{"class":527},[137,6623,985],{"class":527},[137,6625,1225],{"class":527},[137,6627,979],{"class":527},[137,6629,1225],{"class":527},[137,6631,991],{"class":527},[137,6633,1133],{"class":161},[137,6635,996],{"class":527},[137,6637,1303],{"class":161},[20,6639,6640],{},"Third terminal:",[129,6642,6644],{"className":131,"code":6643,"language":133,"meta":25,"style":25},"ros2 run turtlesim turtlesim_node\n",[33,6645,6646],{"__ignoreMap":25},[137,6647,6648,6650,6652,6654],{"class":139,"line":140},[137,6649,295],{"class":157},[137,6651,322],{"class":161},[137,6653,325],{"class":161},[137,6655,6656],{"class":161}," turtlesim_node\n",[20,6658,6659],{},"The fourth terminal:",[129,6661,6662],{"className":131,"code":313,"language":133,"meta":25,"style":25},[33,6663,6664],{"__ignoreMap":25},[137,6665,6666,6668,6670,6672],{"class":139,"line":140},[137,6667,295],{"class":157},[137,6669,322],{"class":161},[137,6671,325],{"class":161},[137,6673,328],{"class":161},[20,6675,6676],{},"Fifth terminal:",[129,6678,6680],{"className":131,"code":6679,"language":133,"meta":25,"style":25},"source install/setup.bash\nros2 run cpp03_tf_broadcaster demo02_dynamic_tf_broadcaster\n",[33,6681,6682,6690],{"__ignoreMap":25},[137,6683,6684,6687],{"class":139,"line":140},[137,6685,6686],{"class":527},"source",[137,6688,6689],{"class":161}," install/setup.bash\n",[137,6691,6692,6694,6696,6698],{"class":139,"line":147},[137,6693,295],{"class":157},[137,6695,322],{"class":161},[137,6697,872],{"class":161},[137,6699,6700],{"class":161}," demo02_dynamic_tf_broadcaster\n",[20,6702,6703],{},[23,6704],{"alt":25,"src":6705},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1345.webp",[20,6707,6708],{},"The above is the preparation work.",[362,6710,6712],{"id":6711},"_1tf2_monitor","1.tf2_monitor",[6714,6715,6717],"h6",{"id":6716},"_11-print-the-publishing-frequency-and-network-latency-of-all-coordinate-frames","1.1 Print the publishing frequency and network latency of all coordinate frames",[20,6719,6720],{},"Execute the command in the terminal:",[129,6722,6724],{"className":131,"code":6723,"language":133,"meta":25,"style":25},"ros2 run tf2_ros tf2_monitor\n",[33,6725,6726],{"__ignoreMap":25},[137,6727,6728,6730,6732,6734],{"class":139,"line":140},[137,6729,295],{"class":157},[137,6731,322],{"class":161},[137,6733,890],{"class":161},[137,6735,6736],{"class":161}," tf2_monitor\n",[20,6738,6739],{},[30,6740,6741],{},"Running result:",[20,6743,6744],{},[23,6745],{"alt":25,"src":6746},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1346.webp",[20,6748,6749],{},"This command has a 10-second blocking time because it needs to measure frequency within an interval.",[20,6751,6752],{},"Static ones remain unchanged, while the publishing frequency of dynamic ones varies to some extent.",[20,6754,6755],{},"This function will publish again every 10 seconds.",[6714,6757,6759],{"id":6758},"_12-print-the-publishing-frequency-and-network-latency-of-the-specified-coordinate-system","1.2 Print the publishing frequency and network latency of the specified coordinate system",[20,6761,6720],{},[129,6763,6765],{"className":131,"code":6764,"language":133,"meta":25,"style":25},"ros2 run tf2_ros tf2_monitor camera laser\n",[33,6766,6767],{"__ignoreMap":25},[137,6768,6769,6771,6773,6775,6778,6780],{"class":139,"line":140},[137,6770,295],{"class":157},[137,6772,322],{"class":161},[137,6774,890],{"class":161},[137,6776,6777],{"class":161}," tf2_monitor",[137,6779,5133],{"class":161},[137,6781,1138],{"class":161},[20,6783,6784],{},[30,6785,6741],{},[20,6787,6788],{},[23,6789],{"alt":25,"src":6790},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1347.webp",[20,6792,6793],{},"It's normal to get errors when data can't be fetched from the cache at first.",[362,6795,6797],{"id":6796},"_2tf2_echo","2.tf2_echo",[20,6799,6800],{},"Print the translation and rotation relationship between two coordinate systems.",[20,6802,6720],{},[129,6804,6806],{"className":131,"code":6805,"language":133,"meta":25,"style":25},"ros2 run tf2_ros tf2_echo world turtle1\n",[33,6807,6808],{"__ignoreMap":25},[137,6809,6810,6812,6814,6816,6819,6822],{"class":139,"line":140},[137,6811,295],{"class":157},[137,6813,322],{"class":161},[137,6815,890],{"class":161},[137,6817,6818],{"class":161}," tf2_echo",[137,6820,6821],{"class":161}," world",[137,6823,6824],{"class":161}," turtle1\n",[20,6826,6827],{},[30,6828,6741],{},[20,6830,6831],{},[23,6832],{"alt":25,"src":6833},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1348.webp",[20,6835,6836],{},"The translation and rotation amounts will be output.",[20,6838,6839,6840,6844],{},"It can be expressed in several ways, such as ",[6841,6842,6843],"em",{},"translation distance, quaternion, Euler angles in radians, Euler angles in degrees, matrix",", etc.",[20,6846,6847],{},[23,6848],{"alt":25,"src":6849},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1349.webp",[20,6851,6852],{},"When the turtle man 🐢🚹 moves, the value also changes.",[362,6854,6856],{"id":6855},"_3-view_frames-commonly-used","3. view_frames (commonly used)",[20,6858,6859],{},"Display the coordinate system relationships graphically.",[20,6861,6720],{},[129,6863,6865],{"className":131,"code":6864,"language":133,"meta":25,"style":25},"ros2 run tf2_tools view_frames\n",[33,6866,6867],{"__ignoreMap":25},[137,6868,6869,6871,6873,6876],{"class":139,"line":140},[137,6870,295],{"class":157},[137,6872,322],{"class":161},[137,6874,6875],{"class":161}," tf2_tools",[137,6877,6878],{"class":161}," view_frames\n",[20,6880,6881,6882,354,6885,6888,6889,6892],{},"Result: The files ",[30,6883,6884],{},"frames_xxxx.gv",[30,6886,6887],{},"frames_xxxx.pdf"," will be generated in the ",[30,6890,6891],{},"current directory",", where xxxx is a timestamp. Opening the pdf file displays the following content:",[20,6894,6895],{},[23,6896],{"alt":25,"src":6897},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1350.webp",[20,6899,6900],{},"This node will listen for 5 seconds and generate the corresponding file.",[20,6902,6903],{},[23,6904],{"alt":25,"src":6905},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1351.webp",[20,6907,6908],{},[23,6909],{"alt":25,"src":6910},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2023/12/30/image1352.webp",[20,6912,6913],{},"The image above shows two coordinate trees, but in an actual project, we can only design one tree, not two.",[10,6915,6917],{"id":6916},"practice","Practice",[15,6919,6921],{"id":6920},"turtle-following","Turtle following",[15,6923,6925],{"id":6924},"turtle-escort","Turtle Escort",[10,6927,4175],{"id":6928},"summary-1",[6930,6931,6932],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":25,"searchDepth":147,"depth":147,"links":6934},[6935,6936,6937,6938,6939,6940],{"id":12,"depth":154,"text":13},{"id":739,"depth":154,"text":740},{"id":4192,"depth":154,"text":4193},{"id":6475,"depth":154,"text":6476},{"id":6916,"depth":154,"text":6917},{"id":6928,"depth":154,"text":4175},"/en-us/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf",8000000,"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/ch8-坐标变换TF",false,null,"en-US","en-us",{},{"title":5,"description":25},"/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf","_i18n/en-us/wiki/2023-12-30-ros2-tutorial/ch8-坐标变换TF","6K2MzmahBwa9TKMb-uNTKARGK4PevhMF8hHj22v5zGk",[6960,6965,6970,6976,6982,6988,6994,7000,7006,7012,7018,7024,7030,7036,7042,7048,7054,7060,7065,7071,7076,7082,7088,7094,7100,7106,7112,7118,7124,7130,7136,7142,7148,7154,7160,7166,7172,7178,7184,7190,7196,7202,7208,7214,7220,7226,7232,7238,7244,7250,7256,7261,7267,7272,7277,7282,7287,7292,7293,7299],{"path":6961,"stem":6962,"title":6963,"date":6943,"chapter":1904,"chapterSort":6964,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":6966,"stem":6967,"title":6968,"date":6943,"chapter":2901,"chapterSort":6969,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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",10000000,{"path":6971,"stem":6972,"title":6973,"date":6943,"chapter":6974,"chapterSort":6975,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":6977,"stem":6978,"title":6979,"date":6943,"chapter":6980,"chapterSort":6981,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":6983,"stem":6984,"title":6985,"date":6943,"chapter":6986,"chapterSort":6987,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":6989,"stem":6990,"title":6991,"date":6943,"chapter":6992,"chapterSort":6993,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":6995,"stem":6996,"title":6997,"date":6943,"chapter":6998,"chapterSort":6999,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7001,"stem":7002,"title":7003,"date":6943,"chapter":7004,"chapterSort":7005,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7007,"stem":7008,"title":7009,"date":6943,"chapter":7010,"chapterSort":7011,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7013,"stem":7014,"title":7015,"date":6943,"chapter":7016,"chapterSort":7017,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7019,"stem":7020,"title":7021,"date":6943,"chapter":7022,"chapterSort":7023,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7025,"stem":7026,"title":7027,"date":6943,"chapter":7028,"chapterSort":7029,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7031,"stem":7032,"title":7033,"date":6943,"chapter":7034,"chapterSort":7035,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7037,"stem":7038,"title":7039,"date":6943,"chapter":7040,"chapterSort":7041,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7043,"stem":7044,"title":7045,"date":6943,"chapter":7046,"chapterSort":7047,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7049,"stem":7050,"title":7051,"date":6943,"chapter":7052,"chapterSort":7053,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7055,"stem":7056,"title":7057,"date":6943,"chapter":7058,"chapterSort":7059,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7061,"stem":7062,"title":7027,"date":6943,"chapter":7063,"chapterSort":7064,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7066,"stem":7067,"title":7068,"date":6943,"chapter":7069,"chapterSort":7070,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7072,"stem":7073,"title":7027,"date":6943,"chapter":7074,"chapterSort":7075,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7077,"stem":7078,"title":7079,"date":6943,"chapter":7080,"chapterSort":7081,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7083,"stem":7084,"title":7085,"date":6943,"chapter":7086,"chapterSort":7087,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7089,"stem":7090,"title":7091,"date":6943,"chapter":7092,"chapterSort":7093,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7095,"stem":7096,"title":7097,"date":6943,"chapter":7098,"chapterSort":7099,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7101,"stem":7102,"title":7103,"date":6943,"chapter":7104,"chapterSort":7105,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7107,"stem":7108,"title":7109,"date":6943,"chapter":7110,"chapterSort":7111,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7113,"stem":7114,"title":7115,"date":6943,"chapter":7116,"chapterSort":7117,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7119,"stem":7120,"title":7121,"date":6943,"chapter":7122,"chapterSort":7123,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7125,"stem":7126,"title":7127,"date":6943,"chapter":7128,"chapterSort":7129,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7131,"stem":7132,"title":7133,"date":6943,"chapter":7134,"chapterSort":7135,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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","odometry","14.6.1",14060100,{"path":7137,"stem":7138,"title":7139,"date":6943,"chapter":7140,"chapterSort":7141,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7143,"stem":7144,"title":7145,"date":6943,"chapter":7146,"chapterSort":7147,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7149,"stem":7150,"title":7151,"date":6943,"chapter":7152,"chapterSort":7153,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7155,"stem":7156,"title":7157,"date":6943,"chapter":7158,"chapterSort":7159,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7161,"stem":7162,"title":7163,"date":6943,"chapter":7164,"chapterSort":7165,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7167,"stem":7168,"title":7169,"date":6943,"chapter":7170,"chapterSort":7171,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7173,"stem":7174,"title":7175,"date":6943,"chapter":7176,"chapterSort":7177,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7179,"stem":7180,"title":7181,"date":6943,"chapter":7182,"chapterSort":7183,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7185,"stem":7186,"title":7187,"date":6943,"chapter":7188,"chapterSort":7189,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7191,"stem":7192,"title":7193,"date":6943,"chapter":7194,"chapterSort":7195,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7197,"stem":7198,"title":7199,"date":6943,"chapter":7200,"chapterSort":7201,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7203,"stem":7204,"title":7205,"date":6943,"chapter":7206,"chapterSort":7207,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7209,"stem":7210,"title":7211,"date":6943,"chapter":7212,"chapterSort":7213,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7215,"stem":7216,"title":7217,"date":6943,"chapter":7218,"chapterSort":7219,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7221,"stem":7222,"title":7223,"date":6943,"chapter":7224,"chapterSort":7225,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7227,"stem":7228,"title":7229,"date":6943,"chapter":7230,"chapterSort":7231,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/en-us/wiki/2023-12-30-ros2-tutorial/ch15-ros2-control","_i18n/en-us/wiki/2023-12-30-ros2-tutorial/ch15-ROS2_Control","ROS2_Control","15",15000000,{"path":7233,"stem":7234,"title":7235,"date":6943,"chapter":7236,"chapterSort":7237,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7239,"stem":7240,"title":7241,"date":6943,"chapter":7242,"chapterSort":7243,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7245,"stem":7246,"title":7247,"date":6943,"chapter":7248,"chapterSort":7249,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7251,"stem":7252,"title":7253,"date":6943,"chapter":7254,"chapterSort":7255,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7257,"stem":7258,"title":7259,"date":6943,"chapter":1922,"chapterSort":7260,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7262,"stem":7263,"title":7264,"date":6943,"chapter":7265,"chapterSort":7266,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7268,"stem":7269,"title":7270,"date":6943,"chapter":1939,"chapterSort":7271,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":7273,"stem":7274,"title":7275,"date":6943,"chapter":1973,"chapterSort":7276,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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",4000000,{"path":7278,"stem":7279,"title":7280,"date":6943,"chapter":1986,"chapterSort":7281,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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",5000000,{"path":7283,"stem":7284,"title":7285,"date":6943,"chapter":1998,"chapterSort":7286,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/en-us/wiki/2023-12-30-ros2-tutorial/ch6-launch","_i18n/en-us/wiki/2023-12-30-ros2-tutorial/ch6-Launch","Launch",6000000,{"path":7288,"stem":7289,"title":7290,"date":6943,"chapter":1864,"chapterSort":7291,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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",7000000,{"path":6941,"stem":6957,"title":5,"date":6943,"chapter":1880,"chapterSort":6942,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},{"path":7294,"stem":7295,"title":7296,"date":6943,"chapter":7297,"chapterSort":7298,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":6950},"/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":6946,"stem":7300,"title":7301,"date":6943,"chapter":6951,"chapterSort":7302,"docKey":6945,"docRoot":6946,"docTitle":6947,"isWikiDoc":143,"isWikiIndex":143},"_i18n/en-us/wiki/2023-12-30-ros2-tutorial/index","ROS2 Robot Operating System Tutorial",0,{"variants":7304},[7305,7306,7309,7312,7315],{"path":6941,"localeSlug":6953,"i18nKey":6949},{"path":7307,"localeSlug":7308,"i18nKey":6949},"/zh-hant/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf","zh-hant",{"path":7310,"localeSlug":7311,"i18nKey":6949},"/zh-hk/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf","zh-hk",{"path":7313,"localeSlug":7314,"i18nKey":6949},"/zh-tw/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf","zh-tw",{"path":7316,"localeSlug":7317,"i18nKey":6949},"/zh-cn/wiki/2023-12-30-ros2-tutorial/ch8-zuo-biao-bian-huan-tf","zh-cn",[6941,6956,7307,6956,7310,6956,7313,6956,7316,6956],1780671798860]