IMU센서에서 출력되는 쿼터니언 값을 Euler_Angle, 즉, 우리가 흔히 접하는 각도로 나타내기 위한
여러가지 방법이 있지만, 저는
Unity에서 작업한 코드 → 다른언어로 변환
할 수 있도록 1차적으로 C# 코드로 구현하려고 했습니다.(구글링으로도 찾기 힘들더라구요...)
1. Unity의 Quaternion 구조체 → Class로 작성
Quaternion a_quat = new Quaternion(x, y, z, w); // Unity
clsQuat b_quat = new clsQuat(w, x, y, z);
clsQuat 는 4개의 float값을 저장하는 간단한 클래스입니다.
★ x, y, z, w 순서 주의해 주세요!
2. 쿼터니언 → 라디안 → Degree
protected static clsPoint Q2E(clsQuat qt)
{
clsPoint euler = new clsPoint(0, 0, 0);
float unit = (qt.qx * qt.qx) + (qt.qy * qt.qy) + (qt.qz * qt.qz) + (qt.qw * qt.qw);
// this will have a magnitude of 0.5 or greater if and only if this is a singularity case
float test = qt.qx * qt.qw - qt.qy * qt.qz;
if (test > 0.4995f * unit) // singularity at north pole
{
euler.x = (float)(Math.PI / 2);
euler.y = (float)(2f * Math.Atan2(qt.qy, qt.qx));
euler.z = 0;
}
else if (test < -0.4995f * unit) // singularity at south pole
{
euler.x = (float)(-Math.PI / 2);
euler.y = (float)(-2f * Math.Atan2(qt.qy, qt.qx));
euler.z = 0;
}
else // no singularity - this is the majority of cases
{
euler.x = (float)(Math.Asin(2f * (qt.qw * qt.qx - qt.qy * qt.qz)));
euler.y = (float)(Math.Atan2(2f * qt.qw * qt.qy + 2f * qt.qz * qt.qx, 1 - 2f * (qt.qx * qt.qx + qt.qy * qt.qy)));
euler.z = (float)(Math.Atan2(2f * qt.qw * qt.qz + 2f * qt.qx * qt.qy, 1 - 2f * (qt.qz * qt.qz + qt.qx * qt.qx)));
}
// all the math so far has been done in radians. Before returning, we convert to degrees...
euler.x *= 57.29578f;
euler.y *= 57.29578f;
euler.z *= 57.29578f;
//...and then ensure the degree values are between 0 and 360
euler.x %= 360;
euler.y %= 360;
euler.z %= 360;
return Internal_MakePositive(euler);
}
clsPoint는 clsQuat와 마찬가지로 3개의 float값을 저장하는 class이고,
return 부분의 Internal_MakePositive() 메서드는 계산된 degree를 나름 보기 좋게 만드는 역할을 합니다.
3. 출력된 값 보기 좋게 변환하기 → Internal_MakePositive()
private static clsPoint Internal_MakePositive(clsPoint euler)
{
float negativeFlip = -0.0001f * Mathf.Rad2Deg;
float positiveFlip = 360.0f + negativeFlip;
if (euler.x < negativeFlip)
euler.x += 360.0f;
else if (euler.x > positiveFlip)
euler.x -= 360.0f;
if (euler.y < negativeFlip)
euler.y += 360.0f;
else if (euler.y > positiveFlip)
euler.y -= 360.0f;
if (euler.z < negativeFlip)
euler.z += 360.0f;
else if (euler.z > positiveFlip)
euler.z -= 360.0f;
return euler;
}
* clsPoint, clsQuat는 단지 값을 저장하는 용도이며,
Unity의 Vector3 → clsPoint
Quaternion → clsQuat
으로 대체했다고 보시면 됩니다.
double이 아닌 float로 작성한 이유는 IMU센서에서 출력되는 값이 float이기 때문입니다.
다른언어로 변환하는데 전혀 어려움이 없을거 같네요:)
p.s. IMU 센서 버리고싶...
Ref :
https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Quaternion.cs
'C# & Unity' 카테고리의 다른 글
[C#] 날짜/시간 차이 구하기 - DateTime (0) | 2022.10.31 |
---|