ODE講座7:ジョイント(関節)

                        

金沢もすっかり寒くなり寒鰤(かんぶり:注1)と地酒(注2)が旨い季節になってまいりました。

さて、ODE(Open Dynamics Engine)講座の7回目です。衝突検出の細かい話は後にして今回はジョイントについてお話しします。 前回課題が出てていましたができましたか? 答えは、nearCallback関数の中にある
contact[i].surface.bounce = 0.0; // (0.0~1.0)   反発係数は0から1まで
の値を0.0以上1.0以下にすればよいのです。反発係数は衝突前と衝突後の速度比でしたね。

では、ジョイントについて説明します。ジョイントは我々の周りでは、折畳み携帯のヒンジやドアの蝶番に相当します。小難しくいうと、2つのボディの位置や姿勢をある一定の関係に保つ拘束がジョイントとなのです。ODEではジョイントと拘束を同じ意味で使っています。

 さっそく上図に示している玉と円柱をヒンジジョイントで結合しているオブジェクトがバウンドするソースコードを以下に示します。なお、前回までと同じ関数や宣言は省略しています。

注1:脂が乗って美味。甘エビもおいしいですね。
注2:石川では菊姫天狗舞万歳楽などが好きですが、福井の黒龍も超お勧め。

// Sample3.cpp  by でむ
typedef struct {
  dBodyID body;
  dGeomID geom;
  dReal   radius,length,mass;
} myLink;
myLink ball, pole;                                                          

static void simLoop (int pause)
{
  const dReal *pos1,*R1,*pos2,*R2;
  dSpaceCollide(space,0,&nearCallback); 
  dWorldStep(world,0.01);
  dJointGroupEmpty(contactgroup);                            
  dsSetColor(1.0,0.0,0.0);
  // ボールの描画                                                    
  pos1 = dBodyGetPosition(ball.body);
  R1   = dBodyGetRotation(ball.body);
  dsDrawSphereD(pos1,R1,ball.radius);
  // 円柱の描画                                                              
  pos2 = dBodyGetPosition(pole.body);
  R2   = dBodyGetRotation(pole.body);
  dsDrawCappedCylinderD(pos2,R2,pole.length,pole.radius);
}

// オブジェクトの作成                                                      
void createBallandPole() {
  dMass m1;
  dReal x0 = 0.0, y0 = 0.0, z0 = 2.5;

  //玉                                                                        
  ball.radius = 0.2;  ball.mass   = 1.0;
  ball.body = dBodyCreate(world);
  dMassSetZero(&m1);
  dMassSetSphereTotal(&m1,ball.mass,ball.radius);
  dBodySetMass(ball.body,&m1);
  dBodySetPosition(ball.body, x0, y0, z0);
  ball.geom = dCreateSphere(space,ball.radius);
  dGeomSetBody(ball.geom,ball.body);

  // 円柱                                                                        
  pole.radius = 0.025;  pole.length = 1.0;  pole.mass   = 1.0;
  pole.body = dBodyCreate(world);
  dMassSetZero(&m1);
  dMassSetCylinderTotal(&m1,pole.mass,3,pole.radius,pole.length);
  dBodySetMass(pole.body,&m1);
  dBodySetPosition(pole.body, x0, y0, z0 – 0.5 * pole.length);
  pole.geom = dCreateCCylinder(space,pole.radius,pole.length);
  dGeomSetBody(pole.geom,pole.body);

  // ヒンジジョイント                                                                 
  joint = dJointCreateHinge(world, 0);           // ヒンジジョイントの生成
  dJointAttach(joint, ball.body,pole.body);         // 玉のボディと円柱のボディをジョイントで結合
  dJointSetHingeAnchor(joint, x0, y0, z0 – ball.radius); // ヒンジジョイントのアンカー(中心点)を設定
  dJointSetHingeAxis(joint, 1, 0, 0);            // ヒンジジョイントの回転軸ベクトルを設定(1,0,0)
}

int main (int argc, char **argv)
{
  setDrawStuff();
  world = dWorldCreate();
  space = dHashSpaceCreate(0);
  contactgroup = dJointGroupCreate(0);
  dWorldSetGravity(world,0,0,-9.8);                                                      
  ground = dCreatePlane(space,0,0,1,0);                                                     
  createBallandPole();
  dsSimulationLoop (argc,argv,352,288,&fn);
  dWorldDestroy (world);
  return 0;

この例では玉と円柱のボディをヒンジジョイントで結びつけています。
ジョイントの使い方は以下のようになります。

  1. ***ジョイントの生成      dJointCreate***()
  2. ***ジョイントとボディの結合 dJointAttach()
  3. ***ジョイントの中心点を設定 dJointSet***Anchor()
  4. ***ジョイントの回転軸を設定 dJointSet***Axis()

 上で***にはジョイントのタイプが入ります。タイプにはHinge(ヒンジ)、Ball(ボール)、Slider(スライダー)、Universal(ユニバーサル)等があります。詳しい使い方はマニュアルを参照してください。

で はソースコードを読みましょう。createBallandPall関数ではまず玉を作り、その後、円柱を作り、それからヒンジジョイントを dJointCreateHinge()で 生成し、dJointAttach()で2つのボディをヒンジジョイントで結合します。その後のdSetHingeAnchor()はジョイントの回転中 心点の位置を設定し、dJointSetHingeAxis()で回転軸ベクトル を設定します。この例では回転軸ベクトルは(1,0,0)なのでx軸方向となります。詳しくはマニュアルを参照。

これでジョイントの生成は終わりです。今回は簡単のためにジョイントのパラメータを設定しませんでしたが、可動域や最大トルク、最大角速度の設定なども可能です。 ここをクリックしてサンプルプログラムをダウンロードして遊んでください。

 次回(11月7日目標)は関節の動かし方やパラメータの設定方法を説明します。なお、説明でわかりずらい箇所や質問があればコメントを投稿してください。よろしく!

コメントを残す

メールアドレスが公開されることはありません。