ODE講座29: ヒンジジョイントを一定角度ずつ回すには
ODE(Open Dynamics Engine)講座の29回目です.今回はヒンジジョイントを一定角度ずつ回転させる方法を説明します.
りんごさんから一度ずつヒンジジョイントを回転させるにはどうすればよいかというご質問を頂きました.その回答の1例としてサンプルプログラムを作りましたので参考にしてください.この例は時計の秒針です.1秒ごとに1度ずつ角度を増加しています.
具体的な方法は42,43行目でヒンジジョイントの最小,最大可動域をそれぞれ目標角度に設定しています.この角度をステップ毎に1度ずつ増加させることにより秒針のような動きを実現しています.
ただし,これはステッピングモータのシミュレーションとしては正しくありません.指定の角度を拘束条件として動力学計算をしているためトルクなどは全く考えていないからです.ステッピングモータをシミュレーションするためには,その動作原理をシミュレーションする必要があります.
// stepper.cpp by Kosei Demura 2008-11-23// これはステッピングモータのシミュレータではありません。#include <ode/ode.h> // ODE#include <drawstuff/drawstuff.h> // ODEの描画ライブラリ#ifdef WIN32#include <windows.h>#else#include <unistd.h>#endif#define NUM 360dWorldID world; // 動力学計算世界dBodyID link; // リンクdJointID joint; // 関節static double THETA[NUM]; // 関節目標角[degree]static double l = 1.0, r = 0.02;void start() /*** 描画APIの初期化 ***/{float xyz[3] = { 2, 0, 1.0}; // 視点x, y, z [m]float hpr[3] = { -180.0, 0.00, 0.00}; // 視線(heading, pitch, roll) [°]dsSetViewpoint(xyz,hpr); // 視点と視線の設定}// シミュレーションループ。簡単にするため衝突検出に関するコードは省略。void simLoop(int pause){static int step = 0; // シミュレーションのステップ数double angle; // 現在の関節角度double theta; // 目標角[rad]if (step == 360) step = 0;if (THETA[step] >= 180) THETA[step] = THETA[step] - 360;theta = THETA[step]*M_PI/180.0;do{// 最小,最大可動域を同じ値にすることにより,その角度でヒンジジョイント拘束するdJointSetHingeParam(joint, dParamLoStop, theta); // 最小可動域の設定dJointSetHingeParam(joint, dParamHiStop, theta); // 最大可動域の設定dWorldStep(world, 0.01);angle = dJointGetHingeAngle(joint)*180.0/M_PI; // 現在の関節角[rad]}while (fabs(angle - THETA[step]) > 0.01);printf("step=%d angle=%5.2f \n",step,angle);dsSetColor(1.0,1.0,1.0); // 色の設定(r, g, b) 各値は0~1、ここでは白に設定dsDrawCapsuleD(dBodyGetPosition(link), dBodyGetRotation(link), l, r);step++;#ifdef WIN32Sleep(1000);#elseusleep(1000*1000);#endif}int main(int argc, char *argv[]){dsFunctions fn; // 描画関数dMass mass; // 質量パラメータdouble x = 0, y = 0, z = 1.5; // 重心位置double m = 1; // 質量double anchor_x = 0, anchor_y = 0,anchor_z= 1.0;//回転中心double axis_x = -1, axis_y = 0, axis_z = 0;fn.version = DS_VERSION;fn.start = &start;fn.step = &simLoop;fn.command = NULL;fn.path_to_textures = "../../drawstuff/textures";dInitODE(); // ODEの初期化world = dWorldCreate(); // 動力学計算世界の生成dWorldSetGravity(world, 0, 0, -9.8); // 重力設定link = dBodyCreate(world); // リンクの生成dBodySetPosition(link, x, y, z); // 位置の設定dMassSetZero(&mass); // 質量パラメータの初期化dMassSetCappedCylinderTotal(&mass,m,3,r,l); // リンクの質量計算dBodySetMass(link, &mass); // 質量の設定joint = dJointCreateHinge(world, 0); // ヒンジ関節生成dJointAttach(joint, link, 0); // 関節の取付けdJointSetHingeAnchor(joint, anchor_x, anchor_y,anchor_z); //関節中心の設定dJointSetHingeAxis(joint, axis_x, axis_y, axis_z); // 関節回転軸の設定for (int i=0; i<NUM; i++) THETA[i] = i;dsSimulationLoop(argc, argv, 640, 570, &fn); // シミュレーションループdCloseODE();return 0;}
