Add cartographer_dev_rosbag_publisher (#854)
This adds a tool to publish a bag file without publishing a simulated clock, modifying header timestamps.master
parent
449a291411
commit
d18365500d
|
@ -102,6 +102,17 @@ install(TARGETS cartographer_pbstream_map_publisher
|
|||
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
)
|
||||
|
||||
google_binary(cartographer_dev_rosbag_publisher
|
||||
SRCS
|
||||
dev/rosbag_publisher_main.cc
|
||||
)
|
||||
|
||||
install(TARGETS cartographer_dev_rosbag_publisher
|
||||
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
)
|
||||
|
||||
google_binary(cartographer_dev_trajectory_comparison
|
||||
SRCS
|
||||
dev/trajectory_comparison_main.cc
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2018 The Cartographer Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "cartographer/common/time.h"
|
||||
#include "cartographer_ros/ros_log_sink.h"
|
||||
#include "cartographer_ros/time_conversion.h"
|
||||
#include "gflags/gflags.h"
|
||||
#include "nav_msgs/Odometry.h"
|
||||
#include "ros/ros.h"
|
||||
#include "ros/time.h"
|
||||
#include "rosbag/bag.h"
|
||||
#include "rosbag/view.h"
|
||||
#include "sensor_msgs/Imu.h"
|
||||
#include "sensor_msgs/LaserScan.h"
|
||||
#include "sensor_msgs/MultiEchoLaserScan.h"
|
||||
#include "sensor_msgs/PointCloud2.h"
|
||||
#include "tf2_msgs/TFMessage.h"
|
||||
|
||||
DEFINE_string(bag_filename, "", "Bag to publish.");
|
||||
|
||||
const int kQueueSize = 1;
|
||||
|
||||
template <typename MessagePtrType>
|
||||
void PublishWithModifiedTimestamp(MessagePtrType message,
|
||||
const ros::Publisher& publisher,
|
||||
ros::Duration bag_to_current) {
|
||||
ros::Time& stamp = message->header.stamp;
|
||||
stamp += bag_to_current;
|
||||
publisher.publish(message);
|
||||
}
|
||||
|
||||
template <>
|
||||
void PublishWithModifiedTimestamp<tf2_msgs::TFMessage::Ptr>(
|
||||
tf2_msgs::TFMessage::Ptr message, const ros::Publisher& publisher,
|
||||
ros::Duration bag_to_current) {
|
||||
for (const auto& transform : message->transforms) {
|
||||
ros::Time& stamp = const_cast<ros::Time&>(transform.header.stamp);
|
||||
stamp += bag_to_current;
|
||||
}
|
||||
publisher.publish(message);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
google::SetUsageMessage(
|
||||
"\n\n"
|
||||
"This replays and publishes messages from a given bag file, modifying "
|
||||
"their header timestamps to match current ROS time.\n\n"
|
||||
"Messages are published in the same sequence and with the same delay "
|
||||
"they were recorded."
|
||||
"Contrary to rosbag play, it does not publish a clock, so time is"
|
||||
"hopefully smoother and it should be possible to reproduce timing"
|
||||
"issues.\n"
|
||||
"It only plays message types related to Cartographer.\n");
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
CHECK(!FLAGS_bag_filename.empty()) << "-bag_filename is missing.";
|
||||
|
||||
ros::init(argc, argv, "rosbag_publisher");
|
||||
ros::start();
|
||||
|
||||
cartographer_ros::ScopedRosLogSink ros_log_sink;
|
||||
|
||||
rosbag::Bag bag;
|
||||
bag.open(FLAGS_bag_filename, rosbag::bagmode::Read);
|
||||
rosbag::View view(bag);
|
||||
ros::NodeHandle node_handle;
|
||||
bool use_sim_time;
|
||||
node_handle.getParam("/use_sim_time", use_sim_time);
|
||||
if (use_sim_time) {
|
||||
LOG(ERROR) << "use_sim_time is true but not supported. Expect conflicting "
|
||||
"ros::Time and message header times or weird behavior.";
|
||||
}
|
||||
std::map<std::string, ros::Publisher> topic_to_publisher;
|
||||
for (const rosbag::ConnectionInfo* c : view.getConnections()) {
|
||||
const std::string& topic = c->topic;
|
||||
if (topic_to_publisher.count(topic) == 0) {
|
||||
ros::AdvertiseOptions options(c->topic, kQueueSize, c->md5sum,
|
||||
c->datatype, c->msg_def);
|
||||
topic_to_publisher[topic] = node_handle.advertise(options);
|
||||
}
|
||||
}
|
||||
ros::Duration(1).sleep();
|
||||
CHECK(ros::ok());
|
||||
|
||||
ros::Time current_start = ros::Time::now();
|
||||
ros::Time bag_start = view.getBeginTime();
|
||||
ros::Duration bag_to_current = current_start - bag_start;
|
||||
for (const rosbag::MessageInstance& message : view) {
|
||||
ros::Duration after_bag_start = message.getTime() - bag_start;
|
||||
if (!::ros::ok()) {
|
||||
break;
|
||||
}
|
||||
ros::Time planned_publish_time = current_start + after_bag_start;
|
||||
ros::Time::sleepUntil(planned_publish_time);
|
||||
|
||||
ros::Publisher& publisher = topic_to_publisher.at(message.getTopic());
|
||||
if (message.isType<sensor_msgs::PointCloud2>()) {
|
||||
PublishWithModifiedTimestamp(
|
||||
message.instantiate<sensor_msgs::PointCloud2>(), publisher,
|
||||
bag_to_current);
|
||||
} else if (message.isType<sensor_msgs::MultiEchoLaserScan>()) {
|
||||
PublishWithModifiedTimestamp(
|
||||
message.instantiate<sensor_msgs::MultiEchoLaserScan>(), publisher,
|
||||
bag_to_current);
|
||||
} else if (message.isType<sensor_msgs::LaserScan>()) {
|
||||
PublishWithModifiedTimestamp(
|
||||
message.instantiate<sensor_msgs::LaserScan>(), publisher,
|
||||
bag_to_current);
|
||||
} else if (message.isType<sensor_msgs::Imu>()) {
|
||||
PublishWithModifiedTimestamp(message.instantiate<sensor_msgs::Imu>(),
|
||||
publisher, bag_to_current);
|
||||
} else if (message.isType<nav_msgs::Odometry>()) {
|
||||
PublishWithModifiedTimestamp(message.instantiate<nav_msgs::Odometry>(),
|
||||
publisher, bag_to_current);
|
||||
} else if (message.isType<tf2_msgs::TFMessage>()) {
|
||||
PublishWithModifiedTimestamp(message.instantiate<tf2_msgs::TFMessage>(),
|
||||
publisher, bag_to_current);
|
||||
} else {
|
||||
LOG(WARNING) << "Skipping message with type " << message.getDataType();
|
||||
}
|
||||
|
||||
ros::Time current_time = ros::Time::now();
|
||||
double simulation_delay = cartographer::common::ToSeconds(
|
||||
cartographer_ros::FromRos(current_time) -
|
||||
cartographer_ros::FromRos(planned_publish_time));
|
||||
if (std::abs(simulation_delay) > 0.001) {
|
||||
LOG(WARNING) << "Playback delayed by " << simulation_delay
|
||||
<< " s. planned_publish_time: " << planned_publish_time
|
||||
<< " current_time: " << current_time;
|
||||
}
|
||||
}
|
||||
bag.close();
|
||||
|
||||
ros::shutdown();
|
||||
}
|
Loading…
Reference in New Issue