After publishing on topic you need to let the ROS spin, to make sure data is actually send on the topic. Calling "publish" doesn't put the data on the topic, so if you destroy publisher before the data is send, you lose the information stored in the buffer.
The best solution is to make your callback a class member and access data as a private variable of the class from function that is publishing this information. Quick code example:
int main (int argc, char **argv)
{
ros::init (..);
myClass myObject;
while(ros::ok())
{
myObject.publishDataIfRecieved();
ros::spinOnce();
}
}
I will skip the class, but constructor should create both subscriber and publisher, callback should be part of a class, as well as the temporary data storage variable/structure and some boolean to indicate new data presence. For high frequency data you should provide some security for overwriting by callback not yet published data.
Also if you are not doing any computation an the data, you can just publish it inside the callback, using publisher that is already initialized as a class member, but you should avoid too much operation in your callback
Easier solution is global variable, as mentioned before, but it is not so elegant one.
EDIT:
ros::spinOnce() callend once in a while (as often as possible) will do the trick, but if you reallllly want to use ros::spin() instead, other solution is:
class myClass
{
(...)
public:
myClass() { pub = (...); sub = (...) }
private:
ros::Publisher pub;
ros::Subscriber sub;
void chattercallback(...) { pub.publish(...); }
}
int main (int argc, char **argv)
{
ros::init (..);
myClass myObject;
ros::spin();
}
Originally posted by kszonek with karma: 459 on 2012-10-15
This answer was NOT ACCEPTED on the original site
Post score: 8
Original comments
Comment by chris_chris on 2012-10-17:
But. In the main function where will you call the ros::spin for the callback function of subscriber? Also, I have a doubt whether updation of publishing topic will happen inside the while loop
Comment by kszonek on 2012-10-17:
There is a slight difference betwean ros::spin() and ros::spinOnce(). First blocks the program and allows ros callbacks to handle node work, when second one releases after doing all ros related stuff. It allows you to do code in main function letting ros do it work.
Comment by chris_chris on 2012-10-17:
I subscribe a point cloud data into this node. If I write a main function as mentioned above without a spin in main function, it gives an error because the subscribed data will be available only at some particular point of time. In case of spin loop inside the main function it will not give error.
Comment by chris_chris on 2012-10-17:
thats why I am asking where to put the spin loop. Also, In your answer, I didn't understand 'Calling "publish" doesn't put the data on the topic, so if you destroy publisher before the data is send, you lose the information stored in the buffer'
Comment by dornhege on 2012-10-17:
In your code, the publisher is a local variable and thus will be destroyed immediately after the callback is handled - thus you won't get any publish.
Comment by chris_chris on 2012-10-18:
In my code, the publisher is data member of the class. So, I think when it enters the callback function it will not be destroyed (callback is the member function of the same class)
Comment by kszonek on 2012-10-18:
@Chris: as mentioned already by domhege, your publisher is being destroyed at the end of a chattercallback function, since it is declared within it. Your publisher is NOT class member.
About the spinning, let me edit my answer, since this comment is already too long.
Comment by chris_chris on 2012-10-18:
Already, I declared my pub as a class member. So, I expect this should be problem with the other node subscribing this one..
Comment by dornhege on 2012-10-18:
We only see the code excerpt in your question, which is not using a class member. If your code has that fixed, you can always test with rostopic echo to eliminate the "other node" as a failure option.
Comment by Sudhan on 2012-10-25:
I would like to know what do you mean in this lines (For high frequency data you should provide some security for overwriting by callback not yet published data.)?
Comment by dornhege on 2012-10-25:
If the callback receives very high frequency data, it might not have been processed (published) until the next data arrives. Thus it will be overwritten, if not handled by queuing.
Comment by Sudhan on 2012-10-25:
so, Can you please tell me how to handle these type of datas?
Comment by dornhege on 2012-10-25:
The usual way is to use a queue as the builtin queue in ROS.
Comment by Sudhan on 2012-10-25:
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
Do you mean this number 1000 for queueing?
As I understand for subscribing high frequency messages, bigger number would be better. I would like to know what I understood is correct?
Comment by dornhege on 2012-10-25:
Not necessarily. A bigger number allows to buffer more messages, but if you cannot handle messages in the speed they arrive, you might get an opposing effect that your queue is full and newer messages are discarded. You will need to decide depending on your system.