Quaternions
These functions create and manipulate quaternions or unit quaternions. The quaternion is represented by a 1D NumPy array with 4 elements: s, x, y, z.
- q2r(q, order='sxyz')[source]
Convert unit-quaternion to SO(3) rotation matrix
- Parameters
- Returns
corresponding SO(3) rotation matrix
- Return type
ndarray(3,3)
Returns an SO(3) rotation matrix corresponding to this unit-quaternion.
>>> from spatialmath.base import q2r >>> q = [0, 0, 1, 0] # rotation of 180deg about y-axis >>> print(q2r(q)) [[-1. 0. 0.] [ 0. 1. 0.] [ 0. 0. -1.]]
Warning
There is no check that the passed value is a unit-quaternion.
- Seealso
- q2v(q)[source]
Convert unit-quaternion to 3-vector
- Parameters
q (
Union
[List
,Tuple
[float
,float
,float
,float
],ndarray
[Any
,dtype
[TypeVar
(ScalarType
, bound=generic
, covariant=True)]]]) – unit-quaternion- Returns
a unique 3-vector
- Return type
ndarray(3)
Returns a unique 3-vector representing the input unit-quaternion. The sign of the scalar part is made positive, if necessary by multiplying the entire quaternion by -1, then the vector part is taken.
>>> from spatialmath.base import q2v >>> from math import sqrt >>> q = [1 / sqrt(2), 0, 1 / sqrt(2), 0] >>> print(q2v(q)) [0. 0.7071 0. ] >>> q = [-1 / sqrt(2), 0, 1 / sqrt(2), 0] >>> print(q2v(q)) [-0. -0.7071 -0. ]
Warning
There is no check that the passed value is a unit-quaternion.
- Seealso
- qangle(q1, q2)[source]
Angle between two unit-quaternions
- Parameters
q0 (array_like(4)) – unit-quaternion
q1 (array_like(4)) – unit-quaternion
- Returns
angle between the rotations [radians]
- Return type
float
If each of the input quaternions is considered a rotated coordinate frame, then the angle is the smallest rotation required about a fixed axis, to rotate the first frame into the second.
>>> from spatialmath.base import qangle >>> from math import sqrt >>> q1 = [1/sqrt(2), 1/sqrt(2), 0, 0] # 90deg rotation about x-axis >>> q2 = [1/sqrt(2), 0, 1/sqrt(2), 0] # 90deg rotation about y-axis >>> qangle(q1, q2) 2.0943951023931953
- References
Metrics for 3D rotations: comparison and analysis, Du Q. Huynh, % J.Math Imaging Vis. DOFI 10.1007/s10851-009-0161-2.
Warning
There is no check that the passed values are unit-quaternions.
- qconj(q)[source]
Quaternion conjugate
- Parameters
q (
Union
[List
,Tuple
[float
,float
,float
,float
],ndarray
[Any
,dtype
[TypeVar
(ScalarType
, bound=generic
, covariant=True)]]]) – quaternion- Returns
conjugate of input quaternion
- Return type
ndarray(4)
Conjugate of quaternion, the vector part is negated.
>>> from spatialmath.base import qconj, qprint >>> q = [1, 2, 3, 4] >>> qprint(qconj(q)) 1.0000 < -2.0000, -3.0000, -4.0000 >
- SymPy
supported
- qdot(q, w)[source]
Rate of change of unit-quaternion
- Parameters
q0 (array_like(4)) – unit-quaternion
w (array_like(3)) – 3D angular velocity in world frame
- Returns
rate of change of unit quaternion
- Return type
ndarray(4)
dot(q, w)
is the rate of change of the elements of the unit quaternionq
which represents the orientation of a body frame with angular velocityw
in the world frame.>>> from spatialmath.base import qdot, qprint >>> from math import sqrt >>> q = [1/sqrt(2), 1/sqrt(2), 0, 0] # 90deg rotation about x-axis >>> qdot(q, [1, 2, 3]) array([-0.3536, 0.3536, 1.7678, 0.3536])
Warning
There is no check that the passed values are unit-quaternions.
- qdotb(q, w)[source]
Rate of change of unit-quaternion
- Parameters
q0 (array_like(4)) – unit-quaternion
w (array_like(3)) – 3D angular velocity in body frame
- Returns
rate of change of unit quaternion
- Return type
ndarray(4)
dotb(q, w)
is the rate of change of the elements of the unit quaternionq
which represents the orientation of a body frame with angular velocityw
in the body frame.>>> from spatialmath.base import qdotb, qprint >>> from math import sqrt >>> q = [1/sqrt(2), 1/sqrt(2), 0, 0] # 90deg rotation about x-axis >>> qdotb(q, [1, 2, 3]) array([-0.3536, 0.3536, -0.3536, 1.7678])
Warning
There is no check that the passed values are unit-quaternions.
- qeye()[source]
Create an identity quaternion
- Returns
an identity quaternion
- Return type
ndarray(4)
Creates an identity quaternion, with the scalar part equal to one, and a zero vector value.
>>> from spatialmath.base import qeye, qprint >>> q = qeye() >>> qprint(q) 1.0000 < 0.0000, 0.0000, 0.0000 >
- qinner(q1, q2)[source]
Quaternion inner product
- Parameters
q0 (: array_like(4)) – quaternion
q1 (array_like(4)) – uaternion
- Returns
inner product
- Return type
float
This is the inner or dot product of two quaternions, it is the sum of the element-wise product.
The inner product
inner(q, q)
is the square of the norm ofq
.If
q0
andq1
are unit quaternions then the inner product is the cosine of the angle between the two orientations.
>>> from spatialmath.base import qinner >>> from math import sqrt, acos, pi >>> q1 = [1, 2, 3, 4] >>> qinner(q1, q1) # square of the norm 30.0 >>> q1 = [1/sqrt(2), 1/sqrt(2), 0, 0] # 90deg rotation about x-axis >>> q2 = [1/sqrt(2), 0, 1/sqrt(2), 0] # 90deg rotation about y-axis >>> acos(qinner(q1, q2)) * 180 / pi # angle between q1 and q2 60.00000000000001
- Seealso
qvmul
- qisequal(q1, q2, tol=20, unitq=False)[source]
Test if quaternions are equal
- Parameters
q1 (array_like(4)) – quaternion
q2 (array_like(4)) – quaternion
unitq (bool) – quaternions are unit quaternions
tol (float) – tolerance in units of eps, defaults to 20
- Returns
whether quaternions are equal
- Return type
bool
Tests if two quaternions are equal.
For unit-quaternions
unitq=True
the double mapping is taken into account, that isq
and-q
represent the same orientation andisequal(q, -q, unitq=True)
will returnTrue
.>>> from spatialmath.base import qisequal >>> q1 = [1, 2, 3, 4] >>> q2 = [-1, -2, -3, -4] >>> qisequal(q1, q2) False >>> qisequal(q1, q2, unitq=True) True
- qisunit(q, tol=20)[source]
Test if quaternion has unit length
- Parameters
v (array_like(4)) – quaternion
tol (float) – tolerance in units of eps, defaults to 20
- Returns
whether quaternion has unit length
- Return type
bool
>>> from spatialmath.base import qeye, qpure, qisunit >>> q = qeye() >>> qisunit(q) False >>> q = qpure([1, 2, 3]) >>> qisunit(q) False
- Seealso
- qmatrix(q)[source]
Convert quaternion to 4x4 matrix equivalent
- Parameters
q (
Union
[List
,Tuple
[float
,float
,float
,float
],ndarray
[Any
,dtype
[TypeVar
(ScalarType
, bound=generic
, covariant=True)]]]) – quaternion- Returns
equivalent matrix
- Return type
ndarray(4)
Hamilton multiplication between two quaternions can be considered as a matrix-vector product, the left-hand quaternion is represented by an equivalent 4x4 matrix and the right-hand quaternion as 4x1 column vector.
>>> from spatialmath.base import qmatrix, qqmul, qprint >>> q1 = [1, 2, 3, 4] >>> q2 = [5, 6, 7, 8] >>> qqmul(q1, q2) # conventional Hamilton product array([-60., 12., 30., 24.]) >>> m = qmatrix(q1) >>> print(m) [[ 1. -2. -3. -4.] [ 2. 1. -4. 3.] [ 3. 4. 1. -2.] [ 4. -3. 2. 1.]] >>> v = m @ np.array(q2) >>> print(v) [-60. 12. 30. 24.]
- Seealso
qqmul
- qnorm(q)[source]
Norm of a quaternion
- Parameters
q (
Union
[List
,Tuple
[float
,float
,float
,float
],ndarray
[Any
,dtype
[TypeVar
(ScalarType
, bound=generic
, covariant=True)]]]) – quaternion- Returns
norm of the quaternion
- Return type
float
Returns the norm (length or magnitude) of the input quaternion which is
\[(s^2 + v_x^2 + v_y^2 + v_z^2)^{1/2}\]>>> from spatialmath.base import qnorm >>> q = qnorm([1, 2, 3, 4]) >>> print(q) 5.477225575051661
- Seealso
- qpositive(q)[source]
Quaternion with positive scalar part
- Parameters
q (
Union
[List
,Tuple
[float
,float
,float
,float
],ndarray
[Any
,dtype
[TypeVar
(ScalarType
, bound=generic
, covariant=True)]]]) – quaternion- Returns
pure quaternion
- Return type
ndarray(4)
If the scalar part is negative return -q.
- qpow(q, power)[source]
Raise quaternion to a power
- Parameters
- Returns
input quaternion raised to the specified power
- Return type
ndarray(4)
- Raises
ValueError – if exponent is non integer
Raises a quaternion to the specified power using repeated multiplication.
>>> from spatialmath.base import qpow, qqmul, qprint >>> q = [1, 2, 3, 4] >>> qprint(qqmul(q, q)) -28.0000 < 4.0000, 6.0000, 8.0000 > >>> qprint(qpow(q, 2)) -28.0000 < 4.0000, 6.0000, 8.0000 > >>> qprint(qpow(q, -2)) # conjugate of above -28.0000 < -4.0000, -6.0000, -8.0000 >
- Seealso
- SymPy
supported for
q
but notpower
.
- qprint(q, delim=('<', '>'), fmt='{: .4f}', file=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>)[source]
Format a quaternion
- Parameters
q (array_like(4)) – unit-quaternion
delim (list or tuple of strings) – 2-list of delimeters [default (‘<’, ‘>’)]
fmt (str) – printf-style format soecifier [default ‘{: .4f}’]
file (file object) – destination for formatted string [default sys.stdout]
- Returns
formatted string
- Return type
str
Format the quaternion in a human-readable form as:
S D1 VX VY VZ D2
where S, VX, VY, VZ are the quaternion elements, and D1 and D2 are a pair of delimeters given by delim.
By default the string is written to sys.stdout.
If file=None then a string is returned.
>>> from spatialmath.base import qprint, qrand >>> q = [1, 2, 3, 4] >>> qprint(q) 1.0000 < 2.0000, 3.0000, 4.0000 > >>> q = qrand() # a unit quaternion >>> qprint(q, delim=('<<', '>>')) -0.5498 << 0.3563, -0.1463, -0.7412 >>
- qpure(v)[source]
Create a pure quaternion
- Parameters
v (array_like(3)) – 3D vector
- Returns
pure quaternion
- Return type
ndarray(4)
Creates a pure quaternion, with a zero scalar value and the vector part equal to the passed vector value.
File "<input>", line 1, in <module> NameError: name 'qpure' is not defined Traceback (most recent call last): File "<input>", line 1, in <module> NameError: name 'qprint' is not defined
- qqmul(q1, q2)[source]
Quaternion multiplication
- Parameters
q0 (: array_like(4)) – left-hand quaternion
q1 (array_like(4)) – right-hand quaternion
- Returns
quaternion product
- Return type
ndarray(4)
This is the quaternion or Hamilton product. If both operands are unit-quaternions then the product will be a unit-quaternion.
>>> from spatialmath.base import qqmul >>> q1 = [1, 2, 3, 4] >>> q2 = [5, 6, 7, 8] >>> qqmul(q1, q2) # conventional Hamilton product array([-60., 12., 30., 24.])
- Seealso
qvmul, qinner, vvmul
- qrand()[source]
Random unit-quaternion
- Returns
random unit-quaternion
- Return type
ndarray(4)
Computes a uniformly distributed random unit-quaternion which can be considered equivalent to a random SO(3) rotation.
>>> from spatialmath.base import qrand, qprint >>> qprint(qrand()) -0.3974 < -0.0791, -0.1223, -0.9060 >
- qslerp(q0, q1, s, shortest=False, tol=20)[source]
Quaternion conjugate
- Parameters
q0 (array_like(4)) – initial unit quaternion
q1 (array_like(4)) – final unit quaternion
s (float) – interpolation coefficient in the range [0,1]
shortest (bool) – choose shortest distance [default False]
tol (float, optional) – Tolerance when checking for identical quaternions, in multiples of eps, defaults to 20
- Returns
interpolated unit-quaternion
- Return type
ndarray(4)
- Raises
ValueError – s is outside interval [0, 1]
An interpolated quaternion between
q0
whens
= 0 toq1
whens
= 1.Interpolation is performed on a great circle on a 4D hypersphere. This is a rotation about a single fixed axis in space which yields the straightest and shortest path between two points.
For large rotations the path may be the long way around the circle, the option
'shortest'
ensures always the shortest path.>>> from spatialmath.base import qslerp, qprint >>> from math import sqrt >>> q0 = [1/sqrt(2), 1/sqrt(2), 0, 0] # 90deg rotation about x-axis >>> q1 = [1/sqrt(2), 0, 1/sqrt(2), 0] # 90deg rotation about y-axis >>> qprint(qslerp(q0, q1, 0)) # this is q0 0.7071 < 0.7071, 0.0000, 0.0000 > >>> qprint(qslerp(q0, q1, 1)) # this is q1 0.7071 < 0.0000, 0.7071, 0.0000 > >>> qprint(qslerp(q0, q1, 0.5)) # this is in "half way" between 0.8165 < 0.4082, 0.4082, 0.0000 >
Warning
There is no check that the passed values are unit-quaternions.
- qunit(q, tol=20)[source]
Create a unit quaternion
- Parameters
v (array_like(4)) – quaterion
tol (float, optional) – Tolerance in multiples of eps, defaults to 20
- Returns
a pure quaternion
- Return type
ndarray(4)
- Raises
ValueError – quaternion has (near) zero norm
Creates a unit quaternion, with unit norm, by scaling the input quaternion.
>>> from spatialmath.base import qunit, qprint >>> q = qunit([1, 2, 3, 4]) >>> qprint(q) 0.1826 < 0.3651, 0.5477, 0.7303 >
Note
Scalar part is always positive.
Note
If the quaternion norm is less than
tol * eps
an exception is raised.- Seealso
- qvmul(q, v)[source]
Vector rotation
- Parameters
q (array_like(4)) – unit-quaternion
v (array_like(3)) – 3-vector to be rotated
- Returns
rotated 3-vector
- Return type
ndarray(3)
The vector v is rotated about the origin by the SO(3) equivalent of the unit quaternion.
>>> from spatialmath.base import qvmul >>> from math import sqrt >>> q = [1/sqrt(2), 1/sqrt(2), 0, 0] # 90deg rotation about x-axis >>> qvmul(q, [1, 2, 3]) # rotated vector array([ 1., -3., 2.])
Warning
There is no check that the passed value is a unit-quaternions.
- Seealso
qvmul
- r2q(R, check=False, tol=20, order='sxyz', shortest=False)[source]
Convert SO(3) rotation matrix to unit-quaternion
- Parameters
R (ndarray(3,3)) – SO(3) rotation matrix
check (bool) – check validity of rotation matrix, default False
tol (float) – tolerance in units of eps, defaults to 20
order (str) – the order of the returned quaternion elements. Must be ‘sxyz’ or ‘xyzs’. Defaults to ‘sxyz’.
shortest (bool, default to False) – ensures the quaternion has non-negative scalar part.
- Returns
unit-quaternion as Euler parameters
- Return type
ndarray(4)
- Raises
ValueError – for non SO(3) argument
Returns a unit-quaternion corresponding to the input SO(3) rotation matrix.
>>> from spatialmath.base import r2q, qprint, rotx >>> R = rotx(90, 'deg') # rotation of 90deg about x-axis >>> print(R) [[ 1. 0. 0.] [ 0. 0. -1.] [ 0. 1. 0.]] >>> qprint(r2q(R)) 0.7071 < 0.7071, 0.0000, 0.0000 >
Warning
There is no check that the passed matrix is a valid rotation matrix.
Note
Scalar part is always positive
implements Cayley’s method
- Reference
Sarabandi, S., and Thomas, F. (March 1, 2019). “A Survey on the Computation of Quaternions From Rotation Matrices.” ASME. J. Mechanisms Robotics. April 2019; 11(2): 021006. doi.org/10.1115/1.4041889
- Seealso
- v2q(v)[source]
Convert 3-vector to unit-quaternion
- Parameters
v (array_like(3)) – vector part of unit quaternion
- Returns
a unit quaternion
- Return type
ndarray(4)
Returns a unit-quaternion reconsituted from just its vector part. Assumes that the scalar part was positive, so \(s = \sqrt{1-||v||}\).
>>> from spatialmath.base import v2q, qprint >>> from math import sqrt >>> v = [0, 1 / sqrt(2), 0] >>> qprint(v2q(v)) 0.7071 < 0.0000, 0.7071, 0.0000 > >>> v = [0, -1 / sqrt(2), 0] >>> qprint(v2q(v)) 0.7071 < 0.0000, -0.7071, 0.0000 >
Warning
There is no check that the value is the vector part of a unit-quaternion, and this can lead to a math domain error.
- Seealso
- vvmul(qa, qb)[source]
Quaternion multiplication
- Parameters
qa (: array_like(3)) – left-hand quaternion
qb (array_like(3)) – right-hand quaternion
- Returns
quaternion product
- Return type
ndarray(3)
This is the quaternion or Hamilton product of unit-quaternions defined only by their vector components. The product will be a unit-quaternion, defined only by its vector component.
>>> from spatialmath.base import vvmul, v2q, q2v, qqmul, qprint >>> from math import sqrt >>> q1 = [1/sqrt(2), 1/sqrt(2), 0, 0] # 90deg rotation about x-axis >>> q2 = [1/sqrt(2), 0, 1/sqrt(2), 0] # 90deg rotation about y-axis >>> qprint(qqmul(q1, q2)) # normal Hamilton product 0.5000 < 0.5000, 0.5000, 0.5000 > >>> v1 = q2v(q1); v2 = q2v(q2) >>> vp = vvmul(v1, v2) # product using 3-vectors >>> qprint(v2q(vp)) # same answer as Hamilton product 0.5000 < 0.5000, 0.5000, 0.5000 >