31 #include "cartographer/mapping/proto/pose_graph.pb.h" 32 #include "cartographer/mapping/proto/trajectory_builder_options.pb.h" 41 #include "gflags/gflags.h" 42 #include "glog/logging.h" 48 #include "tf2_msgs/TFMessage.h" 56 namespace carto = ::cartographer;
58 std::unique_ptr<carto::io::PointsProcessorPipelineBuilder>
59 CreatePipelineBuilder(
60 const std::vector<carto::mapping::proto::Trajectory>& trajectories,
61 const std::string file_prefix) {
62 const auto file_writer_factory =
65 carto::common::make_unique<carto::io::PointsProcessorPipelineBuilder>();
66 carto::io::RegisterBuiltInPointsProcessors(trajectories, file_writer_factory,
69 [file_writer_factory](
70 carto::common::LuaParameterDictionary*
const dictionary,
71 carto::io::PointsProcessor*
const next)
72 -> std::unique_ptr<carto::io::PointsProcessor> {
74 file_writer_factory, dictionary, next);
79 std::unique_ptr<carto::common::LuaParameterDictionary> LoadLuaDictionary(
80 const std::string& configuration_directory,
81 const std::string& configuration_basename) {
83 carto::common::make_unique<carto::common::ConfigurationFileResolver>(
84 std::vector<std::string>{configuration_directory});
86 const std::string code =
87 file_resolver->GetFileContentOrDie(configuration_basename);
88 auto lua_parameter_dictionary =
89 carto::common::make_unique<carto::common::LuaParameterDictionary>(
90 code, std::move(file_resolver));
91 return lua_parameter_dictionary;
95 std::unique_ptr<carto::io::PointsBatch> HandleMessage(
96 const T& message,
const std::string& tracking_frame,
98 const carto::transform::TransformInterpolationBuffer&
99 transform_interpolation_buffer) {
100 const carto::common::Time start_time =
FromRos(message.header.stamp);
102 auto points_batch = carto::common::make_unique<carto::io::PointsBatch>();
103 points_batch->start_time = start_time;
104 points_batch->frame_id = message.header.frame_id;
106 carto::sensor::PointCloudWithIntensities point_cloud;
107 carto::common::Time point_cloud_time;
108 std::tie(point_cloud, point_cloud_time) =
110 CHECK_EQ(point_cloud.intensities.size(), point_cloud.points.size());
112 for (
size_t i = 0; i < point_cloud.points.size(); ++i) {
113 const carto::common::Time
time =
114 point_cloud_time + carto::common::FromSeconds(point_cloud.points[i][3]);
115 if (!transform_interpolation_buffer.Has(time)) {
118 const carto::transform::Rigid3d tracking_to_map =
119 transform_interpolation_buffer.Lookup(time);
120 const carto::transform::Rigid3d sensor_to_tracking =
122 tracking_frame, message.header.frame_id,
ToRos(time)));
123 const carto::transform::Rigid3f sensor_to_map =
124 (tracking_to_map * sensor_to_tracking).cast<float>();
125 points_batch->points.push_back(sensor_to_map *
126 point_cloud.points[i].head<3>());
127 points_batch->intensities.push_back(point_cloud.intensities[i]);
129 points_batch->origin = sensor_to_map * Eigen::Vector3f::Zero();
131 if (points_batch->points.empty()) {
140 const std::vector<std::string>& bag_filenames,
141 const std::string& output_file_prefix)
142 : bag_filenames_(bag_filenames),
146 <<
"Pose graphs contains " <<
pose_graph_.trajectory_size()
148 <<
" bags were provided. This tool requires one bag for each " 149 "trajectory in the same order as the correponding trajectories in the " 156 const std::string file_prefix = !output_file_prefix.empty()
164 const std::string& name,
170 const std::string& configuration_basename,
171 const std::string& urdf_filename,
172 const bool use_bag_transforms) {
173 const auto lua_parameter_dictionary =
174 LoadLuaDictionary(configuration_directory, configuration_basename);
176 std::vector<std::unique_ptr<carto::io::PointsProcessor>> pipeline =
178 lua_parameter_dictionary->GetDictionary(
"pipeline").get());
179 const std::string tracking_frame =
180 lua_parameter_dictionary->GetString(
"tracking_frame");
183 for (
size_t trajectory_id = 0; trajectory_id <
bag_filenames_.size();
185 const carto::mapping::proto::Trajectory& trajectory_proto =
188 LOG(INFO) <<
"Processing " << bag_filename <<
"...";
189 if (trajectory_proto.node_size() == 0) {
193 if (!urdf_filename.empty()) {
197 const carto::transform::TransformInterpolationBuffer
198 transform_interpolation_buffer(trajectory_proto);
203 const double duration_in_seconds =
209 std::deque<rosbag::MessageInstance> delayed_messages;
213 const ::ros::Duration
kDelay(1.);
215 if (use_bag_transforms && message.isType<tf2_msgs::TFMessage>()) {
216 auto tf_message = message.instantiate<tf2_msgs::TFMessage>();
217 for (
const auto& transform : tf_message->transforms) {
222 LOG(WARNING) << ex.what();
227 while (!delayed_messages.empty() && delayed_messages.front().getTime() <
228 message.getTime() -
kDelay) {
230 delayed_messages.front();
232 std::unique_ptr<carto::io::PointsBatch> points_batch;
233 if (delayed_message.
isType<sensor_msgs::PointCloud2>()) {
234 points_batch = HandleMessage(
235 *delayed_message.
instantiate<sensor_msgs::PointCloud2>(),
236 tracking_frame, tf_buffer, transform_interpolation_buffer);
237 }
else if (delayed_message
238 .isType<sensor_msgs::MultiEchoLaserScan>()) {
239 points_batch = HandleMessage(
240 *delayed_message.
instantiate<sensor_msgs::MultiEchoLaserScan>(),
241 tracking_frame, tf_buffer, transform_interpolation_buffer);
242 }
else if (delayed_message.
isType<sensor_msgs::LaserScan>()) {
243 points_batch = HandleMessage(
244 *delayed_message.
instantiate<sensor_msgs::LaserScan>(),
245 tracking_frame, tf_buffer, transform_interpolation_buffer);
247 if (points_batch !=
nullptr) {
248 points_batch->trajectory_id = trajectory_id;
249 pipeline.back()->Process(std::move(points_batch));
251 delayed_messages.pop_front();
253 delayed_messages.push_back(message);
254 LOG_EVERY_N(INFO, 100000)
255 <<
"Processed " << (message.getTime() - begin_time).toSec()
256 <<
" of " << duration_in_seconds <<
" bag time seconds...";
260 }
while (pipeline.back()->Flush() ==
261 carto::io::PointsProcessor::FlushResult::kRestartStream);
265 const std::string& file_path) {
266 const auto file_writer_factory = [file_path](
const std::string&
filename) {
267 return carto::common::make_unique<carto::io::StreamFileWriter>(file_path +
270 return file_writer_factory;
void Run(const std::string &configuration_directory, const std::string &configuration_basename, const std::string &urdf_filename, bool use_bag_transforms)
std::function< std::unique_ptr< PointsProcessor >(common::LuaParameterDictionary *, PointsProcessor *next)> FactoryFunction
std::function< std::unique_ptr< FileWriter >(const std::string &filename)> FileWriterFactory
::cartographer::io::FileWriterFactory CreateFileWriterFactory(const std::string &file_path)
const ::ros::Duration kDelay
void open(std::string const &filename, uint32_t mode=bagmode::Read)
AssetsWriter(const std::string &pose_graph_filename, const std::vector< std::string > &bag_filenames, const std::string &output_file_prefix)
bool setTransform(const geometry_msgs::TransformStamped &transform, const std::string &authority, bool is_static=false)
Rigid3d ToRigid3d(const geometry_msgs::TransformStamped &transform)
std::vector<::cartographer::mapping::proto::Trajectory > all_trajectories_
constexpr char kTfStaticTopic[]
static std::unique_ptr< RosMapWritingPointsProcessor > FromDictionary(::cartographer::io::FileWriterFactory file_writer_factory, ::cartographer::common::LuaParameterDictionary *dictionary, PointsProcessor *next)
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
std::vector< std::string > bag_filenames_
std::unique_ptr<::cartographer::io::PointsProcessorPipelineBuilder > point_pipeline_builder_
void RegisterPointsProcessor(const std::string &name, cartographer::io::PointsProcessorPipelineBuilder::FactoryFunction factory)
boost::shared_ptr< T > instantiate() const
::cartographer::mapping::proto::PoseGraph pose_graph_
mapping::proto::PoseGraph DeserializePoseGraphFromFile(const std::string &file_name)
::cartographer::common::Time FromRos(const ::ros::Time &time)
PoseGraph *const pose_graph_
std::tuple<::cartographer::sensor::PointCloudWithIntensities, ::cartographer::common::Time > ToPointCloudWithIntensities(const sensor_msgs::LaserScan &msg)
::ros::Time ToRos(::cartographer::common::Time time)
tf2_ros::Buffer * tf_buffer
static constexpr const char * kConfigurationFileActionName
std::vector< geometry_msgs::TransformStamped > ReadStaticTransformsFromUrdf(const std::string &urdf_filename, tf2_ros::Buffer *const tf_buffer)