30 #include "gflags/gflags.h" 34 #include "rosgraph_msgs/Clock.h" 35 #include "tf2_msgs/TFMessage.h" 40 "First directory in which configuration files are searched, " 41 "second is always the Cartographer installation to allow " 42 "including files from there.");
44 "Basename, i.e. not containing any directory prefix, of the " 45 "configuration file.");
46 DEFINE_string(bag_filenames,
"",
"Comma-separated list of bags to process.");
49 "URDF file that contains static links for your sensor configuration.");
51 "Whether to read, use and republish the transforms from the bag.");
56 constexpr
char kClockTopic[] =
"clock";
57 constexpr
char kTfStaticTopic[] =
"/tf_static";
58 constexpr
char kTfTopic[] =
"tf";
59 constexpr
int kLatestOnlyPublisherQueueSize = 1;
61 volatile std::sig_atomic_t sigint_triggered = 0;
63 void SigintHandler(
int) { sigint_triggered = 1; }
65 std::vector<string> SplitString(
const string& input,
const char delimiter) {
66 std::stringstream stream(input);
68 std::vector<string> tokens;
69 while (std::getline(stream, token, delimiter)) {
70 tokens.push_back(token);
77 std::tuple<NodeOptions, TrajectoryOptions> LoadOptions() {
80 std::vector<string>{FLAGS_configuration_directory});
84 code, std::move(file_resolver));
90 void Run(
const std::vector<string>& bag_filenames) {
91 NodeOptions node_options;
92 TrajectoryOptions trajectory_options;
93 std::tie(node_options, trajectory_options) = LoadOptions();
97 std::vector<geometry_msgs::TransformStamped> urdf_transforms;
98 if (!FLAGS_urdf_filename.empty()) {
108 node_options.lookup_transform_timeout_sec = 0.;
109 Node node(node_options, &tf_buffer);
111 std::unordered_set<string> expected_sensor_ids;
112 const auto check_insert = [&expected_sensor_ids, &node](
const string& topic) {
113 CHECK(expected_sensor_ids.insert(node.node_handle()->resolveName(topic))
118 if (trajectory_options.use_laser_scan) {
121 if (trajectory_options.use_multi_echo_laser_scan) {
126 if (trajectory_options.num_point_clouds > 0) {
127 for (
int i = 0; i < trajectory_options.num_point_clouds; ++i) {
130 if (trajectory_options.num_point_clouds > 1) {
131 topic +=
"_" + std::to_string(i + 1);
139 if (node_options.map_builder_options.use_trajectory_builder_3d() ||
140 (node_options.map_builder_options.use_trajectory_builder_2d() &&
141 trajectory_options.trajectory_builder_options
142 .trajectory_builder_2d_options()
148 if (trajectory_options.use_odometry) {
153 node.node_handle()->advertise<tf2_msgs::TFMessage>(
154 kTfTopic, kLatestOnlyPublisherQueueSize);
159 node.node_handle()->advertise<rosgraph_msgs::Clock>(
160 kClockTopic, kLatestOnlyPublisherQueueSize);
162 if (urdf_transforms.size() > 0) {
163 static_tf_broadcaster.sendTransform(urdf_transforms);
166 for (
const string& bag_filename : bag_filenames) {
167 if (sigint_triggered) {
171 const int trajectory_id = node.map_builder_bridge()->AddTrajectory(
172 expected_sensor_ids, trajectory_options);
177 const ::ros::Time begin_time = view.getBeginTime();
178 const double duration_in_seconds = (view.getEndTime() - begin_time).toSec();
183 std::deque<rosbag::MessageInstance> delayed_messages;
185 if (sigint_triggered) {
189 if (FLAGS_use_bag_transforms && msg.isType<tf2_msgs::TFMessage>()) {
190 auto tf_message = msg.instantiate<tf2_msgs::TFMessage>();
191 tf_publisher.
publish(tf_message);
193 for (
const auto& transform : tf_message->transforms) {
196 msg.getTopic() == kTfStaticTopic);
198 LOG(WARNING) << ex.what();
203 while (!delayed_messages.empty() &&
204 delayed_messages.front().getTime() <
207 const string topic = node.node_handle()->resolveName(
209 if (delayed_msg.
isType<sensor_msgs::LaserScan>()) {
210 node.map_builder_bridge()
211 ->sensor_bridge(trajectory_id)
212 ->HandleLaserScanMessage(
213 topic, delayed_msg.
instantiate<sensor_msgs::LaserScan>());
215 if (delayed_msg.
isType<sensor_msgs::MultiEchoLaserScan>()) {
216 node.map_builder_bridge()
217 ->sensor_bridge(trajectory_id)
218 ->HandleMultiEchoLaserScanMessage(
220 delayed_msg.
instantiate<sensor_msgs::MultiEchoLaserScan>());
222 if (delayed_msg.
isType<sensor_msgs::PointCloud2>()) {
223 node.map_builder_bridge()
224 ->sensor_bridge(trajectory_id)
225 ->HandlePointCloud2Message(
226 topic, delayed_msg.
instantiate<sensor_msgs::PointCloud2>());
228 if (delayed_msg.
isType<sensor_msgs::Imu>()) {
229 node.map_builder_bridge()
230 ->sensor_bridge(trajectory_id)
231 ->HandleImuMessage(topic,
234 if (delayed_msg.
isType<nav_msgs::Odometry>()) {
235 node.map_builder_bridge()
236 ->sensor_bridge(trajectory_id)
237 ->HandleOdometryMessage(
238 topic, delayed_msg.
instantiate<nav_msgs::Odometry>());
240 rosgraph_msgs::Clock clock;
241 clock.clock = delayed_msg.
getTime();
242 clock_publisher.
publish(clock);
246 LOG_EVERY_N(INFO, 100000)
247 <<
"Processed " << (delayed_msg.
getTime() - begin_time).toSec() <<
" of " 248 << duration_in_seconds <<
" bag time seconds...";
250 delayed_messages.pop_front();
254 node.node_handle()->resolveName(msg.getTopic(),
false );
255 if (expected_sensor_ids.count(topic) == 0) {
258 delayed_messages.push_back(msg);
263 node.map_builder_bridge()->FinishTrajectory(trajectory_id);
266 node.map_builder_bridge()->SerializeState(bag_filenames.front());
267 node.map_builder_bridge()->WriteAssets(bag_filenames.front());
273 int main(
int argc,
char** argv) {
274 google::InitGoogleLogging(argv[0]);
275 google::ParseCommandLineFlags(&argc, &argv,
true);
277 CHECK(!FLAGS_configuration_directory.empty())
278 <<
"-configuration_directory is missing.";
279 CHECK(!FLAGS_configuration_basename.empty())
280 <<
"-configuration_basename is missing.";
281 CHECK(!FLAGS_bag_filenames.empty()) <<
"-bag_filenames is missing.";
283 std::signal(SIGINT, &::cartographer_ros::SigintHandler);
284 ::ros::init(argc, argv,
"cartographer_offline_node",
289 cartographer_ros::Run(
290 cartographer_ros::SplitString(FLAGS_bag_filenames,
','));
DEFINE_bool(use_bag_transforms, true,"Whether to read, use and republish the transforms from the bag.")
void publish(const boost::shared_ptr< M > &message) const
void setUsingDedicatedThread(bool value)
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)
constexpr char kImuTopic[]
constexpr char kLaserScanTopic[]
ros::Time const & getTime() const
int main(int argc, char **argv)
boost::shared_ptr< T > instantiate() const
NodeOptions CreateNodeOptions(::cartographer::common::LuaParameterDictionary *const lua_parameter_dictionary)
constexpr char kOdometryTopic[]
DEFINE_string(configuration_directory,"","First directory in which configuration files are searched, ""second is always the Cartographer installation to allow ""including files from there.")
TrajectoryOptions CreateTrajectoryOptions(::cartographer::common::LuaParameterDictionary *const lua_parameter_dictionary)
constexpr char kMultiEchoLaserScanTopic[]
std::string const & getTopic() const
constexpr char kPointCloud2Topic[]
string GetFileContentOrDie(const string &basename) override
tf2_ros::Buffer * tf_buffer
_Unique_if< T >::_Single_object make_unique(Args &&...args)
std::vector< geometry_msgs::TransformStamped > ReadStaticTransformsFromUrdf(const string &urdf_filename, tf2_ros::Buffer *const tf_buffer)