Robotics StackExchange | Archived questions

Simple example of custom rqt plugin

Hi.

I would like to understand how to subscribe to a ROS topic from custom rqt plugin with Python. As for now i couldn't make it work. Can you provide some very simple example (or reference) to how to write a subscriber that updates some text in GUI based on topic data?

Thanks in advance.

EDIT: I have gone through rqt package tutorial from here and I created my own plugin. Now I want to subscribe to the data from the topic contains array of 8 integers to update 8 text labels. My problem is that the plugin is working for some time and eventually going down after 20-30seconds because of memory leakage This is my_module.py:

import os
import rospy
import rospkg
from std_msgs.msg import Int32MultiArray, String
import time
from qt_gui.plugin import Plugin
from python_qt_binding import loadUi
from python_qt_binding.QtWidgets import QWidget

class MyPlugin(Plugin):

def __init__(self, context):
    super(MyPlugin, self).__init__(context)
    # Give QObjects reasonable names
    self.setObjectName('MyPlugin')

    # Process standalone plugin command-line arguments
    from argparse import ArgumentParser
    parser = ArgumentParser()
    # Add argument(s) to the parser.
    parser.add_argument("-q", "--quiet", action="store_true",
                  dest="quiet",
                  help="Put plugin in silent mode")
    args, unknowns = parser.parse_known_args(context.argv())
    if not args.quiet:
        print 'arguments: ', args
        print 'unknowns: ', unknowns

    # Create QWidget
    self._widget = QWidget()
    # Get path to UI file which should be in the "resource" folder of this package
    ui_file = os.path.join(rospkg.RosPack().get_path('rqt_mypkg'), 'resource', 'MyPlugin.ui')
    # Extend the widget with all attributes and children from UI file
    loadUi(ui_file, self._widget)
    # Give QObjects reasonable names
    self._widget.setObjectName('MyPluginUi')
    # Show _widget.windowTitle on left-top of each plugin (when
    # it's set in _widget). This is useful when you open multiple
    # plugins at once. Also if you open multiple instances of your
    # plugin at once, these lines add number to make it easy to
    # tell from pane to pane.
    if context.serial_number() > 1:
        self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number()))
    # Add widget to the user interface
    context.add_widget(self._widget)

    #Subscriber
    self.sub_status = rospy.Subscriber('/random_status', String, self.callback_string, queue_size=20)
    self.sub = rospy.Subscriber("/random_ints", Int32MultiArray, self.callback, queue_size=20)

def shutdown_plugin(self):
    # TODO unregister all publishers here
    pass
def callback(self, msg):
    self._widget.label_10.setText(repr(msg.data[0]))
    self._widget.label_12.setText(repr(msg.data[1]))
    self._widget.label_14.setText(repr(msg.data[2]))
    self._widget.label_15.setText(repr(msg.data[3]))
    self._widget.label_17.setText(repr(msg.data[4]))
    self._widget.label_19.setText(repr(msg.data[5]))
    self._widget.label_21.setText(repr(msg.data[6]))
    self._widget.label_23.setText(repr(msg.data[7]))
def callback_string(self, msg):
    self._widget.label_2.setText(msg.data)

def save_settings(self, plugin_settings, instance_settings):
    # TODO save intrinsic configuration, usually using:
    # instance_settings.set_value(k, v)
    pass

def restore_settings(self, plugin_settings, instance_settings):
    # TODO restore intrinsic configuration, usually using:
    # v = instance_settings.value(k)
    pass

#def trigger_configuration(self):
    # Comment in to signal that the plugin has a way to configure
    # This will enable a setting button (gear icon) in each dock widget title bar
    # Usually used to open a modal configuration dialog

And MyPlugin.ui:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>913</width>
    <height>527</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QGraphicsView" name="graphicsView">
    <property name="geometry">
     <rect>
      <x>120</x>
      <y>80</y>
      <width>231</width>
      <height>291</height>
     </rect>
    </property>
   </widget>
   <widget class="QLabel" name="label_8">
    <property name="geometry">
     <rect>
      <x>40</x>
      <y>330</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QLabel" name="label_9">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>80</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor7</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_10">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>100</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_11">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>330</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor6</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_12">
    <property name="geometry">
     <rect>
      <x>30</x>
      <y>350</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_13">
    <property name="geometry">
     <rect>
      <x>130</x>
      <y>400</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor5</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_14">
    <property name="geometry">
     <rect>
      <x>130</x>
      <y>420</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_15">
    <property name="geometry">
     <rect>
      <x>280</x>
      <y>420</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_16">
    <property name="geometry">
     <rect>
      <x>280</x>
      <y>400</y>
      <width>67</width>
      <height>16</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor4</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_17">
    <property name="geometry">
     <rect>
      <x>380</x>
      <y>350</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_18">
    <property name="geometry">
     <rect>
      <x>380</x>
      <y>330</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor3</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_19">
    <property name="geometry">
     <rect>
      <x>380</x>
      <y>100</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_20">
    <property name="geometry">
     <rect>
      <x>380</x>
      <y>80</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor2</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_21">
    <property name="geometry">
     <rect>
      <x>130</x>
      <y>40</y>
      <width>61</width>
      <height>16</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_22">
    <property name="geometry">
     <rect>
      <x>130</x>
      <y>20</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor0</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_23">
    <property name="geometry">
     <rect>
      <x>270</x>
      <y>40</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>140cm</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_24">
    <property name="geometry">
     <rect>
      <x>270</x>
      <y>20</y>
      <width>67</width>
      <height>17</height>
     </rect>
    </property>
    <property name="text">
     <string>Sensor1</string>
    </property>
   </widget>
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>510</x>
      <y>210</y>
      <width>191</width>
      <height>31</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>21</pointsize>
     </font>
    </property>
    <property name="text">
     <string>Status:</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_2">
    <property name="geometry">
     <rect>
      <x>700</x>
      <y>210</y>
      <width>170</width>
      <height>31</height>
     </rect>
    </property>
    <property name="font">
     <font>
      <pointsize>26</pointsize>
      <italic>true</italic>
     </font>
    </property>
    <property name="text">
     <string>TextLabel</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>913</width>
     <height>22</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuSafety">
    <property name="title">
     <string>Control</string>
    </property>
   </widget>
   <widget class="QMenu" name="menuControl">
    <property name="title">
     <string>Safety</string>
    </property>
   </widget>
   <addaction name="menuSafety"/>
   <addaction name="menuControl"/>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

I understand that I should use Qt signals in order to implement it, but I don't really know how to do it that's why I ask for help. Thanks in advance.

Asked by rosuseruser on 2018-11-09 05:39:12 UTC

Comments

Perhaps lucasw/rqt_mypkg can help.

Asked by gvdhoorn on 2018-11-09 06:29:22 UTC

Thanks. However, I cannot find any declaration of subscriber/publisher there?

Asked by rosuseruser on 2018-11-09 06:56:02 UTC

I'd missed the part about the subscriber. In general you'd create your subscribers (and publishers) in the ctor though.

For other readers:

As for now i couldn't make it work.

this is typically not enough information. Please describe what you've tried and what exactly is failing for you.

Asked by gvdhoorn on 2018-11-09 07:51:30 UTC

I edited the question and gave more information.

Asked by rosuseruser on 2018-11-09 16:49:29 UTC

Answers