3Dプリンタ スマートロック「3」編(1) 再作成

不満点

スマートロックだが、使用していない。というのもobnizが不安定。

ローカル動作するはずのobnizだが、よく勝手に落ちており接続できない状態が多くある。周辺機器を動かすという点においては、ソフトでI/Oを決めたり、電力容量もある程度気にせず使えたりと、ものすごく便利なのだが、接続が不安定という点においては残念。

またobnizは開発環境が気が付くと変化しており、メンテナンスしようとするとUIが変更されてて戸惑う。
なのでobnizはあきらめてラズパイでの動作に戻してみようと思う。

また、サーボを使った動作についても専用モータードライバが無いと、ソフトでの周波数管理は少し不安定。この辺りも改善したい。

ということで、少し放置していたスマートロックなのだが、もう一度使えるものを作ってみたい。

改善点

CPU

メインの頭脳はobnizからラズパイに変更する。ラズパイが安定しているかというと少し疑問はあるが、融通が利きやすいのでこちらで対応したいと思う。

ラズパイ4か5で動かすと安定しそうな気もするが、サイズが大きいのと電力量が大きいので、ラズパイzero2で対応してみる。状況次第でラズパイ5などもあるかも。

動力部

サーボのMG995を使用していたが、今回新たにステッピングモーターの28BYJ-48を入手したのでこちらを使用してみる。

サーボは停止させるのに、安定した周波数パルスを送る必要があるが、ステッピングモーターだと、パルスを送らなければ一切動作しないので、停止時の安定感は完璧だ。

ただし28BYJ-48はおもちゃ程度のステッピングモーターなので、スペックはかなり劣る。トルクはMG995が9kgcmくらいに対して28BYJ-48は0.3kgcmだと思われ、かなり小さめ。また回転速度もMG995が60rpmくらいで動くのに対して、28BYJ-48は4~6rpmくらいだ。

価格も大きく違っており、MG995は1000円(秋月見ると現在はMG996Rで\1,780)で、28BYJ-48は250円と1/4だ。これでうまく動くか検証してみよう。

モータードライバ

モーター類を直接ラズパイで動作はできない。GPIOでは出力(電流)が足りない。
28BYJ-48購入時はドライバボードとセットで購入したので、ドライバが付属している。

ICの石が刺さっているので見てみると、ULN2003ANとマークされている。1個40円のトランジスタアレイとのことで、中身はダーリントントランジスタが7回路入っているようだ。

まあ、半導体リレーと考えていいだろう。7回路あるが4回路だけ使用しているようだ。

設計

扉のハンドルフィット部分や鍵のツマミ回転部分などは今までと同じ。動力部分がサーボによるギア駆動からステッピングモーターでの直接回転に変わり、初期設計の縦型の構造となる。

ということで、前回までのデータを活用しながら、一から作ってみる。とりあえずこんなのになった。といってもここまでかなりの修正を行った。

これらを印刷して準備。各種ネジを使って組み上げていく。

ステッピングモーターを動かす

ステッピングモーターだが、通常のモーターは電源としてプラスマイナスをつなぐと、決められた方向に回転する。しかしステッピングモーターは電源が複数本あり指定順に電流を流すことで決められた角度ずつ回転するらしい。なので決められた角度だけ回転させるなどの動作が可能。

今回入手の28BYJ-48はよくわからないけどパルスを512飛ばすと1回転するらしい。なので1パルスでは0.7度ほど回転するようだ。目で見てもわからなそうだな。モーターから出ている線は5つ。モータードライバも付属しており、赤色線は電源につながっているようなので、残りの4線をいろいろ操作するようだ。

仕組みに関しても、いろいろと解説してあるところはあるが、頭が痛いので無視。回転させる方法としては、何種類かあるらしく、その動かし方により速さやトルクが変わってくるらしい。当然消費電力も違ってくるのだろう。

とりあえず、4線をgpioにつなぎ、電源の用意とGND接続を行い配線完了。

1相励磁方式

では、サンプルプログラムを入手して作成して動かしてみる。gpio操作はgpiozeroを使用してpythonで動かす。nodejsがいいのだが、人気が無いのかサンプルが少ない。
28BYJ-48のD:Blue, A:Orange, B:Yellow, C:PinkをGPIOの6,13,19,26に接続して、別途電源をドライバにつなぎ、動かしてみる。

# 1相励磁方式
from gpiozero import LED
from gpiozero import LEDBoard
import time

leds = LEDBoard(6,13,19,26) # Blue, Orange, Yellow, Pink
s01 = ((1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)) # 一相励磁
startms = 0

ms = 6    # wait(ms)
agl = 512 # 512 = 360 degree
direc = 1 # 1 or -1

def motor_main():
    for i in range(agl):
        motor_step(s01, direc, ms)

def motor_step(pattern, direction, wtime):
    for j in range(len(pattern)):
        for k in range(len(pattern[j])):
            if pattern[j][k] == 1:
                leds[k].on()
            else:
                leds[k].off()
        time.sleep(wtime * 0.001)

def destroy():
    for i in range(4):
        leds[i].off()
    tms = int(time.time() * 1000) - startms
    print("rotation end")
    print("rotate-time  %d.%d s [wait %dms]" % (tms // 1000, tms % 1000, ms))

if __name__ == '__main__':
    try:
        startms = int(time.time() * 1000)
        print("starting rotation")
        motor_main()
    except KeyboardInterrupt:
        pass
    destroy()

1相励磁方式での回転となるのだが、これは1線ずつ電気を順番に流すのを繰り返す。4線流して1パターンで、これを512回行うと一周する。なので1線に電気を流すと0.176度回転している?ほぼ見えないけど結果的には1周するのでちゃんと動いているのだろう。緻密な動きをさせるには便利そうだ。

ちなみに、「ms = 6」の個所でウエイトタイムを設定。パルス間隔をどれくらい開けるかの設定で、小さいとウェイトタイムが短くなるので回転は速くなるがモーター性能が追い付かないと、ちゃんと回転しない(脱調というらしい)
目で見てもわからないので難しいが、脱調起こすと変な音がするらしい。

2相励磁方式

2相励磁方式はもう少し電気をたくさん流す。その分トルクは強いと思われる。

# 2相励磁方式
from gpiozero import LED
from gpiozero import LEDBoard
import time

leds = LEDBoard(6,13,19,26) # Blue, Orange, Yellow, Pink
s02 = ((1,0,0,1),(1,1,0,0),(0,1,1,0),(0,0,1,1))
startms = 0

ms = 6    # wait(ms)
agl = 512 # 512 = 360 degree
direc = 1 # 1 or -1

def motor_main():
    for i in range(agl):
        motor_step(s02, direc, ms)

def motor_step(pattern, direction, wtime):
    for j in range(len(pattern)):
        for k in range(len(pattern[j])):
            if pattern[j][k] == 1:
                leds[k].on()
            else:
                leds[k].off()
        time.sleep(wtime * 0.001)

def destroy():
    for i in range(4):
        leds[i].off()
    tms = int(time.time() * 1000) - startms
    print("rotation end")
    print("rotate-time  %d.%d s [wait %dms]" % (tms // 1000, tms % 1000, ms))

if __name__ == '__main__':
    try:
        startms = int(time.time() * 1000)
        print("starting rotation")
        motor_main()
    except KeyboardInterrupt:
        pass
    destroy()

動かしてみると、回転速度は1相励磁方式と同じだった。トルクはよくわからない。回転軸を持ってみると違いが感じ取れるのかな?消費電力も倍になりそうだが、測定器具が無いので不明。

回転トルクが足りない場合には、こちらを使用するとよいのだろう。

1-2相励磁方式

1-2相励磁方式は、ステップが倍になる。1相励磁と2相励磁を繰り返しながら回す感じだ。こちらのメリットは何なのか不明。回転が滑らかになるのかな?

# 1ー2相励磁方式
from gpiozero import LED
from gpiozero import LEDBoard
import time

leds = LEDBoard(6,13,19,26) # Blue, Orange, Yellow, Pink
s12 = ((1,0,0,0),(1,1,0,0),(0,1,0,0),(0,1,1,0),(0,0,1,0),(0,0,1,1),(0,0,0,1),(1,0,0,1))

def motor_main():
    ms = 5    # 5ms wait
    agl = 512 # 512 = 360 degree
    direc = 1 # 1 or -1

    for i in range(agl):
        motor_step12(direc,ms)

def motor_step12(direction,mspeed):
    for j in range(8):
        for k in range(4):
            if s12[j][k] == 1:
                led = leds[k]
                led.on()
            else:
                led = leds[k]
                led.off()
        time.sleep(mspeed*0.001)

def destroy():
    for i in range(4):
        led = leds[i]
        led.off()
    print("...end")

if __name__ == '__main__':
    try:
        print("starting...")
        motor_main()
    except KeyboardInterrupt:
        pass
    destroy()

動かしてみると、ステップが倍になった分回転は今までより遅い。半分の速度だ。もともと遅いステッピングモーターなので、これだと使いずらいな。

ロック用動作

ひとまず動かし方は分かった。では本来の目的の扉鍵ロックのための動作を行わせる。ロック動作は90度回転させて戻る動作を行う。施錠するときは右回り⇒左回り、開錠の時は左回り⇒右回りを行うことができればよい。

ということで、ロック動作コードを記述。

from gpiozero import LED
from gpiozero import LEDBoard
import time
import sys

leds = LEDBoard(6,13,19,26) # Blue, Orange, Yellow, Pink
s02 = ((1,0,0,1),(1,1,0,0),(0,1,1,0),(0,0,1,1))
startms = 0

ms = 2    # wait(ms)
agl = 128 # 512 = 360 degree
direc = 1 # 1 or -1

def motor_main(direction):
    for i in range(agl):
        motor_step(s02, direction, ms)
    time.sleep(0.2)
    for i in range(agl):
        motor_step(s02, -direction, ms)

def motor_step(pattern, direction, wtime):
    for j in range(len(pattern)):
        for k in range(len(pattern[j])):
            if pattern[j][k] == 1:
                leds[k * direction].on()
            else:
                leds[k * direction].off()
        time.sleep(wtime * 0.001)

def destroy():
    for i in range(4):
        leds[i].off()
    tms = int(time.time() * 1000) - startms
    print("rotation end")
    print("rotate-time  %d.%d s [wait %dms]" % (tms // 1000, tms % 1000, ms))

if __name__ == '__main__':
    try:
        args = sys.argv
        startms = int(time.time() * 1000)
        print("starting rotation(%d)" % len(args))
        if len(args) > 1:
            if args[1] == "rev":
                direc = -1
        motor_main(direc)
    except KeyboardInterrupt:
        pass
    destroy()

パルスのディレイは2msで行けそうなので、「2」を設定。
90度回して少し待機(200ms)して90度逆回転をさせる。
パラメータで「rev」を受け取ると、逆回転動作を行うようにした。
施錠動作:python lock.py
開錠動作:python lock.py rev

3Dプリンタ スマートロック編一覧

3Dプリンタ スマートロック編(1) ハード作成
3Dプリンタでスマートロックを作ってみる
3Dプリンタ スマートロック編(2) ソフト作成
3Dプリンタでスマートロックを作ってみる
3Dプリンタ スマートロック編(3) 状態検知
3Dプリンタでスマートロックを作ってみる
3Dプリンタ スマートロック編(4) obniz
3Dプリンタでスマートロックを作ってみる
3Dプリンタ スマートロック編(5) 取付中
3Dプリンタでスマートロックを作ってみる
3Dプリンタ スマートロック「2」編(1) 改善検討
3Dプリンタでスマートロック「2」を作ってみる
3Dプリンタ スマートロック「2」編(2) 交換取付
3Dプリンタでスマートロック「2」を作ってみる
3Dプリンタ スマートロック「2」編(3) 2台目
3Dプリンタでスマートロック「2」を作ってみる
3Dプリンタ スマートロック「2」編(4) ガタつき
3Dプリンタでスマートロック「2」を作ってみる
3Dプリンタ スマートロック「2」編(5) シンプルに
3Dプリンタでスマートロック「2」を作ってみる
3Dプリンタ スマートロック「2」編(6) 配線整理
3Dプリンタでスマートロック「2」を作ってみる
3Dプリンタ スマートロック「3」編(1) 再作成
3Dプリンタでスマートロック「3」を作ってみる
3Dプリンタ スマートロック「3」編(2) APIサーバ
3Dプリンタでスマートロック「3」を作ってみる