面向对象C++实现Qt

Node 创建

1. 创建node启动的cpp文件

src目录下创建turtle_control.cpp,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include "ros/ros.h"
#include <iostream>
using namespace std;

int main(int argc, char *argv[]) {
    string nodeName = "qt_turtle_ctrl";
    // 创建节点
    ros::init(argc,argv,nodeName);
    ros::NodeHandle node;
    return 0;
}

2. 配置CMake

来到CMakeLists.txt文件中,添加如下:

1
2
3
4
5
6
7
8
add_executable(turtle_control src/turtle_control.cpp)
target_link_libraries(turtle_control
        ${catkin_LIBRARIES}
        Qt5::Core
        Qt5::Gui
        Qt5::Widgets
        Qt5::PrintSupport
 )

Tip

add_executable是把turtle_control.cpp标记为可执行的

target_link_libraries是为turtle_control.cpp提供链接库的,值得注意的是,${catkin_LIBRARIES}是ros的依赖库,Qt5::CoreQt5::GuiQt5::WigetsQt5::PrintSupport是qt的依赖库。

Qt UI的创建

1. Qt 窗体构建

Tip

通过分析,可以先构建Qt窗体头文件,并且实现

2. 根据需求进行UI布局

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//窗体设置
setWindowTitle("小乌龟控制");
//设置窗体大小
resize(400, 120);

//设置布局
layout = new QFormLayout();
setLayout(layout);

//添加输入框
editLinear = new QLineEdit();
layout->addRow("线速度", editLinear);

//添加输入框
editAngular = new QLineEdit();
layout->addRow("角速度", editAngular);

//添加按钮
btnSend = new QPushButton("发送");
layout->addRow(btnSend);

3. 事件添加

1
2
//添加事件
btnSend->connect(btnSend, &QPushButton::clicked, this, &MainWindow::clickSend);

整合Qt和Node

基本整合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
int main(int argc, char **argv) {
  string nodeName = "turtle_control";
  //创建节点
  ros::init(argc, argv, nodeName);
  ros::NodeHandle node;

  //Qt程序添加
  QApplication app(argc, argv);

  //创建窗体
  MainWindow window;
  window.show();

  return app.exec();
}

UI和Node结合

在开发过程中,窗体window通常是需要有node对象的,因为node对象可以创造我们想要的Publisher等对象。

这个时候,我们可以将node通过参数传入到window中

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
int main(int argc, char **argv) {
  string nodeName = "turtle_control";
  //创建节点
  ros::init(argc, argv, nodeName);
  ros::NodeHandle node;

  //Qt程序添加
  QApplication app(argc, argv);

  //创建窗体
  MainWindow window(&node);
  window.show();

  return app.exec();
}

Publisher创建

1. 创建publisher对象

1
const ros::Publisher &publisher = node.advertise(topicName, 1000);

Tip

值得注意的是,在创建publisher对象时,这里要去确定的有两个点,第一就是topicName,第二就是传递的消息类型。

此处我们只能确定topic 的名称,给小乌龟发送数据的topic为/turtle1/cmd_vel

2. 确定消息传递的数据类型

通过rostopic命令查询主题对应的消息类型

1
rostopic type /turtle1/cmd_vel

得到的结果为geometry_msgs/Twist接下来我们需要导入这个消息类型对应的库

1
#include "geometry_msgs/Twist.h"

接下来就是确定publisher创建时候的类型

1
const ros::Publisher &publisher = node.advertise<geometry_msgs::Twist>(topicName, 1000);

Tip

一些规律的掌握,消息类型为geometry_msgs/Twist,需要导入的头文件为geometry_msgs/Twist.h,需要确定的编码类型为geometry_msgs::Twist

3. 发送消息

1
2
3
4
5
6
7
//创建消息
geometry_msgs::Twist twist;
//填充消息数据
twist.linear.x = linearX;
twist.angular.z = angularZ * M_PI / 180;
//发送消息
publisher->publish(twist);

完整实例代码

MainWindow1.h

MainWindow1.cpp

turtle_ctrl1.cpp