2
$\begingroup$

I have the following code:

void NewCore::spin(){
    ros::Rate rate(10);

    int first =1;
    while(ros::ok()){

        if (first){         
            askMath();first=0;}
        ros::spinOnce();
        rate.sleep();
    }
}

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

    ros::init(argc, argv, "newCore");
    NewCore nc;
    nc.init();

    nc.spin();
}

void NewCore::init(){

    mngrSub = handle.subscribe<std_msgs::String>("/tawi/core/launch", 10, &NewCore::launchCallback, this);
    mngrPub = handle.advertise<std_msgs::String>("/tawi/core/launch", 100);

    mathSub = handle.subscribe<std_msgs::String>("/display", 10, &NewCore::launchCallback, this);
    serSub = handle.subscribe<std_msgs::String>("/tawi/arduino/serial", 100,&NewCore::serialCallback,this);
    mathPub = handle.advertise<std_msgs::String>("/questions", 100);

    ballPub = handle.advertise<std_msgs::Int16>("/tawi/core/ballcount", 100);
    nmbrPub = handle.advertise<std_msgs::Int16>("/tawi/core/number", 100);
}

void NewCore::askMath(){
    ROS_INFO("addition1d<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
    std_msgs::String question;
    question.data = "1digitAddition";
    mathPub.publish(question);
}

(code that isn't interesting has been removed)

Running this causes the following output to appear:

$ rosrun glados newCore 
[ INFO] [1421236273.617723131]: addition1d<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

However if I have the following code on during launch:

$ rostopic echo /questions 

then it does not show me an initial message being sent.

Changing

        if (first){         
            askMath();first=0;}

into

            askMath();first=0;

does appear to work but it then sends a message every cycle rather then just the one at the start.

Does anybody know what is wrong here?

$\endgroup$
  • $\begingroup$ Don't you get a warning when you say rostopic echo /questions that WARNING: topic [/questions] does not appear to be published yet? $\endgroup$ – Shahbaz Jan 14 '15 at 13:13
  • $\begingroup$ No I don't and in fact if I publish a lot of warnings (by removing the if(first)) then they do publish messages. $\endgroup$ – Thijser Jan 14 '15 at 13:16
  • $\begingroup$ If you don't see such a warning, then it looks like that topic already exists. Are you sure you are running rostopic echo /questions before running your node? $\endgroup$ – Shahbaz Jan 14 '15 at 13:20
  • $\begingroup$ I work by activating my code running rostopic echo /questions shutting down my code and then restarting it. If I don't run my code first it does indeed give me a warning that /questions have not been published yet. $\endgroup$ – Thijser Jan 14 '15 at 13:38
  • $\begingroup$ What happens if you just run rostopic first and then your code? $\endgroup$ – Shahbaz Jan 14 '15 at 13:55
3
$\begingroup$

I experimented a bit and here's what I think happens.

When you run

$ rostopic echo /questions

The /questions topic doesn't exist before you run the program. Maybe you cheat it by first running your programming, running this command and then running your program again, but this assertion is still true. So at the point when you run your program, rostopic is not subscribed to any topic.

I don't know internally how this is handled by roscore and rostopic, but somewhere along the line, this is what's happening as the observed behavior of rostopic:

forever

    /* establish connection */
    while not subscribed to topic
        try to subscribe
        if failed
            sleep a bit

    /* intercept messages */
    while topic still exists
        wait for message
        print message

This means that rostopic (or more likely roscore on its behalf) waits for a topic to become available and subscribes to it. It then proceeds to print incoming messages. If the topic becomes unavailable, rostopic (or again more likely roscore on its behalf) goes back to waiting for the topic to become available again.

That said, here's what happens when this runs in parallel with your code:

    rostopic                       you

  wait for topic
      sleep







  wait for topic
      sleep

                                  start
                                ros::init
                             advertise topic
                          publish first message


subscribe to topic
 wait for message
      sleep

As you can see, your program publishes its first message immediately after advertising the topic. The unsuspecting rostopic program is not yet aware of this advertisement so is not actually subscribed to the topic yet. You publish the first message before rostopic gets a chance to subscribe to the topic.

You can verify this simply by putting a relatively large sleep after you advertise the topics and before you publish to them, i.e. between nc.init() and nc.spin().


To address your real problem (as stated and responded in the comments), which is to understand when the node has started up and use this as a trigger for further actions, I'd advise to consider another strategy.

Generally, you would want to make sure a node is up to make sure the other nodes that depend on it can run correctly. However, this doesn't mean that the original node has to be run just before the depending nodes. It could in theory be run long before them, or since ROS doesn't run in real-time and as you have observed, the timing between when topics are advertised, subscribed and the messages going around are quite unpredictable. Add network to this and they are really unpredictable.

So instead, you could devise a mechanism to query whether your node is available or not. This is simply done with a ROS service. You would essentially do all the necessary startup and then put up a service that always returns true. Any node that needs to ensure this node is available before proceeding can poll this service and as soon as a call to this service succeeds, you know the node is running.

As an added bonus, this means that you don't have to take this node down (and all depending nodes) just because you need to restart one of the depending nodes.

$\endgroup$
  • $\begingroup$ Makes sense but does that mean it's also not possible to use launch files and catch a startup message(in effect I want to use this initial message to start a bunch of processes in other nodes and everything is launched by launch files)? $\endgroup$ – Thijser Jan 14 '15 at 15:02
  • $\begingroup$ @Thijser, apparently not. Depending on how you plan on catching this initial message, there may be other options. What I recommend is to use a service. Try to poll a service which is provided by this node, effectively saying "I'm up". Once you detect the node is up, you carry on with spawning your other nodes. This is good, because the node could even be up from before, where you didn't care to check for an initial message. $\endgroup$ – Shahbaz Jan 14 '15 at 15:06
  • $\begingroup$ You can get start up messages from nodes by introducing a delay after all topics are initialized and before publication starts. This allows all communication links to settle. It's even better if you can spin once or twice. $\endgroup$ – Josh Vander Hook Jan 14 '15 at 15:32
  • $\begingroup$ But yes this does appear to be the fix(maybe include it in the main post for future users?) and it does appear to be the answer thank you! $\endgroup$ – Thijser Jan 14 '15 at 15:48
1
$\begingroup$

This thread might also be helpful: http://answers.ros.org/question/9665/test-for-when-a-rospy-publisher-become-available/

The question is specifically about python, but i think the root cause is ROS specific, not language specific.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.