trajectory_comparison_main.cc
Go to the documentation of this file.
00001 /*
00002  * Copyright 2018 The Cartographer Authors
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *      http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <algorithm>
00018 #include <fstream>
00019 #include <iostream>
00020 #include <string>
00021 #include <vector>
00022 
00023 #include "cartographer/common/math.h"
00024 #include "cartographer/io/proto_stream_deserializer.h"
00025 #include "cartographer/mapping/proto/pose_graph.pb.h"
00026 #include "cartographer/transform/transform_interpolation_buffer.h"
00027 #include "cartographer_ros/msg_conversion.h"
00028 #include "cartographer_ros/time_conversion.h"
00029 #include "gflags/gflags.h"
00030 #include "glog/logging.h"
00031 #include "ros/ros.h"
00032 #include "ros/time.h"
00033 #include "rosbag/bag.h"
00034 #include "rosbag/view.h"
00035 #include "tf2_eigen/tf2_eigen.h"
00036 #include "tf2_msgs/TFMessage.h"
00037 
00038 DEFINE_string(bag_filename, "",
00039               "Bag file containing TF messages of the trajectory that will be "
00040               "compared against the trajectory in the .pbstream file.");
00041 DEFINE_string(tf_parent_frame, "map",
00042               "The parent frame ID of the TF trajectory from the bag file.");
00043 DEFINE_string(tf_child_frame, "base_link",
00044               "The child frame ID of the TF trajectory from the bag file.");
00045 DEFINE_string(pbstream_filename, "",
00046               "Proto stream file containing the pose graph. The last "
00047               "trajectory will be used for comparison.");
00048 
00049 namespace cartographer_ros {
00050 namespace {
00051 
00052 double FractionSmallerThan(const std::vector<double>& v, double x) {
00053   return static_cast<double>(std::count_if(
00054              v.begin(), v.end(), [=](double value) { return value < x; })) /
00055          v.size();
00056 }
00057 
00058 std::string QuantilesToString(std::vector<double>* v) {
00059   if (v->empty()) return "(empty vector)";
00060   std::sort(v->begin(), v->end());
00061   std::stringstream result;
00062   const int kNumQuantiles = 10;
00063   for (int i = 0; i < kNumQuantiles; ++i) {
00064     auto value = v->at(v->size() * i / kNumQuantiles);
00065     auto percentage = 100 * i / kNumQuantiles;
00066     result << percentage << "%: " << value << "\n";
00067   }
00068   result << "100%: " << v->back() << "\n";
00069   return result.str();
00070 }
00071 
00072 void Run(const std::string& pbstream_filename,
00073          const std::string& bag_filename) {
00074   cartographer::mapping::proto::PoseGraph pose_graph_proto =
00075       cartographer::io::DeserializePoseGraphFromFile(pbstream_filename);
00076   const cartographer::mapping::proto::Trajectory& last_trajectory_proto =
00077       *pose_graph_proto.mutable_trajectory()->rbegin();
00078   const cartographer::transform::TransformInterpolationBuffer
00079       transform_interpolation_buffer(last_trajectory_proto);
00080 
00081   rosbag::Bag bag;
00082   bag.open(bag_filename, rosbag::bagmode::Read);
00083   rosbag::View view(bag);
00084   std::vector<double> deviation_translation, deviation_rotation;
00085   const double signal_maximum = std::numeric_limits<double>::max();
00086   for (const rosbag::MessageInstance& message : view) {
00087     if (!message.isType<tf2_msgs::TFMessage>()) {
00088       continue;
00089     }
00090     auto tf_message = message.instantiate<tf2_msgs::TFMessage>();
00091     for (const auto& transform : tf_message->transforms) {
00092       if (transform.header.frame_id != FLAGS_tf_parent_frame ||
00093           transform.child_frame_id != FLAGS_tf_child_frame) {
00094         continue;
00095       }
00096       const cartographer::common::Time transform_time =
00097           FromRos(message.getTime());
00098       if (!transform_interpolation_buffer.Has(transform_time)) {
00099         deviation_translation.push_back(signal_maximum);
00100         deviation_rotation.push_back(signal_maximum);
00101         continue;
00102       }
00103       auto optimized_transform =
00104           transform_interpolation_buffer.Lookup(transform_time);
00105       auto published_transform = ToRigid3d(transform);
00106       deviation_translation.push_back((published_transform.translation() -
00107                                        optimized_transform.translation())
00108                                           .norm());
00109       deviation_rotation.push_back(
00110           published_transform.rotation().angularDistance(
00111               optimized_transform.rotation()));
00112     }
00113   }
00114   bag.close();
00115   LOG(INFO) << "Distribution of translation difference:\n"
00116             << QuantilesToString(&deviation_translation);
00117   LOG(INFO) << "Distribution of rotation difference:\n"
00118             << QuantilesToString(&deviation_rotation);
00119   LOG(INFO) << "Fraction of translation difference smaller than 1m: "
00120             << FractionSmallerThan(deviation_translation, 1);
00121   LOG(INFO) << "Fraction of translation difference smaller than 0.1m: "
00122             << FractionSmallerThan(deviation_translation, 0.1);
00123   LOG(INFO) << "Fraction of translation difference smaller than 0.05m: "
00124             << FractionSmallerThan(deviation_translation, 0.05);
00125   LOG(INFO) << "Fraction of translation difference smaller than 0.01m: "
00126             << FractionSmallerThan(deviation_translation, 0.01);
00127 }
00128 
00129 }  // namespace
00130 }  // namespace cartographer_ros
00131 
00132 int main(int argc, char** argv) {
00133   FLAGS_alsologtostderr = true;
00134   google::InitGoogleLogging(argv[0]);
00135   google::SetUsageMessage(
00136       "\n\n"
00137       "This compares a trajectory from a bag file against the "
00138       "last trajectory in a pbstream file.\n");
00139   google::ParseCommandLineFlags(&argc, &argv, true);
00140   CHECK(!FLAGS_bag_filename.empty()) << "-bag_filename is missing.";
00141   CHECK(!FLAGS_pbstream_filename.empty()) << "-pbstream_filename is missing.";
00142   ::cartographer_ros::Run(FLAGS_pbstream_filename, FLAGS_bag_filename);
00143 }


cartographer_ros
Author(s): The Cartographer Authors
autogenerated on Wed Jul 10 2019 04:10:28