基于Eigen的位姿转换

       位姿中姿态的表示形式有很多种,比如:旋转矩阵、四元数、欧拉角、旋转向量等等。这里基于Eigen实现四种数学形式的相互转换功能。本文利用Eigen实现上述四种形式的相互转换。我这里给出一个SE3(4*4)(先平移、再旋转)的构建方法:

Eigen::Isometry3f T1 = Eigen::Isometry3f::Identity(); // 这一句千万别掉
// <1> 初始化R
Eigen::Matrix3f R;
// 按照 ZYX 顺序旋转
R = Eigen::AngleAxisf(3.14159 / 4, Eigen::Vector3f::UnitX()) *Eigen::AngleAxisf(0, Eigen::Vector3f::UnitY()) *Eigen::AngleAxisf(0, Eigen::Vector3f::UnitZ());
// <2> 初始化t
Eigen::Vector3f t(0.0, 0.0, 4.0);
// <3> 构建T = (R|t)
T1.rotate(R);
T1.pretranslate(t); // 这一句别搞错
//T1.translate(t);
std::cout << "T1 = " <<T1.matrix() <<std::endl;

打印结果:

T1 =         1         0         0         00  0.707107 -0.707106         00  0.707106  0.707107         40         0         0         1

下面的黄色立方体,相对坐标系位置为:(0 0 4),绕x轴旋转pi /4,得到绿色立方体

以下是在本地word中笔记的截图:

Pose.h(类Pose声明)

#pragma once
#ifndef POSE_H
#define POSE_H#include<Eigen/Core>
#include<Eigen/Geometry>// namespace Geometryclass Pose
{
public:Pose();Pose& operator= (const Pose& pose);// construct from rotationPose(const Eigen::Matrix3d& rotation);// construct from quaternionPose(const Eigen::Quaterniond& quaternion);// construct from angle axisdPose(const Eigen::AngleAxisd& angle_axis);// construct from euler anglePose(const Eigen::Vector3d& euler_angle);~Pose();// return rotationEigen::Matrix3d rotation() const;// return quaterniondEigen::Quaterniond quaternion() const;// return angle axisdEigen::AngleAxisd angle_axis() const;// return euler angleEigen::Vector3d euler_angle() const;private:Eigen::Matrix3d rotation_;       // 旋转矩阵Eigen::Quaterniond quaternion_;  // 四元数Eigen::AngleAxisd angle_axis_;  // 角轴Eigen::Vector3d euler_angle_;    // 欧拉角 roll(X轴)  pitch(Y轴) yaw(Z轴)};// 姿态组合
Eigen::Isometry3d compose(const Eigen::Isometry3d& T1, const Eigen::Isometry3d& T2);// 求逆
Eigen::Isometry3d inverse(const Eigen::Isometry3d& T);#endif // !POSE_H

Pose.cpp(类Pose的实现)

#include "Pose.h"Pose::Pose()
{}Pose& Pose::operator= (const Pose& pose)
{this->rotation_    = pose.rotation();this->quaternion_  = pose.quaternion();this->angle_axis_ = pose.angle_axis();this->euler_angle_ = pose.euler_angle();return *this;
}//
Pose::Pose(const Eigen::Matrix3d& rotation) :rotation_(rotation),quaternion_(Eigen::Quaterniond(rotation_)),angle_axis_(Eigen::AngleAxisd(rotation_)),euler_angle_(rotation_.eulerAngles(0, 1, 2))
{}Pose::Pose(const Eigen::Quaterniond& quaternion)
{quaternion.normalized();this->rotation_    = quaternion.toRotationMatrix();this->quaternion_  = Eigen::Quaterniond(rotation_);this->angle_axis_ = Eigen::AngleAxisd(rotation_);this->euler_angle_ = rotation_.eulerAngles(0, 1, 2);
}Pose::Pose(const Eigen::AngleAxisd& angle_axis) :rotation_(angle_axis),quaternion_(Eigen::Quaterniond(rotation_)),angle_axis_(Eigen::AngleAxisd(rotation_)),euler_angle_(rotation_.eulerAngles(0, 1, 2))
{}Pose::Pose(const Eigen::Vector3d& euler_angle) :rotation_(Eigen::AngleAxisd(euler_angle.x(), Eigen::Vector3d::UnitX()) * // note: ZYXEigen::AngleAxisd(euler_angle.y(), Eigen::Vector3d::UnitY()) *Eigen::AngleAxisd(euler_angle.z(), Eigen::Vector3d::UnitZ())),quaternion_(Eigen::Quaterniond(rotation_)),angle_axis_(Eigen::AngleAxisd(rotation_)),euler_angle_(rotation_.eulerAngles(0, 1, 2))
{}Pose::~Pose()
{}Eigen::Matrix3d Pose::rotation() const
{return this->rotation_;
}Eigen::Quaterniond Pose::quaternion() const
{return this->quaternion_;
}Eigen::AngleAxisd Pose::angle_axis() const
{return this->angle_axis_;
}Eigen::Vector3d Pose::euler_angle() const
{return this->euler_angle_;
}Eigen::Isometry3d compose(const Eigen::Isometry3d& T1, const Eigen::Isometry3d& T2)
{return T1 * T2;
}Eigen::Isometry3d inverse(const Eigen::Isometry3d& T)
{return T.inverse();
}

test_pose.cpp

#include<iostream>
using namespace std;#include"Pose.h"
const double M_PI = 3.1415926535;// 对于同一个姿态,从不同的数学形式(旋转矩阵、四元数、欧拉角、角轴)构造类Pose
// 依次得到 pose1 pose2 pose3 pose4
void testClassPose(const Eigen::Matrix3d& R1)
{Pose pose1(R1);cout << "旋转矩阵 = " << endl; cout << pose1.rotation() << endl;cout << "欧拉角 = " << endl;   cout << pose1.euler_angle().transpose()*(180 / M_PI) << endl;cout << "四元数 = " << endl;   cout << pose1.quaternion().coeffs().transpose() << endl;cout << "角轴 = " << endl;cout << pose1.angle_axis().angle()* (180 / M_PI) <<" " << pose1.angle_axis().axis().transpose() <<endl;cout << "-----------------------------" << endl;Pose pose2(pose1.euler_angle());cout << "旋转矩阵 = " << endl; cout << pose2.rotation() << endl;cout << "欧拉角 = " << endl;   cout << pose2.euler_angle().transpose()*(180 / M_PI) << endl;cout << "四元数 = " << endl;   cout << pose2.quaternion().coeffs().transpose() << endl;cout << "角轴 = " << endl;cout << pose2.angle_axis().angle()* (180 / M_PI) << " " << pose2.angle_axis().axis().transpose() << endl;cout << "-----------------------------" << endl;Pose pose3(pose1.angle_axis());cout << "旋转矩阵 = " << endl; cout << pose3.rotation() << endl;cout << "欧拉角 = " << endl;   cout << pose3.euler_angle().transpose()*(180 / M_PI) << endl;cout << "四元数 = " << endl;   cout << pose3.quaternion().coeffs().transpose() << endl;cout << "角轴 = " << endl;cout << pose3.angle_axis().angle()* (180 / M_PI) << " " << pose3.angle_axis().axis().transpose() << endl;cout << "-----------------------------" << endl;Pose pose4 = pose3;cout << "旋转矩阵 = " << endl; cout << pose4.rotation() << endl;cout << "欧拉角 = " << endl;   cout << pose4.euler_angle().transpose()*(180 / M_PI) << endl;cout << "四元数 = " << endl;   cout << pose4.quaternion().coeffs().transpose() << endl;cout << "角轴 = " << endl;cout << pose4.angle_axis().angle()* (180 / M_PI) << " " << pose4.angle_axis().axis().transpose() << endl;cout << "-----------------------------" << endl;}// 测试求逆、compose等
void testTheOthers(Eigen::Matrix3d R1, Eigen::Vector3d t1,Eigen::Matrix3d R2, Eigen::Vector3d t2)
{// 初始化T1Eigen::Isometry3d T1 = Eigen::Isometry3d::Identity();T1.prerotate(R1); T1.pretranslate(t1);cout << "T1" << endl; cout << T1.matrix() << endl;// 初始化T2Eigen::Isometry3d T2 = Eigen::Isometry3d::Identity();T2.prerotate(R2); T2.pretranslate(t2);cout << "T2" << endl; cout << T2.matrix() << endl;// 求逆Eigen::Isometry3d T1_inverse = inverse(T1);cout << "T1_inverse = " << endl; cout << T1_inverse.matrix() << endl;// composeEigen::Isometry3d T12 = compose(T1, T2);cout << "T12 = " << endl; cout <<  T12.matrix() << endl;/*cout << "Rotation = " << endl;cout << T1.rotation() * T2.rotation() << endl;cout << "Translation = " << endl;cout << T1.rotation() * T2.translation() + T1.translation() << endl;*/}int main()
{Eigen::Matrix3d R1; //R1R1 = Eigen::AngleAxisd((30.0 / 180) * M_PI, Eigen::Vector3d::UnitX())*Eigen::AngleAxisd((25.0 / 180) * M_PI, Eigen::Vector3d::UnitY())*Eigen::AngleAxisd((27.0 / 180) * M_PI, Eigen::Vector3d::UnitZ());Eigen::Vector3d t1(1.2, 0.234, 2.3);//t1Eigen::Matrix3d R2; //R2R2 = Eigen::AngleAxisd((23.0 / 180) * M_PI, Eigen::Vector3d::UnitX())*Eigen::AngleAxisd((33.0 / 180) * M_PI, Eigen::Vector3d::UnitY())*Eigen::AngleAxisd((89.0 / 180) * M_PI, Eigen::Vector3d::UnitZ());Eigen::Vector3d t2(0.1, 0.4, 0.1); //t2// <1> test Class PosetestClassPose(R1);// <2> test halcon's apitestTheOthers(R1, t1, R2, t2);return 1;
}

可以看到,同一个姿态,不同的表达形式,他们之间相互转换之后结果数值一致。

        写在最后,一个T为4×4的变换矩阵,如果旋转分量是欧式正交群,那个这个T为:欧式变换;否者为:仿射变换。如果一个旋转矩阵,不是SO3,那么可以将其转为四元数,接着归一化,再转为旋转矩阵,这样结果就属于SO3。同理,如果一个四元数,最好对齐进行归一化处理,再转为其他形式。例如:构造函数Pose(const Eigen::Quaterniond& quaternion); 其实现中比其他构造函数多了归一化这一步骤;即:quaternion.normalized();

       请看测试案例test3(),我们在第4或第5行进行四元数归一化,那么24行打印出来的矩阵就是单位阵。(不归一化,则不是单位阵)

void test3()
{Eigen::Quaterniond q = { 0.1,0.35,0.2,0.3 };//q.normalize();Eigen::Matrix3d R = q.normalized().toRotationMatrix();cout << "R = " << endl;cout << R << endl;cout << endl;Eigen::Matrix3d R_transpose = R.transpose();cout << "R.transpose = " << endl;cout << R_transpose << endl;cout << endl;Eigen::Matrix3d R_inverse = R.inverse();cout << "R.inverse = " << endl;cout << R_inverse << endl << endl;cout << endl;Eigen::Matrix3d ret = R * R.transpose();cout << "ret = " << endl;cout << ret << endl << endl;cout << endl;
}

运行结果:

        现在,如果给定一个旋转矩阵(如果你是随机测试,请你参考博客开始部分公式,每个元素是有取值范围的,给出的数字不要太离谱);如下测试案例test4。第8行在底层有四元数归一化操作,所以你看下面效果图,R * R.tranpose() 近似为一个单位矩阵。

void test4()
{Eigen::Matrix3d R;R << 0.74, 0.08, 0.25,0.2, 0.575, 0.05,0.17, 0.19, 0.675;Pose p1(R);Pose p2(p1.quaternion()); // Pose中,针对从四元数构造,默认有归一化功能R = p2.rotation();cout << "R = " << endl;cout << R << endl;cout << endl;cout << "R.inverse = " << endl;cout << R.inverse() << endl;cout << endl;cout << "R.transpose = " << endl;cout << R.transpose() << endl;cout << endl;cout << "R * R.transpose() = " << endl;cout << R * R.transpose() << endl;cout << endl;
}

运行结果:

        其中,R表示旋转,用旋转向量来描述(欧拉角有周期性和方向锁的问题,四元数有单位向量的约束,旋转矩阵冗余度太高且有各个基需要是单位正交的约束);t表示平移,用平移向量来描述。R和t均采用无约束的向量进行描述,于是也均可以通过网络的学习来得到。因为R和t共有六个自由度,因此姿态估计又称为6D姿态估计。

注:旋转向量的方向代表旋转轴,模长代表旋转角的大小,旋转方向为逆时针。

        Eigen对于 translate 与 pretranslate的区别?(先平移、再旋转和 先旋转、再平移,有何区别?)可以看看这个:https://zhuanlan.zhihu.com/p/165020637

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/105757.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有关范数的学习笔记

向量的【范数】&#xff1a;模长的推广&#xff0c;柯西不等式_哔哩哔哩_bilibili 模长 范数 这里UP主给了说明 点赞 范数理解&#xff08;0范数&#xff0c;1范数&#xff0c;2范数&#xff09;_一阶范数-CSDN博客 出租车/曼哈顿范数 det()行列式 正定矩阵&#xff08;Posit…

高校教务系统登录页面JS分析——皖西学院

高校教务系统密码加密逻辑及JS逆向 本文将介绍皖西学院教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的过程。通过本文&#xff0c;你将了解到密码加密的基本概念、常用加密算法以及如何通过逆向分析来破解密码。 本文仅供交流学习&#xff0c;勿用于非法用途。 一、密…

软件工程与计算总结(十三)详细设计中的模块化与信息隐藏

一.模块化与信息隐藏思想 1.设计质量 好的设计要着重满足以下3方面&#xff1a;可管理性、灵活性、可理解性好的设计需要侧重于间接性和可观察性——简洁性使得系统模块易于管理&#xff08;理解和分解&#xff09;、开发&#xff08;修改与调试&#xff09;和复用。实践者都…

集成学习的小九九

集成学习&#xff08;Ensemble Learning&#xff09;是一种机器学习的方法&#xff0c;通过结合多个基本模型的预测结果来进行决策或预测。集成学习的目标是通过组合多个模型的优势&#xff0c;并弥补单个模型的不足&#xff0c;从而提高整体性能。 集成学习的主要策略 在集成…

如果不封车,坚持冬天骑行应该注意些什么?

亲爱的骑行爱好者们&#xff0c;你们好&#xff01;随着秋天的脚步渐行渐远&#xff0c;冬天也不远了。对于热爱骑行的你们来说&#xff0c;秋天的骑行是一种享受&#xff0c;而冬天的骑行则是一种挑战。那么&#xff0c;如果你打算在秋天骑行不封车&#xff0c;坚持过冬天&…

elementUI el-table+树形结构子节点选中后没有打勾?(element版本问题 已解决)

问题 1.不勾选父级CB111&#xff0c;直接去勾选子级&#xff08;ST2001…&#xff09;&#xff0c;子级选中后没有打勾显示 排查 一直以为是这个树形结构和表格不兼容产生的问题&#xff0c;到后来看官方demo都是可以勾选的&#xff0c;最后排查到了版本问题&#xff0c; 项…

竞赛选题 深度学习 机器视觉 车位识别车道线检测 - python opencv

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 车位识别车道线检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) …

《UnityShader入门精要》学习5

Unity中的基础光照 从宏观上来说&#xff0c;渲染包含了两大部分&#xff1a;决定一个像素的可见性&#xff0c;决定这个像素上的光照计算 我们是如何看到这个世界的 通常来讲&#xff0c;我们要模拟真实的光照环境来生成一张图像&#xff0c;需要考虑3种物理现象。 首先&a…

JOSEF约瑟 可调漏电继电器RT-LB230KS+Q-FL-100 导轨安装 配套零序互感器

一、产品用途及特点 RT-LB230KS漏电继电器&#xff08;以下简称继电器&#xff09;适用于交流电压为660V.至1140V电压系统中,频率为50Hz,电流15~4000A线路中做有无中性点漏电保护. 该继电器可与带分励脱扣器或失压脱扣器的断路器、交流接触器、磁力启动器等组成漏电保护装置&…

机器学习: 初探 定义与应用场景

机器学习 第一课 初探 定义与应用场景 机器学习 第一课 初探 定义与应用场景机器学习的历史机器学习为什么重要?机器学习的定义机器学习在日常生活中的应用推荐系统语音识别图像识别 商业领域的机器学习金融风险评估股票市场预测客户关系管理 机器学习在医疗领域的应用疾病预测…

【Linux】:常见指令理解(3)

17.grep指令 grep参考文档 语法&#xff1a; grep [选项] 搜寻字符串 文件 功能&#xff1a; 在文件中搜索字符串&#xff0c;将找到的行打印出来 常用选项&#xff1a; -i &#xff1a;忽略大小写的不同&#xff0c;所以大小写视为相同 -n &#xff1a;顺便输出行号 -v &…

MBBF展示的奇迹绿洲:5G的过去、此刻与未来

如果你来迪拜&#xff0c;一定不会错过全世界面积最大的人工岛项目&#xff0c;这是被称为世界第八大奇迹的棕榈岛。多年以来&#xff0c;这座岛从一片砂石、一棵棕榈树开始&#xff0c;逐步建成了整个波斯湾地区的地标&#xff0c;吸引着全世界游人的脚步。 纵观整个移动通信发…

K8S:Rancher管理 Kubernetes 集群

文章目录 一.Rancher 简介1.Rancher概念2.Rancher 和 k8s 的区别 二.Rancher 安装及配置1.安装 rancher2.登录 Rancher 平台3.Rancher 管理已存在的 k8s 集群4.Rancher 部署监控系统5.使用 Rancher 仪表盘管理 k8s 集群 三.拓展1.Rancher和kubesphere相比较2.K3S和K8S相比较 一…

WorkPlus AI智能助理,基于GPT为企业提供专属的私有化部署解决方案

在当今数字时代&#xff0c;优质的客户服务是企业取得成功的重要因素之一。随着人工智能技术的不断发展&#xff0c;私有化部署AI智能客服成为企业提高客户体验、提升服务效率的新途径。WorkPlus作为领先的品牌&#xff0c;专注于提供可信赖的私有化部署解决方案&#xff0c;助…

unity2022版本 实现加减进度条

简介 在现代游戏开发中&#xff0c;用户界面 (UI) 扮演着至关重要的角色&#xff0c;它不仅为玩家提供信息&#xff0c;还增强了游戏的可玩性。加减进度条是一种常见的UI元素&#xff0c;它可以用于显示游戏中的进度、倒计时、资源管理和其他关键信息。在这篇博客中&#xff0…

JMeter定时器

一. 同步定时器&#xff08;Synchronizing Timer) &#xff08;在Loadrunner中叫做集合点&#xff09; 思考&#xff1a; 如何模拟多个用户同时抢一个红包&#xff1f;如何测试电商网站中抢购活动、秒杀活动&#xff1f; 1.1 介绍 Sync Timer的目的是阻塞线程&#xff0c;直…

C. JoyboardCodeforces Round 902

C. Joyboard 样例1列表找规律&#xff1a; #include<iostream> #define int long long using namespace std; signed main() {int T;cin>>T;while(T--){int n,m,k;cin>>n>>m>>k;if(k1){cout<<1<<endl;}else if(k2){cout<<m…

解析找不到msvcp140.dll的5个解决方法,快速修复dll丢失问题

​在使用计算机过程中&#xff0c;我们也会遇到各种各样的问题。其中&#xff0c;找不到msvcp140.dll修复方法是一个非常普遍的问题。msvcp140.dll是一个动态链接库文件&#xff0c;它是Microsoft Visual C 2015 Redistributable的一部分。这个文件包含了许多用于运行C程序的函…

传输层 | UDP协议、TCP协议

之前讲过的http与https都是应用层协议&#xff0c;当应用层协议将报文构建好之后就要将报文往下层传输层进行传递&#xff0c;而传输层就是负责将数据能够从发送端传到接收端。 再谈端口号 端口号(port)标识了一个主机上进行通信的不同的应用程序&#xff0c;在TCP/IP协议中&…

进阶JAVA篇- LocalDate 类与 LocalTime 类、LocalDateTime 类的常用API(六)

目录 API 1.0 LocalDate 类与 LocalTime 类、LocalDateTime 类的API说明 1.1 如何创建LocalDate 类与 LocalTime 类、LocalDateTime 类的对象 1.2 LocalDate 类与 LocalTime 类、LocalDateTime 类中的以 get 开头实例方法 1.3 LocalDateTime 类中的 toLocalDat…