写在前面

最近有道作业题需要将机器人的历史路径显示出来,但是网上很多相关的教程都是搬运了官网的链接,并没有详细的操作流程。。。因此我又花费了很多时间去ros官网上学习marker的用法,学习怎么写publisher和subscriber,最终成功将路径显示了出来。这篇文章是对这个过程的详细的介绍,原理和代码实践部分会分开,因此如果你赶时间只要一个结果的话,把详细的讲解跳过即可。不过我还是推荐看完,毕竟我花了这么多精力来写知其然也要知其所以然。

(我是ROS新手,从作业这一点也应该看出来了XD,有不对的地方欢迎指正)

你应该已经完成了的准备工作

  • 已经配置好了ROS工作环境。这一点不用多说,参考ROS wiki
  • 这里我用的是Gazebo仿真环境和RVIZ可视化工具,这两个东西是安装ros时用官网上那个最全的安装包里自带(这里展示的是kinetic版本的安装命令,其他的版本到上面的链接里面找):
$ sudo apt install ros-kinetic-desktop-full
  • 已经跟着ROS wiki建立了catkin工作区,我这里的工作区就是wiki上的~/catkin_ws,如果你的不是在用户根目录下记得在后面执行命令的时候改掉。

  • 工作区目录下的src目录在系统的ROS_PACKAGE_PATH环境变量中,不在的话可以这样设置:

$ export ROS_PACKAGE_PATH=${ROS_PACKAEG_PATH}:${HOME}/catkin_ws/src

写路径显示的执行结点

首先要创建一个package,名为show_path。如果用python倒是不需要,可我这用的是C++:

$ cd ~/catkin_ws/src
$ catkin_create_pkg show_path std_msgs roscpp visualization_msgs tf

源代码

将下面的代码放进一个cpp文件,放在刚建好的package下的src目录下。即~/catkin_ws/src/show_path/src/

#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <visualization_msgs/Marker.h> int main( int argc, char** argv )
{
ros::init(argc, argv, "showpath");
ros::NodeHandle n;
ros::Publisher marker_pub = n.advertise<visualization_msgs::Marker>("visualization_marker", 10);
ros::Rate r(10);
tf::TransformListener listener; while (!ros::ok()){
r.sleep();
} visualization_msgs::Marker points, line_strip;
points.header.frame_id = line_strip.header.frame_id = "/map";
points.header.stamp = line_strip.header.stamp = ros::Time::now();
points.ns = line_strip.ns = "showpath";
points.action = line_strip.action = visualization_msgs::Marker::ADD;
points.pose.orientation.w = line_strip.pose.orientation.w = 1.0; points.id = 0;
line_strip.id = 1; points.type = visualization_msgs::Marker::POINTS;
line_strip.type = visualization_msgs::Marker::LINE_STRIP; line_strip.scale.x = 0.05; line_strip.color.b = 1.0;
line_strip.color.a = 1.0; float x(0), y(0);
int cnt(0); while (ros::ok())
{
tf::StampedTransform transform;
try{
listener.lookupTransform("/map", "/base_footprint",
ros::Time(0), transform);
}
catch (tf::TransformException ex){
ROS_ERROR("%s",ex.what());
ros::Duration(1.0).sleep();
}
x = transform.getOrigin().x();
y = transform.getOrigin().y(); geometry_msgs::Point p;
p.x = x;
p.y = y;
p.z = 0.1; if (cnt > 1) {line_strip.points.push_back(p);}
else {cnt++;} marker_pub.publish(line_strip); r.sleep(); }
}

源代码详解

下面我分块讲解以下本例中的源代码,方便大家根据需要更改。

#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <visualization_msgs/Marker.h>

引入必要的头文件。ros.h是C++的api;transform_listener.h的引入是为了获取机器人的坐标;Marker.h则是ros的message,本方法的主角。关于Marker的详细介绍参照ROS的Marker参考页

  ros::init(argc, argv, "showpath");
ros::NodeHandle n;
ros::Publisher marker_pub = n.advertise<visualization_msgs::Marker>("visualization_marker", 10);
ros::Rate r(10);
tf::TransformListener listener;

初始化结点,命名为“showpath”,发布话题为“visualization_marker”,频率为10。同时声明tf坐标听者对象listener

  while (!ros::ok()){
r.sleep();
}

等待ros连接

  visualization_msgs::Marker points, line_strip;
points.header.frame_id = line_strip.header.frame_id = "/map";
points.header.stamp = line_strip.header.stamp = ros::Time::now();
points.ns = line_strip.ns = "showpath";
points.action = line_strip.action = visualization_msgs::Marker::ADD;
points.pose.orientation.w = line_strip.pose.orientation.w = 1.0;

定义了两个对象并且将它们初始化:

  • points是点,并不显示,但是是组成线的基本单元。
  • line_strip线,用于标示历史路径。
  points.id = 0;
line_strip.id = 1;

前面pointsline_strip共用同一个namespace即showpath,这里把两者的id作出区别以免发生冲突。

  points.type = visualization_msgs::Marker::POINTS;
line_strip.type = visualization_msgs::Marker::LINE_STRIP;

设置两种Marker的种类。

  line_strip.scale.x = 0.05;

  line_strip.color.b = 1.0;
line_strip.color.a = 1.0;

设置轨迹的宽度(scale)和颜色(color)。这里设置宽度为0.05, 颜色为蓝色不透明。

tf::StampedTransform transform;
try{
listener.lookupTransform("/map", "/base_footprint",
ros::Time(0), transform);
}
catch (tf::TransformException ex){
ROS_ERROR("%s",ex.what());
ros::Duration(1.0).sleep();
}

在连接的时间内,持续获取/map/base_footprint的坐标,也就是机器人在地图上的坐标,返回到listener对象中。

    x = transform.getOrigin().x();
y = transform.getOrigin().y(); geometry_msgs::Point p;
p.x = x;
p.y = y;
p.z = 0.1;

取出机器人在地图上的坐标,并且记录在点p内。

    if (cnt > 1) {line_strip.points.push_back(p);}
else {cnt++;}

将点p加入line_strip内的点队列内。排除掉第一个点,第一个点有可能会初始化到原点,使路径中出现一段不该有的直线。当然,只是我个人遇到的问题,不敢说一定会这这样。

    marker_pub.publish(line_strip);

    r.sleep();

发布话题以及必要的sleep

后续工作

刚建立的package里的CMakeList.txt中加入以下两行:

add_executable(showpath src/showpath.cpp)
target_link_libraries(showpath ${catkin_LIBRARIES})

之后就可以开始愉快地make啦。

$ cd ~/catkin_ws
$ catkin_make

之后

$ source devel/setup.bash

显示路径

首先还是将turtlebot放进我们的仿真环境。这里就用默认的做个范例:

$ roslaunch turtlebot_gazebo turtlebot_world.launch

之后,启动自动导航,调出地图。

$ roslaunch turtlebot_gazebo amcl_demo.launch
$ roslaunch turtlebot_rviz_launchers view_navigation.launch

在rviz里订阅Marker话题:点击左下角的“add”,在弹出的对话框中选择Marker。

获取坐标需要一定的历史信息,所以可以先让机器人运动一下,再启动showpath节点:

$ rosrun show_path showpath

可能会有这样的报错信息,忽略就好,不影响最终效果(如果有知道为什么请赐教,在此谢过)

给机器人定个目标位姿,导航过去就可以看到路径用蓝色线条标出来啦。

PS:虽然这里是用导航来移动机器人的,但是我们标记历史路径的程序并没有用到导航信息。事实上这里用别的方式去移动机器人,也是可以画出路径的,只是,没有地图的话,这个路径的意义就不是那么明显了。

参考链接

详解如何在RVIZ中用Marker显示机器人运动路径的更多相关文章

  1. 详解如何在CentOS7中使用Nginx和PHP7-FPM安装Nextcloud

    转载地址:https://www.jb51.net/article/109382.htm 这篇文章主要介绍了详解如何在CentOS7中使用Nginx和PHP7-FPM安装Nextcloud,会通过 N ...

  2. 详解如何在Laravel中增加自定义全局函数

    http://www.php.cn/php-weizijiaocheng-383928.html 如何在Laravel中增加自定义全局函数?在我们的应用里经常会有一些全局都可能会用的函数,我们应该怎么 ...

  3. Delphi中ShellExecute使用详解(详细解释10种显示状态)

    有三个API函数可以运行可执行文件WinExec.ShellExecute和CreateProcess.1.CreateProcess因为使用复杂,比较少用.2.WinExec主要运行EXE文件.如: ...

  4. 详解如何在linuxmint上用源码包安装nodejs

    第一步:安装依赖包   因为Linuxmint 和 Ubuntu 同属 Debian系的Linux,而且Linuxmint是建立在Ubuntu的基础上的,所以Ubuntu下的命令和包,Linuxmin ...

  5. 详解如何在 Linux 中安装最新的 Python 3.6 版本

    # 下载源码包安装,先装wget,或curl. yum install wget # 再安装解压缩和编译环境: yum install zlib-devel bzip2-devel openssl-d ...

  6. 详解如何在vue项目中引入饿了么elementUI组件

    在开发的过程之中,我们也经常会使用到很多组件库:vue 常用ui组件库:https://blog.csdn.net/qq_36538012/article/details/82146649 今天具体说 ...

  7. 详解如何在 Linux 启动时自动执行命令或脚本

    我一直很好奇,在启动 Linux 系统并登录的过程中到底发生了什么事情.按下开机键或启动一个虚拟机,你就启动了一系列事件,之后会进入到一个功能完备的系统中,有时,这个过程不到一分钟.当你注销或者关机时 ...

  8. 详解嵌套ListView、ScrollView布局显示不全的问题

    在项目开发中,可能经常遇到嵌套ListView.ScrollView的问题,就是重写onMeasure方法.解决如下 public class ExpandListView extends ListV ...

  9. 一文聊透 Netty IO 事件的编排利器 pipeline | 详解所有 IO 事件的触发时机以及传播路径

    欢迎关注公众号:bin的技术小屋,本文图片加载不出来的话可查看公众号原文 本系列Netty源码解析文章基于 4.1.56.Final版本 1. 前文回顾 在前边的系列文章中,笔者为大家详细剖析了 Re ...

随机推荐

  1. RHSA-2018:0395-重要: 内核 安全和BUG修复更新(需要重启、本地提权、代码执行)

    [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) 修复命令: 使用root账号登陆She ...

  2. day65:nginx代理&nginx负载均衡

    目录 1.nginx代理 2.nginx代理与配置 3.nginx负载均衡调度多web节点(静态页面) 4.nginx负载均衡调度多应用节点(blog) 5.nginx_proxy + web应用节点 ...

  3. S3C6410中断系统

    S3C6410的中断主要改进是. 增加中断向量控制器,这样在S3C2440里需要用软件来跳转的中断处理机制,在S3C6410完全由硬件来跳转.你只要把ISR地址是存在连续向量寄存器空间,而不是象S3C ...

  4. 多测师讲解python函数 _open_高级讲师肖sir

    open()函数 #open() 函数用于打开一个文件,创建一个 file 对象 #Python open() 函数用于打开一个文件,并返回文件对象, # 在对文件进行处理过程都需要使用到这个函数,如 ...

  5. Mac 每次都要执行source ~/.bash_profile 后,配置的环境变量才生效

    问题: 自己在 ~/.bash_profile 中配置环境变量, 可是每次重启终端后配置的不生效.需要重新执行 : $source ~/.bash_profile后,才会生效. 原因: 自己是在bas ...

  6. rs232转rs485

    rs232转rs485 rs232转rs485 ZLAN9223E是上海卓岚科技开发的一款先进的无源RS232转RS485转换器.具有如下优点: 支持最高达230400bps的波特率.高波特率下供电能 ...

  7. jmeter_01_常用快捷键

    jmeter常用快捷键 * 快捷键 功能 备注 Ctrl + C 复制 可复制组件 Ctrl + V 粘贴 可粘贴组件 Ctrl + Shift + C 复制粘贴当前组件到下一行 Ctrl + R 运 ...

  8. 每天一个linux命令:ps命令

      Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进 ...

  9. win8怎样才能启用administrator登录 别的用户也是如此

    但是你可以用命令调出administrator账户打开C盘,打开windows文件夹,再打开system32文件夹,找到cmd.exe右键点击选择以管理员身份运行 在里面输入net user admi ...

  10. lerna管理前端模块实践

    最近在工作中使用了 lerna 进行前端包的管理,效率提升了很多.所以打算总结一下最近几个月使用 lerna 的一些心得.有那些不足的地方,请包涵. 该篇文章主要包括在使用 lerna 的一些注意事项 ...