README.md

rattitude

rattitude has two main functions: (1) inertial-based three-axis accelerometer calibration and (2) attitude determination.

Installation

# install.packages("devtools")
devtools::install_github("adamwbolton/rattitude")

Example

library(rattitude)

Rotations

Rotations can be specified either as rotation matrices, sequences of Euler angles, or rotation quaternions. One can convert between the three with the following functions: euler_to_rotation, euler_to_quaternion, rotation_to_quaternion, rotation_to_euler, quaternion_to_euler, quaternion_to_rotation. Let’s start with a rotation of 90 degrees about the x-axis and convert this to a rotation matrix:

# toy data
pitch <- 90
roll <- 0
yaw <- 0
R <- euler_to_rotation(pitch, roll,yaw, units = "degrees")
# rotation matrix
R
#>      [,1]         [,2]          [,3]
#> [1,]    1 0.000000e+00  0.000000e+00
#> [2,]    0 6.123234e-17 -1.000000e+00
#> [3,]    0 1.000000e+00  6.123234e-17

converting this back to Euler angles

# convert back to euler angles
rotation_to_euler(R)
#> $pitch
#> [1] 90
#> 
#> $roll
#> [1] 0
#> 
#> $yaw
#> [1] 0

and then to a rotation quaternion

# rotation to quaternion
q <- rotation_to_quaterion(R)
q
#> [1] 0.7071068 0.0000000 0.0000000 0.7071068

and back to Euler angles

quaterion_to_euler(q)
#> $pitch
#> [1] 90
#> 
#> $roll
#> [1] 0
#> 
#> $yaw
#> [1] 0

Calibration

The calibration for the inertial-based three-axis accelerometers is done through the following first-order model:

&#10;v_x = \beta_{0_x} + \beta_{x_x} g_x + \beta_{y_x} g_y
+ \beta_{z_x} g_z +
\epsilon_x&#10;

&#10;v_y = \beta_{0_y} + \beta_{y_x} g_x + \beta_{y_y} g_y
+ \beta_{y_y} g_z +
\epsilon_y&#10;

&#10;v_z = \beta_{0_z} + \beta_{z_x} g_x + \beta_{z_y} g_y
+ \beta_{z_z} g_z +
\epsilon_z&#10;

where \epsilon = (\epsilon_x,\epsilon_y, \epsilon_z)^T \sim
N(0,\sigma^2
I_3). For the x-axis accelerometer, \beta_{0_x} is the bias, \beta_{1_x} is the sensitivity, \beta_{1_y} is the coefficient for the cross-axis sensitivity of g_y, \beta_{1_z} is the coefficient for the cross-axis sensitivity of g_z. The sensitivity matrix, \mathbf{\beta}, and the bias vector, \mathbf{\beta_0}, are given by

&#10;\mathbf{\beta} = \left(\begin{array}{rrr}&#10;\beta_{x_x}
& \beta_{x_y} & \beta_{x_z} \\&#10;\beta_{y_x} &
\beta_{y_y} & \beta_{y_z} \\&#10;\beta_{z_x} & \beta_{z_y}
& \beta_{z_z} \\&#10;\end{array}\right), \quad
\mathbf{\beta_0} = \left(\begin{array}{r} \beta_{0_x} \\
\beta_{0_y}\\ \beta_{1_z}
\end{array}\right)&#10;

Calibration is done through the calibration function which takes matrices \mathbf{V} and \mathbf{G} are arguments and returns the estimates of the sensitivity and bias terms of the model above. Each row of \mathbf{G} should have unit norm.

&#10;\mathbf{V} = \left(\begin{array}{rrr}&#10;v_{1x} & v_{1y} &
v_{1z} \\ &#10;\vdots & \vdots & \vdots \\ &#10;v_{nx} &
v_{ny} & v_{nz} &#10;\end{array}\right), \quad \mathbf{G} =
\left(\begin{array}{rrr}&#10;g_{1x} & g_{1y} & g_{1z} \\
&#10;\vdots & \vdots & \vdots \\ &#10;g_{nx} & g_{ny} &
g_{nz}&#10;\end{array}\right)&#10;

# create sensitivity matrix and bias vector
Beta0 <- c(0,0,0)
Beta <- diag(3) + matrix(rnorm(9,sd = 1e-4),nrow = 3)

# number of observations
n <- 10
# create matrix of gravity vectors
G <- matrix(rnorm(3*n), nrow =n)
G <- t(apply(G,1,FUN = function(x) x/norm(x,"2")))

# simulate responses based on calibration model with some noise
V <- G %*% Beta + Beta0 + matrix(rnorm(3*n, sd = 1e-2), nrow =n)

To fit the calibration model….

cal <- calibration(V,G)

Estimates of the sensitivity and bias terms in the model

cal$coef
#> $BetaHat
#>             [,1]         [,2]        [,3]
#> [1,] 0.999601350 -0.016203819 0.002389500
#> [2,] 0.002422397  0.991612219 0.004893546
#> [3,] 0.005512963  0.007760368 1.002375200
#> 
#> $Beta
#>               [,1]          [,2]         [,3]
#> [1,]  1.000076e+00  8.059277e-05 1.135893e-04
#> [2,]  5.456315e-05  9.997552e-01 4.076539e-06
#> [3,] -1.038208e-04 -6.119115e-06 9.999143e-01

Estimates of the gravity vectors given by \hat{g}_i = (v_i -
\mathbf{\beta}_0)^T
\mathbf{\beta}^{-1}

cal$Ghat
#>               [,1]        [,2]        [,3]
#>  [1,] -0.708042358  0.59581656  0.38242550
#>  [2,] -0.115753373  0.96577065  0.18156004
#>  [3,]  0.049395167 -1.02113780 -0.01229979
#>  [4,]  0.122635690  0.05509749 -0.98369083
#>  [5,] -0.003190392  0.70095190  0.71947303
#>  [6,] -0.859939419  0.30872718  0.44181834
#>  [7,] -0.256087371 -0.94040855  0.18621783
#>  [8,] -0.927600534 -0.15038225 -0.28208025
#>  [9,]  0.130101505 -0.64665419  0.74144121
#> [10,]  0.971819066  0.27117651  0.07182864

Estimate of \sigma from calibration model

cal$sd
#> [1] 0.01080902

Attitude Estimation

Wahba’s problem seeks to minimize the cost-function

&#10;L(R) = \frac{1}{n} \sum_{i=1}^n \| w_i - \mathbf{R} v_i
\|^2, \quad n
\ge 2&#10; where \mathbf{w}_{i} is the u-th 3-vector measurement in the reference frame, \mathbf{v}_i is the corresponding i-th 3-vector measurement in the body frame \mathbf{R} is a 3
\times 3 rotation matrix between the reference frame and body frame. The optimal rotation, \mathbf{R}_{opt} can be found using Davenport’s q-method:

Define the corresponding gain function:

\begin{align}
G(R) & = 1- L(R) \\ & = \sum_{i=1}^n tr(\mathbf{w}_i^T \mathbf{R} \mathbf{v}_i) \\ & = 
tr(\mathbf{W}^T \mathbf{R} \mathbf{V}) \\ & = 
tr(\mathbf{R} \mathbf{B}^T)
\end{align}

where \mathbf{B} = \sum_{i=1}^n \mathbf{W}
\mathbf{V}^T

Parameterizing the rotation matrix in terms of quaternion, \mathbf{q}
= (\mathbf{q}_v,
q_r) we have

&#10;\mathbf{R}(q) = (q_r - \| \mathbf{q}_v \|^2) \mathbf{I}_3
+ 2 \mathbf{q}_v \mathbf{q}_v^T - 2 q_r
[\mathbf{q}_v]_x&#10;

where [\mathbf{q}_v]_x is the skew-symmetric matrix of vector {q}_v. The gain function then becomes

&#10;g(\mathbf{q}) = (q_r - \| \mathbf{q}_v \|^2)
tr(\mathbf{B}^T) + 2 tr (\mathbf{q}_v \mathbf{q}_v^T \mathbf{B}^T)
+ 2 q_r tr( [\mathbf{q}_v]_x
\mathbf{B}^T)&#10; Putting this expression in terms of its bilinear form, we have

&#10;g(\mathbf{q}) = \mathbf{q}^T \mathbf{K}
\mathbf{q}&#10;

where

&#10;\mathbf{K}_{4 \times 4} =
\left[&#10;\begin{array}{rr}&#10;\sigma & \mathbf{z}^T
\\&#10;\mathbf{z} & \mathbf{S} - \sigma
\mathbf{I}_3&#10;\end{array}&#10;\right]&#10;

where &#10;\sigma = tr(\mathbf{B}), \quad \mathbf{S} = \mathbf{B} +
\mathbf{B}^T, \quad \mathbf{z} =
\left(&#10;\begin{array}{r}&#10;B_{23} -B{32} \\ &#10;B_{31}
-B{13} \\ &#10;B_{12} -B{21} \\
&#10;\end{array}&#10;\right)&#10;

The optimal quaternion which maximimizes the gain function is the eigenvector associated with the largest eigenvalue, \lambda_{max}, of matrix \mathbf{K}

&#10;\mathbf{K} \mathbf{q}_{opt} = \lambda_{max}
\mathbf{q}_{opt}&#10;

# create some vector in the reference frame
n <- 3
sd <- 1e-3
W <- matrix(rnorm(3 * n, sd = ),ncol = 3)
W <- t(apply(W,2,FUN = function(x) {x/norm(x, "2")^2}))
W
#>            [,1]        [,2]        [,3]
#> [1,] -0.3876940 -0.08612243 -0.42998760
#> [2,] -0.2685413  0.47500568  0.03848487
#> [3,] -0.2655570  0.69677187 -0.32195384
# create some rotation matrix and
pitch <- 90
roll <- 0
yaw <- 0
R <- euler_to_rotation(pitch, roll,yaw, units = "degrees")
# rotation matrix
R
#>      [,1]         [,2]          [,3]
#> [1,]    1 0.000000e+00  0.000000e+00
#> [2,]    0 6.123234e-17 -1.000000e+00
#> [3,]    0 1.000000e+00  6.123234e-17
# create vector in body frame and add noise
sd <- 1e-2

V <- t(apply(W,1,function(x) {R %*% x})) + matrix(rnorm(3*n, mean = 0 ,sd = sd),nrow = n)
V
#>            [,1]        [,2]        [,3]
#> [1,] -0.3791908  0.43733015 -0.07604239
#> [2,] -0.2631449 -0.03920862  0.48399961
#> [3,] -0.2604135  0.31035092  0.68793813

The optimal rotation is found by find_rotation

out <- find_rotation(W,V, output = "euler", sd = NA)
out$rotation
#> $pitch
#> [1] 89.26877
#> 
#> $roll
#> [1] 179.7568
#> 
#> $yaw
#> [1] 179.2509

If standard deviation estimate is given, an estimate of the covariance matrix for the rotation will be returned.

out <- find_rotation(W,V, output = "euler", sd = sd)
out$rotation
#> $pitch
#> [1] 89.26877
#> 
#> $roll
#> [1] 179.7568
#> 
#> $yaw
#> [1] 179.2509
out$cov
#>            pitch       roll        yaw
#> pitch 0.01583568 0.01204993 0.02902866
#> roll  0.01204993 0.01242081 0.02620081
#> yaw   0.02902866 0.02620081 0.05957948


adamwbolton/rattitude documentation built on May 6, 2022, 6:33 p.m.