00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer/io/serialization_format_migration.h"
00018
00019 #include <vector>
00020
00021 #include "absl/container/flat_hash_map.h"
00022 #include "cartographer/mapping/3d/submap_3d.h"
00023 #include "cartographer/mapping/internal/3d/scan_matching/rotational_scan_matcher.h"
00024 #include "cartographer/mapping/probability_values.h"
00025 #include "cartographer/mapping/proto/internal/legacy_serialized_data.pb.h"
00026 #include "cartographer/mapping/proto/internal/legacy_submap.pb.h"
00027 #include "cartographer/mapping/proto/trajectory_builder_options.pb.h"
00028 #include "glog/logging.h"
00029
00030 namespace cartographer {
00031 namespace io {
00032 namespace {
00033
00034 using mapping::proto::SerializedData;
00035 using ProtoMap = absl::flat_hash_map<int, std::vector<SerializedData>>;
00036
00037 bool ReadPoseGraph(cartographer::io::ProtoStreamReaderInterface* const input,
00038 ProtoMap* proto_map) {
00039 auto& pose_graph_vec = (*proto_map)[SerializedData::kPoseGraph];
00040 pose_graph_vec.emplace_back();
00041 return input->ReadProto(pose_graph_vec.back().mutable_pose_graph());
00042 }
00043
00044 bool ReadBuilderOptions(
00045 cartographer::io::ProtoStreamReaderInterface* const input,
00046 ProtoMap* proto_map) {
00047 auto& options_vec =
00048 (*proto_map)[SerializedData::kAllTrajectoryBuilderOptions];
00049 options_vec.emplace_back();
00050 return input->ReadProto(
00051 options_vec.back().mutable_all_trajectory_builder_options());
00052 }
00053
00054 mapping::proto::Submap MigrateLegacySubmap2d(
00055 const mapping::proto::LegacySubmap& submap_in) {
00056 mapping::proto::Submap2D submap_2d;
00057
00058
00059 *submap_2d.mutable_grid()->mutable_limits() =
00060 submap_in.submap_2d().probability_grid().limits();
00061 *submap_2d.mutable_grid()->mutable_cells() =
00062 submap_in.submap_2d().probability_grid().cells();
00063 for (auto& cell : *submap_2d.mutable_grid()->mutable_cells()) {
00064 cell = -1 * cell;
00065 }
00066
00067
00068 submap_2d.mutable_grid()->mutable_known_cells_box()->set_max_x(
00069 submap_in.submap_2d().probability_grid().known_cells_box().max_x());
00070 submap_2d.mutable_grid()->mutable_known_cells_box()->set_max_y(
00071 submap_in.submap_2d().probability_grid().known_cells_box().max_y());
00072 submap_2d.mutable_grid()->mutable_known_cells_box()->set_min_x(
00073 submap_in.submap_2d().probability_grid().known_cells_box().min_x());
00074 submap_2d.mutable_grid()->mutable_known_cells_box()->set_min_y(
00075 submap_in.submap_2d().probability_grid().known_cells_box().min_y());
00076
00077
00078
00079
00080 submap_2d.mutable_grid()->set_max_correspondence_cost(
00081 mapping::kMaxCorrespondenceCost);
00082 submap_2d.mutable_grid()->set_min_correspondence_cost(
00083 mapping::kMinCorrespondenceCost);
00084 submap_2d.mutable_grid()->mutable_probability_grid_2d();
00085 *submap_2d.mutable_local_pose() = submap_in.submap_2d().local_pose();
00086 submap_2d.set_num_range_data(submap_in.submap_2d().num_range_data());
00087 submap_2d.set_finished(submap_in.submap_2d().finished());
00088
00089 mapping::proto::Submap submap_out;
00090 *submap_out.mutable_submap_2d() = submap_2d;
00091 *submap_out.mutable_submap_id() = submap_in.submap_id();
00092 return submap_out;
00093 }
00094
00095 mapping::proto::Submap MigrateLegacySubmap3d(
00096 const mapping::proto::LegacySubmap& submap_in) {
00097 mapping::proto::Submap3D submap_3d;
00098 *submap_3d.mutable_local_pose() = submap_in.submap_3d().local_pose();
00099 submap_3d.set_num_range_data(submap_in.submap_3d().num_range_data());
00100 submap_3d.set_finished(submap_in.submap_3d().finished());
00101 *submap_3d.mutable_high_resolution_hybrid_grid() =
00102 submap_in.submap_3d().high_resolution_hybrid_grid();
00103 *submap_3d.mutable_low_resolution_hybrid_grid() =
00104 submap_in.submap_3d().low_resolution_hybrid_grid();
00105
00106 mapping::proto::Submap submap_out;
00107 *submap_out.mutable_submap_3d() = submap_3d;
00108 *submap_out.mutable_submap_id() = submap_in.submap_id();
00109 return submap_out;
00110 }
00111
00112 bool DeserializeNext(cartographer::io::ProtoStreamReaderInterface* const input,
00113 ProtoMap* proto_map) {
00114 mapping::proto::LegacySerializedData legacy_data;
00115 if (!input->ReadProto(&legacy_data)) return false;
00116
00117 if (legacy_data.has_submap()) {
00118 LOG_FIRST_N(INFO, 1) << "Migrating submap data.";
00119 if (legacy_data.submap().has_submap_2d()) {
00120 CHECK(legacy_data.submap().submap_2d().grid().has_probability_grid_2d() ||
00121 legacy_data.submap().submap_2d().grid().has_tsdf_2d())
00122 << "\nThe legacy data contains a 2D submap, but it's not using the "
00123 "expected grid format. Try to migrate the grid format instead.";
00124 }
00125 auto& output_vector = (*proto_map)[SerializedData::kSubmapFieldNumber];
00126 output_vector.emplace_back();
00127 *output_vector.back().mutable_submap() = legacy_data.submap();
00128 }
00129 if (legacy_data.has_node()) {
00130 LOG_FIRST_N(INFO, 1) << "Migrating node data.";
00131 auto& output_vector = (*proto_map)[SerializedData::kNodeFieldNumber];
00132 output_vector.emplace_back();
00133 *output_vector.back().mutable_node() = legacy_data.node();
00134 }
00135 if (legacy_data.has_trajectory_data()) {
00136 LOG_FIRST_N(INFO, 1) << "Migrating trajectory data.";
00137 auto& output_vector =
00138 (*proto_map)[SerializedData::kTrajectoryDataFieldNumber];
00139 output_vector.emplace_back();
00140 *output_vector.back().mutable_trajectory_data() =
00141 legacy_data.trajectory_data();
00142 }
00143 if (legacy_data.has_imu_data()) {
00144 LOG_FIRST_N(INFO, 1) << "Migrating IMU data.";
00145 auto& output_vector = (*proto_map)[SerializedData::kImuDataFieldNumber];
00146 output_vector.emplace_back();
00147 *output_vector.back().mutable_imu_data() = legacy_data.imu_data();
00148 }
00149 if (legacy_data.has_odometry_data()) {
00150 LOG_FIRST_N(INFO, 1) << "Migrating odometry data.";
00151 auto& output_vector = (*proto_map)[SerializedData::kOdometryData];
00152 output_vector.emplace_back();
00153 *output_vector.back().mutable_odometry_data() = legacy_data.odometry_data();
00154 }
00155 if (legacy_data.has_fixed_frame_pose_data()) {
00156 LOG_FIRST_N(INFO, 1) << "Migrating fixed frame pose data.";
00157 auto& output_vector =
00158 (*proto_map)[SerializedData::kFixedFramePoseDataFieldNumber];
00159 output_vector.emplace_back();
00160 *output_vector.back().mutable_fixed_frame_pose_data() =
00161 legacy_data.fixed_frame_pose_data();
00162 }
00163 if (legacy_data.has_landmark_data()) {
00164 LOG_FIRST_N(INFO, 1) << "Migrating landmark data.";
00165 auto& output_vector =
00166 (*proto_map)[SerializedData::kLandmarkDataFieldNumber];
00167 output_vector.emplace_back();
00168 *output_vector.back().mutable_landmark_data() = legacy_data.landmark_data();
00169 }
00170 return true;
00171 }
00172
00173 bool DeserializeNextAndMigrateGridFormat(
00174 cartographer::io::ProtoStreamReaderInterface* const input,
00175 ProtoMap* proto_map) {
00176 mapping::proto::LegacySerializedDataLegacySubmap legacy_data;
00177 if (!input->ReadProto(&legacy_data)) return false;
00178
00179 if (legacy_data.has_submap()) {
00180 LOG_FIRST_N(INFO, 1) << "Migrating submap data.";
00181 auto& output_vector = (*proto_map)[SerializedData::kSubmapFieldNumber];
00182 output_vector.emplace_back();
00183 if (legacy_data.submap().has_submap_2d()) {
00184 CHECK(legacy_data.submap().submap_2d().has_probability_grid())
00185 << "\nThe legacy data contains a 2D submap, but it has no legacy "
00186 "probability grid that can be migrated to the new grid format.";
00187 *output_vector.back().mutable_submap() =
00188 MigrateLegacySubmap2d(legacy_data.submap());
00189 } else {
00190 *output_vector.back().mutable_submap() =
00191 MigrateLegacySubmap3d(legacy_data.submap());
00192 }
00193 }
00194 if (legacy_data.has_node()) {
00195 LOG_FIRST_N(INFO, 1) << "Migrating node data.";
00196 auto& output_vector = (*proto_map)[SerializedData::kNodeFieldNumber];
00197 output_vector.emplace_back();
00198 *output_vector.back().mutable_node() = legacy_data.node();
00199 }
00200 if (legacy_data.has_trajectory_data()) {
00201 LOG_FIRST_N(INFO, 1) << "Migrating trajectory data.";
00202 auto& output_vector =
00203 (*proto_map)[SerializedData::kTrajectoryDataFieldNumber];
00204 output_vector.emplace_back();
00205 *output_vector.back().mutable_trajectory_data() =
00206 legacy_data.trajectory_data();
00207 }
00208 if (legacy_data.has_imu_data()) {
00209 LOG_FIRST_N(INFO, 1) << "Migrating IMU data.";
00210 auto& output_vector = (*proto_map)[SerializedData::kImuDataFieldNumber];
00211 output_vector.emplace_back();
00212 *output_vector.back().mutable_imu_data() = legacy_data.imu_data();
00213 }
00214 if (legacy_data.has_odometry_data()) {
00215 LOG_FIRST_N(INFO, 1) << "Migrating odometry data.";
00216 auto& output_vector = (*proto_map)[SerializedData::kOdometryData];
00217 output_vector.emplace_back();
00218 *output_vector.back().mutable_odometry_data() = legacy_data.odometry_data();
00219 }
00220 if (legacy_data.has_fixed_frame_pose_data()) {
00221 LOG_FIRST_N(INFO, 1) << "Migrating fixed frame pose data.";
00222 auto& output_vector =
00223 (*proto_map)[SerializedData::kFixedFramePoseDataFieldNumber];
00224 output_vector.emplace_back();
00225 *output_vector.back().mutable_fixed_frame_pose_data() =
00226 legacy_data.fixed_frame_pose_data();
00227 }
00228 if (legacy_data.has_landmark_data()) {
00229 LOG_FIRST_N(INFO, 1) << "Migrating landmark data.";
00230 auto& output_vector =
00231 (*proto_map)[SerializedData::kLandmarkDataFieldNumber];
00232 output_vector.emplace_back();
00233 *output_vector.back().mutable_landmark_data() = legacy_data.landmark_data();
00234 }
00235 return true;
00236 }
00237
00238 ProtoMap ParseLegacyData(
00239 cartographer::io::ProtoStreamReaderInterface* const input,
00240 bool migrate_grid_format) {
00241 ProtoMap proto_map;
00242 CHECK(ReadPoseGraph(input, &proto_map))
00243 << "Input stream seems to differ from original stream format. Could "
00244 "not "
00245 "read PoseGraph as first message.";
00246 CHECK(ReadBuilderOptions(input, &proto_map))
00247 << "Input stream seems to differ from original stream format. Could "
00248 "not "
00249 "read AllTrajectoryBuilderOptions as second message.";
00250 if (migrate_grid_format) {
00251 do {
00252 } while (DeserializeNextAndMigrateGridFormat(input, &proto_map));
00253 } else {
00254 do {
00255 } while (DeserializeNext(input, &proto_map));
00256 }
00257 return proto_map;
00258 }
00259
00260 mapping::proto::SerializationHeader CreateSerializationHeader() {
00261 constexpr uint32_t kVersion1 = 1;
00262 mapping::proto::SerializationHeader header;
00263 header.set_format_version(kVersion1);
00264 return header;
00265 }
00266
00267 void SerializeToVersion1Format(
00268 const ProtoMap& deserialized_data,
00269 cartographer::io::ProtoStreamWriterInterface* const output) {
00270 const std::vector<int> kFieldSerializationOrder = {
00271 SerializedData::kPoseGraphFieldNumber,
00272 SerializedData::kAllTrajectoryBuilderOptionsFieldNumber,
00273 SerializedData::kSubmapFieldNumber,
00274 SerializedData::kNodeFieldNumber,
00275 SerializedData::kTrajectoryDataFieldNumber,
00276 SerializedData::kImuDataFieldNumber,
00277 SerializedData::kOdometryDataFieldNumber,
00278 SerializedData::kFixedFramePoseDataFieldNumber,
00279 SerializedData::kLandmarkDataFieldNumber};
00280
00281 LOG(INFO) << "Writing proto stream.";
00282 output->WriteProto(CreateSerializationHeader());
00283 for (auto field_index : kFieldSerializationOrder) {
00284 const auto proto_vector_it = deserialized_data.find(field_index);
00285 if (proto_vector_it == deserialized_data.end()) continue;
00286 for (const auto& proto : proto_vector_it->second) {
00287 output->WriteProto(proto);
00288 }
00289 }
00290 }
00291 }
00292
00293 void MigrateStreamFormatToVersion1(
00294 cartographer::io::ProtoStreamReaderInterface* const input,
00295 cartographer::io::ProtoStreamWriterInterface* const output,
00296 bool migrate_grid_format) {
00297 SerializeToVersion1Format(ParseLegacyData(input, migrate_grid_format),
00298 output);
00299 }
00300
00301 mapping::MapById<mapping::SubmapId, mapping::proto::Submap>
00302 MigrateSubmapFormatVersion1ToVersion2(
00303 const mapping::MapById<mapping::SubmapId, mapping::proto::Submap>&
00304 submap_id_to_submap,
00305 mapping::MapById<mapping::NodeId, mapping::proto::Node>& node_id_to_node,
00306 const mapping::proto::PoseGraph& pose_graph_proto) {
00307 using namespace mapping;
00308 if (submap_id_to_submap.empty() ||
00309 submap_id_to_submap.begin()->data.has_submap_2d()) {
00310 return submap_id_to_submap;
00311 }
00312
00313 MapById<SubmapId, proto::Submap> migrated_submaps = submap_id_to_submap;
00314 for (const proto::PoseGraph::Constraint& constraint_proto :
00315 pose_graph_proto.constraint()) {
00316 if (constraint_proto.tag() == proto::PoseGraph::Constraint::INTRA_SUBMAP) {
00317 NodeId node_id{constraint_proto.node_id().trajectory_id(),
00318 constraint_proto.node_id().node_index()};
00319 CHECK(node_id_to_node.Contains(node_id));
00320 const TrajectoryNode::Data node_data =
00321 FromProto(node_id_to_node.at(node_id).node_data());
00322 const Eigen::VectorXf& rotational_scan_matcher_histogram_in_gravity =
00323 node_data.rotational_scan_matcher_histogram;
00324
00325 SubmapId submap_id{constraint_proto.submap_id().trajectory_id(),
00326 constraint_proto.submap_id().submap_index()};
00327 CHECK(migrated_submaps.Contains(submap_id));
00328 proto::Submap& migrated_submap_proto = migrated_submaps.at(submap_id);
00329 CHECK(migrated_submap_proto.has_submap_3d());
00330
00331 proto::Submap3D* submap_3d_proto =
00332 migrated_submap_proto.mutable_submap_3d();
00333 const double submap_yaw_from_gravity =
00334 transform::GetYaw(transform::ToRigid3(submap_3d_proto->local_pose())
00335 .inverse()
00336 .rotation() *
00337 node_data.local_pose.rotation() *
00338 node_data.gravity_alignment.inverse());
00339 const Eigen::VectorXf rotational_scan_matcher_histogram_in_submap =
00340 scan_matching::RotationalScanMatcher::RotateHistogram(
00341 rotational_scan_matcher_histogram_in_gravity,
00342 submap_yaw_from_gravity);
00343
00344 if (submap_3d_proto->rotational_scan_matcher_histogram_size() == 0) {
00345 for (Eigen::VectorXf::Index i = 0;
00346 i != rotational_scan_matcher_histogram_in_submap.size(); ++i) {
00347 submap_3d_proto->add_rotational_scan_matcher_histogram(
00348 rotational_scan_matcher_histogram_in_submap(i));
00349 }
00350 } else {
00351 auto submap_histogram =
00352 submap_3d_proto->mutable_rotational_scan_matcher_histogram();
00353 for (Eigen::VectorXf::Index i = 0;
00354 i != rotational_scan_matcher_histogram_in_submap.size(); ++i) {
00355 *submap_histogram->Mutable(i) +=
00356 rotational_scan_matcher_histogram_in_submap(i);
00357 }
00358 }
00359 }
00360 }
00361 return migrated_submaps;
00362 }
00363
00364 }
00365 }