ROS Twist和Odometry消息类型使用(Python)
消息类型:
1. Twist - 线速度角速度
通常被用于发送到/cmd_vel话题,被base controller节点监听,控制机器人运动
geometry_msgs/Twist geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
linear.x指向机器人前方,linear.y指向左方,linear.z垂直向上满足右手系,平面移动机器人常常linear.y和linear.z均为0
angular.z代表平面机器人的角速度,因为此时z轴为旋转轴
示例:
#! /usr/bin/env python
'''
Author: xushangnjlh at gmail dot com
Date: 2017/05/22 @package forward_and_back
'''
import rospy
from geometry_msgs.msg import Twist
from math import pi class ForwardAndBack():
def __init__(self):
rospy.init_node('forward_and_back', anonymous=False)
rospy.on_shutdown(self.shutdown)
# this "forward_and_back" node will publish Twist type msgs to /cmd_vel
# topic, where this node act like a Publisher
self.cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=5) # parameters
rate = 50
r = rospy.Rate(rate) linear_speed = 0.2
goal_distance = 5
linear_duration = goal_distance/linear_speed angular_speed = 1.0
goal_angular = pi
angular_duration = goal_angular/angular_speed # forward->rotate->back->rotate
for i in range(2):
# this is the msgs variant, has Twist type, no data now
move_cmd = Twist() move_cmd.linear.x = linear_speed #
# should keep publishing
ticks = int(linear_duration*rate)
for t in range(ticks):
# one node can publish msgs to different topics, here only publish
# to /cmd_vel
self.cmd_vel.publish(move_cmd)
r.sleep # sleep according to the rate # stop 1 ms before ratate
move_cmd = Twist()
self.cmd_vel.publish(move_cmd)
rospy.sleep(1) move_cmd.angular_speed.z = angular_speed
ticks = int(angular_duration*rate)
for t in range(ticks):
self.cmd_vel.publish(move_cmd)
r.sleep() self.cmd_vel.publish(Twist())
rospy.sleep(1) def shutdown(self):
rospy.loginfo("Stopping the robot")
self.cmd_vel.publish(Twist())
rospy.sleep(1) if __name__=='__main__':
try:
ForwardAndBack()
except:
rospy.loginfo("forward_and_back node terminated by exception")
2. nav_msgs/Odometry - 里程计(位姿+线速度角速度+各自协方差)
通常,发布到/cmd_vel topic然后被机器人(例如/base_controller节点)监听到的Twist消息是不可能准确地转换为实际的机器人运动路径的,误差来源于机器人内部传感器误差(编码器),标定精度,以及环境影响(地面是否打滑平整);因此我们可以用更准确的Odometry消息类型类获取机器人位姿(/odom到/base_link的tf变换)。在标定准确时,该消息类型与真实的机器人位姿误差大致在1%量级(即使在rviz中显示的依然误差较大)。
还包括
- 参考系信息,Odometry使用/odom作为parent frame id,/base_link作为child frame id;也就是说世界参考系为/odom(通常设定为起始位姿,固定不动),移动参考系为/base_link(这里还有点不理解,后面来填坑)
- 时间戳,因此不仅知道运动轨迹,还可以知道对应时间点
Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist
# 展开
Header header
uint32 seq
time stamp
string frame_id
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/Pose pose
geometry_msgs/Point position
float64 x
float64 y
float64 z
geometry_msgs/Quaternion orientation
float64 x
float64 y
float64 z
float64 w
float64[36] covariance
geometry_msgs/TwistWithCovariance twist
geometry_msgs/Twist twist
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
float64[36] covariance
示例:
运动路径和位姿通过内部的Odometry获取,该Odemetry的位姿通过监听tf坐标系变换获取(/odom和/base_link)
#! /usr/bin/env python
'''
Author: xushangnjlh at gmail dot com
Date: 2017/05/23 @package odometry_forward_and_back
'''
import rospy
from geometry_msgs.msg import Twist, Point, Quaternion
import tf
from rbx1_nav.tranform_utils import quat_to_angle, normalize_angle
from math import pi, radians, copysign, sqrt, pow class Odometry_forward_and_back:
def __init__(self):
rospy.ini_node('odometry_forward_and_back', anonymous=False)
rospy.on_shutdown(self.shutdown) self.cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=5) rate = 20
r = rospy.Rate(rate)
linear_speed = 0.2
goal_distance =1.0
angular_speed = 1.0
goal_angle = pi
angular_tolerance = radians(2.5) # Initialize tf listener, and give some time to fill its buffer
self.tf_listener = tf.TransformListener()
rospy.sleep(2) # Set odom_frame and base_frame
self.odom_frame = '/odom' try:
self.tf_listener.waitForTransform(self.odom_frame,
'/base_footprint',
rospy.Time(),
rospy.Duration(1.0))
self.base_frame = '/base_footprint'
except(tf.Exception, tf.ConnectivityException, tf.LookupException):
try:
self.tf_listener.waitForTransform(self.odom_frame,
'/base_link',
rospy.Time(),
rospy.Duration(1.0))
self.base_frame = '/base_link'
except(tf.Exception, tf.ConnectivityException, tf.LookupException):
rospy.loginfo("Cannot find base_frame transformed from /odom")
rospy.signal_shutdown("tf Exception") position = Point() for i in range(2):
move_cmd = Twist()
move_cmd.linear.x = linear_speed
# Initial pose, obtained from internal odometry
(position, rotation) = self.get_odom()
x_start = position.x
y_start = position.y
distance = 0 # Keep publishing Twist msgs, until the internal odometry reach the goal
while distance < goal_distance and not rospy.is_shutdown():
self.cmd_vel.publish(move_cmd)
r.sleep()
(position, rotation) = self.get_odom()
distance = sqrt( pow( (position.x-x_start), 2 ) + \
pow( (position.y-y_start), 2 ) ) # Stop 1 ms before rotate
move_cmd = Twist()
self.cmd_vel.publish(move_cmd)
rospy.sleep(1) move_cmd.angular.z = angular_speed
# should be the current ration from odom
angle_last = rotation
angle_turn = 0
while abs(angle_turn+angular_tolerance) < abs(goal_angle) \
and not rospy.is_shutdown():
self.cmd_vel.publish(move_cmd)
r.sleep()
(position, rotation) = self.get_odom
delta_angle = normalize_angle(rotation - angle_last)
angle_turn += delta_angle
angle_last = rotation move_cmd = Twist()
self.cmd_vel.publish(move_cmd)
rospy.sleep(1) self.cmd_vel.publish(Twist()) def get_dom(self):
try:
(trans, rot) = self.tf_listener.lookupTransfrom(self.odom_frame,
self.base_frame,
rospy.Time(0))
except(tf.Exception, tf.ConnectivityException, tf.LookupException):
rospy.loginfo("TF exception, cannot get_dom()!")
return
# angle is only yaw : RPY()[2]
return (Point(*trans), quat_to_angle(*rot)) def shutdown(self):
rospy.loginfo("Stopping the robot...")
self.cmd_vel.publish(Twist(0))
rospy.sleep(1) if __name__=='__main__':
try:
Odometry_forward_and_back()
except:
rospy.loginfo("Odometry_forward_and_back node terminated!")
注意这里存在tf操作:
self.tf_listener = tf.TransformListener()
rospy.sleep(2)
创建TransformListener对象监听坐标系变换,这里需要sleep 2ms用于tf缓冲。
可以通过以下API获取tf变换,保存在TransformListener对象中,通过lookupTransform获取:
# TransformListener.waitForTransform('ref_coordinate', 'moving_coordinate', rospy.Time(), rospy.Duration(1.0))
self.tf_listener.waitForTransform(self.odom_frame, '/base_footprint', rospy.Time(), rospy.Duration(1.0))
(trans, rot) = self.tf_listener.lookupTransform(self.odom_frame, self.base_frame, rospy.Time(0))
ROS Twist和Odometry消息类型使用(Python)的更多相关文章
- ros中文术语表及消息类型表
前言:整理一些ros常用表格,包括中文术语对照表. 一.中文术语表 二.消息类型表 -END-
- ROS多个master消息互通
需求 有时候我们需要有几个不同的master, 他们之间要交换topic的内容,这时候就不能使用ros自带的设置同一个master的方法. 我们的处理方法是,构造一个client和一个server,他 ...
- rabbitmq(中间消息代理)在python中的使用
在之前的有关线程,进程的博客中,我们介绍了它们各自在同一个程序中的通信方法.但是不同程序,甚至不同编程语言所写的应用软件之间的通信,以前所介绍的线程.进程队列便不再适用了:此种情况便只能使用socke ...
- Language Guide (proto3) | proto3 语言指南(一)定义消息类型
定义消息类型 首先让我们看一个非常简单的例子.假设您想定义一个搜索请求消息格式,其中每个搜索请求都有一个查询字符串.您感兴趣的特定结果页以及每页的结果数.下面是用于定义.proto消息类型的文件. s ...
- RabbitMQ消息中介之Python使用
本文介绍RabbitMQ在python下的基本使用 1. RabbitMQ安装,安装RabbitMQ需要预安装erlang语言,Windows直接下载双击安装即可 RabbitMQ下载地址:http: ...
- Activemq消息类型
Activemq消息类型JMS规范中的消息类型包括TextMessage.MapMessage.ObjectMessage.BytesMessage.和StreamMessage等五种.ActiveM ...
- 分析器错误消息: 类型“test.test.testx”不明确: 它可能来自程序集“F:\testProject\bin\test.test.DLL”或程序集“F:\testProject\bin \testProject.DLL”。请在类型名称中显式指定程序集。
问题描述: RT 分析器错误消息: 类型“test.test.testx”不明确: 它可能来自程序集“F:\testProject\bin\test.test.DLL”或程序集“F:\testProj ...
- ActiveMQ之二--JMS消息类型
1.前言 //发送文本消息 session.createTextMessage(msg); //接受文本消息 public void onMessage(Message msg) { TextMess ...
- JMS消息类型模型
JMS有两种消息类型模型,一种是P2P(Point To Point), 另一种是Pub/Sub(Publisher/Subscriber),二者之间的主要区别在于消息是否支持重复消费. P2P模型中 ...
随机推荐
- BZOJ1923:[SDOI2010]外星千足虫(高斯消元)
Description Input 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用“点足机”的统计结果.每行 包含一个“01”串和一个数字,用一个空格隔开.“01 ...
- 2019.1.3 Mac安装免费版StarUml3.0.2 &&&Xmind思维导图 &&Google浏览器***版
下载StarUml http://staruml.io/ 好像需要FQ 附赠一个 链接:https://pan.baidu.com/s/1_pa9LwopowhOTum5g89zZQ 密码:fxtc ...
- [Raspberry]001Ubuntu下查看linux版本,内核版本,系统位数,gcc版本
1. 查看linux版本 sunny@ubuntu:~$cat /etc/issueUbuntu 11.04 \n \l 2. 查看内核版本1) sunny@ubuntu:~$ cat /proc/ ...
- 在Mac机器上给ITerm2配置lrzsz,便捷的传输文件到远程服务器上
可直接参考文档:http://danqingdani.blog.163.com/blog/static/18609419520141201215750 需要使用到的github脚本:https://g ...
- 父窗口和iframe子窗口之间相互传递参数和调用函数或方法
1.父窗口向子窗口传递参数: 可以在url中添加参数:2.html?a=1&b=2&c=3 然后在子页面上可用js解析,提供一个函数: function getQueryStr(sAr ...
- 【译】2分钟介绍Rx
原文地址:https://medium.com/@andrestaltz/2-minute-introduction-to-rx-24c8ca793877 翻译去掉了一些口水话(⊙o⊙) 诸位应该已经 ...
- Oracle 体系结构一 概述
Oracle服务器由两个实体组成:实例和数据库. 实例由内存结构和进程组成. 它暂时存在于RAM和CPU中.当关闭运行的实例时,实例将消失的无影无踪. 数据库由磁盘上的文件组成.不管在运行状态还是停止 ...
- CSS、JavaScript学习过程
初学JavaScript,通过博客记录自己学习过程中遇到的问题.(包含少量CSS) 零碎记录 JavaScript 输出 type="text/javascript" 那些老旧的实 ...
- 基于LSB的图像数字水印实验
1. 实验类别 设计型实验:MATLAB设计并实现基于LSB的图像数字水印算法. 2. 实验目的 了解信息隐藏中最常用的LSB算法的特点,掌握LSB算法原理,设计并实现一种基于图像的LSB隐藏算法. ...
- 笔记: 对称加密算法的PKCS5 和 PKCS7 填充
PKCS #7 填充字符串由一个字节序列组成,每个字节填充该填充字节序列的长度. 假设,块的长度是 8, 数据长度是 5 数据:AA AA AA AA AA PKCS#7 填充 AA AA AA AA ...