29 #include "cartographer/mapping/proto/sparse_pose_graph.pb.h" 36 #include "gflags/gflags.h" 37 #include "glog/logging.h" 43 #include "tf2_msgs/TFMessage.h" 48 "First directory in which configuration files are searched, " 49 "second is always the Cartographer installation to allow " 50 "including files from there.");
52 "Basename, i.e. not containing any directory prefix, of the " 53 "configuration file.");
56 "URDF file that contains static links for your sensor configuration.");
59 pose_graph_filename,
"",
60 "Proto containing the pose graph written by /write_assets service.");
62 "Whether to read and use the transforms from the bag.");
67 constexpr
char kTfStaticTopic[] =
"/tf_static";
68 namespace carto = ::cartographer;
73 void ReadTransformsFromBag(
const string& bag_filename,
79 const ::ros::Time begin_time = view.getBeginTime();
80 const double duration_in_seconds = (view.getEndTime() - begin_time).toSec();
82 if (msg.isType<tf2_msgs::TFMessage>()) {
83 const auto tf_msg = msg.instantiate<tf2_msgs::TFMessage>();
84 for (
const auto& transform : tf_msg->transforms) {
88 msg.getTopic() == kTfStaticTopic);
90 LOG(WARNING) << ex.what();
94 LOG_EVERY_N(INFO, 100000)
95 <<
"Processed " << (msg.getTime() - begin_time).toSec() <<
" of " 96 << duration_in_seconds <<
" bag time seconds...";
102 template <
typename T>
104 const T& message,
const string& tracking_frame,
106 const carto::transform::TransformInterpolationBuffer&
107 transform_interpolation_buffer,
108 const std::vector<std::unique_ptr<carto::io::PointsProcessor>>& pipeline) {
109 const carto::common::Time
time =
FromRos(message.header.stamp);
110 if (!transform_interpolation_buffer.Has(time)) {
114 const carto::transform::Rigid3d tracking_to_map =
115 transform_interpolation_buffer.Lookup(time);
116 const carto::transform::Rigid3d sensor_to_tracking =
118 tracking_frame, message.header.frame_id, message.header.stamp));
119 const carto::transform::Rigid3f sensor_to_map =
120 (tracking_to_map * sensor_to_tracking).cast<float>();
122 auto batch = carto::common::make_unique<carto::io::PointsBatch>();
124 batch->origin = sensor_to_map * Eigen::Vector3f::Zero();
125 batch->frame_id = message.header.frame_id;
127 carto::sensor::PointCloudWithIntensities point_cloud =
129 CHECK(point_cloud.intensities.size() == point_cloud.points.size());
131 for (
size_t i = 0; i < point_cloud.points.size(); ++i) {
132 batch->points.push_back(sensor_to_map * point_cloud.points[i]);
133 batch->intensities.push_back(point_cloud.intensities[i]);
135 pipeline.back()->Process(std::move(batch));
138 void Run(
const string& pose_graph_filename,
const string& bag_filename,
139 const string& configuration_directory,
140 const string& configuration_basename,
const string& urdf_filename) {
142 carto::common::make_unique<carto::common::ConfigurationFileResolver>(
143 std::vector<string>{configuration_directory});
145 file_resolver->GetFileContentOrDie(configuration_basename);
146 carto::common::LuaParameterDictionary lua_parameter_dictionary(
147 code, std::move(file_resolver));
149 std::ifstream stream(pose_graph_filename.c_str());
150 carto::mapping::proto::SparsePoseGraph pose_graph_proto;
151 CHECK(pose_graph_proto.ParseFromIstream(&stream));
152 CHECK_EQ(pose_graph_proto.trajectory_size(), 1)
153 <<
"Only pose graphs containing a single trajectory are supported.";
154 const carto::mapping::proto::Trajectory& trajectory_proto =
155 pose_graph_proto.trajectory(0);
156 CHECK_GT(trajectory_proto.node_size(), 0)
157 <<
"Trajectory does not contain any nodes.";
159 const auto file_writer_factory = [](
const string&
filename) {
160 return carto::common::make_unique<carto::io::StreamFileWriter>(
filename);
163 carto::io::PointsProcessorPipelineBuilder builder;
164 carto::io::RegisterBuiltInPointsProcessors(trajectory_proto,
165 file_writer_factory, &builder);
166 std::vector<std::unique_ptr<carto::io::PointsProcessor>> pipeline =
167 builder.CreatePipeline(
168 lua_parameter_dictionary.GetDictionary(
"pipeline").get());
172 if (FLAGS_use_bag_transforms) {
173 LOG(INFO) <<
"Pre-loading transforms from bag...";
174 ReadTransformsFromBag(bag_filename, &tf_buffer);
177 if (!urdf_filename.empty()) {
181 const string tracking_frame =
182 lua_parameter_dictionary.GetString(
"tracking_frame");
183 const auto transform_interpolation_buffer =
184 carto::transform::TransformInterpolationBuffer::FromTrajectory(
186 LOG(INFO) <<
"Processing pipeline...";
191 const ::ros::Time begin_time = view.getBeginTime();
192 const double duration_in_seconds = (view.getEndTime() - begin_time).toSec();
195 if (message.isType<sensor_msgs::PointCloud2>()) {
196 HandleMessage(*message.instantiate<sensor_msgs::PointCloud2>(),
197 tracking_frame, tf_buffer,
198 *transform_interpolation_buffer, pipeline);
200 if (message.isType<sensor_msgs::MultiEchoLaserScan>()) {
201 HandleMessage(*message.instantiate<sensor_msgs::MultiEchoLaserScan>(),
202 tracking_frame, tf_buffer,
203 *transform_interpolation_buffer, pipeline);
205 if (message.isType<sensor_msgs::LaserScan>()) {
206 HandleMessage(*message.instantiate<sensor_msgs::LaserScan>(),
207 tracking_frame, tf_buffer,
208 *transform_interpolation_buffer, pipeline);
210 LOG_EVERY_N(INFO, 100000)
211 <<
"Processed " << (message.getTime() - begin_time).toSec() <<
" of " 212 << duration_in_seconds <<
" bag time seconds...";
215 }
while (pipeline.back()->Flush() ==
216 carto::io::PointsProcessor::FlushResult::kRestartStream);
222 int main(
int argc,
char** argv) {
223 FLAGS_alsologtostderr =
true;
224 google::InitGoogleLogging(argv[0]);
225 google::ParseCommandLineFlags(&argc, &argv,
true);
227 CHECK(!FLAGS_configuration_directory.empty())
228 <<
"-configuration_directory is missing.";
229 CHECK(!FLAGS_configuration_basename.empty())
230 <<
"-configuration_basename is missing.";
231 CHECK(!FLAGS_bag_filename.empty()) <<
"-bag_filename is missing.";
232 CHECK(!FLAGS_pose_graph_filename.empty())
233 <<
"-pose_graph_filename is missing.";
235 ::cartographer_ros::Run(FLAGS_pose_graph_filename, FLAGS_bag_filename,
236 FLAGS_configuration_directory,
237 FLAGS_configuration_basename, FLAGS_urdf_filename);
void open(std::string const &filename, uint32_t mode=bagmode::Read)
bool setTransform(const geometry_msgs::TransformStamped &transform, const std::string &authority, bool is_static=false)
Rigid3d ToRigid3d(const geometry_msgs::TransformStamped &transform)
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
DEFINE_string(configuration_directory,"","First directory in which configuration files are searched, ""second is always the Cartographer installation to allow ""including files from there.")
int main(int argc, char **argv)
PointCloudWithIntensities ToPointCloudWithIntensities(const sensor_msgs::LaserScan &msg)
DEFINE_bool(use_bag_transforms, true,"Whether to read and use the transforms from the bag.")
::cartographer::common::Time FromRos(const ::ros::Time &time)
void Run(const std::string &configuration_directory, const std::string &configuration_basename)
ROSTIME_DECL const Duration DURATION_MAX
std::vector< geometry_msgs::TransformStamped > ReadStaticTransformsFromUrdf(const string &urdf_filename, tf2_ros::Buffer *const tf_buffer)