ODEã§å­¦ã¶ï¼£è¨€èªžã€€[Step7: ã¾ã¨ã‚]

2009-07-20
By


Step7: 一本足ロボット

Step7: 一本足ロボット


ODEã§å­¦ã¶C言語ã®Step7ã§ã™ï¼ŽStep6ã¾ã§ã§ä¸€é€šã‚ŠC言語ã®é …ç›®ãŒçµ‚ã‚ã£ãŸã®ã§ä»Šå›žã¯ã¾ã¨ã‚ã®æ¼”ç¿’ã§ã™ï¼Žãƒ—ラス,ODEã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã®ç”Ÿæˆæ³•ã¨ç°¡å˜ãªåˆ¶å¾¡ã®ã‚µãƒ³ãƒ—ルプログラムを紹介ã—ã¾ã™ï¼Ž

ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¯æˆ‘々ã®å‘¨ã‚Šã§ã¯ã€æŠ˜ç•³ã¿æºå¸¯ã®ãƒ’ンジやドアã®è¶ç•ªã«ç›¸å½“ã—ã¾ã™ã€‚å°é›£ã—ãã„ã†ã¨ã€ï¼’ã¤ã®ãƒœãƒ‡ã‚£ã®ä½ç½®ã‚„姿勢をã‚る一定ã®é–¢ä¿‚ã«ä¿ã¤æ‹˜æŸãŒã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¨ãªã®ã§ã™ã€‚ODEã§ã¯ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¨æ‹˜æŸã‚’åŒã˜æ„味ã§ä½¿ã£ã¦ã„ã¾ã™ã€‚

ODEã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆï¼ˆé–¢ç¯€ï¼‰ã¯ï¼’ã¤ã®ãƒœãƒ‡ã‚£(剛体,body)ã‚’ã¤ãªã’ã‚‹ã‚‚ã®ã§ã™ã€‚1ã¤ã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã§ï¼“個以上ã®ãƒœãƒ‡ã‚£ã‚’ã¤ãªã’ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ã—,1個ã®ãƒœãƒ‡ã‚£ã ã‘ã‚’ã¤ãªã’ã‚‹ã“ã¨ã‚‚ã§ãã¾ã›ã‚“.必ãšï¼’個ã®ãƒœãƒ‡ã‚£ã‚’1ã¤ã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã§ã¤ãªã’ãªã‘れã°ãªã‚Šã¾ã›ã‚“.

ã¾ãŸï¼ŒODEã®ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã¯æ‘©æ“¦ãŒã‚りã¾ã›ã‚“ã—,å¯å‹•域を設定ã—ãªã„ã¨+dInfinity(+ç„¡é™å¤§)ã‹ã‚‰-dInfinity(-ç„¡é™å¤§ï¼‰ã¾ã§å›žè»¢ã¾ãŸã¯ç§»å‹•ã—ã¾ã™ï¼Žè§’度ã¯[rad]ã§ã™ï¼Ž


  • ジョイントã®ä½¿ã„æ–¹
  1. ***ジョイントã®ç”Ÿæˆã€€ã€€ã€€ã€€ã€€ã€€dJointCreate***()
  2. ***ジョイントã¨ãƒœãƒ‡ã‚£ã®çµåˆã€€ dJointAttach(dJointID, dBodyID, dBodyID)
  3. ***ジョイントã®ä¸­å¿ƒç‚¹ã‚’設定 dJointSet***Anchor()
  4. ***ジョイントã®å›žè»¢è»¸ã‚’設定 dJointSet***Axis()

上ã§***ã«ã¯ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã®ã‚¿ã‚¤ãƒ—ãŒå…¥ã‚Šã¾ã™ã€‚タイプã«ã¯Hinge(ヒンジ)ã€Ball(ボール)ã€Slider(スライダー)ã€Universal(ユニãƒãƒ¼ã‚µãƒ«)ç­‰ãŒã‚りã¾ã™ã€‚サンプルプログラムã§ã¯ãƒ’ンジジョイントã¨ç›´å‹•å¼ã®ã‚¹ãƒ©ã‚¤ãƒ€ãƒ¼ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆã‚’使ã„ã¾ã™ï¼Ž

  • ジョイントã®ãƒ‘ラメータ設定
  1. å¯å‹•域ã®è¨­å®š
    dJointSetHingeParam(dJointID, dParamLoStop, å¯å‹•域ã®ä¸‹é™ï¼‰;
    dJointSetHingeParam(dJointID, dParamHiStop, å¯å‹•域ã®ä¸Šé™ï¼‰;
  2. 目標角速度ã¨ãれを実ç¾ã™ã‚‹ãŸã‚ã®æœ€å¤§ãƒˆãƒ«ã‚¯ã®è¨­å®š
    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å°å‡ºç¾ã™ã‚‹ã‚ˆã†ã«ãƒ—ログラムを変更ã—ã¾ã—ょã†ï¼Ž

コメントをã©ã†ãž

メールアドレスãŒå…¬é–‹ã•れるã“ã¨ã¯ã‚りã¾ã›ã‚“。

1,510 views  (Since 2010-08-11)