ODEã§å¦ã¶ï¼£è¨€èªžã€€[Step7: ã¾ã¨ã‚]
ODEã§å¦ã¶C言語ã®Step7ã§ã™ï¼ŽStep6ã¾ã§ã§ä¸€é€šã‚ŠC言語ã®é …ç›®ãŒçµ‚ã‚ã£ãŸã®ã§ä»Šå›žã¯ã¾ã¨ã‚ã®æ¼”ç¿’ã§ã™ï¼Žãƒ—ラス,ODEã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã®ç”Ÿæˆæ³•ã¨ç°¡å˜ãªåˆ¶å¾¡ã®ã‚µãƒ³ãƒ—ルプãƒã‚°ãƒ©ãƒ を紹介ã—ã¾ã™ï¼Ž
ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¯æˆ‘々ã®å‘¨ã‚Šã§ã¯ã€æŠ˜ç•³ã¿æºå¸¯ã®ãƒ’ンジやドアã®è¶ç•ªã«ç›¸å½“ã—ã¾ã™ã€‚å°é›£ã—ãã„ã†ã¨ã€ï¼’ã¤ã®ãƒœãƒ‡ã‚£ã®ä½ç½®ã‚„姿勢をã‚る一定ã®é–¢ä¿‚ã«ä¿ã¤æ‹˜æŸãŒã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¨ãªã®ã§ã™ã€‚ODEã§ã¯ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¨æ‹˜æŸã‚’åŒã˜æ„味ã§ä½¿ã£ã¦ã„ã¾ã™ã€‚
ODEã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆï¼ˆé–¢ç¯€ï¼‰ã¯ï¼’ã¤ã®ãƒœãƒ‡ã‚£(剛体,body)ã‚’ã¤ãªã’ã‚‹ã‚‚ã®ã§ã™ã€‚1ã¤ã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã§ï¼“個以上ã®ãƒœãƒ‡ã‚£ã‚’ã¤ãªã’ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ã—,1個ã®ãƒœãƒ‡ã‚£ã ã‘ã‚’ã¤ãªã’ã‚‹ã“ã¨ã‚‚ã§ãã¾ã›ã‚“.必ãšï¼’個ã®ãƒœãƒ‡ã‚£ã‚’1ã¤ã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã§ã¤ãªã’ãªã‘れã°ãªã‚Šã¾ã›ã‚“.
ã¾ãŸï¼ŒODEã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¯æ‘©æ“¦ãŒã‚りã¾ã›ã‚“ã—,å¯å‹•域をè¨å®šã—ãªã„ã¨+dInfinity(+ç„¡é™å¤§)ã‹ã‚‰-dInfinity(-ç„¡é™å¤§ï¼‰ã¾ã§å›žè»¢ã¾ãŸã¯ç§»å‹•ã—ã¾ã™ï¼Žè§’度ã¯[rad]ã§ã™ï¼Ž
- ジョイントã®ä½¿ã„æ–¹
- ***ジョイントã®ç”Ÿæˆã€€ã€€ã€€ã€€ã€€ã€€dJointCreate***()
- ***ジョイントã¨ãƒœãƒ‡ã‚£ã®çµåˆã€€ dJointAttach(dJointID, dBodyID, dBodyID)
- ***ジョイントã®ä¸å¿ƒç‚¹ã‚’è¨å®šã€€dJointSet***Anchor()
- ***ジョイントã®å›žè»¢è»¸ã‚’è¨å®šã€€dJointSet***Axis()
上ã§***ã«ã¯ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã®ã‚¿ã‚¤ãƒ—ãŒå…¥ã‚Šã¾ã™ã€‚タイプã«ã¯Hinge(ヒンジ)ã€Ball(ボール)ã€Slider(スライダー)ã€Universal(ユニãƒãƒ¼ã‚µãƒ«)ç‰ãŒã‚りã¾ã™ã€‚サンプルプãƒã‚°ãƒ©ãƒ ã§ã¯ãƒ’ンジジョイントã¨ç›´å‹•å¼ã®ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã‚’使ã„ã¾ã™ï¼Ž
- ジョイントã®ãƒ‘ラメータè¨å®š
- å¯å‹•域ã®è¨å®š
dJointSetHingeParam(dJointID, dParamLoStop, å¯å‹•域ã®ä¸‹é™ï¼‰;
dJointSetHingeParam(dJointID, dParamHiStop, å¯å‹•域ã®ä¸Šé™ï¼‰; - 目標角速度ã¨ãれを実ç¾ã™ã‚‹ãŸã‚ã®æœ€å¤§ãƒˆãƒ«ã‚¯ã®è¨å®š
dJointSetHingeParam(dJointID, dParamVel, 目標角速度);
dJointSetHingeParam(dJointID, dParamFMax, 最大トルク);
パラメータã¨ã—ã¦ã¯ã€é–¢ç¯€å¯å‹•域ã®ä¸‹é™ã‚’示ã™dParamLoStopã€ä¸Šé™ã‚’示ã™dParamHiStopã€è§’速度(ヒンジジョイント)ã¾ãŸã¯é€Ÿåº¦(ç›´å‹•å¼é–¢ç¯€ï¼‰ã‚’示ã™dParamVelã€æœ€å¤§ãƒˆãƒ«ã‚¯ã‚’示ã™dParaFMaxãªã©ãŒã‚りã¾ã™ã€‚ãªãŠã€ODEã§ã¯é–¢ç¯€ã«ãƒ¢ãƒ¼ã‚¿ãŒæ¨™æº–ã§çµ„ã¿è¾¼ã¾ã‚Œã¦ã„ã‚‹ã®ã§ã€dParamVelã‚„dParaFMaxを指定ã™ã‚‹ã¨é–¢ç¯€ãŒå‹•ãã¾ã™ã€‚
ソースコード
å°‘ã—é•·ããªã‚Šã¾ã™ãŒï¼Œã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã‚’掲載ã—ã¾ã™ï¼Žã“ã®ã‚³ãƒ¼ãƒ‰ã¯ä»Šã¾ã§ç¿’ã£ãŸï¼Œã‚ーæ“作関数,シミュレーションã®å†ã‚¹ã‚¿ãƒ¼ãƒˆï¼Œãƒœãƒ‡ã‚£ã¸åŠ›ã‚’åŠ ãˆã‚‹ãªã©ã®ã»ã‹ã«ï¼Œã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã®ç”Ÿæˆã¨åˆ¶å¾¡æ³•ãªã©ç°¡å˜ãªã‚²ãƒ¼ãƒ やシミュレータを作るãŸã‚ã«å¿…è¦ãªã“ã¨ã¯ä¸€é€šã‚Šå…¥ã£ã¦ã„ã¾ã™ï¼Ž
/* step7 */
#include "dm7.h"
#define START_X 0.0 // åˆæœŸä½ç½®ã®ï½˜åº§æ¨™
#define START_Y 0.0
#define START_Z 1.5
dWorldID world; // 動力å¦ã®ä¸–界
dSpaceID space; // è¡çªæ¤œå‡ºç”¨ã‚¹ãƒšãƒ¼ã‚¹
dGeomID ground; // 地é¢
dJointGroupID contactgroup; // コンタクトグループ
typedef struct
{
dBodyID body; // ボディã®ID
dGeomID geom; // ジオメトリã®ID
dJointID joint; // ジョイントã®ID
double pos[3]; // x, y, z [m]
double *R; // 回転行列 è¦ç´ æ•°4x3
double sides[3]; // ボックスã®ã‚µã‚¤ã‚º
double l, r, m; // 直径[m], åŠå¾„ [m], è³ªé‡ [kg]
float color[3]; // 色 r,g,b
} MyObject;
MyObject torso, leg[2]; // 胴体,脚
static int STEPS = 0; // シミュレーションã®ã‚¹ãƒ†ãƒƒãƒ—æ•°
double S_LENGTH = 0.0; // スライダー長
double H_ANGLE = 0; //ヒンジã®è§’度
// コールãƒãƒƒã‚¯é–¢æ•°
void nearCallback(void *data, dGeomID o1, dGeomID o2)
{
static const int N = 10; // æŽ¥è§¦ç‚¹æ•°ã®æœ€å¤§å€¤
dContact contact[N]; // 接触点
// 接触ã—ã¦ã„る物体ã®ã©ã¡ã‚‰ã‹ãŒåœ°é¢ãªã‚‰isGroundã«éž0をセット
int isGround = ((ground == o1) || (ground == o2));
// 2ã¤ã®ãƒœãƒ‡ã‚£ãŒã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã§çµåˆã•れã¦ã„ãŸã‚‰è¡çªæ¤œå‡ºã—ãªã„
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact)) return;
// è¡çªæƒ…å ±ã®ç”Ÿæˆ nã¯è¡çªç‚¹æ•°
int n = dCollide(o1,o2,N,&contact[0].geom,sizeof(dContact));
if (isGround)
{
for (int i = 0; i < n; i++)
{
contact[i].surface.mode = dContactBounce; // 接触é¢ã®å発性をè¨å®š
contact[i].surface.mu = dInfinity; // 摩擦係数
contact[i].surface.bounce = 0.5; // å発係数(0.0ã‹ã‚‰1.0)
contact[i].surface.bounce_vel = 0.0; // å発ã«å¿…è¦ãªæœ€ä½Žé€Ÿåº¦
// 接触ジョイントã®ç”Ÿæˆ
dJointID c = dJointCreateContact(world,contactgroup,
&contact[i]);
// 接触ã—ã¦ã„ã‚‹ï¼’ã¤ã®å‰›ä½“を接触ジョイントã«ã‚ˆã‚Šæ‹˜æŸ
dJointAttach(c,dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2));
}
}
}
void dmDraw(MyObject obj) /*** ç‰©ä½“ã®æç”» ***/
{
const double *pos, *R;
pos = dGeomGetPosition(obj.geom); // ä½ç½®ã‚’å–å¾—
R = dGeomGetRotation(obj.geom); // 姿勢をå–å¾—
dsSetColor(obj.color[0],obj.color[1],obj.color[2]); // 色ã®è¨å®š(r,g,b)
int type = dGeomGetClass(obj.geom);
if (type == dBoxClass)
{
dsDrawBox(pos,R,obj.sides);
}
else if (type == dSphereClass)
{
dsDrawSphere(pos,R,obj.r);
}
else if (type == dCapsuleClass)
{
dsDrawCapsule(pos,R,obj.l,obj.r);
}
else if (type == dCylinderClass)
{
dsDrawCylinder(pos,R,obj.l,obj.r);
}
}
void dmSphereCreate(MyObject *obj,double p[3], double R[12],
double m, double r, float color[3])
{
int i;
obj->m = m;
obj->r = r;
obj->R = R;
for (i = 0; i < 3; i++)
{
obj->pos[i] = p[i];
obj->color[i] = color[i];
}
dRSetIdentity(obj->R);
obj->body = dBodyCreate(world); // ボールã®ç”Ÿæˆ
dMass mass; // æ§‹é€ ä½“massã®å®£è¨€
dMassSetZero(&mass); // æ§‹é€ ä½“massã®åˆæœŸåŒ–
dMassSetSphereTotal(&mass,obj->m,obj->r); // æ§‹é€ ä½“massã«è³ªé‡ã‚’è¨å®š
dBodySetMass(obj->body,&mass); // ボールã«massã‚’è¨å®š
dBodySetPosition(obj->body,obj->pos[0],obj->pos[1],obj->pos[2]); // ボールã®ä½ç½®(x,y,z)ã‚’è¨å®š
obj->geom = dCreateSphere(space,obj->r); // çƒã‚¸ã‚ªãƒ¡ãƒˆãƒªã®ç”Ÿæˆ
dGeomSetBody(obj->geom, obj->body); // ボディã¨ã‚¸ã‚ªãƒ¡ãƒˆãƒªã®é–¢é€£ä»˜ã‘
}
void dmCapsuleCreate(MyObject *obj,double p[3], double R[12],
double m, double r, double l, float color[3])
{
int i;
obj->m = m;
obj->l = l;
obj->r = r;
obj->R = R;
for (i = 0; i < 3; i++)
{
obj->pos[i] = p[i];
obj->color[i] = color[i];
}
dRSetIdentity(obj->R);
obj->body = dBodyCreate(world); // 剛体ã®ç”Ÿæˆ
dMass mass; // æ§‹é€ ä½“massã®å®£è¨€
dMassSetZero(&mass); // æ§‹é€ ä½“massã®åˆæœŸåŒ–
dMassSetCapsuleTotal(&mass,obj->m,
3, obj->r, obj->l); // æ§‹é€ ä½“massã«è³ªé‡ã‚’è¨å®š
dBodySetMass(obj->body,&mass); // 剛体ã«massã‚’è¨å®š
dBodySetPosition(obj->body,obj->pos[0],obj->pos[1],obj->pos[2]); // 剛体ã®ä½ç½®(x,y,z)ã‚’è¨å®š
obj->geom = dCreateCylinder(space,obj->r, obj->l); // ボックスジオメトリã®ç”Ÿæˆ
dGeomSetBody(obj->geom, obj->body); // ボディã¨ã‚¸ã‚ªãƒ¡ãƒˆãƒªã®é–¢é€£ä»˜ã‘
}
// ãƒãƒœãƒƒãƒˆã®ç”Ÿæˆ
void createMonoBot()
{
int i;
double l_leg = 0.75; // é•·ã•
double m_leg = 1.0; // 質é‡
double r_leg[2] = {0.05, 0.03}; // åŠå¾„
double m_torso = 10.0;
double r_torso = 0.25;
double p_torso[3] = {START_X, START_Y, START_Z}; // ä½ç½®
double p_leg[2][3] = {{START_X, START_Y, START_Z-0.5*l_leg},
{START_X, START_Y, START_Z-0.5*l_leg-0.5}};
double p_anchor[3] = {START_X, START_Y, START_Z};
double R[12]; // 回転行列
float color_torso[3] = {1.0, 0.0, 0.0}; // 色
float color_leg[2][3] = {{0.0, 0.0, 1.0},{1.3, 1.3, 1.3}};
dRSetIdentity(R); //回転行列をå˜ä½è¡Œåˆ—ã§åˆæœŸåŒ–
dmSphereCreate(&torso,p_torso,R,m_torso,r_torso,color_torso); // 胴体ã®ç”Ÿæˆ
for (i = 0; i < 2; i++)
{
dmCapsuleCreate(&leg[i],p_leg[i],R,m_leg,r_leg[i],l_leg,color_leg[i]); // 脚ã®ç”Ÿæˆ
}
// ヒンジジョイント
leg[0].joint = dJointCreateHinge(world, 0); // ヒンジジョイントã®ç”Ÿæˆ
dJointAttach(leg[0].joint, torso.body,leg[0].body); // 2ã¤ã®ãƒœãƒ‡ã‚£ã¨ã®çµåˆ
dJointSetHingeAnchor(leg[0].joint, p_anchor[0],p_anchor[1],p_anchor[2]); // ジョイントä¸å¿ƒã®è¨å®š
dJointSetHingeAxis(leg[0].joint, 1, 0, 0); // 回転軸ベクトルã®è¨å®š
// スライダージョイント
leg[1].joint = dJointCreateSlider(world, 0); // スライダジョイントã®ç”Ÿæˆ
dJointAttach(leg[1].joint, leg[0].body,leg[1].body); // 2ã¤ã®ãƒœãƒ‡ã‚£ã¨ã®çµåˆ
dJointSetSliderAxis(leg[1].joint, 0, 0, 1); // スライダã®è»¸ãƒ™ã‚¯ãƒˆãƒ«ã®è¨å®š
dJointSetSliderParam(leg[1].joint, dParamLoStop, -0.25); // スライダã®å¯å‹•域 下é™
dJointSetSliderParam(leg[1].joint, dParamHiStop, 0.25); // スライダã®å¯å‹•域 上é™
}
// ヒンジジョイントã®åˆ¶å¾¡
static void controlHinge(dReal target)
{
static dReal kp = 10.0, fmax = 1000;
dReal tmp = dJointGetHingeAngle(leg[0].joint);
dReal diff = target - tmp;
if (diff >= M_PI) diff -= 2.0 * M_PI; // diffãŒ2πよりå°ã•ã
if (diff <= - M_PI) diff += 2.0 * M_PI; // diffãŒ-2πより大ãã
dReal u = kp * diff;
dJointSetHingeParam(leg[0].joint, dParamVel, u);
dJointSetHingeParam(leg[0].joint, dParamFMax, fmax);
}
// スライダã®åˆ¶å¾¡ プãƒã‚°ãƒ©ãƒ 2.4
static void controlSlider(dReal target)
{
static dReal kp = 25.0; // 比例定数
static dReal fmax = 1000; // 最大力[N]
double tmp, u;
tmp = dJointGetSliderPosition(leg[1].joint); // スライダã®ç¾åœ¨ä½ç½®
u = kp * (target - tmp); // 残差
dJointSetSliderParam(leg[1].joint, dParamVel, u);
dJointSetSliderParam(leg[1].joint, dParamFMax, fmax);
}
// ãƒãƒœãƒƒãƒˆã®ç ´å£Š
void destroyMonoBot()
{
int i;
dJointDestroy(leg[0].joint); // ヒンジ
dJointDestroy(leg[1].joint); // スライダー
dBodyDestroy(torso.body); // 胴体ã®ãƒœãƒ‡ã‚£ã‚’ç ´å£Š
dGeomDestroy(torso.geom); // 胴体ã®ã‚¸ã‚ªãƒ¡ãƒˆãƒªã‚’ç ´å£Š
for (i = 0; i < 2; i++)
{
dBodyDestroy(leg[i].body); // 脚ã®ãƒœãƒ‡ã‚£ã‚’ç ´å£Š
dGeomDestroy(leg[i].geom); // 脚ã®ã‚¸ã‚ªãƒ¡ãƒˆãƒªã‚’ç ´å£Š
}
}
// シミュレーションã®å†ã‚¹ã‚¿ãƒ¼ãƒˆ
static void restart()
{
STEPS = 0; // ステップ数ã®åˆæœŸåŒ–
H_ANGLE = 0.0; // ヒンジ角度ã®åˆæœŸåŒ–
destroyMonoBot(); // ãƒãƒœãƒƒãƒˆã®ç ´å£Š
dJointGroupDestroy(contactgroup); // ジョイントグループã®ç ´å£Š
contactgroup = dJointGroupCreate(0); // ジョイントグループã®ç”Ÿæˆ
createMonoBot(); // ãƒãƒœãƒƒãƒˆã®ç”Ÿæˆ
}
// ã‚ーæ“作
void command(int cmd)
{
switch (cmd)
{
case 'j':
S_LENGTH = 0.25; break;
case 'f':
S_LENGTH = - 0.25; break;
case 'k':
H_ANGLE += 0.25;
if (H_ANGLE > M_PI) H_ANGLE = -M_PI; break;
case 'd':
H_ANGLE -= 0.25;
if (H_ANGLE < -M_PI) H_ANGLE = M_PI; break;
case 'u':
dBodyAddForce(torso.body, 0, 0, 500); break;
case 'r':
restart(); break;
default :
printf("key missed \n"); break;
}
}
void simLoop(int pause) /*** シミュレーションループ ***/
{
int i;
int s = 1000; // è·³èºã™ã‚‹å‘¨æœŸ(ステップ)
if (!pause)
{
printf("STEPS=%d \n",STEPS++); // ステップ数
// スライダーã®ä¼¸ç¸®
if ((0 <= (STEPS%s)) && ((STEPS%s) <= 10)) S_LENGTH = 0.6;
else if ((11 <= (STEPS%s)) && ((STEPS%s) <= 15)) S_LENGTH = 0.0;
controlSlider(S_LENGTH); // スライダージョイントã®åˆ¶å¾¡
controlHinge(H_ANGLE); // ヒンジジョイントã®åˆ¶å¾¡
dSpaceCollide(space,0,&nearCallback); // è¡çªæ¤œå‡ºé–¢æ•°
dWorldStep(world,0.01); // シミュレーションを1ステップ進ã‚ã‚‹
dJointGroupEmpty(contactgroup); // ジョイントグループを空ã«ã™ã‚‹
}
// ãƒãƒœãƒƒãƒˆã®æç”»
dmDraw(torso); // èƒ´ä½“ã®æç”»
for (i = 0; i < 2; i++)dmDraw(leg[i]); //è„šã®æç”»
}
int main() /*** main関数 ***/
{
dInitODE(); // ODEã®åˆæœŸåŒ–
world = dWorldCreate(); // 動力å¦ç”¨ä¸–界ã®å‰µé€
space = dHashSpaceCreate(0); // è¡çªç”¨ç©ºé–“ã®å‰µé€
contactgroup = dJointGroupCreate(0); // ジョイントグループã®ç”Ÿæˆ
ground = dCreatePlane(space,0,0,1,0); // 地é¢ã®ç”Ÿæˆ
dWorldSetGravity(world,0,0,-9.8); // é‡åŠ›è¨å®š
createMonoBot(); // ãƒãƒœãƒƒãƒˆã®ç”Ÿæˆ
dmLoop(800, 600); // シミュレーションループ ウインドウã®å¹…,高
dSpaceDestroy(space); // è¡çªç”¨ç©ºé–“ã®ç ´å£Š
dWorldDestroy(world); // 動力å¦ç”¨ä¸–界ã®ç ´å£Š
dCloseODE(); // ODEã®çµ‚了
return 0;
}
ホームワーク
- step7-090720.zipをダウンãƒãƒ¼ãƒ‰ã—ã¦å®Ÿè¡Œã—ã¦ã¿ã¾ã—ょã†ï¼Ž
- サンプルプãƒã‚°ãƒ©ãƒ ã®ãƒãƒœãƒƒãƒˆã‚’10å°å‡ºç¾ã™ã‚‹ã‚ˆã†ã«ãƒ—ãƒã‚°ãƒ©ãƒ を変更ã—ã¾ã—ょã†ï¼Ž
