第八篇:ROS的rviz三维可视化平台

本文详细介绍ROS的rviz三维可视化平台,包括其功能、安装运行、界面介绍、数据可视化原理及步骤,以及插件扩展机制。rviz是强大的数据可视化工具,用于直观展示机器人模型、坐标、运动规划、导航、点云等数据。

前言

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长! **开发管理**相关博客专栏: [https://blog.csdn.net/qq_35635374/article/details/138258301](https://blog.csdn.net/qq_35635374/article/details/138258301)

开发经验及方法博客专栏:
https://blog.csdn.net/qq_35635374/article/details/138256324

嵌入式系统平台硬软件底层开发相关博客专栏:
https://blog.csdn.net/qq_35635374/article/details/138229695

机器人导航系统架构及业务模块组合策略的相关博客专栏:
https://blog.csdn.net/qq_35635374/article/details/138202210

运动学与动力学基础知识相关博客专栏:
https://blog.csdn.net/qq_35635374/article/details/138201806

机器人传感器及感知相关教程及博客请关注专栏:
https://blog.csdn.net/qq_35635374/article/details/138507260

机器人定位相关教程及博客请关注专栏:
https://blog.csdn.net/qq_35635374/article/details/138199360

机器人地图建立相关教程及博客请关注专栏:
https://blog.csdn.net/qq_35635374/article/details/138199063

机器人动作策略规划相关教程及博客请关注专栏:
https://blog.csdn.net/qq_35635374/article/details/138175048

机器人全局路径规划相关教程及博客请关注专栏:
https://blog.csdn.net/qq_35635374/article/details/138174918

机器人局部轨迹规划相关教程及博客请关注专栏:
https://blog.csdn.net/qq_35635374/article/details/138174730

机器人轨迹跟踪控制相关教程及博客请关注专栏:
https://blog.csdn.net/qq_35635374/article/details/138168913

本文先对rviz三维可视化平台做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章


提示:以下是本篇文章正文内容

一、功能

rviz是三维可视化工具,强调把已有的数据可视化显示,用于直观的显示数据。(机器人模型、坐标、运动规划,导航、点云、图像、SLAM)。rviz提供了很多插件,这些插件可以显示图像、模型、路径等信息,但是前提都是这些数据已经以话题、参数的形式发布,rviz做的事情就是订阅这些数据,并完成可视化的渲染,rviz帮助开发者实现所有可监测信息的图形化显示,开发者也可以在rviz的控制界面下,通过rviz的planning插件的功能,根据按钮、滑动条、数值等方式,控制机器人的行为【防盗标记–盒子君hzj】

.
.

二、安装并运行rviz

1.安装rviz

rviz已经集成在桌面完整版的ROS系统当中,如果已经成功安装了桌面完整版的ROS,【防盗标记–盒子君hzj】可以直接跳过这一步骤,否则,请使用如下命令进行安装:

$ sudo apt-get install ros-kinetic-rviz

2.运行rviz

$ roscore
$ rosrun rviz rviz

.
.

三、界面介绍

0 :3D视图区,用于可视化显示数据,目前没有任何数据,所以显示黑色
1 :工具栏,提供视角控制、目标设置、发布地点等工具
2 :显示项列表,用于显示当前选择的显示插件,可以配置每个插件的属性
3 :视角设置区,可以选择多种观测视角
4 :时间显示区,显示当前的系统时间和ROS时间
.
.

四、数据可视化原理及步骤

1.原理

行数据可视化的前提当然是要有数据,假设需要可视化的数据以对应的消息类型发布,我们在rviz中使用相应的插件订阅该消息即可实现显示
可视化显示都是通过消息的订阅来完成的,机器人通过ROS发布数据,rviz订阅消息接收数据,然后显示【防盗标记–盒子君hzj】

2.步骤

(1)在源代码中按照可视化话题类型,发布话题

(1)根据消息类型visualization_msgs编程
具体怎么操作可以去wiki上面查,掌握编程的套路,(编程根据数据接口和api会填入数据就行)
【常用的可视化类型记住一下,不常用的上wiki查】


(2)在程序上编程实现了可视化api后,在rviz界面上才可以进行勾选订阅和改变参数的

【DisplayTypes】显示元素的类型
写在了另外一个博客~

(2)rviz订阅对应话题步骤

(1)Add添加显示插件
		方法一:通过显示的类型添加(By display type)
		方法二:通过话题添加(By topic)【常用 】,它会自动识别系统中发布的话题【防盗标记–盒子君hzj】
		方法三:知道话题名字,输入进行搜索


(2)配置话题显示插件
	添加完成后,rviz左侧的Dispaly中会列出已经添加的显示插件;点击插件列表前的加号,
	可以打开一个属性列表(这些属性列表设置也是编程里面visualizatian_msgs接口的成员)
	【可视化颜色、大小等等可以再程序里面改也可以再display中进行配置】,根据需求设置属性。
	一般情况下,“Topic”属性较为重要,用来声明该显示插件所订阅的数据来源,如果订阅成功,在中间的显示区应该会出现可视化后的数据。

(3)保存当前配置好的RVIZ环境

方法:File->Save Config As,下次直接打开这个.rviz就可以直接显示了

3.注意

如果显示有问题,请检查属性区域的“Status”状态。Status有四种状态:OK、Warning、Error和Disabled,【防盗标记–盒子君hzj】
如果显示的状态不是OK,那么请查看错误信息,并详细检查数据发布是否正常

编程时要清除ros可视化,每次显示才会正常

五、插件扩展机制

(1)默认插件(rviz提供)

【用好默认插件已经可以了-我们通常用的就是默认插件的数据类型】

(1)订阅话题的插件
包含坐标轴、摄像头图像、地图、激光等数据。


(2)发布话题的插件
	(1)rviz中的Nav_3D的目标点(goal),在程序中是怎么被接收的?
	【在目标点订阅函数的话题名中被订阅,在回调函数中对这个话题的目标值变量进行处理】
	【话题名可以使用rviz中默认的话题名,也可以自己写一个rviz的插件自己进行定义,rviz和gazebo都是支持插件的】
	
	(2)rviz最上面的界面栏可以发布话题,通过“+”“-”符号添加或者删除话题,【防盗标记–盒子君hzj】
	
	发布的话题名字可以通过rostopic list查看,若是要修改可以在.rviz中进行修改

(2)扩展插件

ROS的rviz仿真插件的编写,可以按照rviz提供的topic type的规范来写

作为一个平台,rviz可以显示的数据不仅仅如此。rviz支持插件扩展机制。如果需要添加其他数据的显示,也可以通过编写扩展插件的形式进行添加

jsk的rviz插件查一查怎么用?

planning有什么插件?【防盗标记–盒子君hzj】

(3)rviz的人机调试界面开发

可视化界面编程–QT(Qt中的重要概念——信号、槽,类似于回调函数)

整体原理
读取用户的输入,然后转换成ROS的topic

举例

//rviz_plugin_for_command.cpp
namespace test_rviz_plugin{
    TestRvizPlugin::TestRvizPlugin(QWidget *parent):Panel(parent)
    {
    	//创建按钮
        auto *button_layout = new QHBoxLayout;

        boundary_record_button_ = new QPushButton("Record Boundary",this);
        button_layout->addWidget(boundary_record_button_);

        connected_record_button_ = new QPushButton("Record Connected Road",this);
        button_layout->addWidget(connected_record_button_);

        virtualwall_record_button_ = new QPushButton("Record Virtual Wall",this);
        button_layout->addWidget(virtualwall_record_button_);

        start_task_button_ = new QPushButton("Start Task", this);
        button_layout->addWidget(start_task_button_);

        start_unFinish_task_button_ =
            new QPushButton("Start unFinish Task", this);
        button_layout->addWidget(start_unFinish_task_button_);

        start_go_charge_button_ = new QPushButton("Start go charge Task", this);
        button_layout->addWidget(start_go_charge_button_);

        pause_task_button_ = new QPushButton("Pause Task", this);
        button_layout->addWidget(pause_task_button_);

        resume_task_button_ = new QPushButton("resume Task", this);
        button_layout->addWidget(resume_task_button_);

        leave_dock = new QPushButton("leave dock", this);
        button_layout->addWidget(leave_dock);

        end_task_button_ = new QPushButton("end Task", this);
        button_layout->addWidget(end_task_button_);

        setLayout(button_layout);

        // 信号连接---点击信号发生,连接到槽函数callback
        connect(boundary_record_button_, SIGNAL(clicked()), this,
                SLOT(boundaryRecordCallback()));
        connect(connected_record_button_, SIGNAL(clicked()), this,
                SLOT(connectedRoadRecordCallback()));
        connect(virtualwall_record_button_, SIGNAL(clicked()), this,
                SLOT(virtualwallRcordCallback()));

        connect(start_task_button_, SIGNAL(clicked()), this,
                SLOT(startTaskCallback()));

        connect(start_unFinish_task_button_, SIGNAL(clicked()), this,
                SLOT(startUnFinishTaskCallback()));

        connect(start_go_charge_button_, SIGNAL(clicked()), this,
                SLOT(startGoChargeCallback()));

        connect(pause_task_button_, SIGNAL(clicked()), this,
                SLOT(PauseTaskCallback()));

        connect(resume_task_button_, SIGNAL(clicked()), this,
                SLOT(ResumeTaskCallback()));

        connect(leave_dock, SIGNAL(clicked()), this, SLOT(LeaveDockCallback()));

        connect(end_task_button_, SIGNAL(clicked()), this,
                SLOT(EndTaskCallback()));

        boundary_record_pub =
            nh_.advertise<std_msgs::Bool>("record_boundary_button", 10);
        connected_road_record_pub =
            nh_.advertise<std_msgs::Bool>("record_connected_road_button", 10);
        virtualwall_record_pub =
            nh_.advertise<std_msgs::Bool>("record_virtualwall_button", 10);

        start_task_pub = nh_.advertise<std_msgs::Bool>("start_task_button", 10);
        start_unFinish_task_pub =
            nh_.advertise<std_msgs::Bool>("start_unFinish_task_button_", 10);
        start_go_charge_pub =
            nh_.advertise<std_msgs::Bool>("start_go_charge_button_", 10);
        pause_task_pub =
            nh_.advertise<std_msgs::Bool>("pause_task_button_", 10);
        resume_task_pub =
            nh_.advertise<std_msgs::Bool>("resume_task_button_", 10);
        leave_dock_pub =
            nh_.advertise<std_msgs::Bool>("leave_dock_button_", 10);
        end_task_pub = nh_.advertise<std_msgs::Bool>("end_task_button_", 10);

        is_start_record_boundary.data = false;
        is_start_record_connected_road.data = false;
        is_start_record_virtualwall.data = false;

        // start_task.data = false;
        // start_unFinish_task.data = false;
        // start_go_charge.data = false;
        // pause_task.data = false;
        // resume_task.data = false;
        // leave_dock_task.data = false;
        // end_task.data = false;
    }

    // 加载配置数据---必须要有的
    void TestRvizPlugin::load(const rviz::Config &config) {
        Panel::load(config);
    }

    // 将所有配置数据保存到给定的Config对象中。在这里,重要的是要对父类调用save(),以便保存类id和面板名称。---必须要有的
    void TestRvizPlugin::save(rviz::Config config) const {
        Panel::save(config);
    }

    void TestRvizPlugin::boundaryRecordCallback() {
        if (!is_start_record_boundary.data)
            is_start_record_boundary.data = true;
        else
            is_start_record_boundary.data = false;
        ROS_INFO("Record Boundary");
        boundary_record_pub.publish(is_start_record_boundary);
    }
}
//rviz_plugin_for_command.h
#ifndef RVIZ_PLUGIN_FOR_COMMAND_H
#define RVIZ_PLUGIN_FOR_COMMAND_H
#include <ros/ros.h>
#include <rviz/panel.h>  //plugin基类的头文件
#include <std_msgs/Bool.h>

#include <QHBoxLayout>
#include <QPushButton>
#include <QString>
namespace test_rviz_plugin{
class TestRvizPlugin : public rviz::Panel {
    // 所有的plugin都必须是rviz::Panel的子类
    // 后边需要用到Qt的信号和槽,都是QObject的子类,所以需要声明Q_OBJECT宏
    Q_OBJECT

   public:
    // 构造函数,在类中会用到QWidget的实例来实现GUI界面,这里先初始化为0即可
    TestRvizPlugin(QWidget *parent = 0);

    // 重载rviz::Panel基类中的函数,用于保存、加载配置文件中的数据
    virtual void load(const rviz::Config &config);
    virtual void save(rviz::Config config) const;

    // 回调函数
   protected Q_SLOTS:
    void boundaryRecordCallback();
    void connectedRoadRecordCallback();
    void virtualwallRcordCallback();
    void startTaskCallback();

    void startUnFinishTaskCallback();
    void startGoChargeCallback();
    void PauseTaskCallback();
    void ResumeTaskCallback();
    void LeaveDockCallback();
    void EndTaskCallback();

   private:
    ros::NodeHandle nh_;
    QPushButton *boundary_record_button_;
    QPushButton *connected_record_button_;
    QPushButton *virtualwall_record_button_;

    QPushButton *start_task_button_;
    QPushButton *start_unFinish_task_button_;
    QPushButton *start_go_charge_button_;
    QPushButton *pause_task_button_;
    QPushButton *resume_task_button_;
    QPushButton *leave_dock;
    QPushButton *end_task_button_;

    std_msgs::Bool is_start_record_boundary;
    std_msgs::Bool is_start_record_connected_road;
    std_msgs::Bool is_start_record_virtualwall;

    // std_msgs::Bool start_task;
    // std_msgs::Bool start_unFinish_task;
    // std_msgs::Bool start_go_charge;
    // std_msgs::Bool pause_task;
    // std_msgs::Bool resume_task;
    // std_msgs::Bool leave_dock_task;
    // std_msgs::Bool end_task;

    ros::Publisher boundary_record_pub;
    ros::Publisher connected_road_record_pub;
    ros::Publisher virtualwall_record_pub;

    ros::Publisher start_task_pub;
    ros::Publisher start_unFinish_task_pub;
    ros::Publisher start_go_charge_pub;
    ros::Publisher pause_task_pub;
    ros::Publisher resume_task_pub;
    ros::Publisher leave_dock_pub;
    ros::Publisher end_task_pub;
};
}
#endif 

效果如下
在这里插入图片描述

参考链接
https://zhuanlan.zhihu.com/p/39390512


总结

启动rviz之前要先启动roscore,遇到错误或者警告先看提示

相关技术专栏推荐

(1)计算技术&硬软件开发工程篇
https://blog.csdn.net/qq_35635374/category_12821115.html

(2)计算机技术基础&开发经验
https://blog.csdn.net/qq_35635374/category_11471204.html

(3)嵌入式系统硬软件开发
https://blog.csdn.net/qq_35635374/category_11464543.html

(4)开发技术管理
https://blog.csdn.net/qq_35635374/category_12344669.html

(5)机器人/自动驾驶导航算法篇
https://blog.csdn.net/qq_35635374/category_12825966.html

(6)导航系统架构及业务模块组合策略
https://blog.csdn.net/qq_35635374/category_11464757.html

(7)运动学与动力学基础知识
https://blog.csdn.net/qq_35635374/category_11471199.html

(8)多传感器标定、数据融合与状态估计
https://blog.csdn.net/qq_35635374/category_11464733.html

(9)定位、地图建立、地图管理SLAM合集
https://blog.csdn.net/qq_35635374/category_12805256.html

(10)定位location
https://blog.csdn.net/qq_35635374/category_11464501.html

(11)地图mapping
https://blog.csdn.net/qq_35635374/category_11464370.html

(12)机器人决策规划控制合集
https://blog.csdn.net/qq_35635374/category_12804215.html

(13)任务决策规划mission_planner
https://blog.csdn.net/qq_35635374/category_12344770.html

(14)动作策略规划motion_planner
https://blog.csdn.net/qq_35635374/category_12176372.html

(15)全局路线规划global_planner
https://blog.csdn.net/qq_35635374/category_12176370.html

(16)局部路径规划local_planner
https://blog.csdn.net/qq_35635374/category_12176374.html

(17)轨迹跟踪控制模块Path_tracking
https://blog.csdn.net/qq_35635374/category_12176376.html

(18)机器人实战篇
https://blog.csdn.net/qq_35635374/category_12821111.html

(19)足式机器人&机械臂控制合集
https://blog.csdn.net/qq_35635374/category_11523332.html

(20)自动驾驶&无人机导航合集
https://blog.csdn.net/qq_35635374/category_12804317.html

(21)四足机器人MIT Cheetah mini
https://blog.csdn.net/qq_35635374/category_11523325.html

(22)自动驾驶Autoware
https://blog.csdn.net/qq_35635374/category_11523328.html

(23)无人机fast_planner
https://blog.csdn.net/qq_35635374/category_11523335.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RoboticsTechLab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值