在ROS中利用PyQt写GUI程序

Posted lwlv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在ROS中利用PyQt写GUI程序相关的知识,希望对你有一定的参考价值。

前段时间买了本王硕、孙洋洋写的《PyQt5快速开发与实战》,大致浏览了下,内容新,熟悉Qt5的人还是挺容易上手的。书中使用的环境为windows,PyQt5.9,Python3.5,Eric 6,Qt 5.9。笔者在自己的电脑上用的win7,Python3.6,PyQt5和PyCharm搭载了该环境,并写了一些测试小程序。PyQt可以在Riverbank上下到。Riverbank这个公司还提供了很多很好玩的库,如QScintilla,PyQtChart等,可以研究研究。

 

在之前的博文 三种方法在ROS中加载Qt库进行GUI设计 中留下了一个问题,有些ros程序中,如rqt_reconfigure,rqt_plot都是用python和pyqt写的,但依赖于rqt这个框架。(补充:用rviz框架也可写gui界面,详见古月居的博文 ROS探索总结(三十四)——rviz plugin

 

今天主要讲讲如何在linux平台上搭建环境并编写ros-pyqt程序:

首先,我们需了解了解如何写pyqt程序,其实就是python封装的qt库,下载好PyQt5后,在PyCharm IDE导入即可,界面设计既可以用代码自己写,也可以用UI。用UI设计还是更直观,能很快看到效果,大多数人偏好,就是配置麻烦点。这里还是得借助Qt的Designer。一是在PyCharm的设置中选择External Tools,添加Qt designer的可执行路径;二是需要用uic工具将UI文件转换为py文件。不过好在ros程序中,可以用python_qt_binding模块中的loadUi读.ui文件。

据python_qt_binding包的描述:This stack provides Python bindings for Qt. There are two providers: pyside and pyqt. PySide is released under the LGPL. PyQt is released under the GPL. Both the bindings and tools to build bindings are included from each available provider. Also provided is adapter code to make the user's Python code independent of which binding provider was actually used which makes it very easy to switch between these.也就是说python与qt的绑定采用了PyQt和PySide方式的库,只是这两种库在不同的协议下。PyQt是Riverbank开发,而PySide是Qt社区官方开发。在网上查了下,两者语法还挺像的。

其次,在ros环境下,安装好pycharm后(可在其官网下载到不同版本的免费Community),加入bash -i -c用于找到ros环境变量,详见ROS_IDES

安装pycharm时,可能会遇到 "No JDK found. Please validate either PYCHARM_JDK, JDK_HOME or JAVA_HOME environment variable points to valid JDK installation. " 的错误,是因为缺少JDK库。

解决方法:

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer

然后输入java -version,如提示有

java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) Client VM (build 25.171-b11, mixed mode)

则说明安装成功,再装pycharm就不会出现问题。

 

如安装ros完整版,会自动安装pyqt4和pyside(可以通过ipython进入后,导入这两个模块试试看,无错误则表明模块是成功的),语法跟qt4很像。虽然qt5和qt4有点差别,但基本模式还是一样。

下面笔者用两种方法进行了界面设计。

1、直接用代码编写界面:

#!/usr/bin/env python

import sys
import rospy
from std_msgs.msg import String
from PyQt4 import QtGui
from PyQt4.QtGui import QLabel, QVBoxLayout, QHBoxLayout, QSlider, QPushButton
from PyQt4.QtCore import Qt

class PyGui(QtGui.QWidget):
    def __init__(self):
        super(PyGui, self).__init__()
        self.setObjectName('PyGui')
        self.pub = rospy.Publisher("pyqt_topic", String, queue_size=10)
        rospy.init_node('pyqt_gui')
        self.current_value = 0
        my_layout = QHBoxLayout()
        my_btn = QPushButton()
        my_btn.setText("Publisher")
        my_btn.setFixedWidth(130)
        my_btn.clicked.connect(self.publish_topic)
        my_layout.addWidget(my_btn)
        my_layout.addSpacing(50)
        self.my_label = QLabel()
        self.my_label.setFixedWidth(140)
        self.my_label.setText("num: " + str(0))
        self.my_label.setEnabled(False)
        my_layout.addWidget(self.my_label)
        my_slider = QSlider()
        my_slider.setMinimum(0)
        my_slider.setMaximum(99)
        my_slider.setOrientation(Qt.Horizontal)
        my_slider.valueChanged.connect(self.changeValue)
        my_vlay = QVBoxLayout()
        my_vlay.addWidget(my_slider)
        layout = QVBoxLayout()
        layout.addLayout(my_layout)
        layout.addLayout(my_vlay)
        self.setLayout(layout)
        # self.show()

    def publish_topic(self):
        self.pub.publish(str(self.current_value))

    def changeValue(self, value):
        self.my_label.setText("num: " + str(value))
        self.current_value = value


if __name__ == "__main__":
    app=QtGui.QApplication(sys.argv)
    pyShow = PyGui()
    pyShow.show()
    sys.exit(app.exec_())

运行后的效果如下:

2、通过qt designer设计界面,由于有ui文件,因此需要引入python_qt_binding模块,详细介绍可参考  http://wiki.ros.org/python_qt_binding,有空得稍微研究下源码,看看具体怎么实现的。

工程代码如下:

#!/usr/bin/env python

import os, sys
import rospy
from std_msgs.msg import String
from python_qt_binding import loadUi
from PyQt4 import QtGui

class pyGui(QtGui.QWidget):
    def __init__(self):
        super(pyGui, self).__init__()
        self_dir = os.path.dirname(os.path.realpath(__file__))
        print self_dir
        self.ui_dir = os.path.join(self_dir, '../ui')
        ui_file = os.path.join(self.ui_dir, 'pygui.ui')
        loadUi(ui_file, self)
        self.pub = rospy.Publisher("pygui_topic", String, queue_size=10)
        rospy.init_node('py_gui')
        self.is_pub = False
        self.current_value = self.horizontalSlider.value()
        print self.current_value
        self.label.setText("num: " + str(self.current_value))
        self.pushButton.pressed.connect(self.publish_topic)
        self.pushButton_2.pressed.connect(self.gui_close)
        self.horizontalSlider.valueChanged.connect(self.change_value)

    def publish_topic(self):
        self.pub.publish(str(self.current_value))
        self.pushButton.setEnabled(False)
        self.is_pub = True

    def change_value(self, value):
        self.current_value = value
        if True == self.is_pub:
            self.label.setText("num: " + str(value))
            self.pub.publish(str(self.current_value))

    def gui_close(self):
        self.close()


def main():
    app=QtGui.QApplication(sys.argv)
    pyShow = pyGui()
    pyShow.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

运行后的效果如下:

 

这样我们便可以自己用pyqt设计界面了,而不依赖于rqt plugin。

 

整个工程的代码可在https://github.com/WelinLee/ROS_QT_GUI中的ros_pyqtpyqt_gui文件夹中找到。

Enjoy!

以上是关于在ROS中利用PyQt写GUI程序的主要内容,如果未能解决你的问题,请参考以下文章

ORBSLAM2在ROS下运行

如何在 PyQt5 GUI 中删除一个拉伸?

利用python写一个gui小公举--制作一个小公举

在树莓派上用PyQt5写GUI出现视频卡死

禁用从 GUI (PyQt) 打开 cmd

PyQt5快速上手基础篇1-开发环境搭建