00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "rosrecord/rosplay.h"
00036
00037 #include "sys/select.h"
00038
00039 using namespace std;
00040 using namespace ros;
00041
00042
00043 void print_usage()
00044 {
00045 fprintf (stderr, "Usage: rosplay [options] BAG1 [BAG2]\n");
00046 }
00047
00048
00049 void print_help()
00050 {
00051 print_usage();
00052 fprintf(stderr, " -n\tdisable display of current log time\n");
00053 fprintf(stderr, " -c\tcheck the contents of the bag without playing back\n");
00054 fprintf(stderr, " -a\tplayback all messages without waiting\n");
00055 fprintf(stderr, " -b hz\tpublish the bag time at frequence <hz>\n");
00056 fprintf(stderr, " -p\tstart in paused mode\n");
00057 fprintf(stderr, " -r\tincrease the publish rate ba a factor <rate_change>\n");
00058 fprintf(stderr, " -s sec\tsleep <sec> sleep duration after every advertise call (to allow subscribers to connect)\n");
00059 fprintf(stderr, " -t sec\tstart <sec> seconds into the files\n");
00060 fprintf(stderr, " -q sz\tUse an outgoing queue of size <sz> (defaults to 0)\n");
00061 fprintf(stderr, " -T\tTry to play future version.\n");
00062 fprintf(stderr, " -h\tdisplay this help message\n");
00063 }
00064
00065
00066
00067
00068 RosPlay::RosPlay(int i_argc, char **i_argv) :
00069 node_handle(NULL),
00070 bag_time_initialized_(false),
00071 at_once_(false),
00072 quiet_(false),
00073 paused_(false),
00074 bag_time_(false),
00075 time_scale_(1.0),
00076 queue_size_(0),
00077 bag_time_publisher_(NULL)
00078 {
00079 const int fd = fileno(stdin);
00080
00081 advertise_sleep_ = ros::WallDuration(.2);
00082
00083 termios flags;
00084 tcgetattr(fd,&orig_flags_);
00085 flags = orig_flags_;
00086 flags.c_lflag &= ~ICANON;
00087 flags.c_cc[VMIN] = 0;
00088 flags.c_cc[VTIME] = 0;
00089 tcsetattr(fd,TCSANOW,&flags);
00090
00091 FD_ZERO(&stdin_fdset_);
00092 FD_SET(fd, &stdin_fdset_);
00093 maxfd_ = fd + 1;
00094
00095 char time[1024];
00096 bool has_time = false;
00097 int option_char;
00098
00099 bool try_future = false;
00100
00101 while ((option_char = getopt(i_argc,i_argv,"ncahpb:r:s:t:q:T")) != -1){
00102 switch (option_char){
00103 case 'c': ros::shutdown(); break;
00104 case 'n': quiet_ = true; break;
00105 case 'a': at_once_ = true; break;
00106 case 'p': paused_ = true; break;
00107 case 's': advertise_sleep_ = ros::WallDuration(atof(optarg)); break;
00108 case 't': strncpy(time,optarg,sizeof(time)); has_time=true; break;
00109 case 'q': queue_size_ = atoi(optarg); break;
00110 case 'b': bag_time_frequency_ = atoi(optarg); bag_time_ = true; break;
00111 case 'r': time_scale_ = atof(optarg); break;
00112 case 'T': try_future = true; break;
00113 case 'h': print_help(); ros::shutdown(); return;
00114 case '?': print_usage(); ros::shutdown(); return;
00115 }
00116 }
00117
00118
00119 float float_time = 0.0f;
00120 if (has_time)
00121 float_time = atof(time);
00122
00123 if (optind == i_argc){
00124 fprintf(stderr, "You must specify at least one bagfile to play from.\n");
00125 print_help(); ros::shutdown(); return;
00126 }
00127
00128 std::vector<std::string> bags;
00129 for (int i = optind; i < i_argc; i++)
00130 bags.push_back(i_argv[i]);
00131
00132
00133 if (bag_time_ && bags.size() > 1){
00134 fprintf(stderr, "You can only play one single bag when using bag time [-b].\n");
00135 print_usage(); ros::shutdown(); return;
00136 }
00137
00138 node_handle = new ros::NodeHandle;
00139
00140 if (bag_time_)
00141 bag_time_publisher_ = new SimpleTimePublisher(bag_time_frequency_, time_scale_);
00142 else
00143 bag_time_publisher_ = new SimpleTimePublisher(-1.0, time_scale_);
00144
00145 start_time_ = ros::WallTime::now();
00146 requested_start_time_ = start_time_;
00147
00148
00149 if (player_.open(bags, ros::Time(start_time_.sec, start_time_.nsec) + ros::Duration().fromSec(-float_time / time_scale_), time_scale_, try_future))
00150 player_.addHandler<AnyMsg>(string("*"), &RosPlay::doPublish, this, NULL, false);
00151 else
00152 {
00153
00154
00155 ros::shutdown();
00156 throw std::runtime_error("Failed to open one of the bag files.");
00157 }
00158
00159 bag_time_publisher_->setTime(player_.getFirstTime());
00160
00161 if (!at_once_){
00162 if (paused_){
00163 paused_time_ = ros::WallTime::now();
00164 std::cout << "Hit space to resume, or 's' to step.";
00165 std::cout.flush();
00166 } else {
00167 std::cout << "Hit space to pause.";
00168 std::cout.flush();
00169 }
00170 }
00171 }
00172
00173
00174
00175 RosPlay::~RosPlay()
00176 {
00177 if (node_handle)
00178 {
00179
00180 usleep(1000000);
00181 delete node_handle;
00182 }
00183
00184 if (bag_time_publisher_)
00185 delete bag_time_publisher_;
00186
00187
00188 const int fd = fileno(stdin);
00189 tcsetattr(fd,TCSANOW,&orig_flags_);
00190 }
00191
00192
00193
00194 bool RosPlay::spin()
00195 {
00196 if (node_handle && node_handle->ok()){
00197 if(!quiet_)
00198 puts("");
00199 ros::WallTime last_print_time(0.0);
00200 ros::WallDuration max_print_interval(0.1);
00201 while (node_handle->ok()){
00202 if (!player_.nextMsg())
00203 break;
00204 ros::WallTime t = ros::WallTime::now();
00205 if(!quiet_ && ((t - last_print_time) >= max_print_interval))
00206 {
00207 printf("Time: %16.6f Duration: %16.6f\r",
00208 ros::WallTime::now().toSec(), player_.getDuration().toSec());
00209 fflush(stdout);
00210 last_print_time = t;
00211 }
00212 }
00213 std::cout << std::endl << "Done." << std::endl;
00214
00215 ros::shutdown();
00216 }
00217
00218 return true;
00219 }
00220
00221 std::map<std::string, ros::Publisher> g_publishers;
00222
00223 void RosPlay::doPublish(string topic_name, ros::Message* m, ros::Time _play_time, ros::Time record_time, void* n)
00224 {
00225
00226 ros::WallTime play_time(_play_time.sec, _play_time.nsec);
00227
00228 if (play_time < requested_start_time_)
00229 {
00230 bag_time_publisher_->setTime(record_time);
00231 return;
00232 }
00233
00234
00235 bool latching = false;
00236 std::string callerid("");
00237
00238 if (m->__connection_header != NULL)
00239 {
00240 M_string::iterator latch_iter = m->__connection_header->find(std::string("latching"));
00241 if (latch_iter != m->__connection_header->end())
00242 {
00243 if (latch_iter->second != std::string("0"))
00244 {
00245 latching = true;
00246 }
00247 }
00248
00249 M_string::iterator callerid_iter = m->__connection_header->find(std::string("callerid"));
00250 if (callerid_iter != m->__connection_header->end())
00251 {
00252 callerid = callerid_iter->second;
00253 }
00254 }
00255
00256
00257
00258
00259 std::string name = callerid + topic_name;
00260
00261 std::map<std::string, ros::Publisher>::iterator pub_token = g_publishers.find(name);
00262
00263 bag_time_publisher_->setWCHorizon(play_time);
00264 bag_time_publisher_->setHorizon(record_time);
00265
00266
00267 if (pub_token == g_publishers.end())
00268 {
00269 AdvertiseOptions opts(topic_name, queue_size_, m->__getMD5Sum(), m->__getDataType(), m->__getMessageDefinition());
00270
00271 opts.latch = latching;
00272 ros::Publisher pub = node_handle->advertise(opts);
00273 g_publishers.insert(g_publishers.begin(), std::pair<std::string, ros::Publisher>(name, pub));
00274 pub_token = g_publishers.find(name);
00275
00276
00277
00278
00279 bag_time_publisher_->runStalledClock(advertise_sleep_);
00280
00281
00282
00283 player_.shiftTime(ros::Duration(advertise_sleep_.sec, advertise_sleep_.nsec));
00284 play_time += advertise_sleep_;
00285 bag_time_publisher_->setWCHorizon(play_time);
00286 }
00287
00288 if (!at_once_){
00289 while ( (paused_ || !bag_time_publisher_->horizonReached()) && node_handle->ok()){
00290 bool charsleftorpaused = true;
00291
00292 while (charsleftorpaused && node_handle->ok()){
00293
00294
00295 char c = EOF;
00296
00297 #ifdef __APPLE__
00298
00299 fd_set testfd;
00300 FD_COPY(&stdin_fdset_, &testfd);
00301
00302 #else
00303
00304 fd_set testfd = stdin_fdset_;
00305
00306 #endif
00307
00308 timeval tv;
00309 tv.tv_sec = 0;
00310 tv.tv_usec = 0;
00311
00312 if (select(maxfd_, &testfd, NULL, NULL, &tv) > 0)
00313 c = getc(stdin);
00314
00315 switch (c){
00316 case ' ':
00317 paused_ = !paused_;
00318 if (paused_) {
00319 paused_time_ = ros::WallTime::now();
00320 std::cout << std::endl << "Hit space to resume, or 's' to step.";
00321 std::cout.flush();
00322 } else {
00323
00324 ros::WallDuration shift = ros::WallTime::now() - paused_time_;
00325 paused_time_ = ros::WallTime::now();
00326 player_.shiftTime(ros::Duration(shift.sec, shift.nsec));
00327 play_time += shift;
00328 bag_time_publisher_->setWCHorizon(play_time);
00329
00330 std::cout << std::endl << "Hit space to pause.";
00331 std::cout.flush();
00332 }
00333 break;
00334 case 's':
00335 if (paused_){
00336
00337 bag_time_publisher_->stepClock();
00338 ros::WallDuration shift = ros::WallTime::now() - play_time ;
00339 paused_time_ = ros::WallTime::now();
00340 player_.shiftTime(ros::Duration(shift.sec, shift.nsec));
00341 play_time += shift;
00342 bag_time_publisher_->setWCHorizon(play_time);
00343
00344 (pub_token->second).publish(*m);
00345 return;
00346 }
00347 break;
00348 case EOF:
00349 if (paused_)
00350 bag_time_publisher_->runStalledClock(ros::WallDuration(.01));
00351 else
00352 charsleftorpaused = false;
00353 }
00354 }
00355
00356 bag_time_publisher_->runClock(ros::WallDuration(.01));
00357 }
00358 } else {
00359 bag_time_publisher_->stepClock();
00360 }
00361
00362 (pub_token->second).publish(*m);
00363 }
00364
00365
00366
00367
00368
00369
00370 struct BagContent
00371 {
00372 string datatype;
00373 string md5sum;
00374 string definition;
00375 int count;
00376 BagContent(string d, string m, string def) : datatype(d), md5sum(m), definition(def), count(1) {}
00377 };
00378
00379
00380 map<string, BagContent> g_content;
00381 unsigned long long g_end_time;
00382
00383
00384
00385
00386 void checkFile(string name, ros::Message* m, ros::Time time_play, ros::Time time_recorded, void* n)
00387 {
00388 map<string, BagContent>::iterator i = g_content.find(name);
00389
00390 if (i == g_content.end())
00391 {
00392 g_content.insert(pair<string, BagContent>(name, BagContent(m->__getDataType(), m->__getMD5Sum(), m->__getMessageDefinition())));
00393 } else {
00394 i->second.count++;
00395 }
00396 g_end_time = time_play.toNSec();
00397 }
00398
00399
00400
00401
00402 int main(int argc, char **argv)
00403 {
00404
00405 bool check_bag = false;
00406 bool show_defs = false;
00407
00408 for (int i = 0; i < argc; i++)
00409 {
00410 if (!strcmp(argv[i],"-c") || !strcmp(argv[i],"-cd"))
00411 {
00412 check_bag = true;
00413 }
00414 }
00415
00416 if (check_bag)
00417 {
00418 bool try_future = false;
00419
00420 int option_char;
00421 while ((option_char = getopt(argc,argv,"cdahpt:q:T")) != -1)
00422 switch (option_char)
00423 {
00424 case 'c': break;
00425 case 'd': show_defs = true; break;
00426 case 'a': fprintf(stderr, "Option -a is not valid when checking bag\n"); return 1;
00427 case 'p': fprintf(stderr, "Option -p is not valid when checking bag\n"); return 1;
00428 case 't': fprintf(stderr, "Option -t is not valid when checking bag\n"); return 1;
00429 case 'q': fprintf(stderr, "Option -q is not valid when checking bag\n"); return 1;
00430 case 'T': try_future = true; break;
00431 case 'h': print_help(); return 0;
00432 case '?': print_usage(); return 0;
00433 }
00434
00435 if (argc - optind > 1)
00436 {
00437 fprintf(stderr, "Only 1 bag can be checked at a time\n");
00438 return 1;
00439 }
00440
00441 ros::record::Player player;
00442
00443 if (player.open(argv[optind], ros::Time(), try_future))
00444 {
00445 player.addHandler<AnyMsg>(string("*"), &checkFile, NULL, false);
00446 }
00447
00448 while(player.nextMsg())
00449 {
00450 }
00451
00452 printf("bag: %s\n", argv[optind]);
00453 printf("version: %s\n", player.getVersionString().c_str());
00454 printf("start_time: %lld\n", (long long int)player.getFirstDuration().toNSec());
00455 printf("end_time: %lld\n", g_end_time + player.getFirstDuration().toNSec());
00456 printf("length: %lld\n", g_end_time);
00457 printf("topics:\n");
00458
00459 for (map<string, BagContent>::iterator i = g_content.begin();
00460 i != g_content.end();
00461 i++)
00462 {
00463 printf(" - name: %s\n", i->first.c_str());
00464 printf(" count: %d\n", i->second.count);
00465 printf(" datatype: %s\n", i->second.datatype.c_str());
00466 printf(" md5sum: %s\n", i->second.md5sum.c_str());
00467
00468 if (show_defs)
00469 {
00470 string def = i->second.definition.c_str();
00471
00472 if (def.length() > 0)
00473 {
00474 printf(" definition: |\n");
00475
00476 size_t oldind = 0;
00477 size_t ind = def.find_first_of('\n', 0);
00478
00479 while (ind != def.npos)
00480 {
00481 printf(" %s\n", def.substr(oldind, ind - oldind).c_str());
00482 oldind = ind + 1;
00483 ind = def.find_first_of('\n', oldind);
00484 }
00485
00486 ind = def.length();
00487
00488 printf(" %s\n", def.substr(oldind, ind - oldind).c_str());
00489 } else {
00490 printf(" definition: NONE\n");
00491 }
00492 }
00493
00494 }
00495 return 0;
00496 }
00497
00498 ros::init(argc, argv, "rosplay", ros::init_options::AnonymousName);
00499
00500 ROS_WARN("Rosplay has been deprecated. Please use 'rosbag play' instead\n");
00501
00502 try
00503 {
00504 RosPlay rp(argc, argv);
00505 rp.spin();
00506 }
00507 catch(std::runtime_error& e)
00508 {
00509 ROS_FATAL("%s", e.what());
00510 return 1;
00511 }
00512
00513 return 0;
00514 }