ROS中利用tf工具或Eigen将imu数据转换至世界坐标下

该博客介绍了如何使用ROS中的tf工具将IMU数据从机体坐标系转换到世界坐标系,以适应卡尔曼滤波等处理。通过四元数和旋转矩阵实现坐标变换,提供了tf库和Eigen库两种实现方式的代码示例。文章还包含了代码解析和参考资料链接,适合ROS初学者和机器人定位导航领域的开发者阅读。
摘要由CSDN通过智能技术生成

ROS中的imu数据(sensor_msgs/imu)一般为机体坐标系下,如果后续需要进行卡尔曼滤波等处理,需要先将其转换至世界坐标系中。借助ROS中tf工具里面的转换矩阵功能,可以较为简单的实现这一目的。(tf官方教程中是教用broadcaster与listener,个人感觉在这里有点大材小用且复杂化了)

代码全文

#include "ros/ros.h"
#include "sensor_msgs/Imu.h"
#include "geometry_msgs/Vector3.h"
#include "tf/tf.h"

void imu_fix_callback(const sensor_msgs::Imu::ConstPtr& data){
    //将imu传感器中的四元数转换为tf工具中的四元数。顺序为x,y,z,w。
    tf::Quaternion q1={data->orientation.x,data->orientation.y,data->orientation.z,data->orientation.w}; 
    //通过四元数得到旋转矩阵
    tf::Matrix3x3 r1;
    r1.setRotation(q1);

    geometry_msgs::Vector3 acc_world;//构建向量用于储存转换后的数据
    //旋转矩阵右乘列向量获得转换后的向量
    acc_world.x=(r1[0][0]*data->linear_acceleration.x)+(r1[0][1]*data->linear_acceleration.y)+(r1[0][2]*data->linear_acceleration.z);
    acc_world.y=(r1[1][0]*data->linear_acceleration.x)+(r1[1][1]*data->linear_acceleration.y)+(r1[1][2]*data->linear_acceleration.z);
    acc_world.z=(r1[2][0]*data->linear_acceleration.x)+(r1[2][1]*data->linear_acceleration.y)+(r1[2][2]*data->linear_acceleration.z);
}


int main(int argc,char **argv)
{
    ros::init(argc,argv,"test");
    ros::NodeHandle nh;

    ros::Subscriber sub=nh.subscribe("/mavros/imu/data",100,imu_fix_callback);

    ros::spin();
    return 0;
}

新:)我发现Eigen版的更简单,所有在这里加一个。(代码是网页版手搓的,要是错了的话,根据提醒改一下就行,顺便告诉我一下)

#include <Eigen/Eigen>


void imu_fix_callback(const sensor_msgs::Imu::ConstPtr& data){
    //将imu传感器中的四元数转换为Eigen中的四元数。顺序为w,x,y,z。
    Eigen::Quaternionf q1={data->orientation.w,data->orientation.x,data->orientation.y,data->orientation.z}; 
    
    
    Eigen::Vector3f v1{data->linear_acceleration.x,data->linear_acceleration.y,data->linear_acceleration.x};   //加速度
    
    v1=q1.inverse()*v1;    //Eigen里面重载了四元数的乘法,实际数学意义为 p_new=q*p*q^(-1) .这里用q1的逆是因为公式为 :q_world*v_world = q_body * v_body 。

    //这么简单的公式我相信大家都懂的,只是我自己笨笨的,之前搞错了,所以记录一下让大伙乐一乐。
    //这时候的v1就是世界坐标系下的加速度了,记得自己减去重力!!!此外,你要是姿态不准的话,去重力不够好,你的加速度信息就挺不好看的。    
}

代码比较简单,也带有注释,看到这里就看懂的就不需要继续往下看了。下面是代码更详细的解析与参考资料链接。

代码解析

int main(int argc,char **argv)
{
    ros::init(argc,argv,"test");
    ros::NodeHandle nh;

    ros::Subscriber sub=nh.subscribe("/mavros/imu/data",100,imu_fix_callback);

    ros::spin();
    return 0;
}

常规的消息订阅,没什么好讲的,刚入门的话建议去看 官方教程

    //将imu传感器中的四元数转换为tf工具中的四元数。顺序为x,y,z,w。
    tf::Quaternion q1={data->orientation.x,data->orientation.y,data->orientation.z,data->orientation.w}; 
    //通过四元数得到旋转矩阵
    tf::Matrix3x3 r1;
    r1.setRotation(q1);

quaternion是tf工具里面储存四元数的一个类,除直接输入x,y,z,w以外,也可以通过输入欧拉角进行设置(里面的setRPY函数)。tf::Quaternion Class Reference

matrix3x3是tf工具里面的3x3多功能矩阵,这里利用的是其通过四元数转换旋转矩阵的功能(setRotation)。详细官方文档在此:tf::Matrix3x3 Class Reference

//旋转矩阵右乘列向量获得转换后的向量
    acc_world.x=(r1[0][0]*data->linear_acceleration.x)+(r1[0][1]*data->linear_acceleration.y)+(r1[0][2]*data->linear_acceleration.z);
    acc_world.y=(r1[1][0]*data->linear_acceleration.x)+(r1[1][1]*data->linear_acceleration.y)+(r1[1][2]*data->linear_acceleration.z);
    acc_world.z=(r1[2][0]*data->linear_acceleration.x)+(r1[2][1]*data->linear_acceleration.y)+(r1[2][2]*data->linear_acceleration.z);

这里的作用就是旋转矩阵与向量相乘。对应的矩阵运算为:

\begin{bmatrix} r_{00} &r_{01} &r_{02} \\ r_{10}& r_{11} & r_{12} \\ r_{20}&r_{21} &r_{22} \end{bmatrix}*\begin{bmatrix} x\\ y\\z \end{bmatrix}

Matrix3x3对运算符[]进行了重载,可直接获得行向量(返回tf的vector类型),可以结合下图进行理解。

(图来源:ros tf 向量计算示例,欧拉角、四元数、转换矩阵之间的互转。里面还有更多情况下的转换,有兴趣的可以去看看原文。)

由于是小功能,代码就写的很随意与丑陋了,改进与优化的任务就留给读者自行解决了,希望能帮助到各位。如有疑问与纠错,欢迎在评论区留言。如需转载,标明出处且附上链接即可。

参考文献

ros tf 向量计算示例,欧拉角、四元数、转换矩阵之间的互转

 tf::Quaternion Class Reference

tf::Matrix3x3 Class Reference

IMU(惯性测量单元)的数据和机器人底盘(通常作为"base_link")之间的TF转换帧)已经确定,你可以通过ROS(Robot Operating System)tf包来进行坐标系转换。以下是一个基本步骤: 1. **导入必要的库**: 首先,在Python代码,你需要导入`tf`(transformations模块的一部分),以及ROS的相关API。 2. **获取TF信息**: 使用`rospy.wait_for_transform()`函数等待imu和base_link之间的转换已经被建立。这通常在ROS节点启动并连接好所有话题后自动完成。 ```python import rospy from tf.transformations import quaternion_from_euler, concatenate_matrices from geometry_msgs.msg import PoseWithCovarianceStamped ``` 3. **订阅IMU数据**: 订阅imu话题上发布的数据(如姿态、速度等)。 4. **IMU数据处理**: 对接收到的IMU数据(比如姿态四元数和加速度计读数),将其转换成适合TF框架的几何消息(如PoseWithCovarianceStamped),包含位置和旋转部分。 5. **坐标系转换**: 使用`concatenate_matrices`函数结合位置和平移矩阵,以及TF提供的旋转矩阵(quaternion_to_matrix),将IMU数据imu坐标系转换到base_link坐标系。 ```python def transform_imu_data(imu_msg): # 获取imu到base_link的转换矩阵 trans = tf_listener.lookupTransform('base_link', 'imu', rospy.Time(0)) # 将imu姿态四元数转换为旋转矩阵 quat = quaternion_from_euler(*imu_msg.orientation) rot = quaternion_matrix(quat) # 构建新的姿态消息 transformed_pose = PoseWithCovarianceStamped() transformed_pose.header.frame_id = 'base_link' transformed_pose.pose.pose.position.x = trans[0][0] * imu_msg.pose.pose.position.x + trans[0][1] * imu_msg.pose.pose.position.y + trans[0][2] * imu_msg.pose.pose.position.z transformed_pose.pose.pose.position.y = trans[1][0] * imu_msg.pose.pose.position.x + trans[1][1] * imu_msg.pose.pose.position.y + trans[1][2] * imu_msg.pose.pose.position.z transformed_pose.pose.pose.position.z = trans[2][0] * imu_msg.pose.pose.position.x + trans[2][1] * imu_msg.pose.pose.position.y + trans[2][2] * imu_msg.pose.pose.position.z transformed_pose.pose.pose.orientation = rot.dot(quat) # 线性变换四元数 return transformed_pose ``` 6. **发布转换后的数据**: 最后,将处理过的转换后的姿态发布到一个新的话题,供其他组件使用。 记得在实际操作前检查tf是否稳定可用,并确保你的ROS环境设置正确。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值