Odometry的发布和发布odom到base_link的tf变换
转载自http://www.ncnynl.com/archives/201702/1328.html
ROS发布nav_msgs/Odometry消息,以及通过tf从“odom”坐标系到“base_link”坐标系的转换。
在ROS上发布Odometry信息
导航包使用tf来确定机器人在世界中的位置,并将传感器数据与静态地图相关联。然而,tf不提供关于机器人的速度的任何信息。因此,导航包要求任何odometry源通过ROS发布包含速度信息的transform和nav_msgs/Odometry消息。
nav_msgs/Odometry消息
nav_msgs/Odometry信息存储在自由空间的机器人的位置和速度的估计:
# This represents an estimate of a position and velocity in free space.
# 这表示对自由空间中的位置和速度的估计
# The pose in this message should be specified in the coordinate frame given by header.frame_id.
# 此消息中的姿势应在由header.frame_id给定的坐标系中指定
# The twist in this message should be specified in the coordinate frame given by the child_frame_id
# 这个消息中的twist应该在由child_frame_id给出的坐标系指定
Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
下面是更详细的消息类型
std_msgs/Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
该消息中的姿势(pose)对应于机器人在世界坐标系中的估计位置以及该姿势估计特定的可选协方差。
该消息中的速度(twist)对应于机器人在子坐标系的速度,通常是移动基站的坐标系,以及该速度估计特定的可选协方差。
使用tf发布Odometry变换
如变换配置教程中所讨论的,“tf”软件库负责管理与变换树中的机器人相关的坐标系之间的关系。
因此,任何odometry(里程)源都必须发布其管理的坐标系的相关信息。
编写代码
我们将编写一些用于通过ROS发布 nav_msgs/Odometry消息的示例代码,以及使用tf的虚拟机器人的变换。
catkin_create_pkg Odom tf nav_msgs roscpp rospy
#include <ros/ros.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h> int main(int argc, char** argv){
ros::init(argc, argv, "odometry_publisher"); ros::NodeHandle n;
ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", );
tf::TransformBroadcaster odom_broadcaster; double x = 0.0;
double y = 0.0;
double th = 0.0; double vx = 0.1;
double vy = -0.1;
double vth = 0.1; ros::Time current_time, last_time;
current_time = ros::Time::now();
last_time = ros::Time::now(); ros::Rate r(1.0);
while(n.ok()){ ros::spinOnce(); // check for incoming messages
current_time = ros::Time::now(); //compute odometry in a typical way given the velocities of the robot
double dt = (current_time - last_time).toSec();
double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
double delta_th = vth * dt; x += delta_x;
y += delta_y;
th += delta_th; //since all odometry is 6DOF we'll need a quaternion created from yaw
geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th); //first, we'll publish the transform over tf
geometry_msgs::TransformStamped odom_trans;
odom_trans.header.stamp = current_time;
odom_trans.header.frame_id = "odom";
odom_trans.child_frame_id = "base_link"; odom_trans.transform.translation.x = x;
odom_trans.transform.translation.y = y;
odom_trans.transform.translation.z = 0.0;
odom_trans.transform.rotation = odom_quat; //send the transform
odom_broadcaster.sendTransform(odom_trans); //next, we'll publish the odometry message over ROS
nav_msgs::Odometry odom;
odom.header.stamp = current_time;
odom.header.frame_id = "odom"; //set the position
odom.pose.pose.position.x = x;
odom.pose.pose.position.y = y;
odom.pose.pose.position.z = 0.0;
odom.pose.pose.orientation = odom_quat; //set the velocity
odom.child_frame_id = "base_link";
odom.twist.twist.linear.x = vx;
odom.twist.twist.linear.y = vy;
odom.twist.twist.angular.z = vth; //publish the message
odom_pub.publish(odom); last_time = current_time;
r.sleep();
}
}
代码解释:
- 代码:
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>
- 解释:我们发布odom坐标系到base_link坐标系的变换和nav_msgs/Odometry消息。需要包含相关头文件
- 代码:
ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);
tf::TransformBroadcaster odom_broadcaster;
- 解释:创建ros::Publisher和tf::TransformBroadcaster实例,以便能够分别使用ROS和tf发送消息。
- 代码:
double x = 0.0;
double y = 0.0;
double th = 0.0;
- 解释:我们假设机器人最初从“odom”坐标系的原点开始
- 代码:
double vx = 0.1;
double vy = -0.1;
double vth = 0.1;
解释:在这里,我们将设置一些速度,其将导致“base_link”坐标系相对于“odom”坐标系,在x方向上以0.1m/s,在y方向上以-0.1m/s的速率和在th方向以0.1rad/s角度移动。这让虚拟机器人走一个圆圈。
代码:
ros::Rate r(1.0);
- 解释:我们将在这个例子中以1Hz的速率发布里程计信息,以使自我检查更容易,大多数系统将希望以更高的速率发布里程消息。
- 代码:
//compute odometry in a typical way given the velocities of the robot
double dt = (current_time - last_time).toSec();
double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
double delta_th = vth * dt;
x += delta_x;
y += delta_y;
th += delta_th;
解释:
- 在这里,我们将根据我们设置的恒定速度更新我们的里程信息。
- 当然,真正的里程系统将整合计算的速度。
代码:
//since all odometry is 6DOF we'll need a quaternion created from yaw
geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);
解释:
- 我们通常尝试使用我们系统中所有消息的3D版本,以允许2D和3D组件在适当的时候一起工作,并将我们要创建的消息数量保持在最小。
- 因此,有必要将我们用于里程的偏航值转换为四元数而发送出去。
- 幸运的是,tf提供了允许从偏航值容易地创建四元数并且容易地访问四元数的偏航值的功能。
代码:
//first, we'll publish the transform over tf
geometry_msgs::TransformStamped odom_trans;
odom_trans.header.stamp = current_time;
odom_trans.header.frame_id = "odom";
odom_trans.child_frame_id = "base_link";
解释:
- 这里我们将创建一个TransformStamped消息,我们将通过tf发送。
- 我们想在“current_time”发布从“odom”坐标系到“base_link”坐标系的转换。
- 因此,我们将相应地设置消息的头部和child_frame_id,确保使用“odom”作为父坐标系,“base_link”作为子坐标系。
代码:
odom_trans.transform.translation.x = x;
odom_trans.transform.translation.y = y;
odom_trans.transform.translation.z = 0.0;
odom_trans.transform.rotation = odom_quat;
//send the transform
odom_broadcaster.sendTransform(odom_trans);
解释:这里我们从我们的odometry数据填充变换消息,然后使用我们的TransformBroadcaster发送变换。
代码:
//next, we'll publish the odometry message over ROS
nav_msgs::Odometry odom;
odom.header.stamp = current_time;
odom.header.frame_id = "odom";
解释:
- 我们还需要发布nav_msgs/Odometry消息,以便导航堆栈可以从中获取速度信息。
- 我们将消息的头部设置为current_time和“odom”坐标系。
代码:
//set the position
odom.pose.pose.position.x = x;
odom.pose.pose.position.y = y;
odom.pose.pose.position.z = 0.0;
odom.pose.pose.orientation = odom_quat;
//set the velocity
odom.child_frame_id = "base_link";
odom.twist.twist.linear.x = vx;
odom.twist.twist.linear.y = vy;
odom.twist.twist.angular.z = vth;
- 解释:
- 这将使用里程数据填充消息,并通过线路发送。
- 我们将消息的child_frame_id设置为“base_link”坐标系,因为这是我们发送速度信息的坐标系。
CMakeLists.txt
add_executable(Odom_exam src/Odom_exam.cpp)
target_link_libraries(Odom_exam ${catkin_LIBRARIES})
Odometry的发布和发布odom到base_link的tf变换的更多相关文章
- IIS上发布WCF发布服务,访问不到
1 环境是IIS7,发布WCF发布服务,访问不到. 一种原因站点自动生成“程序应用池”和站点的Framwork版本不一致. 解决的办法:新建一个“程序应用池”,然后站点指向这个新建的“程序应用池”
- SQL2005 到 SQL2008R2 发布订阅----发布'xxxxx'的初始快照尚不可用。
步骤略! SQL2005 到 SQL2008R2 发布订阅----发布'xxxxx'的初始快照尚不可用. 发布库快照已经创建完成为什么到订阅就快照不可用呢! 订阅通过日志读取代理解析! 查了下代理安全 ...
- 织梦DedeCMS信息发布员发布文章阅读权限不用审核自动开放亲测试通过!
文章发布员在织梦dedecms后台添加文章时却要超级管理员审核,这无疑是增加了没必要的工作. 登录该账号发布文章你会发现该文章显示的是待审核稿件,且并没有生成静态文件,在前台是看不到这篇文章的,而多数 ...
- 织梦DedeCMS信息发布员发布文章默认自动审核更新并生成HTML页面
织梦DedeCMS信息发布员发布文章默认自动审核更新并生成HTML页面 一直以为DEDECMS的信息发布员在后台发布文章后,非要管理员审核才能显示,今天一哥们问我这个问题.问:“能不能直接发布,并自动 ...
- 蓝绿部署、金丝雀发布(灰度发布)、A/B测试
本文转载自蓝绿部署.金丝雀发布(灰度发布).A/B测试的准确定义 概述 蓝绿部署.A/B测试.金丝雀发布,以及灰度发布.流量切分等,经常被混为一谈,影响沟通效率. 根本原因是这些名词经常出现,人们耳熟 ...
- 使用vs中的发布功能发布asp.net core项目时遇到ERROR_CERTIFICATE_VALIDATION_FAILED错误
今天将VS2015编制的一个asp.net core项目发布到服务器进行测试,使用的是vs中主菜单"生成"中的"发布"功能. 遇到了一个错误,在网上反复检索尝试 ...
- SQL Server 发布订阅 发布类型详解
MicrosoftSQL Server 提供了三种复制类型. 每种复制类型都适合于不同应用程序的要求. 根据应用程序需要,可以在拓扑中使用一种或多种复制类型: 快照复制 事务复制 合并复制 为了帮助您 ...
- web.confgi转换,web发布时发布配置(debug/release)生成不同的配置文件
在web.config下有两个config文件,分比为:web.debug.config和web.replease.config文件,打开之后可以看到demo,根据demo修改后即可在发布时根据选择的 ...
- 【转】如何使用离线博客发布工具发布CSDN的博客文章
目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...
随机推荐
- 大容量txt数据导入SQL Server助攻记
小伙伴们有个数据竞赛,提供的数据是944MB大小的TXT数据文档,导入SQL遇到一些麻烦.于是帮着解决,顺便也熟练了SQL Server的一些操作----- 打开如此大的txt需要的时间很长,而且不全 ...
- add-apt-repository 添加
add-apt-repository 添加 需要安装的软件包 apt-get install python-software-properties 除此之外还要安装 software-propert ...
- java从键盘输入一组数据,输出其最大值,平均值,最小值没法输出
总结::需要耐心,加思考.做事不思考,那就是白做徒劳!!!!! package com.aini; import java.util.Scanner; //操...为什么数组的大小比较我硬是搞不懂,比 ...
- 源码安装ceph后使用测试集群的方法
标签(空格分隔): ceph,ceph实验,ceph源码 通过博客 源码编译安装ceph(aarch64架构) 成功安装ceph之后,之后可以运行一个测试集群进行实验 1,进入安装构建目录: [roo ...
- winfrom绘制渐变 / 调用浏览器访问指定地址
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) {//绘制渐变色背景 Graphics g ...
- 解决sever 2008中tomcat的报错 init Failed to initialize end point associated with ProtocolHandler ["http-nio-80"]
错误现象: 01-Aug-2017 14:59:50.140 信息 [main] org.apache.coyote.AbstractProtocol.init Initializing Protoc ...
- PHP函数(四)-变量函数
变量函数 将声明的函数的函数名赋给一个变量,通过该变量来调用函数 <?php function Calculate($a,$b){ return $a + $b; } echo "计算 ...
- DataTable改变column类型
1.必须先克隆DataTable 2.列换类型 3.逐行往新DataTable赋值,并转换某列类型 如: DataTable dt = diorg.Clone(); //必须先克隆,此时并不包含数据 ...
- 关于datagridview自动增加行高度和显示全部内容的设置
this.dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCellsExceptHeaders; //自动调动dat ...
- 【知识碎片】python 篇
领域:运维 网站 游戏 搜索 嵌入式 C/S软件 Openstack二次开发 绿色版:Portable Python 面向对象.解释型动态语言 env python 切换版也好使,自己寻找系统中pyt ...