dcm.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #pragma once
  2. #include <math.h>
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. /**
  7. * @brief 通过四元数构造旋转矩阵
  8. *
  9. * @param Q 输入四元数
  10. * @param dcm 输出旋转矩阵
  11. */
  12. static inline void DCM_ByQuaternion(const float Q[4], float dcm[3][3]) {
  13. float Q0 = Q[0], Q1 = Q[1], Q2 = Q[2], Q3 = Q[3];
  14. float Q0s = Q[0] * Q[0];
  15. float Q1s = Q[1] * Q[1];
  16. float Q2s = Q[2] * Q[2];
  17. float Q3s = Q[3] * Q[3];
  18. dcm[0][0] = Q0s + Q1s - Q2s - Q3s;
  19. dcm[0][1] = 2.0f * (Q1 * Q2 - Q0 * Q3);
  20. dcm[0][2] = 2.0f * (Q0 * Q2 + Q1 * Q3);
  21. dcm[1][0] = 2.0f * (Q1 * Q2 + Q0 * Q3);
  22. dcm[1][1] = Q0s - Q1s + Q2s - Q3s;
  23. dcm[1][2] = 2.0f * (Q2 * Q3 - Q0 * Q1);
  24. dcm[2][0] = 2.0f * (Q1 * Q3 - Q0 * Q2);
  25. dcm[2][1] = 2.0f * (Q0 * Q1 + Q2 * Q3);
  26. dcm[2][2] = Q0s - Q1s - Q2s + Q3s;
  27. }
  28. /**
  29. * @brief 通过欧拉角构造旋转矩阵
  30. * 欧拉角定义顺序必须为 航向->俯仰->横滚 rad, enu-rfu 框架, 右手定则
  31. * @param yaw 航向角, rad
  32. * @param pitch 俯仰角, rad
  33. * @param roll 横滚角, rad
  34. * @param dcm 旋转矩阵, TbN阵
  35. */
  36. static inline void DCM_Enu_ByEuler(float yaw, float pitch, float roll,
  37. float dcm[3][3]) {
  38. float cos_r = cosf(roll);
  39. float cos_p = cosf(pitch);
  40. float cos_y = cosf(yaw);
  41. float sin_r = sinf(roll);
  42. float sin_p = sinf(pitch);
  43. float sin_y = sinf(yaw);
  44. dcm[0][0] = cos_r * cos_y - sin_p * sin_r * sin_y;
  45. dcm[0][1] = -cos_p * sin_y;
  46. dcm[0][2] = sin_r * cos_y + cos_r * sin_p * sin_y;
  47. dcm[1][0] = cos_r * sin_y + sin_r * sin_p * cos_y;
  48. dcm[1][1] = cos_p * cos_y;
  49. dcm[1][2] = sin_r * sin_y - cos_r * sin_p * cos_y;
  50. dcm[2][0] = -sin_r * cos_p;
  51. dcm[2][1] = sin_p;
  52. dcm[2][2] = cos_r * cos_p;
  53. }
  54. /**
  55. * @brief 通过欧拉角构造旋转矩阵
  56. * 欧拉角定义顺序必须为 航向->俯仰->横滚 rad, ned-frd 框架, 右手定则
  57. * @param yaw 航向角 rad
  58. * @param pitch 俯仰角 rad
  59. * @param roll 横滚角 rad
  60. * @param dcm 旋转矩阵, TbN阵
  61. */
  62. static inline void DCM_Ned_ByEuler(float yaw, float pitch, float roll,
  63. float dcm[3][3]) {
  64. float cos_r = cosf(roll);
  65. float cos_p = cosf(pitch);
  66. float cos_y = cosf(yaw);
  67. float sin_r = sinf(roll);
  68. float sin_p = sinf(pitch);
  69. float sin_y = sinf(yaw);
  70. dcm[0][0] = cos_p * cos_y;
  71. dcm[0][1] = -cos_r * sin_y + sin_r * sin_p * cos_y;
  72. dcm[0][2] = sin_r * sin_y + cos_r * sin_p * cos_y;
  73. dcm[1][0] = cos_p * sin_y;
  74. dcm[1][1] = cos_r * cos_y + sin_r * sin_p * sin_y;
  75. dcm[1][2] = -sin_r * cos_y + cos_r * sin_p * sin_y;
  76. dcm[2][0] = -sin_p;
  77. dcm[2][1] = sin_r * cos_p;
  78. dcm[2][2] = cos_r * cos_p;
  79. }
  80. /**
  81. * @brief 使用 frame1 xyz轴向量 在 frame2 下的坐标,构建旋转矩阵
  82. * x, y, z 必须为互相正交的单位向量
  83. * @param x frame1 x 轴在 frame2 系下的单位坐标
  84. * @param y frame1 y 轴在 frame2 系下的单位坐标
  85. * @param z frame1 z 轴在 frame2 系下的单位坐标
  86. */
  87. static inline void DCM_ByXYZAxis(const float X[3], const float Y[3],
  88. const float Z[3], float dcm[3][3]) {
  89. for (int i = 0; i < 3; ++i) {
  90. dcm[i][0] = X[i];
  91. dcm[i][1] = Y[i];
  92. dcm[i][2] = Z[i];
  93. }
  94. }
  95. #ifdef __cplusplus
  96. }
  97. #endif