595 lines
15 KiB
C++
595 lines
15 KiB
C++
/******************** (C) COPYRIGHT 2023 Geek************************************
|
||
* File Name : SensorImpl.cpp
|
||
* Current Version : V1.0
|
||
* Author : zhanli
|
||
* Date of Issued : 2023.09.10
|
||
* Comments : GeekIMU 传感器实现模块
|
||
********************************************************************************/
|
||
/* Header File Including -----------------------------------------------------*/
|
||
|
||
#include "windows.h"
|
||
#include "SensorImpl.h"
|
||
#include "stdio.h"
|
||
#include "quaternion.h"
|
||
#include "math.h"
|
||
#include "UsbHid_CAPI.h"
|
||
#include "MyCls.h"
|
||
extern "C" FILE* fpdata;
|
||
Quaternion GlobalQ;
|
||
BOOL GlobalQ_Updating;
|
||
float LocX,LocY,LocZ;
|
||
float Yaw,Pitch,Roll;
|
||
extern FILE* Getfpdata();
|
||
extern int global_calibration_flag;
|
||
extern int global_Show;
|
||
UINT8 global_key[4] = { 0 };
|
||
float gxc=0, gyc=0, gzc=0;
|
||
int gyro_cali_count = 0;
|
||
#define GYRO_CALIBRATION_SAMPLE_NUMBER 3000
|
||
float gx0=0, gy0=0, gz0=0;
|
||
BOOL GlobalMag_Updating = false;
|
||
Vector3 GlobalMag = {0};
|
||
static bool HmdStandByState;
|
||
|
||
Quaternion CQ_DM = { 1, 0, 0, 0 };
|
||
|
||
bool DM_Corrected = false;
|
||
|
||
void MagFilter(float *mx,float *my,float *mz,float sita);
|
||
void GyroComputeDrift(float *gx, float *gy, float *gz);
|
||
|
||
void LowPassFilterYaw(float *z, float alpha);
|
||
|
||
bool IsHmdIntoStandBy(float *Pitch, float *Roll, float dTime);
|
||
|
||
/**----------------------------------------------------------------------
|
||
* Function : UnpackSensor
|
||
* Description : Oculus 数据解包
|
||
* Date : 2023/09/10 logzhan : 重新整理代码
|
||
*---------------------------------------------------------------------**/
|
||
void UnpackSensor(const UCHAR* buffer, long* x, long* y, long* z)
|
||
{
|
||
struct {INT32 x:21;} s;
|
||
*x = s.x = (buffer[0] << 13) | (buffer[1] << 5) | ((buffer[2] & 0xF8) >> 3);
|
||
*y = s.x = ((buffer[2] & 0x07) << 18) | (buffer[3] << 10) | (buffer[4] << 2) |
|
||
((buffer[5] & 0xC0) >> 6);
|
||
*z = s.x = ((buffer[5] & 0x3F) << 15) | (buffer[6] << 7) | (buffer[7] >> 1);
|
||
}
|
||
|
||
Vector3 GetMagData()
|
||
{
|
||
Vector3 v = { 0 };
|
||
static Vector3 VLast = { 0 };
|
||
if (!GlobalMag_Updating)
|
||
{
|
||
VLast = GlobalMag;
|
||
}
|
||
v = VLast;
|
||
return v;
|
||
}
|
||
|
||
void GetControllerSensor(unsigned char usb_input_buffer[])
|
||
{
|
||
static UINT8 updatecnt = 0;
|
||
INT16 MagX,MagY,MagZ;
|
||
long GX,GY,GZ;
|
||
long AX,AY,AZ;
|
||
UINT NowTime;
|
||
float ax, ay, az, gx, gy, gz, mx, my, mz, mx1, my1, mz1;;
|
||
static float mxlast=0,mylast=0,mzlast=0;
|
||
static int Dtime = 0;
|
||
static UINT LastTime = 0;
|
||
float q0,q1,q2,q3;
|
||
|
||
|
||
NowTime = *(UINT16* )(usb_input_buffer+2);
|
||
if(LastTime != 0)
|
||
{
|
||
if(NowTime >= LastTime)
|
||
{
|
||
Dtime = NowTime - LastTime;
|
||
LastTime = NowTime;
|
||
}else
|
||
{
|
||
Dtime = (65535 - LastTime) + NowTime;
|
||
LastTime = NowTime;
|
||
}
|
||
|
||
}else
|
||
{
|
||
Dtime = 1;
|
||
LastTime = NowTime;
|
||
}
|
||
|
||
if (global_Show==5)
|
||
{
|
||
//clrscr();
|
||
back2zero();
|
||
printf("Hex数据\n\n");
|
||
for (int i = 0; i < 64; i++)
|
||
{
|
||
if ((i%16)==0)
|
||
{
|
||
printf("\n");
|
||
}
|
||
//if (global_debug)
|
||
printf("%2x ", usb_input_buffer[i]);
|
||
|
||
}
|
||
printf("\n");
|
||
}
|
||
|
||
|
||
MagX = *(INT16 *)(usb_input_buffer + 56);
|
||
MagY = *(INT16 *)(usb_input_buffer + 58);
|
||
MagZ = *(INT16 *)(usb_input_buffer + 60);
|
||
|
||
UnpackSensor(usb_input_buffer+8, &AX,&AY,&AZ);
|
||
UnpackSensor(usb_input_buffer+16, &GX,&GY,&GZ);
|
||
|
||
|
||
ax = (float)0.0001*AX;
|
||
ay = (float)0.0001*AY;
|
||
az = (float)0.0001*AZ;
|
||
|
||
gx = (float)0.0001*GX;
|
||
gy = (float)0.0001*GY;
|
||
gz = (float)0.0001*GZ;
|
||
|
||
|
||
printf("%f %f %f\n", ax, ay, az);
|
||
|
||
float x = 16.4 * 180 / 3.14159265358979323846F;
|
||
|
||
if (global_Show == 1)
|
||
{
|
||
printf("gx = %f,gy = %f gz =%f\n", gx*x, gy*x, gz*x);
|
||
}
|
||
|
||
GyroComputeDrift(&gx, &gy, &gz);
|
||
|
||
if (global_calibration_flag == 1)
|
||
{
|
||
if (gyro_cali_count > GYRO_CALIBRATION_SAMPLE_NUMBER)
|
||
{
|
||
gyro_cali_count = 0;
|
||
gxc = gyc = gzc = 0;
|
||
}
|
||
gyro_cali_count++;
|
||
gxc += gx*x;
|
||
gyc += gy*x;
|
||
gzc += gz*x;
|
||
if (gyro_cali_count == GYRO_CALIBRATION_SAMPLE_NUMBER)
|
||
{
|
||
gx0 = gxc / gyro_cali_count;
|
||
gy0 = gyc / gyro_cali_count;
|
||
gz0 = gzc / gyro_cali_count;
|
||
gyro_cali_count++;
|
||
global_calibration_flag = 0;
|
||
printf("%f %f %f\n", gx0, gy0, gz0);
|
||
}
|
||
}
|
||
|
||
|
||
global_key[0] = usb_input_buffer[24];
|
||
global_key[3] = usb_input_buffer[27];
|
||
|
||
|
||
mx = (float)MagX / 16;
|
||
my = (float)MagY / 16;
|
||
mz = (float)MagZ / 16;
|
||
if (global_calibration_flag==3)
|
||
{
|
||
GlobalMag_Updating = true;
|
||
mx = (float)MagX;
|
||
my = (float)MagY;
|
||
mz = (float)MagZ;
|
||
|
||
GlobalMag.x = (float)MagX;
|
||
GlobalMag.y = (float)MagY;
|
||
GlobalMag.z = (float)MagZ;
|
||
GlobalMag_Updating = false;
|
||
}
|
||
|
||
|
||
if(mxlast == 0&&mylast == 0&&mzlast == 0)
|
||
{
|
||
mxlast = mx;
|
||
mylast = my;
|
||
mzlast = mz;
|
||
|
||
MagFilter(&mx, &my, &mz, 0.95f);
|
||
for (int i = 0; i < 200; i++)
|
||
AHRSupdate(0, 0, 0, az, ax, ay, mz, mx, my, 1, Dtime * 400);
|
||
}
|
||
else
|
||
{
|
||
updatecnt++;
|
||
if (updatecnt > 10)
|
||
updatecnt = 0;
|
||
if (mx == mxlast&&my == my&&mz == mzlast && updatecnt < 10)
|
||
{
|
||
AHRSupdate(gz,gx,gy,az,ax,ay,mz,mx,my,1,Dtime);
|
||
|
||
}
|
||
else
|
||
{
|
||
mxlast = mx;
|
||
mylast = my;
|
||
mzlast = mz;
|
||
|
||
MagFilter(&mx,&my,&mz,0.95f);
|
||
|
||
AHRSupdate(gz,gx,gy,az,ax,ay,mz,mx,my,1,Dtime);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/**********************************************************************************************************
|
||
* Function Name : AHRSupdate
|
||
* 输入 : 三轴加速度计、陀螺仪、磁力计的值
|
||
* 描述 :加速度计、陀螺仪、磁力计融合得到的欧拉角
|
||
|
||
1)这个算法基于标准笛卡尔右手坐标系,z轴朝上,x轴朝人,y轴朝右
|
||
2)传感器的方向需要变换到和改算法定义的坐标轴相同。
|
||
|
||
* 修改 :2016/11/5 : 根据磁力计采样率比较低的特点,设置了2种模式:1、融合磁力计 2、不融合磁力计
|
||
2016/11/6 :改进了四元数更新算法,原来的四元数更新算法会导致累计误差。
|
||
2016/11/9 : 规定了本算法运行的坐标轴,重写了四元数到欧拉角变换的代码。
|
||
***********************************************************************************************************/
|
||
|
||
|
||
float q0 = 1, q1 = 0, q2 = 0, q3 = 0;
|
||
float exInt = 0, eyInt = 0, ezInt = 0; /*缩放积分误差 */
|
||
#define Kp 2.5f /*加速度计和磁力计对陀螺仪的比例修正参数 */
|
||
#define Ki 0.005f /*加速度计和磁力计对陀螺仪的积分修正参数 */
|
||
#define Kd 0.0f
|
||
static int AHRS_Init = 0;
|
||
|
||
|
||
void ResetAHRS()
|
||
{
|
||
AHRS_Init = 0; q0 = 1; q1 = 0; q2 = 0; q3 = 0;
|
||
}
|
||
|
||
void AHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz, char useMag, int Dtime)
|
||
{
|
||
/*原算法的定义*/
|
||
float norm, halfT;
|
||
float hx, hy, hz, bz, by;
|
||
float vx, vy, vz, wx, wy, wz;
|
||
float ex, ey, ez;
|
||
float qw, qx, qy, qz;
|
||
float AccelAjust, MagAjust;
|
||
/*方便之后的程序使用,减少计算时间*/
|
||
float q0q0 = q0*q0; float q0q1 = q0*q1;
|
||
float q0q2 = q0*q2; float q0q3 = q0*q3;
|
||
float q1q1 = q1*q1; float q1q2 = q1*q2;
|
||
float q1q3 = q1*q3; float q2q2 = q2*q2;
|
||
float q2q3 = q2*q3; float q3q3 = q3*q3;
|
||
if (AHRS_Init > 200)
|
||
{
|
||
halfT = 0.0005f*Dtime; /*得到每次姿态更新的周期的一半t = (1/SampleFrq) * 0.5 */
|
||
}
|
||
else
|
||
{
|
||
if (useMag == 1)
|
||
{
|
||
halfT = 0.1;
|
||
gx = gy = gz = 0;
|
||
AHRS_Init++;
|
||
}
|
||
else
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
norm = invSqrt(ax*ax + ay*ay + az*az); /*把加速度计向量转换为单位向量*/
|
||
|
||
if ((1.0f / norm) > 1.6 || (1.0f / norm) < 0.4){
|
||
AccelAjust = 0;
|
||
MagAjust = 1.2f;
|
||
|
||
}
|
||
else{
|
||
AccelAjust = 1.0f;
|
||
MagAjust = 1.0f;
|
||
}
|
||
|
||
|
||
ax = ax * norm;
|
||
ay = ay * norm;
|
||
az = az * norm; /*把磁力计向量转换为单位向量 */
|
||
norm = invSqrt(mx*mx + my*my + mz*mz);
|
||
mx = mx * norm;
|
||
my = my * norm;
|
||
mz = mz * norm;
|
||
|
||
|
||
hx = 2.0f*(mx*(0.5f - q2q2 - q3q3) + my*(q1q2 - q0q3) + mz*(q1q3 + q0q2)); /*把(mx,my,mz)转换到地理坐标系的(hx,hy,hz),利用H = Q^-1 * M */
|
||
hy = 2.0f*(mx*(q1q2 + q0q3) + my*(0.5f - q1q1 - q3q3) + mz*(q2q3 - q0q1));
|
||
hz = 2.0f*(mx*(q1q3 - q0q2) + my*(q2q3 + q0q1) + mz*(0.5f - q1q1 - q2q2));
|
||
|
||
/*计的数值为(bx,by,0),所以我们不关注hx的数值 */
|
||
// bx = sqrtf((hx*hx) + (hy*hy)); /*使磁力计正交化*/
|
||
by = sqrtf((hx*hx) + (hy*hy));
|
||
bz = hz;
|
||
|
||
/*v代表的是把地理坐标系的加速度(0,0,1g)转换到机体坐标系的加 */
|
||
vx = 2.0f*(q1q3 - q0q2); /*速度计(ax,ay,az),其实就是用R*(0,0,1),R为旋转矩阵,此矩阵可 */
|
||
vy = 2 * (q0q1 + q2q3); /*由四元数转换得到 */
|
||
vz = q0q0 - q1q1 - q2q2 + q3q3;
|
||
|
||
wx = 2.0f*(by*(q1q2 + q0q3) + bz*(q1q3 - q0q2)); /*把正交化的H即B从地理坐标系转换到飞行器坐标系,利用W = Q * B */
|
||
wy = 2.0f*(by*(0.5f - q1q1 - q3q3) + bz*(q0q1 + q2q3)); /*这里认为bx = 0 */
|
||
wz = 2.0f*(by*(q2q3 - q0q1) + bz*(0.5f - q1q1 - q2q2));
|
||
|
||
|
||
|
||
/*如果使用磁力计,则融合磁力计*/
|
||
if (useMag != 0)
|
||
{ /*用当前姿态向量和加速度的姿态向量做叉乘,乘积越小说明两个向量方向越相同*/
|
||
ex = AccelAjust*(ay*vz - az*vy) + MagAjust*(my*wz - mz*wy);
|
||
ey = AccelAjust*(az*vx - ax*vz) + MagAjust*(mz*wx - mx*wz);
|
||
ez = AccelAjust*(ax*vy - ay*vx) + MagAjust*(mx*wy - my*wx);
|
||
}
|
||
else
|
||
{
|
||
|
||
ex = AccelAjust*(ay*vz - az*vy);
|
||
ey = AccelAjust*(az*vx - ax*vz); /*因为加速度计没有校准,ez不靠谱*/
|
||
ez = AccelAjust*(ax*vy - ay*vx);
|
||
ez = 0;
|
||
}
|
||
|
||
if (ex != 0.0f && ey != 0.0f && ez != 0.0f)
|
||
{
|
||
/*这里使用了PID调节的方式,对角速度修正,Ki 是积分修正,Kp是直接修正 */
|
||
exInt = exInt + ex*Ki * halfT; /*对误差进行积分 */
|
||
eyInt = eyInt + ey*Ki * halfT;
|
||
ezInt = ezInt + ez*Ki * halfT;
|
||
gx = gx + Kp*(1 + Kd*fabsf(ex))*ex + exInt; /*使用比例和积分综合对陀螺仪进行修正,由于存在积分修正,所以才能确保回 */
|
||
gy = gy + Kp*(1 + Kd*fabsf(ey))*ey + eyInt; /*到期望回到的位置 */
|
||
gz = gz + Kp*(1 + Kd*fabsf(ez))*ez + ezInt;
|
||
}
|
||
|
||
|
||
qw = (-q1*gx - q2*gy - q3*gz)*halfT; /*利用一阶龙格库塔法对四元数进行更新*/
|
||
qx = (q0*gx + q2*gz - q3*gy)*halfT;
|
||
qy = (q0*gy - q1*gz + q3*gx)*halfT;
|
||
qz = (q0*gz + q1*gy - q2*gx)*halfT;
|
||
|
||
q0 = q0 + qw;
|
||
q1 = q1 + qx;
|
||
q2 = q2 + qy;
|
||
q3 = q3 + qz;
|
||
|
||
|
||
norm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3); /*对四元数进行规范化,即四元数模为1*/
|
||
|
||
q0 = q0 * norm; //w
|
||
q1 = q1 * norm; //x
|
||
q2 = q2 * norm; //y
|
||
q3 = q3 * norm; //z
|
||
|
||
|
||
/*对原变换公式进行重写,避免了以前坐标轴混乱的问题,按照标准y上z右x前*/
|
||
Pitch = asin(-2.0f*(q2*q1 - q0*q3))* (180.0f / 3.141592f); /*轴进行四元数到欧拉角的转换 */
|
||
Yaw = atan2(q3*q1 + q0*q2, 0.5f - q3*q3 - q2*q2)* (180.0f / 3.141592f);
|
||
Roll = atan2(q3*q2 + q0*q1, 0.5f - q3*q3 - q1*q1)* (180.0f / 3.141592f);
|
||
|
||
LowPassFilterYaw(&Yaw, 0.9f);
|
||
|
||
if (AHRS_Init > 200)
|
||
{
|
||
GlobalQ_Updating = TRUE;
|
||
GlobalQ.w = q0;
|
||
GlobalQ.x = q2;
|
||
GlobalQ.y = q3;
|
||
GlobalQ.z = q1;
|
||
GlobalQ_Updating = FALSE;
|
||
}
|
||
printf("%f %f %f\n", Yaw, Roll, Pitch);
|
||
|
||
IsHmdIntoStandBy(&Pitch, &Roll, 1.0f);
|
||
}
|
||
|
||
|
||
void MagFilter(float *mx, float *my, float *mz, float sita)
|
||
{
|
||
static float xlast = 0, ylast = 0, zlast = 0;
|
||
if (xlast == 0 && ylast == 0 && zlast == 0)
|
||
{
|
||
xlast = *mx;
|
||
ylast = *my;
|
||
zlast = *mz;
|
||
}
|
||
else
|
||
{
|
||
xlast = sita*xlast + (1 - sita)*(*mx);
|
||
ylast = sita*ylast + (1 - sita)*(*my);
|
||
zlast = sita*zlast + (1 - sita)*(*mz);
|
||
}
|
||
}
|
||
|
||
|
||
/*******************************************************************************
|
||
* Function Name : invSqrt
|
||
* Description : 快速计算 1/Sqrt(x),源自雷神3,神奇的0x5f3759df
|
||
* 输入 : x
|
||
* 输出 :1/sqrt(x)
|
||
*******************************************************************************/
|
||
float invSqrt(float x)
|
||
{
|
||
float halfx = 0.5f * x;
|
||
float y = x;
|
||
long i = *(long*)&y;
|
||
i = 0x5f3759df - (i >> 1);
|
||
y = *(float*)&i;
|
||
y = y * (1.5f - (halfx * y * y));
|
||
return y;
|
||
}
|
||
|
||
|
||
void GyroComputeDrift(float *gx, float *gy, float *gz)
|
||
{
|
||
static float GxOffect = 0.0f, GyOffect = 0.0f, GzOffect = 0.0f;
|
||
static float GxOffectTmp = 0.0f, GyOffectTmp = 0.0f, GzOffectTmp = 0.0f;
|
||
static float GxTmp = 0.0f, GyTmp = 0.0f, GzTmp = 0.0f;
|
||
static int count = 0;
|
||
|
||
*gx = *gx - GxOffect;
|
||
*gy = *gy - GyOffect;
|
||
*gz = *gz - GzOffect;
|
||
|
||
if (HmdStandByState == true){
|
||
GxTmp = GxTmp + *gx;
|
||
GyTmp = GyTmp + *gy;
|
||
GzTmp = GzTmp + *gz;
|
||
count++;
|
||
if (count == 3000){
|
||
//printf("陀螺仪校准完成\n");
|
||
|
||
GxOffectTmp = GxTmp / count;
|
||
GyOffectTmp = GyTmp / count;
|
||
GzOffectTmp = GzTmp / count;
|
||
|
||
GxOffect = GxOffect + GxOffectTmp;
|
||
GyOffect = GyOffect + GyOffectTmp;
|
||
GzOffect = GzOffect + GzOffectTmp;
|
||
|
||
GxTmp = 0.0f;
|
||
GyTmp = 0.0f;
|
||
GzTmp = 0.0f;
|
||
count = 0;
|
||
}
|
||
}
|
||
else{
|
||
count = 0;
|
||
GxTmp = 0.0f;
|
||
GyTmp = 0.0f;
|
||
GzTmp = 0.0f;
|
||
}
|
||
|
||
}
|
||
|
||
void LowPassFilterYaw(float *z, float alpha)
|
||
{
|
||
static float lastz = 0;
|
||
if (lastz == 0)
|
||
{
|
||
lastz = *z;
|
||
}
|
||
else
|
||
{
|
||
*z = alpha*lastz + (1 - alpha)*(*z);
|
||
lastz = *z;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
bool IsHmdIntoStandBy(float *Pitch, float *Roll, float dTime)
|
||
{
|
||
static float LastPitch = 0.0f, LastRoll = 0.0f;
|
||
static float LastGyroX = 0.0f, LastGyroY = 0.0f;
|
||
static int count = 0;
|
||
float GyroX = 0.0f, GyroY = 0.0f, alpha = 0.98f;
|
||
|
||
|
||
/* 初始化静态变量 */
|
||
if (LastPitch == 0.0f&&LastRoll == 0.0f){
|
||
LastPitch = *Pitch;
|
||
LastRoll = *Roll;
|
||
}
|
||
/*对Pitch和Roll微分,求Gx和Gy */
|
||
GyroX = fabsf(*Roll - LastRoll) / dTime;
|
||
GyroY = fabsf(*Pitch - LastPitch) / dTime;
|
||
/*初始化静态变量*/
|
||
if (LastGyroX == 0.0f&&LastGyroY == 0.0f){
|
||
LastGyroX = GyroX;
|
||
LastGyroY = GyroY;
|
||
}
|
||
/*进行一个滑动窗口滤波降低偶然误差*/
|
||
GyroX = alpha*LastGyroX + (1 - alpha)*GyroX;
|
||
GyroY = alpha*LastGyroY + (1 - alpha)*GyroY;
|
||
|
||
printf("%f %f\n", GyroX, GyroY);
|
||
|
||
if (GyroX < 0.0055f&&GyroY < 0.0015f){
|
||
count++;
|
||
if (count == 3000){
|
||
count = 0;
|
||
HmdStandByState = true;
|
||
printf("头显进入休眠\n");
|
||
}
|
||
}
|
||
else{
|
||
count = 0;
|
||
HmdStandByState = false;
|
||
}
|
||
/* 更新静态变量 */
|
||
LastRoll = *Roll;
|
||
LastPitch = *Pitch;
|
||
LastGyroX = GyroX;
|
||
LastGyroY = GyroY;
|
||
|
||
return HmdStandByState;
|
||
}
|
||
|
||
float DM_GetYaw(void)
|
||
{
|
||
return Yaw;
|
||
}
|
||
|
||
float DM_GetPitch(void)
|
||
{
|
||
return Pitch;
|
||
}
|
||
float DM_GetRoll(void)
|
||
{
|
||
return Roll;
|
||
}
|
||
|
||
|
||
|
||
|
||
Quaternion CorrectQuaterinonYaw(Quaternion q)
|
||
{
|
||
Quaternion qcorr;
|
||
qcorr.w = q.w; qcorr.x = 0.0f;
|
||
qcorr.y = q.y; qcorr.z = 0.0f;
|
||
qcorr = QuaternionInversion(qcorr);
|
||
float mod = QuaternionMod(qcorr);
|
||
qcorr.w = qcorr.w / mod;
|
||
qcorr.x = qcorr.x / mod;
|
||
qcorr.y = qcorr.y / mod;
|
||
qcorr.z = qcorr.z / mod;
|
||
return qcorr;
|
||
}
|
||
int ResetHeading(void)
|
||
{
|
||
Quaternion q = { GlobalQ.w, 0, GlobalQ.y, 0 };
|
||
CQ_DM = CorrectQuaterinonYaw(q);
|
||
DM_Corrected = true;
|
||
return DM_Corrected ? 1 : 0;
|
||
}
|
||
|
||
Quaternion GetPoseQuat(void)
|
||
{
|
||
static Quaternion QLast = { 1.0f, 0.0f, 0.0f, 0.0f };
|
||
if (!GlobalQ_Updating)
|
||
{
|
||
QLast.w = GlobalQ.w;
|
||
QLast.x = GlobalQ.x;
|
||
QLast.y = GlobalQ.y;
|
||
QLast.z = GlobalQ.z;
|
||
}
|
||
if (DM_Corrected){
|
||
return QuaternionMulti(QLast, CQ_DM);
|
||
}
|
||
return QLast;
|
||
} |