らりほーさんから回転行列のご質問があり,その回答も兼ねて久しぶりに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);
これを使ったサンプルプログラムの主要部分を以下に示します.完全なプログラムのダウンロードはこちらから.
今回はこの辺で…
[cpp] // roll, pitch, yawのサンプルプログラム // rpy.cpp by Kosei Demura (2008-5-12) dWorldID world; // 動力学計算用ワールド dReal START_X = 0, START_Y = 0, START_Z=1.20; // 初期位置 dReal weight = 9.4; // ボックスの質量 dReal size[3] = {0.5,0.1,0.3}; // ボックスのサイズ typedef struct { // MyObject構造体 dBodyID body; // ボディ(剛体)のID番号(動力学計算用) dReal lx, ly, lz; // 長さ[m] } MyObject; MyObject box; // MyObject構造体 // ロール・ピッチ・ヨー角の計算 ODE本P150 static void rollPitchYaw() { const dReal *rot = dBodyGetRotation(box.body); dReal r11,r12,r13,r21,r22,r23,r31,r32,r33; dReal pitch, yaw, roll; r11 = rot[0]; r12 = rot[1]; r13 = rot[2]; r21 = rot[4]; r22 = rot[5]; r23 = rot[6]; r31 = rot[8]; r32 = rot[9]; r33 = rot[10]; // ポインタ的表記では r11 = *(rot+0); r12 = *(rot+1); r13 = *(rot+2); pitch = atan2(-r31, sqrt(r32*r32+r33*r33)); yaw = atan2(r21,r11); roll = atan2(r32,r33); printf("roll=%f pitch=%f yaw=%f r", 180.0*roll/M_PI, 180.0*pitch/M_PI, 180.0*yaw/M_PI); } // 絶対座標系x軸,y軸,z軸の順番で回転 static void rotation() { static dReal angle_x = 45, angle_y = 0, angle_z = 90; const dReal *R0; dMatrix3 R1, R2, R3, R10, R20, R30; R0 = dBodyGetRotation(box.body); dRFromAxisAndAngle(R1, 1, 0, 0, M_PI*angle_x/180.0); // x軸まわり dRFromAxisAndAngle(R2, 0, 1, 0, M_PI*angle_y/180.0); // y軸まわり dRFromAxisAndAngle(R3, 0, 0, 1, M_PI*angle_z/180.0); // z軸まわり dMultiply0(R10, R1, R0, 3, 3, 3); dMultiply0(R20, R2, R10, 3, 3, 3); dMultiply0(R30, R3, R20, 3, 3, 3); dBodySetRotation(box.body, R30); } static void simLoop(int pause) { rollPitchYaw(); dWorldStep(world,0.01); dsSetColor(1.0,0.0,0.0); dsDrawBox(dBodyGetPosition(box.body), dBodyGetRotation(box.body),size); } // ボックスの生成 void makeBox() { dMass mass; box.body = dBodyCreate(world); dMassSetZero(&mass); dMassSetBoxTotal(&mass, weight, size[0], size[1], size[2]); dBodySetMass(box.body, &mass); dBodySetPosition(box.body,START_X,START_Y,START_Z); } int main(int argc, char **argv) { setDrawStuff(); world = dWorldCreate(); // 動力学計算ワールドの作成 makeBox(); // ボックスの作成 rotation(); // 回転 dsSimulationLoop(argc,argv,640,480,&fn); // シミュレーションループ dWorldDestroy(world); // ワールドの破壊 return 0; } [/cpp]
コメント