Line Things + テルミンでDrunken UFO 【ご褒美もらえるVer】

# 前回
[前回](https://qiita.com/karu/items/5455cdef54364f633ca9)は、Line Thingsを利用して距離センサのテルミンで
Flappy Bird的なゲームを作ってみました。
Flappy Birdの鳥をUFOにしてコントローラをテルミンに置き換えただけだったので、
今回は前回作成したものをもう一捻りしてみました。

# 何を作ったか

スコア伸ばしてくだけじゃモチベーションが上がらないので、物理的なご褒美もらえるようにしたい。
ご褒美といえば酒です。頑張ったらお酒飲める。モチベーション上がる。です。
それに前回作ったやつをみていただくといいのですが、このUFOの動きふわふわしてて酔っ払っているように見えなくもない。

ということで、ゲームの画面上にビールを出現させてそれをゲットすると、ビール注いでくれるみたいなのを作ってみました。


# 実装

ゲームの部分は前回作成したものを流用して、
ビール注ぎマシーンは、サーボを利用します。


## 苦労したところ
サーボのスピードをコントロールするために、```delay()```を使っているので、
```loop```内の距離測定の処理を止めないようサーボを動かすタスクは、```xTaskCreate```という関数で非同期で実行してメインのループをブロックしないようにしました。
（arduino全くの無知なので他のいいやり方あれば是非ご教授いただけると..）

**ソース一部抜粋(M5Stack)**

```c++
//Liffからの書き込みコールバック
class writeCallback: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *bleWriteCharacteristic) {
    std::string value = bleWriteCharacteristic->getValue();
    if ((char)value[0] <= 1) {
      if ((char)value[0] == 1) {
        M5.Lcd.clear(WHITE);
        M5.Lcd.setTextColor(BLACK);
        M5.Lcd.setTextSize(4);
        M5.Lcd.setCursor(135, 100);
        M5.Lcd.println("ON");
        calcDistance = true;
      }
      else {
        M5.Lcd.clear(BLACK);
        M5.Lcd.setTextColor(WHITE);
        M5.Lcd.setTextSize(4);
        M5.Lcd.setCursor(130, 100);
        M5.Lcd.println("OFF");
        calcDistance = false;
      }
    }
    if ((char)value[0] == 2) {
      shouldServoMove = true;
    }
  }
};

//省略

void loop() {

  M5.update();
  
  // Disconnection
  if (!deviceConnected && oldDeviceConnected) {
    delay(500); // Wait for BLE Stack to be ready
    thingsServer->startAdvertising(); // Restart advertising
    oldDeviceConnected = deviceConnected;
    M5.Lcd.clear(BLACK);
    M5.Lcd.setTextColor(YELLOW);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(65, 10);
    M5.Lcd.println("Ready to Connect");
  }
  // Connection
  if (deviceConnected && !oldDeviceConnected) {
    oldDeviceConnected = deviceConnected;
    M5.Lcd.clear(BLACK);
    M5.Lcd.setTextColor(GREEN);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(100, 10);
    M5.Lcd.println("Connected");
  }
  //距離測定
  if (calcDistance) {
    float HCSR04_d_d = hcsr04.distance();
    char buf[24];
    snprintf(buf, 24, "%.0f", HCSR04_d_d * 10);
    notifyCharacteristic->setValue(buf);
    notifyCharacteristic->notify();
    Serial.println(buf);
    delay(100);
  }

　//ビールゲットでサーボ動かす
  if (shouldServoMove && !isServoMoving) {
    xTaskCreate(moveServo,"moveServo", 4096, NULL, 1, NULL);
  }
}

//サーボ関数
void moveServo(void *pvParameter) {
  int maxDeg = 120;
  int minDeg = 10;
  int val;
  
  isServoMoving = true;
  servo.attach(Servo_Sig, minUs, maxUs);

  //傾ける
  for (val = 0; val <= maxDeg; val += 1) {
    servo.write(val);
    delay(20);
  }

  //一定時間注ぐ
  delay(900);

  //起こす
  for (val = maxDeg; val >= minDeg; val -= 1) {
    servo.write(val);
    delay(20);
  }
  
  servo.detach();
  isServoMoving = false;
  sholdServoMove = false;
  vTaskDelete( NULL );
}
```
githubにソースあげております。
**[M5Stack](https://github.com/karukade/liff-theremin/blob/master/theremin.ino)**
**[Liff](https://github.com/karukade/liff-theremin/tree/master/liff)**

# こうなりました
2テイク分入ってます。
１テイク目は予想以上に一杯の量が多く溢れ。。
2テイク目はビールがなくなるという残念な結果に。。
いずれうまくいってるバージョンに差し替えるかもしれません。

[![デモ動画サムネイル](http://img.youtube.com/vi/D47g5J0mQoc/0.jpg)](https://youtu.be/D47g5J0mQoc)

# 終わり 

前回作ったやつよりも楽しくなったかな。
やってて気づいたのですが、サーボと距離センサって、前々回投稿で作ったものと全く同じ構成でやってました。。
[前々回の腹筋](https://qiita.com/karu/items/af1d5fc60ab4882be930)にビール組み合わせるのも勢いでやっちゃうかもしれません。
そろそろ違うセンサに手を出さなきゃ。