2017-01-08 27 views
0

У меня есть датчики единиц измерения инерции, которые могут выводить данные в виде кватернионов или углов Эйлера. Как биомеханист, углы Эйлера имеют больше смысла для меня, но я тоже разбираюсь в кватернионах, но я их никогда не изучал. У меня есть математический фон, поэтому я не полностью потерялся, и я понимаю эффект блокировки Gimbal в углах Эйлера.Угол между двумя углами Эйлера или кватернионами, блокировка карданов

Я ищу рассчитать углы между двумя векторами независимо от того, являются ли они кватернионами или углами Эйлера, в частности, для человека. Я в основном хочу найти ось вращения и вычислить разницу в углах в трех основных компонентах (x, y, z), и кажется невероятно маловероятным, что человек сможет сузить свое тело и достичь Гимнального замка ,

Я прочитал this paper и, похоже, как вы решили подойти к вращению (x->y->z получает вас к той же точке, что и x->z->y, но разные пути в плане углов, принятых), где Gimbal замок входит в игру, но предлагаемая последовательность XZ'Y '', кажется, вообще избегает Gimbal-lock.

Я читал, что кватернионы просто проще вычислять компьютеры, где я хотел бы использовать кватернионы, так как я использую Pi, но я просто не совсем понимаю, как перейти от кватернионов к вашему базовые компоненты x, y, z. Поэтому я думаю, мои вопросы:

  1. Являются ли кватернионы необходимыми для человеческого движения?
  2. Будет ли поддерживать номера в кватернионах до тех пор, пока окончательные расчеты угла и не перейдут на угол Эйлера на последнем шаге, избегая блокировки карданов?

ответ

0

В принципе, у вас есть 2 основных варианта работы, например. с каркасом.

  • Использование 4x4 матрица (которая позволяет вращение и перевод)
  • использования (блок) кватернионов для вращения и смещения для перевода.

Если вы посмотрите на типичную реализацию функции, взяв 2 вектора и вернув кватернион, давая вращение между ними, вы увидите, что это не просто простая формула. Пограничные случаи идентифицируются и позаботятся.

let rotFromVectors (v1 : vec3) (v2 : vec3) : quat = 
    let PI = System.Math.PI 
    let PI_BY_TWO = PI/2.0 
    let TWO_PI = 2.0 * PI 
    let ZERO_ROTATION = quat(0.0f,0.0f,0.0f,1.0f) 
    let aabb = sqrt (float (vec3.dot(v1, v1)) * float (vec3.dot(v2,v2))) 
    if aabb <> 0.0 
    then 
     let ab = float (vec3.dot(v1,v2))/aabb 
     let c = 
      vec3 
       (float32 ((float v1.y * float v2.z - float v1.z * float v2.y)/aabb) 
       , float32 ((float v1.z * float v2.x - float v1.x * float v2.z)/aabb) 
       , float32 ((float v1.x * float v2.y - float v1.y * float v2.x)/aabb) 
       ) 
     let cc = float (vec3.dot(c, c)) 
     if cc <> 0.0 
     then 
      let s = 
       match ab > -sin (PI_BY_TWO) with //0.707107f 
       | true -> 1.0 + ab 
       | false -> cc/(1.0 + sqrt (1.0-cc)) 
      let m = sqrt (cc + s * s) 
      quat(float32 (float c.x/m), float32 (float c.y/m), float32 (float c.z/m), float32(s/m)) 
     else 
      if ab > 0.0 
      then 
       ZERO_ROTATION 
      else 
       let m = sqrt (v1.x * v1.x + v1.y * v1.y) 
       if(m <> 0.0f) 
       then 
        quat(v1.y/m, (-v1.x)/m, 0.0f, 0.0f) 
       else 
        quat(1.0f,0.0f,0.0f,0.0f) 
    else 
     ZERO_ROTATION 

Где quat типа для кватерниона и vec3 типа 3D-вектора в приведенной выше коде.

код для поворота вектора на кватернион примерно столь же просто, как математика говорит:

let rotateVector (alpha : quat) (v:vec3) : vec3 = 
    let s = vec3.length v 
    quat.inverse alpha * (vecToPureQuat v) * alpha |> pureQuatToVec |> fun v' -> v' * s 

И что не менее важно функции преобразования между (некоторые ... углы Эйлера - есть на самом деле 24 различные версии углов Эйлера, 12 с фиксированными углами вращения и 12 с последовательными вращениями) использует подход с половинным углом.

let eulerToRot (v:vec3) : quat = 
    let d = 0.5F 
    let t0 = cos (v.z * d) 
    let t1 = sin (v.z * d) 
    let t2 = cos (v.y * d) 
    let t3 = sin (v.y * d) 
    let t4 = cos (v.x * d) 
    let t5 = sin (v.x * d) 
    quat 
     ( t0 * t3 * t4 - t1 * t2 * t5 
     , t0 * t2 * t5 + t1 * t3 * t4 
     , t1 * t2 * t4 - t0 * t3 * t5 
     , t0 * t2 * t4 + t1 * t3 * t5 
     ) 
    |> quat.normalize 

let rotToEuler (q:quat) : vec3 = 
    let ysqr = q.y * q.y 
    // roll (x-axis rotation) 
    let t0 = +2.0f * (q.w * q.x + q.y * q.z) 
    let t1 = +1.0f - 2.0f * (q.x * q.x + ysqr) 
    let roll = atan2 t0 t1 

    // pitch (y-axis rotation) 
    let t2 = 
     let t2' = +2.0f * (q.w * q.y - q.z * q.x) 
     match t2' with 
     | _ when t2' > 1.0f -> 1.0f 
     | _ when t2' < -1.0f -> -1.0f 
     | _ -> t2' 
    let pitch = asin t2 

    // yaw (z-axis rotation) 
    let t3 = +2.0f * (q.w * q.z + q.x *q.y) 
    let t4 = +1.0f - 2.0f * (ysqr + q.z * q.z) 
    let yaw = atan2 t3 t4 
    vec3(roll,pitch,yaw) 

Финальный трюк, чтобы знать, в том, что превратить вектор в (чистом) кватернион пригождается для функции rotateVector.

let vecToPureQuat (v:vec3) : quat = 
    quat(v.x,v.y,v.z,0.0f) 

let pureQuatToVec (q:quat) : vec3 = 
    vec3(q.x,q.y,q.z) 

Итак, чтобы ответить на ваш главный вопрос: нужны ли кватернионы? Нет. Вы также можете использовать матрицы 4х4.

И вы можете перейти от одного к другому, если он сочтет вас полезным:

let offsetAndRotToMat (offset:vec3) (q:quat) : mat4 = 
     let ux = v3 1 0 0 
     let uy = v3 0 1 0 
     let uz = v3 0 0 1 
     let rx = rotateVector q ux 
     let ry = rotateVector q uy 
     let rz = rotateVector q uz 
     mat4 
      (
       rx.x, rx.y, rx.z, 0.0f, 
       ry.x, ry.y, ry.z, 0.0f, 
       rz.x, rz.y, rz.z, 0.0f, 
       offset.x,offset.y,offset.z,1.0f 
      ) 
+0

Спасибо! Я сделал еще несколько исследований, и я думаю, что постоянная ценность кватернионов просто отбросила меня. Я пытался понять, как различие кватернионов приведет к углам, но теперь я понимаю, что вычисление кватерниона вращения от одного кватерниона к другому кватерниону может быть просто преобразовано в его 3D-углы, чтобы найти разницу в углах. Я читал в углах поворота Эйлера, и я понятия не имел, что порядок, который вы делали, имеет значение. На самом деле я обнаружил, что одно конкретное вращение было минимальным сингулярным случаем. – Andrew