ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

For reference in case other people are interested: The complete plugin code with the corrections marked out by @dirk-thomas

import os
import rospy
import rospkg

from qt_gui.plugin import Plugin
from python_qt_binding import loadUi
from python_qt_binding.QtWidgets import QWidget
from python_qt_binding.QtCore import Signal, Slot

import std_srvs.srv as stdsrvs
from rosgraph_msgs.msg import Clock


class SimControl(Plugin):
    update_clock_signal = Signal(float)  # Update clock signal, has to be defined as class attribute

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

        # 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('ros_af_sim'),
                               'resource', 'sim_control.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names
        self._widget.setObjectName('SimControlUi')
        # 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()))

        # Set up handlers
        run_service = '/sim_control/run'
        print('Waiting for services')
        rospy.wait_for_service(run_service, timeout=5.0)
        self.s_run = rospy.ServiceProxy(run_service, stdsrvs.SetBool)

        self._widget.run_button.clicked[bool].connect(self._handle_run_clicked)
        self._widget.pause_button.clicked[bool].connect(
            self._handle_pause_clicked)

        self.update_clock_signal.connect(self._update_clock)  # Connect GUI updater to signal
        self.clock_sub = rospy.Subscriber('/clock', Clock, self._clock_sub)
        print("Finished setup")

        # Add widget to the user interface
        context.add_widget(self._widget)

    def shutdown_plugin(self):
        # Unregister all publishers here
        self.clock_sub.unregister()
        self.s_run.close()

    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 _handle_run_clicked(self):
        try:
            self.s_run(stdsrvs.SetBoolRequest(True))
        except rospy.service.ServiceException as e:
            print(e.message)

    def _handle_pause_clicked(self):
        try:
            self.s_run(stdsrvs.SetBoolRequest(False))
        except rospy.service.ServiceException as e:
            print(e.message)

    def _clock_sub(self, msg):
        clock = msg.clock.to_sec()
        self.update_clock_signal.emit(clock)  # Emit signal

    @Slot(float)
    def _update_clock(self, clock):
        self._widget.clock_field.setText('{}'.format(clock))

    # 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

For reference in case other people are interested: The complete plugin code with the corrections marked out by @dirk-thomas

import os
import rospy
import rospkg

from qt_gui.plugin import Plugin
from python_qt_binding import loadUi
from python_qt_binding.QtWidgets import QWidget
from python_qt_binding.QtCore import Signal, Slot

import std_srvs.srv as stdsrvs
from rosgraph_msgs.msg import Clock


class SimControl(Plugin):
    update_clock_signal = Signal(float)  # Update clock signal, has to be defined as class attribute

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

        # 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('ros_af_sim'),
                               'resource', 'sim_control.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names
        self._widget.setObjectName('SimControlUi')
        # 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()))

        # Set up handlers
        run_service = '/sim_control/run'
        print('Waiting for services')
        rospy.wait_for_service(run_service, timeout=5.0)
        self.s_run = rospy.ServiceProxy(run_service, stdsrvs.SetBool)

        self._widget.run_button.clicked[bool].connect(self._handle_run_clicked)
        self._widget.pause_button.clicked[bool].connect(
            self._handle_pause_clicked)

        self.update_clock_signal.connect(self._update_clock)  # Connect GUI updater to signal
        self.clock_sub = rospy.Subscriber('/clock', Clock, self._clock_sub)
        print("Finished setup")

        # Add widget to the user interface
        context.add_widget(self._widget)

    def shutdown_plugin(self):
        # Unregister all publishers here
        self.clock_sub.unregister()
        self.s_run.close()

    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 _handle_run_clicked(self):
        try:
            self.s_run(stdsrvs.SetBoolRequest(True))
        except rospy.service.ServiceException as e:
            print(e.message)

    def _handle_pause_clicked(self):
        try:
            self.s_run(stdsrvs.SetBoolRequest(False))
        except rospy.service.ServiceException as e:
            print(e.message)

    def _clock_sub(self, msg):
        clock = msg.clock.to_sec()
        self.update_clock_signal.emit(clock)  # Emit signal

    @Slot(float)
    def _update_clock(self, clock):
        self._widget.clock_field.setText('{}'.format(clock))

    # 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

For reference in case other people are interested: The complete plugin code with for the corrections marked out by @dirk-thomasworking plugin.

import os
import rospy
import rospkg

from qt_gui.plugin import Plugin
from python_qt_binding import loadUi
from python_qt_binding.QtWidgets import QWidget
from python_qt_binding.QtCore import Signal, Slot

import std_srvs.srv as stdsrvs
from rosgraph_msgs.msg import Clock


class SimControl(Plugin):
    update_clock_signal = Signal(float)  # Update clock signal, has to be defined as class attribute

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

        # 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('ros_af_sim'),
                               'resource', 'sim_control.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names
        self._widget.setObjectName('SimControlUi')
        # 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()))

        # Set up handlers
        run_service = '/sim_control/run'
        print('Waiting for services')
        rospy.wait_for_service(run_service, timeout=5.0)
        self.s_run = rospy.ServiceProxy(run_service, stdsrvs.SetBool)

        self._widget.run_button.clicked[bool].connect(self._handle_run_clicked)
        self._widget.pause_button.clicked[bool].connect(
            self._handle_pause_clicked)

        self.update_clock_signal.connect(self._update_clock)  # Connect GUI updater to signal
        self.clock_sub = rospy.Subscriber('/clock', Clock, self._clock_sub)
        print("Finished setup")

        # Add widget to the user interface
        context.add_widget(self._widget)

    def shutdown_plugin(self):
        # Unregister all publishers here
        self.clock_sub.unregister()
        self.s_run.close()

    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 _handle_run_clicked(self):
        try:
            self.s_run(stdsrvs.SetBoolRequest(True))
        except rospy.service.ServiceException as e:
            print(e.message)

    def _handle_pause_clicked(self):
        try:
            self.s_run(stdsrvs.SetBoolRequest(False))
        except rospy.service.ServiceException as e:
            print(e.message)

    def _clock_sub(self, msg):
        clock = msg.clock.to_sec()
        self.update_clock_signal.emit(clock)  # Emit signal

    @Slot(float)
    def _update_clock(self, clock):
        self._widget.clock_field.setText('{}'.format(clock))

    # 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