ROS開發:QT插件操控小烏龜

1 安裝QT-ROS插件

本插件在安裝過程中自行安裝QT,無需額外安裝。

1.1 Ubuntu16.04 安裝步驟

打開Terminal,輸入:

sudo add-apt-repository ppa:levi-armstrong/qt-libraries-xenial  
sudo add-apt-repository ppa:levi-armstrong/ppa  
sudo apt-get update && sudo apt-get install qt57creator-plugin-ros

可能需要刪除舊的PPA:

sudo add-apt-repository --remove ppa:beineri/opt-qt57-xenial
sudo add-apt-repository --remove ppa:beineri/opt-qt571-xenial

如果您收到錯誤,請手動刪除它:

sudo rm /etc/apt/sources.list.d/beineri-opt-qt57-xenial-xenial.list
sudo rm /etc/apt/sources.list.d/beineri-opt-qt571-xenial-xenial.list

1.2 測試插件

由於插件的更新,不需要安裝qtcreator,插件自己依賴安裝。
安裝完成後在指令行輸入qt,按Tab鍵看自己安裝的。如圖:
在這裏插入圖片描述

然後輸入存在的qtcreatot-ros回車,qtcreator就啓動了,就會看到有關於ros的創建選項了。如圖:
在這裏插入圖片描述

安裝有問題可以借鑑:

  1. http://blog.csdn.net/zhangrelay/article/details/52068657
  2. http://blog.csdn.net/u013453604/article/details/52186375
  3. http://blog.csdn.net/qq_30460905/article/details/79034633

2 使用QT編寫ROS程序

2.1 實現步驟

  • Terminal新建工作空間catkin_qt,並創建src文件夾
mkdir -p catkin_qt/src
  • Terminal運行插件
qtcreator-ros

然後點擊New Project,命名爲catkin_qt(工程名稱),選擇第一步新建的功能包路徑catkin_qt,點擊Next,Finish。
這樣新建的ROS.workspace就在新建的文件夾路徑下了。文件夾內如圖所示:
在這裏插入圖片描述

  • 創建測試包rostest

在QT界面下,打開工程目錄,右鍵選擇src文件夾,在當前路徑下打開Terminal並創建測試功能包:

catkin_create_qt_pkg rostest

注意:需要預先安裝建包工具:

sudo apt-get install ros-kinetic-qt-ros

注意catkin_qt/devel/setup.bash路徑添加到bash文件中
在這裏插入圖片描述

  • 修改運行設置

點擊Projects,選擇Run選型,添加Add Run Step選項,Package和Target選項都選爲新建的rostest,如圖所示
在這裏插入圖片描述

  • 設計UI

在UI界面拖放幾個按鈕,右鍵更改Text名稱爲up,down,left,right
然後右鍵Go to slot…
選擇clicked()
這樣就新建了4個按鍵點擊事件,如圖所示:
在這裏插入圖片描述
在這裏插入圖片描述

  • 添加控制函數

打開主窗口qnode.hpp,註釋void run(),並添加代碼前進後退左轉右轉指令,如圖所示:
在這裏插入圖片描述
然後寫qnode.cpp文件,主要是一處頭文件,兩處ros通信程序,以及四個控制函數的修改。

/**
 * @file /src/qnode.cpp
 *
 * @brief Ros communication central!
 *
 * @date February 2011
 **/

/*****************************************************************************
** Includes
*****************************************************************************/

#include <ros/ros.h>
#include <ros/network.h>
#include <string>
#include <std_msgs/String.h>
#include <geometry_msgs/Twist.h>    //添加的地方
#include <sstream>
#include "../include/rostest/qnode.hpp"

/*****************************************************************************
** Namespaces
*****************************************************************************/

namespace rostest {

/*****************************************************************************
** Implementation
*****************************************************************************/

QNode::QNode(int argc, char** argv ) :
	init_argc(argc),
	init_argv(argv)
	{}

QNode::~QNode() {
    if(ros::isStarted()) {
      ros::shutdown(); // explicitly needed since we use ros::start();
      ros::waitForShutdown();
    }
	wait();
}

bool QNode::init() {
	ros::init(init_argc,init_argv,"rostest");
	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<geometry_msgs::Twist>("/turtle1/cmd_vel", 1000);
	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,"rostest");
	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<geometry_msgs::Twist>("/turtle1/cmd_vel", 1000);
	start();
	return true;
}
/*註釋run()
void QNode::run() {
	ros::Rate loop_rate(1);
	int count = 0;
	while ( ros::ok() ) {

		std_msgs::String msg;
		std::stringstream ss;
		ss << "hello world " << count;
		msg.data = ss.str();
		chatter_publisher.publish(msg);
		log(Info,std::string("I sent: ")+msg.data);
		ros::spinOnce();
		loop_rate.sleep();
		++count;
	}
	std::cout << "Ros shutdown, proceeding to close the gui." << std::endl;
	Q_EMIT rosShutdown(); // used to signal the gui for a shutdown (useful to roslaunch)
}

*/
//---------------------主要添加的程序--------------------------------
void QNode::up()
{
  ros::Rate loop_rate(1);
  if( ros::ok() )
  {
    geometry_msgs::Twist msg;
    msg.linear.x = 1.0;
    msg.angular.z = 0.0;
    chatter_publisher.publish(msg);

    ros::spinOnce();
    loop_rate.sleep();
  }
}
void QNode::down()
{
  ros::Rate loop_rate(1);
  if( ros::ok() )
  {
    geometry_msgs::Twist msg;
    msg.linear.x = -1.0;
    msg.angular.z = 0.0;
    chatter_publisher.publish(msg);

    ros::spinOnce();
    loop_rate.sleep();
  }
}
void QNode::left()
{
  ros::Rate loop_rate(1);
  if( ros::ok() )
  {
    geometry_msgs::Twist msg;
    msg.linear.x = 0.0;
    msg.angular.z = 1.0;
    chatter_publisher.publish(msg);

    ros::spinOnce();
    loop_rate.sleep();
  }
}
void QNode::right()
{
  ros::Rate loop_rate(1);
  if( ros::ok() )
  {
    geometry_msgs::Twist msg;
    msg.linear.x = 0.0;
    msg.angular.z = -1.0;
    chatter_publisher.publish(msg);

    ros::spinOnce();
    loop_rate.sleep();
  }
}
//--------------------------------------------------------------------
void QNode::log( const LogLevel &level, const std::string &msg) {
	logging_model.insertRows(logging_model.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.setData(logging_model.index(logging_model.rowCount()-1),new_row);
	Q_EMIT loggingUpdated(); // used to readjust the scrollbar
}

}  // namespace rostest

把控制函數添加進按鈕觸發函數中(設計UI的那四個按鍵函數)
如圖所示:
在這裏插入圖片描述

  • 編譯運行

可以在運行設置Turtlesim_node,如圖所示:
在這裏插入圖片描述
然後點擊小錘子編譯,完成編譯。

  • 若main_window.hpp出現按鈕事件函數聲明錯誤:‘slots’ does not name a type

可將private slots:改爲 private Q_SLOTS:
主要是因爲編譯器c++和ros編譯器識別不同type。
在這裏插入圖片描述
在這裏插入圖片描述

2.2 測試QT程序

1.啓動roscore
2.運行qt程序
3.勾選環境變量按鈕,點擊connect連接
4.使用按鍵進行控制小烏龜
在這裏插入圖片描述
在這裏插入圖片描述

3 參考資料

參考資料:

https://blog.csdn.net/weixin_43377151/article/details/84306914
https://blog.csdn.net/qq_39989653/article/details/79189605
https://blog.csdn.net/LOVE1055259415/article/details/80575432

此部分代碼已上傳github:
https://github.com/ShuaiWang-Code/ROS-ROBOT/tree/master/QT-ROS

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章