cartographer中创建轨迹

开始一条轨迹

主要函数,AddTrajectoryBuilder

目的就是创建一个新的TrajectoryBuilder 并返回它的 trajectory_id,cartographer会创建不止一条轨迹,每一条轨迹都会有一个id。

需要的输入参数:

expected_sensor_ids 所有需要的topic的名字的集合

trajectory_options 轨迹的参数配置

local_slam_result_callback 需要传入的回调函数,实际上是map_builder_bridge.cc 中的OnLocalSlamResult() 函数

输出:

return int 新生成的轨迹的id

AddTrajectoryBuilder函数的调用过程

​ 还是从node.cc文件开始

  1. node_main.cc的StartTrajectoryWithDefaultTopics函数

    node.StartTrajectoryWithDefaultTopics(trajectory_options);
    
  2. Node类的StartTrajectoryWithDefaultTopics函数

    void Node::StartTrajectoryWithDefaultTopics(const TrajectoryOptions& options) {
      absl::MutexLock lock(&mutex_);
      // 检查TrajectoryOptions是否存在2d或者3d轨迹的配置信息
      CHECK(ValidateTrajectoryOptions(options));
      // 添加一条轨迹
      AddTrajectory(options);
    }
    
  3. 上面函数中有一个AddTrajectory(options)函数

    const int trajectory_id =
          map_builder_bridge_.AddTrajectory(expected_sensor_ids, options);
    

    其中又包括map_builder_bridge_.AddTrajectory

    map_builder_bridge_是由MapBuilderBridge这个类创建,这个类里面有一个AddTrajectory成员函数

  4. MapBuilderBridge::AddTrajectory

    int MapBuilderBridge::AddTrajectory() {
      // Step: 1 开始一条新的轨迹, 返回新轨迹的id,需要传入一个函数
      const int trajectory_id = map_builder_->AddTrajectoryBuilder(
          expected_sensor_ids, trajectory_options.trajectory_builder_options,
          // lambda表达式 local_slam_result_callback_
          [this]() {
            // 保存local slam 的结果数据 5个参数实际只用了4个
            OnLocalSlamResult(trajectory_id, time, local_pose, range_data_in_local);
          });
      LOG(INFO) << "Added trajectory with ID '" << trajectory_id << "'.";
    
      // Make sure there is no trajectory with 'trajectory_id' yet.
      CHECK_EQ(sensor_bridges_.count(trajectory_id), 0);
      // Step: 2 为这个新轨迹 添加一个SensorBridge,为sensorbridge初始化
      sensor_bridges_[trajectory_id] = absl::make_unique<SensorBridge>(); // CollatedTrajectoryBuilder
    

    至此,AddTrajectoryBuilderMapBuilderBridge::AddTrajectory()函数中被调用

进入AddTrajectoryBuilder函数

​ 参考带注释的源码

const int trajectory_id = trajectory_builders_.size();

id是从零开始的, 所以新trajectory_id就是trajectory_builders_的size()。

absl::optional<MotionFilter> pose_graph_odometry_motion_filter;

在配置文件中没有pose_graph_odometry_motion_filter这个参数,也没有使用后端的里程计motion_filter

构建2d轨迹

else {
    std::unique_ptr<LocalTrajectoryBuilder2D> local_trajectory_builder;
    if (trajectory_options.has_trajectory_builder_2d_options()) {
      // local_trajectory_builder(前端)的初始化
      local_trajectory_builder = absl::make_unique<LocalTrajectoryBuilder2D>(
          trajectory_options.trajectory_builder_2d_options(),
          SelectRangeSensorIds(expected_sensor_ids));
    }

    DCHECK(dynamic_cast<PoseGraph2D*>(pose_graph_.get()));

    // CollatedTrajectoryBuilder初始化
    trajectory_builders_.push_back(absl::make_unique<CollatedTrajectoryBuilder>(
        trajectory_options, sensor_collator_.get(), trajectory_id,
        expected_sensor_ids,
        // 将2D前端与2D位姿图打包在一起, 传入CollatedTrajectoryBuilder
        CreateGlobalTrajectoryBuilder2D(
            std::move(local_trajectory_builder), trajectory_id,
            static_cast<PoseGraph2D*>(pose_graph_.get()),
            local_slam_result_callback, pose_graph_odometry_motion_filter)));
  }

在这里,首先建立了一个LocalTrajectoryBuilder2D类的对象local_trajectory_builder(这个类是不带回环的前端slam,但他包括了位姿估计和扫描匹配)然后传入雷达topic和轨迹配置参数对其初始化。

接着通过dynamic_cast将pose_graph_对象强制转换为PoseGraph2D,并检查数据类型是否正确。

接着构建轨迹跟踪器CollatedTrajectoryBuilder2D,传入轨迹id,位姿图等参数,然后将2D前端与2D位姿图打包在一起, 传入CollatedTrajectoryBuilder,也就是trajectory_builders_.push_back了。

纯定位模式

如果是纯定位模式,调用这个函数,然后仅保存最近的三个submap

 MaybeAddPureLocalizationTrimmer(trajectory_id, trajectory_options,
                                  pose_graph_.get());
void MaybeAddPureLocalizationTrimmer(
    const int trajectory_id,
    const proto::TrajectoryBuilderOptions& trajectory_options,
    PoseGraph* pose_graph) {
  if (trajectory_options.has_pure_localization_trimmer()) {
    pose_graph->AddTrimmer(absl::make_unique<PureLocalizationTrimmer>(
        trajectory_id,
        trajectory_options.pure_localization_trimmer().max_submaps_to_keep()));
  }
}

在纯定位模式中,在pose_graph_中添加一个PureLocalizationTrimmer类型修饰器,来完成这一功能。

根据has_pure_localization_trimmer参数配置,决定保存多少submap,参数在trajectory_builder。lua文件中,默认注释掉,即默认会生成三个submap。

(之前有一个老参数,已经弃用,会报警告,但不影响使用)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Cartographer 是一个开源的地图制图工具,主要用于构建和绘制室内和室外环境的三维地图。它是以Lua语言作为脚本编写和扩展的。 首先,Lua是一种轻量级高级编程语言,被广泛应用于嵌入式系统、游戏开发、脚本编写等领域。Cartographer选择使用Lua作为其脚本编写语言,是因为Lua拥有简洁的语法和高度可扩展性,使得用户可以轻松地编写和修改Cartographer的功能。 使用Lua作为Cartographer的脚本语言,使得开发人员可以根据特定需求自定义各种功能和算法。他们可以通过编写Lua脚本来改变地图的生成方式、路径规划算法、环境感知等内容。这种灵活性使得Cartographer能够适应各种特定的应用场景和需求。 同时,Lua也是一个功能强大的脚本语言,拥有很多有用的函数库和模块,例如字符串处理、JSON解析、网络通信等。这些功能可以被利用来扩展Cartographer的能力,使得它具备更多的功能。例如,用户可以使用内置的JSON库来处理来自传感器的数据,然后将其集成到Cartographer的地图生成过程。 总之,Cartographer使用Lua作为脚本编写语言,给开发人员提供了一种灵活且可扩展的方式来定制和扩展地图生成和绘制的功能。通过编写Lua脚本,用户可以根据自己的需求来改变Cartographer的行为和输出,使其更好地适应各种应用场景。 ### 回答2: 在游戏开发cartographer(制图师)是一个很重要的角色,而Lua则是常用于游戏制作的脚本语言。Lua提供了简单、高效和可嵌入的特性,使得在游戏实现制图功能变得更加容易。 制图师的工作是创建和设计游戏的地图。他们使用图形工具来绘制地图的外貌,并使用Lua脚本来定义地图的行为、布局和特性。 使用Lua的主要好处之一是它的灵活性。制图师可以根据需要编写自定义脚本来控制地图元素的交互逻辑。例如,他们可以编写脚本来定义角色在地图上的移动、碰撞检测和触发事件等。这样可以为游戏增加更多的互动性和挑战性。 此外,Lua还提供了强大的扩展性。制图师可以利用Lua的扩展功能来添加自定义的地图特性,如随机生成地形、动态添加/移除地图元素等。这样可以使游戏的地图更加多样化和有趣。 另一个使用Lua的好处是它的易学性。相对于其他编程语言,Lua语法简洁明了,并且具有良好的文档和丰富的教程资源。制图师即使没有深厚的编程知识,也可以迅速上手并编写简单的脚本来完成地图设计。 总的来说,cartographer的Lua在游戏开发扮演着非常重要的角色。它为制图师提供了强大和灵活的工具,使他们能够轻松创建和定制游戏的地图。无论是添加互动性、扩展地图特性,还是实现复杂的游戏逻辑,Lua都是一个理想的选择。 ### 回答3: cartographer是一个用于构建并绘制地图的开源库,而lua是一种脚本语言,常用于嵌入式系统和游戏开发。在cartographer,可以使用lua来编写自定义的功能和逻辑。 使用lua可以为cartographer添加一些自定义的功能。比如,可以利用lua脚本来编写一些特定的算法,从而优化地图的构建和绘制过程。也可以通过lua脚本来实现特定的地图渲染效果,如灯光效果、阴影等。 此外,使用lua还可以在运行时动态加载和修改地图配置。通过编写lua脚本,可以实现在地图运行时根据特定条件对地图进行修改,例如动态生成障碍物、修改地图尺寸、添加额外的特征等。这使得cartographer在适应不同应用领域和需求时更加灵活。 同时,cartographer还提供了一些接口和函数来与lua进行交互。这些接口和函数可以让lua脚本获取和修改地图、传递数据给其他系统、控制执行流程等。通过这些交互方式,我们可以实现cartographer与其他部分的集成,或者将cartographer作为其他系统的一部分,以满足更具体的需求。 综上所述,cartographer的lua提供了一种扩展和定制地图构建和绘制功能的方法,能够使cartographer更加灵活和适应不同的应用场景和需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值