D.I.Y. アイトラッキング -フォトリフレクタ と Arduino で瞳孔動向センシング-
そろそろハロウィンに向けて準備に取り掛かっておりまして。
去年は家族の半数が体調不良で何もできなかったので今年こそはと気合入っております! 👿
↓一昨年のハロウィンの様子。
ハロウィンへの試作としましてLED目ん玉を本物の目の動きに追従させたら面白いかなと思い、今回はアイトラッキングに挑戦しました!
↓LED目ん玉は3年前のハロウィンのときに作りました。このときは曲げセンサやボリュームで目を動かしました。
目次
LED目ん玉
LEDテープ NeoPixel 68セルをザルに貼り付けて黒く塗って目ん玉にしています。
LEDテープの配置は以下の通りで1筆書きで信号線は1本で制御しています。
センシング – アイトラッキング –
構成
アイトラッキングにはフォトリフレクタ QTR-1A を2個使用しました。
部品
-
Arduino Pro Mini 5V 16MHz
-
Adafruit Pro Trinket バッテリーモジュール
-
リチウムイオンポリマー電池110mAh
- LEDテープ NeoPixel
- フォトリフレクタ QTR-1A
センサ
フォトリフレクタ QTR-1A は目の幅くらいに離してプラ板に配置。
フォトリフレクタ部、マイコン部はそれぞれクリップでメガネに固定しました。
Arduinoコード
黒目が一方のセンサに近づくと反射光が減ってセンサ値が増加し、反対に黒目が遠ざかると反射光が増えてフォトリフレクタのセンサ値が減少する。
LED目ん玉の瞳の左右動作は一方のセンサ値の増減をセンシングして制御しています。
瞬きのときは両方のセンサ値が減少するので、2つのセンサ値が同時に減少するとLED目ん玉のまぶたが下がります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
#include <QTRSensors.h> #include <Adafruit_NeoPixel.h> #define NUM_SENSORS 2 // number of sensors used #define NUM_SAMPLES_PER_SENSOR 10 // average 4 analog samples per sensor reading #define EMITTER_PIN QTR_NO_EMITTER_PIN // emitter is controlled by digital pin 2 int iniSensorValL, sensorValL; int iniSensorValR, sensorValR; #define PIN A3 Adafruit_NeoPixel led = Adafruit_NeoPixel(68, PIN, NEO_GRB + NEO_KHZ800); int blackNum = 24; int pupilNum = 12; uint32_t color; int brightness = 40; byte eyeColor; int LR =7; boolean lid = false; int cnt = 0; //Black eye L&R animation int blackLED[15][24] = {{12,32,35,55,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68}, {12,13,31,36,54,55,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68}, {11,13,14,30,37,53,54,56,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68}, {10,11,14,15,29,38,52,53,56,57,68,68,68,68,68,68,68,68,68,68,68,68,68,68}, { 9,10,11,12,15,16,28,33,34,39,51,52,55,56,57,58,68,68,68,68,68,68,68,68}, { 0, 8, 9,10,11,12,13,16,17,27,32,35,40,50,51,54,55,56,57,58,59,67,68,68}, { 0, 1, 7, 8, 9,10,13,14,17,18,26,31,36,41,49,50,53,54,57,58,59,60,66,67}, { 1, 2, 6, 7, 8, 9,14,15,18,19,25,30,37,42,48,49,52,53,58,59,60,61,65,66}, { 2, 3, 5, 6, 7, 8,15,16,19,20,24,29,38,43,47,48,51,52,59,60,61,62,64,65}, { 3, 4, 5, 6, 7,16,17,20,21,23,28,39,44,46,47,50,51,60,61,62,63,64,68,68}, { 4, 5, 6,17,18,21,22,27,40,45,46,49,50,61,62,63,68,68,68,68,68,68,68,68}, { 4, 5,18,19,26,41,48,49,62,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68}, { 4,19,20,25,42,47,48,63,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68}, {20,21,24,43,46,47,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68}, {21,23,44,46,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68}}; //pupil L&R animation int pupilLED[15][12] = {{33,34,68,68,68,68,68,68,68,68,68,68}, {32,33,34,35,68,68,68,68,68,68,68,68}, {12,31,32,33,34,35,36,55,68,68,68,68}, {12,13,30,31,32,33,34,35,36,37,54,55}, {13,14,29,30,31,32,35,36,37,38,53,54}, {14,15,28,29,30,31,36,37,38,39,52,53}, {15,16,27,28,29,30,37,38,39,40,51,52}, {16,17,26,27,28,29,38,39,40,41,50,51}, {17,18,25,26,27,28,39,40,41,42,49,50}, {18,19,24,25,26,27,40,41,42,43,48,49}, {19,20,23,24,25,26,41,42,43,44,47,48}, {20,21,22,23,24,25,42,43,44,45,46,47}, {21,22,23,24,43,44,45,46,68,68,68,68}, {22,23,44,45,68,68,68,68,68,68,68,68}, {22,45,68,68,68,68,68,68,68,68,68,68}}; //Blink animation int eyelid = 0; int eyelidNum[8] = {0,4,8,16,24,34,44,56}; int eyelidLED[56] = {64,65,66,67,58,59,60,61,56,57,62,63,49,50,51,52,47,48,53,54,38,39,40,41,46,55,36,37,42,43,26,27,28,29,35,44,24,25,30,31,15,16,17,18,34,45,23,32,13,14,19,20,6,7,8,9}; QTRSensorsAnalog qtra((unsigned char[]) {0, 1}, NUM_SENSORS, NUM_SAMPLES_PER_SENSOR, EMITTER_PIN); unsigned int sensorValues[NUM_SENSORS]; void blink(int eyelid, int LR) { if (eyelid != 8){ //白目 for(uint16_t i=0; i<led.numPixels(); i++) { led.setPixelColor(i, led.Color(66, 66, 66)); } //黒目 for(uint16_t i=0; i<blackNum; i++) { led.setPixelColor(blackLED[LR][i], color); } //瞳孔 for(uint16_t i=0; i<pupilNum; i++) { led.setPixelColor(pupilLED[LR][i], led.Color(0, 0, 66)); } //まぶた for(int i=0; i < eyelidNum[eyelid]; i++) { led.setPixelColor(eyelidLED[i], 0); } } else if (eyelid == 8){ led.clear(); } led.show(); } void setup() { Serial.begin(115200); led.begin(); led.setBrightness(brightness); // Initial Brightness 40 led.show(); // Initialize all pixels to 'off' color = led.Color(0, 177, 55); //pupil color delay(100); qtra.read(sensorValues); iniSensorValL = sensorValues[0]; iniSensorValR = sensorValues[1]; blink(eyelid, LR); } void loop() { //フォトリフレクタ値取得 qtra.read(sensorValues); sensorValL = sensorValues[0]; sensorValR = sensorValues[1]; double rasioL = (double)sensorValL / iniSensorValL; double rasioR = (double)sensorValR / iniSensorValR; Serial.print(rasioL); Serial.print(" "); Serial.println(rasioR); //黒目が遠ざかると反射光が増えてセンサ値が減少する if(rasioL > 0.985 && rasioR < 0.985){ //右 for(int i = LR; i < 12; i++){ blink(0, i); delay(40); LR = i; } Serial.println("右"); }else if(rasioL < 0.985 && rasioR > 0.985){ //左 for(int i=LR; i>2; i--){ blink(0, i); delay(40); LR = i; } Serial.println("左"); }else if(lid == false && rasioL < 0.96 && rasioR < 0.96){ //瞬き閉じ動作 for(int i = 1; i < 9; i++){ blink(i, LR); delay(40); lid = true; } Serial.println("瞬き閉じ動作"); }else if(lid == true && rasioL > 0.96 && rasioR > 0.96){ //瞬き開き動作 for(int i = 8; i > 0; i--){ blink(i, LR); delay(40); lid = false; } Serial.println("瞬き開き動作"); }else if(lid == false && rasioL > 0.96 && rasioR > 0.96) { //通常時 //cnt++; //eyelid = 0; if(LR <= 7){ for(int i=LR; i<=7; i++){ blink(0, i); delay(40); LR = i; } }else { for(int i=LR; i>=7; i--){ blink(0, i); delay(40); LR = i; } } Serial.println("通常時"); } //初期値リフレッシュ if (cnt > 10){ iniSensorValL = sensorValL; iniSensorValR = sensorValR; cnt = 0; } } |
動作
瞳孔動向センシング#LED #Arduino #メガネ pic.twitter.com/WVMU07KPE6
— HomeMadeGarbage (@H0meMadeGarbage) 2018年9月15日
簡単な構成でアイトラッキングが実現できました!わーい 😆
これをうまいこと利用してハロウィンに向けて制作すすめます!
いざトリック・オア・トリート!
追記
18/9/25
Adafruit様のブログで紹介いただきました!
19/1/3
Make:の公式YouTubeチャンネルで紹介いただきました!