00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer_ros/map_builder_bridge.h"
00018
00019 #include "absl/memory/memory.h"
00020 #include "absl/strings/str_cat.h"
00021 #include "cartographer/io/color.h"
00022 #include "cartographer/io/proto_stream.h"
00023 #include "cartographer/mapping/pose_graph.h"
00024 #include "cartographer_ros/msg_conversion.h"
00025 #include "cartographer_ros/time_conversion.h"
00026 #include "cartographer_ros_msgs/StatusCode.h"
00027 #include "cartographer_ros_msgs/StatusResponse.h"
00028
00029 namespace cartographer_ros {
00030 namespace {
00031
00032 using ::cartographer::transform::Rigid3d;
00033
00034 constexpr double kTrajectoryLineStripMarkerScale = 0.07;
00035 constexpr double kLandmarkMarkerScale = 0.2;
00036 constexpr double kConstraintMarkerScale = 0.025;
00037
00038 ::std_msgs::ColorRGBA ToMessage(const cartographer::io::FloatColor& color) {
00039 ::std_msgs::ColorRGBA result;
00040 result.r = color[0];
00041 result.g = color[1];
00042 result.b = color[2];
00043 result.a = 1.f;
00044 return result;
00045 }
00046
00047 visualization_msgs::Marker CreateTrajectoryMarker(const int trajectory_id,
00048 const std::string& frame_id) {
00049 visualization_msgs::Marker marker;
00050 marker.ns = absl::StrCat("Trajectory ", trajectory_id);
00051 marker.id = 0;
00052 marker.type = visualization_msgs::Marker::LINE_STRIP;
00053 marker.header.stamp = ::ros::Time::now();
00054 marker.header.frame_id = frame_id;
00055 marker.color = ToMessage(cartographer::io::GetColor(trajectory_id));
00056 marker.scale.x = kTrajectoryLineStripMarkerScale;
00057 marker.pose.orientation.w = 1.;
00058 marker.pose.position.z = 0.05;
00059 return marker;
00060 }
00061
00062 int GetLandmarkIndex(
00063 const std::string& landmark_id,
00064 std::unordered_map<std::string, int>* landmark_id_to_index) {
00065 auto it = landmark_id_to_index->find(landmark_id);
00066 if (it == landmark_id_to_index->end()) {
00067 const int new_index = landmark_id_to_index->size();
00068 landmark_id_to_index->emplace(landmark_id, new_index);
00069 return new_index;
00070 }
00071 return it->second;
00072 }
00073
00074 visualization_msgs::Marker CreateLandmarkMarker(int landmark_index,
00075 const Rigid3d& landmark_pose,
00076 const std::string& frame_id) {
00077 visualization_msgs::Marker marker;
00078 marker.ns = "Landmarks";
00079 marker.id = landmark_index;
00080 marker.type = visualization_msgs::Marker::SPHERE;
00081 marker.header.stamp = ::ros::Time::now();
00082 marker.header.frame_id = frame_id;
00083 marker.scale.x = kLandmarkMarkerScale;
00084 marker.scale.y = kLandmarkMarkerScale;
00085 marker.scale.z = kLandmarkMarkerScale;
00086 marker.color = ToMessage(cartographer::io::GetColor(landmark_index));
00087 marker.pose = ToGeometryMsgPose(landmark_pose);
00088 return marker;
00089 }
00090
00091 void PushAndResetLineMarker(visualization_msgs::Marker* marker,
00092 std::vector<visualization_msgs::Marker>* markers) {
00093 markers->push_back(*marker);
00094 ++marker->id;
00095 marker->points.clear();
00096 }
00097
00098 }
00099
00100 MapBuilderBridge::MapBuilderBridge(
00101 const NodeOptions& node_options,
00102 std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
00103 tf2_ros::Buffer* const tf_buffer)
00104 : node_options_(node_options),
00105 map_builder_(std::move(map_builder)),
00106 tf_buffer_(tf_buffer) {}
00107
00108 void MapBuilderBridge::LoadState(const std::string& state_filename,
00109 bool load_frozen_state) {
00110
00111 const std::string suffix = ".pbstream";
00112 CHECK_EQ(state_filename.substr(
00113 std::max<int>(state_filename.size() - suffix.size(), 0)),
00114 suffix)
00115 << "The file containing the state to be loaded must be a "
00116 ".pbstream file.";
00117 LOG(INFO) << "Loading saved state '" << state_filename << "'...";
00118 cartographer::io::ProtoStreamReader stream(state_filename);
00119 map_builder_->LoadState(&stream, load_frozen_state);
00120 }
00121
00122 int MapBuilderBridge::AddTrajectory(
00123 const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
00124 expected_sensor_ids,
00125 const TrajectoryOptions& trajectory_options) {
00126 const int trajectory_id = map_builder_->AddTrajectoryBuilder(
00127 expected_sensor_ids, trajectory_options.trajectory_builder_options,
00128 [this](const int trajectory_id, const ::cartographer::common::Time time,
00129 const Rigid3d local_pose,
00130 ::cartographer::sensor::RangeData range_data_in_local,
00131 const std::unique_ptr<
00132 const ::cartographer::mapping::TrajectoryBuilderInterface::
00133 InsertionResult>) {
00134 OnLocalSlamResult(trajectory_id, time, local_pose, range_data_in_local);
00135 });
00136 LOG(INFO) << "Added trajectory with ID '" << trajectory_id << "'.";
00137
00138
00139 CHECK_EQ(sensor_bridges_.count(trajectory_id), 0);
00140 sensor_bridges_[trajectory_id] = absl::make_unique<SensorBridge>(
00141 trajectory_options.num_subdivisions_per_laser_scan,
00142 trajectory_options.tracking_frame,
00143 node_options_.lookup_transform_timeout_sec, tf_buffer_,
00144 map_builder_->GetTrajectoryBuilder(trajectory_id));
00145 auto emplace_result =
00146 trajectory_options_.emplace(trajectory_id, trajectory_options);
00147 CHECK(emplace_result.second == true);
00148 return trajectory_id;
00149 }
00150
00151 void MapBuilderBridge::FinishTrajectory(const int trajectory_id) {
00152 LOG(INFO) << "Finishing trajectory with ID '" << trajectory_id << "'...";
00153
00154
00155 CHECK(GetTrajectoryStates().count(trajectory_id));
00156 map_builder_->FinishTrajectory(trajectory_id);
00157 sensor_bridges_.erase(trajectory_id);
00158 }
00159
00160 void MapBuilderBridge::RunFinalOptimization() {
00161 LOG(INFO) << "Running final trajectory optimization...";
00162 map_builder_->pose_graph()->RunFinalOptimization();
00163 }
00164
00165 bool MapBuilderBridge::SerializeState(const std::string& filename,
00166 const bool include_unfinished_submaps) {
00167 return map_builder_->SerializeStateToFile(include_unfinished_submaps,
00168 filename);
00169 }
00170
00171 void MapBuilderBridge::HandleSubmapQuery(
00172 cartographer_ros_msgs::SubmapQuery::Request& request,
00173 cartographer_ros_msgs::SubmapQuery::Response& response) {
00174 cartographer::mapping::proto::SubmapQuery::Response response_proto;
00175 cartographer::mapping::SubmapId submap_id{request.trajectory_id,
00176 request.submap_index};
00177 const std::string error =
00178 map_builder_->SubmapToProto(submap_id, &response_proto);
00179 if (!error.empty()) {
00180 LOG(ERROR) << error;
00181 response.status.code = cartographer_ros_msgs::StatusCode::NOT_FOUND;
00182 response.status.message = error;
00183 return;
00184 }
00185
00186 response.submap_version = response_proto.submap_version();
00187 for (const auto& texture_proto : response_proto.textures()) {
00188 response.textures.emplace_back();
00189 auto& texture = response.textures.back();
00190 texture.cells.insert(texture.cells.begin(), texture_proto.cells().begin(),
00191 texture_proto.cells().end());
00192 texture.width = texture_proto.width();
00193 texture.height = texture_proto.height();
00194 texture.resolution = texture_proto.resolution();
00195 texture.slice_pose = ToGeometryMsgPose(
00196 cartographer::transform::ToRigid3(texture_proto.slice_pose()));
00197 }
00198 response.status.message = "Success.";
00199 response.status.code = cartographer_ros_msgs::StatusCode::OK;
00200 }
00201
00202 std::map<int, ::cartographer::mapping::PoseGraphInterface::TrajectoryState>
00203 MapBuilderBridge::GetTrajectoryStates() {
00204 auto trajectory_states = map_builder_->pose_graph()->GetTrajectoryStates();
00205
00206
00207 for (const auto& sensor_bridge : sensor_bridges_) {
00208 trajectory_states.insert(std::make_pair(
00209 sensor_bridge.first,
00210 ::cartographer::mapping::PoseGraph::TrajectoryState::ACTIVE));
00211 }
00212 return trajectory_states;
00213 }
00214
00215 cartographer_ros_msgs::SubmapList MapBuilderBridge::GetSubmapList() {
00216 cartographer_ros_msgs::SubmapList submap_list;
00217 submap_list.header.stamp = ::ros::Time::now();
00218 submap_list.header.frame_id = node_options_.map_frame;
00219 for (const auto& submap_id_pose :
00220 map_builder_->pose_graph()->GetAllSubmapPoses()) {
00221 cartographer_ros_msgs::SubmapEntry submap_entry;
00222 submap_entry.is_frozen = map_builder_->pose_graph()->IsTrajectoryFrozen(
00223 submap_id_pose.id.trajectory_id);
00224 submap_entry.trajectory_id = submap_id_pose.id.trajectory_id;
00225 submap_entry.submap_index = submap_id_pose.id.submap_index;
00226 submap_entry.submap_version = submap_id_pose.data.version;
00227 submap_entry.pose = ToGeometryMsgPose(submap_id_pose.data.pose);
00228 submap_list.submap.push_back(submap_entry);
00229 }
00230 return submap_list;
00231 }
00232
00233 std::unordered_map<int, MapBuilderBridge::LocalTrajectoryData>
00234 MapBuilderBridge::GetLocalTrajectoryData() {
00235 std::unordered_map<int, LocalTrajectoryData> local_trajectory_data;
00236 for (const auto& entry : sensor_bridges_) {
00237 const int trajectory_id = entry.first;
00238 const SensorBridge& sensor_bridge = *entry.second;
00239
00240 std::shared_ptr<const LocalTrajectoryData::LocalSlamData> local_slam_data;
00241 {
00242 absl::MutexLock lock(&mutex_);
00243 if (local_slam_data_.count(trajectory_id) == 0) {
00244 continue;
00245 }
00246 local_slam_data = local_slam_data_.at(trajectory_id);
00247 }
00248
00249
00250 CHECK_EQ(trajectory_options_.count(trajectory_id), 1);
00251 local_trajectory_data[trajectory_id] = {
00252 local_slam_data,
00253 map_builder_->pose_graph()->GetLocalToGlobalTransform(trajectory_id),
00254 sensor_bridge.tf_bridge().LookupToTracking(
00255 local_slam_data->time,
00256 trajectory_options_[trajectory_id].published_frame),
00257 trajectory_options_[trajectory_id]};
00258 }
00259 return local_trajectory_data;
00260 }
00261
00262 void MapBuilderBridge::HandleTrajectoryQuery(
00263 cartographer_ros_msgs::TrajectoryQuery::Request& request,
00264 cartographer_ros_msgs::TrajectoryQuery::Response& response) {
00265
00266
00267 const auto node_poses = map_builder_->pose_graph()->GetTrajectoryNodePoses();
00268 for (const auto& node_id_data :
00269 node_poses.trajectory(request.trajectory_id)) {
00270 if (!node_id_data.data.constant_pose_data.has_value()) {
00271 continue;
00272 }
00273 geometry_msgs::PoseStamped pose_stamped;
00274 pose_stamped.header.frame_id = node_options_.map_frame;
00275 pose_stamped.header.stamp =
00276 ToRos(node_id_data.data.constant_pose_data.value().time);
00277 pose_stamped.pose = ToGeometryMsgPose(node_id_data.data.global_pose);
00278 response.trajectory.push_back(pose_stamped);
00279 }
00280 response.status.code = cartographer_ros_msgs::StatusCode::OK;
00281 response.status.message = absl::StrCat(
00282 "Retrieved ", response.trajectory.size(),
00283 " trajectory nodes from trajectory ", request.trajectory_id, ".");
00284 }
00285
00286 visualization_msgs::MarkerArray MapBuilderBridge::GetTrajectoryNodeList() {
00287 visualization_msgs::MarkerArray trajectory_node_list;
00288 const auto node_poses = map_builder_->pose_graph()->GetTrajectoryNodePoses();
00289
00290
00291 std::map<int, int >
00292 trajectory_to_last_inter_submap_constrained_node;
00293 std::map<int, int >
00294 trajectory_to_last_inter_trajectory_constrained_node;
00295 for (const int trajectory_id : node_poses.trajectory_ids()) {
00296 trajectory_to_last_inter_submap_constrained_node[trajectory_id] = 0;
00297 trajectory_to_last_inter_trajectory_constrained_node[trajectory_id] = 0;
00298 }
00299 const auto constraints = map_builder_->pose_graph()->constraints();
00300 for (const auto& constraint : constraints) {
00301 if (constraint.tag ==
00302 cartographer::mapping::PoseGraph::Constraint::INTER_SUBMAP) {
00303 if (constraint.node_id.trajectory_id ==
00304 constraint.submap_id.trajectory_id) {
00305 trajectory_to_last_inter_submap_constrained_node[constraint.node_id
00306 .trajectory_id] =
00307 std::max(trajectory_to_last_inter_submap_constrained_node.at(
00308 constraint.node_id.trajectory_id),
00309 constraint.node_id.node_index);
00310 } else {
00311 trajectory_to_last_inter_trajectory_constrained_node
00312 [constraint.node_id.trajectory_id] =
00313 std::max(trajectory_to_last_inter_submap_constrained_node.at(
00314 constraint.node_id.trajectory_id),
00315 constraint.node_id.node_index);
00316 }
00317 }
00318 }
00319
00320 for (const int trajectory_id : node_poses.trajectory_ids()) {
00321 visualization_msgs::Marker marker =
00322 CreateTrajectoryMarker(trajectory_id, node_options_.map_frame);
00323 int last_inter_submap_constrained_node = std::max(
00324 node_poses.trajectory(trajectory_id).begin()->id.node_index,
00325 trajectory_to_last_inter_submap_constrained_node.at(trajectory_id));
00326 int last_inter_trajectory_constrained_node = std::max(
00327 node_poses.trajectory(trajectory_id).begin()->id.node_index,
00328 trajectory_to_last_inter_trajectory_constrained_node.at(trajectory_id));
00329 last_inter_submap_constrained_node =
00330 std::max(last_inter_submap_constrained_node,
00331 last_inter_trajectory_constrained_node);
00332
00333 if (map_builder_->pose_graph()->IsTrajectoryFrozen(trajectory_id)) {
00334 last_inter_submap_constrained_node =
00335 (--node_poses.trajectory(trajectory_id).end())->id.node_index;
00336 last_inter_trajectory_constrained_node =
00337 last_inter_submap_constrained_node;
00338 }
00339
00340 marker.color.a = 1.0;
00341 for (const auto& node_id_data : node_poses.trajectory(trajectory_id)) {
00342 if (!node_id_data.data.constant_pose_data.has_value()) {
00343 PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
00344 continue;
00345 }
00346 const ::geometry_msgs::Point node_point =
00347 ToGeometryMsgPoint(node_id_data.data.global_pose.translation());
00348 marker.points.push_back(node_point);
00349
00350 if (node_id_data.id.node_index ==
00351 last_inter_trajectory_constrained_node) {
00352 PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
00353 marker.points.push_back(node_point);
00354 marker.color.a = 0.5;
00355 }
00356 if (node_id_data.id.node_index == last_inter_submap_constrained_node) {
00357 PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
00358 marker.points.push_back(node_point);
00359 marker.color.a = 0.25;
00360 }
00361
00362
00363 if (marker.points.size() == 16384) {
00364 PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
00365
00366 marker.points.push_back(node_point);
00367 }
00368 }
00369 PushAndResetLineMarker(&marker, &trajectory_node_list.markers);
00370 size_t current_last_marker_id = static_cast<size_t>(marker.id - 1);
00371 if (trajectory_to_highest_marker_id_.count(trajectory_id) == 0) {
00372 trajectory_to_highest_marker_id_[trajectory_id] = current_last_marker_id;
00373 } else {
00374 marker.action = visualization_msgs::Marker::DELETE;
00375 while (static_cast<size_t>(marker.id) <=
00376 trajectory_to_highest_marker_id_[trajectory_id]) {
00377 trajectory_node_list.markers.push_back(marker);
00378 ++marker.id;
00379 }
00380 trajectory_to_highest_marker_id_[trajectory_id] = current_last_marker_id;
00381 }
00382 }
00383 return trajectory_node_list;
00384 }
00385
00386 visualization_msgs::MarkerArray MapBuilderBridge::GetLandmarkPosesList() {
00387 visualization_msgs::MarkerArray landmark_poses_list;
00388 const std::map<std::string, Rigid3d> landmark_poses =
00389 map_builder_->pose_graph()->GetLandmarkPoses();
00390 for (const auto& id_to_pose : landmark_poses) {
00391 landmark_poses_list.markers.push_back(CreateLandmarkMarker(
00392 GetLandmarkIndex(id_to_pose.first, &landmark_to_index_),
00393 id_to_pose.second, node_options_.map_frame));
00394 }
00395 return landmark_poses_list;
00396 }
00397
00398 visualization_msgs::MarkerArray MapBuilderBridge::GetConstraintList() {
00399 visualization_msgs::MarkerArray constraint_list;
00400 int marker_id = 0;
00401 visualization_msgs::Marker constraint_intra_marker;
00402 constraint_intra_marker.id = marker_id++;
00403 constraint_intra_marker.ns = "Intra constraints";
00404 constraint_intra_marker.type = visualization_msgs::Marker::LINE_LIST;
00405 constraint_intra_marker.header.stamp = ros::Time::now();
00406 constraint_intra_marker.header.frame_id = node_options_.map_frame;
00407 constraint_intra_marker.scale.x = kConstraintMarkerScale;
00408 constraint_intra_marker.pose.orientation.w = 1.0;
00409
00410 visualization_msgs::Marker residual_intra_marker = constraint_intra_marker;
00411 residual_intra_marker.id = marker_id++;
00412 residual_intra_marker.ns = "Intra residuals";
00413
00414
00415
00416 residual_intra_marker.pose.position.z = 0.1;
00417
00418 visualization_msgs::Marker constraint_inter_same_trajectory_marker =
00419 constraint_intra_marker;
00420 constraint_inter_same_trajectory_marker.id = marker_id++;
00421 constraint_inter_same_trajectory_marker.ns =
00422 "Inter constraints, same trajectory";
00423 constraint_inter_same_trajectory_marker.pose.position.z = 0.1;
00424
00425 visualization_msgs::Marker residual_inter_same_trajectory_marker =
00426 constraint_intra_marker;
00427 residual_inter_same_trajectory_marker.id = marker_id++;
00428 residual_inter_same_trajectory_marker.ns = "Inter residuals, same trajectory";
00429 residual_inter_same_trajectory_marker.pose.position.z = 0.1;
00430
00431 visualization_msgs::Marker constraint_inter_diff_trajectory_marker =
00432 constraint_intra_marker;
00433 constraint_inter_diff_trajectory_marker.id = marker_id++;
00434 constraint_inter_diff_trajectory_marker.ns =
00435 "Inter constraints, different trajectories";
00436 constraint_inter_diff_trajectory_marker.pose.position.z = 0.1;
00437
00438 visualization_msgs::Marker residual_inter_diff_trajectory_marker =
00439 constraint_intra_marker;
00440 residual_inter_diff_trajectory_marker.id = marker_id++;
00441 residual_inter_diff_trajectory_marker.ns =
00442 "Inter residuals, different trajectories";
00443 residual_inter_diff_trajectory_marker.pose.position.z = 0.1;
00444
00445 const auto trajectory_node_poses =
00446 map_builder_->pose_graph()->GetTrajectoryNodePoses();
00447 const auto submap_poses = map_builder_->pose_graph()->GetAllSubmapPoses();
00448 const auto constraints = map_builder_->pose_graph()->constraints();
00449
00450 for (const auto& constraint : constraints) {
00451 visualization_msgs::Marker *constraint_marker, *residual_marker;
00452 std_msgs::ColorRGBA color_constraint, color_residual;
00453 if (constraint.tag ==
00454 cartographer::mapping::PoseGraph::Constraint::INTRA_SUBMAP) {
00455 constraint_marker = &constraint_intra_marker;
00456 residual_marker = &residual_intra_marker;
00457
00458
00459
00460 color_constraint = ToMessage(
00461 cartographer::io::GetColor(constraint.submap_id.submap_index +
00462 constraint.submap_id.trajectory_id + 25));
00463 color_residual.a = 1.0;
00464 color_residual.r = 1.0;
00465 } else {
00466 if (constraint.node_id.trajectory_id ==
00467 constraint.submap_id.trajectory_id) {
00468 constraint_marker = &constraint_inter_same_trajectory_marker;
00469 residual_marker = &residual_inter_same_trajectory_marker;
00470
00471 color_constraint.a = 1.0;
00472 color_constraint.r = color_constraint.g = 1.0;
00473 } else {
00474 constraint_marker = &constraint_inter_diff_trajectory_marker;
00475 residual_marker = &residual_inter_diff_trajectory_marker;
00476
00477 color_constraint.a = 1.0;
00478 color_constraint.r = 1.0;
00479 color_constraint.g = 165. / 255.;
00480 }
00481
00482 color_residual.a = 1.0;
00483 color_residual.b = color_residual.g = 1.0;
00484 }
00485
00486 for (int i = 0; i < 2; ++i) {
00487 constraint_marker->colors.push_back(color_constraint);
00488 residual_marker->colors.push_back(color_residual);
00489 }
00490
00491 const auto submap_it = submap_poses.find(constraint.submap_id);
00492 if (submap_it == submap_poses.end()) {
00493 continue;
00494 }
00495 const auto& submap_pose = submap_it->data.pose;
00496 const auto node_it = trajectory_node_poses.find(constraint.node_id);
00497 if (node_it == trajectory_node_poses.end()) {
00498 continue;
00499 }
00500 const auto& trajectory_node_pose = node_it->data.global_pose;
00501 const Rigid3d constraint_pose = submap_pose * constraint.pose.zbar_ij;
00502
00503 constraint_marker->points.push_back(
00504 ToGeometryMsgPoint(submap_pose.translation()));
00505 constraint_marker->points.push_back(
00506 ToGeometryMsgPoint(constraint_pose.translation()));
00507
00508 residual_marker->points.push_back(
00509 ToGeometryMsgPoint(constraint_pose.translation()));
00510 residual_marker->points.push_back(
00511 ToGeometryMsgPoint(trajectory_node_pose.translation()));
00512 }
00513
00514 constraint_list.markers.push_back(constraint_intra_marker);
00515 constraint_list.markers.push_back(residual_intra_marker);
00516 constraint_list.markers.push_back(constraint_inter_same_trajectory_marker);
00517 constraint_list.markers.push_back(residual_inter_same_trajectory_marker);
00518 constraint_list.markers.push_back(constraint_inter_diff_trajectory_marker);
00519 constraint_list.markers.push_back(residual_inter_diff_trajectory_marker);
00520 return constraint_list;
00521 }
00522
00523 SensorBridge* MapBuilderBridge::sensor_bridge(const int trajectory_id) {
00524 return sensor_bridges_.at(trajectory_id).get();
00525 }
00526
00527 void MapBuilderBridge::OnLocalSlamResult(
00528 const int trajectory_id, const ::cartographer::common::Time time,
00529 const Rigid3d local_pose,
00530 ::cartographer::sensor::RangeData range_data_in_local) {
00531 std::shared_ptr<const LocalTrajectoryData::LocalSlamData> local_slam_data =
00532 std::make_shared<LocalTrajectoryData::LocalSlamData>(
00533 LocalTrajectoryData::LocalSlamData{time, local_pose,
00534 std::move(range_data_in_local)});
00535 absl::MutexLock lock(&mutex_);
00536 local_slam_data_[trajectory_id] = std::move(local_slam_data);
00537 }
00538
00539 }