该函数中:
1、定义了rviz的显示函数;
2、关于里程计信息的索引(可选);
3、对于轨迹的处理。包括轨迹队列处理、局部轨迹数据、获得轨迹节点列表等。
4、最后还有一部分约束相关的。估计是用于闭环。
同时可以看到里面由于涉及到轨迹,所以使用到了传感器。也就调用了很多次的sensor_bridge。总体来说,MapBuilderBridge这个类里我们依然看不到任何关于算法的影子,它也只是一层封装。
map_builder_bridge.h的注释:
#ifndef CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MAP_BUILDER_BRIDGE_H
#define CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MAP_BUILDER_BRIDGE_H
#include
#include
#include
#include
#include "absl/synchronization/mutex.h"
#include "cartographer/mapping/map_builder_interface.h"
#include "cartographer/mapping/pose_graph_interface.h"
#include "cartographer/mapping/proto/trajectory_builder_options.pb.h"
#include "cartographer/mapping/trajectory_builder_interface.h"
#include "cartographer_ros/node_options.h"
#include "cartographer_ros/sensor_bridge.h"
#include "cartographer_ros/tf_bridge.h"
#include "cartographer_ros/trajectory_options.h"
#include "cartographer_ros_msgs/SubmapEntry.h"
#include "cartographer_ros_msgs/SubmapList.h"
#include "cartographer_ros_msgs/SubmapQuery.h"
#include "cartographer_ros_msgs/TrajectoryQuery.h"
#include "geometry_msgs/TransformStamped.h"
#include "nav_msgs/OccupancyGrid.h"
// Abseil unfortunately pulls in winnt.h, which #defines DELETE.
// Clean up to unbreak visualization_msgs::Marker::DELETE.
#ifdef DELETE
#undef DELETE
#endif
#include "visualization_msgs/MarkerArray.h"
namespace cartographer_ros {
class MapBuilderBridge {
public:
struct LocalTrajectoryData {//一个结构体TrajectoryState;//该结构体存储的是local SLAM处理后的结果。由range_data_in_local中已经估计出了在时刻time时的当前local_pose
// Contains the trajectory data received from local SLAM, after
// it had processed accumulated 'range_data_in_local' and estimated
// current 'local_pose' at 'time'.
struct LocalSlamData {//结构体
::cartographer::common::Time time;//时间
::cartographer::transform::Rigid3d local_pose;//优化匹配出来的local_pose——在submap这个局部坐标系中的位姿
::cartographer::sensor::RangeData range_data_in_local;//激光数据
};
std::shared_ptr<const LocalSlamData> local_slam_data;//局部SLAM的数据
cartographer::transform::Rigid3d local_to_map;//submap到global map的坐标变换关系
std::unique_ptr<cartographer::transform::Rigid3d> published_to_tracking;//猜测是要输入PoseExtrapolator
TrajectoryOptions trajectory_options;//配置参数
};
MapBuilderBridge(
const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* tf_buffer);
MapBuilderBridge(const MapBuilderBridge&) = delete;
MapBuilderBridge& operator=(const MapBuilderBridge&) = delete;//重载了赋值操作
void LoadState(const std::string& state_filename, bool load_frozen_state);
int AddTrajectory(
const std::set<
::cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& trajectory_options);
void FinishTrajectory(int trajectory_id);
void RunFinalOptimization();
bool SerializeState(const std::string& filename,
const bool include_unfinished_submaps);
void HandleSubmapQuery(
cartographer_ros_msgs::SubmapQuery::Request& request,
cartographer_ros_msgs::SubmapQuery::Response& response);
void HandleTrajectoryQuery(
cartographer_ros_msgs::TrajectoryQuery::Request& request,
cartographer_ros_msgs::TrajectoryQuery::Response& response);
std::map<int /* trajectory_id */,
::cartographer::mapping::PoseGraphInterface::TrajectoryState>
GetTrajectoryStates();
cartographer_ros_msgs::SubmapList GetSubmapList();
std::unordered_map<int, LocalTrajectoryData> GetLocalTrajectoryData()
LOCKS_EXCLUDED(mutex_);
visualization_msgs::MarkerArray GetTrajectoryNodeList();
visualization_msgs::MarkerArray GetLandmarkPosesList();
visualization_msgs::MarkerArray GetConstraintList();
SensorBridge* sensor_bridge(int trajectory_id);
private://成员变量:
void OnLocalSlamResult(const int trajectory_id,
const ::cartographer::common::Time time,
const ::cartographer::transform::Rigid3d local_pose,
::cartographer::sensor::RangeData range_data_in_local)
LOCKS_EXCLUDED(mutex_);
//几个Unordered map的container
absl::Mutex mutex_;
const NodeOptions node_options_;
std::unordered_map<int,
std::shared_ptr<const LocalTrajectoryData::LocalSlamData>>
local_slam_data_ GUARDED_BY(mutex_);
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder_;
tf2_ros::Buffer* const tf_buffer_;
std::unordered_map<std::string /* landmark ID */, int> landmark_to_index_;
//跟landmark相关,其中std::string变量表征landmark的ID
// These are keyed with 'trajectory_id'.
std::unordered_map<int, TrajectoryOptions> trajectory_options_;
std::unordered_map<int, std::unique_ptr<SensorBridge>> sensor_bridges_;
//元素 为SensorBridge成员的一个unordered map; Unordered map is an associative container that contains key-value pairs with unique keys.
//Search, insertion, and removal of elements have average constant-time complexity.
std::unordered_map<int, size_t> trajectory_to_highest_marker_id_;
};
} // namespace cartographer_ros
#endif // CARTOGRAPHER_ROS_CARTOGRAPHER_ROS_MAP_BUILDER_BRIDGE_H
map_builder_bridge.cc的注释:
#include "cartographer_ros/map_builder_bridge.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "cartographer/io/color.h"
#include "cartographer/io/proto_stream.h"
#include "cartographer/mapping/pose_graph.h"
#include "cartographer_ros/msg_conversion.h"
#include "cartographer_ros/time_conversion.h"
#include "cartographer_ros_msgs/StatusCode.h"
#include "cartographer_ros_msgs/StatusResponse.h"
namespace cartographer_ros {
namespace {
using ::cartographer::transform::Rigid3d;
//前面这几个似乎是显示函数,几个函数不是MapBuilderBridge的成员函数,而只是一些工具函数
constexpr double kTrajectoryLineStripMarkerScale = 0.07;
constexpr double kLandmarkMarkerScale = 0.2;
constexpr double kConstraintMarkerScale = 0.025;
::std_msgs::ColorRGBA ToMessage(const cartographer::io::FloatColor& color) {
::std_msgs::ColorRGBA result;
result.r = color[0];
result.g = color[1];
result.b = color[2];
result.a = 1.f;
return result;
}
//这个是用于在rviz中进行轨迹显示函数,详细的可以参考一下这个博客:
//https://www.cnblogs.com/HaoQChen/p/11048611.html
visualization_msgs::Marker CreateTrajectoryMarker(const int trajectory_id,
const std::string& frame_id) {
visualization_msgs::Marker marker;
marker.ns = absl::StrCat("Trajectory ", trajectory_id);
marker.id = 0;
marker.type = visualization_msgs::Marker::LINE_STRIP;
marker.header.stamp = ::ros::Time::now();
marker.header.frame_id = frame_id;
marker.color = ToMessage(cartographer::io::GetColor(trajectory_id));
marker.scale.x = kTrajectoryLineStripMarkerScale;
marker.pose.orientation.w = 1.;
marker.pose.position.z = 0.05;
return marker;
}
//看一下cartographer的配置文件(/src/cartographer_ros/cartographer_ros/configuration_files/backpack_2d.lua or backpack_3d.lua)可以发现,
//在里面设置use_landmarks = false,所以,landmar这部分功能在目前的代码中是没有起作用的。但cartographer已经考虑了加入landmark的途径。
//这样在后面的工作中,要更改的代码量应该不会特别大了。调用map_builder_->pose_graph()->GetLandmarkPoses()可获取Landmark的Pose;
//返回一个指定id的landmark在container中的索引值;该函数也并非MapBuilderBridge的成员函数
int GetLandmarkIndex(
const std::string& landmark_id,
std::unordered_map<std::string, int>* landmark_id_to_index) {
auto it = landmark_id_to_index->find(landmark_id);
if (it == landmark_id_to_index->end()) {
const int new_index = landmark_id_to_index->size();
landmark_id_to_index->emplace(landmark_id, new_index);
return new_index;
}
return it->second;
}
//创建一个landmark
visualization_msgs::Marker CreateLandmarkMarker(int landmark_index,
const Rigid3d& landmark_pose,
const std::string& frame_id) {
visualization_msgs::Marker marker;
marker.ns = "Landmarks";
marker.id = landmark_index;
marker.type = visualization_msgs::Marker::SPHERE;
marker.header.stamp = ::ros::Time::now();
marker.header.frame_id = frame_id;
marker.scale.x = kLandmarkMarkerScale;
marker.scale.y = kLandmarkMarkerScale;
marker.scale.z = kLandmarkMarkerScale;
marker.color = ToMessage(cartographer::io::GetColor(landmark_index));
marker.pose = ToGeometryMsgPose(landmark_pose);
return marker;
}
//获取LandMark的Pose列表
void PushAndResetLineMarker(visualization_msgs::Marker* marker,
std::vector<visualization_msgs::Marker>* markers) {
markers->push_back(*marker);
++marker->id;
marker->points.clear();
}
} // namespace
//node_options是从配置文件中加载的配置项,map_builder则是Cartographer的地图构建器,tf_buffer是ROS系统中坐标变换库tf2的监听缓存。
//map_builder_bridge_对象是node对象的一个成员,在node对象的构造函数中构建。 而它的初始化需要在node对象调用它的成员函数AddTrajectory之后才能触发。
//在这个函数中,会调用map_builder_bridge_对象的AddTrajectory成员函数,函数定义在下方
MapBuilderBridge::MapBuilderBridge(
const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* const tf_buffer)
: node_options_(node_options),
map_builder_(std::move(map_builder)),
tf_buffer_(tf_buffer) {}
//调用了map_builder_的成员函数LoadState来加载一个.pbstream文件。map_builder_是接口MapBuilderInterface的实例化对象,而根据是2d还是3d情况,其具体实现会略有不同。
void MapBuilderBridge::LoadState(const std::string& state_filename,
bool load_frozen_state) {
// Check if suffix of the state file is ".pbstream".
const std::string suffix = ".pbstream";
CHECK_EQ(state_filename.substr(
std::max<int>(state_filename.size() - suffix.size(), 0)),
suffix)
<< "The file containing the state to be loaded must be a "
".pbstream file.";
LOG(INFO) << "Loading saved state '" << state_filename << "'...";
cartographer::io::ProtoStreamReader stream(state_filename);
map_builder_->LoadState(&stream, load_frozen_state);
}
//第一句话很长,它通知map_builder_对象添加一个轨迹跟踪器,同时将构建成功的索引返回保存在局部变量trajectory_id中。虽然这句话很长,但这个被调用的函数只有三个参数。
//前两个参数无非是关于传感器和轨迹跟踪器的一些配置信息。第三个参数比较重要,看字面意思,它相当于注册了一个回调函数OnLocalSlamResult,
//用于响应map_builder_完成一个局部SLAM或者说是成功构建了一个子图的事件。
int MapBuilderBridge::AddTrajectory(
const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& trajectory_options) {
//调用了map_builder_->AddTrajectoryBuilder,这已经是cartographer项目中的代码了。可以看到传入的数据有传感器的id,trajectory的一些配置参数,以及一个仿函数对象
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 << "'.";
//检查trajectory_id确保之前没有使用过之后,为之构建一个SensorBridge对象。 SensorBridge(sensor_bridge.h, sensor_bridge.cc)是cartographer_ros中
//对于传感器的一个封装, 用于将ROS的消息转换成Cartographer中的传感器数据类型。
// Make sure there is no trajectory with 'trajectory_id' yet.
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));
//最后将轨迹相关的配置保存到容器对象trajectory_options_中并检查后,返回刚刚生成的索引trajectory_id。
auto emplace_result =
trajectory_options_.emplace(trajectory_id, trajectory_options);
CHECK(emplace_result.second == true);
return trajectory_id;
}
//调用了map_builder_的成员函数来处理:
void MapBuilderBridge::FinishTrajectory(const int trajectory_id) {
LOG(INFO) << "Finishing trajectory with ID '" << trajectory_id << "'...";
// Make sure there is a trajectory with 'trajectory_id'.
CHECK(GetTrajectoryStates().count(trajectory_id));
map_builder_->FinishTrajectory(trajectory_id);
sensor_bridges_.erase(trajectory_id);
}
调用了map_builder_的成员函数来处理:
void MapBuilderBridge::RunFinalOptimization() {
LOG(INFO) << "Running final trajectory optimization...";
map_builder_->pose_graph()->RunFinalOptimization();
}
bool MapBuilderBridge::SerializeState(const std::string& filename,
const bool include_unfinished_submaps) {
return map_builder_->SerializeStateToFile(include_unfinished_submaps,
filename);
}
//处理submap查询的函数,在cartographer_node中被kSubmapQueryServiceName这个Service调用。
//调用map_builder_->SubmapToProto(submap_id, &response_proto);这个函数查询信息,结果放到response这个变量中。
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;
}
//接下来GetFrozenTrajectoryIds这个函数从名字看是冻结一个trajectory.不太明白具体是什么意思,个人猜测是一条trajectory已经构建完毕,不再继续扩展之后是不是就把
//其Frozen并存起来。当然,需要调用map_builder_->pose_graph()->GetTrajectoryNodePoses()和map_builder_->pose_graph()->IsTrajectoryFrozen(trajectory_id)来处理。
std::map<int, ::cartographer::mapping::PoseGraphInterface::TrajectoryState>
MapBuilderBridge::GetTrajectoryStates() {
auto trajectory_states = map_builder_->pose_graph()->GetTrajectoryStates();
// Add active trajectories that are not yet in the pose graph, but are e.g.
// waiting for input sensor data and thus already have a sensor bridge.
for (const auto& sensor_bridge : sensor_bridges_) {
trajectory_states.insert(std::make_pair(
sensor_bridge.first,
::cartographer::mapping::PoseGraph::TrajectoryState::ACTIVE));
}
return trajectory_states;
}
//GetSubmapList(),这个函数是在往kSubmapListTopic这个Topic上发布数据时被Node::PublishSubmapList调用的,用来获取Submap的列表:
//该函数主要也是通过调用map_builder_->pose_graph()->GetAllSubmapPoses()来获取列表信息。
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;
}
//GetLocalTrajectoryStates用来返回一个LocalTrajectoryStates变量组成的unordered_map这个容器。TrajectoryStates这个结构体的定义如上,
//见MapBuilderBridge的成员函数。这里稍微注意一下,Unordered Map跟我们程序里MapBuilder里的map不是同一个概念。Unordered Map只是c++中的一种container, 详见:unordered_map
//第三个成员变量std::unique_ptr published_to_tracking;是通过sensor_bridge.tf_bridge().LookupToTracking获取的。
std::unordered_map<int, MapBuilderBridge::LocalTrajectoryData>
MapBuilderBridge::GetLocalTrajectoryData() {
std::unordered_map<int, LocalTrajectoryData> local_trajectory_data;//变量用来存返回结果
for (const auto& entry : sensor_bridges_) {//一个循环,依次取出来TrajectoryState;这里以SensorBridge为索引来取
const int trajectory_id = entry.first;
const SensorBridge& sensor_bridge = *entry.second;
其中,第二个成员变量std::shared_ptr local_slam_data;是通过map_builder_->pose_graph()->GetLocalToGlobalTransform(trajectory_id)获取的,
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);
}//TrajectoryState结构体中的第一个成员LocalSlamData
// Make sure there is a trajectory with 'trajectory_id'.
CHECK_EQ(trajectory_options_.count(trajectory_id), 1);
local_trajectory_data[trajectory_id] = {//第trajectory_id个TrajectoryState存入返回变量中
local_slam_data,
map_builder_->pose_graph()->GetLocalToGlobalTransform(trajectory_id),
//第三个成员变量std::unique_ptr published_to_tracking;是通过sensor_bridge.tf_bridge().LookupToTracking获取的。
sensor_bridge.tf_bridge().LookupToTracking(
local_slam_data->time,
trajectory_options_[trajectory_id].published_frame),
trajectory_options_[trajectory_id]};
}
return local_trajectory_data;
}
void MapBuilderBridge::HandleTrajectoryQuery(
cartographer_ros_msgs::TrajectoryQuery::Request& request,
cartographer_ros_msgs::TrajectoryQuery::Response& response) {
// This query is safe if the trajectory doesn't exist (returns 0 poses).
// However, we can filter unwanted states at the higher level in the node.
const auto node_poses = map_builder_->pose_graph()->GetTrajectoryNodePoses();
for (const auto& node_id_data :
node_poses.trajectory(request.trajectory_id)) {
if (!node_id_data.data.constant_pose_data.has_value()) {
continue;
}
geometry_msgs::PoseStamped pose_stamped;
pose_stamped.header.frame_id = node_options_.map_frame;
pose_stamped.header.stamp =
ToRos(node_id_data.data.constant_pose_data.value().time);
pose_stamped.pose = ToGeometryMsgPose(node_id_data.data.global_pose);
response.trajectory.push_back(pose_stamped);
}
response.status.code = cartographer_ros_msgs::StatusCode::OK;
response.status.message = absl::StrCat(
"Retrieved ", response.trajectory.size(),
" trajectory nodes from trajectory ", request.trajectory_id, ".");
}
//通过map_builder_->pose_graph()->GetTrajectoryNodePoses()来获取TrajectoryNode的pose的。map_builder_->pose_graph()->constraints()获取Constraints。
//但这个node和constraint具体指什么呢?是建图过程中的一些节点和他们之前的约束?猜测这块儿可能跟GrapherSlam这方便的东西相关。
//PushAndResetLineMarker和ToGeometryMsgPoint应该都是与显示相关的部分。
visualization_msgs::MarkerArray MapBuilderBridge::GetTrajectoryNodeList() {
visualization_msgs::MarkerArray trajectory_node_list;
const auto node_poses = map_builder_->pose_graph()->GetTrajectoryNodePoses();
// Find the last node indices for each trajectory that have either
// inter-submap or inter-trajectory constraints.
std::map<int, int /* node_index */>
trajectory_to_last_inter_submap_constrained_node;
std::map<int, int /* node_index */>
trajectory_to_last_inter_trajectory_constrained_node;
for (const int trajectory_id : node_poses.trajectory_ids()) {
trajectory_to_last_inter_submap_constrained_node[trajectory_id] = 0;
trajectory_to_last_inter_trajectory_constrained_node[trajectory_id] = 0;
}
const auto constraints = map_builder_->pose_graph()->constraints();
for (const auto& constraint : constraints) {
if (constraint.tag ==
cartographer::mapping::PoseGraph::Constraint::INTER_SUBMAP) {
if (constraint.node_id.trajectory_id ==
constraint.submap_id.trajectory_id) {
trajectory_to_last_inter_submap_constrained_node[constraint.node_id
.trajectory_id] =
std::max(trajectory_to_last_inter_submap_constrained_node.at(
constraint.node_id.trajectory_id),
constraint.node_id.node_index);
} else {
trajectory_to_last_inter_trajectory_constrained_node
[constraint.node_id.trajectory_id] =
std::max(trajectory_to_last_inter_submap_constrained_node.at(
constraint.node_id.trajectory_id),
constraint.node_id.node_index);
}
}
}
for (const int trajectory_id : node_poses.trajectory_ids()) {
visualization_msgs::Marker marker =
CreateTrajectoryMarker(trajectory_id, node_options_.map_frame);
int last_inter_submap_constrained_node = std::max(
node_poses.trajectory(trajectory_id).begin()->id.node_index,
trajectory_to_last_inter_submap_constrained_node.at(trajectory_id));
int last_inter_trajectory_constrained_node = std::max(
node_poses.trajectory(trajectory_id).begin()->id.node_index,
trajectory_to_last_inter_trajectory_constrained_node.at(trajectory_id));
last_inter_submap_constrained_node =
std::max(last_inter_submap_constrained_node,
last_inter_trajectory_constrained_node);
if (map_builder_->pose_graph()->IsTrajectoryFrozen(trajectory_id)) {
last_inter_submap_constrained_node =
(--node_poses.trajectory(trajectory_id).end())->id.node_index;
last_inter_trajectory_constrained_node =
last_inter_submap_constrained_node;
}
marker.color.a = 1.0;
for (const auto& node_id_data : node_poses.trajectory(trajectory_id)) {
if (!node_id_data.data.constant_pose_data.has_value()) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
continue;
}
const ::geometry_msgs::Point node_point =
ToGeometryMsgPoint(node_id_data.data.global_pose.translation());
marker.points.push_back(node_point);
if (node_id_data.id.node_index ==
last_inter_trajectory_constrained_node) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
marker.points.push_back(node_point);
marker.color.a = 0.5;
}
if (node_id_data.id.node_index == last_inter_submap_constrained_node) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
marker.points.push_back(node_point);
marker.color.a = 0.25;
}
// Work around the 16384 point limit in RViz by splitting the
// trajectory into multiple markers.
if (marker.points.size() == 16384) {
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
// Push back the last point, so the two markers appear connected.
marker.points.push_back(node_point);
}
}
PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
size_t current_last_marker_id = static_cast<size_t>(marker.id - 1);
if (trajectory_to_highest_marker_id_.count(trajectory_id) == 0) {
trajectory_to_highest_marker_id_[trajectory_id] = current_last_marker_id;
} else {
marker.action = visualization_msgs::Marker::DELETE;
while (static_cast<size_t>(marker.id) <=
trajectory_to_highest_marker_id_[trajectory_id]) {
trajectory_node_list.markers.push_back(marker);
++marker.id;
}
trajectory_to_highest_marker_id_[trajectory_id] = current_last_marker_id;
}
}
return trajectory_node_list;
}
visualization_msgs::MarkerArray MapBuilderBridge::GetLandmarkPosesList() {
visualization_msgs::MarkerArray landmark_poses_list;
const std::map<std::string, Rigid3d> landmark_poses =
map_builder_->pose_graph()->GetLandmarkPoses();
for (const auto& id_to_pose : landmark_poses) {
landmark_poses_list.markers.push_back(CreateLandmarkMarker(
GetLandmarkIndex(id_to_pose.first, &landmark_to_index_),
id_to_pose.second, node_options_.map_frame));
}
return landmark_poses_list;
}
//获取Constraint. 应该是与GetTrajectoryStateNodeList配合使用的。
visualization_msgs::MarkerArray MapBuilderBridge::GetConstraintList() {
visualization_msgs::MarkerArray constraint_list;
int marker_id = 0;
visualization_msgs::Marker constraint_intra_marker;
constraint_intra_marker.id = marker_id++;
constraint_intra_marker.ns = "Intra constraints";
constraint_intra_marker.type = visualization_msgs::Marker::LINE_LIST;
constraint_intra_marker.header.stamp = ros::Time::now();
constraint_intra_marker.header.frame_id = node_options_.map_frame;
constraint_intra_marker.scale.x = kConstraintMarkerScale;
constraint_intra_marker.pose.orientation.w = 1.0;
visualization_msgs::Marker residual_intra_marker = constraint_intra_marker;
residual_intra_marker.id = marker_id++;
residual_intra_marker.ns = "Intra residuals";
// This and other markers which are less numerous are set to be slightly
// above the intra constraints marker in order to ensure that they are
// visible.
residual_intra_marker.pose.position.z = 0.1;
visualization_msgs::Marker constraint_inter_same_trajectory_marker =
constraint_intra_marker;
constraint_inter_same_trajectory_marker.id = marker_id++;
constraint_inter_same_trajectory_marker.ns =
"Inter constraints, same trajectory";
constraint_inter_same_trajectory_marker.pose.position.z = 0.1;
visualization_msgs::Marker residual_inter_same_trajectory_marker =
constraint_intra_marker;
residual_inter_same_trajectory_marker.id = marker_id++;
residual_inter_same_trajectory_marker.ns = "Inter residuals, same trajectory";
residual_inter_same_trajectory_marker.pose.position.z = 0.1;
visualization_msgs::Marker constraint_inter_diff_trajectory_marker =
constraint_intra_marker;
constraint_inter_diff_trajectory_marker.id = marker_id++;
constraint_inter_diff_trajectory_marker.ns =
"Inter constraints, different trajectories";
constraint_inter_diff_trajectory_marker.pose.position.z = 0.1;
visualization_msgs::Marker residual_inter_diff_trajectory_marker =
constraint_intra_marker;
residual_inter_diff_trajectory_marker.id = marker_id++;
residual_inter_diff_trajectory_marker.ns =
"Inter residuals, different trajectories";
residual_inter_diff_trajectory_marker.pose.position.z = 0.1;
const auto trajectory_node_poses =
map_builder_->pose_graph()->GetTrajectoryNodePoses();
const auto submap_poses = map_builder_->pose_graph()->GetAllSubmapPoses();
const auto constraints = map_builder_->pose_graph()->constraints();
for (const auto& constraint : constraints) {
visualization_msgs::Marker *constraint_marker, *residual_marker;
std_msgs::ColorRGBA color_constraint, color_residual;
if (constraint.tag ==
cartographer::mapping::PoseGraph::Constraint::INTRA_SUBMAP) {
constraint_marker = &constraint_intra_marker;
residual_marker = &residual_intra_marker;
// Color mapping for submaps of various trajectories - add trajectory id
// to ensure different starting colors. Also add a fixed offset of 25
// to avoid having identical colors as trajectories.
color_constraint = ToMessage(
cartographer::io::GetColor(constraint.submap_id.submap_index +
constraint.submap_id.trajectory_id + 25));
color_residual.a = 1.0;
color_residual.r = 1.0;
} else {
if (constraint.node_id.trajectory_id ==
constraint.submap_id.trajectory_id) {
constraint_marker = &constraint_inter_same_trajectory_marker;
residual_marker = &residual_inter_same_trajectory_marker;
// Bright yellow
color_constraint.a = 1.0;
color_constraint.r = color_constraint.g = 1.0;
} else {
constraint_marker = &constraint_inter_diff_trajectory_marker;
residual_marker = &residual_inter_diff_trajectory_marker;
// Bright orange
color_constraint.a = 1.0;
color_constraint.r = 1.0;
color_constraint.g = 165. / 255.;
}
// Bright cyan
color_residual.a = 1.0;
color_residual.b = color_residual.g = 1.0;
}
for (int i = 0; i < 2; ++i) {
constraint_marker->colors.push_back(color_constraint);
residual_marker->colors.push_back(color_residual);
}
const auto submap_it = submap_poses.find(constraint.submap_id);
if (submap_it == submap_poses.end()) {
continue;
}
const auto& submap_pose = submap_it->data.pose;
const auto node_it = trajectory_node_poses.find(constraint.node_id);
if (node_it == trajectory_node_poses.end()) {
continue;
}
const auto& trajectory_node_pose = node_it->data.global_pose;
const Rigid3d constraint_pose = submap_pose * constraint.pose.zbar_ij;
constraint_marker->points.push_back(
ToGeometryMsgPoint(submap_pose.translation()));
constraint_marker->points.push_back(
ToGeometryMsgPoint(constraint_pose.translation()));
residual_marker->points.push_back(
ToGeometryMsgPoint(constraint_pose.translation()));
residual_marker->points.push_back(
ToGeometryMsgPoint(trajectory_node_pose.translation()));
}
constraint_list.markers.push_back(constraint_intra_marker);
constraint_list.markers.push_back(residual_intra_marker);
constraint_list.markers.push_back(constraint_inter_same_trajectory_marker);
constraint_list.markers.push_back(residual_inter_same_trajectory_marker);
constraint_list.markers.push_back(constraint_inter_diff_trajectory_marker);
constraint_list.markers.push_back(residual_inter_diff_trajectory_marker);
return constraint_list;
}
//map_builder_bridge_的成员函数, 返回map容器中trajectory_id所对应的对象。
SensorBridge* MapBuilderBridge::sensor_bridge(const int trajectory_id) {
return sensor_bridges_.at(trajectory_id).get();
}
//该函数的目的就是记录下轨迹状态,
void MapBuilderBridge::OnLocalSlamResult(
const int trajectory_id, const ::cartographer::common::Time time,//轨迹索引,更新子图的时间
const Rigid3d local_pose,//子图的参考位置
::cartographer::sensor::RangeData range_data_in_local) {//参考位置下的扫描数据
//然后根据输入的参数构建对象local_slam_data。它的数据类型LocalSlamData是定义在MapBuilderBridge内部的结构体,用于记录局部SLAM反馈的状态。
std::shared_ptr<const LocalTrajectoryData::LocalSlamData> local_slam_data =
std::make_shared<LocalTrajectoryData::LocalSlamData>(
LocalTrajectoryData::LocalSlamData{time, local_pose,
std::move(range_data_in_local)});
absl::MutexLock lock(&mutex_);//最后加锁,写入容器trajectory_state_data_中。
local_slam_data_[trajectory_id] = std::move(local_slam_data);
}
} // namespace cartographer_ros
通篇主要参考于:
https://zhuanlan.zhihu.com/p/48231189