Track heat with eyes via GridEye infrared sensor array.
This commit is contained in:
parent
982c6143d8
commit
fc48529c07
4 changed files with 157 additions and 8 deletions
110
M4_Eyes/HeatSensor.cpp
Normal file
110
M4_Eyes/HeatSensor.cpp
Normal 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
24
M4_Eyes/HeatSensor.h
Normal 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();
|
||||
};
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue