diff --git a/README.md b/README.md index 43bd95a..a6aa8a9 100644 --- a/README.md +++ b/README.md @@ -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: @@ -49,14 +49,14 @@ 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) @@ -64,7 +64,7 @@ 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) @@ -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) @@ -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 @@ -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}` @@ -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*. @@ -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. @@ -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 @@ -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. @@ -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` @@ -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 diff --git a/docs/src/3d_angleaxis.md b/docs/src/3d_angleaxis.md index 95b80ac..d7126da 100644 --- a/docs/src/3d_angleaxis.md +++ b/docs/src/3d_angleaxis.md @@ -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** diff --git a/docs/src/3d_quaternion.md b/docs/src/3d_quaternion.md index a3a15ae..1a94801 100644 --- a/docs/src/3d_quaternion.md +++ b/docs/src/3d_quaternion.md @@ -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 diff --git a/docs/src/rotation_types.md b/docs/src/rotation_types.md index 0dab4c7..8acd182 100644 --- a/docs/src/rotation_types.md +++ b/docs/src/rotation_types.md @@ -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. diff --git a/src/angleaxis_types.jl b/src/angleaxis_types.jl index 85cf09e..b0e0600 100644 --- a/src/angleaxis_types.jl +++ b/src/angleaxis_types.jl @@ -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). @@ -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 @@ -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. """ diff --git a/src/core_types.jl b/src/core_types.jl index 4a3c9f4..358266d 100644 --- a/src/core_types.jl +++ b/src/core_types.jl @@ -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. """ diff --git a/src/derivatives.jl b/src/derivatives.jl index c8000a7..74da8dc 100644 --- a/src/derivatives.jl +++ b/src/derivatives.jl @@ -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. @@ -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) diff --git a/src/error_maps.jl b/src/error_maps.jl index 1038c9b..71b13de 100644 --- a/src/error_maps.jl +++ b/src/error_maps.jl @@ -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. @@ -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()) diff --git a/src/euler_types.jl b/src/euler_types.jl index b48445f..f4e35e5 100644 --- a/src/euler_types.jl +++ b/src/euler_types.jl @@ -566,7 +566,7 @@ end struct RotXYX{T} <: Rotation{3,T} RotXYX(theta1, theta2, theta3) -A 3×3 rotation matrix parameterized by the "proper" XYX Euler angle convention, +A 3×3 rotation matrix parametrized by the "proper" XYX Euler angle convention, consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the X axis by `theta1`. @@ -617,7 +617,7 @@ end struct RotXZX{T} <: Rotation{3,T} RotXZX(theta1, theta2, theta3) -A 3×3 rotation matrix parameterized by the "proper" XZX Euler angle convention, +A 3×3 rotation matrix parametrized by the "proper" XZX Euler angle convention, consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the X axis by `theta1`. @@ -668,7 +668,7 @@ end struct RotYXY{T} <: Rotation{3,T} RotYXY(theta1, theta2, theta3) -A 3×3 rotation matrix parameterized by the "proper" YXY Euler angle convention, +A 3×3 rotation matrix parametrized by the "proper" YXY Euler angle convention, consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Y axis by `theta1`. @@ -719,7 +719,7 @@ end struct RotYZY{T} <: Rotation{3,T} RotYZY(theta1, theta2, theta3) -A 3×3 rotation matrix parameterized by the "proper" YXY Euler angle convention, +A 3×3 rotation matrix parametrized by the "proper" YXY Euler angle convention, consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the Y axis by `theta1`. @@ -770,7 +770,7 @@ end struct RotZXZ{T} <: Rotation{3,T} RotZXZ(theta1, theta2, theta3) -A 3×3 rotation matrix parameterized by the "proper" ZXZ Euler angle convention, +A 3×3 rotation matrix parametrized by the "proper" ZXZ Euler angle convention, consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Z axis by `theta1`. @@ -821,7 +821,7 @@ end struct RotZYZ{T} <: Rotation{3,T} RotZYZ(theta1, theta2, theta3) -A 3×3 rotation matrix parameterized by the "proper" ZXZ Euler angle convention, +A 3×3 rotation matrix parametrized by the "proper" ZXZ Euler angle convention, consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the Z axis by `theta1`. @@ -876,7 +876,7 @@ end RotXYZ(theta1, theta2, theta3) RotXYZ(roll=r, pitch=p, yaw=y) -A 3×3 rotation matrix parameterized by the "Tait-Bryant" XYZ Euler angle +A 3×3 rotation matrix parametrized by the "Tait-Bryant" XYZ Euler angle convention, consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the X axis by `theta1`. @@ -934,7 +934,7 @@ end RotZYX(theta1, theta2, theta3) RotZYX(roll=r, pitch=p, yaw=y) -A 3×3 rotation matrix parameterized by the "Tait-Bryant" ZYX Euler angle +A 3×3 rotation matrix parametrized by the "Tait-Bryant" ZYX Euler angle convention, consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Y axis by `theta2`, and finally a rotation about the Z axis by `theta1`. @@ -992,7 +992,7 @@ end RotXZY(theta1, theta2, theta3) RotXZY(roll=r, pitch=p, yaw=y) -A 3×3 rotation matrix parameterized by the "Tait-Bryant" XZY Euler angle +A 3×3 rotation matrix parametrized by the "Tait-Bryant" XZY Euler angle convention, consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the X axis by `theta1`. @@ -1050,7 +1050,7 @@ end RotYZX(theta1, theta2, theta3) RotYZX(roll=r, pitch=p, yaw=y) -A 3×3 rotation matrix parameterized by the "Tait-Bryant" YZX Euler angle +A 3×3 rotation matrix parametrized by the "Tait-Bryant" YZX Euler angle convention, consisting of first a rotation about the X axis by `theta3`, followed by a rotation about the Z axis by `theta2`, and finally a rotation about the Y axis by `theta1`. @@ -1108,7 +1108,7 @@ end RotYXZ(theta1, theta2, theta3) RotYXZ(roll=r, pitch=p, yaw=y) -A 3×3 rotation matrix parameterized by the "Tait-Bryant" YXZ Euler angle +A 3×3 rotation matrix parametrized by the "Tait-Bryant" YXZ Euler angle convention, consisting of first a rotation about the Z axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Y axis by `theta1`. @@ -1166,7 +1166,7 @@ end RotZXY(theta1, theta2, theta3) RotZXY(roll=r, pitch=p, yaw=y) -A 3×3 rotation matrix parameterized by the "Tait-Bryant" ZXY Euler angle +A 3×3 rotation matrix parametrized by the "Tait-Bryant" ZXY Euler angle convention, consisting of first a rotation about the Y axis by `theta3`, followed by a rotation about the X axis by `theta2`, and finally a rotation about the Z axis by `theta1`. diff --git a/src/mrps.jl b/src/mrps.jl index ccde645..b901675 100644 --- a/src/mrps.jl +++ b/src/mrps.jl @@ -1,7 +1,7 @@ """ MRP{T} <: Rotation -Modified Rodrigues Parameter. Is a 3D parameterization of attitude, and is a sterographic +Modified Rodrigues Parameter. Is a 3D parametrization of attitude, and is a stereographic projection of the 4D unit sphere onto the plane tangent to the negative real pole. They have a singularity at θ = ±360°. diff --git a/src/rand.jl b/src/rand.jl index 106e12b..a793548 100644 --- a/src/rand.jl +++ b/src/rand.jl @@ -10,7 +10,7 @@ function Random.rand(rng::AbstractRNG, ::Random.SamplerType{R}) where R <: Union end # A random rotation can be obtained easily with unit quaternions -# The unit sphere in R⁴ parameterizes quaternion rotations according to the +# The unit sphere in R⁴ parametrizes quaternion rotations according to the # Haar measure of SO(3) - see e.g. http://math.stackexchange.com/questions/184086/uniform-distributions-on-the-space-of-rotations-in-3d function Random.rand(rng::AbstractRNG, ::Random.SamplerType{R}) where R <: Union{<:Rotation{3},<:RotMatrix{3}} # We use the awkward Union{<:Rotation{3},<:RotMatrix{3}} here rather than `Rotation{3}` diff --git a/src/rodrigues_params.jl b/src/rodrigues_params.jl index ce151e8..cbabaad 100644 --- a/src/rodrigues_params.jl +++ b/src/rodrigues_params.jl @@ -2,7 +2,7 @@ """ RodriguesParam{T} -Rodrigues parameters are a three-dimensional parameterization of rotations. +Rodrigues parameters are a three-dimensional parametrization of rotations. They have a singularity at 180° but do not inherit the sign ambiguities of quaternions or MRPs """ diff --git a/src/rotation_error.jl b/src/rotation_error.jl index 6a83968..e194774 100644 --- a/src/rotation_error.jl +++ b/src/rotation_error.jl @@ -47,7 +47,7 @@ end function rotation_error(R1::Rotation, R2::Rotation, error_map::IdentityMap) err = params(R2\R1) if length(err) != 3 - throw(ArgumentError("R2\\R1 must be a three-dimensional parameterization, got $(length(err))")) + throw(ArgumentError("R2\\R1 must be a three-dimensional parametrization, got $(length(err))")) end return RotationError(err, error_map) end diff --git a/src/unitquaternion.jl b/src/unitquaternion.jl index 7e706c3..51b590a 100644 --- a/src/unitquaternion.jl +++ b/src/unitquaternion.jl @@ -335,7 +335,7 @@ where `ω` is the angular velocity. This is equivalent to Ṙ = \\lim_{Δt → 0} \\frac{R δR - R}{Δt} ``` -where ``δR`` is some small rotation, parameterized by a small rotation ``δθ`` about +where ``δR`` is some small rotation, parametrized by a small rotation ``δθ`` about an axis ``r``, such that ``\\lim_{Δt → 0} \\frac{δθ r}{Δt} = ω`` The kinematics are extremely useful when computing the dynamics of rigid bodies, since @@ -468,7 +468,7 @@ Jacobian of `lmult(q) QuatMap(ϕ)`, when ϕ is near zero. Useful for converting Jacobians from R⁴ to R³ and correctly account for unit norm constraint. Jacobians for different - differential quaternion parameterization are the same up to a constant. + differential quaternion parametrization are the same up to a constant. """ function ∇differential(q::QuatRotation) w = real(q.q)