mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-04-04 11:57:45 -06:00
* script changes - no arguments * script changes with 2 arguments * script changes with > 2 arguments * script conversions with 1 argument - pt. 1 * script conversions with 1 argument - pt. 2 * script conversions with 1 argument - pt. 3 * script conversions with 1 argument - pt. 4 * script conversions with 1 argument - pt. 5 Pointer format hunting * Fixed pointer format * script conversions with 1 argument - final * fixed conversion in non utf-8 file * fixed conversion with capital letter * actually fixed conversion with capital letter * fixed another capital lettering issue * Added conversions with LR removed * removed LR from logs * Converted logs that previously contained LR * converted log that originally specified string length * fixed log with commas in main text * fixed multi-line log * Fixed more logs with commas in main text * Fixed unformatted pointer * added conversion with float value * converted lines with double parameters * converted missed line * corrected argument formatting Co-authored-by: Crementif <26669564+Crementif@users.noreply.github.com> * Fixed misspellings of "unhandled" unhandeled -> unhandled Co-authored-by: Crementif <26669564+Crementif@users.noreply.github.com> --------- Co-authored-by: Crementif <26669564+Crementif@users.noreply.github.com>
166 lines
4.6 KiB
C++
166 lines
4.6 KiB
C++
#pragma once
|
|
|
|
#include <math.h>
|
|
#include <cmath>
|
|
#include "util/math/quaternion.h"
|
|
|
|
class MahonySensorFusion
|
|
{
|
|
public:
|
|
MahonySensorFusion()
|
|
{
|
|
// assume default forward pose (holding controller in hand, tilted forward so the sticks/buttons face upward)
|
|
m_imuQ.Assign(sqrtf(0.5), sqrtf(0.5), 0.0f, 0.0f);
|
|
}
|
|
|
|
// gx, gy, gz are in radians/sec
|
|
void updateIMU(float deltaTime, float gx, float gy, float gz, float ax, float ay, float az)
|
|
{
|
|
Vector3f av(ax, ay, az);
|
|
Vector3f gv(gx, gy, gz);
|
|
if (deltaTime > 0.2f)
|
|
deltaTime = 0.2f; // dont let stutter mess up the internal state
|
|
updateGyroBias(gx, gy, gz);
|
|
gv.x -= m_gyroBias[0];
|
|
gv.y -= m_gyroBias[1];
|
|
gv.z -= m_gyroBias[2];
|
|
|
|
// ignore small angles to avoid drift due to bias (especially on yaw)
|
|
if (fabs(gv.x) < 0.015f)
|
|
gv.x = 0.0f;
|
|
if (fabs(gv.y) < 0.015f)
|
|
gv.y = 0.0f;
|
|
if (fabs(gv.z) < 0.015f)
|
|
gv.z = 0.0f;
|
|
|
|
// cemuLog_logDebug(LogType::Force, "[IMU Quat] time {:7.4} | {:7.2} {:7.2} {:7.2} {:7.2} | gyro( - bias) {:7.4} {:7.4} {:7.4} | acc {:7.2} {:7.2} {:7.2} | GyroBias {:7.4} {:7.4} {:7.4}", deltaTime, m_imuQ.x, m_imuQ.y, m_imuQ.z, m_imuQ.w, gv.x, gv.y, gv.z, ax, ay, az, m_gyroBias[0], m_gyroBias[1], m_gyroBias[2]);
|
|
|
|
if (fabs(av.x) > 0.000001f || fabs(av.y) > 0.000001f || fabs(av.z) > 0.000001f)
|
|
{
|
|
av.Normalize();
|
|
Vector3f grav = m_imuQ.GetVectorZ();
|
|
grav.Scale(0.5f);
|
|
Vector3f errorFeedback = grav.Cross(av);
|
|
// apply scaled feedback
|
|
gv -= errorFeedback;
|
|
}
|
|
gv.Scale(0.5f * deltaTime);
|
|
m_imuQ += (m_imuQ * Quaternionf(0.0f, gv.x, gv.y, gv.z));
|
|
m_imuQ.NormalizeXYZW();
|
|
updateOrientationAngles();
|
|
}
|
|
|
|
float getRollRadians()
|
|
{
|
|
return m_roll + (float)m_rollWinding * 2.0f * 3.14159265f;
|
|
}
|
|
|
|
float getPitchRadians()
|
|
{
|
|
return m_pitch + (float)m_pitchWinding * 2.0f * 3.14159265f;
|
|
}
|
|
|
|
float getYawRadians()
|
|
{
|
|
return m_yaw + (float)m_yawWinding * 2.0f * 3.14159265f;
|
|
}
|
|
|
|
void getQuaternion(float q[4]) const
|
|
{
|
|
q[0] = m_imuQ.w;
|
|
q[1] = m_imuQ.x;
|
|
q[2] = m_imuQ.y;
|
|
q[3] = m_imuQ.z;
|
|
}
|
|
|
|
void getGyroBias(float gBias[3]) const
|
|
{
|
|
gBias[0] = m_gyroBias[0];
|
|
gBias[1] = m_gyroBias[1];
|
|
gBias[2] = m_gyroBias[2];
|
|
}
|
|
|
|
private:
|
|
|
|
// calculate roll, yaw and pitch in radians. (-0.5 to 0.5)
|
|
void calcOrientation()
|
|
{
|
|
float sinr_cosp = 2.0f * (m_imuQ.z * m_imuQ.w + m_imuQ.x * m_imuQ.y);
|
|
float cosr_cosp = 1.0f - 2.0f * (m_imuQ.w * m_imuQ.w + m_imuQ.x * m_imuQ.x);
|
|
m_roll = std::atan2(sinr_cosp, cosr_cosp);
|
|
|
|
// pitch (y-axis rotation)
|
|
float sinp = 2.0f * (m_imuQ.z * m_imuQ.x - m_imuQ.y * m_imuQ.w);
|
|
if (std::abs(sinp) >= 1.0)
|
|
m_pitch = std::copysign(3.14159265359f / 2.0f, sinp);
|
|
else
|
|
m_pitch = std::asin(sinp);
|
|
|
|
// yaw (z-axis rotation)
|
|
float siny_cosp = 2.0f * (m_imuQ.z * m_imuQ.y + m_imuQ.w * m_imuQ.x);
|
|
float cosy_cosp = 1.0f - 2.0f * (m_imuQ.x * m_imuQ.x + m_imuQ.y * m_imuQ.y);
|
|
m_yaw = std::atan2(siny_cosp, cosy_cosp);
|
|
}
|
|
|
|
void updateOrientationAngles()
|
|
{
|
|
auto calcWindingCountChange = [](float prevAngle, float newAngle) -> int
|
|
{
|
|
if (newAngle > prevAngle)
|
|
{
|
|
float angleDif = newAngle - prevAngle;
|
|
if (angleDif > 3.14159265f)
|
|
return -1;
|
|
}
|
|
else if (newAngle < prevAngle)
|
|
{
|
|
float angleDif = prevAngle - newAngle;
|
|
if (angleDif > 3.14159265f)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
};
|
|
float prevRoll = m_roll;
|
|
float prevPitch = m_pitch;
|
|
float prevYaw = m_yaw;
|
|
calcOrientation();
|
|
// calculate roll, yaw and pitch including winding count to match what VPAD API returns
|
|
m_rollWinding += calcWindingCountChange(prevRoll, m_roll);
|
|
m_pitchWinding += calcWindingCountChange(prevPitch, m_pitch);
|
|
m_yawWinding += calcWindingCountChange(prevYaw, m_yaw);
|
|
}
|
|
|
|
void updateGyroBias(float gx, float gy, float gz)
|
|
{
|
|
// dont let actual movement influence the bias
|
|
// but be careful about setting this too low, there are controllers out there with really bad bias (my Switch Pro had -0.0933 0.0619 0.0179 in resting state)
|
|
if (fabs(gx) >= 0.35f || fabs(gy) >= 0.35f || fabs(gz) >= 0.35f)
|
|
return;
|
|
|
|
m_gyroTotalSum[0] += gx;
|
|
m_gyroTotalSum[1] += gy;
|
|
m_gyroTotalSum[2] += gz;
|
|
m_gyroTotalSampleCount++;
|
|
if (m_gyroTotalSampleCount >= 200)
|
|
{
|
|
m_gyroBias[0] = (float)(m_gyroTotalSum[0] / (double)m_gyroTotalSampleCount);
|
|
m_gyroBias[1] = (float)(m_gyroTotalSum[1] / (double)m_gyroTotalSampleCount);
|
|
m_gyroBias[2] = (float)(m_gyroTotalSum[2] / (double)m_gyroTotalSampleCount);
|
|
}
|
|
}
|
|
|
|
private:
|
|
Quaternionf m_imuQ; // current orientation
|
|
// angle data
|
|
float m_roll{};
|
|
float m_pitch{};
|
|
float m_yaw{};
|
|
int m_rollWinding{};
|
|
int m_pitchWinding{};
|
|
int m_yawWinding{};
|
|
// gyro bias
|
|
float m_gyroBias[3]{};
|
|
double m_gyroTotalSum[3]{};
|
|
uint64 m_gyroTotalSampleCount{};
|
|
};
|