Gazebo: Q&A Forum - RSS feedhttp://answers.gazebosim.org/questions/Open source question and answer forum for GazeboenCopyright Askbot, 2010-2011.Mon, 22 Apr 2019 11:37:43 -0500How to apply an extrinsic rotation to a link, programmatically?http://answers.gazebosim.org/question/22339/how-to-apply-an-extrinsic-rotation-to-a-link-programmatically/I have models written in SDF that I want to rotate at specific extrinsic angles before starting a Gazebo simulation with them. I have the roll, pitch and yaw of the pose of the link, I have the extrinsic roll, pitch and yaw of the desired rotation, and I want to find out the formula for obtaining the roll, pitch and yaw of the link, after the rotation, so that I can update the pose values in the SDF file.
I couldn't find a source for the Euler angle convention that Gazebo uses, but I can tell that it is using intrinsic angles because when I rotate a link on the X axis by changing its roll pose number, it rotates around the extrinsic X axis, but if I then change the pitch pose number, it doesn't rotate around the extrinsic Y axis but its own, intrinsic, Y axis.
I'll greatly appreciate any help, thank you!
**Edit:** I've managed to find out about a widely used [transformations library](https://www.lfd.uci.edu/~gohlke/code/transformations.py.html) and I've managed to write the following code:
Re = euler_matrix(arr[3]-np.pi, arr[4], arr[5], 'rxyz')
Rx = rotation_matrix(r_arr[0], [1, 0, 0])
Ry = rotation_matrix(r_arr[1], [0, 1, 0])
Rz = rotation_matrix(r_arr[2], [0, 0, 1])
M = concatenate_matrices(Re, Rx, Ry, Rz)
euler = euler_from_matrix(M, 'rxyz')
arr[3] = euler[0]
arr[4] = euler[1]
arr[5] = euler[2]
where r_arr contains the desired extrinsic rotations and arr[3:6] contains the current intrinsic rotations.
Here is the result:
![hand rotated 90 degrees on the Y axis](/upfiles/15558744315746221.png)
The hand has been rotated 90 degrees on the Y axis. The little finger didn't come out right, I think this is a numerical inaccuracy, the links of the little finger being the only ones with negative pitch from all the other fingers. If there is a better way, I'm open to suggestions.
I'm also attaching the [hand SDF file](/upfiles/15558746353024074.world).Sun, 21 Apr 2019 09:23:17 -0500http://answers.gazebosim.org/question/22339/how-to-apply-an-extrinsic-rotation-to-a-link-programmatically/Answer by josephcoombe for <p>I have models written in SDF that I want to rotate at specific extrinsic angles before starting a Gazebo simulation with them. I have the roll, pitch and yaw of the pose of the link, I have the extrinsic roll, pitch and yaw of the desired rotation, and I want to find out the formula for obtaining the roll, pitch and yaw of the link, after the rotation, so that I can update the pose values in the SDF file.</p>
<p>I couldn't find a source for the Euler angle convention that Gazebo uses, but I can tell that it is using intrinsic angles because when I rotate a link on the X axis by changing its roll pose number, it rotates around the extrinsic X axis, but if I then change the pitch pose number, it doesn't rotate around the extrinsic Y axis but its own, intrinsic, Y axis.</p>
<p>I'll greatly appreciate any help, thank you!</p>
<p><strong>Edit:</strong> I've managed to find out about a widely used <a href="https://www.lfd.uci.edu/~gohlke/code/transformations.py.html">transformations library</a> and I've managed to write the following code:</p>
<pre><code>Re = euler_matrix(arr[3]-np.pi, arr[4], arr[5], 'rxyz')
Rx = rotation_matrix(r_arr[0], [1, 0, 0])
Ry = rotation_matrix(r_arr[1], [0, 1, 0])
Rz = rotation_matrix(r_arr[2], [0, 0, 1])
M = concatenate_matrices(Re, Rx, Ry, Rz)
euler = euler_from_matrix(M, 'rxyz')
arr[3] = euler[0]
arr[4] = euler[1]
arr[5] = euler[2]
</code></pre>
<p>where r_arr contains the desired extrinsic rotations and arr[3:6] contains the current intrinsic rotations.</p>
<p>Here is the result:
<img src="/upfiles/15558744315746221.png" alt="hand rotated 90 degrees on the Y axis"></p>
<p>The hand has been rotated 90 degrees on the Y axis. The little finger didn't come out right, I think this is a numerical inaccuracy, the links of the little finger being the only ones with negative pitch from all the other fingers. If there is a better way, I'm open to suggestions.</p>
<p>I'm also attaching the <a href="/upfiles/15558746353024074.world">hand SDF file</a>.</p>
http://answers.gazebosim.org/question/22339/how-to-apply-an-extrinsic-rotation-to-a-link-programmatically/?answer=22342#post-id-22342Based on my own experience and this [Gazebo Answer](http://answers.gazebosim.org/question/9578/pose-calculation-in-gazebosim-tutorial/?answer=9579#post-id-9579), I believe that Gazebo poses do in fact represent extrinsic (fixed axis) xyz rotations.
----------
I have used Christoph Gohlke's [transformation library](https://www.lfd.uci.edu/~gohlke/code/transformations.py.html) and also encountered some numerical inaccuracy issue.
*Numerical Inaccuracy Workaround:*
In [transformations.py](https://www.lfd.uci.edu/~gohlke/code/transformations.py.html), I changed the value of `_EPS` from `numpy.finfo(float).eps * 4.0` to `1e-10`
*Explanation:*
As best as I can tell, most of the recommended algorithms/libraries for converting rotation matrices to euler angles (including transformations.py) use derivatives of an algorithm by **Ken Shoemake** found in **Graphics Gems IV (1994)**.
Example:
def mat2euler(M, cy_thresh=None):
''' Discover Euler angle vector from 3x3 matrix
Uses the conventions above.
Parameters
----------
M : array-like, shape (3,3)
cy_thresh : None or scalar, optional
threshold below which to give up on straightforward arctan for
estimating x rotation. If None (default), estimate from
precision of input.
Returns
-------
z : scalar
y : scalar
x : scalar
Rotations in radians around z, y, x axes, respectively
Notes
-----
If there was no numerical error, the routine could be derived using
Sympy expression for z then y then x rotation matrix, which is::
[ cos(y)*cos(z), -cos(y)*sin(z), sin(y)],
[cos(x)*sin(z) + cos(z)*sin(x)*sin(y), cos(x)*cos(z) - sin(x)*sin(y)*sin(z), -cos(y)*sin(x)],
[sin(x)*sin(z) - cos(x)*cos(z)*sin(y), cos(z)*sin(x) + cos(x)*sin(y)*sin(z), cos(x)*cos(y)]
with the obvious derivations for z, y, and x
z = atan2(-r12, r11)
y = asin(r13)
x = atan2(-r23, r33)
Problems arise when cos(y) is close to zero, because both of::
z = atan2(cos(y)*sin(z), cos(y)*cos(z))
x = atan2(cos(y)*sin(x), cos(x)*cos(y))
will be close to atan2(0, 0), and highly unstable.
The ``cy`` fix for numerical instability below is from: *Graphics
Gems IV*, Paul Heckbert (editor), Academic Press, 1994, ISBN:
0123361559. Specifically it comes from EulerAngles.c by Ken
Shoemake, and deals with the case where cos(y) is close to zero:
See: http://www.graphicsgems.org/
The code appears to be licensed (from the website) as "can be used
without restrictions".
'''
M = np.asarray(M)
if cy_thresh is None:
try:
cy_thresh = np.finfo(M.dtype).eps * 4
except ValueError:
cy_thresh = _FLOAT_EPS_4
r11, r12, r13, r21, r22, r23, r31, r32, r33 = M.flat
# cy: sqrt((cos(y)*cos(z))**2 + (cos(x)*cos(y))**2)
cy = math.sqrt(r33*r33 + r23*r23)
if cy > cy_thresh: # cos(y) not close to zero, standard form
z = math.atan2(-r12, r11) # atan2(cos(y)*sin(z), cos(y)*cos(z))
y = math.atan2(r13, cy) # atan2(sin(y), cy)
x = math.atan2(-r23, r33) # atan2(cos(y)*sin(x), cos(x)*cos(y))
else: # cos(y) (close to) zero, so x -> 0.0 (see above)
# so r21 -> sin(z), r22 -> cos(z) and
z = math.atan2(r21, r22)
y = math.atan2(r13, cy) # atan2(sin(y), cy)
x = 0.0
return z, y, x
If I remember correctly, I'd get flipped links when **cy** was just barely greater than **cy_thresh,** so I (somewhat arbitrarily) increased **cy_thresh** to 1e-10 and haven't had issues since then.
https://pdfs.semanticscholar.org/6681/37fa4b875d890f446e689eea1e334bcf6bf6.pdf presents an alternative algorithm that supposedly addresses this concern - but I haven't yet tried it out.
> "... which is 16*FLT_EPSILON in Shoemake’s
> code. (I wasn’t able to tell where
> this magic value came from – maybe
> it’s just a very longlived fudge
> factor.) However, it can be dangerous
> to use in cases which fall just
> outside the threshold."
Mon, 22 Apr 2019 11:37:43 -0500http://answers.gazebosim.org/question/22339/how-to-apply-an-extrinsic-rotation-to-a-link-programmatically/?answer=22342#post-id-22342