13. ç°¡å˜ãªåˆ¶å¾¡

3関節マニピュレータã®ã‚·ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚¿ã€€ï¼ˆã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã¯ãŸã£ãŸ100行)
ODE (Open Dynamics Engine) åˆç´šè¬›åº§ã®ç¬¬ï¼‘3回目ã§ã™ã€‚
今回ã¯ä»Šã¾ã§ã®çŸ¥è˜ã‚’æ•´ç†ã™ã‚‹ãŸã‚ã«ã€ç°¡å˜ãªï¼“関節マニピュレータã®ãƒ—ãƒã‚·ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚¿ã‚’作ã£ã¦ã¿ã¾ã—ょã†ã€‚ã“れã¯ODEを使ã†ã¨ã€ŒãŸã£ãŸï¼‘ï¼ï¼è¡Œç¨‹åº¦ã§ã“ã®ã‚ˆã†ãªã‚·ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚¿ãŒã§ãã‚‹ã‚“ã§ã™ï¼Žã€ã¨ã„ã†ãƒ—ãƒã‚°ãƒ©ãƒ ãªã®ã§è¡çªè¨ˆç®—部分ã¯çœç•¥ã—ã¦ã„ã¾ã™ï¼Žã“ã®ãƒãƒœãƒƒãƒˆã¯ã‚ãƒ¼ãƒœãƒ¼ãƒ‰ã§æ“作å¯èƒ½ã§ã™ï¼Ž ãƒãƒœãƒƒãƒˆã®ç¬¬ï¼‘関節ã¯jï¼ˆå¢—åŠ ï¼‰åˆã¯f(減少)ã‚ーã§ï¼Œç¬¬ï¼’関節ã¯dåˆã¯kã‚ーã§ï¼Œç¬¬ï¼“関節ã¯såˆã¯lã‚ーã§å‹•ã‹ã™ã“ã¨ãŒã§ãã¾ã™ã€‚
速度&比例制御
関節を制御ã™ã‚‹æ–¹æ³•を説明ã—ã¾ã™ã€‚ODEã®é–¢ç¯€ã«ã¯ãƒ¢ãƒ¼ã‚¿ãŒå†…蔵ã•れã¦ã„ã¾ã™ï¼Žã“ã®ãƒ¢ãƒ¼ã‚¿ã®ãƒˆãƒ«ã‚¯ã‚’コントãƒãƒ¼ãƒ«ã™ã‚‹ãƒˆãƒ«ã‚¯åˆ¶å¾¡ã‚‚å¯èƒ½ã§ã™ãŒï¼Œã‚·ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚¿ã®å®‰å®šæ€§ã‚’考ãˆã‚‹ã¨ãƒ¢ãƒ¼ã‚¿ã®å›žè»¢é€Ÿåº¦ã‚’コントãƒãƒ¼ãƒ«ã™ã‚‹é€Ÿåº¦åˆ¶å¾¡ãŒãŠå‹§ã‚ã§ã™ï¼Žã“ã“ã§ã¯é€Ÿåº¦åˆ¶å¾¡ã®å®Ÿç¾æ³•ã«ã¤ã„ã¦èª¬æ˜Žã—ã¾ã™ï¼Ž
速度制御ã®ä¸ã§ã‚‚色々ã‚りã¾ã™ãŒï¼Œã“ã“ã§ã¯æœ€ã‚‚ç°¡å˜ãªP制御(比例制御)を説明ã—ã¾ã™ï¼Žã“れã¯ç›®æ¨™å€¤ã¨ç¾åœ¨å€¤ã®å·®ã«æ¯”例ã—ã¦é–¢ç¯€ã®è§’速度を変更ã™ã‚‹æ–¹æ³•ã§ã™ã€‚関節角度ã®ç¾åœ¨å€¤ãŒç›®æ¨™å€¤ã¨é›¢ã‚Œã¦ã„ã‚‹å ´åˆã¯å¤§ããªè§’速度を与ãˆã€ç›®æ¨™å€¤ã¨åŒã˜å ´åˆã¯è§’速度ãŒï¼ã¨ãªã‚Šé–¢ç¯€ãŒåœæ¢ã—ã¾ã™ã€‚ã¾ãŸã€ç¾åœ¨å€¤ãŒç›®æ¨™å€¤ã‚’ã¨ãŠã‚Šè¶Šã—ãŸå ´åˆã¯ã€ç¬¦å·ãŒãƒžã‚¤ãƒŠã‚¹ã«ãªã‚‹ãŸã‚回転ãŒå転ã—ã€ç¾åœ¨å€¤ãŒç›®æ¨™å€¤ã«è¿‘ããªã‚Šã¾ã™ã€‚
ã“れを実ç¾ã—ã¦ã„る関数ãŒcontrolã§ã™ã€‚関節ã®ãƒ‘ラメータdParamVelã¯ç›®æ¨™è§’速度ã§ã€dParamFMaxã¯ãã®è§’速度を実ç¾ã™ã‚‹ãŸã‚ã«ã‚¸ãƒ§ã‚¤ãƒ³ãƒˆãŒç™ºæ®ã§ãる最大 トルクã§ã™ã€‚dParamFMaxã‚’ï¼ã«è¨å®šã™ã‚‹ã¨ç›®æ¨™è§’速度をè¨å®šã—ã¦ã‚‚トルクãŒï¼ãªã®ã§é–¢ç¯€ã¯å‹•ã„ã¦ãれã¾ã›ã‚“。
ã§ã¯ï¼Œã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã‚’次ã«ç´¹ä»‹ã—ã¾ã—ょã†ï¼Ž
éŽåŽ»ã®ODEåˆç´šè¬›åº§ã‚’ç†è§£ã•れã¦ã„ã‚‹æ–¹ã«ã¯ç°¡å˜ãªã®ã§èª¬æ˜ŽãŒã»ã¨ã‚“ã©ã„らãªã„ã¨æ€ã„ã¾ã™ï¼Žã‚ã‹ã‚‰ãªã„箇所ãŒã‚れã°ã‚³ãƒ¡ãƒ³ãƒˆã«æ›¸ã込んã§ãã ã•ã„.補足説明をã—ã¾ã™ã€‚
// sample13.cpp 3 DOF manipulator by Kosei Demura 2006-2008
#include "ode/ode.h" // ODE
#include "drawstuff/drawsutt.h" // ODEã®æç”»ãƒ©ã‚¤ãƒ–ãƒ©ãƒª
#define NUM 4 // リンク数(土å°å«ã‚€)
dWorldID world; // 動力å¦è¨ˆç®—世界
dBodyID link[NUM]; // リンク link[0]ã¯åœŸå°
dJointID joint[NUM]; // 関節 joint[0]ã¯åœŸå°ã¨åœ°é¢ã‚’固定
static double THETA[NUM] = { 0.0, 0.0, 0.0, 0.0}; // 関節目標角[rad]
static double l[NUM] = { 0.10, 0.90, 1.00, 1.00}; // リンク長[m]
static double r[NUM] = { 0.20, 0.04, 0.04, 0.04}; // リンクåŠå¾„[m]
void control() { /*** P制御 ****/
static int step = 0; // シミュレーションã®ã‚¹ãƒ†ãƒƒãƒ—æ•°
double k1 = 10.0, fMax = 100.0; // k1:比例ゲイン, fMax:最大トルク[Nm]
printf("\r%6d:",step++);
for (int j = 1; j < NUM; j++) {
double tmpAngle = dJointGetHingeAngle(joint[j]); // ç¾åœ¨ã®é–¢ç¯€è§’[rad]
double z = THETA[j] - tmpAngle; // z: 残差=目標関節角ï¼ç¾åœ¨é–¢ç¯€è§’
dJointSetHingeParam(joint[j], dParamVel, k1*z); // 角速度ã®è¨å®š
dJointSetHingeParam(joint[j], dParamFMax, fMax); // 最大トルクã®è¨å®š
}
}
void start() { /*** æç”»APIã®åˆæœŸåŒ– ***/
float xyz[3] = { 3.04, 1.28, 0.76}; // 視点x, y, z [m]
float hpr[3] = { -160.0, 4.50, 0.00}; // 視線(heading, pitch, roll) [°]
dsSetViewpoint(xyz,hpr); // 視点ã¨è¦–ç·šã®è¨å®š
}
void command(int cmd) { /*** ã‚ーæ“作関数 ***/
switch (cmd) {
case ‘j‘: THETA[1] += 0.05; break; // jã‚ãƒ¼ãŒæŠ¼ã•れるã¨THETA[1]ã®è§’度ãŒ0.05[rad]å¢—åŠ ã™ã‚‹
case ‘f’: THETA[1] -= 0.05; break;
case ‘j’: THETA[2] += 0.05; break;
case ‘d’: THETA[2] -= 0.05; break;
case ‘l’: THETA[3] += 0.05; break;
case ’s’: THETA[3] -= 0.05; break;
}
// 目標角度ãŒé–¢ç¯€å¯å‹•域を越ãˆãªã„よã†ã«åˆ¶é™ã™ã‚‹
if (THETA[1] < - M_PI) THETA[1] = - M_PI; // M_PI:円周率
if (THETA[1] > M_PI) THETA[1] = M_PI;
if (THETA[2] < -2*M_PI/3) THETA[2] = - 2*M_PI/3;
if (THETA[2] > 2*M_PI/3) THETA[2] = 2*M_PI/3;
if (THETA[3] < -2*M_PI/3) THETA[3] = - 2*M_PI/3;
if (THETA[3] > 2*M_PI/3) THETA[3] = 2*M_PI/3;
}
// シミュレーションループ。簡å˜ã«ã™ã‚‹ãŸã‚è¡çªæ¤œå‡ºã«é–¢ã™ã‚‹ã‚³ãƒ¼ãƒ‰ã¯çœç•¥ã€‚
void simLoop(int pause) {
control();
dWorldStep(world, 0.02);
// ãƒãƒœãƒƒãƒˆã®æç”»
dsSetColor(1.0,1.0,1.0); // 色ã®è¨å®š(r, g, b) å„値ã¯0~1ã€ã“ã“ã§ã¯ç™½ã«è¨å®š
for (int i = 0; i < NUM; i++ ) // ãƒãƒœãƒƒãƒˆã®ãƒªãƒ³ã‚¯ã‚’ã‚«ãƒ—ã‚»ãƒ«ã§æç”»
dsDrawCapsuleD(dBodyGetPosition(link[i]), dBodyGetRotation(link[i]), l[i], r[i]);
}
int main(int argc, char *argv[]) {
dsFunctions fn; // æç”»é–¢æ•°
dMass mass; // 質é‡ãƒ‘ラメータ
double x[NUM] = {0.00}, y[NUM] = {0.00}; // é‡å¿ƒä½ç½®
double z[NUM] = { 0.05, 0.50, 1.50, 2.55};
double m[NUM] = {10.00, 2.00, 2.00, 2.00}; // 質é‡
double anchor_x[NUM] = {0.00}, anchor_y[NUM] = {0.00};
double anchor_z[NUM] = { 0.00, 0.10, 1.00, 2.00};//回転ä¸å¿ƒ
double axis_x[NUM] = { 0.00, 0.00, 0.00, 0.00}; //回転軸
double axis_y[NUM] = { 0.00, 0.00, 1.00, 1.00};
double axis_z[NUM] = { 1.00, 1.00, 0.00, 0.00};
fn.version = DS_VERSION; fn.start = &start;
fn.step = &simLoop; fn.command = &command;
fn.path_to_textures = "../../drawstuff/textures";
dInitODE(); // ODEã®åˆæœŸåŒ–
world = dWorldCreate(); // 動力å¦è¨ˆç®—世界ã®ç”Ÿæˆ
dWorldSetGravity(world, 0, 0, -9.8); // é‡åŠ›è¨å®š
for (int i = 0; i < NUM; i++) { // リンクã®ç”Ÿæˆã¨è¨å®š
link[i] = dBodyCreate(world); // リンクã®ç”Ÿæˆ
dBodySetPosition(link[i], x[i], y[i], z[i]); // ä½ç½®ã®è¨å®š
dMassSetZero(&mass); // 質é‡ãƒ‘ラメータã®åˆæœŸåŒ–
dMassSetCappedCylinderTotal(&mass,m[i],3,r[i],l[i]); // リンクã®è³ªé‡è¨ˆç®—
dBodySetMass(link[i], &mass); // 質é‡ã®è¨å®š
}
joint[0] = dJointCreateFixed(world, 0); // 固定関節(土å°ã¨åœ°é¢ã®å›ºå®šï¼‰
dJointAttach(joint[0], link[0], 0); // 固定関節ã®å–付ã‘
dJointSetFixed(joint[0]); // 固定関節ã®è¨å®š
for (int j = 1; j < NUM; j++) {
joint[j] = dJointCreateHinge(world, 0); // ヒンジ関節生æˆ
dJointAttach(joint[j], link[j-1], link[j]); // 関節ã®å–付ã‘
dJointSetHingeAnchor(joint[j], anchor_x[j], anchor_y[j],anchor_z[j]); //関節ä¸å¿ƒã®è¨å®š
dJointSetHingeAxis(joint[j], axis_x[j], axis_y[j], axis_z[j]); // 関節回転軸ã®è¨å®š
}
dsSimulationLoop(argc, argv, 640, 570, &fn); // シミュレーションループ
dCloseODE();
return 0;
}
ãªãŠã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã¯ã“ã“ã‹ã‚‰ãƒ€ã‚¦ãƒ³ãƒãƒ¼ãƒ‰ã§ãã¾ã™ã€‚ ãŠã—ã¾ã„.