Open Dynamics Engine 入門
【2日目】オブジェクトのジョイント
ODE(Open Dynamics Engine)の入門編の2日目です。 といっても、自分自身の勉強がてらつくっています。 「【1日目】球の描画と衝突判定」では、ODEを利用するモチベーションと基本となるプログラムを作成いたしました。
2つの剛体をつなぐ
ODEでは、2つ以上のオブジェクト間に拘束を設定することができます。 今回は、球体と長細いカプセルをヒンジでつないだ物体を、空から大量に投下することをシミュレーションします。
プログラムソース
以下のプログラムソースは、demura.net: ロボットの開発と教育にて公開されているソースを利用させていただいております。
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
#include <time.h>
#include <iostream>
int WindowWidth = 352; //ウィンドウの幅
int WindowHeight = 288; //ウィンドウの高さ
#ifdef dDOUBLE
#define dsDrawSphere dsDrawSphereD // 単精度と倍精度の描画関数に対応するおまじない
#define dsDrawCapsule dsDrawCapsuleD
#endif
const int N = 100;//マッチ棒の数
static dWorldID world;
static dSpaceID space;
static dGeomID ground;
static dJointGroupID contactgroup; // add
dsFunctions fn;
typedef struct {
dBodyID body;
dGeomID geom;
dReal radius;
dReal length;
dReal mass;
} myLink;
myLink ball[N], pole[N]; // add
dJointID joint[N];
static void nearCallback(void *data, dGeomID o1, dGeomID o2)
{
const int N = 10;
dContact contact[N];
int n = dCollide(o1,o2,N,&contact[0].geom,sizeof(dContact));
for (int i = 0; i < n; i++) {
contact[i].surface.mu = 10.0;//dInfinity;
contact[i].surface.mu2 = 10.0;//dInfinity;
contact[i].surface.mode = dContactBounce;
contact[i].surface.bounce = 0.1; // (0.0~1.0)
contact[i].surface.bounce_vel = 0.01;
dJointID c = dJointCreateContact(world,contactgroup,&contact[i]);
dJointAttach (c,dGeomGetBody(contact[i].geom.g1), dGeomGetBody(contact[i].geom.g2));
}
}
static void simLoop (int pause)
{
dSpaceCollide(space,0,&nearCallback);
//dWorldStep(world,0.002);
dWorldQuickStep(world,0.005);
dJointGroupEmpty(contactgroup);
for(int i=0; i<N; i++){
dsSetColor(1.0,0.0,0.0);
dsDrawSphereD( dBodyGetPosition(ball[i].body),dBodyGetRotation(ball[i].body),ball[i].radius);
dsDrawCapsuleD(dBodyGetPosition(pole[i].body),dBodyGetRotation(pole[i].body),pole[i].length,pole[i].radius);
}
}
void start()
{
static float xyz[3] = {0.0,-3.0,1.0};
static float hpr[3] = {90.0,0.0,0.0};
dsSetViewpoint (xyz,hpr);
}
void prepDrawStuff() {
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = NULL;
fn.stop = NULL;
fn.path_to_textures = "C:/ode-0.11.1/drawstuff/textures";
}
void createBallandPole() {
dMass m1;
for(int i=0; i<N; i++){
dReal x0 = 0.0, y0 = 0.0, z0 = 1.2 * (i+1) +2.0;
dReal rx = double(rand()-rand())/double(RAND_MAX);
dReal ry = double(rand()-rand())/double(RAND_MAX);
ball[i].radius = 0.1;
ball[i].mass = 0.1;
ball[i].body = dBodyCreate(world);
dMassSetZero(&m1);
dMassSetSphereTotal(&m1,ball[i].mass,ball[i].radius);
dBodySetMass(ball[i].body,&m1);
dBodySetPosition(ball[i].body, x0 + rx, y0+ ry, z0);
ball[i].geom = dCreateSphere(space,ball[i].radius);
dGeomSetBody(ball[i].geom,ball[i].body);
pole[i].radius = 0.025;
pole[i].length = 1.0;
pole[i].mass = 2.0;
pole[i].body = dBodyCreate(world);
dMassSetZero(&m1);
dMassSetCapsule(&m1,pole[i].mass,3,pole[i].radius,pole[i].length);
dBodySetMass(pole[i].body,&m1);
dBodySetPosition(pole[i].body, x0 + rx, y0 + ry, z0 - ball[i].radius - 0.5 * pole[i].length - pole[i].radius );
pole[i].geom = dCreateCapsule(space, pole[i].radius, pole[i].length);
dGeomSetBody(pole[i].geom, pole[i].body);
// Hinge joint
joint[i] = dJointCreateHinge(world, 0);
dJointAttach(joint[i], ball[i].body,pole[i].body);
dJointSetHingeAnchor(joint[i], x0 + rx, y0 + ry, z0 - ball[i].radius - pole[i].radius/2 );
dJointSetHingeAxis(joint[i], 0, 0, 1);
}
}
void setDrawStuff() {
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = NULL;
fn.stop = NULL;
fn.path_to_textures = "C:/ode-0.11.1/drawstuff/textures";
}
int main (int argc, char **argv)
{
srand(int(time(NULL))); //rand()の種
setDrawStuff();
dInitODE();
world = dWorldCreate();
space = dHashSpaceCreate(0);
contactgroup = dJointGroupCreate(0);
dWorldSetGravity(world,0,0,-9.8);
dWorldSetERP(world, 0.2);
dWorldSetCFM(world, 10E-5);
dWorldSetLinearDamping(world,0.001);
ground = dCreatePlane(space,0,0,1,0);
createBallandPole();
dsSimulationLoop (argc,argv,WindowWidth, WindowHeight,&fn); //シミュレーション用の無限ループ
dWorldDestroy (world);
dCloseODE();
return 0;
}
メモ
■Q.dSolveLCP関数にエラー
■A.スタック領域を使い果たすとエラーになる
コンパイル時に「 /F [バイト数] 」オプションをつけることで、スタック領域を明示的に指定することができる。
([]の中は整数を入れる。デフォルトで、1000000 (1MB) 。)




