序
本篇博客主要介绍怎么使用qt对ros进行gui设计与调试,包括使用List View显示ROS话题发布与接收的消息,点击QT按钮pushbutton进行ros消息的发布。
在阅读本文之前没有安装qt与配置环境可以参考博文:如何用Qt对ROS项目进行调试及创建GUI界面。
一、ROS下创建QT_GUI文件
(1)安装 catkin_create_qt_pkg ROS包,打开终端输入以下命令:
$ sudo apt-get install ros-<distro>-qt-ros //distro是ros版本,例如LZ的就是 ros-hydro-qt-ros
(2)进入工作空间使用如下命令创建基于qt的ros_gui文件:
$ cd catkin_ws/src //进入自己的工作空间 $ catkin_create_qt_pkg ros_gui //创建ros_gui包
(3)如下图,在终端输入qtcreator打开qt(或者在桌面配置了QT-ROS启动快捷方式的直接点击启打开),选择打开项目进入ros_gui文件下选择CMakeList.txt文件打开:
(4)进入CMake向导构建路径步骤点击下一步:
(5)在执行Cmake步骤中,参数选项输入:-DCMAKE_BUILD_TYPE=DEBUG,然后点击执行CMake,最后点击完成:
(6)如下图,可以看到打开的ros_gui项目(吐槽下这里居然不显示头文件目录,导致编辑头文件代码不方便,建议将头文件与cpp文件放在一起再导入,导入后修改cpp中头文件路径):
二、在QT视图中显示ROS话题发布与接收的消息
(1)打开终端roscore启动ros_Master,在qt上直接编译运行ros_gui项目,填写自己的ROS信息(ROS_MASTER_Url可直接在终端中查看,ROS_IP可以在终端输入ifconfig命令查看),点击connect,如下图可以看到程序内置了一个文本视图与ros发送节点,视图上显示节点发送的信息:
(2)下面在窗口空间中添加一个文本视图使其显示接收到的消息,打开main_window.ui文件,拖入一个List View控件并将其对象名更改为view_logging_sub,然后拖入两个Label控件到对应的视图空间上并分别改为sub与pub:
(3)打开qnode.hpp(项目列表不显示的直接打开项目include文件夹拖入qt)与qnode.cpp,在其中添加代码(添加部分代码标记为红色//add):
<qnode.hpp>: /***************************************************************************** ** Includes *****************************************************************************/ #include <ros/ros.h> #include <string> #include <QThread> #include <QStringListModel> #include <std_msgs/String.h> //add public: /********************* ** Logging **********************/ QStringListModel* loggingModel() { return &logging_model; } void log( const LogLevel &level, const std::string &msg); QStringListModel* loggingModel_sub() { return &logging_model_sub; } //add void log_sub( const LogLevel &level, const std::string &msg); //add void Callback(const std_msgs::StringConstPtr& submsg); //add Q_SIGNALS: void loggingUpdated(); void rosShutdown(); void loggingUpdated_sub(); //add private: int init_argc; char** init_argv; ros::Publisher chatter_publisher; QStringListModel logging_model; ros::Subscriber chatter_subscriber; //add QStringListModel logging_model_sub; //add }; } // namespace ros_gui #endif /* ros_gui_QNODE_HPP_ */
<qnode.cpp>: bool QNode::init() { ros::init(init_argc,init_argv,"ros_gui"); if ( ! ros::master::check() ) { return false; } ros::start(); // explicitly needed since our nodehandle is going out of scope. ros::NodeHandle n; // Add your ros communications here. chatter_publisher = n.advertise<std_msgs::String>("chatter", 1000); chatter_subscriber=n.subscribe("chatter",1000,&QNode::Callback,this); //add start(); return true; } bool QNode::init(const std::string &master_url, const std::string &host_url) { std::map<std::string,std::string> remappings; remappings["__master"] = master_url; remappings["__hostname"] = host_url; ros::init(remappings,"ros_gui"); if ( ! ros::master::check() ) { return false; } ros::start(); // explicitly needed since our nodehandle is going out of scope. ros::NodeHandle n; // Add your ros communications here. chatter_publisher = n.advertise<std_msgs::String>("chatter", 1000); chatter_subscriber=n.subscribe("chatter",1000,&QNode::Callback,this); //add start(); return true; } void QNode::log_sub( const LogLevel &level, const std::string &msg) { //add logging_model_sub.insertRows(logging_model_sub.rowCount(),1); std::stringstream logging_model_msg; switch ( level ) { case(Debug) : { ROS_DEBUG_STREAM(msg); logging_model_msg << "[DEBUG] [" << ros::Time::now() << "]: " << msg; break; } case(Info) : { ROS_INFO_STREAM(msg); logging_model_msg << "[INFO] [" << ros::Time::now() << "]: " << msg; break; } case(Warn) : { ROS_WARN_STREAM(msg); logging_model_msg << "[INFO] [" << ros::Time::now() << "]: " << msg; break; } case(Error) : { ROS_ERROR_STREAM(msg); logging_model_msg << "[ERROR] [" << ros::Time::now() << "]: " << msg; break; } case(Fatal) : { ROS_FATAL_STREAM(msg); logging_model_msg << "[FATAL] [" << ros::Time::now() << "]: " << msg; break; } } QVariant new_row(QString(logging_model_msg.str().c_str())); logging_model_sub.setData(logging_model_sub.index(logging_model_sub.rowCount()-1),new_row); Q_EMIT loggingUpdated_sub(); // used to readjust the scrollbar } void QNode::Callback(const std_msgs::StringConstPtr& submsg) //add { log_sub(Info,std::string("Success sub: ")+submsg->data.c_str()); } } // namespace ros_gui
(4)再打开main_window.hpp(项目列表不显示的直接打开项目include文件夹拖入qt)与main_window.cpp,在其中添加代码(添加部分代码标记为红色//add):
<main_window.hpp>: public Q_SLOTS: /****************************************** ** Manual connections *******************************************/ void updateLoggingView(); // no idea why this can't connect automatically void updateLoggingView_sub(); //add /*****/
<main_window.cpp>: /********************* ** Logging **********************/ ui.view_logging->setModel(qnode.loggingModel()); QObject::connect(&qnode, SIGNAL(loggingUpdated()), this, SLOT(updateLoggingView())); ui.view_logging_sub->setModel(qnode.loggingModel_sub()); //add QObject::connect(&qnode, SIGNAL(loggingUpdated_sub()), this, SLOT(updateLoggingView_sub())); //add /***************************************************************************** ** Implemenation [Slots][manually connected] *****************************************************************************/ void MainWindow::updateLoggingView() { ui.view_logging->scrollToBottom(); } void MainWindow::updateLoggingView_sub() { //add
ui.view_logging_sub->scrollToBottom();
}
/*********/
(5)如下图,保存修改后的文件并且编译运行可以实现在gui显示消息的接收与发送:
三、使用QT按钮进行消息的发布
下面实现通过点击按钮进行ros消息的发送:
(1)如下图打开main_window.ui,拖入一个Push button控件,将对象名改为sent_cmd:
(2)打开qnode.hpp(项目列表不显示的直接打开项目include文件夹拖入qt)与qnode.cpp,在其中添加代码(添加部分代码标记为红色//add):
<qnode.hpp>: class QNode : public QThread { Q_OBJECT public: /********************* ** Logging **********************/ void sent_cmd(); //add
<qnode.cpp>: /***************************************************************************** ** Implementation *****************************************************************************/ void QNode::sent_cmd() //add { if( ros::ok() ) { std_msgs::String msg; std::stringstream ss; ss << "clicked the pushbutton"; msg.data = ss.str(); chatter_publisher.publish(msg); log(Info,std::string("I sent: ")+msg.data); ros::spinOnce(); } }(4)再打开 main_window.hpp(项目列表不显示的直接打开项目include文件夹拖入qt)与 main_window.cpp,在其中添加代码(添加部分代码标记为红色 //add):
<main_window.hpp>: public Q_SLOTS: /****************************************** ** Manual connections *******************************************/ void pub_cmd();//add
<main_window.cpp>: /********************* ** Logging **********************/ QObject::connect(ui.sent_cmd, SIGNAL(clicked()), this, SLOT(pub_cmd()));//add /********************* ** Auto Start **********************/ void MainWindow::pub_cmd(){ //add qnode.sent_cmd(); }
(5)最后编译运行,如下图,点击sent_cmd按钮可以看到发送的消息:
下一篇博客会详细讲解怎么在gui中显示rviz,怎么使用按钮运行ros启动文件launch。