Open Dynamics Engine


特定の2物体の衝突有無に関する処理方法

各物体がそれぞれspaceに登録されているとき(addspaceでグルーピングされている物体群がない場合)

 基本的にnearCallbackルーチン内では,1ステップにおけるすべての物体間衝突の計算が行われているので,このルーチン内にプログラムコードを追加すること(下記のプログラム内の位置)で,特定の2物体間の衝突における例外処理が可能である.
ここで使用できる変数は,『ground』や『box[0]』などdGeomIDで設定されているもののみである.dSpaceIDで宣言されている変数を記述するとエラーが起きる.その解決法は,次節を参照してください.

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  int i,n;
  //----------------------------
  この部分に追加
static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  int i,j,n;

// 各ボックスの衝突を無効	
  for(i=0;i<6;i++){
	  for(j=0;j<6;j++){
		  if(i!=j){
			  if((o1==box[i]&&o2==box[j])||(o2==box[i]&&o1==box[j]))break;
		  }
	  }
  }
  //----------------------------
  const int N = 10;
  dContact contact[N];
  • 物体と地面との衝突以外は,計算しない.→物体は地面と衝突するが,物体間の衝突は起こらない.
    if(o1==ground || o2==ground){}
    else {return;}
  • 物体box[0]と物体[1]の衝突は,計算しない.→これら2物体は間の衝突は起こらない.
    if((o1==box[0] && o2==box[1])||(o1==box[1] && o2==box[2]){return;}

addspaceによるグルーピングが行われている物体群がある場合

 関節などになった複数物体でaddspaceによってグルーピングされているものは,このルーチンに内においては1物体としてカウントされる.しかしながら,グルーピングされた物体群は各物体とは違い,geom変数として扱われることができない.ここでは変則的な方法でgeomとして扱う方法を紹介する.その変則的な方法とは,dGeomID変数とdSpaceID変数を両方ともint型に変換し,取り扱う方法である.コンパイラのとき警告は出るが,int型に変換することで,同様の変数として扱うことができる.

static dGeomID box[1]; // 1物体
static dSpaceID geom_group; // 関節を構成する物体群

static void nearCallback (void *data, dGeomID o1, dGeomID o2)
{
  int i,n;
  //----------------------------
  int o1i,o2i;
  o1i=(int)o1;
  o2i=(int)o2;
 if((o1i==(int)box[0])&&(o2i==(int)geom_group)
                         ||(o2i==(int)box[0])&&(o1i==(int)geom_group))return;
  //----------------------------
  const int N = 10;
  dContact contact[N];

物体間における衝突状態を決定する『nearCallback』設定方法

コンタクト数Nの設定

 nearcallback内では,物体の衝突の計算が行われる.物体間のコンタクトの数Nを越えてしまうと,それ以上の衝突計算ができなくなり,物体を透過してしまう.また,Nの値を大きくしてしまうと計算時間が長くなってしまうため,適切な値にすることが望まれる.

const int N = 10;
dContact contact[N];
n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact)); 

衝突点数の検出

 物体間の衝突は,球単体の場合は1点,カプセル型の場合は1〜2点,箱型の場合は1〜3点となる.また,物体群においては,もっと多くの衝突点を確保することとなるだろう.

// 二物体の衝突状態
  const int N = 10;
  dContact contact[N];
  n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
  //-------------------------------------------------
  // ここで『特定二物体間の衝突点数』nの値を確認
  if(((o1==box[0])&&(o2==ground))||((o1==ground)&&(o2==box[0]))){
	  touch_num=n; 
  }
  //-------------------------------------------------
  if (n > 0) {
    for (i=0; i<n; i++) {

衝突点の摩擦設定

クーロン摩擦の設定(通常の方法)

 通常の方法である.一応,静摩擦と動摩擦が設定できる.静摩擦を設定したい場合は,『dContactApprox1』のフラグを追加する.その場合,『surface.mu=1』に対応する力まで物体は滑らない.それに対し『dContactApprox1』のフラグを立てない場合は,静摩擦は無く,『surface.mu=1』に対応する動摩擦力のみ適用される.

// 摩擦無限大(すべらない):dInfinity,摩擦無(すべる):0,一般的な摩擦:1付近
// フラグの設定:dContactApprox1;
contact[i].surface.mu=1;
// contact[i].surface.mu = dInfinity;

FDS摩擦の設定(ODEの特殊な方法)

 FDSは特殊の方法である.簡単にいうと,小さい力を付加するとそれに対応して物体は路面を滑り,力を増加させた場合,ある設定した値に速度が到達すると,突然,摩擦が生じるというものである.この効果は,ある意味上記したクーロン摩擦である(クーロン摩擦では,付加力が弱い場合動かず,付加力が強い場合滑り出す).今一、この摩擦の有用性はわからないが,おそらく,車の場合のコーナリングに有用ということでないだろうか?コーナリングの場合,進行方向に対して直交方向でのすべりが重要となるのでは?

dContactSlip1 | dContactSlip2
contact[i].surface.mu=dInfinity;
contact[i].surface.slip1 = .1;
contact[i].surface.slip2 = .1;
  • ODEページからの翻訳

 FDSは,『接触面に対して接線方向に付加』され,『力に比例』する速度で滑りあう面接触を実現するものです.例えば,摩擦係数が無限大(滑り無し)の接触点を考えてみる場合,これら接触面をすべらせようと,力Fをこれら接触面に付加しても動くはずがありません.しかしながら,この状態に追加してFDS係数設定を正数kとすると,任意の面相対速度『k*f』に到達まで滑り現象を実現することが可能です.なお,これは通常の摩擦効果と全く違う方法ですので,ご注意してください.つまりは,この場合,力は二面に対し相対的な一定の加速度を生じるのではなく,任意の速度を実現する簡略化された加速度を生じることとなります.
 これは,幾つかのモデル(特にタイヤモデル)に対して有効となります.例えば,路面に止まっている車を想像してください.車の進行方向に車体を押すと動き始めます(タイヤが転がる).それに対し,車の進行方向に対し直交する方向(車体側面)を押すと,タイヤがその方向に転がらず,通常,動きません.しかしFDSを設定することで,その車が速度vで動いている場合に進行方向に対し直交する方向に力Fを付加することで,路面上でタイヤがf*vに比例した速度でスリップすることが可能となります.
 そして,実際にODE内にこのような車をモデリングするには,タイヤと路面の接触パラメータを次のように設定します.まず摩擦方向1を車輪が転がる方向と設定し,次に摩擦方向2のFDSスリップ係数をK*Vと設定します(Vはタイヤの転がり速度,kはあなたが実験から選択するタイヤのパラメータ).
 最後に,FDSはクーロン摩擦とは全く違った接着/滑り効果である.これら二つのモードが1接触点において共に適用することができます.

test_buggy.cppを使う上での重要事項

 test_buggy.cppを基準として非車輪系のプログラムを構築すると,床においてある物体が勝手にすべることがあります.その場合,以下のようにslipに関するコードを削除してください.

contact[i].surface.mode = dContactSlip1 | dContactSlip2 
                     | dContactSoftERP | dContactSoftCFM | dContactApprox1;
contact[i].surface.slip1 = 0.1;
contact[i].surface.slip2 = 0.1;
↓(slipの項を削除)
contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1;

衝突点の柔軟性(粘弾性)

// 弾性係数:kp[N/m]
// 粘性係数:kd[Ns/m]
// 刻み時間:DT[sec]
// フラグの設定:dContactSoftERP | dContactSoftCFM
contact[i].surface.soft_erp = DT*GKP/(DT*GKP+GKP);
contact[i].surface.soft_cfm = 1/(DT*GKP+GKP);

衝突点のデータ取得(衝突点に生ずる力,トルク)

  • 宣言部
    dJointFeedback *joint_data0=(dJointFeedback *)malloc(sizeof(dJointFeedback));
  • 衝突部
    // 省略
    dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
    dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2)); 
    
    dJointSetFeedback(c, contact_data);
    contact_data = dJointGetFeedback(c);
    
    if((o1==box[0]&&o2==ground)||(o2==box[0]&&o1==ground)){
      printf("%2.3f	",contact_data->f1[0]);
      if(i==n-1)printf("\n");
    }

衝突点の座標位置取得

  • 衝突部
    // 省略
    dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
    dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2)); 
    // 箱型と地面の衝突なので,状態により1衝突1〜3点の衝突点が生じる.
    if((o1==box[0]&&o2==ground)||(o2==box[0]&&o1==ground)){
      printf("%2.3f	%2.3f	%2.3f\n",contact[i].geom.pos[0],contact[i].geom.pos[1],contact[i].geom.pos[2]);
      if(i==n-1)printf("\n");
    }

衝突点へのノイズ付加

 シミュレーションにおいて,設定したパラメータで物理現象を起こすと,必ず同様の結果が得られる.しかしながら,現実世界においては,同じ物理現象を起こそうとしても起こすのは難しい.そのように,同じ物理現象を起こさないためには環境ノイズをシミュレーションに追加する必要がある.以下のコードは,±10%のノイズを付加している.

// 摩擦係数 
contact[i].surface.mu = 1+((rand()%21)-10)/100.;
contact[i].surface.mu2 = 1+((rand()%21)-10)/100.;
// 粘弾性
gkp=GKP*(1+(rand()%21)-10)/100.);
gkd=GDP*(1+((rand()%21)-10)/100.);
contact[i].surface.soft_erp = DT*gkp/(DT*gkp+gkd);
contact[i].surface.soft_cfm = 1/(DT*gkp+gkd);
// ノイズ(任意方向および任意の力)の付加
dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2));
if((o1==box[0]&&o2==ground)||(o2==box[0]&&o1==ground)){
  // 特定物体間の衝突点に力を付加
  dBodyAddForceAtPos(body[0],rand()%21/10,rand()%21/10,rand()%21/10,
      contact[i].geom.pos[0],contact[i].geom.pos[1],contact[i].geom.pos[2]);
 }
}

サンプルプログラム(上記した方法の統合プログラム)

// 二物体の衝突状態
  const int N = 10;
  dContact contact[N];
  n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
  if (n > 0) {
    for (i=0; i<n; i++) {
      // 衝突状態フラグの設定
      contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1;
	  // クーロン摩擦
	  contact[i].surface.mu = 1.;
	  // 地面の柔軟性設定
	  contact[i].surface.soft_erp = DT*GKP/(DT*GKP+GKD);   // GKP=3000, GKD=100
	  contact[i].surface.soft_cfm = 1/(DT*GKP+GKD);    
    
	dJointID c = dJointCreateContact (world,contactgroup,&contact[i]);
      	dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2)); 
 
	dJointSetFeedback(c, contact_data);
	contact_data = dJointGetFeedback(c);

	  if((o1==box[0]&&o2==ground)||(o2==box[0]&&o1==ground)){
		  printf("%2.3f	",contact_data->f1[0]);
		  if(i==n-1)printf("\n");
		  // 衝突点に力を付加
		  dBodyAddForceAtPos(body[0],.1,0,0,contact[i].geom.pos[0],
                              contact[i].geom.pos[1],contact[i].geom.pos[2]);
	  }
	}

  }
  if(((o1==box[0])&&(o2==ground))||((o1==ground)&&(o2==box[0]))){
	  touch_num=1; 
 }
}

トップ   編集 凍結解除 差分 バックアップ 添付 複製 名前変更 リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-01-23 (火) 08:34:51 (3954d)