ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
3

run a subscriber callback once using rospy.spin()

asked 2012-03-26 06:56:52 -0500

cduguet gravatar image

updated 2022-01-12 10:51:08 -0500

lucasw gravatar image

Hi,

I am sorry if I am not using the proper words when I refer to "run a callback function" from a subscriber while using rospy. I'm not sure I got the concept of keeping the nodes sleeping. However, this is not my question.

I want to make a logger node node which takes data from the first message received in a topic, and writes it as a header in a file. Then it will be storing the raw data as long as rospy.spin() says so. The problem is, I have not found an example of how to do this, or if there is such a function. All I can think about are pretty cluttered solutions, which take the time stamp and compares them in every message.

my question is, is there a way to call

rospy.Subscriber("Flow", OpticalFlow2D.msg.FrameFlow, callbackOF)

many times and

rospy.Subscriber("Flow", OpticalFlow2D.msg.FrameFlow, callbackOFonce)

just on the first time, to write the header?

Many thanks,

Cristian

edit retag flag offensive close merge delete

6 Answers

Sort by ยป oldest newest most voted
6

answered 2012-03-26 08:27:59 -0500

updated 2012-03-26 08:43:59 -0500

If you want a particular callback for a topic only to be run for the first message received, you can unsubscribe from within the callback after you've finished your processing. For example:

def cb_once(msg, subscriber):
    #do processing here
    subscriber.unregister()

sub_once = None
sub_once = rospy.Subscriber('my_topic,', MyType, cb_once, sub_once)

In your case, however, you could have a single callback, and just keep a flag around like wrote_header, which you can set to true after the first message was received so you only write the header once.

edit flag offensive delete link more

Comments

The above may not be entirely correct. The callback args may have to be an iterable, so the line would be sub_once = rospy.Subscriber('my_topic,', MyType, cb_once, [sub_once])

Dan Lazewatsky gravatar image Dan Lazewatsky  ( 2012-03-27 06:54:38 -0500 )edit

Based on the upvotes, I'm guessing this works for others. For me though, cb_once is receiving a None, and I get the exception "AttributeError: 'NoneType' object has no attribute 'unregister'".

Benjamin Blumer gravatar image Benjamin Blumer  ( 2014-06-10 18:11:16 -0500 )edit
1

answered 2014-06-10 18:18:52 -0500

Benjamin Blumer gravatar image

This: http://answers.ros.org/question/46613/rospy-how-do-you-unsubscribe-to-a-topic-from-within-the-callback/ solution works, at the cost of having to make the subscriber global.

edit flag offensive delete link more
1

answered 2012-03-27 06:24:47 -0500

cduguet gravatar image

Thank you!

I did it using a flag, because (I don't know why it doesn't work, because it usually does to me) the callback function does not get the argument sub_once, therefore throwing the error "cb_once needs exactly two arguments", and it is being given one (I don't know why it is not passing the argument, and yes, sub_once is given after the callback function name just as you wrote it).

Anyway, with the flags the problem is solved.

Thank you!

edit flag offensive delete link more

Comments

1

Would you mind giving an example of how you accomplished this in code?

Seanny123 gravatar image Seanny123  ( 2013-11-20 19:18:24 -0500 )edit
0

answered 2014-05-21 23:49:53 -0500

Captcha gravatar image

Hi, i tried the given code but my program was stuck on the rospy.spin() procedure after calling the callback for the forst time ! is there a way i can exit from that blocking statement to a next statement ? Thanks

edit flag offensive delete link more
0

answered 2016-09-07 01:25:12 -0500

siddian93 gravatar image

2 Steps : Flag set to 0 in the class __init__ method. Step 1 : I believe a better alternate is to define the call back method in a class along with the subscriber. And then setting a flag which will be set to one once the callback method has been called for the first time.

Step 2 : Once the Flag has been set 1, in the subscriber declaration block, return to the called block.

An Example is given below : (Tested Works)

class frontCam : def __init__(self): self.flag = 0 rospy.init_node("DFC") self.getVideo()

def getVideo(self) :
    rospy.Rate(1)
    self.image_sub = rospy.Subscriber('Subscribed TOPIC', Message_Type, self.callback )
    print 'Getting Video Feed . . . ' 
    if (self.flag == 1)
        return
    try :
        rospy.spin()
    except KeyboardInterrupt :
        print "Shutting Down"

def callback(self, data) :
    self.flag = 1

However if you guys want, can close the callback method after a certain period using the ropy.sleep() and the return statement as well.

edit flag offensive delete link more
0

answered 2020-03-05 21:19:46 -0500

my trick is create spinOnce function by calling it, the callback will be called

def spinOnce(self):
    r = rospy.Rate(self.rate)
    r.sleep()
edit flag offensive delete link more

Question Tools

3 followers

Stats

Asked: 2012-03-26 06:56:52 -0500

Seen: 19,571 times

Last updated: Jan 12 '22