マイクロビット(e_39)MOVEminiをRadioで操作(1)
MOVE miniをRadio通信で操作1
もう一つのmicro:bitを無線送信用のコントローラーにして、MOVE miniをRadio通信で制御しようと思います。
micro:bitに搭載されているI2Cデバイスの加速度センサの値を使って、前後左右と各々の回転数を変化させます。また、ボタンを使って「開始、終了、Image表示」の副動作をしようと思います。
スクリプト
Move miniが前後左右に進む部分のスクリプトは前記事(e_38)とほぼ同じです。前記事を参照ください。
radioのchanne (デフォルト=7)、queue (デフォルト=3)などconfigはデフォルト状態で使用しています。
ThonnyのメニューからGeneral>「Allow only single Thonny instance」のチェックを外せば複数のThonnyを起動できます。Thonnyを2つ起動して送信用と受信用(MOVE mini)のスクリプトを評価できます。
スクリプト例は以下のようにしてみました。※thonny-microbitのMicroPythonを使っています。
送信側(コントローラー)
radio_send_12-2b.py
from microbit import *
import radio
# 返信待ち 送信したら返信あるまで待機する
def RS():
while True:
r_msg = radio.receive()
if r_msg:
# from Move recieved
print(r_msg)
break
# PUSH Aボタンで開始、イメージ矢印を表示 A+Bで中止
while True:
print('START Push A')
display.show('A') # 乾電池電源で単独動作の時に’A'表示あればわかりやすい
sleep(1000)
display.clear()
sleep(500)
if button_a.is_pressed() & button_b.is_pressed():
display.clear() # displayをクリアして中止
print('A+B STOP')
radio.send('B1') # 開始してから停止させる(受信側の都合)
sleep(10)
radio.send('B3') # 停止送信
break # 中止
if button_a.is_pressed():
print('GO') # イメージ矢印を表示、頭文字+数文字'B1'送信
display.show(Image.ARROW_N)
radio.send('B1') # 開始送信
RS() # 返信待
break # 待機から抜けて 操作 開始
# --MAIN--
radio.on() # 無線をON
cnt=0 # 送信した回数
btn='NON'
while True:
# x:R(+)L(-) Y:B(+)F(-) Z:DN(+)UP(-)
r_acc=accelerometer.get_values() # accデータ値を取得
if button_a.is_pressed() & button_b.is_pressed():
btn='3'
elif button_b.is_pressed():
btn='2'
elif button_a.is_pressed():
btn='1' # 数文字
else :
btn='NON'
#print(cnt,msg,btn)
# ボタン
if btn != 'NON':
msg='B'+btn # ボタン操作の頭文字’B’+数文字A(1)B(2)A+B(3)
radio.send(msg)
cnt=cnt+1
print('btn',cnt, btn, msg)
if btn=='3': # A+Bで終了
radio.off()
display.clear()
print('Break-END')
break
RS() # 返信待
sleep(200) # 多重防止
# accのx、y値の255以上で大きい方のデータを送信する
# x値:r_acc[0] y値:r_acc[1]
if (abs(r_acc[0])>=abs(r_acc[1])) & (abs(r_acc[0])>=255):
x_da=r_acc[0]
x_ms='X'+str(x_da) # 左右に使うデータ
radio.send(x_ms)
cnt=cnt+1
print(cnt,'x_ms',x_ms)
RS() # 返信待
# 前<>後進
if (abs(r_acc[0])<abs(r_acc[1])) & (abs(r_acc[1])>=255):
y_da=r_acc[1]
y_ms='Y'+str(y_da) # 前後に使うデータ
radio.send(y_ms)
cnt=cnt+1
print(cnt,'y_ms',y_ms)
RS() # 返信待
受信側(MOVE mini)
move_radio_recieve_12-3b.py
from microbit import *
import radio
def SEP(sdat): # 文字データの分離
pfx=sdat[0] # 頭文字
dat=sdat[1: len(sdat)] # 残りの文字(数文字)
dat=int(dat) # 数文字を整数値に
return pfx,dat # str,int
# pins
RS=pin1 # servo right(pin1)
LS=pin2 # servo left (pin2)
# right servo
def RSV(pwm):
RS.set_analog_period(20) #周期を設定 20msec
RS.write_analog(pwm)
#print('pwm_L %3d' %pwm)
# left servo
def LSV(pwm):
LS.set_analog_period(20) #周期を設定 20msec
LS.write_analog(pwm)
#print('pwm_L %3d' %pwm)
# pwm off
def M_STOP():
RS.write_analog(0)
LS.write_analog(0)
# neutral position pwm=77
N_pos=77
def M_NPOS():
RSV(N_pos) #neutral
LSV(N_pos) #neutral
#----------------------------------------FRONT-BACKWARD
# 前進
def M_FWD(DAT,tm,wt=0):
LSV(N_pos+DAT[0]) # CW
RSV(N_pos-DAT[1]) # CCW
sleep(tm) # move_time
M_NPOS()
sleep(wt) # wait_time
# 後進
def M_BWD(DAT,tm,wt=0):
LSV(N_pos-DAT[0]) # CW
RSV(N_pos+DAT[1]) # CCW
sleep(tm)
M_NPOS()
sleep(wt)
#----------------------------------------FRONT TURN
# 前右回
def M_FTR(DAT,tm,wt=0):
LSV(N_pos+DAT[0])
#RSV(N_pos+DAT[1])
sleep(tm)
M_NPOS()
sleep(wt)
# 前左回
def M_FTL(DAT,tm,wt=0):
#LSV(N_pos-DAT[0])
RSV(N_pos-DAT[1])
sleep(tm)
M_NPOS()
sleep(wt)
# dat=r_msg[1]>255 受信するacc-dataは255以上
def M_SVM(dat):
t_dat=int(abs(800/1023*dat)) # accデータからサーボ動作時間
d_pwm=int((abs(dat)-255)/96 + 8 ) # accデータからサーボPWM値
s_pwm=(d_pwm-1,d_pwm) # 補正 L-R=1
print(t_dat,s_pwm) # 動作時間、左右pwm値
return t_dat,s_pwm
# --MAIN--
radio.on()
M_STOP()
M_NPOS() # Neutral
sleep(1000)
print('START')
cnt=0
while True: # ボタンAが押されるまで待機
r_msg = radio.receive()
print('Ready A',r_msg)
sleep(2000)
if r_msg=='B1': # Aボタン押のデータ'B1'受信
s_msg='recived'
radio.send(s_msg) # 返信
display.show(Image.ARROW_N) # イメージ矢印を表示
break # 待機を抜けて動作開始
while True:
r_msg = radio.receive()
if r_msg:
cnt=cnt+1
d_msg=SEP(r_msg)
print(cnt,d_msg)
# Button
if d_msg[0]=='B':
print('button')
if d_msg[1]==3: #'C'(3)
print('buttonA+B END')
M_STOP()
radio.off()
display.clear()
break
if d_msg[1]==2: #'B'(2)
print('buttonB')
display.clear()
if d_msg[1]==1: #'A'(1)
print('buttonA')
display.show(Image.HAPPY)
# 回転 頭文字が’X'の場合
if d_msg[0]=='X':
(t_dat,d_pwm)=M_SVM(d_msg[1]) # d_msg[1]はaccデータで整数
if int(d_msg[1])>0:
print('右')
M_FTR(d_pwm,t_dat,0)
else:
print('左')
M_FTL(d_pwm,t_dat,0)
# 前後進 頭文字が’Y'の場合
if d_msg[0]=='Y':
(t_dat,d_pwm)=M_SVM(d_msg[1]) # d_msg[1]はaccデータで整数
if d_msg[1]<0:
print('前')
M_FWD(d_pwm,t_dat,0)
else:
print('後')
M_BWD(d_pwm,t_dat,0)
# 返信
s_msg='recived'
radio.send(s_msg)
else:
pass
スクリプトの説明
スクリプトの部分説明です。
以下の部分はサーボの動作時間とPWM値を送信されたaccデータから作成しています。
def M_SVM(dat):
t_dat=int(abs(800/1023*dat)) # accデータからサーボ動作時間
d_pwm=int((abs(dat)-255)/96 + 8 ) # accデータからサーボPWM値
s_pwm=(d_pwm-1,d_pwm) # 補正 L-R=1
print(t_dat,s_pwm) # 動作時間、左右pwm値
return t_dat,s_pwm
t_dat:サーボ動作時間
送信されるaccデータは255以上なので、動作時間は199(800/1023*255)から800msecの値になります。
d_pwm:左右のサーボに送るPWM値
速度を変化させるために前記事のグラフから8~16値を使うようにしました。送信されるaccデータは255~1023に対して、PWM値が8~16になるようにしています。
左右のサーボ回転速度が違うので s_pwm=(d_pwm-1,d_pwm)で調整しています。
それでもかなりズレます。ピッタリにはなりません。同じような特性のサーボをペアにした方がよいと思います。
実行結果
Thonnyのshellに表示された結果です。
送信側(コントローラー)
>>> %Run radio_send_12-2b.py
START Push A
START Push A
GO # A ボタンでスタート
recived # 返信を受ける・・次送信が可能になる
1 x_ms X256 # 送1 左右データ 右
recived
2 x_ms X352
recived
3 x_ms X-256 # 送3 左右データ 左
recived
4 x_ms X-304
recived
5 y_ms Y256 # 送5 前後データ 左
recived
6 y_ms Y272
recived
btn 7 2 B2 # 送7 ボタン B
recived
btn 8 3 B3 # 送8 ボタン A+B
Break-END # 停止
>>>
受信側(MOVE mini)
>>> %Run move_radio_recieve_12-3b.py
START
Ready A None
Ready A None
Ready A B1 # 受 A ボタンでスタート
1 ('X', 256) # 受1 左右データ 右
200 (7, 8)
右
2 ('X', 352)
275 (8, 9)
右
3 ('X', -256) # 受3 左右データ 左
200 (7, 8)
左
4 ('X', -304)
237 (7, 8)
左
5 ('Y', 256)
200 (7, 8)
後
6 ('Y', 272)
212 (7, 8)
後
7 ('B', 2) # 受7 ボタン B
button
buttonB
8 ('B', 3) # 受8 ボタン A+B
button
buttonA+B END # 停止
>>>
※メモリーのエラーが発生する場合、ThonnyのメニューからDevice>soft reboot後に実行すると解消できることがあります。
動作確認の動画
手元、パソコンにつないだままで動作確認をしました。コントローラとサーボの動作です。まあまあ動いてます。
実動作の動画
電池駆動で独立させて動かしてみます。
送信側(コントローラー)、受信側(MOVE mini)のスクリプトを各々main.pyとしてuploadします。
micro:bitにuploadするにはThonnyのメニューのDevice>Upload current script as main scriptを選択します。
実際に床面で動かしてみました。Move miniの動画です。
車輪がやや滑り気味です。前進はやっぱり曲がってますが、後進はそこそこまっすぐ進みました。
回転などは思ったより上手く動いてます。
まとめ
micro:bitのRadio通信機能を使ってMOVE miniのリモート動作が出来ました。電池が消耗するとピタッと動かなくなります。壊れてはいないので、動かない時は電池交換して見るとよいと思います。前後左右、回転、簡単な動作しかできませんが、実際に動くと面白いです。