#研究室内のハッカソン
恒例となっている研究室内の学生(希望者)によるハッカソンが行われました。
今回、私は加速度センサを使って遊べるものを作ろうと考えました。
そこで、手首にM5StickCをつけて、加速度や角度の変化からパンチやガードを認識して画面になんらかのアクションを表示するものを作ることにしました。
他のメンバーの記事はこちら
#MQTT通信
前準備としてbrew install msquitto
を実行してmosquitto 1.6.7をインストールした
これが、悲劇の始まりだった...
何度mosquitto
を実行しても not found command と出てしまい起動しない
ググって色々試したが全然うまくいかなかったが、なんとか一つの記事にたどり着いた
https://qiita.com/nagayaoh/items/b3d80632e9b5aea68b53
上記の記事によると、パッケージの不具合でうまくいかなかったようでした
記事に従って、起動するとうまくいきます
この記事がなかったらここで終わってたかも(ありがたや〜)
次にsubscriber(受信側)とpublisher(送信側)の準備をします。
sub.pyというpythonファイルとarduinoというファイルを作成しました。
がしかし、mosquittoとsubscriber(受信側)とpublisher(送信側)の準備はできたのに、MQTT通信ができません
そこで、たまたま研究室にいた教授のお力を拝借しました。
教授のお力のおかげで原因を突き止められました。
原因は、自分の使っているmac bookでは、セキュリティソフトのせい(多分)で外部からの通信ができないためでした。(めちゃくちゃ時間を無駄にしてしまった 泣)
なので、ラズパイを使うことを決意。
この時点で、ハッカソンの残り時間は1時間 汗
##raspberry piの準備
ラズパイにmosquittoをインストールする
https://qiita.com/ekzemplaro/items/ab90dd630c3ad8e819ab
上記の記事を参考にした。
mosquitto: 1.5.7
補足
加速度センサから送られてくるデータはbyte型です。
これをfloat型にして使いたかったのでfloat(msg.payload.decode())
と書くことで変換することができました。
#boxing game??
raspberry piの準備が完了した時点で、制限時間が残り15分程度だったのでガードだけでも出すことにしました
ガードの判定に用いたのは、センサの傾きが0付近に出た時に'guard'と表示されるようにしました。
なんとか'gurd'の表示には成功しました。
パンチも認識して欲しかったので急いで、パンチの動きをした時の加速度の変化から、なんとなくできそうな閾値を設定したら一度だけ'punch'と表示することができました。
一度だけの表示じゃ、全然遊べないじゃん。
ここで、ハッカソンの終了時刻を迎えてしまいました。(無念)
中途半端なので、もし時間があれば続きをしようかなと思います。
#コード
subscriber(受信側)
# -*- coding: utf-8 -*-
import paho.mqtt.client as mqtt
host = '192.168.1.90'
port = 1883
topic = 'sensor/#'
def on_connect(client, userdata, flags, respons_code):
print('status {0}'.format(respons_code))
client.subscribe(topic)
def on_message(client, userdata, msg):
a = float(msg.payload.decode())
#print('guard or punch')
if msg.topic == 'sensor/accY':
b = a
if b <= 0:
c = b
if c <= 0 and b >= 0:
print('punch')
c = b
if msg.topic == 'sensor/roll' and -10 < a and a < 10:
print('guard')
if __name__ == '__main__':
# Publisherと同様に v3.1.1を利用
client = mqtt.Client(protocol=mqtt.MQTTv311)
# client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(host, port=port, keepalive=60)
# 待ち受け状態にする
client.loop_forever()
publisher(送信側)
arduino ide を用いてコードを書きます。
送るデータとしては、一方向の加速度と前後左右傾きの角度の3つのデータです。
複数のデータを受信するためにtopicの書き方を下記のように工夫しました。
pub側ではsensor/rollとsensor/pichと書いて
sub側ではsensor/#と書くことでsensor/以下のtopic全てを受信することができました
#include <M5StickC.h>
#include <Ambient.h>
#include <Wire.h>
#include <PubSubClient.h>
float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;
float theta_deg;
float phi_deg;
char* deviceID = "M5StickC";
char* subTopic = "sensor";
WiFiClient client;
PubSubClient mqttClient(client);
//Wifi
const char* ssid = "hogehoge";
const char* password = "hugahuga";
// Pub/Sub
const char* mqttHost = "192.168.1.90"; // MQTTのIPかホスト名
const int mqttPort = 1883; // MQTTのポート
//加速度センサから傾きデータ取得 [deg]
float get_acc_data() {
M5.IMU.getAccelData(&accX,&accY,&accZ);
//傾斜角導出 単位はdeg
//roll
theta_deg = atan( (float)(accZ) / (float)(-1 * accY) ) * 57.29578f;
//pich
phi_deg = -atan( (float)(accX) / sqrt(pow((float)(accY),2) + pow((float)(accZ),2)) ) * 57.29578f;
return theta_deg, phi_deg, accY;
}
//MQTT通信
void connectMQTT() {
mqttClient.setServer(mqttHost, mqttPort);
while (!mqttClient.connected()) {
if (mqttClient.connect(deviceID)) {
Serial.println("Connected.");
mqttClient.subscribe(subTopic);
Serial.println("Subscribed.");
} else {
Serial.print("Failed. Error state=");
Serial.print(mqttClient.state());
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
M5.begin();
M5.Axp.ScreenBreath(8);
M5.IMU.Init();
M5.Lcd.setRotation(1);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(40, 0);
M5.Lcd.println("IMU TEST");
M5.Lcd.setCursor(0, 10);
M5.Lcd.println(" roll pitch");
WiFi.begin(ssid, password); // Wi-Fi APに接続
while (WiFi.status() != WL_CONNECTED) { // Wi-Fi AP接続待ち
delay(500);
Serial.print(".");
}
Serial.print("WiFi connected\r\nIP address: ");
Serial.println(WiFi.localIP());
// mqttClient.setCallback(mqttCallback);
connectMQTT();
// ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化
}
void loop() {
get_acc_data();
//加速度センサによる傾斜角
Serial.print(theta_deg);
Serial.print(", ");
Serial.println(phi_deg);
//カルマン・フィルタによる角度の推定値
// Serial.println(theta_data[0][0]);
M5.Lcd.setCursor(0, 20);
M5.Lcd.printf(" %5.2f %5.2f",theta_deg, phi_deg);
char theta_String[50];
char phi_String[50];
char accY_String[50];
dtostrf(theta_deg,3,3,theta_String);
mqttClient.publish("sensor/roll",theta_String);
dtostrf(phi_deg,3,3,phi_String);
mqttClient.publish("sensor/pich",phi_String);
dtostrf(accY,3,3,accY_String);
mqttClient.publish("sensor/accY",accY_String);
delay(500);
}
最後まで読んでいただきありがとうございます。
日々精進していきたいと思います。