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

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のアイコン画像
ロビヲ@野江内代です。 ヘルニアで人生ハードモード☑️ 電子工作戦闘力3☑️ 普通の戦闘力1☑️ ブログとweb制作と電子工作しつつ四コマ漫画制作予定で人生のラビリンスに迷い込み中☑️ 都知事がストライクゾーン☑️ blogはコチラ⇒https://denkenmusic.com
ログインしてコメントを投稿する