Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@
[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl)
[![DOI](https://zenodo.org/badge/53457088.svg)](https://zenodo.org/badge/latestdoi/53457088)

This package implements various 3D rotation parameterizations and defines
conversions between them. At their heart, each rotation parameterization *is*
This package implements various 3D rotation parametrizations and defines
conversions between them. At their heart, each rotation parametrization *is*
a 3×3 unitary (orthogonal) matrix (based on the [StaticArrays.jl package](https://github.com/JuliaArrays/StaticArrays.jl)),
and acts to rotate a 3-vector about the origin through matrix-vector multiplication.

While the `RotMatrix` type is a dense representation of a `3×3` matrix, we also
have sparse (or computed, rather) representations such as quaternions,
angle-axis parameterizations, and Euler angles.
angle-axis parametrizations, and Euler angles.

For composing rotations about the origin with other transformations, see
the [CoordinateTransformations.jl](https://github.com/JuliaGeometry/CoordinateTransformations.jl)
package.

### Interface
The following operations are supported by all of the implemented rotation parameterizations.
The following operations are supported by all of the implemented rotation parametrizations.

#### Composition
Any two rotations of the same type can be composed with simple multiplication:
Expand All @@ -49,22 +49,22 @@ r = q\r2
```

#### Rotation Angle / Axis
The rotation angle and axis can be obtained for any rotation parameterization using
The rotation angle and axis can be obtained for any rotation parametrization using
```julia
rotation_axis(r::Rotation)
rotation_angle(r::Rotation)
```

#### Initialization
All rotation types support `one(R)` to construct the identity rotation for the desired parameterization. A random rotation, uniformly sampled over the space of rotations, can be sampled using `rand(R)`. For example:
All rotation types support `one(R)` to construct the identity rotation for the desired parametrization. A random rotation, uniformly sampled over the space of rotations, can be sampled using `rand(R)`. For example:
```julia
r = one(QuatRotation) # equivalent to QuatRotation(1.0, 0.0, 0.0, 0.0)
q = rand(QuatRotation)
p = rand(MRP{Float32})
```

#### Conversion
All rotatations can be converted to another parameterization by simply calling the constructor for the desired parameterization. For example:
All rotations can be converted to another parametrization by simply calling the constructor for the desired parametrization. For example:
```julia
q = rand(QuatRotation)
aa = AngleAxis(q)
Expand Down Expand Up @@ -103,7 +103,7 @@ q5 = q3 \ q2 # q5 = inv(q3) * q2
# convert to a Modified Rodrigues Parameter (aka Stereographic quaternion projection, recommended for applications with differentiation)
spq = MRP(r)

# convert to the Angle-axis parameterization, or related Rotation vector
# convert to the Angle-axis parametrization, or related Rotation vector
aa = AngleAxis(r)
rv = RotationVec(r)
ϕ = rotation_angle(r)
Expand All @@ -116,7 +116,7 @@ r_xyz = RotXYZ(r)
# Rotation about the X axis by 0.1 radians
r_x = RotX(0.1)

# Composing axis rotations together automatically results in Euler parameterization
# Composing axis rotations together automatically results in Euler parametrization
RotX(0.1) * RotY(0.2) * RotZ(0.3) === RotXYZ(0.1, 0.2, 0.3)

# Can calculate Jacobian - derivatives of rotations with respect to parameters
Expand All @@ -126,7 +126,7 @@ j2 = Rotations.jacobian(q, p) # How does the rotated point q*p change w.r.t. the
# (MRP is ideal for optimization purposes - no constaints/singularities)
```

### Rotation Parameterizations
### Rotation Parametrizations

1. **Rotation Matrix** `RotMatrix{N, T}`

Expand All @@ -149,7 +149,7 @@ j2 = Rotations.jacobian(q, p) # How does the rotated point q*p change w.r.t. the

3. **Quaternions** `QuatRotation{T}`

A 3D rotation parameterized by a unit quaternion. Note that the constructor
A 3D rotation parametrized by a unit quaternion. Note that the constructor
will renormalize the quaternion to be a unit quaternion, and that although
they follow the same multiplicative *algebra* as quaternions, it is better
to think of `QuatRotation` as a 3×3 matrix rather than as a quaternion *number*.
Expand All @@ -163,7 +163,7 @@ j2 = Rotations.jacobian(q, p) # How does the rotated point q*p change w.r.t. the

Note: If you're differentiating a Rodrigues Vector check the result is what
you expect at theta = 0. The first derivative of the rotation *should*
behave, but higher-order derivatives of it (as well as parameterization
behave, but higher-order derivatives of it (as well as parametrization
conversions) should be tested. The Stereographic Quaternion Projection (`MRP`) is
the recommended three parameter format for differentiation.

Expand Down Expand Up @@ -194,14 +194,14 @@ j2 = Rotations.jacobian(q, p) # How does the rotated point q*p change w.r.t. the
10. **Euler Angles - Three-axis rotations** `RotXYZ{T}`, `RotXYX{T}`, etc

A composition of 3 cardinal axis rotations is typically known as a Euler
angle parameterization of a 3D rotation. The rotations with 3 unique axes,
angle parametrization of a 3D rotation. The rotations with 3 unique axes,
such as `RotXYZ`, are said to follow the [**Tait Bryan**](https://en.wikipedia.org/wiki/Euler_angles#Tait.E2.80.93Bryan_angles) angle ordering,
while those which repeat (e.g. `EulerXYX`) are said to use [**Proper Euler**](https://en.wikipedia.org/wiki/Euler_angles#Conventions) angle ordering.

Like the two-angle versions, the order of application to a vector is right-to-left, so that `RotXYZ(x, y, z) * v == RotX(x) * (RotY(y) * (RotZ(z) * v))`. This may be interpreted as an "extrinsic" rotation about the Z, Y, and X axes or as an "intrinsic" rotation about the X, Y, and Z axes. Similarly, `RotZYX(z, y, x)` may be interpreted as an "extrinsic" rotation about the X, Y, and Z axes or an "intrinsic" rotation about the Z, Y, and X axes.

### The Rotation Error state and Linearization
It is often convenient to consider perturbations or errors about a particular 3D rotation, such as applications in state estimation or optimization-based control. Intuitively, we expect these errors to live in three-dimensional space. For globally non-singular parameterizations such as unit quaternions, we need a way to map between the four parameters of the quaternion to this three-dimensional plane tangent to the four-dimensional hypersphere on which quaternions live.
It is often convenient to consider perturbations or errors about a particular 3D rotation, such as applications in state estimation or optimization-based control. Intuitively, we expect these errors to live in three-dimensional space. For globally non-singular parametrizations such as unit quaternions, we need a way to map between the four parameters of the quaternion to this three-dimensional plane tangent to the four-dimensional hypersphere on which quaternions live.

There are several of these maps provided by Rotations.jl:
* `ExponentialMap`: A very common mapping that uses the quaternion
Expand All @@ -210,7 +210,7 @@ converts a 3D rotation vector (i.e. axis-angle vector) to a unit quaternion.
It tends to be the most computationally expensive mapping.

* `CayleyMap`: Represents the differential quaternion using Rodrigues
parameters. This parameterization goes singular at 180° but does not
parameters. This parametrization goes singular at 180° but does not
inherit the sign ambiguities of the unit quaternion. It offers an
excellent combination of cheap computation and good behavior.

Expand All @@ -221,7 +221,7 @@ differential unit quaternion. This mapping goes singular at 360°.
differential unit quaternion. This mapping also goes singular at 180° but is
the computationally cheapest map and often performs well.

Rotations.jl provides the `RotationError` type for representing rotation errors, that act just like a `SVector{3}` but carry the nonlinear map used to compute the error, which can also be used to convert the error back to a `QuatRotation` (and, by extention, any other 3D rotation parameterization). The following methods are useful for computing `RotationError`s and adding them back to the nominal rotation:
Rotations.jl provides the `RotationError` type for representing rotation errors, that act just like a `SVector{3}` but carry the non-linear map used to compute the error, which can also be used to convert the error back to a `QuatRotation` (and, by extension, any other 3D rotation parametrization). The following methods are useful for computing `RotationError`s and adding them back to the nominal rotation:
```julia
rotation_error(R1::Rotation, R2::Rotation, error_map::ErrorMap) # compute the error between `R1` and `R2` using `error_map`
add_error(R::Rotation, err::RotationError) # "adds" the error to `R` by converting back a `UnitQuaterion` and composing with `R`
Expand All @@ -246,7 +246,7 @@ respect to the infinitesimal rotation. For unit quaternions, this is a 4x3 matri

### Import / Export

All parameterizations can be converted to and from (mutable or immutable)
All parametrizations can be converted to and from (mutable or immutable)
3×3 matrices, e.g.

```julia
Expand Down
2 changes: 1 addition & 1 deletion docs/src/3d_angleaxis.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ R(\bm{v})

!!! note "Differentiation"
If you're differentiating a Rodrigues Vector check the result is what you expect at theta = 0.
The first derivative of the rotation *should* behave, but higher-order derivatives of it (as well as parameterization conversions) should be tested.
The first derivative of the rotation *should* behave, but higher-order derivatives of it (as well as parametrization conversions) should be tested.
The Stereographic Quaternion Projection (`MRP`) is the recommended three parameter format for differentiation.

**example**
Expand Down
2 changes: 1 addition & 1 deletion docs/src/3d_quaternion.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ using Rotations
```

## `QuatRotation`
A 3D rotation parameterized by a unit [quaternion](https://en.wikipedia.org/wiki/Quaternion) ([versor](https://en.wikipedia.org/wiki/Versor)).
A 3D rotation parametrized by a unit [quaternion](https://en.wikipedia.org/wiki/Quaternion) ([versor](https://en.wikipedia.org/wiki/Versor)).
Note that the constructor will renormalize the quaternion to be a unit quaternion, and that although they follow the same multiplicative *algebra* as quaternions, it is better to think of `QuatRotation` as a ``3 \times 3`` matrix rather than as a quaternion *number*.

```math
Expand Down
2 changes: 1 addition & 1 deletion docs/src/rotation_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ For more information, see the sidebar page.
* `RotationVec`
* Rotation around given axis. The length of axis vector represents its angle.
* `QuatRotation`
* A 3D rotation parameterized by a unit quaternion.
* A 3D rotation parametrized by a unit quaternion.
* `MRP`
* A 3D rotation encoded by the stereographic projection of a unit quaternion.
8 changes: 4 additions & 4 deletions src/angleaxis_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
struct AngleAxis{T} <: Rotation{3,T}
AngleAxis(Θ, x, y, z)

A 3×3 rotation matrix parameterized by a 3D rotation by angle θ about an
A 3×3 rotation matrix parametrized by a 3D rotation by angle θ about an
arbitrary axis `[x, y, z]`.

Note that the axis is not unique for θ = 0, and that this parameterization does
Note that the axis is not unique for θ = 0, and that this parametrization does
not continuously map the neighbourhood of the identity rotation (and therefore
might not be suitable for autodifferentation and optimization purposes).

Expand Down Expand Up @@ -99,7 +99,7 @@ end
return AA(r.theta, 0, 0, 1)
end

# Using Rodrigues formula on an AngleAxis parameterization (assume unit axis length) to do the rotation
# Using Rodrigues formula on an AngleAxis parametrization (assume unit axis length) to do the rotation
# (implementation from: https://ceres-solver.googlesource.com/ceres-solver/+/1.10.0/include/ceres/rotation.h)
function Base.:*(aa::AngleAxis, v::StaticVector)
if length(v) != 3
Expand Down Expand Up @@ -141,7 +141,7 @@ end
struct RotationVec{T} <: Rotation{3,T}
RotationVec(sx, sy, sz)

Rodrigues vector parameterization of a 3×3 rotation matrix. The direction of the
Rodrigues vector parametrization of a 3×3 rotation matrix. The direction of the
vector [sx, sy, sz] defines the axis of rotation, and the rotation angle is
given by its norm.
"""
Expand Down
2 changes: 1 addition & 1 deletion src/core_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ end
theta::T
end

A 2×2 rotation matrix parameterized by a 2D rotation by angle.
A 2×2 rotation matrix parametrized by a 2D rotation by angle.
Only the angle is stored inside the `Angle2d` type, values
of `getindex` etc. are computed on the fly.
"""
Expand Down
10 changes: 5 additions & 5 deletions src/derivatives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ ith_partial{N}(X::SMatrix{9,N}, i) = @SMatrix([X[1,i] X[4,i] X[7,i];

"""
jacobian(::Type{output_param}, R::input_param)
Returns the jacobian for transforming from the input rotation parameterization
to the output parameterization, centered at the value of R.
Returns the Jacobian for transforming from the input rotation parametrization
to the output parametrization, centered at the value of R.

jacobian(R::rotation_type, X::AbstractVector)
Returns the jacobian for rotating the vector X by R.
Expand Down Expand Up @@ -221,11 +221,11 @@ end
#
"""
1) hessian(::Type{output_param}, R::input_param)
Returns the 2nd order partial derivatives for transforming from the input rotation parameterization to the output parameterization, centered at the value of R.
The output is an N vector of DxD matrices, where N and D are the number of parameters in the output and input parameterizations respectively.
Returns the 2nd order partial derivatives for transforming from the input rotation parametrization to the output parametrization, centered at the value of R.
The output is an N vector of DxD matrices, where N and D are the number of parameters in the output and input parametrizations respectively.
2) hessian(R::rotation_type, X::AbstractVector)
Returns the 2nd order partial derivatives for rotating the vector X by R.
The output is an 3 vector of DxD matrices, where D is the number of parameters of the rotation parameterization.
The output is an 3 vector of DxD matrices, where D is the number of parameters of the rotation parametrization.
"""
function hessian(::Type{Quaternion}, X::SpQuat)

Expand Down
6 changes: 3 additions & 3 deletions src/error_maps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"""
ErrorMap

A nonlinear mapping between the space of unit quaternions and three-dimensional
A non-linear mapping between the space of unit quaternions and three-dimensional
rotation errors.

These mappings are extremely useful for converting from globally nonsingular 3D rotation
These mappings are extremely useful for converting from globally non-singular 3D rotation
representations such as `QuatRotation` or `RotMatrix3` to a three-parameter error that can
be efficiently used in gradient-based optimization methods that optimize deviations about
a current iterate using first or second-order information.
Expand Down Expand Up @@ -38,7 +38,7 @@ struct IdentityMap <: ErrorMap end
"""
InvErrorMap

The nonlinear mapping from unit quaternions to a three-dimensional error state. Obtained by
The non-linear mapping from unit quaternions to a three-dimensional error state. Obtained by
inverting an `ErrorMap`, i.e.

InvCayleyMap() = inv(CayleyMap())
Expand Down
Loading
Loading