!
Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. |
Reading data from (any) Rosbag.
Description: Describes how to open any rosbag and extract data even if the stored topic are not known at compilation time.Keywords: introspection, rosbag
Tutorial Level: BEGINNER
Next Tutorial: Subscribe to any topic and deserialize its content. Generic Topic Subscriber
When you open a rosbag, DataType and Definition can be accessed through rosbag::ConnectionInfo.
This allows us to deserialize the type-erased ROS containers: rosbag::MessageInstance; all the information we need is stored in the rosbag itself.
1 #include "ros_type_introspection/ros_introspection.hpp"
2 #include <ros/ros.h>
3 #include <rosbag/bag.h>
4 #include <rosbag/view.h>
5
6 using namespace RosIntrospection;
7
8 // usage: pass the name of the file as command line argument
9 int main(int argc, char** argv)
10 {
11 if( argc != 2 ){
12 printf("Usage: pass the name of a file as first argument\n");
13 return 1;
14 }
15
16 Parser parser;
17 rosbag::Bag bag;
18
19 try{
20 bag.open( argv[1] );
21 }
22 catch( rosbag::BagException& ex)
23 {
24 printf("rosbag::open thrown an exception: %s\n", ex.what());
25 return -1;
26 }
27 // this rosbag::View will accept ALL the messages (no filter)
28 rosbag::View bag_view ( bag );
29
30 // register (only once at the beginning) the type of messages
31 for(const rosbag::ConnectionInfo* connection: bag_view.getConnections() )
32 {
33 const std::string& topic_name = connection->topic;
34 const std::string& datatype = connection->datatype;
35 const std::string& definition = connection->msg_def;
36 // register the type using the topic_name as identifier.
37 parser.registerMessageDefinition(topic_name, ROSType(datatype), definition);
38 }
39
40 // It is efficient to reuse the same instance of FlatMessage and RenamedValues
41 // over and over again, to reduce the amount of memory allocations
42 std::map<std::string, FlatMessage> flat_containers;
43 std::map<std::string, RenamedValues> renamed_vectors;
44
45 for(rosbag::MessageInstance msg_instance: bag_view)
46 {
47 const std::string& topic_name = msg_instance.getTopic();
48
49 // This buffer will store the raw bytes where the message is encoded
50 std::vector<uint8_t> buffer;
51 // write the message into the buffer
52 const size_t msg_size = msg_instance.size();
53 buffer.resize(msg_size);
54 ros::serialization::OStream stream(buffer.data(), buffer.size());
55 // the write method copy the serialized data into the buffer.
56 msg_instance.write(stream);
57
58 FlatMessage& flat_container = flat_containers[topic_name];
59 RenamedValues& renamed_values = renamed_vectors[topic_name];
60
61 // deserialize and rename the vectors
62 parser.deserializeIntoFlatContainer( topic_name,
63 absl::Span<uint8_t>(buffer),
64 &flat_container, 100 );
65 // applyNameTransform will convert flat_container.value into renamed_values
66 // using, if previously registered, some "rules".
67 // This particular example doesn't use any rule.
68 parser.applyNameTransform( topic_name,
69 flat_container,
70 &renamed_values );
71
72 // Print the content of the message
73 printf("--------- %s ----------\n", topic_name.c_str() );
74 for (auto it: renamed_values)
75 {
76 const std::string& key = it.first;
77 const Variant& value = it.second;
78 printf(" %s = %f\n", key.c_str(), value.convert<double>() );
79 }
80 for (auto it: flat_container.name)
81 {
82 const std::string& key = it.first.toStdString();
83 const std::string& value = it.second;
84 printf(" %s = %s\n", key.c_str(), value.c_str() );
85 }
86 }
87 return 0;
88 }