【开源】基于Qt5与ROS的跨平台机器人控制界面开发实战(支持地图编辑/多机协同)
1. 为什么你需要一个自己的机器人控制界面?
如果你正在玩机器人,不管是ROS1还是ROS2,大概率都用过Rviz或者RQT。它们功能强大,但用久了总会有点“不得劲”。比如,你想在一个界面上同时看到地图、机器人位置、相机画面,还能随手画个导航点或者擦掉地图上错误的障碍物,你会发现需要打开好几个工具,来回切换,非常麻烦。更别提你想把这个界面放到一个性能不高的工控机或者边缘设备上,Rviz有时候就显得有点“笨重”了。
这就是我当初决定自己动手,用Qt5从头撸一个机器人控制界面的原因。我的核心诉求很简单:一个界面,搞定所有常用的监控和控制操作;一套代码,能在ROS1和ROS2上无缝切换;并且要足够轻量,能在树莓派这类设备上流畅运行。
经过一段时间的折腾,就有了这个开源项目。它不是一个简单的Rviz插件,而是一个完全独立的应用。所有的界面元素,从按钮、仪表盘到地图显示,都是我用Qt5的绘图功能一点点画出来的,没有依赖Qt Designer拖控件。这样做的好处是,代码耦合度低,性能可控,而且跨平台部署时几乎不会遇到奇怪的界面兼容性问题。你可以在Windows、Linux甚至macOS上编译它,只要那里有ROS环境(或者能通过某种方式和ROS机器人通信)。
这个界面最实用的几个功能,也是大家问得最多的,我总结为三点:所见即所得的地图编辑、直观的多机协同管理、以及开箱即用的多点导航链。 接下来,我就带你从零开始,把这个项目跑起来,并深入聊聊这几个功能怎么用,以及背后的一些设计小心思。
2. 从零开始:5分钟搞定环境与编译
很多朋友一看到“Qt”、“CMake”、“ROS”这几个词堆在一起,就觉得头大,感觉配置环境会是一场噩梦。其实不然,这个项目为了最大化降低使用门槛,在构建上做了很多简化。你甚至可以不安装QtCreator,只用命令行就能搞定一切。
2.1 极简依赖安装
首先,我们只需要安装最核心的Qt库和SVG支持(因为一些图标用了SVG格式)。打开你的Ubuntu终端(我假设你用的是ROS最常见的Ubuntu系统),执行下面两行命令就差不多了:
sudo apt-get update
sudo apt-get install qtbase5-private-dev libqt5svg5-dev -y
这里的 qtbase5-private-dev 是关键,它包含了一些Qt内部的头文件,是我们手动绘制控件所必需的。如果编译时还提示缺东西,别慌,执行下面这个“全家桶”安装命令,肯定能搞定:
sudo apt-get install qtbase5-dev qt5-qmake qtbase5-dev-tools libqt5svg5-dev qtbase5-private-dev libeigen3-dev libgtest-dev -y
安装完成后,你的系统自带的Qt5环境就准备好了。这里有个很重要的点: 我们用的是系统自带的Qt库,而不是你自己从Qt官网下载安装的那个。这能避免很多库路径冲突的玄学问题。
2.2 一键获取代码与编译
接下来,把代码拉取到本地。我建议专门建个工作目录:
mkdir -p ~/robot_gui_ws
cd ~/robot_gui_ws
git clone https://github.com/chengyangkj/Ros_Qt5_Gui_App
如果GitHub速度慢,可以用我在Gitee上维护的镜像,速度飞起:
git clone https://gitee.com/chengyangkj/Ros_Qt5_Gui_App
代码拉下来后,进入目录,你会发现里面并没有ROS功能包常见的 package.xml 文件。这是因为项目采用了标准的CMake构建,而不是Catkin或Colcon。这样做是为了实现ROS1/ROS2的版本无感切换。编译步骤非常简单:
cd Ros_Qt5_Gui_App
mkdir -p build
cd build
cmake ..
make -j4 # 使用4个线程并行编译,速度更快
编译脚本会自动检测你当前 source 的ROS环境是1还是2,并链接对应的ROS客户端库。如果你需要明确指定ROS版本,项目根目录也提供了便捷脚本:
# 在项目根目录下执行
sh ./build_ros1.sh # 强制按ROS1环境编译
# 或
sh ./build_ros2.sh # 强制按ROS2环境编译
编译成功后,在 build 目录下就会生成可执行文件 ros_qt5_gui_app。直接运行它:
./ros_qt5_gui_app
第一次运行后,会在同目录下生成一个 config.json 配置文件,后续所有的功能配置都在这里调整。
2.3 开发工具选择:VSCode还是QtCreator?
这里我想多聊几句开发工具的选择,因为很多ROS新手会在这里卡住。一个常见的误区是:做Qt开发就必须安装QtCreator。 其实不然。
在我整个开发过程中,我的主力代码编辑器是VSCode,只安装了基础的C/C++插件用于代码提示和跳转。为什么不用QtCreator?因为本项目所有的UI界面都是在C++代码中动态创建和布局的,没有使用Qt Designer的 .ui 文件来拖拽生成界面(唯一的 .ui 文件基本上是空的)。这种“纯代码绘制”的方式带来了极大的灵活性,也让界面风格和逻辑控制更加统一。
那我什么时候用QtCreator呢?只有在需要编辑资源文件,比如往 .qrc 文件里添加新的图标、图片时,才会临时打开QtCreator,因为它对 .qrc 文件的图形化编辑比较友好。编辑完保存,就关掉它。
所以,对于只想使用本软件的朋友,你完全不需要安装QtCreator。对于想参与开发的朋友,我推荐VSCode + CMake插件的组合,轻量且高效。当然,如果你对QtCreator情有独钟,也可以用QtCreator直接打开项目根目录的 CMakeLists.txt 文件来管理和编译项目,这同样没有问题。
3. 核心实战:地图编辑功能详解
地图编辑是这个控制界面的一大亮点,它把原本需要在多个工具间切换的操作,集成在了一个可视化的画布上,非常直观。启动软件并加载一张地图(比如你的导航包里的 map.pgm)后,你就能看到如下工具栏。
3.1 拓扑地图:像搭积木一样设置导航点
拓扑地图功能,简单说就是让你能在地图上方便地设置一系列导航目标点(Waypoint),并且这些点可以被机器人按顺序依次访问。
操作起来特别简单:点击工具栏上的“拓扑点”按钮(图标通常是一个准星或旗帜),然后直接在地图上的任意位置单击鼠标左键,就会放下一个导航点。每个点都有一个可拖拽的箭头,用来指示机器人到达该点时的朝向。你可以通过拖拽点本身来移动位置,拖拽箭头来旋转朝向。
这里有个非常实用的技巧: 你可以通过拖拽来调整点的顺序。比如,你设置了点A、B、C,后来想让机器人先到C再到B,你只需要用鼠标把C点拖到B点前面就行了。软件内部会自动维护这个顺序列表。
设置好一系列点之后,在任务链面板(通常在主界面一侧)点击“Start Task Chain”,机器人就会开始从当前点出发,依次访问这些目标点。这在需要机器人执行固定巡逻路线,或者完成一系列连贯动作(如去A点取货,再到B点卸货)的场景下,效率提升非常明显。
注意:如果点击地图发布导航点后,机器人没反应,首先检查你的
config.json文件。找到"NavGoal"这一项,确保其"topic"字段的值是你机器人导航栈实际订阅的目标点话题(常见的是/move_base_simple/goal),并且"enable"设置为true。
3.2 地图修饰:画笔、橡皮擦与线段
机器人建好的地图难免有瑕疵,比如飘移的临时障碍物(动态物体被当成静态了),或者该有障碍物的地方却漏掉了(比如很薄的玻璃门)。这时候,地图编辑功能就派上用场了。
- 画笔:选择画笔工具,你可以在地图上“涂黑”,也就是添加障碍物。这适用于补全一些建图时缺失的墙壁或家具轮廓。画笔的粗细可以在工具栏上调整。
- 橡皮擦:和画笔相反,橡皮擦用来“擦白”,即清除地图上的障碍物信息。比如一个临时放在走廊的箱子被扫进了地图,现在箱子移走了,你就可以用橡皮擦把它从地图上抹掉,让路径规划能通过这里。这个功能在动态环境中维护地图的准确性至关重要。
- 线段绘制:这是比画笔更精确的工具。点击线段工具后,在地图上点击确定起点和终点,软件会自动在两点之间画出一条笔直的障碍物线段。这非常适合快速、精确地添加或修正墙壁这类直线障碍。
所有这些编辑操作,都是实时反映在地图显示上的,但并不会自动保存到原始地图文件。 这是一个安全设计,防止误操作覆盖了辛苦建好的原图。编辑完成后,你需要主动点击“保存”按钮。
3.3 地图的保存与加载:格式与集成
点击保存按钮时,软件会一次性生成三个文件:
*.pgm: 编辑后的地图图片文件。这就是ROS导航包(如move_base)使用的标准地图格式。*.yaml: 地图的描述文件,包含了分辨率、原点、图片路径等信息。*.topology: 这是本软件自定义的拓扑地图文件,它用JSON格式保存了你之前设置的所有导航点、点的顺序、以及每个点的朝向信息。
这意味着,你不仅可以修改地图的占据信息,还能把一整套导航点位方案和地图绑定保存。下次需要机器人执行同样的任务链时,你只需要加载这个 .topology 文件,所有的点位就都恢复了,无需重新设置。
如何集成到ROS导航中? 很简单。把你编辑后保存的 .pgm 和 .yaml 文件,复制到你的机器人导航功能包的 maps 文件夹下(例如,替换掉原来的 map.pgm 和 map.yaml),然后重新启动导航节点,机器人就会使用你编辑过的新地图了。而 .topology 文件则由本软件自己管理,用于快速加载任务配置。
4. 多机协同与核心控制功能
一个专业的控制界面,绝不能只局限于单机操作。很多时候,我们需要在办公室的电脑上监控远在实验室或者车间的机器人。这就涉及到了多机通信。
4.1 透明的多机通信配置
为了让新手免于配置的烦恼,这个软件的多机通信完全复用了ROS自身的原生机制。你不需要在软件里填写任何复杂的IP或端口设置。
- 对于ROS1:你只需要按照标准的ROS1多机通信教程,在运行本软件的电脑上设置好
ROS_MASTER_URI(指向机器人主机)和ROS_IP(设置为本机IP)这两个环境变量。软件启动时会自动读取这些环境变量,并连接到指定的ROS Master。 - 对于ROS2:则更加简单,只需要确保运行本软件的电脑和机器人处在同一个域内,即设置相同的
ROS_DOMAIN_ID环境变量即可。
这样一来,软件的所有功能——地图显示、速度发布、点位设置——都会自动通过ROS网络发送到机器人,或者从机器人接收数据。你只需要确保网络是通的,ROS的多机配置是正确的,软件层面无需任何额外操作。
4.2 机器人核心状态监控与控制
除了地图,主界面上还集成了几个非常实用的监控和控制组件,它们都通过 config.json 灵活配置。
- 手动控制与速度仪表盘:界面上的方向按钮或WSAD键盘按键,可以实时发布
geometry_msgs/Twist消息来控制机器人移动。同时,一个酷炫的仪表盘会实时显示从机器人里程计话题(通常是/odom)订阅到的实际速度(线速度和角速度)。这样你既能发送指令,又能看到机器人的实际执行反馈,形成闭环。配置时,确保"Speed"项的topic是你的底盘控制话题(如/cmd_vel),"Odometry"项的topic是你的里程计话题。 - 重定位(Initial Pose):这个功能比Rviz的2D Pose Estimate更直观。你可以在机器人实际所在的位置,用鼠标左键拖拽出一个箭头,箭尾是位置,箭头方向是朝向。在拖拽过程中,软件会实时显示当前位姿下的激光扫描匹配情况(如果订阅了激光话题),帮助你找到一个匹配度最高的位置再松开,这样重定位的精度会高很多。
- 电池电量显示:一个简单的进度条,用于显示从
sensor_msgs/BatteryState话题订阅到的电池电量百分比。这对于移动机器人,尤其是户外或长时间运行的机器人来说,是必不可少的监控项。
所有这些模块都是可插拔的。如果你不需要电池显示,直接在 config.json 里把对应项的 "enable" 设为 false 即可。这种基于配置的模块化管理,让软件可以轻松适配不同传感器配置和功能需求的机器人。
5. 进阶技巧与性能优化心得
项目用久了,自然会积累一些“踩坑”经验和提升使用体验的技巧。这里分享几点,希望能帮你少走弯路。
5.1 配置文件config.json的灵活运用
config.json 是这个软件的大脑,所有功能开关和数据流都归它管。它的结构清晰,是一个JSON数组,每个元素对应界面上的一个功能模块。除了前面提到的修改话题名,你还可以做更多:
- 界面布局调整:虽然UI是代码绘制的,但一些显示属性,如仪表盘的最大速度值、电池电量警告阈值,未来都可能通过配置暴露出来。目前,你可以通过注释掉(删除)某个模块的配置项,来让该模块不在界面上显示,从而实现最基础的界面定制。
- 多话题支持扩展:目前的代码架构很容易扩展为订阅或发布多个同类型话题。比如,你想同时监控两个机器人的里程计,理论上可以复制一份
"Odometry"的配置,改个名字和话题,然后在代码中为它创建一个新的显示部件即可。这为监控多机器人系统提供了可能。
5.2 在低性能设备上流畅运行
“所有功能自行绘制”这个设计选择,带来了一个巨大的优势:极低的资源占用。因为不依赖庞大的Qt Widgets样式引擎,也不加载复杂的主题,界面绘制开销很小。
我实测过,在树莓派4B(4GB内存)上,运行这个控制界面,同时显示地图、激光、摄像头画面,CPU占用率长期低于5%,内存占用在200MB左右,界面操作非常跟手。相比之下,运行一个完整的Rviz并加载类似插件,资源消耗要大得多。
性能优化建议:
- 关闭不必要的模块:在
config.json中禁用你当前实验不需要的功能模块,比如暂时不用相机就关掉图像显示。 - 降低地图刷新率:对于非常低端的设备,可以考虑修改代码中地图的刷新频率。默认情况下,地图会以ROS话题发布的频率更新,对于静态地图,可以适当降低这个频率。
- 使用Release编译:在边缘设备上编译时,务必使用CMake的Release模式(
cmake -DCMAKE_BUILD_TYPE=Release ..),编译器优化会带来显著的性能提升。
5.3 自定义功能开发指南
如果你想为这个界面添加一个新功能,比如显示一个自定义的传感器消息,或者增加一个控制面板,该怎么做?由于项目采用模块化设计,这个过程是比较清晰的:
- 定义数据接口:首先确定你的功能模块需要订阅或发布什么ROS话题,消息类型是什么。
- 创建UI部件:继承Qt的
QWidget类,在paintEvent函数中用QPainter绘制你想要的界面。可以参考SpeedDashboard(速度仪表盘)或BatteryWidget(电池显示)类的实现。 - 集成到主窗口:在你的部件类中,处理好ROS消息的订阅和回调,在回调函数中更新界面数据并触发重绘 (
update())。最后,在主窗口的初始化函数中,创建你的部件实例,并将其添加到主窗口的布局管理器中。 - 更新配置文件:在
config.json中添加你的新模块的配置项,并在代码中增加对应的解析逻辑,使得模块的启用/禁用和话题名可以通过配置控制。
这个过程需要你对Qt绘图和ROS的C++客户端库有一定的了解,但代码结构是开放的,欢迎任何有价值的功能合并请求。
6. 常见问题排查与社区资源
最后,分享几个我遇到过的典型问题及其解决方法,希望能成为你的“救火队员”。
-
问题:编译时找不到Qt5相关的头文件。
- 解决:这几乎肯定是系统Qt开发包没装全。请回头执行 2.1 节中的“全家桶”安装命令。确保安装的是
qtbase5-private-dev,而不仅仅是qtbase5-dev。
- 解决:这几乎肯定是系统Qt开发包没装全。请回头执行 2.1 节中的“全家桶”安装命令。确保安装的是
-
问题:软件能运行,但地图不显示,或者机器人位置不更新。
- 解决:这是ROS通信问题。首先,在终端用
rostopic list(ROS1) 或ros2 topic list(ROS2) 命令,确认你的机器人是否在发布/map(地图)、/tf(坐标变换)、/scan(激光,用于重定位匹配)等话题。其次,检查软件运行终端的环境变量,确认ROS_MASTER_URI和ROS_IP(ROS1)或ROS_DOMAINID(ROS2)设置正确,确保本机能连接到机器人的ROS网络。
- 解决:这是ROS通信问题。首先,在终端用
-
问题:手动控制或设置导航点,机器人没有反应。
- 解决:99%的原因是
config.json中的话题名配置错误。请用rostopic echo或ros2 topic echo命令查看你的机器人底盘实际订阅的速度控制话题 (/cmd_vel?) 和导航目标点话题 (/move_base_simple/goal?),然后严格对应地修改配置文件。修改后,务必重启软件才能生效。
- 解决:99%的原因是
-
问题:在ARM架构的设备(如树莓派、Jetson Nano)上编译失败。
- 解决:项目CI目前主要生成x86_64的Release包。对于ARM设备,你需要从源码编译。步骤和x86平台完全一样。但需要注意,某些ARM平台的Ubuntu软件源可能缺少特定的库,如果遇到依赖问题,可能需要根据编译错误提示,搜索对应的ARM架构包名进行安装。
这个项目完全开源在GitHub和Gitee上,所有代码、文档和预编译的Release包都可以免费获取。我一直在维护它,修复大家提出的Issue。如果你在使用中发现了Bug,或者有特别棒的功能点子,非常欢迎在GitHub的Issues页面提出。更鼓励有能力的开发者直接提交Pull Request,一起让这个工具变得更好用。机器人开发本身就有很多琐碎的工作,一个好用的工具能节省大量时间,让我们更专注于算法和逻辑本身。希望这个基于Qt5和ROS的控制界面,能成为你机器人工具箱里一件称手的利器。
更多推荐
所有评论(0)