RVIZ和QT联合

RVIZ嵌入QT界面

引言:我们最近有一个解决的问题就是通过QT怎么来实时化来展示我们的机器人可视化界面,让我们的机器人实时运动来随着实时展现,我想到一种办法就是将我们的RVIZ来嵌入到我们的QT界面中来,让我们实现我们从ROS2来对我们的MIcro_ROS机器人的控制,并实时显示机器人的状态

最近在更新这个文件

第一天完成了MainWindow窗口,明天完成rviz_panel,主要实现我们MainWindow窗口的实现

如果你装载了ROS2 Humble Desktop 的话,RVIZ2应该是内置的

为了防止我们的安装是被我们安装下面的依赖,如果安装的是上面(ROS2 Humble Desktop ) 可以跳过这一步

bash 复制代码
sudo apt install ros-${ROS_DISTRO}-rviz2 \
                 ros-${ROS_DISTRO}-rviz-common \
                 ros-${ROS_DISTRO}-rviz-rendering \
                 ros-${ROS_DISTRO}-rviz-default-plugins \
                 ros-${ROS_DISTRO}-robot-state-publisher \
                 qtbase5-dev

QT基本知识

这里可能比较枯燥,如果使用QT Creator可能比这个要简单一点

这里适合有cpp基础的人来看,主要是写这个QT框架的使用

下面讲的是这个主程序都需要什么?

这可能和我的开发习惯有关,总是先对这个大的东西来进行我们的设计

下面个人因为也是第一次开发所以就尽可能写的注释详细,大家也可以根据我的思路来设计文件

头文件依赖

cpp 复制代码
// 类的声明
// QT 提供给我们的主窗口,我们要继承这个类的一些实现
class MainWindow : public QMainWindow
{
	 // Q_OBJECT 宏是 Qt 的元对象系统的一部分,用于支持信号和槽机制,在每一个QT程序之前都要加上
    Q_OBJECT
public:
	// Qwidget所有QT UI组件的基类,下面的UI组件都需要继承这个parent的对象
	explicit MainWindow(rclcpp::Node::share_ptr node,Qwidget*parent=nullptr);
	~MainWindow()override;
	// rviz初始化
	initalizeRviz();
// Qt 提供的槽函数,下面是槽函数的声明,就是我们在ROS中的subscription接受者,只是在单个线程中的这个函数
public slot:
	// 归零函数
	void OnGoHome();
	// 调节各个关节的角度的函数,需要传入各个关节的位置,所以要传入应该数组
	 void onJointAnglesChanged(const std::vector<double>& angles_deg);
	 // 准备位函数-预留给我们的抓取,visual pose,也可以使用检测我们的通信是否正常
	 void OnGoReady();
// 下面是不希望让用户修改的功能,相当于我们的config,个人的设计思路,一般把config文件放在我们的private下面
private:
	// 设计我们的界面的API函数
	void SetUpUi();
	// 发布我们的关节的状态
	void publishJointStates();
	// 下面是我们需要用到的成员函数,ROS编程中都有介绍我就不介绍了
	rclcpp::node::share_ptr node_;
	rclcpp::publisher<sensor_msgs::msgs::msgs::Jointstate>share_ptr Joint_pub_;
	rclcpp::TimerBase::SharedPtr timer_;
	    // UI 组件
    // rviz面板
    RvizPanel* rviz_panel_;
    // 关节控制面板
    JointControlPanel* joint_panel_;
    
    // 当前关节角度(弧度)
    std::vector<double> current_joint_angles_;
    // 关节名称 
    std::vector<std::string> joint_names_;
};

下面我们就对我们的功能来进行实现了

cpp 复制代码
// 构造函数,初始化成员
mainwindow::mainwindow(rclcpp::Node::Share_ptr node,QWidget *parent):
QMainWindow(parent)
,node_(node)
,rviz_panel(nullptr)
,joint_panel(nullptr)
{
	  // 初始化关节数据
    joint_names_ = {"joint_1", "joint_2", "joint_3", "joint_4", "joint_5", "joint_6"};
    current_joint_angles_.resize(6, 0.0);
    // 发布关节的位置
    Joint_pub_->node->create_publisher<sensor_msgs::msgs::msgs::JointState>("joint_states",10);
    // 定时发布关节位置,每50ms调用一次这个发布者
    timer_ =node->create_wall_timer(
    std::chrono::milliseconds(50),
    std::bind(&MainWindow::publishJointState,this));
    setUpUi();
}
// 析构函数的实现
~MainWindow(){
// 将定时器对象释放
if(timer_){
	timer_->cancel();
}
}
// 回调函数的实现
void MainWindow::publisherJointState(){
	// 初始化消息类型
	auto msg =sensor_msgs::msg::JointState();
	// 消息的头部分
	msg.header.stamp=node->get_clock()->now();
	// 消息的名称,我们开始初始化消息
	msg.name=joint_names_;
	msg.position=current_joint_angles_;
	// 通过Joint_pub_将消息发出来
	joint_pub_->publish(msg);
}
// 初始化U组件
void MainWindow::setUpUi(){
//可视化界面
 // 中心部件
 QWidget* central = new QWidget(this);
 setCentralWidget(central);
 QHBoxLayout * main_layout=new(central):
 // 创建面板
 QSplitter * splitter =new QSplitter(Qt::Horizontal,central);
 // 左侧RVIZ控制面板,先添加的是在左边,后添加的是在右边
 rviz_panel_ =new RvizPanel(node_,sqlitter);
 rviz_panel_->setMinmumWidth(600);
 // 将这个
 splitter->addWidget(rviz_panel_);
 // 右侧控制面板
 joint_panel_ = new JointControlPanel(6,Splitter);
 joint_panel_ ->setMinimumWidth(250);
 joint_panel_->setMaximumWidth(400);
 // 设置关节限位
 std::vector<std::pair<double,double>>limits={
        {-180, 180},  // Joint 1: 底座
        {-90, 90},    // Joint 2: 肩部
        {-135, 135},  // Joint 3: 肘部
        {-180, 180},  // Joint 4: 腕部旋转
        {-90, 90},    // Joint 5: 腕部俯仰
        {-180, 180}   // Joint 6: 末端
}
// 设置关节的限位
for (int i = 0; i < 6; i++) {
        joint_panel_->setJointName(i, joint_names_[i]);
        joint_panel_->setJointLimits(i, limits[i].first, limits[i].second);
}
splitter->setStretchFactor(0,3);
splitter->setStretchFactor(1,1);
main_layout->addWidget(splitter);
// 控制部分
	//连接信号
	connect(joint_panel_,&JointControlPanel::jointAngleschanged,
	this,&MainWindow::onJointAngleschanged);
	// 回零点信号和槽进行处理
	connect(joint_panel_,&JointControlPanel::jointAngleschanged,this,&MainWindow::onGoHome);
// 准备信号合槽进行处理
connect(joint_panel_,&JointControlPanel::jointAngleschanged,this,&MainWindow::onGoHome);
	
	
// 菜单部分,提供退出按键
QMenu * file_menu =menuBar()->addMenu("文件");
QAction * quit_action =file_menu=file_menu->addAction(
// 将菜单上的退出槽给我们的退出信号关联
connect(quit_action,&QAtion::triggered,this,&QMainWindow::close);
statusBar()->showMessage("就绪 - 等待 robot_description");

}
// 连接信号的处理函数
// 改变关节角度的信号函数
void MainWindow::JointAngleschanged(const std::vector<double>&angles_deg){
  // 度转弧度
    for (size_t i = 0; i < angles_deg.size() && i < current_joint_angles_.size(); i++) {
        current_joint_angles_[i] = angles_deg[i] * M_PI / 180.0;
    }
   // 更新状态栏
   QString status ="关节角度";
   for(size_t i=0;i<angles_deg.size();i++){
   // 这里类似于printf %1 表示第一个参数的值arg(i+1),%2表示第二个参数的值(angles_deg[i])
   //.arg(value, fieldWidth, format, precision)
   // fieldWidth = 0 最小宽度 0 不填充
   // format = 'f'  定点小数点格式
   // precision = 1 小数点后1位
	status+=QString"J%1=%2° "。arg(i+1).arg(angles_deg[i],0,'f',1);
}
}
// 回零位的函数
void MainWindow::onGoHome(){
	std::vector<double> home(6,0.0);
	joint_panel->setJointAngles(home);
}
// 回准备位的函数
void MainWindow::onGoReady(){
	std::vector<double> ready = {0, -45, 90, 0, 45, 0};
    joint_panel_->setJointAngles(ready);
}
void MainWindow::initalizeRviz(){
if(rviz_panel_){
	rviz_panel_->initalize();
	// 添加RVIZ可视化组件
	
	rviz_panel_->addGrid();
	// 机器人模型
	rviz_panel_->addRobotModel();
	// TF树
	rviz_panel_->addTF();
	statusBar()->showMessage("Rviz init success");
}
}
相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能14 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G14 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt