The Easiest Way of (inter) Thread-Communication for Python
Connecting VTK and ROS or ROS and GTK by using Python always causes some kind of trouble because there is a main-thread and some other thread. Whereby, everyone (ROS, VTK, GTK, ETC.) wants to be the main-thread and calling a function/method from another thread is mostly the main-problem. There is one pretty simple solution to all of these problems, namely publish-subscribe or in other words the Python pubsub module. Its usage is quite similar to the usage of pub/sub in ROS.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys, time
from pubsub import pub
from PyQt4 import QtGui
from PyQt4.QtCore import QThread
import roslib
import rospy
from std_msgs.msg import String
# ROS - Worker Thread
class RosThread(QThread):
def __init__(self, topic, parent = None):
QThread.__init__(self, parent)
self.sub = rospy.Subscriber(topic, String, self.callback)
def run(self):
rospy.spin()
def callback(self, msg):
pub.sendMessage('update', string=msg.data )
# Qt - Worker Thread
class WorkerThread(QThread):
def __init__(self, name, sleep, parent = None):
QThread.__init__(self, parent)
self.sleep = sleep
self.name = name
def run(self):
while(True):
time.sleep(self.sleep)
pub.sendMessage('update', string="update: "+self.name)
# Minimal GUI
class Gui(QtGui.QWidget):
def __init__(self):
super(Gui, self).__init__()
self.button = QtGui.QPushButton('Change', self)
self.button.move(20, 20)
self.button.clicked.connect(self.showDialog)
self.text = QtGui.QLabel(self)
self.text.setText('XXXXXXXXXXXXXXXXXXXXXXXX')
self.text.move(100, 22)
self.setGeometry(300, 300, 290, 60)
self.show()
# Update the Gui from the GUI
def showDialog(self):
text, ok = QtGui.QInputDialog.getText(self, 'Change Label', 'String:')
if ok:
self.text.setText(str(text))
# callback method for pubsub
def setLabel(self, string):
self.text.setText(string)
# create a GUI
app = QtGui.QApplication(sys.argv)
gui = Gui()
# connect method 'gui.setLabel' with topic 'update'
pub.subscribe(gui.setLabel, 'update')
# create two simple Worker Threads
worker1 = WorkerThread("worker1", 5)
worker2 = WorkerThread("worker2", 2.5)
worker1.start()
worker2.start()
# create ROS-node
rospy.init_node('test')
ros1 = RosThread("sub1")
ros1.start()
# run main Thread
sys.exit(app.exec_())
The example from above executes two Qt worker threads, one ROS thread, and of course one main thread that is responsible for the GUI.

The GUI consists of a single button and a label, which is updated by the user or the different threads. See line 67, the command ‘pub.subscribe(method, topic)’is everything to connect any method with a certain topic. Afterwards this methods can be called from any thread with command ‘pub.sendMessage(topic, data)’ see lines 24 and 35. Test messages to the ROS node can be send with the following shell-command:
$ rostopic pub sub1 std_msgs/String '{"data":"test"}'
the same works also with VTK, GTK, …