Skip to content

GUI controls as ROS 2 rqt plugin #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: ros2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Furthermore, this framework provides several interfaces that allow humans to int

# Requirements

* ROS2 Foxy
* Ubuntu 20.04
* ROS2 Humble Hawksbill
* Ubuntu 22.04
* Python 3

# Cite
Expand Down
30 changes: 30 additions & 0 deletions ros_pybullet_rqt_plugin/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>ros_pybullet_rqt_plugin</name>
<version>1.0.0</version>
<description>ROS2-based RQT plugin for ROS-PyBullet Interface.</description>
<maintainer email="[email protected]">Jan Kaniuka</maintainer>
<license>TODO: License declaration</license>

<test_depend>ament_copyright</test_depend>
<test_depend>ament_flake8</test_depend>
<test_depend>ament_pep257</test_depend>
<test_depend>python3-pytest</test_depend>

<exec_depend version_gte="0.2.19">python_qt_binding</exec_depend>
<exec_depend>rqt_gui</exec_depend>
<exec_depend>rqt_gui_py</exec_depend>
<exec_depend>rqt_py_common</exec_depend>
<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>

<depend>ros_pybullet_msgs</depend>
<depend>std_srvs</depend>


<export>
<build_type>ament_python</build_type>
<rqt_gui plugin="${prefix}/plugin.xml"/>
</export>
</package>
17 changes: 17 additions & 0 deletions ros_pybullet_rqt_plugin/plugin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<library path="./">
<class name="PyBulletInterfaceControls" type="ros_pybullet_rqt_plugin.ros2_pybullet_interface_controls.Ros2PyBulletInterfaceControls" base_class_type="rqt_gui_py::Plugin">
<description>
RQT plugin used to perform basic interactions with ROS-PyBullet Interface.
</description>
<qtgui>
<group>
<label>Introspection</label>
<icon type="theme">folder</icon>
<statustip>Plugins related to introspection.</statustip>
</group>
<label>PyBullet Interface Controls</label>
<icon type="theme">input-gaming</icon>
<statustip>A Python GUI plugin for ROS-PyBullet Interface.</statustip>
</qtgui>
</class>
</library>
207 changes: 207 additions & 0 deletions ros_pybullet_rqt_plugin/resource/PyBulletInterfaceControls_layout.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ROS</class>
<widget class="QWidget" name="ROS">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>560</width>
<height>320</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>560</width>
<height>320</height>
</size>
</property>
<property name="windowTitle">
<string>ROS</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="PyBulletLogo">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>images/pybullet_logo.svg</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="text_box">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="text">
<string>Initialization</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="start_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Start </string>
</property>
<property name="icon">
<iconset>
<normaloff>images/start_icon.png</normaloff>images/start_icon.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="send_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Send </string>
</property>
<property name="icon">
<iconset>
<normaloff>images/send_icon.png</normaloff>images/send_icon.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="step_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Step </string>
</property>
<property name="icon">
<iconset>
<normaloff>images/step_icon.png</normaloff>images/step_icon.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>23</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stop_button">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Stop </string>
</property>
<property name="icon">
<iconset>
<normaloff>images/stop_icon.png</normaloff>images/stop_icon.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
11 changes: 11 additions & 0 deletions ros_pybullet_rqt_plugin/resource/images/pybullet_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Empty file.
9 changes: 9 additions & 0 deletions ros_pybullet_rqt_plugin/ros_pybullet_rqt_plugin/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import sys
from rqt_gui.main import Main

def main():
main = Main()
sys.exit(main.main(sys.argv, standalone='ros_pybullet_rqt_plugin.ros2_pybullet_interface_controls.Ros2PyBulletInterfaceControls'))

if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import os
from ament_index_python import get_resource
from python_qt_binding import loadUi
from python_qt_binding.QtCore import QProcess
from python_qt_binding.QtWidgets import QWidget
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from std_msgs.msg import Int64
from std_srvs.srv import Trigger

class PyBulletInterfaceControls(QWidget):

def __init__(self, node, plugin=None):

super(PyBulletInterfaceControls, self).__init__()

self._node = node
self.process = QProcess(self)
self._plugin = plugin

_, package_path = get_resource('packages', 'ros_pybullet_rqt_plugin')
ui_file = os.path.join(package_path, 'share', 'ros_pybullet_rqt_plugin', 'resource', 'PyBulletInterfaceControls_layout.ui')
loadUi(ui_file, self)

self.start_button.pressed.connect(self.start_button_handler)
self.send_button.pressed.connect(self.send_button_handler)
self.step_button.pressed.connect(self.step_button_handler)
self.stop_button.pressed.connect(self.stop_button_handler)

self.subscription = self._node.create_subscription(
Int64,
'rpbi/status',
self.status_callback,
10)


def start_button_handler(self):
self.get_srv_handler('rpbi/start', Trigger)

def step_button_handler(self):
self.get_srv_handler('rpbi/step', Trigger)

def stop_button_handler(self):
self.get_srv_handler('rpbi/stop', Trigger)

def send_button_handler(self):
pass

def status_callback(self, msg):
self.text_box.setText("Status: " + str(msg.data))

def get_srv_handler(self, srv_name: str, srv_type: type):
handler = None
handler = self._node.create_client(srv_type, srv_name)
handler.wait_for_service(timeout_sec = 2.0) # wait 2 seconds
self._node.get_logger().info('Service ' + srv_name + ' not available.')
return handler

def start(self):
pass

def shutdown_plugin(self):
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from rqt_gui_py.plugin import Plugin
from .pybullet_interface_controls_widget import PyBulletInterfaceControls

class Ros2PyBulletInterfaceControls(Plugin):

def __init__(self, context):
super(Ros2PyBulletInterfaceControls, self).__init__(context)
self._node = context.node
self._logger = self._node.get_logger().get_child('ros_pybullet_rqt_plugin.ros2_pybullet_interface_controls.Ros2PyBulletInterfaceControls')

super(Ros2PyBulletInterfaceControls, self).__init__(context)
self.setObjectName('Ros2PyBulletInterfaceControls')

self._widget = PyBulletInterfaceControls(context.node, self)

self._widget.start()
if context.serial_number() > 1:
self._widget.setWindowTitle(
self._widget.windowTitle() + (' (%d)' % context.serial_number()))
context.add_widget(self._widget)
4 changes: 4 additions & 0 deletions ros_pybullet_rqt_plugin/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[develop]
script_dir=$base/lib/ros_pybullet_rqt_plugin
[install]
install_scripts=$base/lib/ros_pybullet_rqt_plugin
Loading