当前位置: 首页 > news >正文

建设网站最重要的是什么西乡专业做网站公司

建设网站最重要的是什么,西乡专业做网站公司,优购网官方网上商城,wordpress 编辑 所见即所得插件前言 往期内容#xff1a; 第一期#xff1a;【10天速通Navigation2】(一) 框架总览和概念解释第二期#xff1a;【10天速通Navigation2】(二) #xff1a;ROS2gazebo阿克曼小车模型搭建-gazebo_ackermann_drive等插件的配置和说明 本教材将贯穿nav2的全部内容#xff0c…前言 往期内容 第一期【10天速通Navigation2】(一) 框架总览和概念解释第二期【10天速通Navigation2】(二) ROS2gazebo阿克曼小车模型搭建-gazebo_ackermann_drive等插件的配置和说明 本教材将贯穿nav2的全部内容使用ROS2和C实现一些仿真乃至实车中常见的建图和路径规划算法例如cartographer,ORB-SLAM,RRT,hybrid-astar。我们将注重与原理讲解和代码实现去详细讲解每一步的配置过程和代码复现细节。同理本教材默认大家有一些基础的ROS2和C的编程基础故不对一些基础部分进行详细说明。本教程使用的环境 ROS2 humbleubuntu 22.04 LTS 本期我们将从建图算法cartographer原理入手再从仿真到实车进行配置达到以下的效果 仿真建图实车建图 1 Cartographer原理解读 1-1 介绍 Cartographer是由Google开发的一套基于图优化的激光SLAMSimultaneous Localization and Mapping即时定位与地图构建算法。该算法同时支持2D和3D激光SLAM能够跨平台使用并支持多种传感器配置如Lidar激光雷达、IMU惯性测量单元、Odometry里程计、GPS和Landmark等。为啥不使用基于滤波方法的Gmapping 当地图很大的时候粒子更新的计算量和实时性有问题粒子估计计算量会成倍增加Gmapping没有闭环检测。 下述大部分内容节选自《机器人SLAM导航核心技术与实战》,书本关于SLAM的内容讲得很好这里结合了本人的理解一起呈现给大家。 1-2 基于优化方法方法的SLAM系统 基于优化方法方法的SLAM系统通常采用前端建图闭环检测后端全局优化这样的经典框架。 #mermaid-svg-4oyRfUFeNnaVM92b {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-4oyRfUFeNnaVM92b .error-icon{fill:#552222;}#mermaid-svg-4oyRfUFeNnaVM92b .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4oyRfUFeNnaVM92b .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-4oyRfUFeNnaVM92b .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4oyRfUFeNnaVM92b .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4oyRfUFeNnaVM92b .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4oyRfUFeNnaVM92b .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4oyRfUFeNnaVM92b .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4oyRfUFeNnaVM92b .marker.cross{stroke:#333333;}#mermaid-svg-4oyRfUFeNnaVM92b svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4oyRfUFeNnaVM92b .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4oyRfUFeNnaVM92b .cluster-label text{fill:#333;}#mermaid-svg-4oyRfUFeNnaVM92b .cluster-label span{color:#333;}#mermaid-svg-4oyRfUFeNnaVM92b .label text,#mermaid-svg-4oyRfUFeNnaVM92b span{fill:#333;color:#333;}#mermaid-svg-4oyRfUFeNnaVM92b .node rect,#mermaid-svg-4oyRfUFeNnaVM92b .node circle,#mermaid-svg-4oyRfUFeNnaVM92b .node ellipse,#mermaid-svg-4oyRfUFeNnaVM92b .node polygon,#mermaid-svg-4oyRfUFeNnaVM92b .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4oyRfUFeNnaVM92b .node .label{text-align:center;}#mermaid-svg-4oyRfUFeNnaVM92b .node.clickable{cursor:pointer;}#mermaid-svg-4oyRfUFeNnaVM92b .arrowheadPath{fill:#333333;}#mermaid-svg-4oyRfUFeNnaVM92b .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4oyRfUFeNnaVM92b .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4oyRfUFeNnaVM92b .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-4oyRfUFeNnaVM92b .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-4oyRfUFeNnaVM92b .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4oyRfUFeNnaVM92b .cluster text{fill:#333;}#mermaid-svg-4oyRfUFeNnaVM92b .cluster span{color:#333;}#mermaid-svg-4oyRfUFeNnaVM92b div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4oyRfUFeNnaVM92b :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 传感器数据 前端: 局部建图 闭环检测 后端: 全局建图 全局优化 这样基于优化方法就可以实现大规模地图的构建。 只要有新的传感器数据输入前端的局部建图就会实时的进行这样就可以保证实时性一旦检测到回环后端建图就开始了保证计算量。后端运行的时候即使计算量很大计算速度很慢但是不影响前端不影响实时性 1-3 局部建图 在进一步了解Cartographer局部地图构建的原理之前我们首先需要知道Cartographer的地图结构Cartographer采用局部地图采用局部子图(submap)的方式来组织整个地图,而每个子图都是由一些系列雷达帧组成的通过拼接局部地图我们就获得了一张张局部地图submap。全部的局部地图拼接在一起我们就得到了全局地图。 #mermaid-svg-KJjCgQWNUWOLhIyg {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KJjCgQWNUWOLhIyg .error-icon{fill:#552222;}#mermaid-svg-KJjCgQWNUWOLhIyg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KJjCgQWNUWOLhIyg .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-KJjCgQWNUWOLhIyg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KJjCgQWNUWOLhIyg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KJjCgQWNUWOLhIyg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KJjCgQWNUWOLhIyg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KJjCgQWNUWOLhIyg .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KJjCgQWNUWOLhIyg .marker.cross{stroke:#333333;}#mermaid-svg-KJjCgQWNUWOLhIyg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KJjCgQWNUWOLhIyg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-KJjCgQWNUWOLhIyg .cluster-label text{fill:#333;}#mermaid-svg-KJjCgQWNUWOLhIyg .cluster-label span{color:#333;}#mermaid-svg-KJjCgQWNUWOLhIyg .label text,#mermaid-svg-KJjCgQWNUWOLhIyg span{fill:#333;color:#333;}#mermaid-svg-KJjCgQWNUWOLhIyg .node rect,#mermaid-svg-KJjCgQWNUWOLhIyg .node circle,#mermaid-svg-KJjCgQWNUWOLhIyg .node ellipse,#mermaid-svg-KJjCgQWNUWOLhIyg .node polygon,#mermaid-svg-KJjCgQWNUWOLhIyg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KJjCgQWNUWOLhIyg .node .label{text-align:center;}#mermaid-svg-KJjCgQWNUWOLhIyg .node.clickable{cursor:pointer;}#mermaid-svg-KJjCgQWNUWOLhIyg .arrowheadPath{fill:#333333;}#mermaid-svg-KJjCgQWNUWOLhIyg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KJjCgQWNUWOLhIyg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KJjCgQWNUWOLhIyg .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-KJjCgQWNUWOLhIyg .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-KJjCgQWNUWOLhIyg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KJjCgQWNUWOLhIyg .cluster text{fill:#333;}#mermaid-svg-KJjCgQWNUWOLhIyg .cluster span{color:#333;}#mermaid-svg-KJjCgQWNUWOLhIyg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KJjCgQWNUWOLhIyg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 雷达帧1 局部地图1 雷达帧2 雷达帧3 局部地图2 雷达帧4 全局地图 局部建图就是利用传感器扫描数据构建局部地图的过程。 1-3-1 局部优化 那么在构建局部地图的过程中我们往往需要对一系列雷达扫描到的轮廓进行匹配和合并进而构建一张完整的局部地图这时候就不得不介绍两种匹配合并的算法 Scan-to-scan matching:相邻两帧之间去匹配去更新代价地图。Scan-to-map matching:采用当前雷达帧和已构建出的地图进行匹配。 很明显Scan-to-scan matching使用相邻的两帧容易造成误差累积偏差会越来越大因此在Cartographer中选取了Scan-to-map matching这样可以减小误差特征也更加明显。 1-3-2 新雷达数据加入子图–概率栅格地图更新 和Gmapping类似Cartographer的子图也采用概率栅格地图,即在栅格所划分的地图中概率值越大越表示该区域所存在障碍物的可能性越高。 之所以采用如此原理进行更新主要是应对不同雷达帧在扫描到同一个栅格时候出现不同的结果。什么意思呢也就是假如我连续两帧雷达在同一个位置扫描出的结果分别是有障碍物和无障碍物那我要怎么办 这里就需要进行两种情况的讨论了 我们以上述栅格地图为例子当前雷达 ζ \zeta ζ所处发射出的射线其中的一帧雷达数据扫描结果显示 h 3 h_3 h3​位置有障碍物这时候我们要求 h 3 h_3 h3​这个栅格以及这条射线扫描到的所有栅格进行分类讨论 如果之前的雷达帧构建的子图中 h 3 h_3 h3​和这一帧雷达经过的栅格从来没有被扫描到那么我们就使用雷达概率观测模型的 P h i t P_{hit} Phit​和 P m i s s P_{miss} Pmiss​分别对这些栅格进行概率初始化 M new ( x ) { P hit , if state ( x ) hit P miss , if state ( x ) miss M_{\text{new}}(x) \begin{cases} P_{\text{hit}}, \text{if } \text{state}(x) \text{hit} \\ P_{\text{miss}}, \text{if } \text{state}(x) \text{miss} \end{cases} Mnew​(x){Phit​,Pmiss​,​if state(x)hitif state(x)miss​ 如果之前的雷达帧构建的子图中栅格已经被初始化为 M o l d ( x ) M_{old}(x) Mold​(x)那么这时候我们就需要使用到两次不同的数据通过下属公式对该栅格进行迭代处理 M n e w ( x ) { c l a m p ( o d d s − 1 ( o d d s ( M o l d ( x ) ) ⋅ o d d s ( P h i t ) ) , 当 s t a t e ( x ) h i t 时 c l a m p ( o d d s − 1 ( o d d s ( M o l d ( x ) ) ⋅ o d d s ( P m i s s ) ) , 当 s t a t e ( x ) m i s s 时 M_{new}(x) \left\{ \begin{array}{ll} clamp(odd_s^{-1}(odd_s(M_{old}(x)) \cdot odds(P_{hit})), 当state(x)hit时 \\ clamp(odd_s^{-1}(odd_s(M_{old}(x)) \cdot odds(P_{miss})), 当state(x)miss时 \end{array} \right. Mnew​(x){clamp(odds−1​(odds​(Mold​(x))⋅odds(Phit​)),clamp(odds−1​(odds​(Mold​(x))⋅odds(Pmiss​)),​当state(x)hit时当state(x)miss时​ 其中, o d d s ( p r o b ) p r o b 1 − p r o b odds(prob)\frac{prob}{1-prob} odds(prob)1−probprob​ 通过上述更新机制我们就能处理同一个位置不同雷达帧出现不同结果的问题这常常被应用在处理环境中动态障碍物的干扰上。 1-3-3 雷达源局部优化 上述更新子图的一个重要前提是雷达的源 ζ \zeta ζ误差极小的情况下而往往在真实过程中我们同样需要对这个雷达的源 ζ \zeta ζ进行局部优化这其实是一个非线性最小二乘问题在新的雷达数据加入子图之前通过运动预测出雷达位姿附近窗口内进行搜索匹配。而对于这个问题Cartographer使用到了Ceres非线性优化工具来解决这个问题。 arg ⁡ min ⁡ ζ ∑ k 1 K ( 1 − M smooth ( T ζ h k ) ) 2 \arg \min_{\zeta} \sum_{k1}^{K} \left( 1 - M_{\text{smooth}}(T_{\zeta} h_k) \right)^2 argζmin​k1∑K​(1−Msmooth​(Tζ​hk​))2 1-4 闭环检测 尽管我们已经通过上述优化方法对于观测源雷达的位姿进行局部优化但是随着距离增加误差累积当机器人运动一圈后回到原点会发现地图无法完全闭环出现了重影。通过引入闭环检测我们可以对误差的地方进行修正,最直观的原理就是判断机器人何时回到了之前走过的地方而这通常有几种方法 暴力搜索匹配把雷达帧和地图上的所有点进行匹配耗时计算量大分支界定匹配 分支界定匹配简单说就是把地图的分辨率降低然后依次提高分辨率进行匹配类似于一种二分的感觉进行从大到小的匹配。分支界定匹配属于广度优先策略,暴力搜索匹配可以看成分支界定匹配处于最高分辨率情况下的特例 1-5 全局建图 闭环检测成功以后会触发后端全局优化并更新全局代价地图. #mermaid-svg-4a1dK2QCQm9ljlc5 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .error-icon{fill:#552222;}#mermaid-svg-4a1dK2QCQm9ljlc5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4a1dK2QCQm9ljlc5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .marker.cross{stroke:#333333;}#mermaid-svg-4a1dK2QCQm9ljlc5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4a1dK2QCQm9ljlc5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .cluster-label text{fill:#333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .cluster-label span{color:#333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .label text,#mermaid-svg-4a1dK2QCQm9ljlc5 span{fill:#333;color:#333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .node rect,#mermaid-svg-4a1dK2QCQm9ljlc5 .node circle,#mermaid-svg-4a1dK2QCQm9ljlc5 .node ellipse,#mermaid-svg-4a1dK2QCQm9ljlc5 .node polygon,#mermaid-svg-4a1dK2QCQm9ljlc5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4a1dK2QCQm9ljlc5 .node .label{text-align:center;}#mermaid-svg-4a1dK2QCQm9ljlc5 .node.clickable{cursor:pointer;}#mermaid-svg-4a1dK2QCQm9ljlc5 .arrowheadPath{fill:#333333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4a1dK2QCQm9ljlc5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-4a1dK2QCQm9ljlc5 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-4a1dK2QCQm9ljlc5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4a1dK2QCQm9ljlc5 .cluster text{fill:#333;}#mermaid-svg-4a1dK2QCQm9ljlc5 .cluster span{color:#333;}#mermaid-svg-4a1dK2QCQm9ljlc5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4a1dK2QCQm9ljlc5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 局部地图1 全局地图 局部地图2 2 Cartographer配置和参数说明 2-1 安装 那事不宜迟,我们选择最快的方法进行cartographer安装 sudo apt install ros-humble-cartographer-ros注意的是这里我们安装的是cartographer-ros而不是cartographer本身可以输入下属指令判断是否安装成功 ros2 pkg list | grep cartographer2-2 lua配置文件 Lua是一种轻量级的编程语言被广泛应用于游戏开发、脚本编写和网络应用中。Lua文件通常以.lua为扩展名包含了Lua语言的代码。在cartographer建图算法中,我们将使用lua对其中的参数进行配置: 老规矩先上完整代码我们再来细看参数 include map_builder.lua include trajectory_builder.luaoptions {map_builder MAP_BUILDER,trajectory_builder TRAJECTORY_BUILDER,map_frame map,tracking_frame base_footprint,published_frame odom,odom_frame odom,provide_odom_frame false,publish_frame_projected_to_2d false,use_pose_extrapolator true,use_odometry true,use_nav_sat false,use_landmarks false,num_laser_scans 1,num_multi_echo_laser_scans 0,num_subdivisions_per_laser_scan 1,num_point_clouds 0,lookup_transform_timeout_sec 0.5,submap_publish_period_sec 0.2,pose_publish_period_sec 5e-3,trajectory_publish_period_sec 30e-3,rangefinder_sampling_ratio 1.,odometry_sampling_ratio 1.,fixed_frame_pose_sampling_ratio 1.,imu_sampling_ratio 1.,landmarks_sampling_ratio 1., }MAP_BUILDER.use_trajectory_builder_2d true MAP_BUILDER.num_background_threads 2TRAJECTORY_BUILDER_2D.num_accumulated_range_data 1 --积累几帧激光数据作为一个标准单位scan TRAJECTORY_BUILDER_2D.min_range 0.1 --激光的最近有效距离 TRAJECTORY_BUILDER_2D.max_range 12. --激光最远的有效距离 TRAJECTORY_BUILDER_2D.missing_data_ray_length 5. --无效激光数据设置距离为该数值 TRAJECTORY_BUILDER_2D.use_imu_data false --是否使用imu数据TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching true TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window 0.1 --线距离搜索框在这个框的大小内搜索最佳scan匹配 减小该参数可以增强实时的建图效果降低闭环优化的效果形成闭环时产生的重影较多 TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher. angular_search_window math.rad(10.) --角度搜索框的大小 TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.translation_delta_cost_weight 20. TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.rotation_delta_cost_weight 2e-1 --影响的是过程中的效果间接会影响最后的优化时间长TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight 30. TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight 30. TRAJECTORY_BUILDER_2D.ceres_scan_matcher.ceres_solver_options.max_num_iterations 20TRAJECTORY_BUILDER_2D.submaps.num_range_data 40 --num_range_data设置的值与CPU有这样一种关系值小(10)CPU使用率比较稳定整体偏高值大时CPU短暂爆发使用(插入子图的时候)平时使用率低呈现极大的波动状态。 TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.hit_probability 0.55 TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.miss_probability 0.49TRAJECTORY_BUILDER_2D.motion_filter.max_distance_meters 0.05 --//尽量小点 // 如果移动距离过小, 或者时间过短, 不进行地图的更新 TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians math.rad(0.3) TRAJECTORY_BUILDER_2D.motion_filter.max_time_seconds 0.5POSE_GRAPH.optimization_problem.huber_scale 1e2 --鲁棒核函数去噪POSE_GRAPH.optimize_every_n_nodes 35 --后端优化节点 POSE_GRAPH.global_constraint_search_after_n_seconds 10 POSE_GRAPH.optimization_problem.ceres_solver_options.max_num_iterations 15 --优化迭代步数 POSE_GRAPH.optimization_problem.ceres_solver_options.num_threads 1POSE_GRAPH.constraint_builder.max_constraint_distance 15. POSE_GRAPH.constraint_builder.sampling_ratio 0.3 POSE_GRAPH.constraint_builder.min_score 0.50 POSE_GRAPH.constraint_builder.global_localization_min_score 0.6 POSE_GRAPH.constraint_builder.fast_correlative_scan_matcher.linear_search_window 3. POSE_GRAPH.constraint_builder.fast_correlative_scan_matcher.branch_and_bound_depth 5. --搜索方法界定分支法求解问题构成一个搜索树depth是构造树的深度 POSE_GRAPH.global_sampling_ratio 0.001return options2-2-1 Option options: 这是一个表table包含了Cartographer算法的各种配置选项。 include map_builder.lua include trajectory_builder.luamap_builder MAP_BUILDER, trajectory_builder TRAJECTORY_BUILDER,map_builder: 指定用于构建地图的类。 trajectory_builder: 指定用于构建轨迹的类。 map_frame map,tracking_frame base_footprint,published_frame odom,odom_frame odom,provide_odom_frame false,publish_frame_projected_to_2d false,use_pose_extrapolator true,use_odometry true,map_frame: 地图的坐标系。tracking_frame: 跟踪的坐标系通常是机器人底盘的坐标系。published_frame: 发布的坐标系通常是用于导航的坐标系。注意这里用于设置cartographer是否发布从tracking_frame到odom_frame之间的tf树 #mermaid-svg-hak3d0Yy3LYOLaBp {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-hak3d0Yy3LYOLaBp .error-icon{fill:#552222;}#mermaid-svg-hak3d0Yy3LYOLaBp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hak3d0Yy3LYOLaBp .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-hak3d0Yy3LYOLaBp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hak3d0Yy3LYOLaBp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hak3d0Yy3LYOLaBp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hak3d0Yy3LYOLaBp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hak3d0Yy3LYOLaBp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hak3d0Yy3LYOLaBp .marker.cross{stroke:#333333;}#mermaid-svg-hak3d0Yy3LYOLaBp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hak3d0Yy3LYOLaBp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-hak3d0Yy3LYOLaBp .cluster-label text{fill:#333;}#mermaid-svg-hak3d0Yy3LYOLaBp .cluster-label span{color:#333;}#mermaid-svg-hak3d0Yy3LYOLaBp .label text,#mermaid-svg-hak3d0Yy3LYOLaBp span{fill:#333;color:#333;}#mermaid-svg-hak3d0Yy3LYOLaBp .node rect,#mermaid-svg-hak3d0Yy3LYOLaBp .node circle,#mermaid-svg-hak3d0Yy3LYOLaBp .node ellipse,#mermaid-svg-hak3d0Yy3LYOLaBp .node polygon,#mermaid-svg-hak3d0Yy3LYOLaBp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hak3d0Yy3LYOLaBp .node .label{text-align:center;}#mermaid-svg-hak3d0Yy3LYOLaBp .node.clickable{cursor:pointer;}#mermaid-svg-hak3d0Yy3LYOLaBp .arrowheadPath{fill:#333333;}#mermaid-svg-hak3d0Yy3LYOLaBp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hak3d0Yy3LYOLaBp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hak3d0Yy3LYOLaBp .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-hak3d0Yy3LYOLaBp .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-hak3d0Yy3LYOLaBp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hak3d0Yy3LYOLaBp .cluster text{fill:#333;}#mermaid-svg-hak3d0Yy3LYOLaBp .cluster span{color:#333;}#mermaid-svg-hak3d0Yy3LYOLaBp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hak3d0Yy3LYOLaBp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} tracking_frame odom_frame 为了满足建图时候的tf坐标数结构完整 #mermaid-svg-N7ouk8tn8GBHQ6MM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .error-icon{fill:#552222;}#mermaid-svg-N7ouk8tn8GBHQ6MM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-N7ouk8tn8GBHQ6MM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .marker.cross{stroke:#333333;}#mermaid-svg-N7ouk8tn8GBHQ6MM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-N7ouk8tn8GBHQ6MM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .cluster-label text{fill:#333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .cluster-label span{color:#333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .label text,#mermaid-svg-N7ouk8tn8GBHQ6MM span{fill:#333;color:#333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .node rect,#mermaid-svg-N7ouk8tn8GBHQ6MM .node circle,#mermaid-svg-N7ouk8tn8GBHQ6MM .node ellipse,#mermaid-svg-N7ouk8tn8GBHQ6MM .node polygon,#mermaid-svg-N7ouk8tn8GBHQ6MM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-N7ouk8tn8GBHQ6MM .node .label{text-align:center;}#mermaid-svg-N7ouk8tn8GBHQ6MM .node.clickable{cursor:pointer;}#mermaid-svg-N7ouk8tn8GBHQ6MM .arrowheadPath{fill:#333333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-N7ouk8tn8GBHQ6MM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-N7ouk8tn8GBHQ6MM .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-N7ouk8tn8GBHQ6MM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-N7ouk8tn8GBHQ6MM .cluster text{fill:#333;}#mermaid-svg-N7ouk8tn8GBHQ6MM .cluster span{color:#333;}#mermaid-svg-N7ouk8tn8GBHQ6MM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-N7ouk8tn8GBHQ6MM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} base_footprint odom map 因此如果这里设置为false,你就需要额外在开一个新的tf静态坐标转换节点用于广播odom到base_footprint之间的变换 ros2 run tf2_ros static_transform_publisher 0.0 0.0 0.0 0.0 0.0 0.0 odom base_footprintodom_frame: 里程计坐标系。provide_odom_frame: 是否提供里程计坐标系。publish_frame_projected_to_2d: 是否将3D数据投影到2D进行发布。use_pose_extrapolator: 是否使用姿态外推器。use_odometry: 是否使用里程计数据。通常我们需要引入odom或者IMU用于辅助定位,否则会出现偏移和无法闭环的问题(后面我们会讲到)use_nav_sat: 是否使用导航卫星数据。use_landmarks: 是否使用地标数据。num_laser_scans: 使用的激光扫描仪数量。num_multi_echo_laser_scans: 使用多回声激光扫描仪的数量。num_subdivisions_per_laser_scan: 每个激光扫描数据的细分数量。num_point_clouds: 使用的点云数据数量。lookup_transform_timeout_sec: 查找变换的超时时间。submap_publish_period_sec: 发布子地图的周期。pose_publish_period_sec: 发布姿态的周期。trajectory_publish_period_sec: 发布轨迹的周期。rangefinder_sampling_ratio: 激光采样比率。odometry_sampling_ratio: 里程计采样比率。fixed_frame_pose_sampling_ratio: 固定帧姿态采样比率。imu_sampling_ratio: IMU采样比率。landmarks_sampling_ratio: 地标采样比率。 以下是其他配置参数的说明 MAP_BUILDER.use_trajectory_builder_2d true MAP_BUILDER.num_background_threads 2TRAJECTORY_BUILDER_2D.num_accumulated_range_data 1 --积累几帧激光数据作为一个标准单位scan TRAJECTORY_BUILDER_2D.min_range 0.1 --激光的最近有效距离 TRAJECTORY_BUILDER_2D.max_range 12. --激光最远的有效距离 TRAJECTORY_BUILDER_2D.missing_data_ray_length 5. --无效激光数据设置距离为该数值 TRAJECTORY_BUILDER_2D.use_imu_data false --是否使用imu数据TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching true TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.linear_search_window 0.1 --线距离搜索框在这个框的大小内搜索最佳scan匹配 减小该参数可以增强实时的建图效果降低闭环优化的效果形成闭环时产生的重影较多 TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher. angular_search_window math.rad(10.) --角度搜索框的大小 TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.translation_delta_cost_weight 20. TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.rotation_delta_cost_weight 2e-1 --影响的是过程中的效果间接会影响最后的优化时间长TRAJECTORY_BUILDER_2D.ceres_scan_matcher.translation_weight 30. TRAJECTORY_BUILDER_2D.ceres_scan_matcher.rotation_weight 30. TRAJECTORY_BUILDER_2D.ceres_scan_matcher.ceres_solver_options.max_num_iterations 20TRAJECTORY_BUILDER_2D.submaps.num_range_data 40 --num_range_data设置的值与CPU有这样一种关系值小(10)CPU使用率比较稳定整体偏高值大时CPU短暂爆发使用(插入子图的时候)平时使用率低呈现极大的波动状态。 TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.hit_probability 0.55 TRAJECTORY_BUILDER_2D.submaps.range_data_inserter.probability_grid_range_data_inserter.miss_probability 0.49TRAJECTORY_BUILDER_2D.motion_filter.max_distance_meters 0.05 --//尽量小点 // 如果移动距离过小, 或者时间过短, 不进行地图的更新 TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians math.rad(0.3) TRAJECTORY_BUILDER_2D.motion_filter.max_time_seconds 0.5POSE_GRAPH.optimization_problem.huber_scale 1e2 --鲁棒核函数去噪POSE_GRAPH.optimize_every_n_nodes 35 --后端优化节点 POSE_GRAPH.global_constraint_search_after_n_seconds 10 POSE_GRAPH.optimization_problem.ceres_solver_options.max_num_iterations 15 --优化迭代步数 POSE_GRAPH.optimization_problem.ceres_solver_options.num_threads 1POSE_GRAPH.constraint_builder.max_constraint_distance 15. POSE_GRAPH.constraint_builder.sampling_ratio 0.3 POSE_GRAPH.constraint_builder.min_score 0.50 POSE_GRAPH.constraint_builder.global_localization_min_score 0.6 POSE_GRAPH.constraint_builder.fast_correlative_scan_matcher.linear_search_window 3. POSE_GRAPH.constraint_builder.fast_correlative_scan_matcher.branch_and_bound_depth 5. --搜索方法界定分支法求解问题构成一个搜索树depth是构造树的深度 POSE_GRAPH.global_sampling_ratio 0.001MAP_BUILDER.use_trajectory_builder_2d: 是否使用2D轨迹构建器。MAP_BUILDER.num_background_threads: 地图构建器使用的后台线程数。TRAJECTORY_BUILDER_2D 相关参数 num_accumulated_range_data: 累积多少帧激光数据作为一个扫描单位。min_range 和 max_range: 激光数据的有效距离范围。missing_data_ray_length: 无效激光数据的设置距离。use_imu_data: 是否使用IMU数据。use_online_correlative_scan_matching: 是否使用在线相关扫描匹配。real_time_correlative_scan_matcher 相关参数: 实时相关扫描匹配器的配置。ceres_scan_matcher 相关参数: Ceres扫描匹配器的配置。submaps 相关参数: 子地图的配置。motion_filter 相关参数: 运动过滤器的配置。 TRAJECTORY_BUILDER_2D.real_time_correlative_scan_matcher.angular_search_window 参数定义了在实时相关扫描匹配器中进行角度搜索的范围。这个参数的值是以弧度为单位的角度用于确定在匹配当前激光扫描数据与之前扫描数据时可以接受的最大角度差异。,后续当地图出现飘逸的时候需要i修改这个参数. POSE_GRAPH 相关参数 optimization_problem 相关参数: 优化问题的配置。optimize_every_n_nodes: 每隔多少个节点进行一次优化。global_constraint_search_after_n_seconds: 多少秒后进行全局约束搜索。constraint_builder 相关参数: 约束构建器的配置 2-3 启动文件 这里直接参考小鱼的节点cartographer_node:这是Cartographer的核心节点负责处理传感器数据如激光扫描和IMU数据执行SLAMSimultaneous Localization and Mapping同时定位与建图算法并构建环境的地图。它还负责轨迹的优化和闭环检测。cartographer_occupancy_grid_node:这个节点将Cartographer生成的概率网格转换为ROS中的nav_msgs/OccupancyGrid消息格式这样就可以被其他导航和路径规划节点使用。这个网格通常用于机器人的路径规划和避障。 import os from launch import LaunchDescription from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node from launch_ros.substitutions import FindPackageSharedef generate_launch_description():# 定位到功能包的地址pkg_share FindPackageShare(packageqingzhou_sim).find(qingzhou_cartographer)#运行节点需要的配置# 是否使用仿真时间我们用gazebo这里设置成trueuse_sim_time LaunchConfiguration(use_sim_time, defaulttrue)# 地图的分辨率resolution LaunchConfiguration(resolution, default0.05)# 地图的发布周期publish_period_sec LaunchConfiguration(publish_period_sec, default1.0)# 配置文件夹路径configuration_directory LaunchConfiguration(configuration_directory,default os.path.join(pkg_share, config) )# 配置文件configuration_basename LaunchConfiguration(configuration_basename, defaultqingzhou_2d.lua)#声明三个节点cartographer/occupancy_grid_node/rviz_nodecartographer_node Node(packagecartographer_ros,executablecartographer_node,namecartographer_node,outputscreen,parameters[{use_sim_time: use_sim_time}],arguments[-configuration_directory, configuration_directory,-configuration_basename, configuration_basename])occupancy_grid_node Node(packagecartographer_ros,executablecartographer_occupancy_grid_node,namecartographer_occupancy_grid_node,outputscreen,parameters[{use_sim_time: use_sim_time}],arguments[-resolution, resolution, -publish_period_sec, publish_period_sec])rviz_node Node(packagerviz2,executablerviz2,namerviz2,# arguments[-d, rviz_config_dir],parameters[{use_sim_time: use_sim_time}],outputscreen)#定义启动文件ld LaunchDescription()ld.add_action(cartographer_node)ld.add_action(occupancy_grid_node)ld.add_action(rviz_node)return ld 3 Cartographer仿真和实车演示 那么现在要做的很简单,启动以下节点: gazebo仿真节点,上一期提到的键盘控制节点cartographer建图节点 3-1 仿真实操与问题解决 那很显然,我们遇到了第一个问题 如上图所示,仿真小车在前半段的地图运行一定距离时候,出现了odom和map坐标系严重偏离的情况,这是因为雷达扫描不到边缘周围的环境没有出现特征点,SLAM出现了估计错误. 很简单这里是仿真把雷达扫描的范围扩大 由于扩大的雷达的扫描距离,就不会出现估计的偏差,如下我们完成了一圈的建图,这时候就可以开始进行地图保存 3-2 map_server map_server 是一个用于在ROSRobot Operating System中提供地图数据的节点。它主要用于读取、保存和发布地图数据这些地图数据通常是由SLAMSimultaneous Localization and Mapping算法生成的或者是由其他方式创建的静态地图。我们写一个bash脚本用于地图保存 #!/bin/bash# 获取当前的日期和时间格式为 YYYY-MM-DD_HH-MM-SS current_datetime$(date %Y-%m-%d_%H-%M-%S)# 构建地图文件名 map_filenamemap_$current_datetime# 切换到相应的目录并运行map_saver_cli命令 cd src/qingzhou_cartographer/maps ros2 run nav2_map_server map_saver_cli -t map -f $map_filename运行上述命令后map_server将把我们的地图保存为如下形式: **map.yaml文件描述了地图的属性和相关的PGM文件 image: map_2024-10-23_23-10-11.pgm mode: trinary resolution: 0.05 origin: [-1.97, -3.77, 0] negate: 0 occupied_thresh: 0.65 free_thresh: 0.25image: 地图的PGM文件名这个文件包含了地图的像素数据。 mode: 地图的模式trinary表示地图使用三种值0空闲100占用和-1未知。 resolution: 地图中每个单元格代表的实际距离这里是0.05米。 origin: 地图原点在真实世界坐标系中的位置这里是[-1.97, -3.77, 0]表示地图左下角的位置。 negate: 一个标志用来指示是否反转地图的占用值0表示不反转。 occupied_thresh: 占用阈值用于确定一个单元格是否被占用这里是0.65意味着如果PGM文件中单元格的值大于或等于65则该单元格被认为是占用的。 free_thresh: 空闲阈值用于确定一个单元格是否空闲这里是0.25意味着如果PGM文件中单元格的值小于或等于25则该单元格被认为是空闲的。 同时我们有的得到一张保存的pgm图片 这时候我们仿真就完成了cartographer的配置. 3-2 实车建图问题与解决 这里我拿另一个项目实车所遇到的问题和解决方案一同和大家分享 3-2-1 实车建图飘逸问题 如下图实车的雷达更新频率只有10hz,单纯使用雷达进行匹配容易造成地图出现飘逸 而往往实车中是有轮式里程计的存在的,这时候我们只需要打开lua配置中的使用里程计 这时候驱动小车移动一圈回到原点后发现地图没有出现大幅度漂移但是仍有模糊现象,这时候我们需要 把最小角度改小!!! 这样地图基本上没问题了. 3-2-2 实车建图里程计报错问题 Carto建图报错找不到Odom 可能原因一Odom话题非发布一查话题确实掉了 可能原因二tf树断开 本地下载tf树 sudo apt-get install ros-humble-rqt-tf-tree运行 ros2 run rqt_tf_tree rqt_tf_tree --force-discover发现tf树确实断开,缺少 #mermaid-svg-nyW4JAAHHeLdpMPB {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-nyW4JAAHHeLdpMPB .error-icon{fill:#552222;}#mermaid-svg-nyW4JAAHHeLdpMPB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nyW4JAAHHeLdpMPB .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-nyW4JAAHHeLdpMPB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nyW4JAAHHeLdpMPB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nyW4JAAHHeLdpMPB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nyW4JAAHHeLdpMPB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nyW4JAAHHeLdpMPB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nyW4JAAHHeLdpMPB .marker.cross{stroke:#333333;}#mermaid-svg-nyW4JAAHHeLdpMPB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nyW4JAAHHeLdpMPB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nyW4JAAHHeLdpMPB .cluster-label text{fill:#333;}#mermaid-svg-nyW4JAAHHeLdpMPB .cluster-label span{color:#333;}#mermaid-svg-nyW4JAAHHeLdpMPB .label text,#mermaid-svg-nyW4JAAHHeLdpMPB span{fill:#333;color:#333;}#mermaid-svg-nyW4JAAHHeLdpMPB .node rect,#mermaid-svg-nyW4JAAHHeLdpMPB .node circle,#mermaid-svg-nyW4JAAHHeLdpMPB .node ellipse,#mermaid-svg-nyW4JAAHHeLdpMPB .node polygon,#mermaid-svg-nyW4JAAHHeLdpMPB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nyW4JAAHHeLdpMPB .node .label{text-align:center;}#mermaid-svg-nyW4JAAHHeLdpMPB .node.clickable{cursor:pointer;}#mermaid-svg-nyW4JAAHHeLdpMPB .arrowheadPath{fill:#333333;}#mermaid-svg-nyW4JAAHHeLdpMPB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nyW4JAAHHeLdpMPB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nyW4JAAHHeLdpMPB .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-nyW4JAAHHeLdpMPB .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-nyW4JAAHHeLdpMPB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nyW4JAAHHeLdpMPB .cluster text{fill:#333;}#mermaid-svg-nyW4JAAHHeLdpMPB .cluster span{color:#333;}#mermaid-svg-nyW4JAAHHeLdpMPB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nyW4JAAHHeLdpMPB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} base_footprint odom 完整的tf树应该这样,这里有两种方法发布base_footprint–odom 如果provide_odom_frame这个参数打开会自动帮你进行odom到base_footprint的转换 把他关掉的话就需要自己额外进行静态坐标变换 推荐关掉自己发布 ros2 run tf2_ros static_transform_publisher 0.0 0.0 0.0 0.0 0.0 0.0 odom base_footprint4 小节 本节我们介绍了cartographer的原理,并分别从仿真和实车进行配置和问题分析.如有错误,欢迎指出!!!下一期我们讲讲如何在仿真中配置libgazebo_ros_camera深度相机插件,并使用ORB-SLAM进行建图感谢大家的支持!!!
http://www.hkea.cn/news/14442144/

相关文章:

  • 网络推广网站排名成都科技网站建设联系
  • 佛山优化网站关键词网站seo置顶
  • 农村建设房子建设网站建设临沂画册设计公司
  • 制作视频网站开发wordpress输入密码查看内容
  • 网站如何做反爬wordpress登录cdn
  • 做网站 前端导航网站 win8风格
  • 中科 网站会员注册系统建设小说网站开发多少钱
  • 新乡搜狗网站推广工具制作网站需要哪些工具
  • 百度做的网站迁移什么是网络营销?网络营销的特点有哪些?
  • 做尽调需要用到的网站中美网站建设
  • 重庆网站制作公司多少钱网站如何优化排名软件
  • 门户网站开发要求尉氏做网站
  • 江门站官网淘宝网站建设图片素材
  • 9377手游交易平台成都网站优化常识
  • 网站开发 岗位职责搭网站要多少钱
  • 网站建设工作小组分工手机网站全屏
  • 淮安做网站app惊艳的网站
  • 天津站设计单位超好看WordPress
  • 帮人网站开发维护违法wordpress 翻译工具
  • 17网站一起做网店新塘个人网站制作的主要内容
  • 做网站江西网站首页title怎么修改
  • 免费wap自助建站系统宁波市江北区建设局网站
  • 化妆品网站建设说明徐州网站建设开发
  • 网站建设制度西安区seo搜索排名优化
  • 外贸人自己搭建外贸网站wordpress网站流量统计分析的维度包括
  • 网站seo优化技术入门淮安市做网站
  • 消防电气火灾监控系统网站开发网站建设导航栏变化
  • 我被钓鱼网站骗了骗取建设信用卡建设银行会怎么处理钱会还回吗如何建立免费微网站
  • 自己做好网站网站优化企业排名
  • dede静态网站wordpress图片链接大图