●スマートフォンのアプリをつくる(iOS)


 今回からiPhoneのリモコンアプリの制作となりますが、ゼロからすべてを作っていくのはハードルが高くなってしまいますので途中まで作成したサンプルプロジェクトにプログラムを追加していく方法となることをご了承ください。
 iPhoneアプリの開発にはXcodeという開発環境を使いますので、お使いのmacにインストールしてください。(iPhoneアプリの開発にはmacパソコンが必要です。) Xcodeの基本的な使い方に関しては初心者向けの書籍等を参照してください。
 
 次にこちらーBLEControllerーからサンプルプロジェクトをダウンロードします。zipファイルを解凍し、Xcodeからプロジェクトを開いてください。
 左側の「BLEController」->「BLEController」->「ViewController.swift」を開きます。上のメニューから「Product」->「Build」でエラーが出ないことを確認します。

 左側で「BLEController」->「BLEController」->「Main.storyboard」を開きます。こちらはアプリの画面の設定となります。下半分が空いていますがこちらには後ほど別の部品を追加します。

 ViewControllerに戻って先頭のUUIDは、ESP32のプログラムに書かれていたものをそのまま記載します。これが違っているとマイコン側とスマートフォン側とで通信が成立しません。

 プログラム30行目からの@IBActionには、ボタンがタップされたときの処理が書かれています。現在はスキャン、接続、切断、左旋回の処理のみでその他の処理は未記載です。左旋回(LTRN)の記載内容を参考に残りの部分のコードを完成させてください。Main.storyboardからcontrol+ドラッグしてボタンとアクションの関連付けを行います。(初めての方:xcode 紐付け で検索)
 前回はBLEデータのやり取りを文字列で行いましたが、今回はBYTE配列を使います。(ESP32のプログラムも変更します。)実際のデータの送信は、プログラム下方のfunc write(byteValue: [UInt8]) で実行されます。

@IBAction func tapScanBtn(_ sender: Any) {
    startScan()
}
@IBAction func tapConnectBtn(_ sender: Any) {
    self.centralManager.connect(blePeripheral, options: nil)
}
@IBAction func tapLtrnBtn(_ sender: Any) {
    write(byteValue: [1])
}
@IBAction func tapFwrdBtn(_ sender: Any) {
    write(byteValue: [2])
}
@IBAction func tapRtrnBtn(_ sender: Any) {
    write(byteValue: [3])
}
@IBAction func tapLeftBtn(_ sender: Any) {
    write(byteValue: [4])
}
@IBAction func tapStopBtn(_ sender: Any) {
    write(byteValue: [5])
}
@IBAction func tapRghtBtn(_ sender: Any) {
    write(byteValue: [6])
}
@IBAction func tapLedonBtn(_ sender: Any) {
    write(byteValue: [7])
}
@IBAction func tapBwrdBtn(_ sender: Any) {
    write(byteValue: [8])
}
@IBAction func tapLedoffBtn(_ sender: Any) {
    write(byteValue: [9])
}
@IBAction func tapSndBtn(_ sender: Any) {
    write(byteValue: [0])
}

 mm12bをもとに、ESP32側もBYTE配列でデータを受け取るように変更しmm15とします。

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      if (value.length() > 0) {
        for (int i = 0; i < value.length(); i++){
          byte data = (uint8_t)value[i];
          Serial.print(data);
          if(data == 0 || data == 7 || data == 9) {
            switch(data){
            case 0:  //"0"ボタン
              start_playback();
              break;
            case 7:  //"7"ボタン  
              digitalWrite(14,HIGH);
              break;
            case 9:  //"9"ボタン  
              digitalWrite(14,LOW);
              break;
            default:
              break;
            }
          } else {
            switch(data){  //<-switch文を追加
            case 2:  //"2"ボタン
              actionMode = FWRD;
              memcpy(motionAngles, fwrdAngles, sizeof(fwrdAngles));
              maxRows = sizeof(fwrdAngles) / sizeof(*fwrdAngles) - 1;
              break;
            case 5:  //"5"ボタン
              actionMode = STOP;
              for(int i=0; i<12; i++) {
                tempAngles[i] = stopAngles[i];
              }
              set_angle();
              break;
            case 8:  //"8"ボタン
              actionMode = BWRD;
              memcpy(motionAngles, bwrdAngles, sizeof(bwrdAngles));
              maxRows = sizeof(bwrdAngles) / sizeof(*bwrdAngles) - 1;
              break;
            case 1:  //"1"ボタン
              actionMode = LTRN;
              memcpy(motionAngles, ltrnAngles, sizeof(ltrnAngles));
              maxRows = sizeof(ltrnAngles) / sizeof(*ltrnAngles) - 1;
              break;
            case 3:  //"3"ボタン
              actionMode = RTRN;
              memcpy(motionAngles, rtrnAngles, sizeof(rtrnAngles));
              maxRows = sizeof(rtrnAngles) / sizeof(*rtrnAngles) - 1;
              break;
            case 4:   //"4"ボタン
              actionMode = LEFT;
              memcpy(motionAngles, leftAngles, sizeof(leftAngles));
              maxRows = sizeof(leftAngles) / sizeof(*leftAngles) - 1;
              break;
            case 6:  //"6"ボタン
              actionMode = RGHT;
              memcpy(motionAngles, rghtAngles, sizeof(rghtAngles));
              maxRows = sizeof(rghtAngles) / sizeof(*rghtAngles) - 1;
              break;
            default:
            break;
            }
            divCounter = 0;
            keyFrame = 0;
            nextKeyFrame = 1;
          }
        }  
      }
    }
};

<= マイクロマシーン チュートリアル(12)
チュートリアルベース
マイクロマシーン チュートリアル (16) =>