boxing game を作りたい

#研究室内のハッカソン
恒例となっている研究室内の学生（希望者）によるハッカソンが行われました。
今回、私は加速度センサを使って遊べるものを作ろうと考えました。
そこで、手首にM5StickCをつけて、加速度や角度の変化からパンチやガードを認識して画面になんらかのアクションを表示するものを作ることにしました。
他のメンバーの記事は[こちら](https://qiita.com/Rtakaha/items/f18c4872d62f5aeafb54)
#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(受信側)**

```python:sub.py
# -*- 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全てを受信**することができました

```C++:arduino.ino
#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);
}
```
最後まで読んでいただきありがとうございます。
日々精進していきたいと思います。