1 月 16
図:2リンク機構に初期角速度を与えるシミュレーション
CohCohさんのご質問で初期の関節角速度の設定法がありましたので、久しぶりにODE(Open Dynamics Engine)講座を開講します。
ODEでは関節にモータが標準で付属していますが、関節角速度を設定しようとしても、目標角速度に到達するまで時間がかかりますし、その角速度を維持するためにはそれなりの制御が必要です。現実のモータを単純にモデル化したものです。
これでは、初期角速度を設定できません。この問題を解決する方法として、ODEには理想的なAMOTORがあります。マニュアルでは1ステップで目標角速度に到達するとありますが、関節に与える最大トルクdParamFmaxの値が0だと目標角速度に到達しません。また、小さな値の場合は、目標角速度に到達するまで数ステップかかることを確認しました。
そこで、十分大きな値を設定してください。以下のサンプルプログラムでは目標角速度dParamVelに無限大dInifinityを与えています。
また、初期角速度だけ与えたい場合は、角速度が目標値に到達したら、dJointDestroy()でamotorを破壊する必要があります。これを忘れると常に角速度は目標角速度のままです。amotorを破壊したくない場合は、dJointSetAMotorNumAxes(amotor, 0)で制御する軸数を0に設定し、無効化してもOKです。
次に、APIを紹介します。
dJointID dJointCreateAMotor(dWorldID, dJointGroupID); AMOTORの生成。 void dJointSetAMotorMode(dJointID, int mode); AMOTORのモード設定。modeはユーザが独自に設定するdAMotorUserまたは、自動的にオイラー角が計算されるdAMotorEulerの2つのモードがある。 void dJointSetAMotorNumAxes(dJointID, int num); AMOTORでコントロールされる軸数を設定する。numの値は0から3までで、0の場合はジョイントを無効化する。dAMotorEulerモードの場合は自動的に3が設定される。 void dJointSetAMotorAxis (dJointID, int anum, int rel, dReal x, dReal y, dReal z); AMOTORの回転軸を設定する。引数anumは変更する軸(0, 1, 2)、relは以下の相対回転モードを設定する。最後の(x,y,z)は回転軸ベクトル。AMOTORはAngular Motorの略ですが、エー(良い)モータですね。ソースコードを以下に示しますので試してください。 なお、簡単にするために衝突検出機能は実装されていません。ここからダウンロード可能です(amotor2-080115.tgz)。void dJointSetAMotorParam (dJointID, int parameter, dReal value); AMOTORのパラメータを設定する。 parameterについては他のジョイントと同じ。この例では角速度(スライダージョイントの場合は速度)dParamVel、最大発揮トルクdParamFMaxを使用した。
- 0: 軸は絶対座標系に固定
- 1: 1番目のボディに固定
- 2: 2番目のボディに固定
CODE:
- // 2008-1-15
- // amotor2.c: 2 Links with an amotor by Kosei Demura
- #include
- #include
- #include
- #include
- #define NUM 2
- #ifdef dDOUBLE
- #define dsDrawCylinder dsDrawCylinderD
- #endif
- dWorldID world;
- dSpaceID space;
- dGeomID ground;
- dJointID joint[NUM], amotor;
- dsFunctions fn;
- typedef struct {
- dBodyID body;
- dGeomID geom;
- } MyLink;
- MyLink rlink[NUM];
- void createArm()
- {
- dReal init_avel = 1.0; // 初期角速度[rad/s]
- dMass mass;
- dReal x[] = { 0.00, 0.00}, y[] = { 0.00, 0.00}, z[]= { 0.75 ,0.25}; // 重心
- dReal length[] = { 0.50, 0.50}; // リンク長
- dReal weight[] = { 1.00, 1.00}; // 質量
- dReal r[] = { 0.02, 0.02}; // 半径
- dReal anchor_x[] = { 0.00, 0.00}; // 回転軸中心
- dReal anchor_y[] = { 0.00, 0.00};
- dReal anchor_z[] = { 1.00, 0.50};
- dReal axis_x[] = { 1.00, 1.00}; // 回転軸ベクトル
- dReal axis_y[] = { 0.00, 0.00};
- dReal axis_z[] = { 0.00, 0.00};
- // リンクの生成
- for (int i = 0; i <NUM; i++) {
- rlink[i].body = dBodyCreate(world);
- dBodySetPosition(rlink[i].body, x[i], y[i], z[i]);
- dMassSetZero(&mass);
- dMassSetCylinderTotal(&mass,weight[i],3,r[i],length[i]);
- dBodySetMass(rlink[i].body, &mass);
- rlink[i].geom = dCreateCylinder(space,r[i],length[i]);
- dGeomSetBody(rlink[i].geom,rlink[i].body);
- }
- //ジョイントの生成と結合
- for (int j = 0; j <NUM; j++) {
- joint[j] = dJointCreateHinge(world, 0);
- // リンク1はjoint[0]により静的環境0と結合
- if (j == 0) dJointAttach(joint[0], rlink[0].body, 0);
- else dJointAttach(joint[j], rlink[j].body, rlink[j-1].body);
- dJointSetHingeAnchor(joint[j], anchor_x[j], anchor_y[j], anchor_z[j]);
- dJointSetHingeAxis(joint[j], axis_x[j], axis_y[j],axis_z[j]);
- }
- // リンク1とリンク2を結合しているジョイントを可動域設定
- dJointSetHingeParam(joint[1], dParamLoStop, -0.0 * M_PI); // 可動域の下限
- dJointSetHingeParam(joint[1], dParamHiStop, 0.0 * M_PI); // 可動域の上限
- // amotorの生成
- amotor = dJointCreateAMotor(world, 0); // AMotorの生成
- dJointAttach(amotor, rlink[0].body, 0); // AMotorとリンクとの結合
- dJointSetAMotorMode(amotor, dAMotorUser); // ユーザモードに設定、デフォルト、省略可
- dJointSetAMotorNumAxes(amotor, 1); // AMotorでコントロールする軸数
- // 軸の設定:回転軸0を絶対座標系に固定、回転軸ベクトルは(1, 0, 0)
- dJointSetAMotorAxis(amotor, 0 /*軸0*/, 0 /*絶対座標系に固定*/, 1 /*x成分*/, 0 /*y成分*/, 0 /*z成分*/);
- // amotorの設定, 初期角速度をinit_avelに設定
- dReal fmax = dInfinity; // 無限大
- dJointSetAMotorParam(amotor, dParamVel, init_avel);
- dJointSetAMotorParam(amotor, dParamFMax, fmax);
- }
- void drawLink()
- {
- dReal r,length;
- for (int i = 0; i <NUM; i++ ) {
- if (i == 1) dsSetColor(1.3, 1.3, 0.0);
- else dsSetColor(0.0, 0.0, 1.3);
- dGeomCylinderGetParams(rlink[i].geom, &r,&length);
- dsDrawCylinder(dBodyGetPosition(rlink[i].body),
- dBodyGetRotation(rlink[i].body),length,r);
- }
- }
- void start()
- {
- float xyz[3] = { 2, 0, 1};
- float hpr[3] = {-180, 0, 0.0};
- dsSetViewpoint(xyz,hpr);
- }
- // 簡単にするため衝突検出は未実装
- void simLoop(int pause)
- {
- static int step = 0;
- drawLink();
- const dReal ang_rate = dJointGetHingeAngleRate(joint[0]);
- printf("step=%4d: angle rate=%8.6f \n", step, ang_rate);
- dWorldStep(world, 0.001);
- dReal k1 = 0.0; // 摩擦トルク用比例係数 負値を設定
- dJointAddHingeTorque(joint[0], k1 * ang_rate); // 摩擦トルクを付加
- if (step == 0) dJointDestroy(amotor); // amotorの破壊
- // amotorを破壊したくない場合は以下でも良い
- // if (step == 0) dJointSetAMotorNumAxes(amotor, 0);
- step++;
- }
- void setDrawStuff() {
- fn.version = DS_VERSION;
- fn.start = &start;
- fn.step = &simLoop;
- fn.path_to_textures = "../../drawstuff/textures";
- }
- int main(int argc, char *argv[])
- {
- setDrawStuff();
- world = dWorldCreate();
- space = dHashSpaceCreate(0);
- // dWorldSetGravity (world, 0, 0, -9.8); // 重力加速度
- createArm();
- dsSimulationLoop(argc,argv,640, 480,&fn);
- dSpaceDestroy(space);
- dWorldDestroy(world);
- return 0;
- }
終わり。
投稿:08年01月16日

