ros/ros_comm — pull request #208 by brindza (2013-04-02 13:55:19+00:00)
Title: rospy bug fix: subscribing to a topic with multiple publishers does not connect to all topics

Problem:
rospy subscriptions do not connect to all nodes publishing a topic.

To Reproduce:

1. Start a new roscore.
2. Create 10 publishers on the same topic. Run this command in each terminal: ```rostopic pub -r 10 /test std_msgs/String -- hi```
3. Create a python node that subscribes to /test and inspect its connections. I used the code at the bottom of this comment which just prints the number of connections but you can also just use 'rostopic echo /test' as it is implemented in python and do a rosnode info on that node to inspect its connections. The node does not connect to all publishing nodes more often than it does.

NOTE: 10 publishers is just an arbitrary number I chose. It can be higher or
lower (at least 2, though it is harder to reproduce) and still cause the issues.
10 was enough nodes to make the problem happen very frequently. The more you make the more likely it will be to drop the connections.

Cause:
The subscriber is trying to add connections before they are initialized.

1. The TCPROSHandler in tcpros_pubsub.py creates a Transport object which keeps track of the endpoint_id, port, etc
* the endpoint_id is 'unknown' by default
2. Two things happen:
* A 'robust_connect_subscriber' is created
- This thread first makes the connection between the publisher and
subscriber
- Then it loops waiting for new messages
* The connection is 'added' to the subscriber
- The first thing this function does is check to see if there is already
a connection to this endpoint and removes it if it exists
3. The problem is the 'endpoint_id' is used to determine if a connection already
exists but the 'endpoint_id' is not set until a connection is made between
the nodes so most 'add_connection' calls happen when the 'endpoint_id' is
still set to 'unknown' causing the subscriber to drop connections to any
nodes that have not made a full connection yet (ie. the endpoint_id was
still uninitialised and also set to 'unknown').

Solution:
I was able to fix the issue by setting the Transport object's 'endpoint_id' from
the 'pub_uri' when the Transport object is created and didn't have any issues
connecting to over 100 publishers.

I am not sure if this is the correct way to resolve this issue or if there is a way to
wait until the connection is established before before adding it to the subscriber.
Or if there is a better way to check for duplicate connections that doesn't use the endpoint_id.

subscription node:

import roslib
roslib.load_manifest('std_msgs');

import rospy
import std_msgs.msg as std_msgs

test_sub = None;

def test_sub(msg):
rospy.loginfo('%d connections' % test_sub.get_num_connections());

if (__name__=='__main__'):
rospy.init_node('test_rospy_sub');

# subscriber
rospy.loginfo('creating test sub');
test_sub = rospy.Subscriber('/test', std_msgs.String, test_sub);

rospy.spin();