packages feed

switch-0.1.0.0: test/Cube/Madgwick.hs

module Madgwick where

-- linear
import Linear.Quaternion
import Linear.V3

-- Madgwick's sensor fusion algorithm.
-- See: https://x-io.co.uk/open-source-imu-and-ahrs-algorithms/
madgwick
  :: (Float, Float, Float)
  -> (Float, Float, Float)
  -> Float
  -> Float
  -> Quaternion Float
  -> Quaternion Float
madgwick (ax,ay,az) (gx,gy,gz) beta sampleFreq (Quaternion q0 (V3 q1 q2 q3)) =
  let
    qDot1 = 0.5 * (-q1 * gx - q2 * gy - q3 * gz)
    qDot2 = 0.5 * (q0 * gx + q2 * gz - q3 * gy)
    qDot3 = 0.5 * (q0 * gy - q1 * gz + q3 * gx)
    qDot4 = 0.5 * (q0 * gz + q1 * gy - q2 * gx)

    (newDot1, newDot2, newDot3, newDot4) = help qDot1 qDot2 qDot3 qDot4

    q0t = q0 + newDot1 * (1.0 / sampleFreq)
    q1t = q1 + newDot2 * (1.0 / sampleFreq)
    q2t = q2 + newDot3 * (1.0 / sampleFreq)
    q3t = q3 + newDot4 * (1.0 / sampleFreq)

    recipNorm = 1 / sqrt (q0t * q0t + q1t * q1t + q2t * q2t + q3t * q3t)
  in
    Quaternion (q0t * recipNorm) (V3 (q1t * recipNorm) (q2t * recipNorm) (q3t * recipNorm))
  where
    help qDot1 qDot2 qDot3 qDot4 =
      if(not ((ax == 0) && (ay == 0) && (az == 0))) then
        let recipNorm = 1 / sqrt (ax * ax + ay * ay + az * az)
            fax = ax * recipNorm
            fay = ay * recipNorm
            faz = az * recipNorm;  

            _2q0 = 2.0 * q0
            _2q1 = 2.0 * q1
            _2q2 = 2.0 * q2
            _2q3 = 2.0 * q3
            _4q0 = 4.0 * q0
            _4q1 = 4.0 * q1
            _4q2 = 4.0 * q2
            _8q1 = 8.0 * q1
            _8q2 = 8.0 * q2
            q0q0 = q0 * q0
            q1q1 = q1 * q1
            q2q2 = q2 * q2
            q3q3 = q3 * q3

            s0 = _4q0 * q2q2 + _2q2 * fax + _4q0 * q1q1 - _2q1 * fay
            s1 = _4q1 * q3q3 - _2q3 * fax + 4.0 * q0q0 * q1 - _2q0 * fay - _4q1 + _8q1 * q1q1 + _8q1 * q2q2 + _4q1 * faz
            s2 = 4.0 * q0q0 * q2 + _2q0 * fax + _4q2 * q3q3 - _2q3 * fay - _4q2 + _8q2 * q1q1 + _8q2 * q2q2 + _4q2 * faz
            s3 = 4.0 * q1q1 * q3 - _2q1 * fax + 4.0 * q2q2 * q3 - _2q2 * fay
            recipNorm2 = 1 / sqrt (s0 * s0 + s1 * s1 + s2 * s2 + s3 * s3)
        in (qDot1 - beta * s0 * recipNorm2, qDot2 - beta * s1 * recipNorm2, qDot3 - beta * s2 * recipNorm2, qDot4 - beta * s3 * recipNorm2)
      else
        (qDot1, qDot2, qDot3, qDot4)