マイ アーム

Created Date: 2024-08-15/ updated date: 2024-11-07
Owner & Collaborators
License
Summary
3Dプリント自助具コンテスト2024応募作品
手の不自由な方のための食事介助ロボットです

Materials

    Tools

      Blueprints

        Making

        • 鍼灸マッサージ師の私が、手の不自由な方が操作可能な食事介助ロボットアームを製作してみました。
          押す引く2つの動作で4つのボタンを押し、2つのお皿を回転させながら食事をする事ができます。

          • ・座位時に軽い介助下で肘の屈曲伸展が可能  (自力では不可)
            ・手関節、手指の筋力は僅かにある程度 (物を握ることは不可)
          • Aさん(筋ジストロフィー)


          • 5年前、介護職員としてAさんの食事介助(介助者が、Aさんの手をスプーンとともに握りこんでの全介助)をしていた際、多少本人の筋力を感じたため、「何か装備を着ければ自力での食事ができるのではないか?」と伝えたところ、「じゃあ作って下さい」と頼まれた事がきっかけです。
          • 当初は木製のボディにゴムを使った形から制作を開始。5年間の期間、月1回フィッティングをしながらの試行錯誤。その後3Dプリンターとモーター、マイコンを使ったロボットアームへ。
          • 全介助だった食事が、自らおかずを選択し、おおよそ自分のペースで食事をする事ができるようになる。
        • 手袋のような物を作りスプーンを固定してみる。
          前腕の下にはバケツを解体し、カーブのついた側面でスプーンを動かせるように工夫してみた。



          • 腕の筋力が弱く、スプーンを持ち上げることができなかった。
          • 喜びながらも、「スプーンを握りたいですね。」
          • 自身の指でスプーンを握ることによって、スプーンから伝わる食べ物の感触を感じたかったのではないか。
        • 木材を蛇腹のように組み立て、バネをつけ、可動を補助した。


          • 動きを調節することができなかった。

          • 腕の曲げ伸ばしをしながら、「ラクに動きますね。コントロールが難しいですね。」
        • 肘の動きを固定し、お皿の下にターンテーブルを置き回転させる事によって、食べ物をすくえるように工夫してみた。



          • 初めて食事を口に運ぶ事に成功した。
            お皿が自動的に回転し続けてしまうので、食べたい物を選ぶという動作ができなかった。

          • ゴムの調節が難しく、過剰な筋力を使うため身体的負担の心配がある
          • 嬉しそうに、「もっと筋トレして、完食できるようにしますね。」
          • Aさんと雑談している際に、「AIやロボットアーム3Dプリンターなどが一般化しているので、これからはそういう自助具が使えるようになる未来があるかも知れない」と伝えたところ、「じゃあ作って下さい」と頼まれました。

            当初、私は自力で食事をとることができる自助具に執着していましたが、本人の希望(ロボットに対する興味)もあり、ロボットアームにチャレンジしてみることにしました。

            私自身、PCに疎く、マイコン3D CADなどの知識が全くなかったため、ネット等で検索し、自己流で制作を進める事に…
        • 最初はジョイスティックなどを使いロボット操作を行おうと考えていましたが、十字キーの左右の動きが困難なため、まずはボタン2つでロボットを制御できるように工夫してみました。


          • 良かった点
            • 3回に1回ほどはおかずをすくう事ができるようになった。
            • 時間はかかるがほぼ完食することが可能。

            悪かった点
            • ロボットアームは負荷がかかった時に誤作動を起こす事があり、危険である。   
            • ターンテーブルを逆回転するという配線が難しく、一方向でお皿を回すため、おかずをすくうのに時間がかかる。
          • 「これは暴れ馬ですね。飼い慣らせるようになりたいですね。」

          • 誤作動を起こす原因となる負荷を減らすため、紐を使ってアームを吊るし遊び、ゆとりを作りました。
          • ターンテーブルとロボットアームの配線を分け、正転、逆転スイッチを使いました。
          • Aさんの筋力を再評価し、どの方向で1番コントローラーを動かしやすいか、本人と再確認しました。
          • 誤作動が減り、また衝撃を吸収される役割も果たし、精度が上がった。
            • 緊急停止機能など安全装置の必要性がある
            • プログラミングに対する知識が少なく、毎回設定に時間がかかるため、すぐに利用できるような立ち上げの設定が必要

          • 「ありがとうございます。次はラーメンが食べたいです(笑)」  私「‼」
            • スプーンを上手く回転させれば、自助皿の曲面を利用してすくうことができる
            • お皿を回転することができれば、スプーンを中央から端に動かす一方向の動きだけで、ほとんどの食べ物をすくうことができる
          • ロボットアームと人の身体は同じであると感じることがありました。
            ボタンが押されるまで、ロボットアームは同じ体勢で維持するようプログラミングされていますが、過剰な負荷などがかかると揺れを起こし止まらなくなります。再びボタンを押すと揺れは止まります。この状態がパーキンソン病などに見られる安静時震戦に似ていると感じました。
            負荷や電圧が上がらないように肩甲骨などに負担を吸収する機能をつけてみましたが、思うようにいきませんでした。結果、より強力なモーターを使うことで揺れはなくなりましたが、固定力を強くすることで動きを制御するのではなく、人の身体のように姿勢の変化で動きを制御できるようになればと模索中です。

          • 当初は、自分の力で物を食べるということだけに着目して製作を行っていましたが、長い期間Aさんと接するうちに、彼の考え方や価値観を知る事ができました。なかなか成果が出なかった時に、「この試行錯誤しながら考えている時間が楽しいんですよ」と言われたことにとても感銘を受けました。
            ただ食事を食べるという目標を達成するだけの物作りなのではなく、そこに辿り着くまでのAさんとの時間こそが大切な時間だと感じました。

          • ELEGOO PLAフィラメント 1.75mmを使用

            • フレーム上下
            • 皿台2つ
            • 滑車ネジ
            • 皿受け
            • 肩甲骨
            • 上腕
            • 上腕横・後ろ蓋
            • 前腕
            • 手蓋
            • コントローラー台・コントローラーパッド
            • Aruduino
            • USB昇降圧コンバーター
            • PCA9685 PWMサーボモーターモジュールドライバーボード
            • ジャンパーワイヤー
            • ロッカースイッチ6ターミナル3ポジション
            • MG996R
            • サーボホーン
            • 小型モーター
            • サーボコネクター延長ケーブル
            • 正転逆転スイッチ
        • ①長コードをコントローラー台のボタン穴(小)から背面の穴に通す
          ②コードをスイッチに取り付ける(極性なし)
          ③スイッチをボタン穴にはめ込む
          ④ロッカースイッチをボタン穴(大)にはめる (配線は動画にて説明)
          ⑤反対側のスイッチも同様に取り付ける
          ⑥コントローラーパッドを横の穴にはめ込む
          ⑦完成
          • ④ロッカースイッチ配線
        • ①小型モーターを取り付ける
              コードは横の穴から通し、ネジで固定する
          ②滑車ネジをマイナスドライバーで固定する
          ③2つの皿台を組み合わせる
          ④完成
          • ①電源コードを取り付ける  (極性なし)
            ②コードを穴に通し、はめ込む
            ③青コードの一方を2つのモーターの+に、もう一方を-へ繋ぐ (どちらでも良い)   ※配線図参照
            混線を防ぐため、コードにビニールテープを巻く
            ④フレーム下の差込口にコードを通す
            ⑤上にコードを通す
            • ①2又コードを統合してGNDへ
                  右ボタンの赤コードを2へ
                  左ボタンの赤コードを3へ繋ぐ
              ②極性あり  ※+-間違えるとショートするため注意
              ③フレーム上の上部にはめ込み、コードは穴から通して下へ
              ④上から通したコードをArduinoに差し込み(配線図参照)、フレームの横部に取り付ける
              ⑤USBケーブルを差し込み
              ⑥蓋をして完成
              • ①たこ糸、もしくはワイヤーや釣り糸などを使用する
                ②肘と肩甲骨が平行になるように糸の長さを調節し、フックにかけて結ぶ
                ③④肘と手が平行になるように、肘と手の穴に糸を通して結ぶ
                ⑤手と前腕に延長コードをとりつけ、手のコードは前腕を通して肘の方へ
                ⑥上腕の右側にコードを通していく
                • ①フレーム上
                  ②肩甲骨
                  ③手
                  ④前腕    へサーボモーターを取り付ける

                  ⑤肩甲骨
                  ⑥上腕
                  ⑦肘        へサーボホーンを取り付ける
                  ⑧組み立てる
                    • #include <Wire.h>
                      #include <Adafruit_PWMServoDriver.h>

                      Adafruit_PWMServoDriver pwm;

                      #define SERVO_MIN 140
                      #define SERVO_MAX 500
                      #define SERVO0_PIN 0
                      #define SERVO2_PIN 2
                      #define SERVO3_PIN 3
                      #define SERVO4_PIN 4
                      #define SERVO5_PIN 5
                      #define BUTTON1_PIN 2
                      #define BUTTON2_PIN 3
                    • int servoPositions[6] = {90, 90, 90, 90, 90, 90}; // 各サーボモーターの初期位置
                      bool button1Pressed = false;
                      bool button2Pressed = false;


                    • void setServoPosition(int servoNum, int targetAngle, int speed) {
                        int currentAngle = servoPositions[servoNum];
                        int step = (targetAngle > currentAngle) ? 1 : -1;
                        int delayTime = map(speed, 1, 10, 20, 5);

                    •  while (currentAngle != targetAngle) {
                          currentAngle += step;
                          if ((step > 0 && currentAngle > targetAngle) || (step < 0 && currentAngle < targetAngle)) {
                            currentAngle = targetAngle;
                          }
                    •  pwm.setPWM(servoNum, 0, map(currentAngle, 0, 180, SERVO_MIN, SERVO_MAX));
                          servoPositions[servoNum] = currentAngle;
                          delay(delayTime);
                        }
                      }
                    • void setServoPositionDual(int servoNum1, int targetAngle1, int servoNum2, int targetAngle2, int speed) {
                        int currentAngle1 = servoPositions[servoNum1];
                        int currentAngle2 = servoPositions[servoNum2];
                        int step1 = (targetAngle1 > currentAngle1) ? 1 : -1;

                    •  int step2 = (targetAngle2 > currentAngle2) ? 1 : -1;
                        int delayTime = map(speed, 1, 10, 20, 5);

                    • while (currentAngle1 != targetAngle1 || currentAngle2 != targetAngle2) {
                          if (currentAngle1 != targetAngle1) {
                            currentAngle1 += step1;
                    •  if ((step1 > 0 && currentAngle1 > targetAngle1) || (step1 < 0 && currentAngle1 < targetAngle1)) {
                              currentAngle1 = targetAngle1;
                            }
                           
                    • pwm.setPWM(servoNum1, 0, map(currentAngle1, 0, 180, SERVO_MIN, SERVO_MAX));
                            servoPositions[servoNum1] = currentAngle1;
                          }
                    •  if (currentAngle2 != targetAngle2) {
                            currentAngle2 += step2;
                         
                    •  if ((step2 > 0 && currentAngle2 > targetAngle2) || (step2 < 0 && currentAngle2 < targetAngle2)) {
                              currentAngle2 = targetAngle2;
                            }
                    •  pwm.setPWM(servoNum2, 0, map(currentAngle2, 0, 180, SERVO_MIN, SERVO_MAX));
                            servoPositions[servoNum2] = currentAngle2;
                          }

                          delay(delayTime);
                        }
                      }
                    • void setup() {
                        pwm.begin();
                        pwm.setPWMFreq(60);

                        pinMode(BUTTON1_PIN, INPUT_PULLUP);
                        pinMode(BUTTON2_PIN, INPUT_PULLUP);
                      }
                    • void loop() {
                        bool button1State = digitalRead(BUTTON1_PIN);
                        bool button2State = digitalRead(BUTTON2_PIN);
                    •  if (button1State == LOW && !button1Pressed) {
                          // ボタン1が押されたら、アームの位置を制御
                          setServoPositionDual(SERVO4_PIN, 52, SERVO0_PIN, 180, 8); // 2つのサーボを同時に動かす
                          setServoPositionDual(SERVO2_PIN, 0, SERVO3_PIN, 145, 3); // スプーンを皿に降ろす
                         
                    • delay(200); // 一旦停止

                          setServoPosition(SERVO4_PIN, 0, 2); // 皿内移動
                          setServoPositionDual(SERVO0_PIN, 37, SERVO4_PIN, 4, 1); // スプーンを返す
                          setServoPositionDual(SERVO0_PIN, 90, SERVO4_PIN, 20, 3); //
                    •  delay(200);
                         
                          setServoPositionDual(SERVO2_PIN, 60, SERVO3_PIN, 140, 3);  // スプーンを引く
                          setServoPosition(SERVO4_PIN, 90, 2); // 中央に
                          setServoPositionDual(SERVO2_PIN, 120, SERVO3_PIN, 0, 3);   // リーチ動作
                    • delay(4000); // 初期位置に戻す

                          setServoPositionDual(SERVO2_PIN, 140, SERVO3_PIN, 50, 3);
                          setServoPositionDual(SERVO2_PIN, 100, SERVO3_PIN, 90, 3);
                          setServoPosition(SERVO2_PIN, 100, 1);
                          setServoPosition(SERVO4_PIN, 90, 2);
                    •  setServoPosition(SERVO0_PIN, 90, 2);
                          button1Pressed = true;
                        } else if (button1State == HIGH) {
                          button1Pressed = false;
                        }
                    •  if (button2State == LOW && !button2Pressed) {
                          // ボタン2が押されたら、アームの位置を制御
                         
                          setServoPositionDual(SERVO0_PIN, 10, SERVO4_PIN, 120, 8);
                          setServoPositionDual(SERVO2_PIN, 35, SERVO3_PIN, 135, 3); // スプーンを皿に降ろす
                       
                    •  setServoPosition(SERVO4_PIN, 168, 2);
                         
                          setServoPositionDual(SERVO0_PIN, 130, SERVO2_PIN, 25, 3); // 2つのサーボを同時に動かす
                          setServoPosition(SERVO4_PIN, 160, 2);
                          setServoPositionDual(SERVO0_PIN, 90,  SERVO4_PIN, 150, 3); // バック
                    • setServoPositionDual(SERVO2_PIN, 60, SERVO3_PIN, 140, 5);  //
                          setServoPosition(SERVO4_PIN, 90, 1);
                          setServoPositionDual(SERVO2_PIN, 120, SERVO3_PIN, 0, 3);  // リーチ動作
                    • delay(4000); // 初期位置に戻す

                          setServoPositionDual(SERVO2_PIN, 140, SERVO3_PIN, 50, 1); // 2つのサーボを同時に動かす
                          setServoPositionDual(SERVO2_PIN, 100, SERVO3_PIN, 90, 3);
                    •  setServoPosition(SERVO4_PIN, 90, 1);
                          setServoPosition(SERVO0_PIN, 90, 1);
                          button2Pressed = true;
                        } else if (button2State == HIGH) {
                          button2Pressed = false;
                        }
                      }
                  Add Card Order

                  References

                    Usages

                      Project comments