Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer/common/time.h"
00018 #include "cartographer_ros/ros_log_sink.h"
00019 #include "cartographer_ros/time_conversion.h"
00020 #include "gflags/gflags.h"
00021 #include "nav_msgs/Odometry.h"
00022 #include "ros/ros.h"
00023 #include "ros/time.h"
00024 #include "rosbag/bag.h"
00025 #include "rosbag/view.h"
00026 #include "sensor_msgs/Imu.h"
00027 #include "sensor_msgs/LaserScan.h"
00028 #include "sensor_msgs/MultiEchoLaserScan.h"
00029 #include "sensor_msgs/PointCloud2.h"
00030 #include "tf2_msgs/TFMessage.h"
00031
00032 DEFINE_string(bag_filename, "", "Bag to publish.");
00033
00034 const int kQueueSize = 1;
00035
00036 template <typename MessagePtrType>
00037 void PublishWithModifiedTimestamp(MessagePtrType message,
00038 const ros::Publisher& publisher,
00039 ros::Duration bag_to_current) {
00040 ros::Time& stamp = message->header.stamp;
00041 stamp += bag_to_current;
00042 publisher.publish(message);
00043 }
00044
00045 template <>
00046 void PublishWithModifiedTimestamp<tf2_msgs::TFMessage::Ptr>(
00047 tf2_msgs::TFMessage::Ptr message, const ros::Publisher& publisher,
00048 ros::Duration bag_to_current) {
00049 for (const auto& transform : message->transforms) {
00050 ros::Time& stamp = const_cast<ros::Time&>(transform.header.stamp);
00051 stamp += bag_to_current;
00052 }
00053 publisher.publish(message);
00054 }
00055
00056 int main(int argc, char** argv) {
00057 google::InitGoogleLogging(argv[0]);
00058 google::SetUsageMessage(
00059 "\n\n"
00060 "This replays and publishes messages from a given bag file, modifying "
00061 "their header timestamps to match current ROS time.\n\n"
00062 "Messages are published in the same sequence and with the same delay "
00063 "they were recorded."
00064 "Contrary to rosbag play, it does not publish a clock, so time is"
00065 "hopefully smoother and it should be possible to reproduce timing"
00066 "issues.\n"
00067 "It only plays message types related to Cartographer.\n");
00068 google::ParseCommandLineFlags(&argc, &argv, true);
00069 CHECK(!FLAGS_bag_filename.empty()) << "-bag_filename is missing.";
00070
00071 ros::init(argc, argv, "rosbag_publisher");
00072 ros::start();
00073
00074 cartographer_ros::ScopedRosLogSink ros_log_sink;
00075
00076 rosbag::Bag bag;
00077 bag.open(FLAGS_bag_filename, rosbag::bagmode::Read);
00078 rosbag::View view(bag);
00079 ros::NodeHandle node_handle;
00080 bool use_sim_time;
00081 node_handle.getParam("/use_sim_time", use_sim_time);
00082 if (use_sim_time) {
00083 LOG(ERROR) << "use_sim_time is true but not supported. Expect conflicting "
00084 "ros::Time and message header times or weird behavior.";
00085 }
00086 std::map<std::string, ros::Publisher> topic_to_publisher;
00087 for (const rosbag::ConnectionInfo* c : view.getConnections()) {
00088 const std::string& topic = c->topic;
00089 if (topic_to_publisher.count(topic) == 0) {
00090 ros::AdvertiseOptions options(c->topic, kQueueSize, c->md5sum,
00091 c->datatype, c->msg_def);
00092 topic_to_publisher[topic] = node_handle.advertise(options);
00093 }
00094 }
00095 ros::Duration(1).sleep();
00096 CHECK(ros::ok());
00097
00098 ros::Time current_start = ros::Time::now();
00099 ros::Time bag_start = view.getBeginTime();
00100 ros::Duration bag_to_current = current_start - bag_start;
00101 for (const rosbag::MessageInstance& message : view) {
00102 ros::Duration after_bag_start = message.getTime() - bag_start;
00103 if (!::ros::ok()) {
00104 break;
00105 }
00106 ros::Time planned_publish_time = current_start + after_bag_start;
00107 ros::Time::sleepUntil(planned_publish_time);
00108
00109 ros::Publisher& publisher = topic_to_publisher.at(message.getTopic());
00110 if (message.isType<sensor_msgs::PointCloud2>()) {
00111 PublishWithModifiedTimestamp(
00112 message.instantiate<sensor_msgs::PointCloud2>(), publisher,
00113 bag_to_current);
00114 } else if (message.isType<sensor_msgs::MultiEchoLaserScan>()) {
00115 PublishWithModifiedTimestamp(
00116 message.instantiate<sensor_msgs::MultiEchoLaserScan>(), publisher,
00117 bag_to_current);
00118 } else if (message.isType<sensor_msgs::LaserScan>()) {
00119 PublishWithModifiedTimestamp(
00120 message.instantiate<sensor_msgs::LaserScan>(), publisher,
00121 bag_to_current);
00122 } else if (message.isType<sensor_msgs::Imu>()) {
00123 PublishWithModifiedTimestamp(message.instantiate<sensor_msgs::Imu>(),
00124 publisher, bag_to_current);
00125 } else if (message.isType<nav_msgs::Odometry>()) {
00126 PublishWithModifiedTimestamp(message.instantiate<nav_msgs::Odometry>(),
00127 publisher, bag_to_current);
00128 } else if (message.isType<tf2_msgs::TFMessage>()) {
00129 PublishWithModifiedTimestamp(message.instantiate<tf2_msgs::TFMessage>(),
00130 publisher, bag_to_current);
00131 } else {
00132 LOG(WARNING) << "Skipping message with type " << message.getDataType();
00133 }
00134
00135 ros::Time current_time = ros::Time::now();
00136 double simulation_delay = cartographer::common::ToSeconds(
00137 cartographer_ros::FromRos(current_time) -
00138 cartographer_ros::FromRos(planned_publish_time));
00139 if (std::abs(simulation_delay) > 0.001) {
00140 LOG(WARNING) << "Playback delayed by " << simulation_delay
00141 << " s. planned_publish_time: " << planned_publish_time
00142 << " current_time: " << current_time;
00143 }
00144 }
00145 bag.close();
00146
00147 ros::shutdown();
00148 }