Writing a ros node with both a publisher and subscriber?

Carlton Banks picture Carlton Banks · Nov 9, 2016 · Viewed 16.4k times · Source

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?

Answer

Vtik picture Vtik · Nov 10, 2016

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 !