Reputation: 365
I am currently trying to make a ROS node in Python which has both a subscriber and a publisher.
I've seen examples where a message is published within the callback, but I want it to "constantly" publish messages, and perform callbacks when it is the case.
Here is how I do it now:
#!/usr/bin/env python
import rospy
from std_msgs.msg import Empty
from std_msgs.msg import String
import numpy as np
pub = rospy.Publisher('/status', String, queue_size=1000)
def callback(data):
print "Message received"
def listener():
rospy.init_node('control', anonymous=True)
rospy.Subscriber('control_c', Empty, callback)
rospy.spin()
if __name__ == '__main__':
print "Running"
listener()
So where should I publish?
Upvotes: 10
Views: 29148
Reputation: 5017
Simply replace rospy.spin()
with the following loop:
while not rospy.is_shutdown():
# do whatever you want here
pub.publish(foo)
rospy.sleep(1) # sleep for one second
Of course you can adjust the sleep duration to whatever value you want (or even remove it entirely).
According to this reference subscribers in rospy are running in a separate thread, so you don't need to call spin actively.
Note that in roscpp (i.e. when using C++) this is handled differently. There you have to call ros::spinOnce()
in the while loop.
Upvotes: 5
Reputation: 3130
Well, I think there's a lot of solutions here, you could even make use of a python process, but what I'm proposing is a ROS approach using a ros Timer.
I am not really that efficient in python but this code may gave you a heads up.
#!/usr/bin/env python
import rospy
from std_msgs.msg import Empty
from std_msgs.msg import String
import numpy as np
last_data = ""
started = False
pub = rospy.Publisher('/status', String, queue_size=1000)
def callback(data):
print "New message received"
global started, last_data
last_data = data
if (not started):
started = True
def timer_callback(event):
global started, pub, last_data
if (started):
pub.publish(last_data)
print "Last message published"
def listener():
rospy.init_node('control', anonymous=True)
rospy.Subscriber('control_c', String, callback)
timer = rospy.Timer(rospy.Duration(0.5), timer_callback)
rospy.spin()
timer.shutdown()
if __name__ == '__main__':
print "Running"
listener()
Here, your callback will update the message and your timer will fire up every 0.5sec and publishes the last data received.
you can test this code by publishing data on "/contriol_c" every 3 seconds and configuring you timer to 0.5 sec. start an echo on /status
$ rostopic echo /status
and you'll got your message published on a 2 Hz rate.
Hope that helps !
Upvotes: 6