上腕二頭筋とサーボモーターが奏でる至高のプロテインシェイク

こんにちは、普段デザイナーをしている**ウエハラ シンペイ**です。

前回開発したChatGPTによるヘルシーレシピBotで、
食事改善に取り組めたのですが、目指すべきモテボディにはそれだけでは足りませんでした。

https://qiita.com/PEI__/items/2418a985f9b2539f26cf

### そう、チカラ is パワー「筋肉」ですね。

![barbell-1839086_1280.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618353/f8e740fa-d3b5-efa3-4772-2da02ad59a24.jpeg)


知識先行型ダイエッターの私が調べた限り、筋肉は１日のエネルギー代謝量が最も多いとされていて、筋肉をつけるほど太りにくい体になるらしいです。なので今回はマッスルボディを生み出すアプリケーションを作っていきます。

# プロテインはしっかり混ざってないとマズい
筋肉愛好家からプロテイン飲んどきゃなんとかなる勢まで、全員が悩んでいるプロテインの混ざり具合。一応液体と先に入れたり量をしっかり測ったりしても、やっぱりダマになる部分が残ってしまいます。

ならば、その問題をどう解決するべきか。答えは１つでした。

### そう、チカラ is パワー「筋肉」ですね。

![man-3563462_1280.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618353/9302f84d-573f-2ee8-011d-7998ea020d42.jpeg)

トレーニング中の筋肉をシェイクすることに使うことによって、直後のゴールデンタイムに最高のプロテインができるんじゃないかと。

# 筋トレに合わせてプロテインが自動でシェイクされるアプリをつくる

### こんなイメージ
![イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618353/fd51a04f-8d1f-0bea-bc62-647217b1a4b2.png)


このような感じで、ダンベルや腕立てに合わせて超音波センサーにダンベルが近づくとサーボモーターが左右に動きプロテインがシェイクされることを目指します！筋肉番付のアレです、アレ。

<iframe width="560" height="315" src="https://www.youtube.com/embed/H0lrsN1pxwY?si=bcIj0p1PCotusl0u&amp;start=352" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


### 開発環境
Github codespaces
node.js (v20.8.1)
obniz Board 1Y
超音波距離センサー
サーボモーター


# とりあえずサーボに無理やりシェイカーをつけてみる

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ミニハッカソン初号機。ダンベルの上げ下げに合わせてプロテインがシェイクされるマッチョなプロダクトを目指す。<br><br>暴れてんなー<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/minihack?src=hash&amp;ref_src=twsrc%5Etfw">#minihack</a> <a href="https://twitter.com/hashtag/%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#エントリー</a> <a href="https://twitter.com/hashtag/%E3%82%AC%E3%83%A0%E3%83%86?src=hash&amp;ref_src=twsrc%5Etfw">#ガムテ</a> <a href="https://t.co/ij1RWDBUkm">pic.twitter.com/ij1RWDBUkm</a></p>&mdash; PEI (@PEIxxxxxxxx) <a href="https://twitter.com/PEIxxxxxxxx/status/1728250679318519959?ref_src=twsrc%5Etfw">November 25, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

割り箸にガムテで無理やり固定してみましたが、一旦サーボモーターが動くことは確認できました。
obniz Boardについているボタンの左右で動くようにしているんですが、すんごい暴れておる。

この時点ではサーボモータのパワー不足と縦にシェイクがむずかしいのかなと思ったので他の方法を考えます。


<details><summary>テスト用のコード</summary>

```javascript:test.js
const Obniz = require('obniz');
const obniz = new Obniz('Obniz_ID'); // Obniz_IDに自分のIDを入れます

obniz.onconnect = async function () {
  // サーボモータを利用
  const servo = obniz.wired('ServoMotor', { signal: 2 });

  // 角度を保持する変数
  let degrees = 90.0;

  // ディスプレイ表示（初期画面）
  obniz.display.clear();
  obniz.display.print('Hello obniz!');

  // スイッチの反応を常時監視
  // 「スイッチ状態が変化した瞬間に1回だけ実行される」ことに注意しましょう
  obniz.switch.onchange = function (state) {
    // スイッチの状態で角度を決め、最後に動かします
    if (state === 'push') {
      // スイッチが押されている状態
      console.log('pushed');
      degrees = 45.0;
    } else if (state === 'right') {
      // 右にスイッチを倒したとき
      console.log('right');
      degrees = 45.0;
    } else if (state === 'left') {
      // 左にスイッチを倒したとき
      console.log('left');
      degrees = 135.0;
    } else {
      // スイッチが押されていない状態
      console.log('released');
      degrees = 90.0;
    }
  
  // ディスプレイに角度を表示
  obniz.display.clear();
  obniz.display.print(`Current: ${degrees} deg`);
  // サーボを指定の角度まで動かします
  servo.angle(degrees);
  }
}
```

</details>


# 超音波センサーに近づいたらシェイカーが左右にするようにする
超音波センサーを使って物体が500mmまで近づいたらサーボモータが動くようにしていきます。

### まずは超音波センサーで距離を取得する
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618353/9bcb37ac-4b63-1645-cfb4-71153625b442.gif">


無事、距離を取得してくれるようになりました！
![スクリーンショット 2023-11-28 0.37.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618353/6ba547a9-97db-be2b-3d9e-3333e66d277f.png)

###サーボモータと土台の作成
続いて、プロテインシェイカーが回転するようなケースを作成。なんかちょうど良さそうなウェットティッシュケースのそこに土台とサーボボーターを取り付けてそれっぽいものが完成！

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618353/eeb0a969-917c-2800-9c4d-b1e1bab136e1.png">

<details><summary>実際のコード</summary>

```javascript:protein.js
// ########################################
// obniz処理部分
// Obniz_ID：自分のobniz ID（XXXX-XXXX）
// ########################################
const Obniz = require('obniz');
const obniz = new Obniz('obniz ID');

let sendToID;

// obnizと接続確立したとき
obniz.onconnect = async () => {
  obniz.display.clear();
  obniz.display.print('obniz Ready');

  let servo; // サーボモータのインスタンス

  // サーボを180度動かす関数
  const moveServoTo180Degrees = async () => {
    if (!servo) {
      // サーボが初めて動く場合にのみ初期化
      servo = obniz.wired('ServoMotor', { signal: 11 });
    }

    // 左右どちらに動かすかを決定
    const angle = Math.random() > 0.5 ? 180 : 0;

    // サーボを動かす
    servo.angle(angle);
    await obniz.wait(100); // 1秒待機
  };

  // 超音波センサーの処理を記述
  const hcsr04 = obniz.wired('HC-SR04', { gnd: 0, echo: 1, trigger: 2, vcc: 3 });

  setInterval(async function () {
    // 距離を取得
    let distance = await hcsr04.measureWait();

    // 距離(mm)をターミナルに表示
    console.log(distance + ' mm');
    // obnizディスプレイに表示
    // 一度消してから距離+mmの単位を表示
    obniz.display.clear();
    obniz.display.print(distance + ' mm');

    // 距離が1000mm以下かどうかの判定
    if (distance <= 500) {
      // サーボを動かし続ける
      moveServoTo180Degrees();
    }
  }, 500); // 500ミリ秒 = 0.5秒おきに実行
}

// ########################################
// Expressサーバー部分
// ########################################
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

// PORT番号のポートでサーバーを開始
app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

```

</details>


# 実際に試してみた！

と思ったんですが、まさかのジャンパワイヤーが短くて届かず、、、
忘れてた😭

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">自動プロテインシェイクシステムがジャンパワイヤー短すぎた問題にて一時中断😭<br><br>長いやつ買お。。<a href="https://twitter.com/hashtag/Protoout?src=hash&amp;ref_src=twsrc%5Etfw">#Protoout</a> <a href="https://twitter.com/hashtag/%E5%A4%B1%E6%95%97?src=hash&amp;ref_src=twsrc%5Etfw">#失敗</a> <a href="https://twitter.com/hashtag/%E7%AD%8B%E3%83%88%E3%83%AC?src=hash&amp;ref_src=twsrc%5Etfw">#筋トレ</a> <a href="https://t.co/TeMj3eEWhN">pic.twitter.com/TeMj3eEWhN</a></p>&mdash; PEI (@PEIxxxxxxxx) <a href="https://twitter.com/PEIxxxxxxxx/status/1729501468619833381?ref_src=twsrc%5Etfw">November 28, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>



# 感想
初めてセンサー類を使ってプログラムを作ってみたんですが、ソフトウェアにはない感動がありますね。
ただ、ジャンパワイヤー長くしても筋トレの邪魔なんで無線化してみたり、サーボモータに高トルクに交換したりと今後色々と改善していきたいです！

プログラムもムキムキボディも一日にしてならず！