Ask Your Question
0

publish and subscribe in the same node but fails, subscribe does't work.

asked 2019-09-17 14:05:24 -0500

yxl1940 gravatar image

updated 2019-09-17 19:55:33 -0500

jayess gravatar image

Hello guys, I'm trying to change the demo in the tutorial(publisher and subscriber) to two nodes which can subscribe and publish by themselves.

Talker will start first and advertise the topic "chatter" and after publishing it will subscribe to "chatter1".

After the talker start, listener will subscribe to "chatter" and advertise the topic "chatter1" , then publish messages to chatter1.

void chatterCallback1(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  ros::Subscriber sub = n.subscribe("chatter1", 1000, chatterCallback1);
  ros::Rate loop_rate(10);
  int count = 0;
  int np=sub.getNumPublishers();; // number of publishers
  while (ros::ok())
    {
        num = chatter_pub.getNumSubscribers();
         ROS_INFO("%d",num);
        if(num>0)
        {
          std_msgs::String msg;
          std::stringstream ss;
          ss << "hello world " << count;
          msg.data = ss.str();
          ROS_INFO("%s", msg.data.c_str());
          chatter_pub.publish(msg);
          ++count;
         }
      loop_rate.sleep();
      if(np==0)
      {
          sub = n.subscribe("chatter1", 1000, chatterCallback1);
     // ros::Duration(0.4).sleep();  
       }                  
      np = sub.getNumPublishers();
      ROS_INFO("pub num is %d",np);
  ros::spinOnce();
  }
  return 0;
}

Because the listener runs after the talker, the topic "chatter1" is not advertised yet, so I re-declare the subscriber in the loop.

However it still can't subscribe to chatter1.

Here's the listener:

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());     
}
int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter1", 1000);
    int count1=0;
    int num1=0;
   while(ros::ok())
    {
    num1=chatter_pub.getNumSubscribers();
    if(num1>0)
      {
        ROS_INFO("number of subscribers %d chatter1",num1);
        std_msgs::String msg1;
            std::stringstream ss;
            ss << "hello world " <<count1;
            msg1.data = ss.str();
        chatter_pub.publish(msg1);
        ++count1;
        }
        ros::spinOnce();
      }
}

I runs talker first and then the listener. The listener can get the message from the talker but the talker can't heard from the listener.

I checked the topic by running

rostopic list

and

rostopic  echo /chatter1

I find topic chatter1 exists and also I can get the message from echo.

Are there anyone who can explain why the subscriber in the talker.cpp doesn't work?

Thanks a lot.

edit retag flag offensive close merge delete

Comments

I don't see a reason to recreate a subscriber in a loop. In fact, there's some overhead in creating a subscriber so creating one in a loop (especially without any sleep()s) is probably going to be problematic. Try creating the subscriber only once, outside of the loop, and see what happens.

jayess gravatar imagejayess ( 2019-09-17 20:03:25 -0500 )edit

@jayess Thanks, however, when I create the subscriber outside the loop, it seems that the callback function never works.

yxl1940 gravatar imageyxl1940 ( 2019-09-18 11:53:17 -0500 )edit

That means that it's not receiving messages on the topic

jayess gravatar imagejayess ( 2019-09-18 12:06:03 -0500 )edit

@jayess I just create another node talker2 to continually publish the message on the topic chatter1. I tried in different order. If I start the node talker2 at first, the talker will receive messages. However when I start talker first, although talker2 continually publish message to the topic. There's still no message received by talker.

yxl1940 gravatar imageyxl1940 ( 2019-09-18 12:16:50 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
0

answered 2019-09-18 01:32:12 -0500

ffusco gravatar image

updated 2019-09-19 00:30:31 -0500

In my opinion @jayess gave you the correct answer. I will just elaborate his comment more in details.

Subscribing to a topic requires a short amount of time, say 1 second. In your case, right after the first subscription, you enter the loop when the initialization is probably not complete yet. If this is the case, the number of publishers np will be 0. You thus subscribe again, sleep for 0.1 seconds and repeat. However, since you just re-subscribed, you can likely expect that the connection with the topic will not have been accomplished (again, it might take around 1s). You should easily see that this leads you to a loop in which the subscriber never has the time to fully connect with other nodes, since you re-initialize it every 0.1s. Note that the publisher-subscriber policy is fine with that: in general, a subscriber can expect any number of publishers, even zero, and since this is perfectly fine the roscpp client does not try to ensure that at least one publisher is found before leaving the initialization of a subscriber. You can simply drop your check: you will simply loose a couple of messages in the beginning, but eventually everything will work just fine.

If for any reason you must make sure that a subscriber has at least one publisher before entering the main loop, a better solution is to add, between the first ros::Subscriber sub = n.subscribe("chatter1", 1000, chatterCallback1); and the main loop, something like:

while(ros::ok() && sub.getNumPublishers() == 0)
  ros::Duration(0.2).sleep();

The ros::ok() condition is important in case you send a shutdown signal to the node while it is in this "initialization loop".

EDIT

Given your comment, try to compile and run the following code:

#include <ros/ros.h>
#include <std_msgs/String.h>

void callback(const std_msgs::String& msg) {
  ROS_INFO("I heard '%s'", msg.data.c_str());
}

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

  ros::Subscriber sub = nh.subscribe("chatter", 1, callback);
  ros::Publisher pub = nh.advertise<std_msgs::String>("talk", 1);
  std_msgs::String msg;
  msg.data = "Hello";

  while(ros::ok() && sub.getNumPublishers() == 0) {
    ros::Duration(0.2).sleep();
    ROS_INFO_THROTTLE(1.0, "Waiting for publishers...");
  }

  ROS_INFO("There are now %d subscribers connected!", sub.getNumPublishers());

  ros::Rate rate(1);
  while(ros::ok()) {
    ros::spinOnce();
    pub.publish(msg);
    rate.sleep();
  }

  return 0;
}

It is a shorter version of your code, and when you start it you should see on the console the message "waiting for publishers" printed every second. In a new terminal, type:

rostopic pub -r 0.2 /chatter  std_msgs/String "data: 'ROS'"

You should now see (in node's terminal) that the program advanced by reporting 1 publisher and by printing every 5s the received message. In addition, it will publish every second a message in the topic talker. This runs fine in my PC, can you tell me if it is the same for you?

edit flag offensive delete link more

Comments

@ffusco Thanks a lot. However, when I add another loop between the subscribe line and the main loop. the number of publisher is always zero so that the program is always in that loop. I even tried to create another node which will continually publish message to chatter1 but sub.getNumPublishers still remains at 0;

yxl1940 gravatar imageyxl1940 ( 2019-09-18 11:59:00 -0500 )edit

I see, unfortunately I cannot understand why it is not working... Can you see in my edit if the code I wrote runs fine for you?

ffusco gravatar imageffusco ( 2019-09-19 00:23:28 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

Stats

Asked: 2019-09-17 14:05:24 -0500

Seen: 36 times

Last updated: Sep 19