3 ROS人机交互界面的搭建
3 ROS人机交互界面的搭建
3.1 Qt安装和配置
前提条件,虚拟机运行ROS-melodic和Qt5.9.9。其他版本很容易报错。
安装----- 在http://download.qt.io/archive/qt/
下载Qt5(linux对于.run文件这里下载的是Qt5.9.9) ,下载完后在改文件夹打开终端,输入sudo chmod a+x /
给安装包赋予权限,之后双击安装,安装时,没有Qt账户的需要注册,然后在安装组件那一步勾选gcc,其他都按照默认的安装(即安装在home目录下)。安装完Qt后设置快捷方式,sudo gedit /usr/bin/qtcreator
打开后输入
#!/bin/sh
export QT_HOME=/home/用户名xxx/Qt5.9.9/Tools/QtCreator/bin
$QT_HOME/qtcreator $*
最后再chmod a+x /usr/bin/qtcreator
赋予权限。安装完Qt后再给ROS安装Qt依赖项,输入命令sudo apt-get install ros-melodic-qt-create
和sudo apt-get install ros-melodic-qt-bulid
。
配置----- 配置的前题,最好是melodic和Qt5.9.9,其他版本容易失败。在ROS工作空间的src目录下(/catkin_ws/src),新建Qt包catkin_create_qt_pkg qt_demo功能包名 roscpp rospy 个依赖项。创建完成后再工作空间的目录下(/catkin_ws)进行编译,编译无误则无需后面的配置文件更改,编译出现问题的话可以在qt包的CMakeLists.txt文件(/catkin_ws/src/qt_demo/CMakeLists.txt)进行下面的修改:①添加当前目录set(CMAKE_INCLUDE_CURRENT_DIR ON) ②添加Qt库find_package(Qt5 REQUIRED Core Widgets)和set(QT_LIBRARIES Qt5::Widgets) ③注释掉rosbuild_prepare_qt4(QtCore QtGui) ④将相应的QT4的变量改成QT5 ⑤打开include文件下的mainwindows.hpp将头文件QtGUI改成QtWidgets ⑥打开src文件下的mainwindows.cpp把QtGUI换成QtWidgets。
设置完成后,首先打开ROS的工作空间(举例catkin_ws),执行catkin_make先进行编译,没有问题之后,就在这个终端后面输入qtcreator打开Qt,再导入文件,选择工作空间的源文件(/catkin_ws/src/CMakeLists.txt)下的CMakeLists.txt文件,打开时注意build的指向必须指向工作空间的build目录。
个人理解的Qt界面与ROS的关系:
3.2 Qt-UI的基本操作
在新建项目,选择qt widegets application项目,确定好项目的存放位置一切,其余全部默认即可。
在ui界面设置的文本其中①处文本可以被源文件的代码给替换掉,②和③处的文本是同一个内容,是对按钮这个参数的命名,在源文件中对这个按钮所要执行的所有操作,都用这个变量名来调用。
// Headers/mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//---------------------------------------------
//**************---START---*********************
//---------------------------------------------
public slots:
void but1_fun(bool);
void ckb_fun(int);
void hts_fun(int);
//---------------------------------------------
//**************---END---*********************
//---------------------------------------------
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
// Sources/mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
//---------------------------------------------
//**************---START---*********************
//---------------------------------------------
#include "QDebug"
#include "qtreewidget.h"
#include "qcombobox.h"
//---------------------------------------------
//**************---END---*********************
//---------------------------------------------
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//---------------------------------------------
//**************---START---*********************
//---------------------------------------------
//对按键but1进行连接,通过点击的信号,进行回调函数操作
connect(ui->but1,SIGNAL(clicked(bool)),this,SLOT(but1_fun(bool)));
//对选项框ckb进行连接,通过状态字的改变,进行回调函数操作
connect(ui->ckb,SIGNAL(stateChanged(int)),this,SLOT(ckb_fun(int)));
//对拖拉条hts进行连接,通过值的改变,进行回调函数操作
ui->hts->setRange(0,100);
ui->hts->setValue(25);
ui->lab3->setText("25");
ui->pgb->setValue(25);
connect(ui->hts,SIGNAL(valueChanged(int)),this,SLOT(hts_fun(int)));
//对树状条进行连接,先是头标的样式,空格是用来撑住宽度的,也可以换成文字
ui->tw->setHeaderLabels(QStringList()<<" "<<" ");
//下面两条命令是一组,用来创建下拉菜单,并且命名为top
QTreeWidgetItem* item=new QTreeWidgetItem(QStringList()<<"top");
ui->tw->addTopLevelItem(item);
//下面两条命令是一组,用来创建下拉条top的第一列条目,并命名为next1
QTreeWidgetItem* item_child1=new QTreeWidgetItem(QStringList()<<"next1");
item->addChild(item_child1);
//同理创建了下拉条top下的第二列条目,并命名为next2
QTreeWidgetItem* item_child2=new QTreeWidgetItem(QStringList()<<"next2");
item->addChild(item_child2);
//给第一列条目next1添加了下拉框,并且命名为name,而且是默认选中状态
QComboBox* box=new QComboBox;
box->addItem("name");
box->setEditable(true);
ui->tw->setItemWidget(item_child1,1,box);
//---------------------------------------------
//**************---END---*********************
//---------------------------------------------
}
//---------------------------------------------
//**************---START---*********************
//---------------------------------------------
void MainWindow::hts_fun(int)
{
ui->lab3->setText(QString::number(ui->hts->value()));
ui->pgb->setValue(ui->hts->value());
}
void MainWindow::ckb_fun(int state)
{
if(state==2)
{
ui->lab2->setText("Clicked");
}
else
{
ui->lab2->setText("NOT CHICKED");
}
}
void MainWindow::but1_fun(bool)
{
ui->ckb->setChecked(true);
ui->lab2->setText("Clicked!");
}
//---------------------------------------------
//**************---END---*********************
//---------------------------------------------
MainWindow::~MainWindow()
{
delete ui;
}
现在对已经编辑好的qt_demo文件添加跳转窗口的操作。
首先向qt_demo里添加form类文件。并在UI中设计一个pushbutton来执行返回操作。
在mainwindow.hpp里添加form的头文件,然后定义两个回调函数,来完成qt_demo里的按钮操作,以及相应form里的按钮操作。
// Headers/mainwindow.hpp
…
#include <form.h>
…
public slots:
…
void but2_fun(bool);//qt_demo里的按钮回调操作
void slot_qt_demo_show();//比较特殊,是给form-ui的按钮的响应函数
…
在mianwindow.cpp里编写程序。
// mainwindow.cpp
…
connect(ui->but2,SIGNAL(clicked(bool)),this,SLOT(but2_fun(bool)));
…
void MainWindow::but2_fun(bool)
{
Form* f = new Form;//声明form对象(form是新建的UI class文件名)
f->show();//显示form的ui界面
connect(f,SIGNAL(close_and_open()),this,SLOT(slot_qt_demo_show()));//创建连接,如果f收到了close_and_open信号则在this(指代此时的qt_demo)里执行slot_qt_demo_show()的回调操作。
this->hide();//声明完qt_demo页面隐藏
}
void MainWindow::slot_qt_demo_show()
{
this->show();
}
…
在form文件里所要的内容包括一个自定义信号close_and_open()和其按键的回调函数。
// Headers/form.hpp
…
public slots:
void slot_pushbutton();
signals:
void close_and_open();
…
//form.cpp
…
connect(ui->pushButton,SIGNAL(clicked(bool)),this,SLOT(slot_pushbutton()));
…
void Form::slot_pushbutton()
{
emit close_and_open();
this->hide();
}
…
最终效果:
3.3 Qt与ROS的交互
3.3.1创建节点订阅消息
Step1----- 创建基础的Qt的ros模板(见3.1).
Step2----- 在qnode.hpp文件里添加头文件、订阅者和回调函数。
推荐阅读