4 #include <boost/program_options.hpp> 8 #include <fmt/chrono.h> 15 #include <rosgraph_msgs/Clock.h> 23 namespace po = boost::program_options;
26 int play(
const std::vector<std::string>& options)
32 po::options_description desc(
"Options");
34 (
"help",
"Display this help message")
35 (
"clock",
"Publish clock (requires use_sim_time)")
38 po::options_description hidden(
"Hidden");
40 (
"input", po::value<std::vector<std::string>>()->required(),
"Input file")
43 po::options_description all(
"All");
44 all.add(desc).add(hidden);
46 po::positional_options_description p;
50 std::cout <<
"Usage: rosbag_fancy play [options] <bag file(s)>\n\n";
51 std::cout << desc <<
"\n\n";
57 po::command_line_parser(options).options(all).positional(p).
run(),
71 std::cerr <<
"Could not parse arguments: " << e.what() <<
"\n\n";
77 bool publishClock = vm.count(
"clock");
83 pub_clock =
ros::NodeHandle{}.advertise<rosgraph_msgs::Clock>(
"/clock", 1,
true);
87 explicit Bag(
const std::string&
filename)
92 std::unordered_map<int, ros::Publisher> publishers;
95 std::vector<Bag> bags;
98 std::map<std::string, int> topicMap;
105 for(
auto&
filename : vm[
"input"].as<std::vector<std::string>>())
107 auto& bag = bags.emplace_back(
filename);
109 if(startTime ==
ros::Time(0) || bag.reader.startTime() < startTime)
110 startTime = bag.reader.startTime();
112 if(endTime ==
ros::Time(0) || bag.reader.endTime() > endTime)
113 endTime = bag.reader.endTime();
115 for(
auto& [
id, con] : bag.reader.connections())
121 opts.
topic = con.topicInBag;
122 opts.
latch = con.latching;
128 auto it = topicMap.find(con.topicInBag);
129 if(it == topicMap.end())
131 topicMap[con.topicInBag] = topicManager.
topics().size();
132 topicManager.
addTopic(con.topicInBag);
137 std::vector<BagReader*> bagReaders;
138 for(
auto& bag : bags)
139 bagReaders.push_back(&bag.reader);
147 return connection.topicInBag !=
"/tf_static";
150 for(
auto& bag : bags)
151 view.
addBag(&bag.reader, topicPredicate);
159 std::unique_ptr<PlaybackUI> ui;
165 if(!vm.count(
"no-ui"))
167 ui.reset(
new PlaybackUI{topicManager, startTime, endTime});
169 ui->seekForwardRequested.connect([&](){
173 it = view.findTime(currentTime);
175 ui->seekBackwardRequested.connect([&](){
179 if(currentTime < startTime)
181 currentTime = startTime;
182 bagRefTime = currentTime;
186 it = view.findTime(currentTime);
188 ui->pauseRequested.connect([&](){
190 bagRefTime = currentTime;
193 ui->exitRequested.connect([&](){
207 auto& msg = *it->
msg;
209 if(msg.stamp < bagRefTime)
215 currentTime = msg.stamp;
216 ui->setPositionInBag(msg.stamp);
218 bags[it->
bagIndex].publishers[msg.connection->id].publish(msg);
220 auto& topic = topicManager.
topics()[topicMap[msg.connection->topicInBag]];
221 topic.notifyMessage(msg.size());
225 rosgraph_msgs::Clock msg;
226 msg.clock = currentTime;
228 lastClockPublishTime = wallStamp;
232 if(
auto tfmsg = tf2Scanner.fetchUpdate(currentTime))
245 FD_SET(STDIN_FILENO, &fds);
247 int ret = select(STDIN_FILENO+1, &fds,
nullptr,
nullptr, &timeout);
250 if(errno != EAGAIN && errno != EINTR)
251 throw std::runtime_error{
fmt::format(
"select() error: {}", strerror(errno))};
257 ui->setPaused(paused);
std::string message_definition
void run(class_loader::ClassLoader *loader)
std::vector< Topic > & topics()
int play(const std::vector< std::string > &options)
void addTopic(const std::string &topic, float rateLimit=0.0f, int flags=0)
void publish(const boost::shared_ptr< M > &message) const
static bool sleepUntil(const SteadyTime &end)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const BagReader::Message * msg
void addBag(BagReader *reader)
WallDuration & fromNSec(int64_t t)
ROSCPP_DECL void shutdown()
ROSCPP_DECL void spinOnce()