PuppyC、買っちゃいました
先日のIRユニット買ったときにじつはPuppyCも買ってたんです。
なにがどうって「パピー」って名前に惹かれちゃいますよね。
こんな感じにサーボモーターが4個ついてます。
PuppyC自体はHATなので、M5StickCにザクっとつなげて動作させます。
PuppyCを動かしてみる
まずはサンプルコードを取得して動かしてみます。
スイッチサイエンスの製品紹介にもリンクがあるこちら ↓ を利用します。
ここのgitにUIFlowとArduinoふたつが格納されています。
どちらも動かしてみました。
UIFlowのサンプルプログラム
M5Flow(UIFlow)に読み込ませるとこんな感じ。
ひたすら4つのサーボモーターを動かしています。
また新しいおもちゃを手に入れた!#M5StickC #PuppyC pic.twitter.com/fbzWljG93p
— しろいとり子 (@siroitori0413) 2020年4月27日
前に進んでいきます。か、かわいい・・!!
そういえばここで「動かない!」ってちょっと躓いてたんでした。
原因は、PuppyCの電源をONにしていなかったというオチ・・。電源はパピーのおしり部分にあります。
製品紹介ページに書いてあるのでちゃーんと見ましょう。
Arduinoのサンプルプログラム
前に10回、そのあと後ろに10回動くというのを繰り返すプログラムでした。
(ここでは詳細は割愛しますが、このあとの改造ではこのプログラム PuppyC.ino をもとにして作っています。)
PuppyCをもっとパピーにしたい!
せっかくパピーCって名前なんでもっとパピー(子犬)っぽくしてみようと思いました。
パピー変身セット材料
・M5StickC+PuppyC
・セリアの犬の顔マグネット
・フェルトで作った体の着ぐるみ → 頭の部分(白い所)にはマグネットを縫い付け、しっぽには使い古しの乾電池を入れています。縫い目、汚い…見ないで…w
・小さいジャムのふた
着替え
最初に体を着せます。胴体の部分を髪留めゴムでとめます。
頭のマグネットにジャムのふたと犬の顔をくっつけます。
完成。
ここに至るまで試行錯誤あり、最終的にこの形になりました。
【工夫したところ】
・マグネットとマグネットの引っ付く力が弱かったので、間にジャムのふたを挟んで固定するようにしました。
・頭が重くなったのでバランスをとるためにしっぽに電池をいれておもりにしました。
歩いてみる
あんよがじょうず、あんよがじょうず!
パピーちゃん歩けるようになりました^^
さらにパピーちゃんをリモートコントロールできるようにしてみる
先日息子くんの書いてたArduinoプログラムを流用しながらPuppyCのArduinoサンプルプログラムを書き換え、パピーちゃんをリモコン操作できるように書いてみました。
Arduinoプログラム
#include <M5StickC.h> #include "IIC_.h" #include <WiFi.h> #include <WiFiClient.h> #include <WiFiAP.h> const char *ssid = "M5StickCtrl"; const char *password = ""; WiFiServer server(80); TaskHandle_t pthreadHandle; String mode = "Stop"; void puppy_start() { angle_all_set(90,90,90,90); //servo 1 2 3 4 => set 90° delay(100); } void puppy_go() { angle_all_set(55,60,130,120); //servo 1 2 3 4 delay(100); angle_all_set(55,160,130,120); //servo 1 2 3 4 delay(100); angle_all_set(120,130,150,60); //servo 1 2 3 4 delay(100); angle_all_set(120,130,60,60); //servo 1 2 3 4 delay(100); angle_all_set(55,130,60,60); //servo 1 2 3 4 delay(100); angle_all_set(55,60,130,30); delay(100); } void puppy_back() { angle_all_set(120,130,60,55); delay(100); angle_all_set(120,130,160,55); delay(100); angle_all_set(60,150,130,120); delay(100); angle_all_set(60,60,130,120); delay(100); angle_all_set(60,60,130,55); delay(100); angle_all_set(30,130,60,55); delay(100); } // the setup routine runs once when M5StickC starts up void setup(){ // Initialize the M5StickC object M5.begin(); // LCD display M5.Lcd.println(" "); M5.Lcd.println(" IIC_PUPPY"); IIC_Init(); //sda 0 scl 26 /* 1 2 3 4 */ angle_set(1,90); //servo 1 => set 90° angle_set(2,90); angle_set(3,90); angle_set(4,90); // delay(1000); // WiFi INIT Serial.println("Configuring access point..."); WiFi.softAP(ssid, password); IPAddress myIP = WiFi.softAPIP(); Serial.print("AP IP address: "); Serial.println(myIP); server.begin(); Serial.println("Connect:"); Serial.println(ssid); Serial.println("Enter:"); Serial.println(myIP); mode = "Stop"; xTaskCreatePinnedToCore(moveTask, "moveTask", 4096, NULL, 1, &pthreadHandle, 0); delay(1000); // M5.Lcd.qrcode(myIP.toString(), // 80, 0, 80, 15); } void moveTask(void* arg) { puppy_start(); while(true){ if (mode == "Forward"){ puppy_go(); }else if (mode == "Back"){ puppy_back(); }else{ delay(100); } } } void loop() { M5.update(); WiFiClient client = server.available(); if (client) { Serial.println("Client Connected."); String currentLine = ""; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); if (c == '\n') { if (currentLine.length() == 0) { client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html; charset=utf-8;"); client.println(); client.println("<!DOCTYPE HTML>"); client.println("<html>"); client.println("<head>"); client.println("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />"); client.println("</head>"); client.println("<body>"); client.println("<form method=\"get\">"); client.println("<input name=\"control\" type=\"text\" value=\"Forward\" style=\"display:none;\" \\>"); client.println("<button type=\"submit\">Go Forward</button>"); client.println("</form>"); client.println("<form method=\"get\">"); client.println("<input name=\"control\" type=\"text\" value=\"Stop\" style=\"display:none;\" \\>"); client.println("<button type=\"submit\">Stop</button>");\ client.println("</form>"); client.println("<form method=\"get\">"); client.println("<input name=\"control\" type=\"text\" value=\"Back\" style=\"display:none;\" \\>"); client.println("<button type=\"submit\">Go Back</button>");\ client.println("</form>"); client.println("</body>"); client.println("</html>"); Serial.println("html Rendering"); break; } else if (currentLine.indexOf("GET /?") == 0) { Serial.print("currentLine = "); Serial.println(currentLine); int pos1 = 0; int pos2 = 0; String val = ""; pos1 = currentLine.indexOf('control=', pos2); pos2 = currentLine.indexOf(' ', pos1); val = currentLine.substring(pos1 + 1, pos2); Serial.print("val = "); Serial.println(val); client.println("HTTP/1.1 302 Request Succsessful"); client.println("Connection: close"); client.println("Location: /"); client.println(); client.println("Request was succsessful. redirect to <a href=\"/\"> here. </a>"); client.println(); if (val == "Forward") { Serial.println("[Button Push] Forward"); // 前に進む mode = "Forward"; } else if(val == "Back") { Serial.println("[Button Push] Back"); // 後ろに進む mode = "Back"; } else { // ストップ mode = "Stop"; } } else { currentLine = ""; } } else if (c != '\r') { currentLine += c; } } } client.stop(); Serial.println("Client Disconnected."); } // Aボタンが押されたら準備状態にする if (M5.BtnA.wasPressed()){ puppy_start(); } }
Arduinoプログラム解説
流用したという先日息子くんの書いてたプログラムっていうのはこれ ↓
siroitori.hatenablog.com
リモコン(今回はPCブラウザで実行)とM5StickCをつなぐために、M5StickCをサーバとして起動しています。
クライアントとなるリモコン側からはまずはWiFiのつなぎ先をプログラム中にあるSSID「M5StickCtrl」に接続します。(このへんは上記のリモコン操作のブログに書いています。)
今回のプログラムでは、最初にパピーちゃんを動かす「moveTask」というタスクを起動しました。ここでは、ブラウザのボタン押された現在の状態を確認しながら、どう動かすか処理しています。
ブラウザには「Forward」「Stop」「Back」というボタンを表示させるようにして、それぞれ押下時に現在の状態を切り替えています。
ブラウザの画面 ↓
最終形
PCのブラウザからパピーちゃんが操作できる様子がわかります^^
ちょっと歩き方ぎこちないですけどね。
「さいごまで よんでくれて ありがとワン」