Classical Rodrigues Parameters
The Classical Rodrigues Parameters (CRP) are defined by the following immutable structure:
struct CRP{T}
q1::T
q2::T
q3::T
endThe CRP is a 3-element parameterization of a rotation. In this package, it can be seen as the stereographic parameter obtained from a quaternion by dividing the vector part by the real part. Hence, it is singular for rotations of $180^\circ$.
If a rotation is represented by the Euler angle $\phi$ and the unitary Euler vector $\mathbf{e}$, then the corresponding CRP $\mathbf{c}$ is defined by:
\[\mathbf{c} = \mathbf{e} \tan\left(\frac{\phi}{2}\right)\ .\]
Therefore, if $\phi = \pi$ rad ($180^\circ$), then $\tan(\phi/2)$ is singular and the CRP is not defined.
Initialization
The constructors for this structure are:
CRP(q1::T1, q2::T2, q3::T3) where {T1,T2,T3}
CRP(v::AbstractVector)in which a CRP with components q1, q2, and q3 will be created. Notice that the type of the returned structure will be selected according to the input types.
julia> CRP(0.1, 0.2, 0.3)CRP{Float64}: X : + 0.1 Y : + 0.2 Z : + 0.3julia> CRP([0.1, 0.2, 0.3])CRP{Float64}: X : + 0.1 Y : + 0.2 Z : + 0.3julia> CRP(1, 2, 3.0f0)CRP{Float32}: X : + 1.0 Y : + 2.0 Z : + 3.0
It is also possible to create the identity rotation using I, zero, and one:
julia> CRP(I)CRP{Bool}: X : + false Y : + false Z : + falsejulia> zero(CRP)CRP{Float64}: X : + 0.0 Y : + 0.0 Z : + 0.0julia> one(CRP)CRP{Float64}: X : + 0.0 Y : + 0.0 Z : + 0.0
Individual elements of the CRP can be accessed by:
c.q1
c.q2
c.q3or using linear indexing:
c[1]
c[2]
c[3]Operations
Sum, subtraction, and scalar multiplication
julia> c1 = CRP(0.1, 0.2, 0.3)CRP{Float64}: X : + 0.1 Y : + 0.2 Z : + 0.3julia> c2 = CRP(0.2, -0.1, 0.1)CRP{Float64}: X : + 0.2 Y : - 0.1 Z : + 0.1julia> c1 + c2CRP{Float64}: X : + 0.3 Y : + 0.1 Z : + 0.4julia> c1 - c2CRP{Float64}: X : - 0.1 Y : + 0.3 Z : + 0.2julia> 2c1CRP{Float64}: X : + 0.2 Y : + 0.4 Z : + 0.6julia> c1 / 2CRP{Float64}: X : + 0.05 Y : + 0.1 Z : + 0.15
Multiplication (rotation composition)
The multiplication of two CRPs is defined here as the composition of the rotations. Let $\mathbf{c}_1$ and $\mathbf{c}_2$ be two CRPs (instances of the structure CRP). Thus, the operation:
\[\mathbf{c}_{2,1} = \mathbf{c}_2 \cdot \mathbf{c}_1\]
will return a new CRP $\mathbf{c}_{2,1}$ that represents the composed rotation of $\mathbf{c}_1$ followed by $\mathbf{c}_2$.
The CRP representation is singular at $180^\circ$. Therefore, composing two CRPs can fail if the resulting rotation is exactly at that singularity.
julia> c1 = angle_to_crp(0.1, 0.2, 0.3, :ZYX)CRP{Float64}: X : + 0.146004 Y : + 0.107816 Z : + 0.0348512julia> c2 = angle_to_crp(-0.2, 0.1, -0.1, :XYZ)CRP{Float64}: X : - 0.102865 Y : + 0.0450321 Z : - 0.0550765julia> c2 * c1CRP{Float64}: X : + 0.0352059 Y : + 0.155426 Z : - 0.00252945
Inversion
The inverse rotation is obtained using inv:
julia> c = angle_to_crp(0.2, -0.1, 0.3, :ZYX)CRP{Float64}: X : + 0.156275 Y : - 0.0349041 Z : + 0.10798julia> inv(c)CRP{Float64}: X : - 0.156275 Y : + 0.0349041 Z : - 0.10798
Functions
Useful helper functions include:
julia> c = CRP(0.1, 0.2, 0.3)CRP{Float64}: X : + 0.1 Y : + 0.2 Z : + 0.3julia> norm(c)0.37416573867739417julia> vect(c)3-element StaticArraysCore.SVector{3, Float64} with indices SOneTo(3): 0.1 0.2 0.3julia> copy(c)CRP{Float64}: X : + 0.1 Y : + 0.2 Z : + 0.3julia> shadow_rotation(c)CRP{Float64}: X : + 0.1 Y : + 0.2 Z : + 0.3
The shadow rotation of a CRP is the CRP itself.
Kinematics
The time-derivative of a CRP can be computed using:
function dcrp(c::CRP, wba_b::AbstractVector)julia> c = CRP(0.0, 0.0, 0.0)CRP{Float64}: X : + 0.0 Y : + 0.0 Z : + 0.0julia> wba_b = [0.01, 0.02, -0.03]3-element Vector{Float64}: 0.01 0.02 -0.03julia> dcrp(c, wba_b)CRP{Float64}: X : + 0.005 Y : + 0.01 Z : - 0.015