LoginSignup
2
0

More than 3 years have passed since last update.

【姿勢計算】Euler角と回転行列

Last updated at Posted at 2021-01-24

はじめに

回転計算について、何度も調べては実装を繰り返しています。今回もまた調べて実装したので、メモっておきます。

姿勢計算は、自動運転やロボティクスでは必ず使われます。3つの軸xyz の正規直行系が、回転操作により3次元空間で変化してきます。
姿勢情報はいくつか表現がありますが、初期の姿勢から回転操作によるある姿勢に達するので、回転操作と姿勢は同じような数式の表現になります。

  • 回転操作あるいは姿勢を表すのには、回転行列、四元数、回転ベクトル(so(3))などあります。
  • 回転操作の時間微分にあたる角速度(ベクトル)については、位置のような単純な積分にはならないので、その計算方法が必要です。
  • 物理の解析力学ではオイラー角はZ-Y-Zの順で回転させると定義します。どちらから見ても同じ順序になって便利と。これは、工学で使用しているオイラー角とは異なるものなので要注意。

Euler角と回転行列

ここでは、良く使うroll, pitch, yaw と回転行列の変換を整理します。
地球上の位置座標は緯度、経度、楕円体高(地球を楕円体でモデル化)が用いられます。
姿勢を表すには、方位角(azimuth)、仰角(elevation)などが用いられます。これらの関係について整理します。

Euler角から回転行列

グローバル座標の軸とローカル座標の軸が一致した状態を最初に考えます。
そこから、

  1. まずローカル座標系のZ軸をつまんで、$\psi$ だけ回転させます。この状態では、ローカル座標系はグローバル座標系と同じXY平面上に乗っています。
  2. つぎにローカル座標系のY軸をつまんで$\theta$だけ回転させます。この状態では、ローカル座標系のX軸はグローバル座標系のXY平面から$\theta$だけ上向き(回転角が負なら下向き)になっています。
  3. さらに、ローカル座標軸のX軸をつまんで$\phi$だけ回転させます。

この3つの操作で、任意のローカル座標系の姿勢に変換することができます。ここで回転させたX軸、y軸、z軸周りの回転はそれぞれroll, pitch, yaw と呼ばれます。これらをEuler角と呼ぶようです。

\textrm{U}_{local} = \textrm{U}_{global} R_z(\psi) R_y(\theta) R_x(\phi)

です。Uは回転行列で、xyz軸を並べたものです。

\textrm{U} = \left[ \textrm{u}_x,\textrm{u}_y,\textrm{u}_z\right] 

ローカル座標系のxyzなら姿勢と呼ばれますし、グローバル座標ならxyz軸がそれぞれの軸の単位ベクトルを表すのでUは単位行列になります。

各軸の周りの回転は以下のように計算できます。

from numpy import ndarray, pi
from numpy import array, sin, cos, dot, arctan2, arcsin, deg2rad, rad2deg

def Rx(r:float) -> ndarray:
    """
    Parameters
    ----------
    r, roll angle in radian
    """
    cr, sr = cos(r), sin(r)
    return array( [ [1.0, 0., 0.0],\
                    [0.0, cr, -sr], \
                    [0.0, sr, cr]])

def Ry(p:float) -> ndarray:
    """
    Parameters
    ----------
    p, pitch angle in radian
    """
    ry = [  [cos(p), 0., sin(p)],\
            [0.0, 1.0, 0.0], \
            [-sin(p), 0.0, cos(p)]]
    return array(ry)

def Rz(y:float) -> ndarray:
    """
    Parameters
    ----------
    y, yaw angle in radian
    """
    rz = [  [cos(y), -sin(y), 0.0],\
            [sin(y), cos(y), 0.0], \
            [0.0, 0.0, 1.0]]
    return array(rz)

これらを計算した結果は、下記の通りになります。当然、直接3つの行列を書けても同じ結果になりますが。

また、式から明らかですが、math U_{local} の各列は、ローカル座標のx、y、z軸のグローバル座標での表現になっています。

回転行列からEuler角

回転行列を書き下した形から、逆三角関数を使ってもとめることができます。いろいろな求め方がありますが、次の方法がよく用いられています。

def R2euler(R:ndarray) -> list:
    """
    Convert rotation matrix to Euler angles
    Parameters
    ----------
    R, rotation matrix
    Returns
    -------
    Euelr angles in radian.
    r, roll
    p, pitch
    y, yaw
    """
    # ジンバルロックを無視すると、、、
    return [ arctan2(R[2,1], R[2,2]), arcsin(-R[2,0]), arctan2(R[1,0], R[0,0]) ]

ジンバルロック

注意すべきはpitch が$\theta=\frac{\pi}{2}$ or $\theta=-\frac{\pi}{2}$ のときです。実際に、回転行列を計算してみると分かります。

\begin{eqnarray}
 \textrm{R}_z(\psi)  \textrm{R}_y(\pi/2)  \textrm{R}_x(\phi) 
&=& \left[\begin{array}{ccc}
\cos(\psi) & -\sin(\psi) & 0\\
\sin(\psi) & \cos(\psi) & 0 \\
0 & 0 & 1
\end{array} 
\right]
\left[\begin{array}{ccc}
0 & 0 & 1\\
0 & 1 & 0\\
-1 & 0 & 0
\end{array}
\right]
\left[\begin{array}{ccc}
1 & 0 & 0 \\
0 & \cos\phi & -\sin\phi\\
0 & \sin\phi & \cos\phi  \\
\end{array}
\right] \\
& = &
\left[\begin{array}{ccc}
0 & -\sin(\psi-\phi) & \cos(\psi-\phi) \\
0 & \cos(\psi-\phi) & \sin(\psi-\phi)\\
-1 & 0 & 0  \\
\end{array}
\right]
\end{eqnarray}

となります。ローカル座標のx軸が [0, 0, -1] となっている、つまりY軸方向に90度回転して下向きになっているのが分かります。そして重要なのが、Y軸、Z軸はグローバル座標のXY平面にいるのですが、回転の自由度は1しかなく、その大きさは$\psi-\phi$です。つまりroll と yaw は差だけが決まるが、個々の値は不定となっています。

では、このような場合、どのようにEuler角に戻したらよいでしょうか。一つの方法では、rollを0としてyaw の値を定める方法があるようです。そのような実装を見かけます。

メモ

scipy

回転計算がquaternion, rotation vector も含めて一通りそろっている様子。最初からこれを使えばよいのか。

その他

まとめ

エイやで書いていて、この記事も含め、修正しつつ、良い内容にに仕上げていきたいと思います。下記途中ですが、投稿してしまいます。

本日はまずはEuler角と回転行列の相互変換を実装しました。最終的にはquaternionやso(3)、IMUを用いた慣性航法の式まで説明できたらと思います。

(2021/01/24)

編集メモ

  • 雑なジンバルロックの説明(数式による)を追加 (2021/01/26)
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0