RoboCup Japan Open 2008沼津 ヒューマノイドリーグはTeam Osaka優勝 35万ページビュー
5 月 12
らりほーさんから回転行列のご質問があり,その回答も兼ねて久しぶりにODE (Open Dynamics Engine)講座を開講します. 回転行列は,基準の姿勢から現在の姿勢を行列で表したものです.回転行列は3行3列の行列ですが,ODEでは計算を高速化させるために,回転行列の各成分を要素数12個の1次元配列に格納しています. 回転行列のi行j列成分をrijとすると,回転行列の配列は以下で表すことができます(ODE本P103参照).4番目、8番目、12番目の要素は数字の0(ゼロ)です。 dReal R[12] = {r11, r12, r13, 0, r21, r22, r23, 0, r31, r32, r33,0}; なお、ODEの回転行列はdMatrix3型で、src/ode-バージョン番号/include/ode/common.hで次のように定義されています。
  • typedef dReal dMatrix3[4*3] ;
つまり、要素数12個のdReal(ODEの実数型)型配列です。 これがわかるとロール(roll)・ピッチ(pitch)・ヨー(yaw)角をODEの回転行列から求めることができます.ロール・ピッチ・ヨー角の回転行列は,絶対座標系のx軸まわりにroll角度回転,次にy軸のまわりにpitch角度回転,最後にz軸のまわりにyaw角度回転させたものとなります.ここでは導出しませんが,次式で求めることができます(ODE本P149参照) roll = atan2(r32, r33); pitch = atan2(-r31, sqrt(r32*r32+r33*r33)) または atan2(-r31, -sqrt(r32*r32+r33*r33)); yaw = atan2(r21, r11); これを使ったサンプルプログラムの主要部分を以下に示します.完全なプログラムのダウンロードはこちらから. 今回はこの辺で...
C++:
  1. // roll, pitch, yawのサンプルプログラム
  2. // rpy.cpp by Kosei Demura (2008-5-12)
  3.  
  4. dWorldID world;  // 動力学計算用ワールド
  5. dReal START_X = 0, START_Y = 0, START_Z=1.20; // 初期位置
  6. dReal weight    = 9.4;                        // ボックスの質量
  7. dReal size[3]   = {0.5,0.1,0.3};              // ボックスのサイズ
  8.  
  9. typedef struct {            // MyObject構造体
  10.     dBodyID body;       // ボディ(剛体)のID番号(動力学計算用)
  11.     dReal  lx, ly, lz;  // 長さ[m]
  12. } MyObject;
  13.  
  14. MyObject box;  // MyObject構造体
  15.  
  16. // ロール・ピッチ・ヨー角の計算 ODE本P150
  17. static void rollPitchYaw()
  18. {
  19.     const dReal *rot = dBodyGetRotation(box.body);
  20.     dReal r11,r12,r13,r21,r22,r23,r31,r32,r33;
  21.     dReal pitch, yaw, roll;
  22.  
  23.     r11 = rot[0];    r12 = rot[1];    r13 = rot[2];
  24.     r21 = rot[4];    r22 = rot[5];    r23 = rot[6];
  25.     r31 = rot[8];    r32 = rot[9];    r33 = rot[10];
  26.     // ポインタ的表記では r11 = *(rot+0); r12 = *(rot+1); r13 = *(rot+2);
  27.  
  28.     pitch = atan2(-r31, sqrt(r32*r32+r33*r33));
  29.     yaw   = atan2(r21,r11);
  30.     roll  = atan2(r32,r33);
  31.  
  32.     printf("roll=%f pitch=%f yaw=%f  r", 180.0*roll/M_PI, 180.0*pitch/M_PI, 180.0*yaw/M_PI);
  33. }
  34.  
  35. // 絶対座標系x軸,y軸,z軸の順番で回転
  36. static void rotation()
  37. {
  38.     static dReal angle_x = 45, angle_y = 0, angle_z = 90;
  39.     const dReal *R0;
  40.     dMatrix3 R1, R2, R3, R10, R20, R30;
  41.  
  42.     R0 = dBodyGetRotation(box.body);
  43.  
  44.     dRFromAxisAndAngle(R1, 1, 0, 0, M_PI*angle_x/180.0); // x軸まわり
  45.     dRFromAxisAndAngle(R2, 0, 1, 0, M_PI*angle_y/180.0); // y軸まわり
  46.     dRFromAxisAndAngle(R3, 0, 0, 1, M_PI*angle_z/180.0); // z軸まわり
  47.  
  48.     dMultiply0(R10, R1,  R0, 3, 3, 3);
  49.     dMultiply0(R20, R2, R10, 3, 3, 3);
  50.     dMultiply0(R30, R3, R20, 3, 3, 3);
  51.  
  52.     dBodySetRotation(box.body, R30);
  53. }
  54.  
  55. static void simLoop(int pause)
  56. {
  57.     rollPitchYaw();
  58.     dWorldStep(world,0.01);
  59.     dsSetColor(1.0,0.0,0.0);
  60.     dsDrawBox(dBodyGetPosition(box.body),
  61.     dBodyGetRotation(box.body),size);
  62. }
  63.  
  64. // ボックスの生成
  65. void makeBox()
  66. {
  67.     dMass mass;
  68.  
  69.     box.body  = dBodyCreate(world);
  70.     dMassSetZero(&mass);
  71.     dMassSetBoxTotal(&mass, weight, size[0], size[1], size[2]);
  72.     dBodySetMass(box.body, &mass);
  73.     dBodySetPosition(box.body,START_X,START_Y,START_Z);
  74. }
  75.  
  76. int main(int argc, char **argv)
  77. {
  78.     setDrawStuff();
  79.     world = dWorldCreate();                  // 動力学計算ワールドの作成
  80.     makeBox();                               // ボックスの作成
  81.     rotation();                              // 回転
  82.     dsSimulationLoop(argc,argv,640,480,&fn); // シミュレーションループ
  83.     dWorldDestroy(world);                    // ワールドの破壊
  84.     return 0;
  85. }

投稿:08年05月12日

Leave a Reply

カウンタ (since 2008-1-11)
Copyright © 1998-2008    Kosei Demura