ドップラレーダーとサーモセンサによる非接触万歩計およびGoogleEarthProコントローラー
概要
Doppler Radar(RCWL_0516) と Thermopilearray(AMG8833)を使い、人の足踏みの動きを非接触で計測し歩数表示する万歩計、及び動きに同期してGoogleEarthProの映像を移動するキーコードを送信(bluetooth)し足踏みしながら世界を観光。部屋の中で世界観光しながら歩数を見て有酸素運動が出来る ジェスチャー入力GoogleEarthコントローラーを作った。
応用としてフィットネスバイクの前に置くと、ペダル回転数を歩数として計測しGoogleTourが楽しめ、また車いすでも、腕の振りだけでも振りを歩数として計測するのでGoogleTourが楽しめる。
動作原理
歩行速度はdoppler radar(PCWL_0516)で検出
radar出力波形sample値の差分を積算し積算値から歩行速度を分類しGoogleの画像を移動させる速度のキーコードを送信(bluetooth)し、あたかも画像の中を歩行速度に合わせ歩いているようにコントロールする。(静止:【PgUp】下降 ゆっくり:【Alt+↑】ゆっくり前進 通常【↑】早い前進 全速:【PgDn】上昇)
radarに指向性をつけようとホーンを作ったが、まだ検討中。
radarによる足踏み速度に応じ得られる出力波形例
左右向き 歩行数はサーモセンサ(AMG8833)で検出
温度は8X8で計測され、主に顔の位置から左 正面 右を判別しあたかも画像の中を自分の方向に合わせ歩いているようにコントロールする。(右:【→】右移動 左:【←】左移動)
歩行数は腕の温度変化の差分を積算し一周期を1歩とし万歩計表示する。
サーモセンサによる歩行姿勢の8X8温度計測例
使い方
材料
部品 | 備考 |
---|---|
M5stickC | コントローラー |
RCWL_0516 | DopplerRadar amazon ¥200~¥300 |
AMG8833 | サーモグラフィー |
回路図
回路はM5stickCのGroveポートと2つのデバイスをつなぐだけでシンプルであるが注意点がいくつかある
①RCWL出力は基板OUTからとるのでなく、中のIC(rcwl_9196)12pinからdoppler波形をとる。
②Contaサーモグラフィーの スレーブアドレスは”69H"にソルダージャンパーで設定(defaultは”68H")(またプルアップ抵抗が必要と書いてあるが、Groveポート側についているようで無しでも動いた?)
ソースコード
どこでも万歩計
#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/
マイクロ波ドップラーセンサを用いた非接触生体計測技術(1) http://sensait.jp/13037/
M5StickCでBluetooth keyboardを実装してプレゼン用リモコンを作る https://lang-ship.com/blog/work/m5stickc-bluetooth-keyboard/
M5StickCでI2C通信をする https://lang-ship.com/blog/work/m5stickc-i2c/
M5StickCのDisplay周り解析 その2 https://lang-ship.com/blog/work/m5stickc-display2/
特許
最近は特許もネット出願できるようになり推進されているようです。検索した限りではこのようなジェスチャー入力類似例は見つからなかったので出願しています。
特願2021-12089 【フィットネストレーニング対応ジェスチャー入力コントローラー】
ジェスチャー入力 Google Earth controller
製作品
ジェスチャー入力 GoogleEarthコントローラー
セットアップや使用方法
DopplerRadar Thermal pile arrayにより歩行速度 向きを非接触でセンスし M5stickCでGoogleEarthキー操作に変換しBluetoothで送信し あたかもGoogleEarthの映像の中を歩行するように見せる
感想
非接触で見ながら使える万歩計やGoogleコントローラーは、実際に使ってみると家庭で気軽に使え、ゲームなど応用範囲もひろく今後ジェスチャー入力製品が増えてくるのではと感じた。
このレポートでジェスチャー入力に興味を持たれ、応用製品を作る参考となりましたら幸いです。次の目標はカメラ入力による、より細かな動きを非接触で判別し、安価に実現できたらと夢をみています。これらの技術をご教授いただけたら幸いです。
本工作はGUGEN2021に応募しています。是非そちらもご覧ください。No. GUGEN 2021 -028 どこでも万歩計 https://gugen.jp/subscriptions/work/1062
**重要な注意**
本作品がスタート動作している時 PCに対しBluetoothでキーを送ります。スタート動作のままGoogle画面を閉じると、今度はPCのカーソル キーが勝手に動いてしまいPCのコントロールが効かなくなる事があります。
”Googleの画面を閉じる前に必ず本体を[スタート画面]に戻してから閉じるようにしてください。”
投稿者の人気記事
-
syouwa-taro
さんが
2021/11/15
に
編集
をしました。
(メッセージ: 初版)
-
syouwa-taro
さんが
2021/12/27
に
編集
をしました。
-
syouwa-taro
さんが
2023/11/08
に
編集
をしました。
(メッセージ: 重要な注意 追記)
-
syouwa-taro
さんが
2023/11/26
に
編集
をしました。
ログインしてコメントを投稿する