4足歩行ロボを作って、うまくいかなくてやめた、って話


サーボモータ8個とArduinoを使った4足歩行ロボット（挫折）🥺

#概要

4足歩行ロボットは大きく分けて2種類ある。[ソフトバンクホークスをPepper君と応援して話題になった、Boston Dynamics社のSpot君](https://youtu.be/J6j1yQHyFvw)のような、逆関節で4足歩行する哺乳類的なロボと、[強襲突撃型トーマス](https://youtu.be/2q82bGtujFA)のような、足を上げてから本体に対して回転させて歩行するクモ型ロボである（クモ型ロボは6本足のものも多い）。この中で、前者のようなロボを作ろうとした。
ボディを3Dプリンタで印刷したサーボを保持するパーツ(マウント)と、タミヤのユニバーサルプレート、およびユニバーサルアームを模した3Dプリンタ製パーツなどで制作、Arduino nanoと16chサーボドライバ(PCA9685)で8個のマイクロサーボを動かすまでには至った。
しかし、座る←→立つ、歩くといった動作がうまくいかずに挫折した。
改善するべき点はいくつかあるし、わかってもいるが、一旦打ち切りにしようと思った。
失敗の原因と思しきものなどを記録として残すことにした。

#材料・使用器具

[Arduino nano 中華製互換品](https://www.amazon.co.jp/dp/B072F5NS4X/ref=cm_sw_r_tw_dp_x_vJFnFbM2QH6HQ)
[16chサーボモータドライバ PCA9685](https://www.amazon.co.jp/dp/B07SLRG5J1/ref=cm_sw_r_tw_dp_x_4FFnFbFH237AN)
[マイクロサーボ(SG-90)　中華製互換品](https://www.amazon.co.jp/dp/B07PHFQY6B/ref=cm_sw_r_tw_dp_x_DHFnFbSPP8NGW)
[QIDI Tech 3Dプリンタ　QIDI X-Smart](https://www.amazon.co.jp/dp/B078Q5HKLR/ref=cm_sw_r_tw_dp_x_3RFnFb1C8YH0M)
[タミヤ　ユニバーサルプレート（2枚セット）](https://www.tamiya.com/japan/products/70157/index.html)
[タミヤ　ユニバーサルアームセット（オレンジ）←3Dプリンタで模したパーツに換装](https://www.tamiya.com/japan/products/70183/index.html)
アクリサンデー
Nintendo SwitchのJoy-Conのスティックのカバー（足先の滑り止め）
M3なべネジ 10mm 12mm ワッシャー　六角ナット
ブレッドボード
ジャンパワイヤ
単三電池　4本
単三電池ボックス
（途中で挫折したため、Arduino本体の外部電源は不使用。モバブか9V電池を使用予定だった。）

#外観

見た目はよくできてると思う
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/83ecb794-aa2a-ed4f-c3b7-b574ab53c454.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/cbd6a05e-0d96-9d2d-3ea7-37a9da5dbaba.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/fea91458-f958-1c61-0016-45da5c91ebd1.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/8ef42621-e17d-0166-333b-937f1ef00675.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/b803a0a9-b772-6d00-c902-c7680cdc63d2.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/75b64509-5b89-de6b-62c9-1f3c83b7d544.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/dd1d94d5-2606-3623-5e55-d9f2238fee4e.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/ce1ffdd3-5e39-2a64-a5da-84a9a16c58f9.jpeg" width=50%>

#動画

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">歩かないンゴｫｫｫｫｫｫｫwwwwwwww <a href="https://t.co/9u6yVQtBtV">pic.twitter.com/9u6yVQtBtV</a></p>&mdash; まーくん (@ogawa_megane) <a href="https://twitter.com/ogawa_megane/status/1293848227930759169?ref_src=twsrc%5Etfw">August 13, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#制作過程メモ

ArduinoスケッチはPCA9685_test1~7
サーボモータの番号は、右前足の腰が0、膝が1、左前足の腰が2、膝が3、右後ろ足の腰が4、膝が5、左後ろ足の腰が6、膝が7。
腰が90°、膝が180°で座る。腰が0°、膝が0°で立つ。（←腰が0°までだと腿を前に出す動作はできない。Spot君みたいな動作を目指すしかない。）
足の角度メモは↓
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/9057bae7-2547-af34-741a-65038f99919c.jpeg" width=50%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678326/4fb65f6c-a235-d1fb-ba64-faa8e0f03373.jpeg" width=50%>


#コード
PCA9685_test_7.ino(歩かせるプログラム。↑の動画のやつ)を載せるが、これを使っても歩けない。もっとうまいやり方があるはず。
<details><summary>PCA9685_test_7.ino(クリックして展開)</summary><div>

```c++:PCA9685_test_7.ino
// PCA9685(サーボモータドライバ)テスト7
// 歩かせようとしたけど、トルク不足か強度不足か、足が浮かず歩かなかった

#include <Wire.h>
#include <PCA9685.h>            //PCA9685用ヘッダーファイル（秋月電子通商作成）

PCA9685 pwm = PCA9685(0x40);    //PCA9685のアドレス指定（アドレスジャンパ未接続時）

#define SERVOMIN 150            //最小パルス幅 (標準的なサーボパルスに設定)
#define SERVOMAX 600            //最大パルス幅 (標準的なサーボパルスに設定)

void setup() {
  pwm.begin();                   //初期設定 (アドレス0x40用)
  pwm.setPWMFreq(60);            //PWM周期を60Hzに設定 (アドレス0x40用)

  // 立つ
  servo_write(0, 180);  // 右前腿を真下に
  servo_write(2, 0);    // 左前腿を真下に
  servo_write(4, 180);  // 右後ろ腿を真下に
  servo_write(6, 0);    // 左後ろ腿を真下に

  servo_write(1, 0);    // 右前すねを180°開く
  servo_write(3, 180);  // 左前すねを180°開く
  servo_write(5, 0);    // 右後ろすねを180°開く
  servo_write(7, 180);  // 左後ろすねを180°開く
  delay(2000);
}

void loop() {
  // 右足シーケンス1
  servo_write(0, 180);  // 右前腿を真下に
  servo_write(2, 0);    // 左前腿を真下に
  servo_write(4, 180);  // 右後ろ腿を真下に
  servo_write(6, 0);    // 左後ろ腿を真下に

  servo_write(1, 10);   // 右前すねを
  servo_write(3, 180);  // 左前すねを180°開く
  servo_write(5, 0);    // 右後ろすねを180°開く
  servo_write(7, 170);  // 左後ろすねを
  delay(250);

  // 右足シーケンス2
  servo_write(0, 180);  // 右前腿を真下に
  servo_write(2, 20);   // 左前腿を
  servo_write(4, 160);  // 右後ろ腿を
  servo_write(6, 0);    // 左後ろ腿を真下に

  servo_write(1, 10);   // 右前すねを
  servo_write(3, 180);  // 左前すねを180°開く
  servo_write(5, 0);    // 右後ろすねを180°開く
  servo_write(7, 170);  // 左後ろすねを
  delay(250);

  // 右足シーケンス3
  servo_write(0, 180);  // 右前腿を真下に
  servo_write(2, 10);   // 左前腿を
  servo_write(4, 170);  // 右後ろ腿を
  servo_write(6, 0);    // 左後ろ腿を真下に

  servo_write(1, 0);    // 右前すねを180°開く
  servo_write(3, 180);  // 左前すねを180°開く
  servo_write(5, 0);    // 右後ろすねを180°開く
  servo_write(7, 180);  // 左後ろすねを180°開く
  delay(250);

  // 左足シーケンス1
  servo_write(0, 180);  // 右前腿を真下に
  servo_write(2, 0);    // 左前腿を真下に
  servo_write(4, 180);  // 右後ろ腿を真下に
  servo_write(6, 0);    // 左後ろ腿を真下に

  servo_write(1, 0);    // 右前すねを180°開く
  servo_write(3, 170);  // 左前すねを
  servo_write(5, 10);   // 右後ろすねを
  servo_write(7, 180);  // 左後ろすねを180°開く
  delay(250);

  // 左足シーケンス2
  servo_write(0, 160);  // 右前腿を
  servo_write(2, 0);    // 左前腿を真下に
  servo_write(4, 180);  // 右後ろ腿を真下に
  servo_write(6, 20);   // 左後ろ腿を

  servo_write(1, 0);    // 右前すねを180°開く
  servo_write(3, 170);  // 左前すねを
  servo_write(5, 10);   // 右後ろすねを
  servo_write(7, 180);  // 左後ろすねを180°開く
  delay(250);

  // 左足シーケンス3
  servo_write(0, 170);  // 右前腿を
  servo_write(2, 0);    // 左前腿を真下に
  servo_write(4, 180);  // 右後ろ腿を真下に
  servo_write(6, 10);   // 左後ろ腿を

  servo_write(1, 0);    // 右前すねを180°開く
  servo_write(3, 180);  // 左前すねを180°開く
  servo_write(5, 0);    // 右後ろすねを180°開く
  servo_write(7, 180);  // 左後ろすねを180°開く
  delay(250);
}
void servo_write(int ch, int ang) { //動かすサーボチャンネルと角度を指定
  ang = map(ang, 0, 180, SERVOMIN, SERVOMAX); //角度（0～180）をPWMのパルス幅（150～600）に変換
  pwm.setPWM(ch, 0, ang);
  delay(1);
}
```

</div></details>

#失敗した原因？

- サーボのトルク不足
立つ動作さえできない。歩く時も足が浮かない。
でもこれより大きいトルクが出せるサーボは秋月で1個1300円、Amazonでも安くて1500円とかするし、重量がかさむ

- 足が長すぎ
もっと短ければトルクの小さいマイクロサーボでもいける？
- 本体が重い
電池がね……単4電池に変えれば電池の重量と容量は半分に減る。有線接続も視野に入れるべきか？
- プログラミング
足が立つような順序、足が浮いて歩くような角度を研究すべき
- バランスが悪い
そもそもうまく立たない。前か横に倒れる。サーボとマウントの角度がそろってない。それぞれの足の角度が違うからバランス崩れる？
- サーボの軸からマウントが外れて回転する
付属のねじ止め(M2タッピング)も限界がある。3Dプリンタ製パーツの嵌めあいも微妙なところ。付属のサーボホーンを利用してどうにかするのがベターか？

#改良したい点・案

- サーボマウントの設計
軸から外れて回転しないようにしたいのと、アームとマウントは別、かつ、ネジ一本で簡単に分離できるような設計にしたい（挟みこむ形にしているので、分離が大変←調整やメンテ性の低下）

- 足の向きの変更
足をSpot君みたいに前足・後ろ足を両方逆関節にするのではなく、前足は順関節(人間の膝的な)にするとか？前後方向に機体が大きくなるけど安定性は増しそう。
- 計画性のなさ
全体の設計図を考えてから作ったほうがいい

#結果と考察

上に示した諸原因により、座る←→立つ、歩くといった動作ができなかった。疲れた~~し萎えた~~のでいったんこのプロジェクトはやめにして、別のロボットなどに着手することにする。
何事もうまくいくとは限らないのだ……失敗を糧に次に繋げよう。🥺