Raspberry Pi Pico Wを使用してステッピングモータをBLE通信で制御する実験(MicroPython使用)


Raspberry Pi Pico WとスマホをBLE (Bluetooth Low Energy)通信で接続してステッピングモータを制御する実験を紹介します。

Bluetoothには古くから存在するBluetoothクラシックと、後から開発され消費電力を大幅に削減出来るBluetooth Low Energyがあります。それぞれ互換性はありません。Raspberry Pi Pico Wは両方の規格に対応しています。
今回はBLE(Bluetooth Low Energy)を使用してスマホとRaspberry Pi Pico Wを無線通信接続してステッピングモータの動作を制御する実験を行いました。

Raspberry Pi Pico Wのプログラミング言語はMicroPython使用しました。
スマホ側は既存のアプリであるSerial Bluetooth Terminalを使用しました。

1.動作動画

今回作成した実験装置を動作させた動画です。
スマホにはSerial Bluetooth Terminalアプリをインストールしてあります。そのアプリを使用してRaspberry Pi Pico WをBLE接続した後に、スマホ側から例えば”m4000\r\n”を送信すると4000のステップ位置にステッピングモータが回転します。

2.Raspberry Pi Pico Wに関して

今回ステッピングモータを駆動するコントローラとして、マイコンボード Raspberry Pi Pico W を使用しました。

図1にRaspberry Pi Pico Wの外観と特徴に関して記載します。

図1.Raspberry Pi Pico Wの外観等

3.MicroPythonに関して

Raspberry Pi Pico Wのプログラム言語としてMicroPythonを使用しました。
MicroPythonをRaspberry Pi Pico Wで使用するための手順を以下に説明します。

①Raspberry Pi Pico WとパソコンをBOOTSELボタンを押しながらUSBケーブルを使用して接続します。Raspberry Pi Pico Wがディスクドライブとして認識されます。

図2.Pico WのBOOTSELボタンとUSBコネクタ

②エクスプローラで見て、「RPI-RP2」がRaspberry Pi Pico Wのディスクドライブです。
MicroPythonのダウンロードページ(https://MicroPython.org/download/)
から、Raspberry Pi Pico W用のファームウェアをダウンロードします。

今回ダウンロードしたファームウェアはバージョン1.25.0でファイル名称は、
RPI_PICO_W-20250415-v1.25.0.uf2
でした。
このファイルを「RPI-RP2」ディスクにコピーします。これで、Raspberry Pi Pico WでMicroPythonが動作するようになります。


③MicroPythonのプログラム作成ツールとしてThonnyをパソコンにインストールします。

Thonnyのダウンロードページは、
https://thonny.org/
です。

Raspberry Pi Pico WとパソコンをUSBケーブルで接続して、Thonnyを起動することによって、プログラムの編集や実行を行うことが出来ます。

図3はThonnyの画面です。

図3.Thonny画面

4.MicroPythonの実行手順

MicroPythonで作成したプログラムをRaspberry Pi Pico Wで実行する手順に関して以下で説明します。

①パソコンでThonnyを起動して、Raspberry Pi Pico WをUSBケーブルで接続します。

②Thonny画面の右下部をクリックして、「MicroPython (Raspberry Pi Pico)—」を選択します。


③プログラムを書きます。


④画面左上のをクリックするとプログラムがRaspberry Pi Pico Wで実行されます。

5.BLE通信に関して

BLEとはBluetooth Low Energyの略です。
Bluetoothには古くから存在するBluetoothクラシックと、後から開発され消費電力を大幅に削減出来るBluetooth Low Energyがあります。それぞれ互換性はありません。Raspberry Pi Pico Wは両方の規格に対応しています。

BLEは親側(セントラル)と子側(ペリフェラル)で通信します。本記事の実験ではRaspberry Pi Pico Wがペリフェラルで、スマホがセントラルとしました。

BLE通信接続手順

BLE通信ではセントラル側は以下の手順でペリフェラルと接続します。
・BLEデバイスのスキャン
・BLEデバイスのGATTサーバに接続
・利用可能なServiceの検出
・利用可能なServiceの特性に基づいて接続されたデバイスとデータを転送する

GATTはGeneric Attribute Profileのことで、BLEはこのプロファイルに基づいて通信します。
今回は、セントラルであるスマホ側は、既存のアプリであるSerial Bluetooth Terminalを使用し、このアプリでBLEの接続処理を行っています。

ペリフェラル側は、その機能をまとめたServiceと言うデータを持っています。Serviceは実際の機能を果たす複数のCharacteristicと言うデータを内蔵しています。
ServiceとCharacteristicはUUIDと言う16進数のデータが割り付けられています。このUUIDを使ってCharacteristicにデータを書き込んだり、読み出したりすることによって、セントラルとペリフェラル間のデータのやり取りを行うことが出来ます。

MicroPythonのBLEペリフェラルサンプルプログラムとして公開されているble_simple_peripheral.pyプログラムのServiceとCharacteristicのUUIDとデバイス名称は表1の通りです。 

項目UUID等
Service6E400001-B5A3-F393-E0A9-E50E24DCCA9E
受信 Characteristic6E400002-B5A3-F393-E0A9-E50E24DCCA9E
送信 Characteristic6E400003-B5A3-F393-E0A9-E50E24DCCA9E
デバイス名称mpy-uart
表1.MicroPythonペリフェラルプログラムサンプルのServiceとCharacteristicのUUIDとデバイス名称

6.MicroPythonでBLEライブラリを使用する方法

今回、Raspberry Pi Pico Wは、BLEのペリフェラル側にしました。

MicroPythonでBLEライブラリを使用して、ペリフェラル側の動作をさせるため、下記GitHubのページから
ble_advertising.py
ble_simple_peripheral.py
の2個のサンプルプログラムのファイルをダウンロードしてRaspberry Pi Pico Wにアップロードしました。

ble_simple_peripheral.pyは、BLEにシリアル通信動作(UART)をさせるペリフェラルソフトです。

以下にRaspbery Pi Pico Wにこれらのファイルをアップロードする手順を示します。

①以下ホームページにアクセスします。
https://github.com/micropython/micropython/tree/master/examples/bluetooth


②ble_advertising.pyとble_simple_peripheral.pyの2個のファイルをダウンロードします。
ダウンロードは例えばble_advertising.pyの場合、ble_advertising.pyの部分をクリックするとそのソースコードが下図の様に表示されます。
ソースコード画面部の右上にあるをクリックすると、パソコンにソースコードをダウンロードすることができます。


③Raspberry Pi Pico WをパソコンにUSBケーブルで接続した状態で、Thonnyを起動します。
画面右下をクリックして、MicroPython(Raspberry Pi Pico)を選択します。


④「表示」をクリックして表示される一覧表の「ファイル」をクリックしてチェックを付けますと、画面の左欄にフォルダーやファイルのツリー表示がされます。


⑤先ほどダウンロードしたble_advertising.pyとble_simle_peripheral.pyが存在するフォルダを表示して、2個のファイルを表示します。
ここで下図の様に、ble_advertising.pyを右クリックして表示される「/にアップロード」をクリックすると、Raspberry Pi Pico Wにble_advertising.pyファイルがアップロードされます。


⑥アップロードすると、下図の様に画面左下のRaspberry Pi Picoの欄にble_advertising.pyが表示されます。


⑦同様の操作でble_simple_peripheral.pyファイルもRaspberry Pi Pico Wにアップロードします。以上でBLEのライブラリが使用可能となります。

MicroPythonのソースコードで
import bluetooth
from ble_simple_periphral import BLESimplePeripheral
と記載することで、BLEライブラリが使用出来ます。

7.BLE通信プログラム

7ー1.BLE通信関係関数

MicroPythonのプログラムで、

import bluetooth
from ble_simple_periphral import BLESimplePeripheral

を記すとBLEライブラリが使用出来ます。表2に主要関数を示します。

関数説明
ble = bluetooth.BLE()BLEオブジェクトを生成します
peri = BLESimplePeripheral(ble)ペリフェラルを生成します
peri.send(data)データを送信します
peri.on_write(func)データ受信時にコールバックする関数を指定します
peri.is_connected()BLE通信が接続時にTrueとなる関数です
表2.BLE通信関数例

7-2.BLE通信プログラム例

表2のBLE通信用関数を使用した簡単なプログラムの例を示します。
このプログラムは、Thonnyを起動したパソコンとRaspberry Pi Pico WをUSB接続してPico Wのプログラムを起動した後に、スマホと Pico WをBLE接続をして、スマホからテキストデータをPico Wに送ると、Thonnyの画面にスマホから送信したデータが表示されます。
また、1秒毎に増える数値を Pico Wからスマホに送信します。

#BLEテストプログラム
import bluetooth
from ble_simple_peripheral import BLESimplePeripheral
import time

connect_flag = False

#BLEオブジェクト生成
ble = bluetooth.BLE()
#ペリフェラル生成
peri = BLESimplePeripheral(ble)

#BLE受信コールバック関数
def rcv_data(data):
    print(data)
        
#----------メイン処理--------------------
peri.on_write(rcv_data)	#受信コールバック関数設定

no = 0
while True:
    if peri.is_connected():		#BLE接続中?
        if connect_flag == False:
            print("BLE接続")
            connect_flag = True

        no = no + 1
        text = str(no) + "\r\n"
        peri.send(text)				#ループ回数をBLE送信
    else:
        if connect_flag == True:
            print("BLE切断")
            connect_flag = False
    
    time.sleep(1)			#1秒待ち

【プログラム説明】
2行目、3行目:
import bluetooth
from ble_simple_peripheral import BLESimplePeripheral
で、BLEライブラリが使用可能となります。

9行目:
ble = bluetooth.BLE()
は、BLEオブジェクトを生成します。

11行目:
peri = BLESimplePeripheral(ble)
は、ペリフェラルを生成します。

14行目:
def rcv_data(data):
は、BLE通信で受信データがあるときに呼び出されるコールバック関数です。この関数名は18行目のperi.on_write(rcv_data)関数の引数で指定されています。

18行目:
peri.on_write(rcv_data)
は、BLE通信でデータを受信した時のコールバック関数名をrcv_data()に設定しています。

22行目:
if peri.is_connected():
で、peri.is_connected()がTureの時、BLEが接続されています。Falseの時は切断されています。

29行目
peri.send(text)
は、while文のループ回数をBLE送信します。

8.ステッピングモータと実験回路

ステッピングモータは28BYJ-48とそのドライバーボードのセットを使用しました。このステッピングモータとドライバーボードは複数のネット通販から購入することが出来ます。

28BYJ-48ステッピングモータとドライバ
28BYJ-48ステッピングモータ裏面
実験装置

今回使用したステッピングモータの主な仕様は表3の通りです。このモータは1/64のギアで減速されていて、1-2相励磁でステップ角は5.625°/64なので4096ステップでモータ軸が1回転します。最大自起動周波数が500ppsなので、500パルス/sec以下で起動する必要があります。起動後は徐々に加速を行った場合に、最大で1000パルス/secまで仕様上は可能と思われます。

項目仕様
相数4相
励磁方式1-2相励磁方式
ステップ角5.625°/64   (減速比1/64)
電圧5VDC
相抵抗22Ω ± 7% 25°C
最大応答周波数1000pps
最大自起動周波数500pps
引き込みトルク800gf.cm / 5VDC 400pps
表3.28BYJ-48ステッピングモータの主な仕様

8-1.ステッピングモータの駆動に関して

今回使用したステッピングモータ28BYJ-48は1-2相励磁駆動用で、8ステップでモータのコイルの励磁を切り替えて駆動します。4096ステップでモータが1回転します。ドライバーボードの外部接続コネクタの信号ピン(IN1~IN4)から見た励磁の順番を28BYJ-48の仕様書から表4に作成しました。本表から分かるように1相励磁と2相励磁を繰り返すので1-2相励磁と呼びます。この順にIN1~IN4の信号線を制御すればステッピングモータを回転させることが出来ます。

ボードピンモータ線ステップ1ステップ2ステップ3ステップ4ステップ5ステップ6ステップ7ステップ8
IN1LOWLOWLOWLOWLOWHIGHHIGHHIGH
IN2LOWLOWLOWHIGHHIGHHIGHLOWLOW
IN3LOWHIGHHIGHHIGHLOWLOWLOWLOW
IN4HIGHHIGHLOWLOWKIWLOWLOWHIGH
表4.励磁順序(反時計方向回り)

8-2.実験装置回路図

図3にステッピングモータを動作させる実験装置の回路図を示します。1個のステッピングモータをRaspberry Pi Pico Wと接続しています。

28BYJ-48ステッピングモータのドライバーボードはテキサスインスツルメンツのULN2003ANと言うダーリントントランジスタアレイが使用されています。

ステッピングモータのドライバーボードの入力信号IN1~IN4をRaspberry Pi Pico WのGP0~GP3に接続しました。

BLE通信を使用してスマホと接続しています。Thonnyを起動したパソコンをUSBケーブルで接続しています。

図3.実験装置の回路図

8-3.ステッピングモータの駆動プログラム例

以下にステッピングモータを駆動するプログラム例を示します。プログラムの動作は最初にステッピングモータが0ステップの位置から1000ステップの位置ヘ回転します。その後にまた0ステップの位置に戻ります。

#ステッピングモータテストプログラム
from machine import Pin
import time

#ステッピングモータ用出力ピン設定
sp1 = Pin(0, Pin.OUT)						#GP0をステッピングモータ出力1とする
sp2 = Pin(1, Pin.OUT)						#GP1をステッピングモータ出力2とする
sp3 = Pin(2, Pin.OUT)						#GP2をステッピングモータ出力3とする
sp4 = Pin(3, Pin.OUT)						#GP3をステッピングモータ出力4とする

#処理待ち時間の設定
STEPS = 4096								#モータ1回転のステップ数
RPM_SPEED = 7								#モータ回転速度(RPM)
step_time = 60 * 1000 / STEPS / RPM_SPEED	#モータを1ステップ回転する時間間隔(msec)

current_pos = 0								#モータ現在位置
mot_step = 1								#モータステップ位置

#ステッピングモータ1ステップ回転処理
def step_1_rot(step, cw_flag):
    ret_step = 0	#リターンステップ番号
    
    #モータの現在のステップ位置による分岐
    if step == 1:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.on()
            ret_step = 2		#ステップ2へ
        else:
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 8		#ステップ8へ
    elif step == 2:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.off()
            ret_step = 3		#ステップ3へ
        else:
            sp1.off()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 1		#ステップ1へ 
    elif step == 3:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.on()
            sp3.on()
            sp4.off()
            ret_step = 4		#ステップ4へ
        else:
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.on()
            ret_step = 2		#ステップ2へ  
    elif step == 4:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 5		#ステップ5へ
        else:
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.off()
            ret_step = 3		#ステップ3へ  
    elif step == 5:
        if cw_flag == True:	#CW移動
            sp1.on()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 6		#ステップ6へ
        else:
            sp1.off()
            sp2.on()
            sp3.on()
            sp4.off()
            ret_step = 4		#ステップ4へ  
    elif step == 6:
        if cw_flag == True:	#CW移動
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.off()
            ret_step = 7		#ステップ7へ
        else:
            sp1.off()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 5		#ステップ5へ  
    elif step == 7:
        if cw_flag == True:	#CW移動
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 8		#ステップ8へ
        else:
            sp1.on()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 6		#ステップ6へ  
    elif step == 8:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 1		#ステップ1へ
        else:
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.off()
            ret_step = 7		#ステップ7へ
            
    return ret_step		#ステップ位置リターン

#ステッピングモータをposの位置まで回す
def mot_move(pos):
    global current_pos
    global mot_step
    
    while True:
        print(current_pos) 
        if pos > current_pos:						#目的位置>現在位置
            mot_step = step_1_rot(mot_step, True)	#CW方向1ステップ回転
            current_pos = current_pos + 1           #現在位置プラス
            if pos == current_pos:					#位置到達?
                break								#終了
        elif pos < current_pos:						#目的位置<現在位置
            mot_step = step_1_rot(mot_step, False) 	#CCW方向1ステップ回転
            current_pos = current_pos - 1           #現在位置マイナス
            if pos == current_pos:					#位置到達
                break								#終了
        else:
            break

        time.sleep_ms(int(step_time))				#時期ステップ移動待ち 

#----------メイン処理--------------------
#ステッピングモータ初期位置設定
sp1.off()
sp2.off()
sp3.off()
sp4.on()
ret_step = 1
current_pos = 0

time.sleep(1)

mot_move(4096)	#1000の位置に回転
mot_move(0)		#0の位置に回転

【プログラム説明】
6行目~9行目:
sp1 = Pin(0, Pin.OUT)
sp2 = Pin(1, Pin.OUT)
sp3 = Pin(2, Pin.OUT)
sp4 = Pin(3, Pin.OUT)
は、ステッピングモータのドライブ基板を接続するI/Oの指定をしています。GP0~GP3を使用しています。

14行目:
step_time = 60 * 1000 / STEPS / RPM_SPEED
は、ステッピングモータを1ステップ動作した後、次に1ステップ動作させるまでの時間(msec単位)を、ステッピングモータの1回転のステップ数(STEPS)と、回転速度(RPM_SPEED)から計算しています。RPM_SPEEDの単位はrpmです。

このstep_timeを使用して151行目のtime.sleep_ms(int(step_time))で、次のステップ送りまでの時間を取っています。

20行目:
def step_1_rot(step, cw_flag):
は、ステッピングモータを1ステップ駆動する関数です。
パラメータstepは、表5に示すステッピングモータ励磁順序の現在のステップ値です。1~8までの数値です。
cw_flagは回転方向で、Trueの時CW方向回転、Falseの時CCW方向回転です。
戻り値は、1ステップ駆動後の励磁ステップ値(1~8)です。

動作は現在のステップ値に応じて表5に従って、次のステップの励磁状態になるように、モータ線が接続されたI/Oの状態を変えています。

ボードピンモータ線ステップ1ステップ2ステップ3ステップ4ステップ5ステップ6ステップ7ステップ8
IN1LOWLOWLOWLOWLOWHIGHHIGHHIGH
IN2LOWLOWLOWHIGHHIGHHIGHLOWLOW
IN3LOWHIGHHIGHHIGHLOWLOWLOWLOW
IN4HIGHHIGHLOWLOWKIWLOWLOWHIGH
表5.励磁順序(反時計方向回り)

132行目:
def mot_move(pos):
は、ステッピングモータをposで指定したステップ位置に回転させる関数です。
複数回の1ステップ送り(step_1_rot()関数)を実効して、目的位置まで移動します。

138行目:
if pos > current_pos:
ステッピングモータの目標駆動ステップ位置が現在の位置より大きいか判断しています。大きい場合は139行目で、CW方向に1ステップ駆動させます。小さい場合は144行目で、CCW方向に1ステップ駆動させます。

139行目:
mot_step = step_1_rot(mot_step, True)
ステッピングモータをCW方向に1ステップ駆動しています。関数の戻り値は、ステッピングモータの1ステップ駆動後の励磁のステップ値です。

144行目:
mot_step = step_1_rot(mot_step, False)
ステッピングモータをCCW方向に1ステップ駆動しています。関数の戻り値は、ステッピングモータの1ステップ駆動後のステップ値です。

151行目:
time.sleep_ms(int(step_time))
は、ステッピングモータを1ステップ駆動した後、次に1ステップ駆動させるまで待っています。

9.BLE通信とステッピングモータ動作を組み合わせた最終プログラムコード

BLE通信とステッピングモータ動作を組み合わせた最終版のMicroPythonプログラムを以下に示します。
BLE接続後に、スマホ側から例えば”m1000\r\n”を送信すると、1000ステップの位置にモータが回転します。
スマホ側のアプリと操作は10項を参照して下さい。

#BLE通信とステッピングモータ駆動テストプログラム
from machine import Pin
import bluetooth
from ble_simple_peripheral import BLESimplePeripheral
import time

#BLEオブジェクト生成
ble = bluetooth.BLE()
#ペリフェラル生成
peri = BLESimplePeripheral(ble)

#ステッピングモータ用出力ピン設定
sp1 = Pin(0, Pin.OUT)						#GP0をステッピングモータ出力1とする
sp2 = Pin(1, Pin.OUT)						#GP1をステッピングモータ出力2とする
sp3 = Pin(2, Pin.OUT)						#GP2をステッピングモータ出力3とする
sp4 = Pin(3, Pin.OUT)						#GP3をステッピングモータ出力4とする

#処理待ち時間の設定
STEPS = 4096								#モータ1回転のステップ数
RPM_SPEED = 7								#モータ回転速度(RPM)
step_time = 60 * 1000 / STEPS / RPM_SPEED	#モータを1ステップ回転する時間間隔(msec)

mov_flag = False							#モータ動作フラグ
mov_pos = 0									#モータ動作目標位置
current_pos = 0								#モータ現在位置
mot_step = 1								#モータステップ位置

#ステッピングモータ1ステップ回転処理
def step_1_rot(step, cw_flag):
    ret_step = 0	#リターンステップ番号
    
    #モータの現在のステップ位置による分岐
    if step == 1:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.on()
            ret_step = 2		#ステップ2へ
        else:
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 8		#ステップ8へ
    elif step == 2:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.off()
            ret_step = 3		#ステップ3へ
        else:
            sp1.off()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 1		#ステップ1へ 
    elif step == 3:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.on()
            sp3.on()
            sp4.off()
            ret_step = 4		#ステップ4へ
        else:
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.on()
            ret_step = 2		#ステップ2へ  
    elif step == 4:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 5		#ステップ5へ
        else:
            sp1.off()
            sp2.off()
            sp3.on()
            sp4.off()
            ret_step = 3		#ステップ3へ  
    elif step == 5:
        if cw_flag == True:	#CW移動
            sp1.on()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 6		#ステップ6へ
        else:
            sp1.off()
            sp2.on()
            sp3.on()
            sp4.off()
            ret_step = 4		#ステップ4へ  
    elif step == 6:
        if cw_flag == True:	#CW移動
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.off()
            ret_step = 7		#ステップ7へ
        else:
            sp1.off()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 5		#ステップ5へ  
    elif step == 7:
        if cw_flag == True:	#CW移動
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 8		#ステップ8へ
        else:
            sp1.on()
            sp2.on()
            sp3.off()
            sp4.off()
            ret_step = 6		#ステップ6へ  
    elif step == 8:
        if cw_flag == True:	#CW移動
            sp1.off()
            sp2.off()
            sp3.off()
            sp4.on()
            ret_step = 1		#ステップ1へ
        else:
            sp1.on()
            sp2.off()
            sp3.off()
            sp4.off()
            ret_step = 7		#ステップ7へ
            
    return ret_step		#ステップ位置リターン

#ステッピングモータをposの位置まで回す
def mot_move(pos):
    global current_pos
    global mot_step
    
    no = 0    
    while True:
        print(current_pos) 
        if pos > current_pos:						#目的位置>現在位置
            mot_step = step_1_rot(mot_step, True)	#CW方向1ステップ回転
            current_pos = current_pos + 1           #現在位置プラス
            if pos == current_pos:					#位置到達?
                break								#終了
        elif pos < current_pos:						#目的位置<現在位置
            mot_step = step_1_rot(mot_step, False) 	#CCW方向1ステップ回転
            current_pos = current_pos - 1           #現在位置マイナス
            if pos == current_pos:					#位置到達
                break								#終了
        else:
            break
        
        #10回に1回BLE通信で現在位置を送る
        no = no + 1
        if no >= 10:
            no = 0
            send_pos(current_pos)					#現在位置送信 

        time.sleep_ms(int(step_time))				#時期ステップ移動待ち
    
    send_pos(current_pos)					#最終現在位置送信
    
#モータの現在位置をBLE送信
def send_pos(pos):
    text = str(pos) + "\r\n"
    peri.send(text)

#BLE受信コールバック関数
def rcv_data(data):
    global mov_flag
    global mov_pos
    
    data_str = data.decode()		#受信データをstr型に変換 
    
    f_m = data_str.find("m")		#"m"の位置検索                
    f_end = data_str.find("\r\n")	#"\r\n"の位置検索
                    
    if (f_m != -1 and f_end != -1 and f_m < f_end):
        m_data = data_str[f_m + 1 : f_end]	#位置データ取り出し
        mov_pos = int(m_data)		#モータ回転目標位置セット
        mov_flag = True				#モータ動作フラグセット
    
#----------メイン処理--------------------
connect_flag = False

#ステッピングモータ初期位置設定
sp1.off()
sp2.off()
sp3.off()
sp4.on()
ret_step = 1

peri.on_write(rcv_data)	#BLE受信コールバック関数設定

while True:
    if peri.is_connected():		#BLE接続中?
        if connect_flag == False:
            print("BE接続")
            connect_flag = True
                    
        if mov_flag == True:		#モータ動作要求?
            mot_move(mov_pos)		#モータ駆動
            mov_flag = False
    
    else:
        if connect_flag == True:
            print("BLE切断")
            connect_flag = False

10.スマホ側のアプリと操作手順に関して

今回はAndroidスマホとRaspberry Pi Pico WをBLE通信接続してステッピングモータの動作テストをしました。
スマホ側のBLE通信のテスト用アプリとして、Serial Bluetooth Terminalを使用しました。このアプリはGoogle Playよりダウンロード出来ます。

テスト時のアプリの操作手順に関して以下に示します。

①Raspberry Pi Pico W側の今回作成したMicroPythonプログラムを起動します。

②スマホのSerial Bluetooth Terminalアプリを起動します。
画面左上のにタッチします。

③Devices画面が表示されるので、Bluetooth LEを選択してSCANを押すと、周辺BLEデバイスが検索されます。
名称がmpy-uartと表示されるのが、Raspberry Pi Pico Wです。
mpy-uartにタッチするとスマホとRaspberry Pi Pico WがBLE接続されます。

④アプリの初期画面に戻すと、Connectedと表示されて右上にあるアイコンが接続状態になります。(切断状態の時のアイコンはです)

これで、スマホとRaspberry Pi Pico WがBLE通信で接続されました。

以後、このアイコン部分をタッチすることによって、BLEの接続、切断が可能です。


⑤スマホからRaspberry Pi Pico Wにステッピングモータ回転指令データを送ります。

例えばステッピングモータを1000ステップの位置に回転させる時は、データ送信欄に「m1000」と入力して、アイコンにタッチすると”m1000\r\n”がRaspberry Pi Pico Wに送信されます。
Raspberry Pi Pico Wがこのデータを受け取ると1000ステップの位置にステッピングモータを回転させます。


⑥ステッピングモータが1000ステップの位置に回転するのと並行して、モータの現在ステップ位置が逐次BLE通信で送られてきて、アプリ画面に表示されます。最終値はモータの最終ステップ位置で「1000」となります。

11.最後に

スマホとRaspberry Pi Pico WとをBLE通信で接続して、ステッピングモータの動作を操作することが出来ました。低消費電力無線でのモータの操作のため様々な用途に応用出来ると思います。
今回はスマホ側のアプリとして既存のSerial Bluetooth Terminalを使用しました。今後スマホ側のBLE通信オリジナルアプリにも挑戦したいと思います。


PAGE TOP