編集履歴一覧に戻る
Ketunorobioのアイコン画像

Ketunorobio が 2022年08月07日21時12分57秒 に編集

初版

タイトルの変更

+

M5Stackで”2足歩行ロボット スタックチャン”

タグの変更

+

M5Stack

+

スタックチャン

+

二足歩行

+

ブラジャー

+

メガネ

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

製作品

本文の変更

+

「ミニサイズのサーボモーター」「ミニサイズのサーボドライバ」を手に入れる事が出来ましたので、M5Stackを使って2足歩行できるスタックチャンを作ってみました。 @[twitter](https://twitter.com/ketunorobio/status/1540617300092473345?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1540617300092473345%7Ctwgr%5Ee8750dc84e3f7b8e285908e2a991a6e3cde1c5a1%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a0e6a78b%2F) ## ハードウェア構成 ・M5Stack ・サーボモーター × 5 ・miniサーボモータドライバ(※PONDAさん作) ・Lipo BT M5Stack ⇒ i2c ⇒ サーボドライバ ⇒ サーボモーター の構成にします。 miniサーボドライバは、@PONDA_makeさんのお手製サーボドライバを使用しています。 こちら、PCA9685の半分のサイズにしてなんと接続ch数変わらず16chです。素晴らしいです、市販の製品には無かったので非常に助かりました。 ## ソフトウェア 開発言語はmicropythonを使います。 ロボットの操作については、別途コントローラー( 今回はM5Stack core2 )を用意し、遠隔で操作出来るようにします。 通信手段にはUDP通信を使います。 core2 ⇒ UDP ⇒ M5stack ## ボディ部の印刷、部品の格納 ボディの部分をCADでスケッチし、3Dプリンターで印刷、主要部品を格納します。 @[twitter](https://twitter.com/ketunorobio/status/1542634174535806976?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1542634174535806976%7Ctwgr%5E25f6da0bd209faea571f2fee8c4cd44647ca18b7%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a1e3839c%2F) ## 足の印刷と組立 @[twitter](https://twitter.com/ketunorobio/status/1543476800881184768?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1543476800881184768%7Ctwgr%5Ed732d7bae5168e0d7ea00950fabff9b0aff88c2e%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a2e8b6b3%2F) ## プログラム ### M5Stack core2(コントローラー側) ``` from m5stack_ui import * from socket import socket, AF_INET, SOCK_DGRAM import time import network from m5stack import * #from m5stack import lcd from machine import Pin from uiflow import * screen = M5Screen() screen.clean_screen() screen.set_screen_bg_color(0xFFFFFF) dstip = "m5stackのIP" dstport = ポート番号 wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected(): print('connecting to network...') wlan.connect('SSID', 'PASS') while not wlan.isconnected(): pass print('network config:', wlan.ifconfig()) print('network config:', wlan.ifconfig()) s = socket(AF_INET, SOCK_DGRAM) #s.bind((dstip, dstport)) touch_button0 = M5Btn(text='Button', x=110, y=10, w=100, h=80, bg_c=0xFFFFFF, text_c=0x000000, font=FONT_MONT_14, parent=None) touch_button1 = M5Btn(text='Button', x=10, y=80, w=100, h=80, bg_c=0xFFFFFF, text_c=0x000000, font=FONT_MONT_14, parent=None) touch_button2 = M5Btn(text='Button', x=210, y=80, w=100, h=80, bg_c=0xFFFFFF, text_c=0x000000, font=FONT_MONT_14, parent=None) touch_button3 = M5Btn(text='Button', x=110, y=150, w=100, h=80, bg_c=0xFFFFFF, text_c=0x000000, font=FONT_MONT_14, parent=None) touch_button4 = M5Btn(text='Button', x=116, y=100, w=40, h=40, bg_c=0xFFFFFF, text_c=0x000000, font=FONT_MONT_14, parent=None) touch_button5 = M5Btn(text='Button', x=165, y=100, w=40, h=40, bg_c=0xFFFFFF, text_c=0x000000, font=FONT_MONT_14, parent=None) def touch_button0_pressed(): global data data = "F" def touch_button3_pressed(): global data data = "B" def touch_button1_pressed(): global data data = "L" def touch_button2_pressed(): global data data = "R" #touch_button0.pressed(touch_button0_pressed) # ボタン"A" が「離された」時の処理 def touch_button0_released(): global data data = "S" def touch_button4_pressed(): global data data = "on" def touch_button5_pressed(): global data data = "off" #data = touch_button0.released(touch_button0_released) data = "nane" stamp = 0 while(True): #global data touch_button0.pressed(touch_button0_pressed) touch_button1.pressed(touch_button1_pressed) touch_button2.pressed(touch_button2_pressed) touch_button3.pressed(touch_button3_pressed) touch_button4.pressed(touch_button4_pressed) touch_button5.pressed(touch_button5_pressed) #data = "A" touch_button0.released(touch_button0_released) touch_button1.released(touch_button0_released) touch_button2.released(touch_button0_released) touch_button3.released(touch_button0_released) s.sendto(data, (dstip, dstport)) print(data) #print(Slider2.get_value()) time.sleep(0.1) ``` 操作ボタンを配置し、ボタン押下でボタンに紐づいた文字列をUDPでM5Stack側へ送信しています。 ### M5Stack側(本体側) ``` from socket import socket, AF_INET, SOCK_DGRAM import time import network from machine import Pin, I2C import pca9685 import servo import _thread from m5stack import * from m5stack import lcd #from machine import Pin posi = {"lx":90, "ly":90, "lr":10, "rx":230, "ry":90, "rr":10, "ux":110, "uy":170} lcd.clear(lcd.BLACK) lcd.circle(posi["lx"], posi["ly"], posi["lr"], lcd.WHITE, lcd.WHITE) lcd.circle(posi["rx"], posi["ry"], posi["rr"], lcd.WHITE, lcd.WHITE) lcd.rect(posi["ux"], posi["uy"], 100, 5, lcd.WHITE, lcd.WHITE) a = 92 b = 83 c = 83 d = 95 i2c = I2C(0, scl=Pin(22), sda=Pin(21)) sev = servo.Servos(i2c) #p0 = Pin(19, Pin.OUT) #p1 = Pin(23, Pin.OUT) HOST = "IP" PORT = ポート番号 wlan = network.WLAN(network.STA_IF) wlan.active(True) if not wlan.isconnected(): print('connecting to network...') wlan.connect('SSID', 'PASS') while not wlan.isconnected(): pass print('network config:', wlan.ifconfig()) s = socket(AF_INET, SOCK_DGRAM) s.bind((HOST, PORT)) print("bind") msg = "nane" def recieve(): while(True): global msg msg = s.recv(64) msg = msg.decode() print(msg) time.sleep(0.01) _thread.start_new_thread(recieve, ()) while(True): if msg =="F": while(b <= 125): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b + 1 if d <= 125: d = d + 1 while(c >= 75): sev.position(2, c) time.sleep(0.009) c = c - 1 while(b >= 95): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b - 1 if d >= 95: d = d - 1 while(c <= 95): sev.position(2, c) time.sleep(0.009) c = c + 1 while(d >= 65): sev.position(1, b) sev.position(3, d) time.sleep(0.009) d = d - 1 if b >= 65: b = b - 1 while(a <= 110): sev.position(0, a) time.sleep(0.009) a = a + 1 while(b <= 95): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b + 1 if d <= 95: d = d + 1 while(a >= 90): sev.position(0, a) time.sleep(0.009) a = a - 1 elif msg == "B": while(b <= 125): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b + 1 if d <= 125: d = d + 1 while(c <= 115): sev.position(2, c) time.sleep(0.009) c = c + 1 while(b >= 95): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b - 1 if d >= 95: d = d - 1 while(c >= 95): sev.position(2, c) time.sleep(0.009) c = c - 1 while(d >= 65): sev.position(1, b) sev.position(3, d) time.sleep(0.009) d = d - 1 if b >= 65: b = b - 1 while(a >= 70): sev.position(0, a) time.sleep(0.009) a = a - 1 while(b <= 95): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b + 1 if d <= 95: d = d + 1 while(a <= 90): sev.position(0, a) time.sleep(0.009) a = a + 1 elif msg == "L": while(d >= 65): sev.position(1, b) sev.position(3, d) time.sleep(0.009) d = d - 1 if b >= 65: b = b - 1 while(a >= 70): sev.position(0, a) time.sleep(0.009) a = a - 1 while(b <= 95): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b + 1 if d <= 95: d = d + 1 while(a <= 90): sev.position(0, a) time.sleep(0.009) a = a + 1 elif msg == "R": while(b <= 125): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b + 1 if d <= 125: d = d + 1 while(c <= 115): sev.position(2, c) time.sleep(0.009) c = c + 1 while(b >= 95): sev.position(1, b) sev.position(3, d) time.sleep(0.009) b = b - 1 if d >= 95: d = d - 1 while(c >= 95): sev.position(2, c) time.sleep(0.009) c = c - 1 time.sleep(0.01) ``` UDPで文字列を受信するループと、サーボを駆動させるループを並列で処理させています。(まとめて処理させると遅延が発生する為) ちなみに、pca9685のライブラリを使っているので、M5Stackのフラッシュにpca9685関連のファイルを保存させておく必要があります。ファイルはgitで公開されています。 ## 余談 歩行テスト時に、足が全く動かないトラブルに見舞われました。 宙に浮かせると動くのですが、床に置くと動かない。。 結論から言えば、もともと足のサーボの軸を本体の外側に配置していたので、重心を外れて力が伝わりづらかったんですよね。こんな感じで、だいぶ外れてました(;^ω^)↓ ![キャプションを入力できます](https://camo.elchika.com/8a14efa8904f82beaf257b1cce7fce7daacf94b5/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f34653664313436612d363231302d343032322d393337642d3336306465323666623861662f61333161363462392d323931632d343132662d383663612d353665343731346365313462/) これの軸を中心に持ってくるように修正した所、足に動力が伝わるようになりました。 ## 完成(仮) @[twitter](https://twitter.com/ketunorobio/status/1545166926451658752?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1545166926451658752%7Ctwgr%5E119d484928bcc5fb456197603df91eeabdd60849%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a3e38397%2F) これでほぼ完成なのですが、ツートンカラーがあれなので、ケースを再度印刷し直し、ブラックでペイントします。 ## パーツの再印刷 @[twitter](https://twitter.com/ketunorobio/status/1545550817201049601?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1545550817201049601%7Ctwgr%5E1301dd44b7e755bc2aa72ba0c73072f1d3607bd8%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a4e3839c%2F) 完成です。 ## 2足歩行スタックチャン @[twitter](https://twitter.com/ketunorobio/status/1545551917752823809?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1545551917752823809%7Ctwgr%5Eed7b86d4071f87ad4dfeb65c8575e13d80528685%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a4e3839c%2F) ブラックスタックチャンの完成です!(^▽^)/ しかし、少し味気ないので、ここからもう一つ、改良を加えたいと思います。 @[twitter](https://twitter.com/ketunorobio/status/1545917341900214273?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1545917341900214273%7Ctwgr%5Eed7b86d4071f87ad4dfeb65c8575e13d80528685%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a4e3839c%2F) このスタックチャンに少しでもオリジナリティを持たせるために、「メガネ」をかけさせてみようと思います。なんか嫌な予感はするのですが。。 2足歩行でもすでに先駆者がいますので、そこを創造的模範といいますか、同じじゃないですよと言いたいがためでもあります。 それでは、2足歩行メガネスタックチャンを、ご覧ください。 ## まさかの変態仮面 ### ブラジャーにしか見えない。。 @[twitter](https://twitter.com/ketunorobio/status/1546605177179803650?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1546605177179803650%7Ctwgr%5E8c617da0c7353111d8f821d3b2fb15c4015adf46%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a5%2F) イヤな予感は想像の斜め上をいきました。 サポート取ってないせいもあるのですが、それを差し引いてもやはりこれはブラジャーにしか見えません。。 こんなはずじゃなかった(-_-;) 対策を考えます ## サングラスにしてみる @[twitter](https://twitter.com/ketunorobio/status/1546971390976282624?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1546971390976282624%7Ctwgr%5E8c617da0c7353111d8f821d3b2fb15c4015adf46%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a5%2F) なんとか逃げ切れました?(;^ω^)多分OKでしょう。 しかし色加えるだけでこうも印象が変わるんですね。メガネって怖いですね。。 それでは最後に、メガネスタックチャンを歩かせて、終了としたいと思います。 @[twitter](https://twitter.com/ketunorobio/status/1547326664987709441?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1547326664987709441%7Ctwgr%5E8c617da0c7353111d8f821d3b2fb15c4015adf46%7Ctwcon%5Es1_&ref_url=https%3A%2F%2Fdenkenmusic.com%2Fm5stacke381a72e8b6b3e6ada9e8a18ce383ade3839ce38383e38388e382b9e382bfe38383e382afe38381e383a3e383b3e381aee4bd9ce68890e291a5%2F) 以上です。 ありがとうございました。