Ancient-models

械電八屋

ロボット製作・3Dプリンタ

【人型ロボ開発記#1】3軸脚歩行モーション

「ゲームのモーションをリアルロボットで再現したい」
TPV系のゲームをプレイしているとき、ふと思いつきました。
ダッシュ・ジャンプ・クライミング・剣技・射撃...
機械が動くシーンを見るのが好きな私ですが、ロボットにダイナミックなアクションを実行させる面白さを追求してみたいと思いました。

現実世界でロボットを動かすことは、地形や障害物との衝突、機体重心制御、機体の反応速度などといった観点から、ゲーム世界でキャラクターを操作するより難しく、歩行という単純動作においても複雑な制御を必要とします。

市販の人型ロボやロボットアーム等をほぼ触ったことが無い私は、まず、人型ロボットをサーボ使って自作するところから、始めようと思います。

1.人型モデルを考える

人の骨格・筋肉構造から、ロボットモデルを決定します。
モーションを実行するために、まず最低限の構成で組んでみます。
部位は胴体・腰・腕2部・脚2部。軸位置は腰2軸・肩3軸・肘1軸・手首2軸・股3軸・膝1軸・足首3軸(片側)とします。(図1)

図1 人型モデル

サーボの電力消費、多軸型モーションの複雑さ、本体重量等の制限を考慮し、1号機の制作を目指します。

2.「3軸脚」

今回は、下半身の歩行モーションを作ってみました。実際に歩行させるのは大分先になりますが、ロボットを宙に浮かせた状態でモーションを実行させます。
下半身のモデルは目標が片側計5軸ですが、まずは簡単なモーションを見るため、3軸構成の脚モデル「3軸脚」を組みます。(図2)

図2 3軸脚

サーボはLewansoulのLDX-218を使用。ブラケットと3Dプリントパーツでモデルを組み、塩ビパイプで支柱を作成しました。制御基板はArduinoを使います。
↓回路図

図3 回路図

サーボ制御には、ロボットアームなどに用いられる「逆運動学」を適用します。ロボット脚の場合、逆運動学は足先の座標と姿勢角から各関節軸の角度を決定する方法です。今回の3軸脚・逆運動学モデルを図4に示します。

図4 3軸脚・逆運動学モデル

3.歩行モーション1「5ステップ型」

歩行モーションの制作にあたり、まず足先の軌道を設定します。仮想地面を足裏がなでるようなモーションを目標にします。歩行動作の順番は
①前脚位置 ②踏み込み ③地面をなでる ④蹴り ⑤後ろ脚位置
とし、このループを繰り返します。

図5 歩行モーションプロセス

この5段階の足位置座標を目標とし、サーボを動作させることにより、歩行モーションを再現します。5個の足先座標を点々と移動する動作であるため、カクカクな歩行になります。実行結果はこちらです。

www.youtube.com

Arduinoコード

#include <Servo.h>
int Servo1_Socket = 3;
int Servo2_Socket = 5;
int Servo3_Socket = 6;

Servo servo1;
Servo servo2;
Servo servo3;

float th1 = 0, th2 = 0, th3 = 0; 
float phi;
float L1 = 60.2, L2 = 60.2, L3 = 33; 
float x,y,alpha;

void setup(){
  servo1.attach(Servo1_Socket,500,2500);
  servo2.attach(Servo2_Socket,500,2500);
  servo3.attach(Servo3_Socket,500,2500);
  set_servo();
  
  x = 0;
  y = 116.56;
  alpha = 0;
  }

void loop(){
  //process1
  x = 50.90;
  y = 105.14;
  alpha = 60;
  ik();
  set_servo();
  //process2
  x = 20;
  y = 112.23;
  alpha = 60;
  ik();
  set_servo();
  //process3
  x = 0;
  y = 116.56;
  alpha = 90;
  ik();
  set_servo();
  //process4
  x = -20;
  y = 112.23;
  alpha = 120;
  ik();
  set_servo();
  //process5
  x = -50.90;
  y = 105.14;
  alpha = 120;
  ik();
  set_servo();
  }

void ik(){
  float x1, y1, phi, ld, k, th_r1, th_r2, th_r3, alpha_r;
  float A, B, C, D;
  alpha_r = alpha * 3.14/180;
  x1 = x - L3 * cos(alpha_r);
  y1 = y - L3 * sin(alpha_r);
  A = x1*x1 + y1*y1 + L1*L1 + L2*L2;
  B = x1*x1 + y1*y1;
  C = L1*L1*L1*L1 + L2*L2*L2*L2;
  k = sqrt(A*A - 2 * (B*B + C));
  th_r1 = atan2(y1, x1) - atan2(k, B + L1*L1 - L2*L2);
  th_r2 = atan2(k, B - L1*L1 - L2*L2);
  th_r3 = 3.14/2 + alpha_r - (th_r1 + th_r2);
  th1 = th_r1 * 180/3.14;
  th2 = th_r2 * 180/3.14;
  th3 = th_r3 * 180/3.14;
  }

void set_servo(){
  servo1.write(th1);
  servo2.write(th2);
  servo3.write(th3);
  }

4.歩行モーション2「スイープ型」

次は5ステップ型を改良し、スムーズなモーションを目指します。各座標間の移動を直線補間で関数的に表し、一定時間ごとの座標を逐次計算するコードを作りました。なお、足裏で地面をなでる動作は、足首軸の回転に伴い座標移動を行うものとしています。実行結果はこちらです。

www.youtube.com

Arduinoコード

#include <Servo.h>
int Servo1_Socket = 3;
int Servo2_Socket = 5;
int Servo3_Socket = 6;

Servo servo1;
Servo servo2;
Servo servo3;

float th1 = 0, th2 = 0, th3 = 0; 
float phi = 3.14;
float L1 = 60.2, L2 = 60.2, L3 = 33; 
float x,y,alpha,xH,yH,xT,yT;
float q = 55, p = 30, r = 65, t = 60, n = 140;

void setup(){
  servo1.attach(Servo1_Socket,500,2500);
  servo2.attach(Servo2_Socket,500,2500);
  servo3.attach(Servo3_Socket,500,2500);
  set_servo();
  x = 70;
  y = 90;
  alpha = 60;
  }

void loop(){
  //process1-2
  while(x >= 53){
    y = -0.7349 * x + 141.44;
    ik();
    set_servo();
    x = x - 1;
  //process2-3
  xH = 40;
  yH = 110;
  alpha = 60;
  while(alpha <= 90){
    x = xH + 15 * cos(phi/2 - alpha * phi/180);
    y = yH - 15 * sin(phi/2 - alpha * phi/180);
    ik();
    set_servo();
    alpha++;
    xH = xH -q/p;
    }
  //process3-4
  xT = 25;
  yT = yH;
  while(xT >= 0){
    x =  -( 25 * cos(alpha * phi/180 - phi/2) - xT );
    y = yT - 25 * sin(alpha * phi/180 - phi/2);
    ik();
    set_servo();
    alpha ++;
    xT = xT - r/p;
  }
  while(xT <= 40){
    x = -( xT + 25 * cos(alpha * phi/180 - phi/2));
    y = yT - 25 * sin(alpha * phi/180 - phi/2);
    ik();
    set_servo();
    alpha ++;
    xT = xT + r/p;
  }
  //process4-5
  x = -62;
  while(x >= -70){
    y = 0.8383 * x + 148.68;
    ik();
    set_servo();
    thprint();
    x = x -1;
  }
  //process5-1
  while(x <= 70){
    y = 90;
    ik();
    set_servo();
    thprint_2();
    x++;
    alpha = alpha - t/n;
  }
 }

void ik(){
  float x1, y1, phi, ld, k, th_r1, th_r2, th_r3, alpha_r;
  float A, B, C, D;
  alpha_r = alpha * 3.14/180;
  x1 = x - L3 * cos(alpha_r);
  y1 = y - L3 * sin(alpha_r);
  A = x1*x1 + y1*y1 + L1*L1 + L2*L2;
  B = x1*x1 + y1*y1;
  C = L1*L1*L1*L1 + L2*L2*L2*L2;
  k = sqrt(A*A - 2 * (B*B + C));
  th_r1 = atan2(y1, x1) - atan2(k, B + L1*L1 - L2*L2);
  th_r2 = atan2(k, B - L1*L1 - L2*L2);
  th_r3 = 3.14/2 + alpha_r - (th_r1 + th_r2);
  th1 = th_r1 * 180/3.14;
  th2 = th_r2 * 180/3.14;
  th3 = th_r3 * 180/3.14;
  }

void set_servo(){
  servo1.write(th1);
  servo2.write(th2);
  servo3.write(th3);
  }


次回は軸数7の制御方法を考え、2脚での歩行モーションを再現しようと思います。
ご覧いただきありがとうございました。