ROS坐标转换工具

tf2

API手册

tf2定义的数据

头文件:#include<tf2/LinearMath/...>

geometry_msgs的消息类型有很好的对应关系,并可以通过tf2_geometry_msgs包进行转化。

tf2::Quaternion 对应 geometry_msgs::Quaternion

tf2::Vector3 对应 geometry_msgs::Vector3 geometry_msgs::Point

tf2::Transform 对应 geometry_msgs::Pose geometry_msgs::Transform

tf2::Stamped 模板类

给数据类型带上header,将tf2的数据类型与geometry_msgs的Stamped对应。

公共属性

  • std::string frame_id_
    The frame_id associated this data.

  • ros::Time stamp_
    The time stamp associated with this data.

公共成员函数

Stamped<T> & operator= (const Stamped<T> &rhs)
void setData (const T &input){*static_cast<T*>(this) = input;};
Stamped()
Stamped (const Stamped<T> &s)
Stamped (const T &input, const ros::Time &timestamp, const std::string &frame_id)

tf2::Stamped<tf2::Quaternion> 对应 geometry_msgs::QuaternionStamped

tf2::Stamped<tf2::Vector3> 对应 geometry_msgs::Vector3Stamped geometry_msgs::PointStamped

tf2::Stamped<tf2::Transform> 对应 geometry_msgs::PoseStamped geometry_msgs::TransformStamped

对应的数据类型均可以通过tf2_geometry_msgs包的tf2::fromMsgtf2::toMsg函数转化。

跳转链接:tf2_geometry_msgs

Quaternion

头文件
#include "tf2/LinearMath/Quaternion.h"
成员函数
tf2Scalar tf2::Quaternion::getX();//获取x分量
tf2Scalar tf2::Quaternion::getY();//获取y分量
tf2Scalar tf2::Quaternion::getZ();//获取z分量
tf2Scalar tf2::Quaternion::getW();//获取w分量
Quaternion tf2::Quaternion::inverse();//求逆
tf2Scalar tf2::Quaternion::angle(const Quaternion& q)//返回两个四元数表示的转角的中间角

对于四元数,有两种 数据类型:msg 和 tf

geometry_msgs::Quaternion quat_msg //这种声明的就是 msg 类型
tf tf2::Quaternion myQuaternion //这种声明的就是 tf 类型

在tf2_geometry_msgs.h ⽂件中提供了数据类型转换的函数

#include <tf2_geometry_msgs/tf2_geometry_msgs.h>
tf2::Quaternion quat_tf;
geometry_msgs::Quaternion quat_msg;
tf2::convert(quat_msg,quat_tf);//将msg类型转换为tf类型
tf2::fromMsg(quat_msg,quat_tf);//将msg类型转换为tf类型
quat_msg=tf2::toMsg(quat_tf);//将tf类型转换为msg类型
四元数与欧拉角的转换
四元数转欧拉角
void tf2::Quaternion::setRPY(const tf2Scalar &roll,
                             const tf2Scalar &pitch,
                             const tf2Scalar &yaw );
void tf2::Quaternion::setEulerZYX(const tf2Scalar &yaw,
                                  const tf2Scalar &pitch,
                                  const tf2Scalar &roll){
    setRPY(roll,pitch,yaw);
}

设置表示以下旋转的四元数

  1. 先绕物体的Z轴旋转偏航角yaw
  2. 绕旋转之后的Y轴旋转俯仰角pitch
  3. 绕旋转之后的X轴旋转滚转角roll// Transform from global_frame_ to map_frame_
  • Parameters
    • roll : Angle around X
    • pitch : Angle around Y
    • yaw : Angle around Z
欧拉角转四元数

API

tf2::Quaternion quat;
double roll,pitch,yaw;//定义存储rpy的容器
//法一
#include <tf2/impl/utils.h>
void tf2::impl::getEulerYPR(const tf2::Quaternion &q,double &yaw,double &pitch,double &roll);
double tf2::impl::getYaw(const tf2::Quaternion &q);//getEulerYPR的简化版
//法二
tf2:Matrix3x3 m(quat);
m.getRPY(roll,pitch,yaw);//进行转换

坐标转换

API

tf会对非记录点的中间时刻进行插值计算。

最重要的三个类:坐标转换发布者tf2_ros::TransformBroadcaster,坐标转换监听者tf2_ros::TransformListener,坐标转换监听者缓存区tf2_ros::Buffertf2_ros::TransformListenertf2_ros::Buffer配合使用实现坐标监听和坐标转换,tf2_ros::TransformListener只有一个构造函数,负责ROS中订阅坐标树话题,tf2_ros::Buffer用来缓存从坐标树话题接收的坐标转换信息,其提供了所有的坐标监听和坐标转换的API。

另外还有专门针对静态坐标转换优化的tf2_ros::StaticTransformBroadcaster,不再保留时间历史,节省存储和查找时间。

tf2_ros::TransformBroadcaster

#include <tf2_ros/transform_broadcaster.h>
void TransformBroadcaster::sendTransform(const geometry_msgs::TransformStamped & msgtf)
void TransformBroadcaster::sendTransform(const std::vector<geometry_msgs::TransformStamped> & msgtf)

tf2_ros::TransformListener

此类提供了一种请求和接收坐标系变换信息的简单方法

#include <tf2_ros/transform_listener.h>
TransformListener(tf2::BufferCore &buffer, bool spin_thread=true, ros::TransportHints transport_hints=ros::TransportHints())
TransformListener(tf2::BufferCore &buffer, const ros::NodeHandle &nh, bool spin_thread=true, ros::TransportHints transport_hints=ros::TransportHints())
  • spin_thread:是否单开回调线程

tf2_ros::Buffer

Buffer (ros::Duration cache_time=ros::Duration(BufferCore::DEFAULT_CACHE_TIME), bool debug=false);
//cache_time:保存多长时间的历史坐标变换
检测坐标转换是否可以提供
//普通API,查询目标时刻的两个坐标系的坐标转换
bool tf2_ros::Buffer::canTransform (const std::string &target_frame,
                                    const std::string &source_frame,
                                    const ros::Time &target_time,
                                    const ros::Duration timeout,
                                    std::string *errstr = NULL )	
//高级API,查询目标时刻的目标坐标系到源时刻的源坐标系的坐标转换
bool tf2_ros::Buffer::canTransform (const std::string &target_frame,
                                    const ros::Time &target_time,
                                    const std::string &source_frame,
                                    const ros::Time &source_time,
                                    const std::string &fixed_frame,
                                    const ros::Duration timeout,
                                    std::string *errstr = NULL )	

Parameters

  • target_frame

    目标坐标系

  • target_time

    需要转换的目标坐标系的时刻

  • source_frame

    源坐标系

  • source_time

    需要转换的源坐标系的时刻

  • fixed_frame

    不随时间变化的固定坐标系,比如“world”,“map”

  • timeout

    How long to block before failing

  • errstr

    A pointer to a string which will be filled with why the transform failed, if not NULL

查询坐标变换并缓存到缓存区
//普通API,查询目标时刻的两个坐标系的坐标转换
geometry_msgs::TransformStamped tf2_ros::Buffer::lookupTransform(const std::string &target_frame,
                                                                 const std::string &source_frame,
                                                                 const ros::Time &time,
                                                                 const ros::Duration timeout )
//高级API,查询源时刻的源坐标系到目标时刻的目标坐标系的坐标转换(源坐标系相对目标坐标系的偏移)
geometry_msgs::TransformStamped tf2_ros::Buffer::lookupTransform(const std::string &target_frame,
                                                                 const ros::Time &target_time,
                                                                 const std::string &source_frame,
                                                                 const ros::Time &source_time,
                                                                 const std::string &fixed_frame,
                                                                 const ros::Duration timeout )	
  • 参数

    • time

      需要坐标转换的时间点(0代表最新的)

    • target_frame

      目标坐标系

    • target_time

      需要转换的目标坐标系的时刻(0代表最新的)

    • source_frame

      源坐标系

    • source_time

      需要转换的源坐标系的时刻(0代表最新的)

    • fixed_frame

      不随时间变化的固定坐标系,比如“world”,“map”

    • timeout

      How long to block before failing

  • 返回值:代表坐标转换的TransformStamped消息

通常用法

tf2_ros::Buffer buffer(ros::Duration(10));
tf2_ros::TransformListener tfListener(buffer);
try
{
    transform = buffer->lookupTransform(map_frame_, global_frame_, ros::Time(0));
}
catch (tf2::TransformException ex)
{
    ROS_ERROR("%s", ex.what());
    return;
}
执行坐标变换

注意:Vector3和Point的坐标变换是不同的,Vector3是矢量,坐标变换只改变方向,而Point是坐标点,既旋转又平移变换。

  1. 坐标转换乘法

    geometry_msgs::TransformStamped transform;
    transform = buffer->lookupTransform(map_frame, global_frame, ros::Time(0));
    tf2::Transform tf2_transform;
    tf2::convert(transform.transform, tf2_transform);
    tf2::Vector3 p(x,y,z);
    p = tf2_transform * p;// Transform from global_frame to map_frame
    
  2. tf2::doTransform API

    template<class T >
    void tf2::doTransform( const T &data_in, T &data_out,const geometry_msgs::TransformStamped &transform )	
    
  3. Buffer成员函数transformAPI

    内部也是调用tf2::doTransformAPI实现

    //返回值作为输出
    template <class T>
         T& transform(const T& in, T& out, 
                      const std::string& target_frame, ros::Duration timeout=ros::Duration(0.0)) const
    
    template<class T >//简单API,同一时间点的转换
    T tf2_ros::BufferInterface::transform(const T &in,
                                          const std::string &target_frame,
                                          ros::Duration timeout = ros::Duration(0.0) )	
    template<class T >//高级API,允许在不同时间点之间进行转换,并指定不随时间变化的固定帧
    T tf2_ros::BufferInterface::transform(const T &in,
                                          const std::string &target_frame,
                                          const ros::Time &target_time,
                                          const std::string &fixed_frame,
                                          ros::Duration timeout = ros::Duration(0.0) )
    //参数引用作为输出
    template<class T >//简单API,同一时间点的转换
    T& tf2_ros::BufferInterface::transform(const T &in, T &out, 
                                           const std::string &target_frame,
                                           ros::Duration timeout = ros::Duration(0.0) )
    {
        // do the transform
        tf2::doTransform(in, out, lookupTransform(target_frame, tf2::getFrameId(in), tf2::getTimestamp(in), timeout));
        return out;
    }
    template<class T >//高级API,允许在不同时间点之间进行转换,并指定不随时间变化的固定帧
    T& tf2_ros::BufferInterface::transform(const T &in, T &out, 
                                           const std::string &target_frame,
                                           const ros::Time &target_time,
                                           const std::string &fixed_frame,
                                           ros::Duration timeout = ros::Duration(0.0) )	
    {
        // do the transform
        tf2::doTransform(in, out, lookupTransform(target_frame, target_time, 
                                                  tf2::getFrameId(in), tf2::getTimestamp(in), 
                                                  fixed_frame, timeout));
        return out;
    }
    //将结果转换为指定的输出类型,输入类型A,输出类型B
    template<class A , class B >//简单API,同一时间点的转换
    B& tf2_ros::BufferInterface::transform(const A &in, B &out,
                                           const std::string &target_frame,
                                           ros::Duration timeout = ros::Duration(0.0) )
    template<class A , class B >//高级API,允许在不同时间点之间进行转换,并指定不随时间变化的固定帧
    B& tf2_ros::BufferInterface::transform(const A &in, B &out,
                                           const std::string &target_frame,
                                           const ros::Time &target_time, 
                                           const std::string &fixed_frame,
                                           ros::Duration timeout = ros::Duration(0.0) )	
    

    模板类型可以是Transform、Pose、Vector、Quaternion(在geometry_msgs中定义的)

tf2_geometry_msgs

API手册

定义函数

  • 坐标转换函数:tf2::doTransform

  • 格式转换函数:tf2::convert

    template<class A , class B >
    void tf2::convert( const A &a,B &b )//从A转换为B,底层依靠fromMsg和toMsg实现,需有对应类型的fromMsg或toMsg定义	
    
  • geometry_msgs转化为tf2数据类型:tf2::fromMsg(geometry_msgs::A,tf2::B)

  • tf数据类型转化为geometry_msgs:geometry_msgs::B = tf2::toMsg(tf2::A)

  • 从geometry_msgs消息的header中提取frame id:tf2::getFrameId

  • 从geometry_msgs消息的header中提取stamp时间:tf2::getTimestamped

tf2_eigen

头文件#include<tf2_eigen/tf2_eigen.h>
包含eigen和geometry_msgs数据类型的相互转换

tf2命名空间

API手册

geometry_msgs::TransformStamped eigenToTransform (const Eigen::Isometry3d &T)
geometry_msgs::TransformStamped eigenToTransform (const Eigen::Affine3d &T)
Eigen::Isometry3d transformToEigen (const geometry_msgs::Transform &t)
Eigen::Isometry3d transformToEigen (const geometry_msgs::TransformStamped &t)

注意:调用上述方法需要加tf2::

Eigen命名空间

void fromMsg (const geometry_msgs::Point &msg, Eigen::Vector3d &out)
void fromMsg (const geometry_msgs::Pose &msg, Eigen::Affine3d &out)
void fromMsg (const geometry_msgs::Pose &msg, Eigen::Isometry3d &out)
void fromMsg (const geometry_msgs::Quaternion &msg, Eigen::Quaterniond &out)
void fromMsg (const geometry_msgs::Twist &msg, Eigen::Matrix< double, 6, 1 > &out)
geometry_msgs::Pose toMsg (const Eigen::Affine3d &in)
geometry_msgs::Pose toMsg (const Eigen::Isometry3d &in)
geometry_msgs::Twist toMsg (const Eigen::Matrix< double, 6, 1 > &in)
geometry_msgs::Quaternion toMsg (const Eigen::Quaterniond &in)
geometry_msgs::Point toMsg (const Eigen::Vector3d &in)

注意:调用上述方法需要加Eigen::

发布静态坐标变换

<launch>
   <node pkg="tf2_ros" type="static_transform_publisher" args="x y z yaw pitch roll frame_id child_frame_id period_in_ms" />
   <node pkg="tf2_ros" type="static_transform_publisher" args="x y z qx qy qz qw frame_id child_frame_id period_in_ms" />
</launch>
  • 欧拉角是ZYX顺序(父坐标系先旋转yaw角,再旋转pitch角,再旋转roll角,得到子坐标系)。
  • period_in_ms决定发布频率,以周期(ms)的形式给出

发布机器人各关节的坐标变换

joint_state_publisher

joint_state_publisher - ROS Wiki

该节点从参数服务器读取robot_description参数,发现机器人urdf文件定义中的non-fixed joints,并且以sensor_msgs/JointState消息的格式发布这些joints定义。

该节点配合robote_state_publisher节点使用,发布机器人的所有tf变换。

常用参数

  • rate

    发布joint states的频率

robot_state_publisher

robot_state_publisher - ROS Wiki

将机器人的状态发布到tf2

robot_state_publisher使用参数robots_description指定的URDF和来自话题joint_states(一般由joint_state_publisher发布)的关节位置信息来计算机器人各部件的位置关系并通过tf发布坐标变换。

常用参数

  • use_tf_static(bool)

    设置是否使用/tf_static锁存static transform broadcaster发布的静态坐标变换

回答: 引发com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN的原因是登录时使用的身份验证机制PLAIN被拒绝了。\[1\]这可能是由于账号密码不正确、没有赋予账号密码权限、5672端口没有正常对外开放等原因引起的。解决方法可以包括检查账号密码是否正确、检查是否赋予了账号密码权限、检查5672端口是否正常对外开放等。\[3\]另外,还需要确保虚拟主机的访问权限被正确指定。\[3\] #### 引用[.reference_title] - *1* [com.rabbitmq.client.AuthenticationFailureException: ACCESS_REFUSED - Login was refused using authent](https://blog.csdn.net/qq_45995427/article/details/120086426)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [解决ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the ...](https://blog.csdn.net/lvoelife/article/details/126657171)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [RabbitMQ异常:ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN.](https://blog.csdn.net/duyun0/article/details/127564315)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Shilong Wang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值