ROS project development practice (3) - GUI interface design of ROS using QT (on)

sequence

    This blog mainly introduces how to use qt to design and debug ros on ros, including using List View to display the messages published and received by ROS topics, and clicking the QT button pushbutton to publish ros messages .

Before reading this article, if you did not install qt and configure the environment, you can refer to the blog post: How to use Qt to debug a ROS project and create a GUI interface .


1. Create a QT_GUI file under ROS

    (1) Install the catkin_create_qt_pkg ROS package, open the terminal and enter the following command:

$ sudo apt-get install ros-<distro>-qt-ros //distro is the ros version, for example, LZ is ros-hydro-qt-ros

    (2) Enter the workspace and use the following command to create a qt-based ros_gui file:

$ cd catkin_ws/src //Enter your own workspace
$ catkin_create_qt_pkg ros_gui //Create ros_gui package


    (3) As shown in the figure below, enter qtcreator in the terminal to open qt (or directly click to open if the QT-ROS startup shortcut is configured on the desktop), select the open project to enter the ros_gui file and select the CMakeList.txt file to open:


    (4) Enter the CMake wizard build path step and click Next:


    (5) In the step of executing Cmake, enter the parameter option: -DCMAKE_BUILD_TYPE=DEBUG , then click to execute CMake, and finally click to finish:


    (6) As shown in the figure below, you can see the open ros_gui project (the header file directory is not displayed here under Tucao, which makes it inconvenient to edit the header file code. It is recommended to put the header file and the cpp file together before importing, and modify the cpp after importing. header file path):



2. Display the messages published and received by the ROS topic in the QT view

    (1) Open the terminal roscore to start ros_Master, compile and run the ros_gui project directly on qt, fill in your own ROS information (ROS_MASTER_Url can be viewed directly in the terminal, ROS_IP can be viewed in the terminal by entering the ifconfig command), click connect, as shown in the following figure The program has a built-in text view and ros sending node, which displays the information sent by the node:

    (2) Next, add a text view in the window space to display the received message, open the main_window.ui file, drag in a List View control and change its object name to view_logging_sub , then drag in two Label controls to the corresponding on the view space and changed to sub and pub respectively:


    (3) Open qnode.hpp (directly open the project include folder and drag it into qt if the project list is not displayed) and qnode.cpp , and add the code in it (the added code is marked in red //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) Open main_window.hpp again (open the project include folder directly and drag it into qt if the project list is not displayed) and main_window.cpp , and add code in it (add some code marked as red //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) As shown in the figure below, saving the modified file and compiling and running can realize the receiving and sending of messages displayed on the gui:


3. Use the QT button to publish messages

The following implements the sending of ros messages by clicking the button:

    (1) Open main_window.ui as shown below , drag in a Push button control, and change the object name to sent_cmd :


    (2) Open qnode.hpp (directly open the project include folder and drag it into qt if the project list is not displayed) and qnode.cpp , and add the code in it (the added code is marked in red //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) Open main_window.hpp again (open the project include folder directly and drag it into qt if the project list is not displayed) and main_window.cpp , and add code in it (add some code marked as red //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) Finally compile and run, as shown in the figure below, click the send_cmd button to see the sent message:


The next blog will explain in detail how to display rviz in the gui and how to use the button to run the ros startup file launch.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324737225&siteId=291194637