[ros-users] Writing generic subscription callbacks

Julian Brunner julianbrunner at googlemail.com
Wed May 18 21:14:06 UTC 2011


Hey Daniele,

I've had to do something similar some time ago in order to pass the
data received on ROS topics to a generic graph visualization
application (http://streamvis.googlecode.com).

In the ROS package 'topic_tools', there is a class called
'ShapeShifter' (http://www.ros.org/doc/api/topic_tools/html/classtopic__tools_1_1ShapeShifter.html),
which can be used as message type. It will basically accept any
message and give you information about it such as DataType, MD5Sum and
MessageDefinition. You can also write the binary data of the message
to a stream.

You can see how I did it in streamvis. I subscribed to the ROS topic
in a little C++ wrapper using the ShapeShifter
(http://code.google.com/p/streamvis/source/browse/tags/Version%201.4/Source/Wrappers/streamvis-wrappers-ros/source/streamvis-wrappers-ros.cpp),
then pass the information about the message type together with the
message data to the C# code that the rest of the application is
written in (http://code.google.com/p/streamvis/source/browse/tags/Version%201.4/Source/Visualizer/Data.Ros/RosPort.cs).
Since the "getMessageDefinition" method unfortunately did not
recursively give all the information of the subtypes in the message
definition when I last checked, I had to invoke 'rosmsg show' to
actually get the fully recursive message definition needed to actually
parse the binary message.

This approach unfortunately requires a bit of work since you'll have
to write a parser for binary ROS messages (which includes all the
primitive types as well as recursively parsing structures). If your
license is compatible with GPLv3, feel free to reuse and/or adapt my
parsing code though.

Maybe you can also look into how it is done in rospy and/or the
implementation of 'rostopic echo', since these seem to be able to
handle dynamic message types aswell.

Hope this helps,
 Julian Brunner

On Thu, May 5, 2011 at 10:31 AM, Daniele Calisi
<daniele.calisi at gmail.com> wrote:
> On Wed, May 4, 2011 at 7:59 PM, Troy Straszheim
> <straszheim at willowgarage.com> wrote:
>>
>> On Wed, May 4, 2011 at 10:07 AM, Daniele Calisi <daniele.calisi at gmail.com>
>> wrote:
>>>
>>> The problem comes when I try to write a generic subscriber: I tried with
>>> this:
>>>                 sub = new
>>> ros::Subscriber(rosNodeHandle->subscribe(url.getPath(), 1000,
>>> &RosAphModule::subscriptionCallback, this));
>>> but this cannot be done, since the callback should be something like:
>>> void RosAphModule::subscriptionCallback(const ros::Message::ConstPtr&
>>> msg)
>>> that is not allowed, because ros::Message is an abstract type and the
>>> compiler says what I paste at the end of this email... moreover, I would
>>> like to know how to get the topic the message was coming from (given the
>>> ros::Message& msg in the callback, I mean).
>>
>> Hey Daniele,
>> Looks tricky indeed...   the compiler can only know which serialization
>> method to instantiate if it knows what message type to expect via the type
>> argument to subscribe<>.  For instance, there is no procedure by which a ros
>> node, given an incoming message of unknown type, can look up a serialization
>> method in a table, since this table does not exist.  If it did exist, there
>> would be no  guarantee that it is complete, as the incoming message might
>> have been generated by code that this node does not have access to.   Also,
>> to do anything with this message one would then need to type-switch or
>> something, which is quickly going to break down... there are just a lot of
>> problems here that might be better addressed with an alternate design.
>> So...  can I ask you to elaborate on how this will all fit together?
>> Troy
>
> Hi Troy, thanks very much for the answer.
> You are saying that the DEserialization method (I can do what I want with
> the publisher, the problem exists only with the subscriber) is instantiated
> during the building process and not dynamically at run-time (i.e., ROS uses
> C++ templating facilities). This could be good for efficiency reasons (how
> much?), but I do not see the point of not having the
> serializers/deserializers table. Of course you can build a node with a
> publisher that uses serialization method A and a node with a subscriber, for
> the same object, with a serialization method B (e.g., a different version of
> the same object) and things are going to fail. Unmarshalling are usually
> done (by Data Distribution Services and some other middleware software) by
> checking object name, version, etc. and then decide how to deserialize. Here
> it seems that ROS can check this meta information, but only to decide if it
> is going to use the right deserializer or not. Moreover, how subclassing is
> working here? If I send an object of class A to a subscriber of class B :
> public A, what happens?
> I think that, since you are just receiving a stream of bytes from the
> network, it's up to the subscriber to convert that stream to what is right.
> Finally, you are always "type-converting" a stream of bytes to an object, I
> do not see the point of fearing this conversion, being that done statically
> at building time, or dynamically with an smart unmarshalling system.
> What am I missing here?
> Thanks again for the discussion, I am new to ROS and I want to go in deep
> detail :-).
> --
> Daniele "MadMage" Calisi
> "Your limit is always a bit beyond"
>
> _______________________________________________
> ros-users mailing list
> ros-users at code.ros.org
> https://code.ros.org/mailman/listinfo/ros-users
>
>



More information about the ros-users mailing list