문제

회전의 쿼터니온 표현을 오일러 각도 표현으로 변환하기위한 기존 알고리즘이 있습니까? 오일러 표현의 회전 순서는 알려져 있으며 6 개의 순열 (예 : xyz, xzy, yxz, yzx, zxy, zyx) 중 하나 일 수 있습니다. 고정 회전 순서 (보통 NASA 제목, 은행, 롤 컨벤션)에 대한 알고리즘을 보았지만 임의의 회전 순서는 아닙니다.

또한 단일 방향의 여러 오일러 각도 표현이 있기 때문에이 결과는 모호 할 것입니다. 이것은 방향이 여전히 있기 때문에 허용됩니다 유효한, 그것은 단지 사용자가 기대하는 것이 아닐 수도 있습니다), 그러나 회전 한도 (즉, 자유도 수와 각 자유도의 한계)를 고려한 알고리즘이 있다면 더 나을 것입니다. 그러한 제약을 감안할 때 '가장 현명한'오일러 표현을 산출했습니다.

나는이 문제 (또는 비슷한 것)가 IK 또는 강성 바디 역학 영역에 존재할 수 있다고 생각합니다.


해결 : 나는 그래픽 보석에서 Ken Shoemake의 알고리즘을 따라이 문제를 해결했다는 것이 분명하지 않다는 것을 깨달았습니다. 나는 당시 내 자신의 질문에 대답했지만, 내가 그렇게했다는 것이 확실하지 않을 수도 있습니다. 자세한 내용은 아래의 답변을 참조하십시오.


그냥 명확히하기 위해 - 나는 4 중주에서 소위로 전환하는 방법을 알고 있습니다. '테이트-브라이언'표현 - 내가'NASA '컨벤션이라고 부르는 것. 이것은 ZXY의 회전 순서 ( 'Z'축이 상승한 대회)입니다. 알고리즘이 필요합니다 모두 회전 명령.

그러므로 해결책은 ZXY 주문 변환을 취하고 다른 회전 명령에 대한 5 가지 전환에서 도출하는 것입니다. 나는 더 '가장 중요한'해결책이 있기를 바라고 있다고 생각합니다. 어쨌든, 나는 기존 솔루션을 찾을 수 없다는 것에 놀랐습니다.

또한, 이것은 아마도 별도의 질문이되어야합니다. 하나 오일러 표현이지만 실제로는 많이 있습니다. 예를 들어, YXZ의 회전 순서가 주어지면 두 가지 표현 (0,0,180)과 (180,180,0)은 동일합니다 (동일한 쿼터니온을 산출 할 것입니다). 자유도의 한계를 사용하여 솔루션을 제한하는 방법이 있습니까? 당신이 IK와 Rigid Body Dynamics에서하는 것처럼? 위의 예에서 Z 축에 대해 자유도가 1 만 있으면 두 번째 표현을 무시할 수 있습니다.


나는 알고리즘이 될 수있는 하나의 논문을 추적했다. 이 PDF 그러나 나는 논리와 수학을 따르기가 조금 어렵다고 고백해야합니다. 확실히 다른 솔루션이 있습니까? 임의의 회전 순서가 정말 드문가요? 분명히 골격 애니메이션과 함께 Quaternion 보간 (예 : Maya, Max, Blender 등)과 함께이 문제를 정확히 해결해야합니까?

도움이 되었습니까?

해결책

이것은 오래된 기술이 간과되는 고전적인 사례처럼 보입니다. 나는 차고에서 그래픽 보석 IV 사본을 파고 들었고 Ken Shoemake는 Euler 각도에서 변환하기위한 알고리즘 만있는 것처럼 보입니다. 임의 회전 순서뿐만 아니라 주제에 대한 다른 질문에도 답변합니다. 책을위한 만세. 만약 내가 Shoemake 씨의 대답에 투표 할 수 있다면 명성 포인트로 그를 보상 할 수 있습니다.

Euler Angles로 작업하는 사람은 누구나 해당 지역 라이브러리에서 그래픽 보석 IV 사본을 가져 와서 222 페이지부터 시작해야 할 섹션을 읽어야한다고 생각합니다. 내가 아직 읽은 문제에 대한 가장 명확하고 가장 간결한 설명이어야합니다.


여기에 내가 찾은 유용한 링크가 있습니다. http://www.cgafaq.info/wiki/euler_angles_from_matrix - 이것은 Shoemake와 동일한 시스템을 따릅니다. 회전 순서의 24 가지 순열은 내부 축, 패리티, 반복 및 프레임의 4 가지 매개 변수로 인코딩되어 알고리즘을 24 건에서 2로 줄일 수 있습니다. 일반적으로 유용한 위키가 될 수 있습니다. 전에 그 건너.

제공된 오래된 링크는 깨진 것 같습니다 여기 "회전 매트릭스에서 나온 오일러 각도"의 또 다른 사본입니다.

다른 팁

Z 축이 향상 된 오른 손잡이 직교 좌표 시스템에서 다음을 수행하십시오.

struct Quaternion
{
    double w, x, y, z;
};

void GetEulerAngles(Quaternion q, double& yaw, double& pitch, double& roll)
{
    const double w2 = q.w*q.w;
    const double x2 = q.x*q.x;
    const double y2 = q.y*q.y;
    const double z2 = q.z*q.z;
    const double unitLength = w2 + x2 + y2 + z2;    // Normalised == 1, otherwise correction divisor.
    const double abcd = q.w*q.x + q.y*q.z;
    const double eps = 1e-7;    // TODO: pick from your math lib instead of hardcoding.
    const double pi = 3.14159265358979323846;   // TODO: pick from your math lib instead of hardcoding.
    if (abcd > (0.5-eps)*unitLength)
    {
        yaw = 2 * atan2(q.y, q.w);
        pitch = pi;
        roll = 0;
    }
    else if (abcd < (-0.5+eps)*unitLength)
    {
        yaw = -2 * ::atan2(q.y, q.w);
        pitch = -pi;
        roll = 0;
    }
    else
    {
        const double adbc = q.w*q.z - q.x*q.y;
        const double acbd = q.w*q.y - q.x*q.z;
        yaw = ::atan2(2*adbc, 1 - 2*(z2+x2));
        pitch = ::asin(2*abcd/unitLength);
        roll = ::atan2(2*acbd, 1 - 2*(y2+x2));
    }
}

나는 비슷한 솔루션을 며칠 동안 찾고 있었고 마침내이 웹 사이트를 가로 질러 쿼터니언을 임의의 Euler 및 Tait-Bryan 회전으로 변환하기위한 알고리즘이 있습니다!

다음은 링크입니다. http://bediyap.com/programming/convert-quaternion-to-euler-rotations/

코드는 다음과 같습니다.

///////////////////////////////
// Quaternion to Euler
///////////////////////////////
enum RotSeq{zyx, zyz, zxy, zxz, yxz, yxy, yzx, yzy, xyz, xyx, xzy,xzx};

void twoaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r11, r12 );
  res[1] = acos ( r21 );
  res[2] = atan2( r31, r32 );
}

void threeaxisrot(double r11, double r12, double r21, double r31, double r32, double res[]){
  res[0] = atan2( r31, r32 );
  res[1] = asin ( r21 );
  res[2] = atan2( r11, r12 );
}

void quaternion2Euler(const Quaternion& q, double res[], RotSeq rotSeq)
{
    switch(rotSeq){
    case zyx:
      threeaxisrot( 2*(q.x*q.y + q.w*q.z),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    -2*(q.x*q.z - q.w*q.y),
                     2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                     res);
      break;

    case zyz:
      twoaxisrot( 2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.z + q.w*q.y),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.z - q.w*q.y),
                  res);
      break;

    case zxy:
      threeaxisrot( -2*(q.x*q.y - q.w*q.z),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      2*(q.y*q.z + q.w*q.x),
                     -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                      res);
      break;

    case zxz:
      twoaxisrot( 2*(q.x*q.z + q.w*q.y),
                  -2*(q.y*q.z - q.w*q.x),
                   q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                   2*(q.x*q.z - q.w*q.y),
                   2*(q.y*q.z + q.w*q.x),
                   res);
      break;

    case yxz:
      threeaxisrot( 2*(q.x*q.z + q.w*q.y),
                     q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    -2*(q.y*q.z - q.w*q.x),
                     2*(q.x*q.y + q.w*q.z),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                     res);
      break;

    case yxy:
      twoaxisrot( 2*(q.x*q.y - q.w*q.z),
                   2*(q.y*q.z + q.w*q.x),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.x*q.y + q.w*q.z),
                  -2*(q.y*q.z - q.w*q.x),
                  res);
      break;

    case yzx:
      threeaxisrot( -2*(q.x*q.z - q.w*q.y),
                      q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                      2*(q.x*q.y + q.w*q.z),
                     -2*(q.y*q.z - q.w*q.x),
                      q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                      res);
      break;

    case yzy:
      twoaxisrot( 2*(q.y*q.z + q.w*q.x),
                  -2*(q.x*q.y - q.w*q.z),
                   q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                   2*(q.y*q.z - q.w*q.x),
                   2*(q.x*q.y + q.w*q.z),
                   res);
      break;

    case xyz:
      threeaxisrot( -2*(q.y*q.z - q.w*q.x),
                    q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z,
                    2*(q.x*q.z + q.w*q.y),
                   -2*(q.x*q.y - q.w*q.z),
                    q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                    res);
      break;

    case xyx:
      twoaxisrot( 2*(q.x*q.y + q.w*q.z),
                  -2*(q.x*q.z - q.w*q.y),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.y - q.w*q.z),
                   2*(q.x*q.z + q.w*q.y),
                   res);
      break;

    case xzy:
      threeaxisrot( 2*(q.y*q.z + q.w*q.x),
                     q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z,
                    -2*(q.x*q.y - q.w*q.z),
                     2*(q.x*q.z + q.w*q.y),
                     q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                     res);
      break;

    case xzx:
      twoaxisrot( 2*(q.x*q.z - q.w*q.y),
                   2*(q.x*q.y + q.w*q.z),
                   q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z,
                   2*(q.x*q.z + q.w*q.y),
                  -2*(q.x*q.y - q.w*q.z),
                  res);
      break;
    default:
      std::cout << "Unknown rotation sequence" << std::endl;
      break;
   }
}

내 웹 사이트 Noelhughes.net에 "기하학적 방법을 사용하여 임의의 회전 시퀀스에 대한 Quaternion to Euler Angle 변환"이라는 제목의 논문을 게시했습니다. 또한 이번 주말에 게시 할 방향 코사인 매트릭스로 오일러 각도 세트를 쿼터니온 및 쿼터니언으로 변환하기위한 알고리즘이 있습니다. 이것들은 또한 Martin Bakers 웹 사이트에 있지만 찾기가 어렵습니다. Google 내 이름, Noel Hughes 및 Quaternions를 찾아야합니다.

이런 식으로 해결합니다.

1 단계: 예를 들어 원하는 날러 회전에 대한 규칙을 확인하십시오. Zyx.

2 단계: 회전에 대한 분석 회전 행렬을 계산합니다. 예를 들어, R (Zyx),

** r *** zyx*= ** r *** x*( )*** r *** y*( 세타 )*** r *** z*( psi ), 요소가되는 곳

R11 =  cos(theta)*cos(psi)
R12 = -cos(theta)*sin(psi)
R13 =  sin(theta)
R21 =  sin(psi)*cos(phi) + sin(theta)*cos(psi)*sin(phi)
R22 =  cos(psi)*cos(phi) - sin(theta)*sin(psi)*sin(phi)
R23 = -cos(theta)*sin(phi)
R31 =  sin(psi)*sin(phi) - sin(theta)*cos(psi)*cos(phi)
R32 =  cos(psi)sin(phi) + sin(theta)*sin(psi)*cos(phi)
R33 =  cos(theta)*cos(phi) 

3 단계: 검사를 통해 위의 요소를 사용하여 세 각도에 대한 죄 또는 황갈색을 찾을 수 있습니다. 이 예에서

tan(phi) = -R23/R33

sin(theta) = -R13

tan(psi) = -R12/R11

4 단계: Quaternion에서 회전 매트릭스 계산 (참조 위키 백과), 요소의 경우 위의 3)에서와 같이 각도를 계산해야합니다.

다른 규칙은 동일한 절차를 사용하여 계산할 수 있습니다.

다음은 쿼터니언을 오일러 각도로 전환하는 데 쓴 논문입니다.

링크 1

또한이 위치에 쿼터니언, 오일러 각도 및 회전 매트릭스 (DCM)의 다양한 측면을 논의하는 여러 문서를 넣었습니다.

링크 2

인터넷 검글링 중에이 페이지에 걸려 넘어지는 사람들의 경우, 최근 12 개의 고유 테이프-브라이안 (1-2-3, 3-2-1 등)과 적절한 오일러 (1-2-1, 3-1-3 등) 다음 두 참조의 회전 시퀀스 :

감사합니다 Frodo2975 두 번째 링크의 경우.

위키 백과 Quaternion의 일부를 사용하고 오일러 각도를 계산할 수있는 방법을 보여줍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top