Track heat with eyes via GridEye infrared sensor array.

This commit is contained in:
teejaydub 2019-10-03 21:21:39 -04:00
parent 982c6143d8
commit fc48529c07
4 changed files with 157 additions and 8 deletions

110
M4_Eyes/HeatSensor.cpp Normal file
View file

@ -0,0 +1,110 @@
/* Read the IR sensor and try to figure out where the heat is located.
*/
#include "HeatSensor.h"
#include <Wire.h>
#include <Adafruit_AMG88xx.h>
Adafruit_AMG88xx amg;
float pixels[AMG88xx_PIXEL_ARRAY_SIZE];
void HeatSensor::setup()
{
x = 0;
y = 0;
magnitude = 0;
bool status;
// default settings
status = amg.begin();
if (!status) {
Serial.println("Could not find a valid AMG88xx sensor, check wiring!");
while (1);
}
yield();
delay(100); // let sensor boot up
}
// Find the approximate X and Y values of the peak temperature in the pixel array,
// along with the magnitude of the brightest spot.
void HeatSensor::find_focus()
{
amg.readPixels(pixels);
yield();
x = 0, y = 0, magnitude = 0;
float minVal = 100, maxVal = 0;
int i = 0;
for (float yPos = 3.5; yPos > -4; yPos -= 1.0) {
for (float xPos = 3.5; xPos > -4; xPos -= 1.0) {
float p = pixels[i];
x += xPos * p;
y += yPos * p;
minVal = min(minVal, p);
maxVal = max(maxVal, p);
i++;
}
}
x = - x / AMG88xx_PIXEL_ARRAY_SIZE / 5.0;
y = y / AMG88xx_PIXEL_ARRAY_SIZE / 5.0;
x = max(-1.0, min(1.0, x));
y = max(-1.0, min(1.0, y));
magnitude = max(0, min(50, maxVal - 20));
// Report.
#define SERIAL_OUT 3
#if SERIAL_OUT == 1
// Print raw values
Serial.print("[");
for(int i=1; i<=AMG88xx_PIXEL_ARRAY_SIZE; i++){
Serial.print(pixels[i-1]);
Serial.print(", ");
if( i%8 == 0 ) Serial.println();
}
Serial.println("]");
Serial.println();
#endif
#if SERIAL_OUT == 2
// Print character-graphic array
const char charPixels[] = " .-*o0#";
Serial.println("========");
for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++) {
int val = min(5, round(max(0, pixels[i-1] - 20) / 2));
Serial.print(charPixels[val]);
if (i % 8 == 0)
Serial.println();
}
Serial.println();
#endif
#if SERIAL_OUT == 3 || SERIAL_OUT == 2
// Print coordinates and brightness
Serial.print(x);
Serial.print(' ');
Serial.print(y);
Serial.print(' ');
Serial.println(magnitude);
#endif
}
/*
void loop() {
// Read all the pixels
// Find the focal point.
float x, y, magnitude;
find_focus(x, y, magnitude);
// Set diagnostic LEDs.
analogWrite(CENTER_LED, round(max(0, magnitude / 30) * 255));
analogWrite(RIGHT_LED, round(min(1.0, max(0.0, -x / 3)) * 255));
analogWrite(LEFT_LED, round(min(1.0, max(0.0, x / 3)) * 255));
analogWrite(UP_LED, round(min(1.0, max(0.0, y / 3)) * 255));
analogWrite(DOWN_LED, round(min(1.0, max(0.0, -y / 3)) * 255));
delay(200);
}
*/

24
M4_Eyes/HeatSensor.h Normal file
View file

@ -0,0 +1,24 @@
/* Read the IR sensor and try to figure out where the heat is located.
Orientation: Looking into the sensor, the window is on the bottom of the silver package,
and the Adafruit star is at the upper left.
X goes from about -1.0 on the left, facing out of the sensor, to +1.0 on the right.
Y goes roughly from -1.0 (less?) on the bottom to +1.0 on the top.
The sensor is oriented with its text upside down for the moment.
Magnitude is currently the maximum temperature of any pixel, in degrees C.
*/
class HeatSensor {
public:
// The current focus position, each from -1.0 .. +1.0.
float x, y;
// The current magnitude estimate, in degrees C.
float magnitude;
// Must be called once.
void setup();
// Reads the sensor and updates x, y, and magnitude.
void find_focus();
};

View file

@ -68,6 +68,9 @@ float iris_prev[IRIS_LEVELS] = { 0 };
float iris_next[IRIS_LEVELS] = { 0 };
uint16_t iris_frame = 0;
// For heat sensing
HeatSensor heatSensor;
// Callback invoked after each SPI DMA transfer - sets a flag indicating
// the next line of graphics can be issued as soon as its ready.
static void dma_callback(Adafruit_ZeroDMA *dma) {
@ -184,6 +187,7 @@ void setup() {
eye[0].display = arcada.display;
#endif
#ifdef DO_SPLASH_SCREEN
yield();
if (arcada.drawBMP("/splash.bmp", 0, 0, (eye[0].display)) == IMAGE_SUCCESS) {
Serial.println("Splashing");
@ -203,6 +207,7 @@ void setup() {
delay(20);
}
}
#endif
// Initialize DMAs
yield();
@ -417,6 +422,7 @@ void setup() {
}
user_setup();
heatSensor.setup();
lastLightReadTime = micros() + 2000000; // Delay initial light reading
}
@ -475,8 +481,8 @@ void loop() {
if(eyeInMotion) { // Currently moving?
if(dt >= eyeMoveDuration) { // Time up? Destination reached.
eyeInMotion = false; // Stop moving
eyeMoveDuration = random(10000, 3000000); // 0.01-3 sec stop
eyeMoveStartTime = t; // Save initial time of stop
// eyeMoveDuration = random(10000, 3000000); // 0.01-3 sec stop
// eyeMoveStartTime = t; // Save initial time of stop
eyeX = eyeOldX = eyeNewX; // Save position
eyeY = eyeOldY = eyeNewY;
} else { // Move time's not yet fully elapsed -- interpolate position
@ -489,13 +495,22 @@ void loop() {
eyeX = eyeOldX;
eyeY = eyeOldY;
if(dt > eyeMoveDuration) { // Time up? Begin new move.
// Estimate the focus position.
heatSensor.find_focus();
// r is the radius in X and Y that the eye can go, from (0,0) in the center.
float r = (float)mapDiameter - (float)DISPLAY_SIZE * M_PI_2; // radius of motion
r *= 0.6;
eyeNewX = random(-r, r);
float h = sqrt(r * r - x * x);
eyeNewY = random(-h, h);
r *= 0.6; // calibration constant
// Set values for the new X and Y.
eyeNewX = heatSensor.x * r;
eyeNewY = -heatSensor.y * r;
// Adjust for the map.
eyeNewX += mapRadius;
eyeNewY += mapRadius;
// Set the duration for this move, and start it going.
eyeMoveDuration = random(83000, 166000); // ~1/12 - ~1/6 sec
eyeMoveStartTime = t; // Save initial time of move
eyeInMotion = true; // Start move on next frame
@ -870,8 +885,7 @@ void loop() {
lightSensorPin = -1; // Stop trying to use the light sensor
} else {
lastLightReadTime = t - LIGHT_INTERVAL + 30000; // Try again in 30 ms
}
}
} }
}
irisValue = (irisValue * 0.97) + (lastLightValue * 0.03); // Filter response for smooth reaction
} else {

View file

@ -2,6 +2,7 @@
#include "Adafruit_Arcada.h"
#include "DMAbuddy.h" // DMA-bug-workaround class
#include "HeatSensor.h"
#if defined(GLOBAL_VAR) // #defined in .ino file ONLY!
#define GLOBAL_INIT(X) = (X)