在用到ABB机器人时,姿态使用的是四元素的方式,如下

然后,选择几个需求实现一下,这基本上就把互转实现差不多了
1.四元素转旋转矩阵
q=w+xi+yj+zk 中 w x y z 也对应有些文档里写的q0 q1 q2 q3

2.旋转矩阵转四元素


3.四元素转俯仰角(pitch,θ\thetaθ)、滚转角(roll,ϕ\phiϕ)、偏航角(yaw,ψ\psiψ)
计算方法如下:

和这个也一样,所以公式应该没啥问题,直接套就行了

4.欧拉角转四元素
直接套下面公式即可:

测试代码,欢迎取用,留下点赞+收藏
struct Quaternion {
double w, x, y, z;
};
void matrixToQuaternion(double R[3][3]) {
Quaternion q;
double trace = R[0][0] + R[1][1] + R[2][2]; // 矩阵的迹
if (trace > 0.0) {
double s = 0.5 / sqrt(trace + 1.0);
q.w = 0.25 / s;
q.x = (R[2][1] - R[1][2]) * s;
q.y = (R[0][2] - R[2][0]) * s;
q.z = (R[1][0] - R[0][1]) * s;
} else {
if (R[0][0] > R[1][1] && R[0][0] > R[2][2]) {
double s = 2.0 * sqrt(1.0 + R[0][0] - R[1][1] - R[2][2]);
q.w = (R[2][1] - R[1][2]) / s;
q.x = 0.25 * s;
q.y = (R[0][1] + R[1][0]) / s;
q.z = (R[0][2] + R[2][0]) / s;
} else if (R[1][1] > R[2][2]) {
double s = 2.0 * sqrt(1.0 + R[1][1] - R[0][0] - R[2][2]);
q.w = (R[0][2] - R[2][0]) / s;
q.x = (R[0][1] + R[1][0]) / s;
q.y = 0.25 * s;
q.z = (R[1][2] + R[2][1]) / s;
} else {
double s = 2.0 * sqrt(1.0 + R[2][2] - R[0][0] - R[1][1]);
q.w = (R[1][0] - R[0][1]) / s;
q.x = (R[0][2] + R[2][0]) / s;
q.y = (R[1][2] + R[2][1]) / s;
q.z = 0.25 * s;
}
}
qDebug()<<"四元素:"<<q.w<<" "<<q.x<<" "<<q.y<<" "<<q.z;
}
//先给一个点位姿XYZUVW
st_PosAttitude p1;
p1.dX = 1311.45;
p1.dY = -50.21;
p1.dZ = 979.57;
p1.dA = 0.24258;
p1.dB = 0.04898;
p1.dC = 0.96886;
p1.dD = 0.00833;
//对应的四元素值
//q=w+xi+yj+zk
double w = p1.dA;
double x = p1.dB;
double y = p1.dC;
double z = p1.dD;
//构建旋转矩阵
double a00 = 1.0 - 2.0 * y * y - 2.0 * z * z;
double a01 = 2.0 * x * y - 2.0 * w * z;
double a02 = 2.0 * x * z + 2.0 * w * y;
double a10 = 2.0 * x * y + 2.0 * w * z;
double a11 = 1.0 - 2.0 * x * x -2.0 * z * z;
double a12 = 2.0 * y * z - 2.0 * w * x;
double a20 = 2.0 * x * z - 2.0 * w * y;
double a21 = 2.0 * y * z + 2.0 * w * x;
double a22 = 1.0 - 2.0 * x * x - 2.0 * y * y;
Eigen::Matrix4d xyzdelt;
xyzdelt<<a00,a01,a02,0,
a10,a11,a12,0,
a20,a21,a22,0,
0,0,0,1;
//旋转矩阵打印出来
qDebug()<<xyzdelt(0,0)<<" "<<xyzdelt(0,1)<<" "<<xyzdelt(0,2)<<" "<<xyzdelt(0,3);
qDebug()<<xyzdelt(1,0)<<" "<<xyzdelt(1,1)<<" "<<xyzdelt(1,2)<<" "<<xyzdelt(1,3);
qDebug()<<xyzdelt(2,0)<<" "<<xyzdelt(2,1)<<" "<<xyzdelt(2,2)<<" "<<xyzdelt(2,3);
qDebug()<<xyzdelt(3,0)<<" "<<xyzdelt(3,1)<<" "<<xyzdelt(3,2)<<" "<<xyzdelt(3,3);
//直接使用Eigen库中的四元素转旋转矩阵,做对比
Eigen::Quaterniond q_odom_curr_tmp;
q_odom_curr_tmp.x() = x;
q_odom_curr_tmp.y() = y;
q_odom_curr_tmp.z() = z;
q_odom_curr_tmp.w() =w;
Eigen::Matrix3d R_odom_curr_tmp;
R_odom_curr_tmp= q_odom_curr_tmp.normalized().toRotationMatrix();
qDebug()<<R_odom_curr_tmp(0,0)<<" "<<R_odom_curr_tmp(0,1)<<" "<<R_odom_curr_tmp(0,2);
qDebug()<<R_odom_curr_tmp(1,0)<<" "<<R_odom_curr_tmp(1,1)<<" "<<R_odom_curr_tmp(1,2);
qDebug()<<R_odom_curr_tmp(2,0)<<" "<<R_odom_curr_tmp(2,1)<<" "<<R_odom_curr_tmp(2,2);
//旋转矩阵转四元素,这个可能会遇到w1为0的情况,但是大部分情况下不用管,和下面那种方法结果一致,如果遇到为0,换下面那种方法试一下
double w1 = 1.0/2.0*(sqrt(1.0 + a00 + a11 + a22));
double x1 = (a21 - a12) / (4.0 * w1);
double y1 = (a02 - a20) / (4.0 * w1);
double z1 = (a10 - a01) / (4.0 * w1);
qDebug()<<"四元素:"<<w1<<" "<<x1<<" "<<y1<<" "<<z1;
//旋转矩阵转四元素,直接用的是以下链接的函数,主要做对比使用
//https://blog.csdn.net/qq_44339029/article/details/142431407?ops_request_misc=%257B%2522request%255Fid%2522%253A%252282244049b96523ad4d78ccf477e67b26%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=82244049b96523ad4d78ccf477e67b26&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~baidu_landing_v2~default-4-142431407-null-null.nonecase&utm_term=%E6%97%8B%E8%BD%AC%E7%9F%A9%E9%98%B5%E8%BD%AC%E5%9B%9B%E5%85%83%E7%B4%A0&spm=1018.2226.3001.4450
double R[3][3];
R[0][0] = xyzdelt(0,0);R[0][1] = xyzdelt(0,1);R[0][2] = xyzdelt(0,2);
R[1][0] = xyzdelt(1,0);R[1][1] = xyzdelt(1,1);R[1][2] = xyzdelt(1,2);
R[2][0] = xyzdelt(2,0);R[2][1] = xyzdelt(2,1);R[2][2] = xyzdelt(2,2);
matrixToQuaternion(R);
//四元素转UVW 即 θ ϕ ψ
//俯仰角(pitch):θ\thetaθ x轴
//滚转角(roll):ϕ\phiϕ y轴
//偏航角(yaw):ψ\psiψ z轴
double pitch = asin(2.0 * (w1 * y1 - x1 * z1));
double roll = atan2((2.0 * (w1 * x1 + y1 * z1)),(1.0 - 2.0*(x * x + y * y)));
double yaw = atan2((2.0 * (w1 * z1 + x1 * y1)),(1.0 - 2.0*(z * z + y * y)));
qDebug()<<"rxryrz:"<<pitch<<" "<<roll<<" "<<yaw;
qDebug()<<"rxryrz:"<<pitch*180.0/M_PI<<" "<<roll*180.0/M_PI<<" "<<yaw*180.0/M_PI;
//欧拉角到四元素
double w2 = cos(roll/2.0) * cos(pitch/2.0) * cos(yaw/2.0) + sin(roll/2.0) * sin(pitch/2.0) * sin(yaw/2.0);
double x2 = sin(roll/2.0) * cos(pitch/2.0) * cos(yaw/2.0) - cos(roll/2.0) * sin(pitch/2.0) * sin(yaw/2.0);
double y2 = cos(roll/2.0) * sin(pitch/2.0) * cos(yaw/2.0) + sin(roll/2.0) * cos(pitch/2.0) * sin(yaw/2.0);
double z2 = cos(roll/2.0) * cos(pitch/2.0) * sin(yaw/2.0) - sin(roll/2.0) * sin(pitch/2.0) * cos(yaw/2.0);
qDebug()<<"四元素:"<<w2<<" "<<x2<<" "<<y2<<" "<<z2;
打印出来的结果:
//自己组的旋转矩阵 xyzdelt输出
-0.877518 0.0908681 0.470868 0
0.0989509 0.995063 -0.00762193 0
-0.469236 0.0399043 -0.882177 0
0 0 0 1
//调用Eigen库的输出结果,发现结果是一致的
-0.877512 0.0908679 0.470867
0.0989506 0.995063 -0.0076219
-0.469235 0.0399042 -0.882171
//调用其他博文输出的四元素结果
四元素: 0.24258 0.04898 0.96886 0.00833
//通过公式计算的结果,基本一致
四元素: 0.242573 0.0489813 0.968886 0.00833023
//通过四元素计算的欧拉角
rxryrz: 0.488425 3.09639 3.0293
rxryrz: 27.9847 177.41 173.566
//通过欧拉角计算的四元素,和ABB机器人示教器端显示的一模一样,说明准确
四元素: 0.24258 0.0489824 0.968858 0.00832969
有些公式借鉴该博客:https://blog.csdn.net/weixin_45784125/article/details/144908718?ops_request_misc=%257B%2522request%255Fid%2522%253A%252268b949e6f6310d7a6aa2379907f888f2%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=68b949e6f6310d7a6aa2379907f888f2&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-16-144908718-null-null.142v102pc_search_result_base7&utm_term=%E6%97%8B%E8%BD%AC%E7%9F%A9%E9%98%B5&spm=1018.2226.3001.4187

8765

被折叠的 条评论
为什么被折叠?



