Ketunorobioのアイコン画像
Ketunorobio 2022年08月07日作成 (2022年08月07日更新)
製作品 製作品 閲覧数 2212
Ketunorobio 2022年08月07日作成 (2022年08月07日更新) 製作品 製作品 閲覧数 2212

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

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

「ミニサイズのサーボモーター」「ミニサイズのサーボドライバ」を手に入れる事が出来ましたので、M5Stackを使って2足歩行できるスタックチャンを作ってみました。

ハードウェア構成

・M5Stack

・サーボモーター × 5

・miniサーボモータドライバ(※PONDAさん作)

・Lipo BT

M5Stack ⇒ i2c ⇒ サーボドライバ ⇒ サーボモーター の構成にします。

miniサーボドライバは、@PONDA_makeさんのお手製サーボドライバを使用しています。

こちら、PCA9685の半分のサイズにしてなんと接続ch数変わらず16chです。素晴らしいです、市販の製品には無かったので非常に助かりました。

ソフトウェア

開発言語はmicropythonを使います。

ロボットの操作については、別途コントローラー( 今回はM5Stack core2 )を用意し、遠隔で操作出来るようにします。

通信手段にはUDP通信を使います。

core2 ⇒ UDP ⇒ M5stack

ボディ部の印刷、部品の格納

ボディの部分をCADでスケッチし、3Dプリンターで印刷、主要部品を格納します。

足の印刷と組立

プログラム

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で公開されています。

余談

歩行テスト時に、足が全く動かないトラブルに見舞われました。

宙に浮かせると動くのですが、床に置くと動かない。。

結論から言えば、もともと足のサーボの軸を本体の外側に配置していたので、重心を外れて力が伝わりづらかったんですよね。こんな感じで、だいぶ外れてました(;^ω^)↓

キャプションを入力できます

これの軸を中心に持ってくるように修正した所、足に動力が伝わるようになりました。

完成(仮)

これでほぼ完成なのですが、ツートンカラーがあれなので、ケースを再度印刷し直し、ブラックでペイントします。

パーツの再印刷

完成です。

2足歩行スタックチャン

ブラックスタックチャンの完成です!(^▽^)/

しかし、少し味気ないので、ここからもう一つ、改良を加えたいと思います。

このスタックチャンに少しでもオリジナリティを持たせるために、「メガネ」をかけさせてみようと思います。なんか嫌な予感はするのですが。。

2足歩行でもすでに先駆者がいますので、そこを創造的模範といいますか、同じじゃないですよと言いたいがためでもあります。

それでは、2足歩行メガネスタックチャンを、ご覧ください。

まさかの変態仮面

ブラジャーにしか見えない。。

イヤな予感は想像の斜め上をいきました。

サポート取ってないせいもあるのですが、それを差し引いてもやはりこれはブラジャーにしか見えません。。

こんなはずじゃなかった。。。

対策を考えます

サングラスにしてみる

なんとか逃げ切れました?(;^ω^)多分OKでしょう。

しかし色加えるだけでこうも印象が変わるんですね。メガネって怖いですね。。

それでは最後に、メガネスタックチャンを歩かせて、終了としたいと思います。

以上です。
ありがとうございました。

1
1
Ketunorobioのアイコン画像
ロビヲ@野江内代です。
ログインしてコメントを投稿する