(!) 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_introspection

Keywords: 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 }

Wiki: ros_type_introspection/Tutorials/GenericTopicSubscriber (last edited 2019-01-19 16:16:20 by DavideFaconti)