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