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

Listening to Publisher in Python from C++ Subscriber: Problem

asked 2015-12-30 17:29:13 -0500

edessale gravatar image

updated 2016-01-01 04:53:44 -0500

gvdhoorn gravatar image

Hello all,

I have a publisher in Python that I want publishing an Integer value from 0-2. I want to subscribe to that publisher from C++ and obtain that value. Below is the relevant code:

PYTHON:

def capturePointCloud(tracker):
    pub1 = rospy.Publisher('PointCloudView', Int8, queue_size=1)
    pub1.publish(tracker)   
    print "Made it"

where the tracker parameter is 0, 1 or 2. This is published 3 times through 3 capturePointCloud calls. I'd like for it to only be published once, and then when it's received on the C++ subscriber be stopped publishing, but for now I just want this working.

C++

 int main (int argc, char** argv)
{
    ros::init (argc, argv, "my_pcl_tutorial");
    ros::NodeHandle nh2;

    ROS_INFO("message is");
    while(true)
    {
      sub4 = nh2.subscribe<std_msgs::Int8>("/PointCloudView", 1, saveFiles);
    if(tracker == 2)
    break;
    }
}
    void saveFiles(std_msgs::Int8 msg)
    {
    ROS_INFO("message is");
    tracker = msg.data;
    ....

I have not finished the saveFiles callback function because it is irrelevant. For some reason, the callback function in C++ is never reached. I have used rostopic info /PointCloudView and I get:

Type: std_msgs/Int8

Publishers: 
 * /BAXTER (http://localhost:37366/)

Subscribers: 
 * /my_pcl_tutorial (http://localhost:38479/)
 * /rostopic_8283_1451517068960 (http://localhost:59099/)

/PointCloudView even shows up on rostopic list, so what am I doing wrong here? The code looks fine to me, and I cannot figure out why the subscriber is not listening to the publisher. C++ listeners should be able to access Python publishers and what I'm doing is fairly simple, so why is this not working? I'd be very grateful for any help. Thank you all.


EDIT:

Thanks to @gvdhoorn, I was able to fix my problem as well as get a better understanding of subscribers/publisher control. Below is the updated code:

Python:

 rospy.init_node('BAXTER', anonymous=True)
 pub1 = rospy.Publisher('PointCloudView', String, queue_size=10)
 pub2 = rospy.Publisher('PointCloudView', String, queue_size=10)
 pub3 = rospy.Publisher('PointCloudView', String, queue_size=10)    
....
 pub1.publish(str(0))
...
 pub2.publish(str(1))
...
 pub3.publish(str(2))

C++:

ros::init (argc, argv, "my_pcl_tutorial");
ros::NodeHandle nh2;

sub4 = nh2.subscribe("/PointCloudView", 10, saveFiles);
ros::spin();
edit retag flag offensive close merge delete

Comments

Please don't use answers to post updates, edit your original question for that (use the edit link/button below it). I've already merged your update into your post, but please keep it in mind for future questions.

gvdhoorn gravatar image gvdhoorn  ( 2016-01-01 04:56:04 -0500 )edit

You don't need multiple publishers to publish the same message to the same topic. A single one will suffice. You can publish any number of messages with a single publisher (but they have to be of the same type). Also: it's fine if you do, but normally you don't need multiple NodeHandles either.

gvdhoorn gravatar image gvdhoorn  ( 2016-01-01 04:57:39 -0500 )edit

And a suggestion if I may: try to pick up a book (or two) about ROS. That will very quickly allow you to gain some insight into why things are done the way they are, moving away from 'magic incantations'. See wiki/Books (A Gentle Introduction to ROS is nice, and free).

gvdhoorn gravatar image gvdhoorn  ( 2016-01-01 04:59:40 -0500 )edit

Will do! I'll change my code up as well, thank you.

edessale gravatar image edessale  ( 2016-01-02 17:02:59 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
2

answered 2015-12-31 03:08:09 -0500

gvdhoorn gravatar image

updated 2015-12-31 03:11:17 -0500

tl;dr: don't create and destroy your Publishers (or Subscribers) in a tight loop, ROS won't have time to properly register your subscriptions, and the chance that your Python node publishes its message at exactly the right time (between a creation and a destruction of your Subscriber) is rather slim. Move Pub/Sub creation to your code that initialises your node, and implement your business logic in callbacks.


longer version:

while(true)
{
  sub4 = nh2.subscribe<std_msgs::Int8>("/PointCloudView", 1, saveFiles);
 [..]

This (and you probably have other lines like this elsewhere), is probably what is causing your setup not to work.

From your code, I believe you are trying to implement a polling system: retrieve the current state every so often, then upon change, influence the control flow of your program.

ROS on the other hand (and other systems implementing the Observer/Observable or Publish/Subscribe style) is a callback system: you express your interest in certain events (ie: the arrival of Int8 messages on the PointCloudView topic), tell the middleware who it should notify if/when such an event occurs (ie: you register a callback) and whenever an event occurs, the middleware will delegate processing / reacting to the event to your callback.

A typical ROS node registers its callbacks during its initialisation phase (c'tor, first part of your main, etc), initialises some internal state and then just hands over control of everything to ROS (ie: calls ros::spin()). If you have other things to do as well (so when no messages are arriving), use a loop construct and give ROS just enough time to process events every now and then (ie: call ros::spinOnce() periodically).

As to your issue: I expect that if you move the creation of your Subscriber(s) to somewhere outside your while-loop (and perhaps change some details as to how your business logic interacts with your callbacks) things will start to work.

PS: ROS does support a synchronous (ie: blocking) service based interaction style, which is similar to traditional client/server. Depending on your actual needs, that might be more suited here, but I can't say from what you've described.


Edit:

def capturePointCloud(tracker):
    pub1 = rospy.Publisher('PointCloudView', Int8, queue_size=1)
    pub1.publish(tracker)   
    print "Made it"

I'd also advise you to do the same with your Python code: right now, upon invocation of the capturePointCloud(..) function, a Publisher is created, which will try to publish a message, but it (the Publisher) will most likely only exist for a few milliseconds. I'd be surprised if it can successfully publish anything.

edit flag offensive delete link more

Comments

Thank you for the very informative write! You explained everything very, very clearly. in a way people relatively new such as myself can understand. I'm fixing my code right now and I will post it as soon as it is ready.

edessale gravatar image edessale  ( 2015-12-31 12:58:24 -0500 )edit

Question Tools

1 follower

Stats

Asked: 2015-12-30 17:29:13 -0500

Seen: 1,754 times

Last updated: Jan 01 '16