如何基于PyQt5实现ROS人机交互软件(python语言)

本文介绍了如何在ROS2环境中使用PyQt5创建用户界面,包括安装环境设置、QtDesigner设计UI、创建功能包、编写并测试代码,以及展示了一个实例,展示了如何实现实时消息传递和UI更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文参考课程链接为:古月学院课程《如何基于PyQt5实现ROS人机交互软件 • 蒋程扬》

ROS2学习资料为:ROS2官方文档

ROS2课程学习链接为:古月居·ROS2入门21讲

一、本机开发环境说明

虚拟机版本Ubuntu操作系统ROS操作系统qt creator版本
VMWare17Ubuntu 22.04 LTSROS2 Humble

5.12.9

下载链接:qt不同版本下载链接

二、前期准备工作        

        我在Ubuntu下安装了qtcreator后,就自带python库PyQt5PyQt5-tools开发工具,在VSCode中下载插件(python、PYQT Integration、Qt for python),终端采用

sudo apt install pyqt5-dev-tools

sudo apt install pyqt5-dev-tools安装pyuic

pyuic5的作用为:Qt通过其专门的界面设计(Qt Designer),可很方便的通过拖拉拽的方式去生成界面,Qt将其界面以 .ui 的后缀进行保存,在pyqt5中通过命令pyuic5 $FileNsetupUiame$ -o $FileNameWithoutExtension$.py(后边会详细说明)即可将.ui文件转化为.python文件进行代码使用。

 三、ROS2环境下创建PyQt5功能包

        ROS环境下使用PyQt5的基本思路是:先创建python功能包,接着导入pyqt5直接使用。事实上不创建功能包,仅仅通过一个py文件就可以使用ROS与PyQt5,这里创建功能包(主要作用是)将py文件封装成一个标准的ROS可识别的可执行程序,以便使用ROS的生态,如通过rosrun等运行功能包。创建基于python的ROS2功能包步骤如下:

1. 创建工作空间

mkdir -p ~/ros2_ws/src

2. 来到工作空间src目录下执行创建功能包指令:

ros2 pkg create --build-type ament_python --node-name ros2_pyqt5_app ros2_pyqt5_app

创建成功如下图所示: 

3. 编译工作空间

cd ~/ros2_ws
colcon build

4. source工作空间到环境变量

cd ~/ros2_ws
source ./install/setup.sh

5. 在ros2_ws下运行功能包

ros2 run ros2_pyqt5_app ros2_pyqt5_app

运行功能包效果如下图所示。终端会打印一句python文件自带的一句打印输出(Hi from ros2_pyqt5_app.
) 

四、实例1

1. 在Qt 5 Designer中设计UI界面

双击打开Qt 5 designer

会提示如下界面:

        依次选择Main Window、create、如下图所示:

点击create后,出现如下界面:

在红色框框内进行拖拽左侧的一系列控件,我这里拖拽一个文本显示控件Label控件,如下图所示:

拖拽好label控件后,CTRL+S保存,会提示保存在哪里。你要先去ros2_ws工作空间的以下目录(~/ros2_ws/src/ros2_pyqt5_app/ros2_pyqt5_app)创建一个ui文件夹,如下图所示:

然后再掉过头来在Qt Designer设计器保存那里选择你刚才创建的ui文件夹双击进去,点击save。如下图所示:

保存以后,你会看到ui文件夹里面多了一个.ui文件:

2. 将UI界面设计好的.ui文件通过pyuic5的命令自动生成.py文件 

这个.ui文件就是你刚才在Qt Designer设计器里面的UI界面拖拽了一个label控件的那个UI界面。在ui文件夹里面的空白处右键,打开终端,输入以下命令:【这里解释一下该句命令的含义:用pyuic5将untitled.ui文件,自动生成mainwindow_ui.py这个python文件。mainwindow_ui.py这个python文件的命名可以自己随意命名。】

pyuic5 untitled.ui -o mainwindow_ui.py

会看到ui文件夹里面多出了一个文件(上面那个pyuic5命令自动生成的):

3. 需要在ui文件夹内新建一个空白.py文件 

然后需要在ui文件夹里面新建一个空的python文件(__init__.py),因为不新建这个空文件,后续UI文件夹就不会成为我们的一个模块,影响后续的执行。命令如下(在ui文件夹里面直接打开终端,输入以下命令):

touch __init__.py

4. 复制UI文件夹到指定路径下 

然后,将ui文件夹复制到该目录下(~/ros2_ws/install/ros2_pyqt5_app/lib/python3.10/site-packages/ros2_pyqt5_app),原因也是不复制会影响后续代码运行,如下图所示:

5. 编写代码ros2_pyqt5_app.py文件 

复制好以后就开始编写代码,我直接右键ros2_ws下的src,用其他方式打开,选择VSCode,如下图所示:

看到VSCode中显示如上图四行代码,我们就是要在这个python文件里面编写代码。在写代码前,先看一下ui文件里面之前用pyuic5命令自动生成的python文件里面都有哪些内容吧,内容如下:

后边也主要是用UI_MainWindow这个类。

接下来开始编写代码(ros2_pyqt5_app.py文件)如下:

#encoding utf-8
import sys
import threading
import time
import rclpy
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget
from PyQt5.QtCore import QObject, pyqtSignal, QTimer
from std_msgs.msg import String
from rclpy.node import Node
from ui.mainwindow_ui import *

# 定义ROS节点和Qt信号的类
class RclCommNode(Node, QObject):
    signal_recv_msg = pyqtSignal(str)  # 自定义的Qt信号,用于在ROS和Qt之间传递消息

    def __init__(self):
        Node.__init__(self, "ros2_pyqt5_demo")  # 初始化ROS节点
        QObject.__init__(self)  # 初始化Qt对象
        self.chatter_publisher = self.create_publisher(String, "ros2_chatter", 10)  # 创建ROS发布者
        self.chatter_subscriber = self.create_subscription(String, "ros2_chatter", self.chatter_callback, 10)  # 创建ROS订阅者

        # 定时器,每秒发布一次车速信息
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.publish_speed)
        self.timer.start(1000)

    # ROS订阅回调函数,当接收到消息时触发
    def chatter_callback(self, data):
        msg = data.data
        print("接收到消息:", msg)
        self.signal_recv_msg.emit(msg)  # 发送Qt信号,通知Qt界面更新

    # 发布车速信息
    def publish_speed(self):
        # 生成在[0, 100]范围内的带有一位小数的虚拟车速信息
        speed_value = round((time.time() % 100), 1)
        speed_msg = String()
        speed_msg.data = "车速: {} m/s".format(speed_value)
        self.chatter_publisher.publish(speed_msg)

# Qt主窗口类
class MainWindow(QMainWindow,Ui_MainWindow):
    def __init__(self, comm_node):
        super(MainWindow, self).__init__()
        self.setupUi(self)        
        comm_node.signal_recv_msg.connect(self.set_label_text)  # 将Qt信号连接到更新界面的方法

    # 更新标签文本的方法
    def set_label_text(self, msg):
        self.label.setText("接收到的消息: " + msg)

# 在单独线程中运行ROS节点的spin函数
def ros_spin(node):
    while True:
        rclpy.spin_once(node)
        time.sleep(0.1)

# 主函数
def main(args=None):
    rclpy.init(args=args)
    app = QApplication(sys.argv)

    # 创建ROS节点和Qt主窗口
    commNode = RclCommNode()
    w = MainWindow(commNode)
    w.show()
    # 在单独线程中运行ROS节点的spin函数
    thread_spin = threading.Thread(target=ros_spin, args=(commNode,))
    thread_spin.start()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

6. 测试代码方法1 

编写完毕代码后,如何进行测试呢?

第一种测试方法:找到该路径后在该路径下打开终端(~/ros2_ws/src/ros2_pyqt5_app/ros2_pyqt5_app),

在终端输入:

python3 ./ros2_pyqt5_app.py

输入命令后回车

会看到如下:

测试成功,这里的例子就是为了先在UI界面上拖拽一个laebl文本控件,然后通过ROS发布随机车速消息,再订阅这个车速消息后,将其显示在提前设计好的UI界面的label文本框内。

7. 测试代码方法2 

测试方法2(不用python3的命令,用ROS命令。python3命令仅需要在指定文件夹内敲一行命令即可,很方便,很适合自己平时私下测试代码,倘若要与别的开发模块集成,就需要用到colcon build等命令了)

测试方法2需要修改一行代码,如下(在 ui.mainwindow_ui 前面加个点(.)):

from .ui.mainwindow_ui import *

加了(.)以后才能用ros2 run运行成功,这是区别于python3 测试的区别。具体运行命令如下:

在ros2_ws下打开终端运行:

colcon build

编译成功以后继续source环境变量,然后运行功能包节点:

source ./install/setup.sh
ros2 run ros2_pyqt5_app ros2_pyqt5_app

运行成功以后可以看到测试成功,如下图所示。

8. 查看话题及节点 

我们来看下运行代码的时候,都有哪些话题消息,都有哪些节点在运行

打开任意终端输入以下命令可以看到话题消息

ros2 topic list

再输入以下命令可以看到当前运行节点

rqt_graph

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值