squad是Shoemake在1987年提出的一种比贝塞尔曲线更高效的近似算法,之前想运用它进行机械臂末端的多姿态平滑插值,但是上网搜关于squad姿态插补的算法,没找着,所以自己写了个C语言版本的,还没测试,仅供参考吧。

四元数的相关基础知识还有slerp、squad等插值方法这里就不赘述了,相关的知识推荐去看一下Krasjet*的《四元数与三维旋转》,想更深入可以去看《Quaternions, Interpolation and Animation》。

如果我们有一个四元数序列 , , . . . , ,那么插补公式有:

  式中,都是单位四元数,t的范围是0~1;第二条式子是求控制点的。细心的同学可能会发现,如果要求,那就要有,这时有两种解决方法,第一种是令==,第二种是令==,两种方法都可以,对整段插补曲线的影响较小。需要注意的是:假设你有三个姿态,那么分为~~两段squad插补。与slerp插补不同的是,使用squad能保持这两段可以平滑过渡,而slerp会发生角速度突变。

  然后是公式中四元数的对数和指数运算,这里引用《Quaternions, Interpolation and Animation》中的,红色框中可能是你需要注意的。

代码:

math_robot.c

/**************************** @file       math_robot.c* @brief      四元数相关运算* @author     vanvan* @date       2020-4-20* @version    ****************************/
#include "math_robot.h"//四元数乘法
double Quat_Mupltipy(QUAT *Q1, QUAT *Q2)
{return (Q1->s*Q2->s + Q1->v[0]*Q2->v[0] + Q1->v[1]*Q2->v[1] + Q1->v[2]*Q2->v[2]);
}//四元数标量乘法
QUAT Quat_Smupltipy(QUAT *Q, double scalar)
{QUAT q;q.s = Q->s*scalar;q.v[0] = Q->v[0]*scalar;q.v[1] = Q->v[1]*scalar;q.v[2] = Q->v[2]*scalar;return q;
}//四元数共轭
QUAT Quat_Conj(QUAT *Q)
{QUAT q;q.s = Q->s;q.v[0] = -Q->v[0];q.v[1] = -Q->v[1];q.v[2] = -Q->v[2];return q;
}//两四元数点积
double Quat_Dot(QUAT *q1, QUAT *q2)
{return (sqrt(q1->s*q2->s+q1->v[0]*q2->v[0]+q1->v[1]*q2->v[1]+q1->v[2]*q2->v[2]));
}//四元数取反
QUAT Quat_Reverse(QUAT *Q)
{QUAT q;q.s = -Q->s;q.v[0] = -Q->v[0];q.v[1] = -Q->v[1];q.v[2] = -Q->v[2];return q;
}//四元数对数运算
QUAT Quat_Log(QUAT *q)
{//四元数求对数// log(q)=[0, θv]double sina = sqrt(q->v[0]*q->v[0]+q->v[1]*q->v[1]+q->v[2]*q->v[2]);double cosa = q->s;double theta = atan2(sina,cosa);QUAT Q;//当sina很小时,不能作分子,用theta代替sin(theta)if(cosa > 0.9995){Q = *q;}else{ Q = Quat_Smupltipy(q, theta/sina);}Q.s=0;return Q;
}//四元数指数运算
QUAT Quat_Exp(QUAT *q)
{//exp(q)=[cosθ,sinθv]//求四元数的指数double theta = sqrt(q->v[0]*q->v[0]+q->v[1]*q->v[1]+q->v[2]*q->v[2]);double cosa = COS(theta);QUAT Q;//当sina很小时,不能作分子,用theta代替sin(theta)if(cosa > 0.9995){Q = *q;}else{Q = Quat_Smupltipy(q, sin(theta)/theta);}Q.s = cosa;return Q;
}//四元数相乘
QUAT Quat_Product(QUAT *q1, QUAT *q2)
{QUAT Q;Q.s    = q1->s*q2->s    - q1->v[0]*q2->v[0] - q1->v[1]*q2->v[1] - q1->v[2]*q2->v[2] ;Q.v[0] = q1->v[0]*q2->s + q1->s*q2->v[0]    - q1->v[2]*q2->v[1] + q1->v[1]*q2->v[2] ;Q.v[1] = q1->v[1]*q2->s + q1->v[2]*q2->v[0] + q1->s*q2->v[1]    - q1->v[0]*q2->v[2] ;Q.v[2] = q1->v[2]*q2->s - q1->v[1]*q2->v[0] + q1->v[0]*q2->v[1] + q1->s*q2->v[2] ;return Q;
}//四元数相加
QUAT Quat_Add(QUAT *q1, QUAT *q2)
{QUAT Q;Q.s    = q1->s+q2->s;Q.v[0] = q1->v[0]+q2->v[0];Q.v[1] = q1->v[1]+q2->v[1];Q.v[2] = q1->v[2]+q2->v[2];return Q;
}//计算控制点,形参n是控制点数,跟姿态个数相同
void GetCtlPoint(QUAT Qn[], int n, QUAT Sn[])
{Sn[0] = Qn[0];        //第一个控制点和最后一个控制点无法由公式获取Sn[n-1] = Qn[n-1];    //因此设置为与第一个插值点和最后一个插值点相同,对整个曲线影响不大QUAT qi,qi_m1,qi_a1,qi_conj;QUAT m0,m1,m0_log,m1_log,m_log_sum,k,k_exp;u8 i = 0;for(i = 1; i < n-1; i++){qi = Qn[i];qi_m1 = Qn[i-1];qi_a1 = Qn[i+1];if(Quat_Dot(&qi, &qi_m1)<0)  qi_m1 = Quat_Reverse(&qi_m1);if(Quat_Dot(&qi, &qi_a1)<0)  qi_a1 = Quat_Reverse(&qi_a1);qi_conj = Quat_Conj(&qi);m0 = Quat_Product(&qi_conj, &qi_m1);m1 = Quat_Product(&qi_conj, &qi_a1);//k = -((log(m0)+log(m1))/4);m0_log = Quat_Log(&m0);m1_log = Quat_Log(&m1);m_log_sum = Quat_Add(&m0_log,&m1_log);k = Quat_Smupltipy(&m_log_sum, -1/4);k_exp = Quat_Exp(&k);Sn[i] = Quat_Product(&qi,&k_exp);}
}//四元数球面线性插值
QUAT Slerp_Inter(QUAT *Qs, QUAT *Qe, float lambda)
{float cosa = Qs->s*Qe->s + Qs->v[0]*Qe->v[0] + Qs->v[1]*Qe->v[1] + Qs->v[2]*Qe->v[2];float k0, k1;QUAT Qt;// If the dot product is negative, the quaternions have opposite handed-ness and slerp won't take// the shorter path. Fix by reversing one quaternion.//q与-q实际上对应的是同一个旋转(double cover),为了得到最短路径,//插补之前应该判断两个四元数的角度,钝角则反转其中一个四元数if(cosa < 0){cosa = -cosa;Qe->s = -Qe->s;Qe->v[0] = -Qe->v[0];Qe->v[1] = -Qe->v[1];Qe->v[2] = -Qe->v[2];}// If the inputs are too close for comfort, linearly interpolate //这里使用的是Lerp,使用Nlerp可能误差更小if(cosa > 0.9995f){k0 = 1.0f - lambda;k1 = lambda;}else{float sina = sqrt(1.0f - cosa*cosa);float a = atan2(sina, cosa);k0 = sin((1.0f - lambda)*a) / sina;k1 = sin(lambda*a) / sina;}Qt.s      = Qs->s*k0 + Qe->s*k1;Qt.v[0] = Qs->v[0]*k0 + Qe->v[0]*k1;Qt.v[1] = Qs->v[1]*k0 + Qe->v[1]*k1;Qt.v[2] = Qs->v[2]*k0 + Qe->v[2]*k1;return Qt;
}//squad姿态插值
QUAT Squad(QUAT *Qi, QUAT *Si, QUAT *Si_1, QUAT *Qi_1, double t)
{QUAT k1 = Slerp_Inter(Qi,Qi_1,t);QUAT k2 = Slerp_Inter(Si,Si_1,t);return Slerp_Inter(&k1,&k2, 2*t*(1-t));
}

math_robot.h

#ifndef _MATH_ROBOT_H_
#define _MATH_ROBOT_H_typedef struct Quat{float s;         //scalarfloat v[3];       //vector
}QUAT;QUAT Slerp_Inter(QUAT *Qs, QUAT *Qe, float lambda);
QUAT Squad(QUAT *Qi, QUAT *Si, QUAT *Si_1, QUAT *Qi_1, double t);
void GetCtlPoint(QUAT Qn[], int n, QUAT Sn[4]);#endif

代码仅供参考,如果有错误,请告诉我一下,Thanks!

参考文献:

《四元数与三维旋转》

《Quaternions, Interpolation and Animation》

文章分享给你们:

链接:https://pan.baidu.com/s/1Wuv25T7J0OYCdFPW_QAzqw 
提取码:169y

单位四元数多姿态插值(squad)相关推荐

  1. 基于单位四元数的姿态插补算法

    基于单位四元数的姿态插补算法 文章目录 基于单位四元数的姿态插补算法 摘要 单位四元数空间与欧式空间的转化 四元数的旋转变换表示空间定点旋转 两个姿态间的插补 仿真验证 小结 摘要 现代制造领域对工业 ...

  2. 三维空间刚体运动4-3:四元数线性插值方法:Squad

    三维空间刚体运动4-3:四元数线性插值方法:Squad Squad的引出 B e ˊ z i e r c u r v e B\acute{e}zier \space curveB e ˊ zier c ...

  3. 一、旋转矩阵,旋转向量,单位四元数的相互转换总结

    文章目录 前言 一.要点 1. 旋转矩阵 2. 旋转向量 3. 单位四元数 二.旋转向量--->旋转矩阵(罗德里格斯公式) 三.旋转矩阵--->旋转向量 四.单位四元数--->旋转矩 ...

  4. 机器人学:四元数插值方法SLERP和SQUAD的C语言实现

    目录 文件声明 使用到的基本运算 SLERP SQUAD 在理解四元数的SLERP和SQUAD的数学推导的基础上,使用C语言实现这两种插值方法: 参考:Understanding Quaternion ...

  5. 单位四元数(unit quaternion)

    在机器人学中,表示旋转变换的有旋转矩阵.欧拉角.角/度轴和单位四元数. ##1.四元数的表示 四元数是由复数扩展而来: a+bi⟹ω+xi+yj+zka + bi \Longrightarrow \o ...

  6. 四元数AHRS姿态解算和IMU姿态解算分析

    ref:https://blog.csdn.net/xiaoxie613520/article/details/78227170 AHRS是自动航向基准系统(Automatic Heading Ref ...

  7. 捷联惯导算法与组合导航原理学习——四元数和姿态阵转换(二)

    四元数和姿态阵转换 学习资料参考: [1] 严恭敏,翁浚. 捷联惯导算法与组合导航原理[M]. 西安: 西北工业大学出版社, 2019.8. Quaternion.h #pragma once #in ...

  8. 六轴传感器基础知识学习:MPU6050特性,四元数,姿态解算,卡尔曼滤波

    实际上,只要说到多少轴的传感器一般是就是指加速度传感器(即加速计).角速度传感器(即陀螺仪).磁感应传感器(即电子罗盘).这三类传感器测量的数据在空间坐标系中都可以被分解为X,Y,Z三个方向轴的力,因 ...

  9. MoveIT和KDL中进行机械臂位置和姿态插值

    机械臂轨迹规划中,可以使用直线和圆弧规划,不同规划方式对应不同的计算方法.在MoveIT中,moveit_planners/pilz_industrial_motion_planner/src/下保存 ...

最新文章

  1. C#总结项目《汽车租聘系统》项目代码实例【全注释版】
  2. 三、CSS重要的盒子模型知识总结(中篇)
  3. Machinations——可视化游戏设计
  4. 初次就这么给了你(Django-rest-framework)
  5. linux下mono的安装与卸载
  6. 迪士尼手机官方专卖东家京破产
  7. Python 数据科学手册 5.8 决策树和随机森林
  8. python 并发编程目录
  9. @程序员,你的技术为啥十年八年也没有进步?
  10. 什么是SOHO一族?
  11. Use AVAudioPlayer in OperationQueue
  12. STM32 - L4系列芯片手册: 总线架构
  13. 蛮牛精选七款Unity插件
  14. Unity渲染管线详解
  15. 支持向量机原理(理解SVM的三层境界)
  16. 牛刀杀鸡-开源社区API之抢楼大作战
  17. 机器学习如何优化策略游戏
  18. 苹果4S恢复模式 一直正在等待iphone解决办法
  19. 百度地图集成,经纬度返回 4.9e-324
  20. 如何让自己像打王者荣耀一样发了疯、拼了命、失了智的学习?

热门文章

  1. 【文献阅读】MUTAN——多模态塔克融合VQA模型(Hedi Ben-younes等人,ArXiv,2017,有代码)
  2. Java后台生成图表——主代码(折线图,饼状图,柱状图,-》并产出图片PDF或其他格式的图片内容)
  3. 数字化不是试出来,而是蹚出来的|行知数字中国 × 富士康史喆
  4. 国际首例!郭光灿团队在二维材料固态自旋色心室温操控取得突破
  5. Android App开发超实用实例 | AlertDialog对话框
  6. 计算机专业的中职论文,中职计算机专业论文毕业论文
  7. 12个月的英语名称来历
  8. 记本最新22款验机工具大全(适用于XP和vista)
  9. 16级C++第三次上机解题报告
  10. 关于github page 建立博客访问404