ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
2

publisher and subscriber in single node

asked 2012-10-14 22:47:17 -0500

chris_chris gravatar image

updated 2012-10-14 23:18:16 -0500

Consider node 'x' publishes topic 'a' and 'b'. Now, I should create a node 'y' to subscribe a topic 'a'. Then the subscribed topic should be edited and published again in the name 'c'.

I tried,

// some part of the codes

void chattercallback(const .... )
{

.........

// edit or process the subscribed value<
//to publish the edited data

ros::Publisher d =......;

d.publish(..) ;

....}

int main (int argc, char **argv){

ros::init (..);

ros::Subscriber sub = .....(.. , .. , chattercallback);

....

}

But, the data is not published continuously. This node publishes data only when the topic 'a' is available i.e) only when the data is subscricbed. I need to change this codes such that data is to be published continuously i.e) even if the subscriber does not subscribe any data, it should publish the data according to the last subscribed one.

Is there any ideas for this problem?


I cannot find the option 'post a comment' below the answers. So I will post it here.

But the problem is how to access the value in topic 'a' for storing it to a variable?

edit retag flag offensive close merge delete

Comments

I cannot find the option 'post a comment' below the answers. So I will post it here.

But the problem is how to access the value in topic 'a' for storing it to a variable?

chris_chris gravatar image chris_chris  ( 2012-10-14 23:33:16 -0500 )edit
1

Normally,publishers, subscribers and callbacks are implemented as class members. If you need to store a value, you just put it into a member variable so that e.g. a publisher can access it.

Lorenz gravatar image Lorenz  ( 2012-10-15 03:14:05 -0500 )edit

5 Answers

Sort by ยป oldest newest most voted
7

answered 2012-10-14 23:02:13 -0500

KruseT gravatar image

Store the last value from topic a in a variable. In main, use an explicit spin loop. In that loop, after a timeout, publish on c.

edit flag offensive delete link more

Comments

I used callback function as a class member and store data from callback function into a data member. I do publishing in the main function within a while loop (loop has ros::spinOnce). But, I cannot understand what is explicit spin loop and where to put the spin loop in the main function.

chris_chris gravatar image chris_chris  ( 2012-10-17 21:58:56 -0500 )edit
1

Using spinOnce in a while loop is called an explicit spin loop.

dornhege gravatar image dornhege  ( 2012-10-17 23:49:24 -0500 )edit
8

answered 2012-10-15 03:10:59 -0500

kszonek gravatar image

updated 2012-10-18 04:04:25 -0500

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();
}
edit flag offensive delete link more

Comments

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

chris_chris gravatar image chris_chris  ( 2012-10-17 00:04:53 -0500 )edit
1

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.

kszonek gravatar image kszonek  ( 2012-10-17 08:44:06 -0500 )edit

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.

chris_chris gravatar image chris_chris  ( 2012-10-17 22:23:28 -0500 )edit

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'

chris_chris gravatar image chris_chris  ( 2012-10-17 22:24:01 -0500 )edit

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.

dornhege gravatar image dornhege  ( 2012-10-17 23:52:24 -0500 )edit

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)

chris_chris gravatar image chris_chris  ( 2012-10-18 03:55:13 -0500 )edit

@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.

kszonek gravatar image kszonek  ( 2012-10-18 03:57:31 -0500 )edit

Already, I declared my pub as a class member. So, I expect this should be problem with the other node subscribing this one..

chris_chris gravatar image chris_chris  ( 2012-10-18 04:41:52 -0500 )edit
4

answered 2012-10-14 23:05:35 -0500

arzhed gravatar image

updated 2012-10-15 04:57:01 -0500

You should not declare your publiser in your callback function : this callback function is called only when data is received on topic 'a', that is why topic 'c' depends on topic 'a'. Store the data you got from topic 'a' into a "global" variable and declare your published topic 'c' into the main. For example :

float64 aux;

void chatterCallback(const& msg)
{
   aux=msg->data;
}

int main (int argc, char **argv){

ros::init (..);

ros::Subscriber sub = .....(.. , .. , chattercallback);

ros::Publisher d =......;

d.publish(..) ;

}

Update : To your question "how to access data from a topic" (see comments)

For example, if you want to access the x position of your robot spawned in gazebo empty world. You can get that information from the topic /model_state that you can get in gazebo your callback function would look like this :

void chatterCallback(const& msg)
{
   aux=msg->pose[1].position.x;
}

Look at the links above. If you need better understanding, launch a robot in gazebo and run the following

$ rostopic echo /gazebo/model_states
edit flag offensive delete link more

Comments

Thank you! This worked for me, but do you think this is a good a idea to have a global variable?

ErivaldoJunior gravatar image ErivaldoJunior  ( 2016-02-10 14:49:07 -0500 )edit

This works for me, thanks!!

ami gravatar image ami  ( 2016-06-10 11:23:04 -0500 )edit
0

answered 2015-07-17 04:24:29 -0500

saikrishnagv gravatar image

hello, I have done it as per the solutions give here.

I am subscribing to a sensor_msgs::Image, and I want to publish my_package/RectifiedImage.msg over a topic "mycustomtopic".

When I do "rostopic list", it is showing /mycustomtopic

When I do "rostopic echo mycustomtopic", it is showing "the rosdep view is empty: call 'sudo rosdep init' and 'rosdep update' ERROR: Cannot load message class for [stereo_msgs/RectifiedImage]. Are your messages built?"

this is what I was doing:

void callback(const ..){

..

my_msg_pub_.publish(myimage);

..

return;

}

and

int main(int argc , char** argv){

subscribe to sensor_msgs::Image

callback

my_msg_pub_ = nh.advertise<stereo_msgs::rectifiedimage>("mycustomtopic", 1);

ros::spin();

return 0;

}

where could be my mistake?

edit flag offensive delete link more

Comments

Please do not use Answer form unless you actually have an answer. ROS Answers is not a forum, but Q&A site. So consider creating a separate question. Once done, please remove your 'Answer' from here. For discussions use comments.

Boris gravatar image Boris  ( 2015-07-18 02:53:04 -0500 )edit

@saikrishnagv Please try to make your answers or comments more readable. You can do this by using the "101 010" button on top of the comment or answer field for code snippets. You can use the preview function of answers to check if your code is formatted like it should.

Wifi-cable gravatar image Wifi-cable  ( 2020-02-19 04:06:01 -0500 )edit
0

answered 2012-10-17 02:13:27 -0500

chris_chris gravatar image

updated 2012-10-17 02:16:00 -0500

I don't know whether this is an efficient solution or not. but this is working.

my class {

public:

//.....constructors.......

//--- defining a callback function----

void callback (......){

.........

while(ros::ok) {

//publish data

ros::spinOnce;

}

}

.........

};

int main(...){

ros::init(...);

.....

myclass a (....define publisher and subscriber to load the constructor...);

ros::spin();

....

}

I think spin loop will be calling the callback function, when the data is available for subscribing. and while loop inside the callback function with ros::ok will publish the data continuously.

If there is any problem in this, I wish to know...

edit flag offensive delete link more

Comments

1

I would not recommend this. Use the approach suggested by @KruseT. @kszonek already posted sample code that works like that (maybe missing a sleep to limit the rate).

dornhege gravatar image dornhege  ( 2012-10-17 03:13:12 -0500 )edit

But, I have a doubt where to put the ros::spin for callback function of the subscriber? If I write a code as mentioned above, I can view the required data inside the while loop. By calling the function publish, data is not put into the topic. I don't know why it happend.

chris_chris gravatar image chris_chris  ( 2012-10-17 07:18:40 -0500 )edit
1

Calling spinOnce() inside of callback is a bad idea.

kszonek gravatar image kszonek  ( 2012-10-18 04:31:51 -0500 )edit

Question Tools

Stats

Asked: 2012-10-14 22:47:17 -0500

Seen: 16,629 times

Last updated: Jul 17 '15