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

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のアイコン画像
ロビヲ@野江内代です。
ログインしてコメントを投稿する