Rosanswers logo

I am trying to return an array that contains a latitude and a longitude from a subscriber that I wrote. What I am trying to do is have some type of global variable and when infoGetter() is called, go to the callback function, run once, set new values from the /novatel/fix topic to my latitude and longitude variables and return them in an array once we are back in the infoGetter function. The array is sent to another program so I made my subscriber into a function. It is only supposed to run once in my other program and return those values. Is it possible to do what I am trying to do? What am I missing? Here's my subscriber function:

#!/usr/bin/env python
import rospy
from sensor_msgs.msg import NavSatFix
#from RetreiveFiles import whatTheHell
latitude = 0
longitude = 0
ra = [0,0] 

def callback(data):
   rospy.loginfo("Longitude: %f, Latitude %f" % (data.longitude, data.latitude))
   global latitude
   global longitude 
   latitude = data.latitude
   longitude = data.longitude
   #whatTheHell(latitude, longitude)
def infoGetter(): 
    rospy.init_node('infoGetter', anonymous=True)
    rospy.Subscriber("/novatel/fix", NavSatFix, callback)
    global latitude
    global longitude
    global ra
    pritn ra
    ra[0] = latitude 
    ra[1] = longitude 
    return ra
"""if __name__ == '__main__':
    infoGetter() """  

Originally posted by negotiator14 on ROS Answers with karma: 35 on 2015-08-13

Post score: 1


1 Answer 1


Rosanswers logo

I assume you want the latitude and longitude values from one message in your main thread?

You can wait on a result from the subscriber using a threading.Event object. The "InfoGetter" is better contained in a class than global variables and a function. Here is working code.

import rospy
from sensor_msgs.msg import NavSatFix
import threading
class InfoGetter(object):
    def __init__(self):
        #event that will block until the info is received
        self._event = threading.Event()
        #attribute for storing the rx'd message
        self._msg = None
    def __call__(self, msg):
        #Uses __call__ so the object itself acts as the callback
        #save the data, trigger the event
        self._msg = msg

    def get_msg(self, timeout=None):
        """Blocks until the data is rx'd with optional timeout
        Returns the received message
        return self._msg
if __name__ == '__main__':
    rospy.init_node('infoGetter', anonymous=True)
    #Get the info
    ig = InfoGetter()
    rospy.Subscriber("/novatel/fix", NavSatFix, ig)
    #ig.get_msg() Blocks until message is received
    msg = ig.get_msg()
    print msg

You can test that this code works by starting a roscore, running this script, and executing the following command

rostopic pub /novatel/fix sensor_msgs/NavSatFix "{latitude: 4.0, longitude: 5.0}"

Originally posted by sloretz with karma: 3061 on 2015-08-13

This answer was ACCEPTED on the original site

Post score: 1

Original comments

Comment by Dan Lazewatsky on 2015-08-13:
You might want to read through the rospy tutorials again as there's a bit of important incorrect info here. First, in rospy, the only thing spin does is block until the node is shutdown. It is not required for callbacks to happen. Second, rospy.Subscriber does not block.

Comment by sloretz on 2015-08-13:
Thanks for the comment, Dan. I checked and you're correct that rospy.spin is not responsible for calling callbacks, my mistake. I've removed the extra thread from the script. Of course subscriber doesn't block, but ig.get_msg() does. I've edited the comment to clarify.

Comment by lffox on 2017-03-30:
Why exactly did you use a threading event object?

Comment by sloretz on 2017-03-30:
@lffox The subscriber callback happens asynchronously in another python thread. The threading.Event blocks the main thread until a message is received. This unusual, but the question seems to ask for a way to block until the first message is received.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.