syouwa-taro が 2021年11月15日13時11分05秒 に編集
初版
タイトルの変更
ドップラレーダーとサーモセンサによる非接触万歩計およびGoogleEarthProコントローラー
タグの変更
M5StickC
thermopilearray
dopplerradar
万歩計
ジェスチャー入力
フィットネスバイク
車いす
GoogleEarthPro
Arduino
メイン画像の変更
本文の変更
### 概要 Doppler Radar(RCWL_0516) と Thermopilearray(AMG8833)を使い、人の足踏みの動きを非接触で計測し歩数表示する万歩計、及び動きに同期してGoogleEarthProの映像を移動するキーコードを送信(bluetooth)し足踏みしながら世界を観光。部屋の中で世界観光しながら歩数を見て有酸素運動が出来る ジェスチャー入力GoogleEarthコントローラーを作った。 応用としてフィットネスバイクの前に置くと、ペダル回転数を歩数として計測しGoogleTourが楽しめ、また車いすでも、腕の振りだけでも振りを歩数として計測するのでGoogleTourが楽しめる。 @[youtube](https://www.youtube.com/watch?v=HHg73FhsfJE) ### 動作原理 ![キャプションを入力できます](https://camo.elchika.com/8335350793d1a802ba4469ab7e31c292c0c7a4fe/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f65373839373266382d396462352d343035612d623036362d633930633639646435353362/) **歩行速度はdoppler radar(PCWL_0516)で検出** radar出力波形sample値の差分を積算し積算値から歩行速度を分類しGoogleの画像を移動させる速度のキーコードを送信(bluetooth)し、あたかも画像の中を歩行速度に合わせ歩いているようにコントロールする。(静止:【PgUp】下降 ゆっくり:【Alt+↑】ゆっくり前進 通常【↑】早い前進 全速:【PgDn】上昇) radarに指向性をつけようとホーンを作ったが、まだ検討中。 **radarによる足踏み速度に応じ得られる出力波形例**![RCWL出力 vs 歩行速度](https://camo.elchika.com/487ad35d2a0f134dd71c7a0db5126c32edb7fb49/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f30633832616264662d653464652d343364332d623564642d366333376165663536353533/) **左右向き 歩行数はサーモセンサ(AMG8833)で検出** 温度は8X8で計測され、主に顔の位置から左 正面 右を判別しあたかも画像の中を自分の方向に合わせ歩いているようにコントロールする。(右:【→】右移動 左:【←】左移動) 歩行数は腕の温度変化の差分を積算し一周期を1歩とし万歩計表示する。 **サーモセンサによる歩行姿勢の8X8温度計測例**![8X8で計測される歩行姿勢の表示例](https://camo.elchika.com/14af71085386392a6d2c92071f2bfe95e1a814f1/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f38303263376231662d646136632d343063632d616635362d653261656430386135393636/) ### 使い方 ![キャプションを入力できます](https://camo.elchika.com/e255abcb0387f365cac33d2fdd531acdf3939e87/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f65656361333538632d356638622d346134612d613031312d383538623166656336393666/) ### 材料 | 部品 | 備考 | |:---:|:---:| |M5stickC | [コントローラー](https://www.switch-science.com/catalog/6350/) https://www.switch-science.com/catalog/6350/ | |RCWL_0516| DopplerRadar amazon ¥200~¥300| |AMG8833| [サーモグラフィー](https://www.switch-science.com/catalog/3395/) https://www.switch-science.com/catalog/3395/ | ### 回路図 ![ジェスチャー入力GoogleEarthコントローラー](https://camo.elchika.com/4433927b18c55b8cbb64a99a0260ce380eafd473/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f36653432353163622d343436392d343764622d613831622d356130313265653666623838/) **回路はM5stickCのGroveポートと2つのデバイスをつなぐだけでシンプルであるが注意点がいくつかある** ①RCWL出力は基板OUTからとるのでなく、中のIC(rcwl_9196)12pinからdoppler波形をとる。 ②Contaサーモグラフィーの$I^2C$ スレーブアドレスは”69H"にソルダージャンパーで設定(defaultは”68H")(また$I^2C$プルアップ抵抗が必要と書いてあるが、Groveポート側についているようで無しでも動いた?) ![①rcwl_9196 12pin](https://camo.elchika.com/ef2510ed619b4a6ee427c88eb0c8c768669b9229/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f32316264376363322d386566342d346234342d626439352d356261623338626261666564/) ### ソースコード ```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; #include <Wire.h> #define AMG88_ADDR 0x69 // 68H:LOW default 69H:HIGH 68Hはほかで使われているので69Hで使う #define PCTL 0x00 #define RST 0x01 #define FPSC 0x02 #define INTC 0x03 #define STAT 0x04 #define SCLR 0x05 #define AVE 0x07 #define INTHL 0x08 #define TTHL 0x0E #define INT0 0x10 #define T01L 0x80 int radarX,radarXX,difradar ; int n = 0 ; //0 1 2 3 4 5 PSD[n]6回積算数列 int f = 0 ; //MODE frame数列 int PSD[30] = {2000,2000,2000,2000,2000, 2000,5,5,5,5, 5,5,5,5,5, 5,5,5,5,5, 5,5,5,5,5, 5,5,5,5,5 } ; //∑6回=12000:hover int PSDS = 12000; //radar hover init int HADS = 0 ; //iimax変化 0~63 imaxLR 6 7 で左右最大変化 int MPSDS4 = 46000; //6loop46000閾値 上昇しすぎ防止のためヒステリシスつけない 上昇 MODE4 int MPSDS3 = 30000; //6loop30000-3000X2=24000閾値 30000-3000X3=21000ヒステリシス 速足 MODE3 int MPSDS2 = 19000; //6loop19000-3000X1=16000閾値 19000-3000X2=13000ヒステリシス ゆっくり MODE2 int MPSDS1 = 7000; //6loop7000-400X0=7000閾値 7000-400X1 = 6600ヒステリシス hover min MODE1 int MPSDS0 = 0 ; // 0 停止で下降 MODE0 int MODE[10] = {1,1,1,1,1,1,1,1,1,1} ; //1:hover MODE数列 [5]で4framecheck MPSDS1にかぶる MODE[0]:動作中 MODE[1~4]:NewFamecheckRingBuffer int MODEN = 1 ; //NewFrameMODE 0:descent 1:hover 2:cruise 3:fast 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 bta = 0 ; //bt active flag 送信:1 停止:0 int BTBLK = 0 ; //bt 未接続Blink counter every1sec int TMPDAT0[64] ; //温度データー64個所XBuffer1層 int TMPDATmax = 0 ,TMPDATs = 0 ; //TMPDATss = 0,TMPDATsss = 0; int imax = 0 ,imaxx=0 , imaxLR = 3 ; //imax:Therm max pos(0~63上下逆) imaxLR:therm horizont max pos 0~2:L 3 4:front 5~7:R int CNT = 0 , CNTF = -1; //万歩計 void setup() { pinMode(10,OUTPUT); //LED PORT OUT pinMode(36,ANALOG); //radarIN G36:HOTport M5.begin(); M5.Lcd.setRotation(3); M5.Lcd.fillScreen(BLUE); M5.Lcd.setTextSize(2); bleKeyboard.begin(); M5.begin(); Serial.begin(115200); pinMode(0, INPUT_PULLUP); pinMode(26, INPUT_PULLUP); Wire.begin(0,26); //pin SCL:G26 SDA:G0 address68HはほかIMUで使われているので69Hで使う write8(AMG88_ADDR, FPSC, 0x00); // 10fps write8(AMG88_ADDR, INTC, 0x00); // INT出力無効 write8(AMG88_ADDR, 0x1F, 0x50); // 移動平均出力モード有効 write8(AMG88_ADDR, 0x1F, 0x45); write8(AMG88_ADDR, 0x1F, 0x57); write8(AMG88_ADDR, AVE, 0x20); write8(AMG88_ADDR, 0x1F, 0x00); } void loop() { if(bleKeyboard.isConnected()) { // BT connected ? YESならば ボタン有効 表示開始 // ボタン状態更新RIGHT_SHIFT); M5.update(); // Key refresh if ( M5.BtnA.wasPressed() ) { if (bta == 0 ) {bta = 1 ; CNT = 0 ; delay(2000); //スタート、歩数計reset SWを押す振動誤動作をwait 避ける PSD[0]=2000;PSD[1]=2000;PSD[2]=2000;PSD[3]=2000;PSD[4]=2000;PSD[5]=2000;PSDS=12000;MODE[0]=1;MODE[1]=1;MODE[2]=1;MODE[3]=1;MODE[4]=1; } else {bta = 0 ;} //Standby } //*******************AMG8833Data処理 Radar MODE **************************** if (bta >= 1 ) { //スタートキーON Main loop HADSDAT(); //AMG8833 顔の位置(向き) 腕振り周期 判別 PSDSDAT(); //PCWL_0516 radar歩行計測 walking(); //動き判別 BLE controll out //*************MODE Frame Check****************** f = f + 1 ; if ( f > 5 ) f=1 ; //速足なりやすいPSDS1300n15 4 3frame check (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++ ) //速足なりやすいPSDS1500n15NewMode4 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]; //4Frame YES でMODEN⇒現MODESave if (MODE[0] != 2) M2st = MODE[0]; //M2最初先回MODE[0]⇒M2stそのままM2stで分岐 その後MODE[0]=2なのでM2stはいじられず内部state UPを停止しないとSlowにならない //***************MODE[0]Bluetooth送信 ************************ if (MODE[0] == 0) {rALT(); rU(); pLRrLR(); LED(); //descent foward PULock対策左右ON後一旦rPU 左右OFF前にpPU:左右⇒foward 直進で間が開く対策 } else if (MODE[0] == 1) {delay(200); rALT(); rPDrPUrU(); pLRrLR(); // hover descendでstreetview切り替わり:地上直前で信号OFF delay(200) } else if (MODE[0] == 2) {M2LK(); // cruiseslow } else if (MODE[0] == 3) {rALT(); rPDrPUpU(); pLRrLR(); // cruise } else {rALT(); pPDrPUrU(); rLR(); // climb 上昇中はLR受け付けない 安定 } //*************************MainLCD*************************************************************** M5.Lcd.fillScreen(BLUE); M5.Lcd.setTextSize(5); M5.Lcd.setTextColor(WHITE,BLUE); if (CNT > 999 ) M5.Lcd.setCursor(30,13); else if (CNT > 99) M5.Lcd.setCursor(45,13); else if (CNT > 9) M5.Lcd.setCursor(50,13); else M5.Lcd.setCursor(65,13); M5.Lcd.print(CNT); //M5.Lcd.fillScreen(BLUE); M5.Lcd.setTextSize(1); printEfont("万歩計", 56,16*4); //horizon56 vertical 16*4 if (imaxLR < 3) { // (0 1 2 :LEFT) M5.Lcd.fillTriangle(15, 60, 45, 50, 45, 70,WHITE); //◀ ▷ M5.Lcd.drawTriangle(145, 60, 115, 50, 115, 70,WHITE); } else if (imaxLR < 5) { //(3 4 :front) M5.Lcd.drawTriangle(15,60,45,50,45,70,WHITE); //M5.Lcd.drawTriangle(15, 60, 45, 50, 45, 70,WHITE); M5.Lcd.drawTriangle(145,60,115,50,115,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);//◁ ▶ } //*************************Standby ************************************************************ } else { //ble standby active end bleKeyboard.releaseAll() ; //ble active end if ( M5.BtnB.wasPressed() ) { //右ボタンで視野を水平 bleKeyboard.press(KEY_LEFT_SHIFT); delay(10); bleKeyboard.press(KEY_DOWN_ARROW); delay(100); //press+delay だと受け付ける 500ms 200ms 100msおおきい 30msOKたまに飛ぶ bleKeyboard.release(KEY_UP_ARROW); delay(10); //else ではおしつずけても動かず bleKeyboard.release(KEY_LEFT_SHIFT); } // key end 水平視野 //******BT connected スタートSTNDBY画面******** //M5.Lcd.fillScreen(BLUE); // Flicker 画面をクリア M5.Lcd.setTextSize(1); M5.Lcd.setTextColor(WHITE, BLUE); // 赤(背景色グレー) M5.Lcd.setRotation(3); printEfont("下のボタンで水平調整", 0 ,16*0); printEfont("요요요요요요요요요요",0,16*1); M5.Lcd.setTextSize(2); //(1); M5.Lcd.setTextColor(GREEN, BLUE); // 赤(背景色グレー) printEfont("スタート", 15, 16*2); printEfont("요요요요요요요요요요",0,16*4); digitalWrite(10, HIGH); //BT接続後LED OFF } //bla=0 standby end } else { //ble connected end unconnected //*******powon BT not conncted 画面****************** //M5.Lcd.fillScreen(BLUE); //画面クリア M5.Lcd.setTextSize(2); //(1); 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++; } //BT未接続LEDBlink } //ble unconnected end } //loop end //**************************************************************************** //**************************************************************************** void HADSDAT() { //AMG8833 顔の位置(向き) 腕振り周期 判別 int sensorData[128]; //2byte per one data dataread(AMG88_ADDR, T01L, sensorData, 128); //ADDress 0x68:LOW 0x69:highSCL:G26 SDA:G0 address68Hはほかで使われているので69Hで使う TMPDATmax = 0 ; imax = 0 ; TMPDATs = 0; //init for (int i = 0 ; i < 64 ; i++) { int16_t temporaryData = sensorData[i * 2 + 1] * 256 + sensorData[i * 2]; if (abs( TMPDAT0[i] - temporaryData) > 4) { //>3 noise swing searching if ((i%8 > imaxLR+1)&&(i < (imaxx+4))) { //右腕:上下逆なのでiが少ないほうが顔から下 顔右腕振り”+4” TMPDATs = TMPDATs + (temporaryData - TMPDAT0[i]); //*(i / 8); 右側腕振りすべて差分積算 } //i pos 前frameとの温度差積算 if ((i%8 < imaxLR-1)&&(i < (imaxx-1))) { //上下逆なのでiが少ないほうが顔から下 顔左腕振り”^-1”まで積算 TMPDATs = TMPDATs - (temporaryData - TMPDAT0[i] ); //*(i / 8); 左側腕振り”マイナス”差分すべて積算 } } //noise end if (temporaryData > TMPDATmax) {TMPDATmax = temporaryData ; imax = i ;} //現frame max:face searching TMPDAT0[i] = temporaryData ; //現frame data save } //frame end if ((TMPDATs > 0)&&(CNTF < 0)) {CNTF = 1; CNT++ ;} //万歩計カウントアップ if ((TMPDATs <= 0)&&(CNTF >= 0)) {CNTF = -1;} HADS = abs(imax - imaxx); //HADS =abs(imax - imaxx);(MODE[0]の時)急ハンドル検出radar誤動作 imaxx = imax; imaxLR = imaxx % 8; //次のframe の顔位置 【現framedataではsearching中誤動作)LR判別 i%8 = 0 1 2:L 3 4:front 5 6 7:R } void PSDSDAT() { //PCWL_0516 radar歩行計測 PSDS PedalSpeed Difference Sum if (HADS<7) { //i pos 0~63 上下左右移動中 1 ~7 8以上速度値異常で積算PASS 方向変換中=PSD[n]入力 積算はお休み PSDS=前LOOP値 n = n + 1 ; if (n > 5) n = 0 ; //300X6=1.8sec n回のradar差分SUMを計算 /100で停止ノイズキャンセル その後更に6回のリングSUMしてfoward動き判別 PSD[n] = 0 ; radarXX = analogRead(36); //最初の差分のダミー for (int m = 0; m < 20 ; m++) //sample周期20ms(delay10)X20回のほうが30よりバラツキがすくなそう・・ { radarX = analogRead(36); // 30noise peak count if ((radarX-radarXX) != 0) {difradar = abs(radarX-radarXX) ; } //radar clipのとき直前差分を代入 PSD[n] = PSD[n] + difradar ; radarXX = radarX; delay(10); } if (PSD[n] > 10000 ) { PSD[n]=10000 ;} //異常値10000以上 ほぼmax10000 limmiter PSDS = 0; //init for (int i = 0; i < 6 ; i++) //1loop:300ms X 6loop =1,8sec のdelay { PSDS = PSDS + PSD[i]; } //PSD積算 } //急ハンドルない時だけ∑PSD[n」=PSDS計算 } //PSDS END //*******************Loop毎にNewMODE(before Framecheck)決定 MODE切り替えthreshiholdでHysterysisをつける****************************** void walking() { //radar差分積値から新MODEN判定 if (PSDS > (MPSDS4 - MODE[0]*2 )) {MODEN = 4 ; //climb } else if (PSDS > (MPSDS3 - MODE[0]*3000)) {MODEN = 3 ; //cycling forward } else if (PSDS > (MPSDS2 - MODE[0]*3000)) {MODEN = 2 ; //cruiseslow } else if (PSDS > (MPSDS1 - MODE[0]*400)) {MODEN = 1 ; //hoverはhysterisis400 MODE0入りやすく出にくく } else {MODEN = 0 ; //descend } } void pPDrPUrU() { //if ( PSDS >= 1400 ) { //climb下限 n=15 1000:左右エラー減らすと1400 1200:たまに上昇 700:ときどき上昇 n=10 1400 n=20 3500 上昇 bleKeyboard.release(KEY_PAGE_UP); delay(10); //降下OFF bleKeyboard.release(KEY_UP_ARROW); delay(10); //前進OFF releaseAll() ; delay(30); bleKeyboard.press(KEY_PAGE_DOWN); delay(10); //上昇ON } void rPDrPUpU() { //PSDS > 400 cruise下限 n=15 20 330左右誤動作対策 n=15 300 n=10 400 n=20 800 前進 bleKeyboard.release(KEY_PAGE_UP); delay(10); //降下OFF bleKeyboard.release(KEY_PAGE_DOWN); delay(10); //上昇OFF bleKeyboard.press(KEY_UP_ARROW) ; delay(10); //前進ON Map:writeNG earth:press(KEY_UP_ARROW); 前進 } void rPDrPUrU() { //hover // PSDS >= 300 hover下限 n=15 150(limit20) 140 descent/hover130下降し易いn=10 190 n=20 300 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() { // PSDS <250 descend /Byke //上昇 下降んはロック対策で左右送信と併せて行う bleKeyboard.release(KEY_UP_ARROW); delay(10); //前進OFF descend landing //bleKeyboard.release(KEY_DOWN_ARROW) ; //(後進OFF) } //**************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; } } //**************delay encounter****************************** void rALL() {bleKeyboard.releaseAll();delay(1000);} //delay(10);}hover for Landing time 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 ((imaxLR < 3)||(imaxLR > 4)) {rU();pLR();M2st=6;} else {M2st = 6;} } //L||R((T0m1 < RANG)||(T0m1 > LANG)) void cas6() { if ((imaxLR > 2)&&(imaxLR < 5)) {rLR();pU();M2st=5;} else {M2st = 5;} } //Front((T0m1 < LANG)&&(T0m1 > RANG)) void rLR() { //上昇中左右キー受け付けない 上昇中左右キーがあると一旦DOWNrelease bleKeyboard.release(KEY_LEFT_ARROW); delay(10); bleKeyboard.release(KEY_RIGHT_ARROW); delay(10); } void pLR() { if (imaxLR < 3) {bleKeyboard.press(KEY_LEFT_ARROW);delay(10); } //Left (T0m1 > LANG) if (imaxLR > 4) {bleKeyboard.press(KEY_RIGHT_ARROW);delay(10); }//Right (T0m1 < RANG) } void pLRrLR() { //descent if (imaxLR > 4) { //Right imaxLR 5 6 7 //bleKeyboard.release(KEY_PAGE_DOWN); delay(30); bleKeyboard.press(KEY_RIGHT_ARROW); delay(10); //MAP writeNG earth press 右旋回 SHIFT+RIGHT 誤動作するので右移動 bleKeyboard.release(KEY_PAGE_UP); delay(10); M0flg = 0; } else { if (imaxLR > 2) { //Front imaxLR 3 4 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を対策 //if (MODE[0] == 0) {bleKeyboard.press(KEY_PAGE_UP); delay(30);} //(下降中断)対策で左右キーreleasePU frontでpressPU MODE[0]にrealMODEsave } else { //LEFT imaxLR 0 1 2 (200~ //bleKeyboard.releaseAll() ; delay(30) ; //LRの時いったんUP DOWN をrelease UP DOWN ロック対策 //bleKeyboard.release(KEY_PAGE_DOWN); delay(30); 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 上昇中左右キー受けつけないpressで上昇しるとreleaseALLないと上昇はやすぎ (上昇前の行に挿入) } //void descent(){ rPDrU(); pLRrLR(); } //PageUP lock対策で左右キーがあるときrelease PageUpする void LED() { digitalWrite(10, LOW); //LandingLED ON delay(10); //0だとLED光らずNG digitalWrite(10, HIGH); //LandingLED OFF } void write8(int id, int reg, int data) { Wire.beginTransmission(id); Wire.write(reg); Wire.write(data); uint8_t result = Wire.endTransmission(); // Serial.printf("reg: 0x%02x, result: 0x%02x\r\n", reg, result); } void dataread(int id,int reg,int *data,int datasize) { Wire.beginTransmission(id); Wire.write(reg); Wire.endTransmission(); Wire.requestFrom(id, datasize); int i = 0; while (Wire.available() && i < datasize) {data[i++] = Wire.read();} } ``` ### 参考にさせて頂いた資料 [Investigating a RCWL_9196](https://www.rogerclark.net/investigating-a-rcwl-9196-rcwl-0516-radar-motion-detector-modules/) https://www.rogerclark.net/investigating-a-rcwl-9196-rcwl-0516-radar-motion-detector-modules/ [マイクロ波ドップラーセンサを用いた非接触生体計測技術(1)](http://sensait.jp/13037/) http://sensait.jp/13037/ [M5StickCでBluetooth keyboardを実装してプレゼン用リモコンを作る](https://lang-ship.com/blog/work/m5stickc-bluetooth-keyboard/) https://lang-ship.com/blog/work/m5stickc-bluetooth-keyboard/ [M5StickCでI2C通信をする](https://lang-ship.com/blog/work/m5stickc-i2c/) https://lang-ship.com/blog/work/m5stickc-i2c/ [M5StickCのDisplay周り解析 その2]( https://lang-ship.com/blog/work/m5stickc-display2/ ) https://lang-ship.com/blog/work/m5stickc-display2/ **特許** 最近は特許もネット出願できるようになり推進されているようです。検索した限りではこのようなジェスチャー入力類似例は見つからなかったので出願しています。 特願2021-12089 【フィットネストレーニング対応ジェスチャー入力コントローラー】 ### 感想 非接触で見ながら使える万歩計やGoogleコントローラーは、実際に使ってみると家庭で気軽に使え、ゲームなど応用範囲もひろく今後ジェスチャー入力製品が増えてくるのではと感じた。 このレポートでジェスチャー入力に興味を持たれ、応用製品を作る参考となりましたら幸いです。次の目標はカメラ入力による、より細かな動きを非接触で判別し、安価に実現できたらと夢をみています。これらの技術をご教授いただけたら幸いです。 本工作はGUGEN2021に応募しています。是非そちらもご覧ください。[No. GUGEN 2021 -028 どこでも万歩計](https://gugen.jp/subscriptions/work/1062) https://gugen.jp/subscriptions/work/1062