Skip to content

Commit fc48529

Browse files
committed
Track heat with eyes via GridEye infrared sensor array.
1 parent 982c614 commit fc48529

4 files changed

Lines changed: 157 additions & 8 deletions

File tree

M4_Eyes/HeatSensor.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/* Read the IR sensor and try to figure out where the heat is located.
2+
*/
3+
4+
#include "HeatSensor.h"
5+
6+
#include <Wire.h>
7+
#include <Adafruit_AMG88xx.h>
8+
9+
Adafruit_AMG88xx amg;
10+
11+
float pixels[AMG88xx_PIXEL_ARRAY_SIZE];
12+
13+
void HeatSensor::setup()
14+
{
15+
x = 0;
16+
y = 0;
17+
magnitude = 0;
18+
19+
bool status;
20+
21+
// default settings
22+
status = amg.begin();
23+
if (!status) {
24+
Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
25+
while (1);
26+
}
27+
28+
yield();
29+
delay(100); // let sensor boot up
30+
}
31+
32+
// Find the approximate X and Y values of the peak temperature in the pixel array,
33+
// along with the magnitude of the brightest spot.
34+
void HeatSensor::find_focus()
35+
{
36+
amg.readPixels(pixels);
37+
yield();
38+
39+
x = 0, y = 0, magnitude = 0;
40+
float minVal = 100, maxVal = 0;
41+
int i = 0;
42+
for (float yPos = 3.5; yPos > -4; yPos -= 1.0) {
43+
for (float xPos = 3.5; xPos > -4; xPos -= 1.0) {
44+
float p = pixels[i];
45+
x += xPos * p;
46+
y += yPos * p;
47+
minVal = min(minVal, p);
48+
maxVal = max(maxVal, p);
49+
i++;
50+
}
51+
}
52+
x = - x / AMG88xx_PIXEL_ARRAY_SIZE / 5.0;
53+
y = y / AMG88xx_PIXEL_ARRAY_SIZE / 5.0;
54+
x = max(-1.0, min(1.0, x));
55+
y = max(-1.0, min(1.0, y));
56+
magnitude = max(0, min(50, maxVal - 20));
57+
58+
// Report.
59+
#define SERIAL_OUT 3
60+
#if SERIAL_OUT == 1
61+
// Print raw values
62+
Serial.print("[");
63+
for(int i=1; i<=AMG88xx_PIXEL_ARRAY_SIZE; i++){
64+
Serial.print(pixels[i-1]);
65+
Serial.print(", ");
66+
if( i%8 == 0 ) Serial.println();
67+
}
68+
Serial.println("]");
69+
Serial.println();
70+
#endif
71+
#if SERIAL_OUT == 2
72+
// Print character-graphic array
73+
const char charPixels[] = " .-*o0#";
74+
Serial.println("========");
75+
for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++) {
76+
int val = min(5, round(max(0, pixels[i-1] - 20) / 2));
77+
Serial.print(charPixels[val]);
78+
if (i % 8 == 0)
79+
Serial.println();
80+
}
81+
Serial.println();
82+
#endif
83+
#if SERIAL_OUT == 3 || SERIAL_OUT == 2
84+
// Print coordinates and brightness
85+
Serial.print(x);
86+
Serial.print(' ');
87+
Serial.print(y);
88+
Serial.print(' ');
89+
Serial.println(magnitude);
90+
#endif
91+
}
92+
93+
/*
94+
void loop() {
95+
// Read all the pixels
96+
97+
// Find the focal point.
98+
float x, y, magnitude;
99+
find_focus(x, y, magnitude);
100+
101+
// Set diagnostic LEDs.
102+
analogWrite(CENTER_LED, round(max(0, magnitude / 30) * 255));
103+
analogWrite(RIGHT_LED, round(min(1.0, max(0.0, -x / 3)) * 255));
104+
analogWrite(LEFT_LED, round(min(1.0, max(0.0, x / 3)) * 255));
105+
analogWrite(UP_LED, round(min(1.0, max(0.0, y / 3)) * 255));
106+
analogWrite(DOWN_LED, round(min(1.0, max(0.0, -y / 3)) * 255));
107+
108+
delay(200);
109+
}
110+
*/

M4_Eyes/HeatSensor.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* Read the IR sensor and try to figure out where the heat is located.
2+
3+
Orientation: Looking into the sensor, the window is on the bottom of the silver package,
4+
and the Adafruit star is at the upper left.
5+
X goes from about -1.0 on the left, facing out of the sensor, to +1.0 on the right.
6+
Y goes roughly from -1.0 (less?) on the bottom to +1.0 on the top.
7+
The sensor is oriented with its text upside down for the moment.
8+
Magnitude is currently the maximum temperature of any pixel, in degrees C.
9+
*/
10+
11+
class HeatSensor {
12+
public:
13+
// The current focus position, each from -1.0 .. +1.0.
14+
float x, y;
15+
16+
// The current magnitude estimate, in degrees C.
17+
float magnitude;
18+
19+
// Must be called once.
20+
void setup();
21+
22+
// Reads the sensor and updates x, y, and magnitude.
23+
void find_focus();
24+
};

M4_Eyes/M4_Eyes.ino

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ float iris_prev[IRIS_LEVELS] = { 0 };
6868
float iris_next[IRIS_LEVELS] = { 0 };
6969
uint16_t iris_frame = 0;
7070

71+
// For heat sensing
72+
HeatSensor heatSensor;
73+
7174
// Callback invoked after each SPI DMA transfer - sets a flag indicating
7275
// the next line of graphics can be issued as soon as its ready.
7376
static void dma_callback(Adafruit_ZeroDMA *dma) {
@@ -184,6 +187,7 @@ void setup() {
184187
eye[0].display = arcada.display;
185188
#endif
186189

190+
#ifdef DO_SPLASH_SCREEN
187191
yield();
188192
if (arcada.drawBMP("/splash.bmp", 0, 0, (eye[0].display)) == IMAGE_SUCCESS) {
189193
Serial.println("Splashing");
@@ -203,6 +207,7 @@ void setup() {
203207
delay(20);
204208
}
205209
}
210+
#endif
206211

207212
// Initialize DMAs
208213
yield();
@@ -417,6 +422,7 @@ void setup() {
417422
}
418423

419424
user_setup();
425+
heatSensor.setup();
420426

421427
lastLightReadTime = micros() + 2000000; // Delay initial light reading
422428
}
@@ -475,8 +481,8 @@ void loop() {
475481
if(eyeInMotion) { // Currently moving?
476482
if(dt >= eyeMoveDuration) { // Time up? Destination reached.
477483
eyeInMotion = false; // Stop moving
478-
eyeMoveDuration = random(10000, 3000000); // 0.01-3 sec stop
479-
eyeMoveStartTime = t; // Save initial time of stop
484+
// eyeMoveDuration = random(10000, 3000000); // 0.01-3 sec stop
485+
// eyeMoveStartTime = t; // Save initial time of stop
480486
eyeX = eyeOldX = eyeNewX; // Save position
481487
eyeY = eyeOldY = eyeNewY;
482488
} else { // Move time's not yet fully elapsed -- interpolate position
@@ -489,13 +495,22 @@ void loop() {
489495
eyeX = eyeOldX;
490496
eyeY = eyeOldY;
491497
if(dt > eyeMoveDuration) { // Time up? Begin new move.
498+
// Estimate the focus position.
499+
heatSensor.find_focus();
500+
501+
// r is the radius in X and Y that the eye can go, from (0,0) in the center.
492502
float r = (float)mapDiameter - (float)DISPLAY_SIZE * M_PI_2; // radius of motion
493-
r *= 0.6;
494-
eyeNewX = random(-r, r);
495-
float h = sqrt(r * r - x * x);
496-
eyeNewY = random(-h, h);
503+
r *= 0.6; // calibration constant
504+
505+
// Set values for the new X and Y.
506+
eyeNewX = heatSensor.x * r;
507+
eyeNewY = -heatSensor.y * r;
508+
509+
// Adjust for the map.
497510
eyeNewX += mapRadius;
498511
eyeNewY += mapRadius;
512+
513+
// Set the duration for this move, and start it going.
499514
eyeMoveDuration = random(83000, 166000); // ~1/12 - ~1/6 sec
500515
eyeMoveStartTime = t; // Save initial time of move
501516
eyeInMotion = true; // Start move on next frame
@@ -870,8 +885,7 @@ void loop() {
870885
lightSensorPin = -1; // Stop trying to use the light sensor
871886
} else {
872887
lastLightReadTime = t - LIGHT_INTERVAL + 30000; // Try again in 30 ms
873-
}
874-
}
888+
} }
875889
}
876890
irisValue = (irisValue * 0.97) + (lastLightValue * 0.03); // Filter response for smooth reaction
877891
} else {

M4_Eyes/globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "Adafruit_Arcada.h"
44
#include "DMAbuddy.h" // DMA-bug-workaround class
5+
#include "HeatSensor.h"
56

67
#if defined(GLOBAL_VAR) // #defined in .ino file ONLY!
78
#define GLOBAL_INIT(X) = (X)

0 commit comments

Comments
 (0)