坐标变换学习笔记—代码篇Eigen

这篇博客探讨了在ROS和Eigen中使用旋转量时需要注意的问题,如四元数的顺序差异。作者建议在工程中优先使用ROS的旋转量,并警告不要混合使用ROS和Eigen的转换方法。博客详细介绍了旋转向量、四元数、欧拉角和旋转矩阵之间的转换函数,并提供了测试代码示例。

先说结论,关于ROS和Eigen中使用旋转量,个人认为有一下问题需要注意下:

  • ROS中使用的四元数顺序是x,y,z,w; 而Eigen中使用的四元数顺序是w,x,y,z; 这里需要注意下。

  • 在工程中,千万不要用Eigen中的方法转换由ROS中的方法得到的旋转量,也不要用ROS中的旋转方法转换Eigen得到的旋转量。

  • 在工程中如果用到ROS,则建议优先使用ROS中的旋转量来表达旋转,因为它们事先确定了旋转顺序按照ZYX来,而不像Eigen中,可通过参数选择旋转顺序,得到不同的顺序的旋转量,容易给自己挖坑。

  • 在工程中,尽量少用欧拉角。

旋转向量

旋转向量与其它旋转量间的转换

Eigen/src/Geometry/AngleAxis.h

四元数 → \to 旋转向量:

Eigen中,通过重载=操作符,实现旋转矩阵,四元数对转旋转向量的直接赋值,但是从下面的函数实现看,它的旋转角 θ \theta θ是通过 a t a n 2 atan2 atan2的方式求出来的,与理论篇中的式 ( 3.1 ) (3.1) (3.1)稍微有点差别。
Eigen/src/Geometry/AngleAxis.h,operator=(const QuaternionBase

/** Set \c *this from a \b unit quaternion.
  *
  * The resulting axis is normalized, and the computed angle is in the [0,pi] range.
  * 
  * This function implicitly normalizes the quaternion \a q.
  */
template<typename Scalar>
template<typename QuatDerived>
EIGEN_DEVICE_FUNC AngleAxis<Scalar>& AngleAxis<Scalar>::operator=(const QuaternionBase<QuatDerived>& q)
{
   
   
  EIGEN_USING_STD_MATH(atan2)
  EIGEN_USING_STD_MATH(abs)
  Scalar n = q.vec().norm();
  if(n<NumTraits<Scalar>::epsilon())
    n = q.vec().stableNorm();

  if (n != Scalar(0))
  {
   
   
    m_angle = Scalar(2)*atan2(n, abs(q.w()));
    if(q.w() < Scalar(0))
      n = -n;
    m_axis  = q.vec() / n;
  }
  else
  {
   
   
    m_angle = Scalar(0);
    m_axis << Scalar(1), Scalar(0), Scalar(0);
  }
  return *this;
}
旋转向量 → \to 旋转矩阵:

n = [ n x   n y   n z ] T \mathbf{n} =[n_x~n_y~n_z]^T n=[nx ny nz]T代入展开可得:
R = c o s ( θ ) I + ( 1 − c o s ( θ ) ) n n T + s i n ( θ ) n ∧ = c o s ( θ ) I + ( 1 − c o s ( θ ) ) [ n x 2 n x n y n x n z n y n x n y 2 n y n z n z n x n z n y n z 2 ] + s i n ( θ ) [ 0 − n z n y n z 0 − n x − n y n x 0 ] = c o s ( θ ) I + ( 1 − c o s ( θ ) ) [ n x 2 0 0 0 n y 2 0 0 0 n z 2 ] + [ 0 ( 1 − c o s ( θ ) ) n x n y − s i n ( θ ) n z ( 1 − c o s ( θ ) ) n x n z + s i n ( θ ) n y ( 1 − c o s ( θ ) ) n y n x + s i n ( θ ) n z 0 ( 1 − c o s ( θ ) ) − s i n ( θ ) n x ( 1 − c o s ( θ ) ) n z n x − s i n ( θ ) n y ( 1 − c o s ( θ ) ) n z n y + s i n ( θ ) n x 0 ] (1.1.1) \begin{aligned}\mathbf{R} \tag{1.1.1} =& cos(\theta) \mathbf{I} + (1-cos(\theta))\mathbf{n}\mathbf{n}^T + sin(\theta) \mathbf{n}^{\wedge} \\ =& cos(\theta) \mathbf{I} + (1-cos(\theta))\left[\begin{matrix}n_x^2 & n_xn_y & n_xn_z \\ n_yn_x & n_y^2 & n_yn_z \\ n_zn_x & n_zn_y & n_z^2 \end{matrix}\right] + sin(\theta) \left[\begin{matrix}0 & -n_z & n_y \\ n_z & 0 & -n_x \\ -n_y & n_x & 0 \end{matrix}\right] \\ =& cos(\theta) \mathbf{I} + (1-cos(\theta))\left[\begin{matrix}n_x^2 & 0& 0 \\ 0 & n_y^2 & 0 \\ 0 & 0 & n_z^2 \end{matrix}\right] + \left[\begin{matrix}0 & (1-cos(\theta))n_xn_y - sin(\theta)n_z & (1-cos(\theta))n_xn_z + sin(\theta)n_y \\ (1-cos(\theta))n_yn_x+sin(\theta)n_z & 0 & (1-cos(\theta))-sin(\theta)n_x \\ (1-cos(\theta))n_zn_x-sin(\theta)n_y & (1-cos(\theta))n_zn_y+sin(\theta)n_x & 0 \end{matrix}\right] \end{aligned} R===cos(θ)I+(1cos(θ))nnT+sin(θ)ncos(θ)I+(1cos(θ))nx2nynxnznxnxnyny2nznynxnznynznz2+sin(θ)0nznynz0nxnynx0cos(θ)I+(1cos(θ))n

### 使用Eigen库进行坐标变换及创建变换矩阵 #### 创建变换矩阵 在Eigen库中,可以通过`Affine3f`或`Isometry3f`类来表示三维空间中的刚体变换。这些类能够处理旋转和平移操作。 对于给定的角度θ=π/2(即90度),可以构建一个绕Z轴逆时针方向的旋转变换矩阵R: \[ R=\begin{bmatrix} \cos(\theta)&-\sin(\theta)\\ \sin(\theta)&\cos(\theta) \end{bmatrix}= \begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix}\] 接着定义平移向量t=(tx,ty)=(2,2),则完整的齐次变换矩阵T可由下述方式获得[^3]: ```cpp #include <iostream> #include <Eigen/Dense> using namespace Eigen; int main() { Matrix3d rotation_matrix; rotation_matrix << 0,-1, 1, 0; // Rotation by pi/2 radians around Z axis Vector2d translation_vector(2, 2); Affine2d transform = Translation2d(translation_vector)*Rotation2D<double>(M_PI / 2); std::cout << "Transform matrix:\n" << transform.matrix() << "\n"; } ``` 此代码片段展示了如何利用Eigen库构造一个二维平面内的仿射变换对象,并打印出对应的变换矩阵形式。 #### 应用变换到点上 当有一个位于frame_1下的点P其坐标为(1,0),要将其转换至全局坐标系(world frame)下,则需执行如下运算: \[ P_{world}=RP_{local}+t \] 其中\( P_{local}=[1,0]^T\) 是待变换点的位置矢量,在上述例子中已经给出具体的数值;而 \( t=[2,2]^T \) 则代表了frame_1相对世界坐标的位移分量。因此, \[ P_{world} = \begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix} \times \begin{bmatrix} 1 \\ 0 \end{bmatrix}+ \begin{bmatrix} 2 \\ 2 \end{bmatrix}= \begin{bmatrix} 2 \\ 3 \end{bmatrix}\]. 这段解释说明了怎样通过乘法和加法完成从局部坐标系到全局坐标系之间的位置映射过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值