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. |
How to create a generic Topic Subscriber
Description: Subscribe and extract data from any topic using ShapeShifter and ros_type_introspectionKeywords: introspection shapeshifter, topic, subscriber
Tutorial Level: BEGINNER
topic_tools::ShapeShifter is a type frequently used to create "generic subscribers", i.e. a subscriber that can subscribe and perform type erasure on any topic message. Let's see an example.
1 #include "ros_type_introspection/ros_introspection.hpp"
2 #include <ros/ros.h>
3 #include <topic_tools/shape_shifter.h>
4
5 using namespace RosIntrospection;
6 using topic_tools::ShapeShifter;
7
8 void topicCallback(const ShapeShifter::ConstPtr& msg,
9 const std::string &topic_name,
10 RosIntrospection::Parser& parser)
11 {
12 const std::string& datatype = msg->getDataType();
13 const std::string& definition = msg->getMessageDefinition();
14
15 // don't worry if you do this more than once
16 parser.registerMessageDefinition( topic_name,
17 RosIntrospection::ROSType(datatype),
18 definition );
19 std::vector<uint8_t> buffer;
20 FlatMessage flat_container;
21 RenamedValues renamed_value;
22
23 // copy raw memory into the buffer
24 buffer.resize( msg->size() );
25 ros::serialization::OStream stream(buffer.data(), buffer.size());
26 msg->write(stream);
27
28 // deserialize and rename the vectors
29 parser.deserializeIntoFlatContainer( topic_name,
30 absl::Span<uint8_t>(buffer),
31 &flat_container,
32 100);
33 parser.applyNameTransform( topic_name, flat_container, &renamed_value );
34
35 // Print the content of the message
36 printf("--------- %s ----------\n", topic_name.c_str() );
37 for (auto it: renamed_value)
38 {
39 const std::string& key = it.first;
40 const Variant& value = it.second;
41 printf(" %s = %f\n", key.c_str(), value.convert<double>() );
42 }
43 for (auto it: flat_container.name)
44 {
45 const std::string& key = it.first.toStdString();
46 const std::string& value = it.second;
47 printf(" %s = %s\n", key.c_str(), value.c_str() );
48 }
49 }
50
51
52 // usage: pass the name of the file as command line argument
53 int main(int argc, char** argv)
54 {
55 Parser parser;
56
57 if( argc != 2 ){
58 printf("Usage: rosbag_example topic_name\n");
59 return 1;
60 }
61 const std::string topic_name = argv[1];
62
63 ros::init(argc, argv, "universal_subscriber");
64 ros::NodeHandle nh;
65
66 //who is afraid of lambdas and boost::functions ?
67 boost::function<void(const ShapeShifter::ConstPtr&) > callback;
68 callback = [&parser, topic_name](const ShapeShifter::ConstPtr& msg)
69 {
70 topicCallback(msg, topic_name, parser) ;
71 };
72 ros::Subscriber subscriber = nh.subscribe(topic_name, 10, callback);
73
74 ros::spin();
75 return 0;
76 }