Files
WoodDrone/dev/ori2.cpp
Dana Markova 0de214c9a1 first commit
2025-07-28 13:21:36 +03:00

206 lines
4.8 KiB
C++

#include <math.h>
#include "imu.h"
#include "ori.h"
#include "med2.h"
static const float PI = 3.14159265359f;
static const float TO_DEG = 57.2957795130f;
static float FK_PR = 0.01f;
static float FK_Y = 0.01f;
void ORI_Init()
{
IMU_Init();
}
//------------------------------------------------------------------------------
static const long IMU_Iner_Fil = 64;
static float IMU_Iner[3];
static float GetCompass(struct ORI_Data& Data)
{
float x=-Data.Mag.Y/1000.0f, y=-Data.Mag.X/1000.0f, z=-Data.Mag.Z/1000.0f;
float sp = Data.SinPitch;
float sr = Data.SinRoll;
float cp = Data.CosPitch;
float cr = Data.CosRoll;
float cx = x * cp + z * sp;
float cy = x * sr * sp + y * cr - z * sr * cp;
float n=-atan2f(cy, cx)*TO_DEG;
float north=360+n;
Data.North=Data.Upside;
if(n>90) n=180-n;
else if(n<-90) n=-180-n;
else Data.North=!Data.Upside;
static long nnn;
nnn=n;
Data.Yaw = Data.Yaw * (1.0f - FK_Y) + n * FK_Y;
return north;
}
inline float GetAngle(float a1, float a2, float az)
{
if(a2 == 0.0f && az == 0.0f) return a1>0 ? 90.0f : -90.0f;
return atanf(a1/(sqrtf(a2*a2+az*az))) * TO_DEG;
}
static void GetAngle(ORI_Data& Data, const unsigned long Freq, short Iner[3])
{
const float sr=Data.SinRoll;
const float sp=Data.SinPitch;
const float cr=Data.CosRoll;
const float cp=Data.CosPitch;
float gx = Data.Gyr.X / 16.0f / Freq;
float gy = Data.Gyr.Y / 16.0f / Freq;
float gz = Data.Gyr.Z / 16.0f / Freq;
float ax = Data.Acc.X;
float ay = Data.Acc.Y;
float az = Data.Acc.Z;
float sum_xyz;
sum_xyz = sqrtf((ax*ax)+(ay*ay)+(az*az)) / 1000.0f;
Data.Acc.Sum=sum_xyz*1000;
if(Data.Upside) gz=-gz;
float gn=gz*cp*cr-gx*sr-gy*sp;
if(Data.Upside) { gx=-gx; gy=-gy; gz=-gz; }
float gp=gx*cr+gz*sr;
float gr=gy*cp+gz*sp;
static float pitch=0;
static float roll=0;
float yaw=Data.Yaw;
pitch -= gp;
roll += gr;
yaw += gn;
if(pitch>90.0f) { Data.Upside=!Data.Upside; pitch=180.0f-pitch; }
else if(pitch<-90.0f) { Data.Upside=!Data.Upside; pitch=-180.0f-pitch; }
if(roll>90.0f) { Data.Upside=!Data.Upside; roll=180.0f-roll; }
else if(roll<-90.0f) { Data.Upside=!Data.Upside; roll=-180.0f-roll; }
if(yaw>90.0f) { Data.North=!Data.North; yaw=180.0f-yaw; }
else if(yaw<-90.0f) { Data.North=!Data.North; yaw=-180.0f-yaw; }
if((sum_xyz>0.98f) && (sum_xyz<1.02f))
{
float ap=GetAngle(ay, ax, az);
float ar=GetAngle(ax, ay, az);
Data.Upside=az>0;
pitch = pitch * (1.0f - FK_PR) + ap * FK_PR;
roll = roll * (1.0f - FK_PR) + ar * FK_PR;
}
Data.Pitch = pitch;
Data.Roll = roll;
Data.Yaw = yaw;
Data.SinPitch=sinf(pitch*PI/180.0f);
Data.SinRoll=sinf(roll*PI/180.0f);
Data.SinYaw=sinf(yaw*PI/180.0f);
Data.CosPitch=sqrtf(1.0f-Data.SinPitch*Data.SinPitch);
Data.CosRoll=sqrtf(1.0f-Data.SinRoll*Data.SinRoll);
Data.CosYaw=sqrtf(1.0f-Data.SinYaw*Data.SinYaw);
}
static short GyroShift[3]{20, 10, -2};
static short NormAcc_X[2]{-4090, 4110}, NormAcc_Y[2]{-4130, 4075}, NormAcc_Z[2]{-4182, 4070};
static short NormMag_X[2]{-360, 270}, NormMag_Y[2]{-260, 340}, NormMag_Z[2]{-350, 320};
static void NormalizeAcc(short& X, short& Y, short& Z, const short G)
{
short x=(NormAcc_X[1]-NormAcc_X[0])/2;
short y=(NormAcc_Y[1]-NormAcc_Y[0])/2;
short z=(NormAcc_Z[1]-NormAcc_Z[0])/2;
X=(X-(NormAcc_X[0]+x))*G/x;
Y=(Y-(NormAcc_Y[0]+y))*G/y;
Z=(Z-(NormAcc_Z[0]+z))*G/z;
}
static void NormalizeMag(short& X, short& Y, short& Z, const short N)
{
short x=(NormMag_X[1]-NormMag_X[0])/2;
short y=(NormMag_Y[1]-NormMag_Y[0])/2;
short z=(NormMag_Z[1]-NormMag_Z[0])/2;
X=(X-(NormMag_X[0]+x))*N/x;
Y=(Y-(NormMag_Y[0]+y))*N/y;
Z=(Z-(NormMag_Z[0]+z))*N/z;
}
IMU_Data DataIMU;
void ORI_Get(ORI_Data& Data, const unsigned long Freq, short Iner[3])
{
IMU_Get(DataIMU);
short ax = DataIMU.Acc.X;
short ay = DataIMU.Acc.Y;
short az = DataIMU.Acc.Z;
NormalizeAcc(ax, ay, az, 1000);
Data.Acc.X = ax;
Data.Acc.Y = ay;
Data.Acc.Z = az;
Data.Gyr.X = DataIMU.Gyr.X + GyroShift[0];
Data.Gyr.Y = DataIMU.Gyr.Y + GyroShift[1];
Data.Gyr.Z = DataIMU.Gyr.Z + GyroShift[2];
short mx = DataIMU.Mag.X;
short my = DataIMU.Mag.Y;
short mz = DataIMU.Mag.Z;
NormalizeMag(mx, my, mz, 1000);
Data.Mag.X = mx;
Data.Mag.Y = my;
Data.Mag.Z = mz;
GetAngle(Data, Freq, Iner);
GetCompass(Data);
}
short CompAcc[3];
void ORI_TiltCompAcc(float Pitch, float Roll, short Acc[3], IMU_Data& Data)
{
float sin_r = sinf(Roll*PI/180.0f);
float sin_p = sinf(Pitch*PI/180.0f);
float cos_r = sqrtf(1.0f-sin_r*sin_r); // cosf(Roll*PI/180.0f);
float cos_p = sqrtf(1.0f-sin_p*sin_p); // cosf(Pitch*PI/180.0f);
Acc[0] = Data.Acc.X - 4000 * sin_r;
Acc[1] = Data.Acc.Y + 4000 * sin_p;
Acc[2] = Data.Acc.Z - 4000 * fabs(cos_r) * fabs(cos_p);
CompAcc[0]=Acc[0];
CompAcc[1]=Acc[1];
CompAcc[2]=Acc[2];
}