How to publish once (only one message) into a topic and get it to work

It’s very likely that it has happened to you before. You sent a command to move or stop a robot by publishing to the cmd_vel topic, but it disobeyed! Your code is correct and you have published to the right topic, yet…

This might have happened to you when publishing to any other topic. For example, you might have been trying to take off or land a drone.

Of course, you were miffed - this probably caused you to lose time, energy, marks or even money. This kind of misbehaviour never produces anything good (except the learning you got)! Maybe you felt like breaking the robot, or your computer screen (if it’s a virtual robot). But thank God you didn’t, because…

The robots are not to blame! At least 99% of the time. In most cases, if you publish more than once, the robot responds. Why?

This happens because the publisher was not yet ready, so your commands just went into oblivion. There was not enough time between creating the publisher and sending the message on it for any listener node to register with this new publisher. If you add a one-second sleep after creating the publisher it will likely solve this problem.

But you don’t need to add a one-second sleep, here’s my favorite way of doing it. Instead of writing your publishing code in this fashion:

# Python version
# ...
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
pub.publish(msg)
# ...
// C++ version
// ...
ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("cmd_vel", 1000);
pub.publish(msg)
# ...

Try something like this:

# Python version
# ...
pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
while pub.get_num_connections() < 1:
     # wait for a connection to publisher
     # you can do whatever you like here or simply do nothing

pub.publish(msg)
# ...
// C++ version
// ...
ros::Publisher pub = nh.advertise<geometry_msgs::Twist>("cmd_vel", 1000);
while (pub.getNumSubscribers() < 1) {
    // wait for a connection to publisher
    // you can do whatever you like here or simply do nothing
}
pub.publish(msg)
// ...

So now you only need to “bark” once and the robot obeys :wink:.

Hope this helps. If it does, please let me know.

Cheers!

18 Likes

Could I not use the ‘latch’ option of the rospy.Publisher to achieve a similar result? Just found it on the API documentation.

# Python version
# ...
pub = rospy.Publisher('/cmd_vel', Twist, latch=True, queue_size=1)
pub.publish(msg)
# ...

In case the problem is really that the connection to the subscriber was not yet established, enabling ‘latch’ should force the message to be republished once it is established, shouldn’t it?

No, you can’t.

Latching achieves a different purpose related to subscribers, and we’re talking strictly about publishers here. You want to publish to a topic and be “cock sure” it will work at the first shot (all other things being equal).

When you create a publisher (latched or not), the connection has to be ready before you can publish anything, or you’ll just be publishing to /dev/null :wink:.


By the way, welcome to the community!