本文主要介绍map_builder类的大致实现逻辑
AddTrajectoy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 int MapBuilderBridge::AddTrajectory ( const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>& expected_sensor_ids, const TrajectoryOptions& trajectory_options) { const int trajectory_id = map_builder_->AddTrajectoryBuilder ( expected_sensor_ids, trajectory_options.trajectory_builder_options, [this ](const int trajectory_id, const ::cartographer::common::Time time, const Rigid3d local_pose, ::cartographer::sensor::RangeData range_data_in_local, const std::unique_ptr< const ::cartographer::mapping::TrajectoryBuilderInterface:: InsertionResult>) { OnLocalSlamResult (trajectory_id, time, local_pose, range_data_in_local); }); LOG (INFO) << "Added trajectory with ID '" << trajectory_id << "'." ; CHECK_EQ (sensor_bridges_.count (trajectory_id), 0 ); sensor_bridges_[trajectory_id] = absl::make_unique<SensorBridge>( trajectory_options.num_subdivisions_per_laser_scan, trajectory_options.tracking_frame, node_options_.lookup_transform_timeout_sec, tf_buffer_, map_builder_->GetTrajectoryBuilder (trajectory_id)); auto emplace_result = trajectory_options_.emplace (trajectory_id, trajectory_options); CHECK (emplace_result.second == true ); return trajectory_id; }
第一步:开始一条新的轨迹, 返回新轨迹的id 通过调用map_builder来添加一条轨迹,调用函数AddTrajectoryBuilder,第三个参数为一个lambda表达式
[this]: 以值的形式捕获this指针,传入了五个参数,在lambda表达式的函数体中调用了另外一个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const int trajectory_id = map_builder_->AddTrajectoryBuilder ( expected_sensor_ids, trajectory_options.trajectory_builder_options, [this ](const int trajectory_id, const ::cartographer::common::Time time, const Rigid3d local_pose, ::cartographer::sensor::RangeData range_data_in_local, const std::unique_ptr< const ::cartographer::mapping::TrajectoryBuilderInterface:: InsertionResult>) { OnLocalSlamResult (trajectory_id, time, local_pose, range_data_in_local); }); LOG (INFO) << "Added trajectory with ID '" << trajectory_id << "'." ;
第二步,为轨迹添加一个sensorBridge 每一个轨迹都会有一个sensorBridge, 保存在变量sensorbridges 之中
1 std::unordered_map<int, std::unique_ptr<SensorBridge>> sensor_bridges_;
因此,在新增了轨迹之后,需要把SensorBridge的信息也要添加进变量之中。
1 2 3 4 5 6 7 // Step: 2 为这个新轨迹 添加一个SensorBridge sensor_bridges_[trajectory_id] = absl::make_unique<SensorBridge>( trajectory_options.num_subdivisions_per_laser_scan, trajectory_options.tracking_frame, node_options_.lookup_transform_timeout_sec, tf_buffer_, map_builder_->GetTrajectoryBuilder(trajectory_id)); // CollatedTrajectoryBuilder
第三步, 保存轨迹的参数配置 保存轨迹 的参数配置到trajectoryoptions 中,返回的值的第二个参数可以判断是否插入元素成功
1 2 3 4 5 // Step: 3 保存轨迹的参数配置 auto emplace_result = trajectory_options_.emplace(trajectory_id, trajectory_options); CHECK(emplace_result.second == true); return trajectory_id;
结束指定id的轨迹 首先判断此ID的轨迹是否活跃,调用mapbuilder的FinishTrajectory方法结束指定轨迹。最后也需要在sensor_bridges 里删除对应的ID
1 2 3 4 5 6 7 8 void MapBuilderBridge::FinishTrajectory (const int trajectory_id) { LOG (INFO) << "Finishing trajectory with ID '" << trajectory_id << "'..." ; CHECK (GetTrajectoryStates ().count (trajectory_id)); map_builder_->FinishTrajectory (trajectory_id); sensor_bridges_.erase (trajectory_id); }
处理地图信息 处理地图信息的函数一个service,它的数据格式为
1 2 3 4 5 6 int32 trajectory_id int32 submap_index --- cartographer_ros_msgs/StatusResponse status int32 submap_version cartographer_ros_msgs/SubmapTexture[] textures
request的内容为轨迹的ID,和submap的index
response的有栅格的具体的信息 textures,数据格式为
1 2 3 4 5 uint8[] cells 此值表示栅格的值 int32 width int32 height float64 resolution geometry_msgs/Pose slice_pose 具体的位姿
下面是具体的函数,具体的submap信息其实都存储在mapbuilder 之中,通过SubmapToProto来获得
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 void MapBuilderBridge::HandleSubmapQuery ( cartographer_ros_msgs::SubmapQuery::Request& request, cartographer_ros_msgs::SubmapQuery::Response& response) { cartographer::mapping::proto::SubmapQuery::Response response_proto; cartographer::mapping::SubmapId submap_id{request.trajectory_id, request.submap_index}; const std::string error = map_builder_->SubmapToProto (submap_id, &response_proto); if (!error.empty ()) { LOG (ERROR) << error; response.status.code = cartographer_ros_msgs::StatusCode::NOT_FOUND; response.status.message = error; return ; } response.submap_version = response_proto.submap_version (); for (const auto & texture_proto : response_proto.textures ()) { response.textures.emplace_back (); auto & texture = response.textures.back (); texture.cells.insert (texture.cells.begin (), texture_proto.cells ().begin (), texture_proto.cells ().end ()); texture.width = texture_proto.width (); texture.height = texture_proto.height (); texture.resolution = texture_proto.resolution (); texture.slice_pose = ToGeometryMsgPose ( cartographer::transform::ToRigid3 (texture_proto.slice_pose ())); } response.status.message = "Success." ; response.status.code = cartographer_ros_msgs::StatusCode::OK; }
获取轨迹的状态 轨迹的状态也是通过mapbuilder 中的pose_graph获取,但是有的轨迹还没有到pose_graph中,需要到sensor bridge中查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 std::map<int , ::cartographer::mapping::PoseGraphInterface::TrajectoryState> MapBuilderBridge::GetTrajectoryStates () { auto trajectory_states = map_builder_->pose_graph ()->GetTrajectoryStates (); for (const auto & sensor_bridge : sensor_bridges_) { trajectory_states.insert (std::make_pair ( sensor_bridge.first, ::cartographer::mapping::PoseGraphInterface::TrajectoryState::ACTIVE)); } return trajectory_states; }
获取所有submap的信息 包括 trajectory_id,submap_index,submap_version,pose。submaplist的消息也是在map_builder中。从pose_graph中提取,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cartographer_ros_msgs::SubmapList MapBuilderBridge::GetSubmapList () { cartographer_ros_msgs::SubmapList submap_list; submap_list.header.stamp = ::ros::Time::now (); submap_list.header.frame_id = node_options_.map_frame; for (const auto & submap_id_pose : map_builder_->pose_graph ()->GetAllSubmapPoses ()) { cartographer_ros_msgs::SubmapEntry submap_entry; submap_entry.is_frozen = map_builder_->pose_graph ()->IsTrajectoryFrozen ( submap_id_pose.id.trajectory_id); submap_entry.trajectory_id = submap_id_pose.id.trajectory_id; submap_entry.submap_index = submap_id_pose.id.submap_index; submap_entry.submap_version = submap_id_pose.data.version; submap_entry.pose = ToGeometryMsgPose (submap_id_pose.data.pose); submap_list.submap.push_back (submap_entry); } return submap_list; }
获得前端的轨迹数据 获取local坐标系下的TrajectoryData
从sensorbridge 中循环找每一条轨迹的消息,把消息全部放入local_trajectory_data,local_trajectory_data中的数据结构为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct LocalTrajectoryData { struct LocalSlamData { ::cartographer::common::Time time; ::cartographer::transform::Rigid3d local_pose; ::cartographer::sensor::RangeData range_data_in_local; }; std::shared_ptr<const LocalSlamData> local_slam_data; cartographer::transform::Rigid3d local_to_map; std::unique_ptr<cartographer::transform::Rigid3d> published_to_tracking; TrajectoryOptions trajectory_options; };
从localslam_data 中获取local_slam_data
从mapbuilder 的pose_graph中获取local frame 到 global frame间的坐标变换
从sensor_bridge中获得从published_frame 到 tracking_frame 间的坐标变换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 std::unordered_map<int , MapBuilderBridge::LocalTrajectoryData> MapBuilderBridge::GetLocalTrajectoryData () { std::unordered_map<int , LocalTrajectoryData> local_trajectory_data; for (const auto & entry : sensor_bridges_) { const int trajectory_id = entry.first; const SensorBridge& sensor_bridge = *entry.second; std::shared_ptr<const LocalTrajectoryData::LocalSlamData> local_slam_data; { absl::MutexLock lock (&mutex_) ; if (local_slam_data_.count (trajectory_id) == 0 ) { continue ; } local_slam_data = local_slam_data_.at (trajectory_id); } CHECK_EQ (trajectory_options_.count (trajectory_id), 1 ); local_trajectory_data[trajectory_id] = { local_slam_data, map_builder_->pose_graph ()->GetLocalToGlobalTransform (trajectory_id), sensor_bridge.tf_bridge ().LookupToTracking ( local_slam_data->time, trajectory_options_[trajectory_id].published_frame), trajectory_options_[trajectory_id]}; } return local_trajectory_data; }