編集履歴一覧に戻る
syouwa-taroのアイコン画像

syouwa-taro が 2021年02月11日17時28分26秒 に編集

初版

タイトルの変更

+

フィットネスバイクで世界旅行する人力飛行機Simulatorを作った

タグの変更

+

M5StickC

+

GoogleEarth

+

Arduino

+

flight-simulator

+

世界旅行シミュレーター

メイン画像の変更

メイン画像が設定されました

本文の変更

+

**【きっかけ】**  GoogleEarthにはFlightSimulatorの機能がありPCのキーで操縦できます。操作しているうちに、Bluetoothでキーコードを送ればGoogleEarthの景色を巡る操作が出来るのではと思い試してみたところ成功。ヽ(^o^)丿更にフィットネスバイクと連動させ人力飛行機Simulatorを作ったものです。 **【概要】** バイクのハンドルの上にただ置くだけで、運動しながら人力飛行機で世界中(GoogleEarth)を健康的に旅行できるフィットネスバイク用コントローラーを作り更に以下の目標を目指した。 仕様目標 1. コントローラー本体コスト¥2000台 ⇨ 達成 1. 種類の多いフィットネスバイクのいろいろな形状に対応 ⇨ 感度調整を追加し評価待ち 1. ルームランナーにも対応 ⇨ 感度調整を追加し評価待ち 1. 健康器具を使わなくとも、身に着け足踏みしながら楽しめる  ⇨ほぼ達成 ![全体像](https://camo.elchika.com/b8530345deca95604de9f05ca345dfaaa7f66b99/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f62623535653634662d393561612d343036612d393166392d663235346538366630363432/) **【仕組み】** フィットネスバイクのペダルを漕ぐ振動を、ハンドルの上に置いたM5stickC内蔵のMPU6886で加速度を検出しペダルの速さを演算判別する(速さ=∫加速度 ここがミソ)とともに、ハンドルの軸の手前傾斜により向きに応じ変わるY軸重力値を計測して向きを判別し(ここがミソ) 速さと向きに合わせ 着陸 ホバリング ゆっくり前進 前進 上昇 左右旋廻 のキー操作を内蔵BluetoothでPCに送信して、運動に合わせGoogleEarthの中をバイクで走ったり飛んだりするシミュレーターコントローラー。(要はバイクを改造することなくペダル漕ぎの速さを検出し、バイクを漕ぎながら世界旅行出来るシミュレーターを作った) ![M5stickCをハンドルに置いた図](https://camo.elchika.com/199be9c4d172a46b66919a7696893d147e7fd1b5/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f64353464633939372d633530352d343066612d623332392d313538633762386635313365/) ![ハンドルの向きで変わるY軸加速度(ハンドルを右90度向けた横面図)](https://camo.elchika.com/380071197fe9dbe083c0baa9ab46924c85556ad0/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f63366264646363632d356335652d343761392d616339382d636662383561363638363838/) **【作り方】** コントローラーのハードはM5stickCポッキリで追加回路一切無しヽ(^o^)丿 本ArduinoスケッチをコピペしてコンパイルしM5stickCに書き込めば完成 (ものの数分ではなしですが、ただしライブラリーに追加インストールするソフトがいくつか必要です。) 取り付け機構として輪ゴムでもハンドルに固定できますが、M5付属のホールダーを使い裏に100均磁石を接着しておくと、ハンドルの上に置くだけで磁石ですっきり固定されます。人に取り付ける場合、胸ポケットがあれば入れるだけでよく、ポケットがない場合、ゼムクリップなどを衣服に挟みそこに磁石付きホルダーで固定できます。 ![古く見にくいのですが概略ソフトの流れ参考です](https://camo.elchika.com/8cb480abf5b60e6c261daeb4f0b80ab8ddfd7a32/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f65616235326236332d613366302d346461392d616138662d393739643434303035396435/) **【コントローラー材料】** 1. M5stickC(ESP32-Pico MPU6886 )  スイッチサイエンス 本体のみ¥1650 ホルダー付¥1980 1. 磁石 100均 1. 接着材 100均 1. (groveポート 4pメスコネクタ1本  ハンドルが動かせない場合左右タッチスイッチを追加 スイッチサイエンス 5本/¥500くらい) **【フィットネスバイク】** 手持ち付きエクササイズペダラー HC-201A amazon ¥4980 (評価目的で安価。ハンドル改造方法:ハンドル高さ調整ピンを抜くとハンドルが回ります) *ハンドルが回せないバイクの場合・・・安心してください 2つ方法があります  ①自分の胸に付け バイクを漕ぎながら左右に体を傾ける(こちらのほうが楽しいかもです)  ②groveポート(G32 G33)から左右タッチセンサの線を出して左右グリップ等に付け線をタッチして操作 ![optionタッチ板](https://camo.elchika.com/ce594fd028952621e99e7ddcc28cd223604d6a1e/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f61646231393363322d633530382d343863352d613630392d376237363462343561636333/) **タッチ板を使うときはLOOPの//touch のコメントを外してください** *バイクがない場合・・・安心してください 胸に付け足踏みしながら左右に傾けばタケコプターで世界旅行出来ます。(万歩計は容量オーバーで動かず) ![MstikCを体に付けた図](https://camo.elchika.com/5a8294b43bcde766c2975b1f5b51eda736af4aaa/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f35363164313135622d326433622d343965332d613435632d656635363431353063373639/) **【使い方】** 1. PCでGoogleEarth(衛星写真)を立ち上げ、旅行場所上空をセット 1. コントローラーの[電源]を入れPCとBluetoothペアリングする(ペアリングは最初一度だけです)1【スタート画面】で体力 形状に合わせ感度設定を行う。(本体右[設定キー]を押しながら 前後回転 左右傾斜 で速度 左右 の感度を調整し離すと決定) 1. ハンドルに乗せるか胸に付け 本体上[スタートキー]を押す(動作/停止トグル)。 バイクを漕ぐ あるいは足踏み歩行すると、運動速度に合わせ 下降 ホバリング ゆっくり前進 前進 上昇 。 ハンドルを回す あるいは体を傾けると左右に移動 ****重要な注意**** 本作品がスタート動作している時 PCに対しBluetoothでキーを送ります。スタート動作のままGoogle画面を閉じると、今度はPCのカーソル キーが勝手に動いてしまいPCのコントロールが効かなくなる事があります。  **”Googleの画面を閉じる前に必ず本体を[スタート画面]に戻してから閉じるようにしてください。”** @[youtube](https://www.youtube.com/watch?v=8ueAq2I8-eo&feature=youtu.be) **【考察】** この工作の肝は バイクを漕ぐ振動をハンドルの上に乗せた加速度センサで受けその加速度から漕ぐ速度を求めているところです。 加速度の波形をサンプリングし差分をとり(/70ms毎) 差分を積算(n=30)して漕ぐ速度に応じた電圧を計算しています。FFTでスペクトルを計算できるとよいのですが,技術不足と周期が遅くうまくいきませんでした。このあたり改良が必要です。 下図は加速度波形とそれから速度を計算したグラフです(横軸は目分量(足分量?)。スケッチのdebug用serial.printのコメントを外すとモニタでみられます。実際は常にX Y Z軸加速度を監視して最大の軸に切り替えています。) ![Y軸加速度波形](https://camo.elchika.com/2b294682df413dc93cd349c37b844c8a45ada650/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f33306464663638652d623539352d343261332d616432382d323131623461663933396134/) ![速度計算結果](https://camo.elchika.com/f9289646df31581327d4728ba4e8007b5b1247f7/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f37393932663439662d643031622d343265312d386438652d366537376464323330333663/) **【感想】** GoogleEarthを見る時、体の自然な動きで景色が動くことにより、考えながらコツコツのキー操作では味わえない楽しさがあります。 衛星写真なので、世界の街の裏通りまで入り現地の生活感がみえるのも発見です。 未踏の冬のヒマラヤを自分で動き周り、誰も見たことのない素晴らしい雪景色を味わう経験はありえません。本物火星の上も探検できます。 簡単なFlightSimuratorとしても楽しめ、本物の滑走路上に侵入禁止表示が書いてあるのにびっくり。 孫が遊んだところバイクを漕ぎ景色が変わるところが、どの孫もはまってしまい食事に呼んでもなかなかやめません。安全で元気に運動できるので親も安心です。 まだまだ改善の余地がありますが、まずはこの健康的な楽しさを多くの人と共有できればと思います。 **【産業上の利用可能性】** 近年テレワークがすすみ家庭に籠る時間が増え、運動不足が気になり運動を始めるが飽きてしまいがち。本作品のようなものが製品化され、運動しながら旅行シミュレーション・ゲーム等を楽しみ室内運動が盛んになれば、室内運動器具・ゲームマーケットの活性化が期待できる。 **【特許】** ざっとの検索(J-PlatPat)ですが、今回のアイデアのズバリ先願は見つかりませんでした。ただ海外メーカーが多く出しているVR関連で、広く権利化されているものがあれば抵触するかもしれません。当初本作品の特許出願準備していましたが中断中で、今回中断書類を再利用し説明書作成。出願せず説明書公開で安心して下さいヽ(^o^)丿。 **【今後】** 今回"Let's elchika!"で、本作品を見、更に良いものを作られ、またなにか新作品のヒントになれば幸いです。今後も精進して次は非接触ジェスチャー入力等々・・・・で、この共有の場が続くことを期待しています。 【参考にさせていただいた資料です。感謝いたします。】 [M5StickCでBluetooth keyboardを実装してプレゼン用リモコンを作る](https://lang-ship.com/blog/work/m5stickc-bluetooth-keyboard/) [M5StickCで振動を測定する](http://pages.switch-science.com/letsiot/vibration/index.html) [Arduino(M5StickC)でefont Unicodeフォント表示 完結編](https://lang-ship.com/blog/work/arduino-m5stickc-efont-unicode/) [M5StickC非公式日本語リファレンス タッチセンサー](https://lang-ship.com/reference/unofficial/M5StickC/Peripherals/TouchSensor/) ```arduino:コントローラー #include <BleConnectionStatus.h> #include <BleKeyboard.h> #include <KeyboardOutputCallbacks.h> #include <M5StickC.h> #include <efontEnableJaMini.h> // 第2水準相当の日本語フォントを読み込み 4千文字139KB #include <efont.h> // 実際のフォントデータの読み込み #include "efontM5StickC.h" // efontテキスト描画関数 BleKeyboard bleKeyboard; float accX=0 , accY=0 , accZ=0 ; float accXX=0 , accYY=0 , accZZ=0 ; int dX=0 , dY=0 , dZ=0 ; int dXYZ = 0 ; int n = 0 ; int f = 0 ; //MODE frame数列 int PSD[30] = {10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10};//ΔXYZmax数列 n=30 int PSDS =300 ; //hovering スタートでhovering設定 int HADS = 0 ; //スタートで正面設定 int MPSDS4 = 6200; //climb      感度高閾値:default  int MPSDS3 = 2500; //cruise     感度高閾値:default int MPSDS2 = 300 ; //cruiseslow  感度高閾値:default int MPSDS1 = 200 ; //hover 感度高閾値:default int MODE[10] = {1,1,1,1,1,1,1,1,1,1} ; //FamecheckRingBuffer init:MODE=1 Hover int MODEN = 1 ; //0:descent(下降) 1:hover(ホバリング) 2:cruiseslow(前進)3:cruise(前進) 4:climb(上昇) int meflg = 1 ; //MODEFrame Equal FLG 1:YES 0:NO int M2st = 1 ; //MODE2 state 0:MO 1:M1 2:M2 3:M3 4:M4 5:UP 6:LR int M0flg = 1; //1:M0 0:other int RANGh = -80, RANG = -80; //Rightangle:感度H閾値:default int LANGh = 110, LANG = 110; //Leftangle:感度H閾値:default int bta = 0 ; //bt active flag 送信:1 停止:0 int BTBLK = 0 ; //bt 未接続Blink counter every1sec int WKBY = 1 ; //前進感度 walking:0 bicycle:1~3 1高 2中 3低 int WKLR = 1 ; //左右感度 walking:0 bicycle:1~3 1高 2中 3低 int tchswth = 10; //TouchSWthreshold 感度設定 高:数字大 低:数字小 G32:L G33:R int acc ; //Serialモニタ 加速度整数 void setup() { pinMode(10,OUTPUT); //LED PORT OUT M5.begin(); M5.Lcd.setRotation(3); //3~1逆さま M5.Lcd.fillScreen(BLUE); M5.Lcd.setTextSize(2); M5.MPU6886.Init(); bleKeyboard.begin(); Serial.begin(115200); } //********************************************************LOOP*********************************************************************** void loop() { if(bleKeyboard.isConnected()) { // BT connect ? YESならば ボタン有効 表示開始 //*************************************************【Ble connected BOX alive】**************************************** M5.update(); //key refresh if ( M5.BtnA.wasPressed() ) { //start key? if (bta == 0 ) {bta = 1 ; delay(1000);} else {bta = 0 ;} //スタートの時SWを押す振動誤動作を避けるwait(1000) } if (bta == 0 ) { //******************************【Standby(スタート画面)】****************************************** bleKeyboard.releaseAll() ; //【重要 動作時以外は必ずStandBy(スタート画面)にしてBle出力OFF 重要】 【】 Stby() ; //standby & set sensitivity LCDstby() ; } else { //************************************【START】*************************************************** SpdCal() ; //SpeedCalculation  XYZ軸で出力の大きい軸の加速度の差分積算  //****Debug コメントを外すとモニタ表示(115200bps)************************* // acc=accY*1000 ; Serial.println(acc); //加速度表示 //Serial.print(PSDS);//差分積算計算値表示 Setthrhys() ;//Set threshold hysteresis 差分積算値からthresholdで速度判別  閾値(thresold)にヒステリシス( hysteresis)を付ける Frmchk() ; //Frame check :3frame一致で速度切り替え //touch(); //**タッチスSWを使うときコメントを外す** ハンドルが動かせない場合optionタッチSWで左右に動かすことが出来ます G32:左方向 G33:右方向 BleTR() ; //Bluetooth transmit 速度 および向きに応じBluetoothでキー操作送信 LCDmain() ; //MainLCD画面 } //************************************【START END】*********************************************** } else {LCDbtunconnct(); } //BT未接続表示 } //*********************************************************【LOOP END】******************************************************************** // standby************************水平位置調整 前まわし角度感度設定 WKBY 0:前向きwaiking 1:上向き感度Low 2:内向き感度Mid 3:手前向き感度High************** void Stby() { M5.update(); //key refresh M5.MPU6886.getAccelData(&accX,&accY,&accZ); //get XYZ加速度 if (M5.BtnB.isPressed() ) { //右ボタン押している間設定変更 離すと決定 //******Walking/Bicycle 傾きaccXより設定****************** if (accX * 1000 > 500) WKBY = 0 ; //前向き walking:0 (1000~500) else if (accX * 1000 > -250 ) WKBY = 1 ; //上向き bicycle:1 (-250~500) 感度高:default    else if (accX * 1000 > -450 ) WKBY = 2 ; //手前45度 bicycle:2 (-450~-250) 感度中   else WKBY = 3 ; //手前90度 bicycle:3 ( <-450) 感度低   //******左右感度 傾きaccYより設定  if (accX * 1000 > 500 ) WKLR = 0 ; //前向き walking:0         else if (accY * 1000 > -390 ) WKLR = 1 ; //水平  感度高:default    else if (accY * 1000 > -660) WKLR = 2 ; //右30度 感度中   else WKLR = 3 ; //右60度 感度低 } } //SpeedCalculation**********************************************X軸加速度 差分積算して速度判別***************************************************************************** void SpdCal() { M5.MPU6886.getAccelData(&accX,&accY,&accZ); //getXYZ加速度データー //***急ハンドル検出**** if (( MODE[0] != 0 )||( abs(accY - accYY) * 1000 < 80)) { ; //MODE[0]の時急ハンドル spike noise検出したらPass //*** 差分積算計算=Σ❘ΔXYZmax❘ n=30 ********************************* n = n + 1 ; if (n > 29) n = 0 ; //n回のSUMを計算 dX=abs(accX-accXX)*1000 ; dY=abs(accY-accYY)*1000 ; dZ=abs(accZ-accZZ)*1000 ; //ΔX、ΔY、ΔZを計算して比較 Max軸をcheck accXX = accX ; accYY = accY ; accZZ = accZ ; //次の差分比較に為save if (dX > dY) { if (dX > dZ) PSD[n]=dX;} else if (dY > dZ) PSD[n]=dY; else PSD[n]=dZ; //ΔXYZ軸のmax軸に切り替える/sample if (PSD[n]< 30) PSD[n]=0 ; //細かい振動ノイズ除去 PSDS = 0; //init for (int i = 0; i < 30 ; i++) //n個の差分を合計 { PSDS = PSDS + PSD[i]; } //PSD積算 } } void Setthrhys() { switch(WKBY) { //WKBY前進判別閾値設定 0waiking 1感度高 2感度中 3感度低 case 0 : walking(); break; case 1 : bicycle1(); break;//default case 2 : bicycle2(); break; case 3 : bicycle3(); break; default : break; } switch(WKLR) { //WKLR左右判別閾値設定 0waiking感度高 1感度高 2感度中 3感度低 case 0 :RANG = RANGh ; LANG = LANGh; break; case 1 :RANG = RANGh ; LANG = LANGh; break; //default case 2 :RANG = RANGh-30;LANG = LANGh+30; break; case 3 :RANG = RANGh-60;LANG = LANGh+60; break; default : break; } } void Frmchk() { f = f + 1 ; if ( f > 5 ) f=1 ; //3frame check set (f0:現MODE) f1⇒f2⇒f3⇒f4 (f3: f>4 ) MODE[f] = MODEN ; //MODENew FrameRingBufferSave meflg = 1 ; //MODEEqual FLG = 1 (一致) for (int i=2; i<5; i++ ) //3frame check (f0:現MODE[0]) f1:新MODE[1]=f2⇒f3⇒f4 { if (MODE[i] != MODE[1]) meflg = 0 ; //Frame check NO:meflg=0 } if (meflg != 0 ) MODE[0]=MODE[1]; //3Frame YES でMODEN⇒現MODESave if (MODE[0] != 2) M2st = MODE[0]; } void BleTR() { if (MODE[0] == 0) {rALT(); rU(); pLRrLR(); LED(); //descent foward } else if (MODE[0] == 1) {rALT(); rPDrPUrU(); pLRrLR(); //hover } else if (MODE[0] == 2) {M2LK(); //cruiseslow } else if (MODE[0] == 3) {rALT(); rPDrPUpU(); pLRrLR(); //cruise } else {rALT(); pPDrPUrU(); rLR(); //climb 上昇中はLR受け付けない 安定 } } //*******************感度イベントごとの速度判別閾値 ヒステリシス設定****************************** void walking() { //walking sky/land if (PSDS > (MPSDS4 +3500 +MODE[0]*300)) {MODEN = 4 ; //climb /backward } else if (PSDS > (MPSDS3+1000 - MODE[0]*400)) {MODEN = 3 ; //cruise /forward } else if (PSDS > (MPSDS2+400 - MODE[0]*100)) {MODEN = 2 ; //cruiseslow /forward } else if (PSDS > (MPSDS1+200 -MODE[0]*50 )) {MODEN = 1 ; //hover /stop } else {MODEN = 0 ; //descent /AUTUDrive } } void bicycle1() { //高 sky/land if (PSDS/WKBY > (MPSDS4 + MODE[0]*100) ) {MODEN = 4 ; //climb /backward } else if (PSDS > (MPSDS3 - MODE[0]*400) ) {MODEN = 3 ; //cruise /forward } else if (PSDS > (MPSDS2 - MODE[0]*100) ) {MODEN = 2 ; //cruiseslow /fowardslow } else if (PSDS > (MPSDS1 - MODE[0]*50) ) {MODEN = 1 ; //Hover /stop   } else {MODEN = 0 ; //descent /AUTODrive } } void bicycle2() { //中 sky/land if (PSDS > (MPSDS4 +900 + MODE[0]*200) ) {MODEN = 4 ; //climb /backward } else if (PSDS > (MPSDS3+800-MODE[0]*500) ) {MODEN = 3 ; //cruise /forward } else if (PSDS > (MPSDS2+200-MODE[0]*120) ) {MODEN = 2 ; //cruiseslow /fowardslow } else if (PSDS > (MPSDS1+10-MODE[0]*60) ) {MODEN = 1 ; //Hover /stop   } else {MODEN = 0 ; //descent /AUTODrive } } void bicycle3() { //低 sky/land if (PSDS > (MPSDS4 + 1800 + MODE[0]*400 )) {MODEN = 4 ; //climb /backward } else if (PSDS > (MPSDS3+1600 - MODE[0]*600)) {MODEN = 3 ; //cruise /forward } else if (PSDS > (MPSDS2+400 - MODE[0]*140)) {MODEN = 2 ; //cruiseslow /fowardslow } else if (PSDS > (MPSDS1+20 - MODE[0]*70)) {MODEN = 1 ; //Hover /stop } else {MODEN = 0 ; //descent /Autodrive  } } void pPDrPUrU() { bleKeyboard.release(KEY_PAGE_UP); delay(10); //降下OFF bleKeyboard.release(KEY_UP_ARROW); delay(10); //前進OFF   bleKeyboard.press(KEY_PAGE_DOWN); delay(10); //上昇ON } void rPDrPUpU() { bleKeyboard.release(KEY_PAGE_UP); delay(10); //降下OFF   bleKeyboard.release(KEY_PAGE_DOWN); delay(10); //上昇OFF bleKeyboard.press(KEY_UP_ARROW) ; delay(10); //前進ON } void rPDrPUrU() { //hover bleKeyboard.release(KEY_PAGE_UP); delay(10); //降下OFF   bleKeyboard.release(KEY_PAGE_DOWN); delay(10); //上昇OFF bleKeyboard.release(KEY_UP_ARROW); delay(10); //前進OFF HOVERING } void rPDrU() { bleKeyboard.release(KEY_UP_ARROW); delay(10); //前進OFF descend landing } //**************Lock encounter****************************** void M2LK() { switch(M2st) { case 0: rU();pALT();pU();M2st=5;break; //UP slow 一度UP停止rUしないとALT効かずslowにならない case 1: rU();pALT();pU();M2st=5;break; //UP slow 一度UP停止rUしないとALT効かずslowにならない case 2: rU();pALT();pU();M2st=5;break; //M2st =MODE[0](2以外)なのでこないはず case 3: rU();pALT();pU();M2st=5;break; //UP slow 一度UP停止rUしないとALT効かずslowにならない case 4: rU();pALT();pU();M2st=5;break; //UP slow 一度UP停止rUしないとALT効かずslowにならない case 5: cas5(); break; //UPslow to LRslow:Lock encounter case 6: cas6(); break; //LRslow to UPslow:Lock encounter default: break; } } void rALL() {bleKeyboard.releaseAll();delay(10);} void rALT() {bleKeyboard.release(KEY_LEFT_ALT);delay(10);} void pALT() {bleKeyboard.press(KEY_LEFT_ALT);delay(10);} void rU() {bleKeyboard.release(KEY_UP_ARROW);delay(10); } void pU() {bleKeyboard.press(KEY_UP_ARROW);delay(10);} void cas5() { if ((accY*1000 < RANG)||(accY*1000 > LANG)) {rU();pLR();M2st=6;} else {M2st = 6;} } void cas6() { if ((accY*1000 < LANG)&&(accY*1000 > RANG)) {rLR();pU();M2st=5;} else {M2st = 5;} } void rLR() { //上昇中左右キー受け付けない bleKeyboard.release(KEY_LEFT_ARROW); delay(10); bleKeyboard.release(KEY_RIGHT_ARROW); delay(10); } void pLR() { if (accY*1000 > LANG) {bleKeyboard.press(KEY_LEFT_ARROW);delay(10); } if (accY*1000 < RANG) {bleKeyboard.press(KEY_RIGHT_ARROW);delay(10); } } void pLRrLR() { // descent if (accY * 1000 < RANG ) { // RIGHT~-100 bleKeyboard.press(KEY_RIGHT_ARROW); delay(10); // 右旋回 SHIFT+RIGHT 誤動作するので右移動 bleKeyboard.release(KEY_PAGE_UP); delay(10); M0flg = 0; } else { if (accY * 1000 < LANG ) { // MODE0ではゆっくり下降 if (MODE[0] == 0) { if (M0flg ==0 ) { bleKeyboard.press(KEY_PAGE_UP);delay(10);M0flg=1;} } else {if (M0flg == 1) {bleKeyboard.release(KEY_PAGE_UP);delay(2000);M0flg=0;} else {delay(10);} } rLR(); //LROFFする前にUPonしてfowardのdelayを対策 } else { //LEFT (200~ bleKeyboard.press(KEY_LEFT_ARROW); delay(10); //??********************Map writeNG Earth press(KEY_LEFT_ARROW); bleKeyboard.release(KEY_PAGE_UP); delay(10); M0flg=0; } //LEFT移動end } //正面 LEFT end } void LED() { digitalWrite(10, LOW); //LandingLED ON delay(10); //LED Blink   digitalWrite(10, HIGH); //LandingLED OFF } void touch() { //ハンドルが回らないとき左右タッチスイッチを付ける if (touchRead(32) < tchswth) accY = -0.2 ; //dummyY加速度:L groveG32:Lスイッチ if (touchRead(33) < tchswth) accY = 0.2 ; //dummyY加速尾:R groveG33:Rスイッチ } void LCDstby() { //******BT connected スタートSTNDBY画面******** //M5.Lcd.fillScreen(BLUE); // Flicker 画面をクリア M5.Lcd.setTextSize(1); M5.Lcd.setTextColor(WHITE, BLUE); // 赤(背景色グレー) if (WKBY == 0 ) {M5.Lcd.setRotation(1); printEfont("요ウォーキング요요", 0, 16*0); } else if (WKBY == 1) {M5.Lcd.setRotation(3); printEfont("前進感度요高(回転)", 0 ,16*0); //default } else if (WKBY == 2) {M5.Lcd.setRotation(3); printEfont("前進感度요中(回転)", 0 ,16*0); } else if (WKBY == 3) {M5.Lcd.setRotation(3); printEfont("前進感度요低(回転)", 0 ,16*0); } if (WKLR == 0 ) {M5.Lcd.setRotation(1); printEfont("요요요요요요요요요요",0,16*1); } else if (WKLR == 1) {M5.Lcd.setRotation(3); printEfont("左右感度요高(傾斜)", 0 ,16*1); //default } else if (WKLR == 2) {M5.Lcd.setRotation(3); printEfont("左右感度요中(傾斜)", 0 ,16*1); } else if (WKLR == 3) {M5.Lcd.setRotation(3); printEfont("左右感度요低(傾斜)", 0 ,16*1); } M5.Lcd.setTextSize(2); M5.Lcd.setTextColor(GREEN, BLUE); // 赤(背景色グレー) printEfont("スタート", 15, 16*2); printEfont("요요요요요요요요요요",0,16*4); digitalWrite(10, HIGH); //BT接続後LED OFF } void LCDbtunconnct() { //******* BT not conncted 画面****************** //M5.Lcd.fillScreen(BLUE); // 画面をクリア flicker M5.Lcd.setTextSize(2); M5.Lcd.setTextColor(WHITE, BLUE); // 赤(背景色グレー) printEfont("どこでも요", 0, 16*0); printEfont("요요ドア세", 0, 16*2); M5.Lcd.setTextSize(1); //(1); M5.Lcd.setTextColor(RED, BLUE); // 赤(背景色グレー) printEfont("BT設定してください", 5, 16*4); if (BTBLK > 100) {LED(); BTBLK = 0;} else { BTBLK++; } } void LCDmain() { if (WKBY == 0) { M5.Lcd.fillScreen(BLUE); //walking画面(万歩計予定) M5.Lcd.setTextSize(1); M5.Lcd.setTextColor(WHITE,BLUE); printEfont("万歩計", 55,16*0); M5.Lcd.setTextSize(3); printEfont("----", 30,16*1); } else { M5.Lcd.fillScreen(BLUE); //Bike走行画面 M5.Lcd.fillRect(75,70-PSDS/(30*WKBY),10,PSDS/(30*WKBY), WHITE); if (accY*1000 > LANG) { M5.Lcd.fillTriangle(15, 60, 45, 50, 45, 70,WHITE); M5.Lcd.drawTriangle(145, 60, 115, 50, 115, 70,WHITE); } else if (accY*1000 > RANG) { M5.Lcd.drawTriangle(15,60,45,50,45,70,WHITE); M5.Lcd.drawTriangle(145,60,115,50,115,70,WHITE); } else { M5.Lcd.drawTriangle(15, 60, 45, 50, 45, 70,WHITE); M5.Lcd.fillTriangle(145, 60, 115, 50, 115, 70,WHITE); } } } //********************************************************************************************************************************** ```