Open Dynamics Engine


基本的な手順

簡単に説明すると,まずは『積み木』をするイメージで物体の種類・初期位置&角度を決めます.そして,各々の物体の接続状態(言い換えると,関節)の種類&軸方向を設定するだけです。

順序項目内容
1仮想物理世界の初期設定重力,衝突の条件など
2物体の初期設定種類・サイズ・重量・位置・角度の指定
3関節の初期設定種類・位置・軸方向・角度範囲の指定
4物体のグループ設定グルーピングされた物体同士は,物体間衝突を起きない


仮想物理世界の設定

  • 重力設定
    dWorldSetGravity (world,0,0,-9.8);
  • 物理単位
    距離[m]		角度[rad]			弾性係数[N/m]
    速度[m/s]		角速度[rad/s]		粘性係数[Ns/m]
    加速度[m/s2]	角加速度[rad/s2]	

物体の設定

物体の種類

箱型(Box)球型(Sphere)カプセル型(Capped Cylinder)
ode-box.jpg
ode-sphere.jpg
ode-capped_cylinder.jpg

物体の初期設定プログラムコード

static dBodyID body[3];				// 物体の『存在』
static dGeomID box[1], sphere[1], ccylinder[1];	// 物体の『幾何情報』
  • 箱型(Box)
    body[0]=dBodyCreate(world);					// 物体の存在を生成
    dBodySetPosition(body[0],位置x座標,位置y座標,位置z座標);	// 物体の初期位置
    dMassSetBox(&m,1,長さ,幅,高さ);				// 物体のサイズ設定
    dMassAdjust(&m,重量);					
    dBodySetMass(body[0],&m);					// 物体の重量分布設定
    box[0]=dCreateBox(space,長さ,幅,高さ);			// 物体の幾何情報を生成
    dGeomSetBody (box[0],body[0]);				// 物体の『存在』と『幾何情報』の一致
  • 球型(Sphere)
    body[1] = dBodyCreate (world);				// 物体の存在を生成
    dBodySetPosition (body[1],位置x座標,位置y座標,位置z座標);	// 物体の初期位置
    dMassSetSphere (&m,1,半径);					// 物体のサイズ設定
    dMassAdjust (&m,重量);					// 
    dBodySetMass (body[1],&m);					// 物体の重量分布設定
    sphere[0] = dCreateSphere (space,半径);			// 物体の幾何情報を生成
    dGeomSetBody (sphere[0],body[1]);				// 物体の『存在』と『幾何情報』の一致
  • カプセル型(Capped Cylinder / Capsule)

注意!:カプセル型の半径と長さは,生成する場合には『半径,長さ』だが,描画の場合『長さ,半径』と逆になるので気をつけること.また,カプセル型の全長は,『半径+長さ+半径』となります.

body[2] = dBodyCreate (world);				// 物体の存在を生成
dBodySetPosition (body[2],位置x座標,位置y座標,位置z座標);	// 物体の初期位置
dMassSetCapsule (&m,1,3,半径,長さ);				// 物体のサイズ設定
dMassAdjust (&m,重量);					// 
dBodySetMass (body[2],&m);					// 物体の重量分布設定
ccylinder[0] = dCreateCCylinder (space,半径,長さ);		// 物体の幾何情報を生成
dGeomSetBody (ccylinder[0],body[2]);				// 物体の『存在』と『幾何情報』の一致

サンプルプログラムコード1:三種類の物体生成

物体もどき?RAY(線分)の生成方法

  • 線分描画のみ
    【宣言部】
    #define LENGTH 2;
    static dGeomID ray;
    【描画部】
    // pos0は線分開始座標,pos1は線分終了座標
    dVector3 pos0,pos1;
    dBodyGetRelPointPos(body[0],0,0,0,pos0);
    dBodyGetRelPointPos(body[0],2,0,0,pos1);
    dsDrawLine (pos0,pos1);
    【物体設定部】
    ray=dCreateRay (0,LENGTH);
    // このようにSPACEの設定が0となっている場合,
    // 物体と同じ空間上にいないので,決して衝突しない描画のみの役割を持つ
    // もし各物体と同じ空間に設定した場合,物体がrayに衝突時,激しく飛んでいく.
    // これは,おそらくrayが物体として認識されているが重量を持たないため起こること?


関節の設定

関節の種類

固定ヒンジ1自由度ヒンジ2自由度
ただ固定関節を作成できるが,『動作角度範囲が0°のヒンジ1自由度』を固定関節とするのも可能である.この方法にすると,固定関節から粘弾関節に変換するのが簡単である.
hinge.jpg
hinge2.jpg
スライダボールソケットユニバーサル
slider.jpg
ball-and-socket.jpg
universal.jpg

関節の初期設定プログラムコード

【パラメータ】
kp:弾性係数[N/m]		v:速度[m/s]
kd:粘性係数[Ns/m]		DT:刻み幅[sec]	
* 角度範囲はラジアン表記.(-dInfinity〜0〜+dInfinity)
  • 固定関節
    joint[i] = dJointCreateFixed (world,0);
    dJointAttach (joint[i],body[0],body[1]);
    dJointSetFixed  (joint[i]);
  • ヒンジ1自由度(固定・フリー・粘弾性・モータなど関節状態の具体例
    joint[i] = dJointCreateHinge (world,0);
    dJointAttach (joint[i],body[0],body[1]);
    dJointSetHingeAnchor (joint[i],関節位置x座標,関節位置y座標,関節位置z座標);
    dJointSetHingeAxis (joint[i],軸ベクタx要素,軸ベクタy要素,軸ベクタz要素);
    // dJointSetHingeParam (joint[i],dParamLoStop,角度範囲下限);
    // dJointSetHingeParam (joint[i],dParamHiStop,角度範囲上限);
    // dJointSetHingeParam (joint[i],dParamStopCFM,1/(DT*kp+kd));
    // dJointSetHingeParam (joint[i],dParamStopERP,(DT*kp)/(DT*kp+kd));
    // dJointSetHingeParam (joint[i],dParamVel,速度);
    // dJointSetHingeParam (joint[i],dParamFMax,力の最大値);
    // dJointSetHingeParam (joint[i],dParamFudgeFactor,0.1);
  • ヒンジ2自由度(主に車輪として使用)
    joint[i] = dJointCreateHinge2 (world,0);
    dJointAttach (joint[i],body[2],body[3]);
    dJointSetHinge2Anchor (joint[i],関節位置x座標,関節位置y座標,関節位置z座標);
    dJointSetHinge2Axis1 (joint[i],軸ベクタx要素,軸ベクタy要素,軸ベクタz要素);
    dJointSetHinge2Axis2 (joint[i],軸ベクタx要素,軸ベクタy要素,軸ベクタz要素);
    // dJointSetHinge2Param (joint[i],dParamSuspensionERP,1/(DT*kp+kd));
    // dJointSetHinge2Param (joint[i],dParamSuspensionCFM,(DT*kp)/(DT*kp+kd)); 
    // dJointSetHinge2Param (joint[i],dParamVel,v);
    // dJointSetHinge2Param (joint[i],dParamFMax,力の最大値);
    // dJointSetHinge2Param (joint[i],dParamLoStop,角度範囲下限);
    // dJointSetHinge2Param (joint[i],dParamHiStop,角度範囲上限);
    // dJointSetHinge2Param (joint[i],dParamFudgeFactor,0.1);
  • スライダー関節(固定・フリー・粘弾性・モータなど関節状態の具体例
    joint[i] = dJointCreateSlider(world,0);
    dJointAttach (joint[i],body[4],body[5]);
    dJointSetSliderAxis (joint[i],軸ベクタx要素,軸ベクタy要素,軸ベクタz要素);
    // dJointSetSliderParam (joint[i],dParamLoStop,位置範囲下限);
    // dJointSetSliderParam (joint[i],dParamHiStop,位置範囲上限);
    // dJointSetSliderParam (joint[i],dParamVel,v);
    // dJointSetSliderParam (joint[i],dParamFMax,力の最大値);
    // dJointSetSliderParam (joint[i],dParamStopCFM,1/(DT*kp+kd));
    // dJointSetSliderParam (joint[i],dParamStopERP,(DT*kp)/(DT*kp+kd)); 
    // dJointSetSliderParam (joint[i],dParamFudgeFactor,0.1);
  • ボールソケット関節
    joint[i] = dJointCreateBall (world,0);
    dJointAttach (joint[i],body[6],body[7]);
    dJointSetBallAnchor (joint[i],関節位置x座標,関節位置y座標,関節位置z座標);
  • ユニバーサルジョイント(固定・フリー・粘弾性・モータなど関節状態の具体例はヒンジ関節と同様
    joint[i] = dJointCreateUniversal (world,0);
    dJointAttach (joint[i],body[8],body[9]);
    dJointSetUniversalAnchor (joint[i],関節位置x座標,関節位置y座標,関節位置z座標);
    dJointSetUniversalAxis1 (joint[i],軸ベクタx要素,軸ベクタy要素,軸ベクタz要素);
    dJointSetUniversalAxis2 (joint[i],軸ベクタx要素,軸ベクタy要素,軸ベクタz要素);
    // dJointSetUniversalParam (joint[i],dParamLoStop,角度範囲下限);
    // dJointSetUniversalParam (joint[i],dParamHiStop,角度範囲上限);
    // dJointSetUniversalParam (joint[i],dParamLoStop2,角度範囲下限);
    // dJointSetUniversalParam (joint[i],dParamHiStop2,角度範囲上限);
    // dJointSetUniversalParam (joint[i],dParamVel,速度);
    // dJointSetUniversalParam (joint[i],dParamVel2,速度);
    // dJointSetUniversalParam (joint[i],dParamFMax,力の最大値);
    // dJointSetUniversalParam (joint[i],dParamFMax2,力の最大値);
  • 【補足】:dParam設定
    dParamLoStop	| 角度[rad](距離[m])範囲の下限
    dParamHiStop	| 角度[rad](距離[m])範囲の上限
    dParamStopCFM	| 範囲上下限部位の粘弾性 1/(DT*kp+kd))=cfm値
    dParamStopERP	| 範囲上下限部位の粘弾性 (DT*kp)/(DT*kp+kd))=erp値
    dParamVel		| 関節回転(移動)速度[m/s](ギアモータの電圧調整に相当)
    dParamFMax	| 速度負荷における力の最大値[N](ギアモータの最大トルクに相当)
    dParamFudgeFactor	| 0.1

サンプルプログラムコード2:六種類の関節例

なお,サンプルプログラムコード1とは,各物体の幾何情報の『space』への登録方法で大きく異なる.各物体生成時には登録せず,グルーピング時に『space』への登録を行っている(以下参照).グルーピングにおいて登録する理由は,登録した物体間の接触を無効にするためである.もし,各物体生成時に,登録してしまうと各物体が接触してしまい,関節が曲がらなくなる.グルーピングの節を参照してください.


関節のデータ取得

  • ODE表記
    void dJointSetFeedback (dJointID, dJointFeedback *);
    dJointFeedback *dJointGetFeedback (dJointID);
    typedef struct dJointFeedback {
      dVector3 f1;       // force that joint applies to body 1
      dVector3 t1;       // torque that joint applies to body 1
      dVector3 f2;       // force that joint applies to body 2
      dVector3 t2;       // torque that joint applies to body 2
    } dJointFeedback;

 このコマンドにより,関節の力&トルクの状態を獲得することができます.

【cppの頭】
// 変数宣言
dJointFeedback *joint_data0;
dJointFeedback *joint_data1;
【main内】
// 固定関節の設定
joint[i] = dJointCreateFixed (world,0);
dJointAttach (joint[i],body[0],body[1]);
dJointSetFixed  (joint[i]);
// 固定関節の関節状態
// まず第一に,joint_data0のデータ領域確保が重要となる.
// 領域確保をしなければエラーとなり,シミュレーションが開始されない. 
joint_data0 = (dJointFeedback *)malloc(sizeof(dJointFeedback));
dJointSetFeedback(joint[i], joint_data0);
joint_data0 = dJointGetFeedback(joint[i]);

// ヒンジ1自由度関節の設定
joint[i] = dJointCreateHinge (world,0);
dJointAttach (joint[i],body[2],body[3]);
dJointSetHingeAnchor (joint[i],joint_x[i],joint_y[i],joint_z[i]);
dJointSetHingeAxis (joint[i],0,1,0);
dJointSetHingeParam (joint[i],dParamLoStop,-dInfinity);
dJointSetHingeParam (joint[i],dParamHiStop,dInfinity);
dJointSetHingeParam (joint[i],dParamVel,1);
dJointSetHingeParam (joint[i],dParamFMax,2000.0);
joint_data1 = (dJointFeedback *)malloc(sizeof(dJointFeedback));
dJointSetFeedback(joint[i], joint_data1);
joint_data1 = dJointGetFeedback(joint[i]);
【Simloop内】
printf("%2.2f %2.2f %2.2f %2.2f %2.2f %2.2f\n",
	joint_data0->f1[0],joint_data0->f1[1],joint_data0->f1[2],
	joint_data0->t1[0],joint_data0->t1[1],joint_data0->t1[2]);
printf("%2.2f %2.2f %2.2f %2.2f %2.2f %2.2f\n",
	joint_data1->f1[0],joint_data1->f1[1],joint_data1->f1[2],
	joint_data1->t1[0],joint_data1->t1[1],joint_data1->t1[2]);

サンプルプログラムコード3:関節の力&トルク値出力

物体のグルーピング(関節を構成する2物体の衝突を無効)

1. グルーピングを行う例

以下のコードを利用し,複数物体を一つの物体とする方法.グルーピングされた物体同士の衝突は無効化され,計算量が軽減される.

dSpaceID dSimpleSpaceCreate (dSpaceID space);
void dSpaceAdd (dSpaceID, dGeomID);
【各々物体ごとに登録する場合】
box[0]=dCreateBox(space,長さ,幅,高さ);
sphere[0] = dCreateSphere (space,半径);
ccylinder[0] = dCreateCCylinder (space,長さ,半径);
↓
【各物体を生成した後,グルーピング時に登録する場合】
box[0]=dCreateBox(0,長さ,幅,高さ);
sphere[0] = dCreateSphere (0,半径);
ccylinder[0] = dCreateCCylinder (0,長さ,半径);
geom_group = dSimpleSpaceCreate (space);  
dSpaceSetCleanup (geom_group,0);
dSpaceAdd(geom_group,box[0]);
dSpaceAdd(geom_group,sphere[0]);
dSpaceAdd(geom_group,ccylinder[0]);

2. グルーピングせずに,物体衝突を無効化する例

 ただしグルーピングした場合,グルーピングした物体の接触状態を判断することは不可能にある(グルーピング物体のgeom設定が無いためである).その場合は,グルーピングを止め,任意物体間の接触計算をnearCallbackルーチンの頭で無効する方法が有効です.つまり,グルーピングせず特定の物体との衝突を無効することでその物体のgeom情報を残すことができるので,物体接触判定ができる(タッチセンサ参照).

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
int i,n;
// 指定する2物体の衝突有無を設定
if((o1==box[0])&&(o2==box[1])||(o2==box[0])&&(o1==box[1]))return;
const int N = 10;
dContact contact[N];

サンプルプログラムコード4:関節とグルーピングの関係

 このサンプルプログラムには,三種類の関節例をしめしている.各関節は,モータとなっており,常に回転するようになっている.

  1. グルーピングした物体により構成される関節(左側)
  2. グルーピングしない物体により構成される関節(真ん中)
  3. 先に紹介したグルーピングせずに物体衝突を無効化して構成される関節(右側)


注目すべきは,1番目と3番目が同様に回転しているのに対して,2番目は物体を透過できず止まってしまう.なお,ここでは各関節にかかるトルク(dParamMax)を50というように小さい値に設定している.万一,1000など大きな値にする場合2番目の関節の生じるトルクは物体間の反発力に打ち勝ち,強引に回転することとなる.


添付ファイル: filesample04.cpp 2274件 [詳細] filesample03.cpp 2168件 [詳細] filesample02.cpp 3175件 [詳細] filesample01.cpp 6086件 [詳細] fileuniversal.jpg 1049件 [詳細] fileslider.jpg 1141件 [詳細] filehinge.jpg 1355件 [詳細] filehinge2.jpg 1049件 [詳細] fileball-and-socket.jpg 972件 [詳細] fileode-capped_cylinder.jpg 987件 [詳細] fileode-sphere.jpg 962件 [詳細] fileode-box.jpg 1165件 [詳細]

トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2010-08-02 (月) 12:44:04 (2578d)