概要
前の投稿やった iPhoneを使ってM5BALAを操作する(JavaScript-MQTT編) の Pythonista版です。
- iPhone の傾きを Pythonista で検知する
- Pythonista から MQTT 経由で制御コマンドを送信する
- 受信した制御コマンドに従ってM5BALA+M5GOが動く
Pythonista は iPhone や iPad 上で Python が実行できる開発環境。以前 Pythonista を知った時は、興味は持ったものの、有料(1200円)であることや、iPhone や iPad 上でコーティングなんて外付キーボードを使っても無理、と思って使わずでしたが、今は iCloud Drive で連携できるので、Mac で iCloud Drive 上のファイルを編集し、iPhone側で iCloud Drive 上のファイルをそのまま実行できるのでとっても楽です。BLEが使えるので、M5Stack と BLE で連携というのも、そのうち試したいことです。
環境
- M5BALA+M5GO
- M5UI.Flow (Firmware 0.7.2/0.8.0 で確認)
- iMac (macOS Mojave)
- MQTT Broker (mosquitto version 1.4.15)
- MQTT Client (paho-mqtt 1.4.0)
- Pythonista3 v3.2
- iPhone6 iOS 12.0.1
実行例
iPhoneを前後左右に傾けることで、M5BALAが前進・後進・右回転・左回転します。
前回JavaScriptでやったことをPythonistaにしました。私のM5GOは今ジャイロが使えないので、バランスモードは使わず牽引車にしています。左手はiPadでビデオ、右手はIPhoneで操作、難しい〜。
— 稲澤祐一 (@inasawa) 2018年10月26日
「iPhoneを使ってM5BALAを操作する(Pythonista-MQTT編)」https://t.co/TdyAiuA1yW#M5Stack #M5BALA pic.twitter.com/ivwNKtbUga
M5BALAが引っ張る荷台にiPhoneを乗っけて撮影してみました。テーブル&椅子の脚の間を走らせています。#M5Stack #M5BALA pic.twitter.com/AhU5CIBIgm
— 稲澤祐一 (@inasawa) 2018年10月27日
Pythonista3プログラム
iPhoneの前後左右の傾きに応じて、左右の車輪を動かすための指示をMQTT経由で送信する仕組みです。
MQTTクライアントが必要なので StaSh - Shell Like an Expert in Pythonista をインストール。(Pythonista のコンソールで以下を実行)
import requests as r; exec(r.get('http://bit.ly/get-stash').text)
StaSh を実行し pip で paho-mqtt をインストール。
pip install paho-mqtt
import motion
import time
import paho.mqtt.client as mqtt
import math
import ui
MQTT_BROKER = 'MQTTBroker' # MQTTBroker のアドレスを設定
MQTT_TOPIC = 'M5BALA'
def end_controller(sender):
global action_loop
sender.superview.close()
send_action('I')
action_loop = False
def send_action(action):
global last_action
client.publish(MQTT_TOPIC, action)
view['action'].text = action
last_action = action
view = ui.load_view()
view.present('sheet')
client = mqtt.Client('iPhonePythonista3', protocol=mqtt.MQTTv311)
client.connect(MQTT_BROKER, keepalive=60)
motion.start_updates()
# 'I' : Init Params
send_action('I')
action_loop = True
while action_loop:
roll, pitch, yaw = motion.get_attitude()
yaw = math.degrees(yaw)
pitch = math.degrees(pitch)
roll = math.degrees(roll)
view['yaw'].text = '{:.2f}'.format(yaw)
view['pitch'].text = '{:.2f}'.format(pitch)
view['roll'].text = '{:.2f}'.format(roll)
move = max(-60, min(60, pitch)) * 4
turn = max(-60, min(60, roll)) * 1
action = 'L={:.2f},R={:.2f}'.format(move + turn / 2, move - turn / 2)
if action != last_action:
send_action(action)
time.sleep(0.5)
Pythonista3 UI
[
{
"nodes" : [
{
"nodes" : [
],
"frame" : "{{17, 197}, {337, 45}}",
"class" : "Label",
"attributes" : {
"name" : "action",
"frame" : "{{45, 104}, {150, 32}}",
"uuid" : "95E5B18C-90A9-4784-BA75-4B1016070924",
"class" : "Label",
"alignment" : "center",
"text" : "Action",
"font_size" : 36,
"font_name" : "<System>"
},
"selected" : false
},
{
"nodes" : [
],
"frame" : "{{96, 27}, {60, 32}}",
"class" : "Label",
"attributes" : {
"name" : "label2",
"frame" : "{{82, 125}, {150, 32}}",
"uuid" : "5144134F-E68A-4023-A81E-A67824AF01CA",
"class" : "Label",
"alignment" : "right",
"text" : "方角",
"font_size" : 24,
"font_name" : "<System>"
},
"selected" : false
},
{
"nodes" : [
],
"frame" : "{{96, 67}, {60, 32}}",
"class" : "Label",
"attributes" : {
"name" : "label3",
"frame" : "{{82, 125}, {150, 32}}",
"uuid" : "01A7842C-1680-4655-9F09-F3B52A0721B6",
"class" : "Label",
"alignment" : "right",
"text" : "前後",
"font_size" : 24,
"font_name" : "<System>"
},
"selected" : false
},
{
"nodes" : [
],
"frame" : "{{96, 107}, {60, 32}}",
"class" : "Label",
"attributes" : {
"name" : "label4",
"frame" : "{{82, 125}, {150, 32}}",
"uuid" : "A5EF17D2-3351-4AA3-B918-A82382B2DF4D",
"class" : "Label",
"alignment" : "right",
"text" : "左右",
"font_size" : 24,
"font_name" : "<System>"
},
"selected" : false
},
{
"nodes" : [
],
"frame" : "{{164, 27}, {103, 32}}",
"class" : "Label",
"attributes" : {
"name" : "yaw",
"frame" : "{{82, 125}, {150, 32}}",
"uuid" : "F6954500-8FAB-4E42-B4A6-29A7865C50F9",
"class" : "Label",
"alignment" : "right",
"text" : "",
"font_size" : 24,
"font_name" : "<System>"
},
"selected" : false
},
{
"nodes" : [
],
"frame" : "{{164, 67}, {103, 32}}",
"class" : "Label",
"attributes" : {
"name" : "pitch",
"frame" : "{{82, 125}, {150, 32}}",
"uuid" : "A73FDD85-DBEE-4857-9B9E-39B13FEEA553",
"class" : "Label",
"alignment" : "right",
"text" : "",
"font_size" : 24,
"font_name" : "<System>"
},
"selected" : false
},
{
"nodes" : [
],
"frame" : "{{164, 107}, {103, 32}}",
"class" : "Label",
"attributes" : {
"name" : "roll",
"frame" : "{{82, 125}, {150, 32}}",
"uuid" : "7744E0CF-F2CD-4985-AAD3-A68158E7F67D",
"class" : "Label",
"alignment" : "right",
"text" : "",
"font_size" : 24,
"font_name" : "<System>"
},
"selected" : false
},
{
"nodes" : [
],
"frame" : "{{136, 266}, {87, 39}}",
"class" : "Button",
"attributes" : {
"action" : "end_controller",
"border_width" : 1,
"frame" : "{{146, 149}, {80, 32}}",
"title" : "終了",
"uuid" : "0EC4234B-2C78-4812-89A4-236FB5384680",
"class" : "Button",
"corner_radius" : 8,
"font_bold" : true,
"name" : "button1",
"font_size" : 24
},
"selected" : false
}
],
"frame" : "{{0, 0}, {372, 330}}",
"class" : "View",
"attributes" : {
"name" : "M5BALA Controller",
"enabled" : true,
"border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)",
"background_color" : "RGBA(1.000000,1.000000,1.000000,1.000000)",
"tint_color" : "RGBA(0.000000,0.478000,1.000000,1.000000)",
"flex" : ""
},
"selected" : false
}
]