Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

rospy.spin() is a blocking call. See

rospy.spin() is a blocking call. See more details

add more detailsedit: shoot accidentally deleted my answer

edit: shoot accidentally deleted my answeranswer, will fix now

edit: shoot accidentally deleted my answer, will fix nowrospy.spin() is a blocking call:

Here is the source of spin():

def spin():
    Blocks until ROS node is shutdown. Yields activity to other threads.
    @raise ROSInitException: if node is not in a properly initialized state

    if not rospy.core.is_initialized():
        raise rospy.exceptions.ROSInitException("client code must call rospy.init_node() first")
    logdebug("node[%s, %s] entering spin(), pid[%s]", rospy.core.get_caller_id(), rospy.core.get_node_uri(), os.getpid())        
        while not rospy.core.is_shutdown():
    except KeyboardInterrupt:
        logdebug("keyboard interrupt, shutting down")
        rospy.core.signal_shutdown('keyboard interrupt')

A key observation here is the contents of the "try" block. All spin() does is wait for rospy to shutdown. If you are doing this yourself, there is no need for rospy.spin().

Okay, on to cvancleef's comment on while loops and timers. Let's take a quick look at the implementation of timer, starting line 178 here:

First thing to note is that Timer extends threading.Thread. Python's (at least cpython, which is the standard distro that you download from the site) threading.Thread is not a native thread. That is to say, the interpreter decides what order to execute commands, but nothing happens in parallel. This means you don't really get any guarantees as for timing nor do you really get much as far as performance benefits. If that's what you need you would have to make your own threads using the multiprocessing module instead.

Here is the run() function:

def run(self):
    r = Rate(1.0 / self._period.to_sec())
    current_expected = rospy.rostime.get_rostime() + self._period
    last_expected, last_real, last_duration = None, None, None
    while not rospy.core.is_shutdown() and not self._shutdown:
        except rospy.exceptions.ROSInterruptException as e:
            if rospy.core.is_shutdown():
        if self._shutdown:
        current_real = rospy.rostime.get_rostime()
        start = time.time()
        self._callback(TimerEvent(last_expected, last_real, current_expected, current_real, last_duration))
        if self._oneshot:
        last_duration = time.time() - start
        last_expected, last_real = current_expected, current_real
        current_expected += self._period

Just like rospy.spin(), all it really does is a while loop checking for ros still being alive, and calls your function if the expected duration has passed. Not really much different from using Rate().