Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a ros node with both a publisher and subscriber?

Tags:

python

ros

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?

like image 997
Carlton Banks Avatar asked Nov 09 '16 13:11

Carlton Banks


2 Answers

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 !

like image 61
Vtik Avatar answered Oct 03 '22 23:10

Vtik


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.

like image 31
luator Avatar answered Oct 04 '22 00:10

luator