Unfrozen trajectories (#710)

Unfrozen trajectories
master
Juraj Oršulić 2018-02-27 21:26:52 +01:00 committed by Christoph Schütte
parent 32542786a8
commit b7d8af834e
9 changed files with 57 additions and 34 deletions

View File

@ -105,10 +105,18 @@ MapBuilderBridge::MapBuilderBridge(
map_builder_(std::move(map_builder)), map_builder_(std::move(map_builder)),
tf_buffer_(tf_buffer) {} tf_buffer_(tf_buffer) {}
void MapBuilderBridge::LoadMap(const std::string& map_filename) { void MapBuilderBridge::LoadState(const std::string& state_filename,
LOG(INFO) << "Loading map '" << map_filename << "'..."; bool load_frozen_state) {
cartographer::io::ProtoStreamReader stream(map_filename); // Check if suffix of the state file is ".pbstream".
map_builder_->LoadMap(&stream); const std::string suffix = ".pbstream";
CHECK_EQ(state_filename.substr(
std::max<int>(state_filename.size() - suffix.size(), 0)),
suffix)
<< "The file containing the state to be loaded must be a "
".pbstream file.";
LOG(INFO) << "Loading saved state '" << state_filename << "'...";
cartographer::io::ProtoStreamReader stream(state_filename);
map_builder_->LoadState(&stream, load_frozen_state);
} }
int MapBuilderBridge::AddTrajectory( int MapBuilderBridge::AddTrajectory(

View File

@ -63,7 +63,7 @@ class MapBuilderBridge {
MapBuilderBridge(const MapBuilderBridge&) = delete; MapBuilderBridge(const MapBuilderBridge&) = delete;
MapBuilderBridge& operator=(const MapBuilderBridge&) = delete; MapBuilderBridge& operator=(const MapBuilderBridge&) = delete;
void LoadMap(const std::string& map_filename); void LoadState(const std::string& state_filename, bool load_frozen_state);
int AddTrajectory( int AddTrajectory(
const std::set< const std::set<
::cartographer::mapping::TrajectoryBuilderInterface::SensorId>& ::cartographer::mapping::TrajectoryBuilderInterface::SensorId>&

View File

@ -657,9 +657,10 @@ void Node::SerializeState(const std::string& filename) {
<< "Could not write state."; << "Could not write state.";
} }
void Node::LoadMap(const std::string& map_filename) { void Node::LoadState(const std::string& state_filename,
const bool load_frozen_state) {
carto::common::MutexLocker lock(&mutex_); carto::common::MutexLocker lock(&mutex_);
map_builder_bridge_.LoadMap(map_filename); map_builder_bridge_.LoadState(state_filename, load_frozen_state);
} }
} // namespace cartographer_ros } // namespace cartographer_ros

View File

@ -108,8 +108,8 @@ class Node {
// Serializes the complete Node state. // Serializes the complete Node state.
void SerializeState(const std::string& filename); void SerializeState(const std::string& filename);
// Loads a persisted state to use as a map. // Loads a serialized SLAM state from a .pbstream file.
void LoadMap(const std::string& map_filename); void LoadState(const std::string& state_filename, bool load_frozen_state);
::ros::NodeHandle* node_handle(); ::ros::NodeHandle* node_handle();

View File

@ -28,12 +28,16 @@ DEFINE_string(configuration_directory, "",
DEFINE_string(configuration_basename, "", DEFINE_string(configuration_basename, "",
"Basename, i.e. not containing any directory prefix, of the " "Basename, i.e. not containing any directory prefix, of the "
"configuration file."); "configuration file.");
DEFINE_string(map_filename, "", "If non-empty, filename of a map to load."); DEFINE_string(load_state_filename, "",
"If non-empty, filename of a .pbstream file to load, containing "
"a saved SLAM state.");
DEFINE_bool(load_frozen_state, true,
"Load the saved state as frozen (non-optimized) trajectories.");
DEFINE_bool( DEFINE_bool(
start_trajectory_with_default_topics, true, start_trajectory_with_default_topics, true,
"Enable to immediately start the first trajectory with default topics."); "Enable to immediately start the first trajectory with default topics.");
DEFINE_string( DEFINE_string(
save_map_filename, "", save_state_filename, "",
"If non-empty, serialize state and write it to disk before shutting down."); "If non-empty, serialize state and write it to disk before shutting down.");
namespace cartographer_ros { namespace cartographer_ros {
@ -52,8 +56,8 @@ void Run() {
cartographer::common::make_unique<cartographer::mapping::MapBuilder>( cartographer::common::make_unique<cartographer::mapping::MapBuilder>(
node_options.map_builder_options); node_options.map_builder_options);
Node node(node_options, std::move(map_builder), &tf_buffer); Node node(node_options, std::move(map_builder), &tf_buffer);
if (!FLAGS_map_filename.empty()) { if (!FLAGS_load_state_filename.empty()) {
node.LoadMap(FLAGS_map_filename); node.LoadState(FLAGS_load_state_filename, FLAGS_load_frozen_state);
} }
if (FLAGS_start_trajectory_with_default_topics) { if (FLAGS_start_trajectory_with_default_topics) {
@ -65,8 +69,8 @@ void Run() {
node.FinishAllTrajectories(); node.FinishAllTrajectories();
node.RunFinalOptimization(); node.RunFinalOptimization();
if (!FLAGS_save_map_filename.empty()) { if (!FLAGS_save_state_filename.empty()) {
node.SerializeState(FLAGS_save_map_filename); node.SerializeState(FLAGS_save_state_filename);
} }
} }

View File

@ -52,8 +52,11 @@ DEFINE_string(urdf_filenames, "",
"static links for the sensor configuration(s)."); "static links for the sensor configuration(s).");
DEFINE_bool(use_bag_transforms, true, DEFINE_bool(use_bag_transforms, true,
"Whether to read, use and republish transforms from bags."); "Whether to read, use and republish transforms from bags.");
DEFINE_string(pbstream_filename, "", DEFINE_string(load_state_filename, "",
"If non-empty, filename of a pbstream to load."); "If non-empty, filename of a .pbstream file to load, containing "
"a saved SLAM state.");
DEFINE_bool(load_frozen_state, true,
"Load the saved state as frozen (non-optimized) trajectories.");
DEFINE_bool(keep_running, false, DEFINE_bool(keep_running, false,
"Keep running the offline node after all messages from the bag " "Keep running the offline node after all messages from the bag "
"have been processed."); "have been processed.");
@ -75,7 +78,8 @@ void RunOfflineNode(const MapBuilderFactory& map_builder_factory) {
<< "-configuration_directory is missing."; << "-configuration_directory is missing.";
CHECK(!FLAGS_configuration_basenames.empty()) CHECK(!FLAGS_configuration_basenames.empty())
<< "-configuration_basenames is missing."; << "-configuration_basenames is missing.";
CHECK(!FLAGS_bag_filenames.empty()) << "-bag_filenames is missing."; CHECK(!(FLAGS_bag_filenames.empty() && FLAGS_load_state_filename.empty()))
<< "-bag_filenames and -load_state_filename cannot both be unspecified.";
const auto bag_filenames = const auto bag_filenames =
cartographer_ros::SplitString(FLAGS_bag_filenames, ','); cartographer_ros::SplitString(FLAGS_bag_filenames, ',');
cartographer_ros::NodeOptions node_options; cartographer_ros::NodeOptions node_options;
@ -95,7 +99,9 @@ void RunOfflineNode(const MapBuilderFactory& map_builder_factory) {
} }
bag_trajectory_options.push_back(current_trajectory_options); bag_trajectory_options.push_back(current_trajectory_options);
} }
CHECK_EQ(bag_trajectory_options.size(), bag_filenames.size()); if (bag_filenames.size() > 0) {
CHECK_EQ(bag_trajectory_options.size(), bag_filenames.size());
}
// Since we preload the transform buffer, we should never have to wait for a // Since we preload the transform buffer, we should never have to wait for a
// transform. When we finish processing the bag, we will simply drop any // transform. When we finish processing the bag, we will simply drop any
@ -122,10 +128,8 @@ void RunOfflineNode(const MapBuilderFactory& map_builder_factory) {
tf_buffer.setUsingDedicatedThread(true); tf_buffer.setUsingDedicatedThread(true);
Node node(node_options, std::move(map_builder), &tf_buffer); Node node(node_options, std::move(map_builder), &tf_buffer);
if (!FLAGS_pbstream_filename.empty()) { if (!FLAGS_load_state_filename.empty()) {
// TODO(jihoonl): LoadMap should be replaced by some better deserialization node.LoadState(FLAGS_load_state_filename, FLAGS_load_frozen_state);
// of full SLAM state as non-frozen trajectories once possible
node.LoadMap(FLAGS_pbstream_filename);
} }
::ros::Publisher tf_publisher = ::ros::Publisher tf_publisher =
@ -308,10 +312,12 @@ void RunOfflineNode(const MapBuilderFactory& map_builder_factory) {
LOG(INFO) << "Peak memory usage: " << usage.ru_maxrss << " KiB"; LOG(INFO) << "Peak memory usage: " << usage.ru_maxrss << " KiB";
#endif #endif
if (::ros::ok()) { if (::ros::ok() && bag_filenames.size() > 0) {
const std::string output_filename = bag_filenames.front() + ".pbstream"; const std::string output_filename = bag_filenames.front();
LOG(INFO) << "Writing state to '" << output_filename << "'..."; const std::string suffix = ".pbstream";
node.SerializeState(output_filename); const std::string state_output_filename = output_filename + suffix;
LOG(INFO) << "Writing state to '" << state_output_filename << "'...";
node.SerializeState(state_output_filename);
} }
if (FLAGS_keep_running) { if (FLAGS_keep_running) {
::ros::waitForShutdown(); ::ros::waitForShutdown();

View File

@ -27,7 +27,7 @@
type="cartographer_node" args=" type="cartographer_node" args="
-configuration_directory $(find cartographer_ros)/configuration_files -configuration_directory $(find cartographer_ros)/configuration_files
-configuration_basename backpack_2d_localization.lua -configuration_basename backpack_2d_localization.lua
-map_filename $(arg map_filename)" -load_state_filename $(arg load_state_filename)"
output="screen"> output="screen">
<remap from="echoes" to="horizontal_laser_2d" /> <remap from="echoes" to="horizontal_laser_2d" />
</node> </node>

View File

@ -30,7 +30,7 @@ Pure localization
roslaunch cartographer_ros offline_backpack_2d.launch bag_filenames:=${HOME}/Downloads/b2-2016-04-05-14-44-52.bag roslaunch cartographer_ros offline_backpack_2d.launch bag_filenames:=${HOME}/Downloads/b2-2016-04-05-14-44-52.bag
# Run pure localization: # Run pure localization:
roslaunch cartographer_ros demo_backpack_2d_localization.launch \ roslaunch cartographer_ros demo_backpack_2d_localization.launch \
map_filename:=${HOME}/Downloads/b2-2016-04-05-14-44-52.bag.pbstream \ load_state_filename:=${HOME}/Downloads/b2-2016-04-05-14-44-52.bag.pbstream \
bag_filename:=${HOME}/Downloads/b2-2016-04-27-12-31-41.bag bag_filename:=${HOME}/Downloads/b2-2016-04-27-12-31-41.bag
# Pure localization demo in 3D: We use 2 different 3D bags from the Deutsche # Pure localization demo in 3D: We use 2 different 3D bags from the Deutsche
@ -42,7 +42,7 @@ Pure localization
roslaunch cartographer_ros offline_backpack_3d.launch bag_filenames:=${HOME}/Downloads/b3-2016-04-05-13-54-42.bag roslaunch cartographer_ros offline_backpack_3d.launch bag_filenames:=${HOME}/Downloads/b3-2016-04-05-13-54-42.bag
# Run pure localization: # Run pure localization:
roslaunch cartographer_ros demo_backpack_3d_localization.launch \ roslaunch cartographer_ros demo_backpack_3d_localization.launch \
map_filename:=${HOME}/Downloads/b3-2016-04-05-13-54-42.bag.pbstream \ load_state_filename:=${HOME}/Downloads/b3-2016-04-05-13-54-42.bag.pbstream \
bag_filename:=${HOME}/Downloads/b3-2016-04-05-15-52-20.bag bag_filename:=${HOME}/Downloads/b3-2016-04-05-15-52-20.bag
Revo LDS Revo LDS

View File

@ -38,10 +38,14 @@ TODO(hrapp): Should these not be removed? It seems duplicated efforts documentin
Basename (i.e. not containing any directory prefix) of the configuration file Basename (i.e. not containing any directory prefix) of the configuration file
(e.g. backpack_3d.lua). (e.g. backpack_3d.lua).
\-\-map_filename \-\-load_state_filename
A Cartographer state file that will be loaded from disk. This allows to A Cartographer .pbstream state file that will be loaded from disk. This allows
add new trajectories SLAMing from an earlier state, but the loaded state is to add new trajectories SLAMing from an earlier state.
frozen.
\-\-load_frozen_state
This boolean parameter controls if the saved state, specified using the option
\-\-load_state_filename, is going to be loaded as a set of frozen (not
optimized) trajectories.
Subscribed Topics Subscribed Topics
----------------- -----------------