通过Eigen库实现机械手位姿转换为Isometry3f类型

博主初步接触相关内容,先简单实现效果,待熟练掌握后再优化。因百度搜索时多数答主描述复杂,故记录如何直接使用,实现结果与Halcon中pose_to_hom_mat3d算子输出相同。

初步接触这方面,根据自己的理解先简单实现效果。熟练掌握和使用后再进行优化。

因为百度搜索时,大部分答主描述的比较复杂,这里记录一下如何直接使用

//其中pose1是由机械手坐标X、Y、Z和Rx、Ry、Rz组成。
int Pose2Isometry3f(const std::vector<float>& pose1, Eigen::Isometry3f& matrix)
{
	float roll	= pose1[3] * PI / 180;
	float pitch = pose1[4] * PI / 180;
	float yaw	= pose1[5] * PI / 180;

	Eigen::AngleAxisf rotX(roll, Eigen::Vector3f::UnitX());	  // 轴角表达公式
	Eigen::AngleAxisf rotY(pitch, Eigen::Vector3f::UnitY());  // 轴角表达公式
	Eigen::AngleAxisf rotZ(yaw, Eigen::Vector3f::UnitZ());	  // 轴角表达公式

	Eigen::Translation3f trans(pose1[0], pose1[1], pose1[2]);//位移量,录入当前位置
	matrix = trans * rotZ * rotY * rotX;

	std::cout << "Hand Matrix = " << matrix.matrix() << std::endl;//机器人位姿转换为矩阵的形式

	return 0;
}

int main()
{
    Eigen::Isometry3f PoseMat;
	std::vector<float> pose1 = {0.76227, 0.59453, 0.28947, -178.9, 0.87, 92.96};//X、Y、Z、Rx、Ry、Rz
	Pose2Isometry3f(pose1, PoseMat);
}

结果如下,跟halcon中的算子pose_to_hom_mat3d的输出结果相同

 

<think> 我们通常所说的6自由度数据在机器人学和三维空间中指的是平移向量(3自由度)和旋转向量(3自由度,即旋转轴的方向向量乘以旋转角,也称为角轴表示)。Eigen::Affine3f是一个4x4的仿射变换矩阵,它包含旋转和平移信息。 要将Eigen::Affine3f转换为6自由度数据,可以分解为: 1. 提取平移向量(前三个元素,于矩阵的最后一列的前三行)。 2. 提取旋转矩阵(左上角3x3部分),然后将旋转矩阵转换为旋转向量(角轴表示)。 注意:旋转向量是一个3维向量,其方向表示旋转轴,模长表示旋转角度(弧度)。 在Eigen中,我们可以这样做: - 平移部分:直接使用`affine.translation()`得到平移向量。 - 旋转部分:使用`Eigen::AngleAxisf`将旋转矩阵转换为旋转向量。 因此,6自由度数据可以用一个6维向量表示:前3个分量是平移向量,后3个分量是旋转向量。 具体步骤: 1. 从Affine3f中提取平移部分(Vector3f)。 2. 从Affine3f中提取旋转部分(Matrix3f),然后将其转换为AngleAxisf(旋转向量表示)。 3. 将旋转向量的三个分量(即角轴表示的向量)和平移向量组合成一个6维向量。 注意:当旋转角度为0时,旋转向量为零向量。当旋转角度接近0时,旋转向量也会很小,但这是合理的。 代码示例: ```cpp #include <Eigen/Dense> #include <Eigen/Geometry> #include <iostream> // 将Affine3f转换为6自由度的Vector6f(前3个是平移,后3个是旋转向量) Eigen::VectorXf affine3fTo6DoF(const Eigen::Affine3f& affine) { // 创建一个6维向量 Eigen::VectorXf dof6(6); // 提取平移部分(3维向量) Eigen::Vector3f translation = affine.translation(); // 提取旋转部分并转换为旋转向量(角轴表示) Eigen::AngleAxisf rotation_vector(affine.rotation()); // 将平移向量和旋转向量组合 dof6.head<3>() = translation; dof6.tail<3>() = rotation_vector.axis() * rotation_vector.angle(); // 注意:axis()返回的是单向量,乘以角度后就是旋转向量 return dof6; } ``` 但是注意:旋转向量在Eigen中,`Eigen::AngleAxisf`的`axis()`方法返回的是单向量,而`angle()`返回的是旋转角度(标量)。因此,旋转向量就是`axis() * angle()`。 然而,需要注意的是,当旋转角度为0时,旋转轴是未定义的(任意轴),但Eigen会返回一个默认轴(如(1,0,0))并且角度为0,所以乘积为零向量,这是合理的。 另外,我们也可以直接使用`Eigen::AngleAxisf`的向量表示,因为`Eigen::AngleAxisf`内部存储的就是一个旋转向量(等价于`angle() * axis()`)。所以我们可以直接使用其构造函数将旋转矩阵转换为旋转向量,然后通过`.vec()`方法获取旋转向量(实际上,`Eigen::AngleAxisf`对象可以直接赋值给一个Vector3f,其值就是旋转向量)。 因此,更简洁的写法是: ```cpp Eigen::VectorXf affine3fTo6DoF(const Eigen::Affine3f& affine) { Eigen::VectorXf dof6(6); dof6.head<3>() = affine.translation(); // 将旋转部分转换为旋转向量(角轴表示),然后直接赋值给后3个元素 Eigen::AngleAxisf rotation_vector; rotation_vector = affine.rotation(); // 从旋转矩阵赋值 dof6.tail<3>() = rotation_vector.vec(); // 或者直接使用:dof6.tail<3>() = rotation_vector.axis() * rotation_vector.angle(); // 注意:rotation_vector.vec()返回的向量就是旋转向量(即axis * angle) // 实际上,rotation_vector.vec()和rotation_vector.axis() * rotation_vector.angle()是等价的。 return dof6; } ``` 但是,查看Eigen文档,`Eigen::AngleAxisf`类有一个成员函数`vec()`,它返回的向量就是旋转向量(即旋转轴乘以旋转角度)。因此,我们可以直接使用`vec()`。 然而,需要注意的是,`Eigen::AngleAxisf`的`vec()`方法返回的向量与`axis() * angle()`完全相同。 因此,我们也可以这样写: ```cpp Eigen::VectorXf affine3fTo6DoF(const Eigen::Affine3f& affine) { Eigen::VectorXf dof6(6); dof6.head<3>() = affine.translation(); Eigen::AngleAxisf rotation_vector(affine.rotation()); dof6.tail<3>() = rotation_vector.vec(); return dof6; } ``` 或者更简洁地(避免临时变量): ```cpp Eigen::VectorXf affine3fTo6DoF(const Eigen::Affine3f& affine) { Eigen::VectorXf dof6(6); dof6.head<3>() = affine.translation(); dof6.tail<3>() = Eigen::AngleAxisf(affine.rotation()).vec(); return dof6; } ``` 注意:`Eigen::AngleAxisf`的构造函数接受一个3x3的旋转矩阵,并将其转换为旋转向量(角轴)表示。 但是,如果旋转矩阵不是标准的(例如有缩放),那么转换可能不准确。在我们的场景中,`Eigen::Affine3f`的旋转部分应该是标准的旋转矩阵(正交矩阵,行列式为1)。如果仿射变换中包含缩放或剪切,则这种方法不适用。但在姿表示中,通常只包含旋转和平移。 另外,这种转换会丢失缩放信息(如果有的话),但6自由度假设只包含旋转和平移。 使用示例: ```cpp int main() { // 创建一个仿射变换,包含旋转和平移 Eigen::Affine3f affine = Eigen::Affine3f::Identity(); // 设置平移 affine.translation() = Eigen::Vector3f(1.0, 2.0, 3.0); // 设置旋转:绕Z轴旋转90度 affine.rotate(Eigen::AngleAxisf(M_PI/2, Eigen::Vector3f::UnitZ())); // 转换为6自由度 Eigen::VectorXf dof6 = affine3fTo6DoF(affine); std::cout << "6自由度向量: " << dof6.transpose() << std::endl; return 0; } ``` 输出应为: 平移部分:1.0, 2.0, 3.0 旋转向量:由于绕Z轴旋转90度(π/2),旋转向量应为(0,0,π/2) -> (0,0,1.57)(近似) 注意:旋转向量的模长等于旋转角度(弧度),方向为旋转轴。 相关问题: 1. 如何将6自由度数据(平移向量+旋转向量)转换Eigen::Affine3f? 2. 旋转向量和四元数之间如何转换3. 在机器人姿表示中,除了6自由度表示法,还有哪些常见的表示方法? 4. 如何处理旋转向量中的奇异性(万向节锁)问题? </think> ### Eigen::Affine3f 转换为 6 自由度数据的实现方法 在机器人学和三维变换中,6 自由度(6-DoF)数据通常表示为平移向量 $[t_x, t_y, t_z]$ 和旋转向量 $[\theta_x, \theta_y, \theta_z]$(或欧拉角)。以下是两种将 `Eigen::Affine3f` 转换为 6 自由度的实现方法: --- ### 方法一:直接提取平移和旋转向量 ```cpp #include <Eigen/Dense> #include <Eigen/Geometry> Eigen::Matrix<float, 6, 1> affineTo6DoF(const Eigen::Affine3f& affine) { Eigen::Matrix<float, 6, 1> dof; // 提取平移分量 (3自由度) dof.head<3>() = affine.translation(); // 提取旋转分量 (3自由度) Eigen::AngleAxisf rotation(affine.rotation()); dof.tail<3>() = rotation.angle() * rotation.axis(); return dof; } ``` #### 关键步骤解析: 1. **平移分量提取**: `affine.translation()` 直接获取平移向量 $[t_x, t_y, t_z]$ 2. **旋转分量提取**: - 通过 `Eigen::AngleAxisf` 将旋转矩阵转换为旋转向量 - 旋转向量的方向表示旋转轴 $\mathbf{n} = [n_x, n_y, n_z]$ - 旋转向量的模长表示旋转角度 $\theta$ - 最终旋转分量:$[\theta n_x, \theta n_y, \theta n_z]$ #### 使用示例: ```cpp Eigen::Affine3f pose = Eigen::Affine3f::Identity(); pose.translate(Eigen::Vector3f(1, 2, 3)); pose.rotate(Eigen::AngleAxisf(M_PI/2, Eigen::Vector3f::UnitZ())); Eigen::Matrix<float, 6, 1> dof = affineTo6DoF(pose); std::cout << "6-DoF: " << dof.transpose() << std::endl; // 输出示例: [1, 2, 3, 0, 0, 1.57] ``` --- ### 方法二:使用欧拉角(需注意万向锁) ```cpp Eigen::Matrix<float, 6, 1> affineToEuler(const Eigen::Affine3f& affine) { Eigen::Matrix<float, 6, 1> dof; // 平移分量 dof.head<3>() = affine.translation(); // 旋转矩阵转欧拉角 (ZYX顺序) Eigen::Vector3f euler = affine.rotation().eulerAngles(2, 1, 0); dof.tail<3>() = euler; // [θ_z, θ_y, θ_x] return dof; } ``` #### 注意事项: - **万向锁问题**:当俯仰角 $\theta_y = \pm \pi/2$ 时会出现奇点[^1] - **旋转顺序**:`eulerAngles(2,1,0)` 表示 Z-Y-X 顺序(航偏-俯仰-横滚) - **适用场景**:适用于俯仰角不接近 $\pm 90^\circ$ 的情况 --- ### 方法对比 | **方法** | **优点** | **缺点** | **适用场景** | |----------------|------------------------------|------------------------------|-------------------------| | 旋转向量法 | 无奇点,数值稳定 | 旋转向量不直观 | SLAM、运动规划[^3] | | 欧拉角法 | 直观易理解 | 存在万向锁问题 | 机器人示教、可视化[^1] | > **工程建议**:优先使用旋转向量法避免奇异性问题,仅在需要人类可读输出时使用欧拉角。 --- ### 相关问题 1. 如何将 6 自由度数据转换回 `Eigen::Affine3f`? 2. 旋转向量和四元数在表示旋转时有何区别?如何选择?[^1][^2] 3. 在存在万向锁的情况下如何处理欧拉角转换? 4. `Eigen::Isometry3d` 和 `Eigen::Affine3f` 在表示姿时有何区别?[^1][^3] [^1]: Eigen 中对各种形式的表达方式总结如下。请注意每种类型都有单精度和双精度两种 数据类型[^1] [^3]: T.rotate(rotation_vector); // 按照rotation_vector进行旋转 T.pretranslate(Vector3d(1, 3, 4))[^3
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值