19 views (last 30 days)

Show older comments

I've been using the quaternion class from the sensor fusion toolbox and I just want to be sure that I haven't made a misunderstanding with the conventions.

At first glance, I guessed that this is following the Hamilton convention for quaternions: in that the scalar part comes first, and so on. But I am slightly in doubt when it comes to the "point" vs "frame" rotation terminology. I am assuming point corresponds to passive and frame corresponds to active due to the results of this

q = quaternion([0.42718, 0.24083, 0.59322, 0.63844]);

v = [1,0,0];

vQuat = quaternion([0,v]);

q * vQuat * conj(q)

rotatepoint(q, v)

conj(q) * vQuat * q

rotateframe(q, v)

the result of which is

ans =

quaternion

0 - 0.51903i + 0.83119j - 0.19931k

ans =

-0.5190 0.8312 -0.1993

ans =

quaternion

0 - 0.51903i - 0.25973j + 0.81433k

ans =

-0.5190 -0.2597 0.8143

which suggests that rotatepoint corresonds to where ⊗ quaternion multiplication.

"Realistic" Example for body to local frame rotation

If we a consider a "real-life" example instead, say the quaternion q represents the orientation of a body frame in a local frame (like e.g. if I want to construct the rotation matrix from body -> local then my guess is that would be rotmat(quat, 'point'). My implementation of this "real-life" example is here

drawArrow = @(p,varargin) quiver( 0,0,p(1),p(2),0,varargin{:} );

% original point

p1 = [1; 0; 0];

% axis-angle rotation, 45 degrees around positive x axis

theta = deg2rad(45);

a = [0, 0, 1];

q = quaternion([cos(theta/2), sin(theta/2)*a]);

% i think rotation corresponds to

p2 = rotatepoint(q, p1'); % body to local frame

p3 = rotateframe(q, p1'); % local frame to body

figure(1)

clf

hold on

drawArrow(p1);

drawArrow(p2);

drawArrow(p3);

grid on

xlabel('x')

ylabel('y')

xlim([-0.5,2])

ylim([-1,1])

legend({'orignal','b->l','l->b'})

where the resulting plot is attached. My understanding here is that blue is the original vector in body frame, red is the same vector in the local frame when the rotation from body to local is given by the specific axis-angle rotation.

Yiping Liu
on 23 Apr 2021

Your understanding seems to be correct.

If the quaternion q reprsents a 3D rotation that rotates frame Local into frame Body, then the rotation matrix acquired through R = q.rotmat('frame') represents the same 3D rotation, but keep in mind that the same R can also be interpreted as "the rotation that re-expresses a point in body frame into local frame".

To express a point that is originally given in local frame into the body frame, you need R', which is equivalent to q.rotmat('point')

>> q.rotmat('frame') * q.rotmat('point')

ans =

1.0000 0 0

0 1.0000 0

0 0 1.0000

James Tursa
on 26 Apr 2021

Edited: James Tursa
on 26 Apr 2021

See this post for comments regarding "point" vs "frame" convention:

And also this post for a graphic example:

James Tursa
on 29 Apr 2021

I am not seeing the confusion here. If you look at your explicit rotation matrix

0.7071 -0.7071 0

0.7071 0.7071 0

0 0 1.0000

this sure looks like an active rotation of 45 degrees to me. E.g., take a vector along the x-axis [1;0;0] and multiply it by that matrix and you will get the first column. This is what you would expect by actively rotating a [1;0;0] vector by 45 degrees within the same coordinate frame. It should end up halfway between the x-axis and the y-axis, and that is what we got. And take a y-axis vector [0;1;0] and do the same multiplication and you get the 2nd column, which is a vector halfway between the y-axis and the negative x-axis. Again, this is what I would expect from an active rotation of 45 degrees within the same coordinate frame.

As for the quaternion to direction cosine matrix conversion formula, this does look like a Scalar-Vector order Left Chain Active Hamilton convention.

Brian Fanous
on 28 Apr 2021

The quaternion class does follow the Hamilton convention – the scalar part is first.

Point rotations are active rotations and correspond to q * v * conj(q).

Frame rotations are passive rotations and corresponds to conj(q) * v * q

See this example for a fuller explanation https://www.mathworks.com/help/fusion/ug/rotations-orientation-and-quaternions.html

Brian Fanous
on 28 Apr 2021

We might be using the same definition of orientation, but just to be sure, our orientation definition is :

“Orientation is defined as the frame rotation that takes the parent frame to the child frame.”

This is in the doc on this page: https://www.mathworks.com/help/fusion/gs/spatial-representation-coordinate-systems-and-conventions.html

The equation you’ve written with the rotation matrix takes the body (child) frame to the parent (navigation) frame. Your rotation matrix is what we’d call a point rotation matrix. Really it’s the transpose of what we call orientation in the toolboxes. But that’s why it works in your equation – you are going body to nav so using the transpose is correct.

The quaternion you’ve built is the same one you’d get if you did this:

quaternion([45 0 0], 'eulerd', 'ZYX', 'point')

which is to say, “make a quaternion q such that q * v * conj(q) will rotate a point 45 degrees around the Z axis.”

That’s why you get the same answer as the matrix you’ve defined above which rotates a point around the Z axis. The transpose of that matrix rotates the frame of reference.

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!