Browse Source

Erste Versuche mit wärmebildkamera,

2 ultraschallsensoren an einen esp angeschlossen
master
Johannes Krug 4 years ago
parent
commit
944d0a19b1

+ 312
- 0
arduino/Arduino_ESP32_MLX90640/Arduino_ESP32_MLX90640.ino View File

@@ -0,0 +1,312 @@
#include <Wire.h>
#include "MLX90640_API.h"
#include "MLX90640_I2C_Driver.h"
//#include "SPI.h"
//#include "Adafruit_GFX.h"
//#include "Adafruit_ILI9341.h"

// For the ESP-WROVER_KIT, these are the default.
/*#define TFT_CS 15
#define TFT_DC 2
#define TFT_MOSI 13
#define TFT_CLK 14
#define TFT_RST 26
#define TFT_MISO 12
#define TFT_LED 27*/

/*Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);*/

const byte MLX90640_address = 0x33; //Default 7-bit unshifted address of the MLX90640

#define TA_SHIFT 8 //Default shift for MLX90640 in open air

static float mlx90640To[768];
paramsMLX90640 mlx90640;

int xPos, yPos; // Abtastposition
int R_colour, G_colour, B_colour; // RGB-Farbwert
int i, j; // Zählvariable
float T_max, T_min; // maximale bzw. minimale gemessene Temperatur
float T_center; // Temperatur in der Bildschirmmitte




// ***************************************
// **************** SETUP ****************
// ***************************************

void setup()
{
Serial.begin(115200);
Wire.begin();
Wire.setClock(400000); //Increase I2C clock speed to 400kHz

while (!Serial); //Wait for user to open terminal
Serial.println("MLX90640 IR Array Example");

if (isConnected() == false)
{
Serial.println("MLX90640 not detected at default I2C address. Please check wiring. Freezing.");
while (1);
}
Serial.println("MLX90640 online!");

//Get device parameters - We only have to do this once
int status;
uint16_t eeMLX90640[832];
status = MLX90640_DumpEE(MLX90640_address, eeMLX90640);
if (status != 0)
Serial.println("Failed to load system parameters");

status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640);
if (status != 0)
{
Serial.println("Parameter extraction failed");
Serial.print(" status = ");
Serial.println(status);
}

//Once params are extracted, we can release eeMLX90640 array

MLX90640_I2CWrite(0x33, 0x800D, 6401); // writes the value 1901 (HEX) = 6401 (DEC) in the register at position 0x800D to enable reading out the temperatures!!!
// ===============================================================================================================================================================

//MLX90640_SetRefreshRate(MLX90640_address, 0x00); //Set rate to 0.25Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x01); //Set rate to 0.5Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x02); //Set rate to 1Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x03); //Set rate to 2Hz effective - Works
MLX90640_SetRefreshRate(MLX90640_address, 0x04); //Set rate to 4Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x05); //Set rate to 8Hz effective - Works at 800kHz
//MLX90640_SetRefreshRate(MLX90640_address, 0x06); //Set rate to 16Hz effective - Works at 800kHz
//MLX90640_SetRefreshRate(MLX90640_address, 0x07); //Set rate to 32Hz effective - fails

//pinMode(TFT_LED, OUTPUT);
//digitalWrite(TFT_LED, HIGH);

/*tft.begin();

tft.setRotation(1);

tft.fillScreen(ILI9341_BLACK);
tft.fillRect(0, 0, 319, 13, tft.color565(255, 0, 10));
tft.setCursor(100, 3);
tft.setTextSize(1);
tft.setTextColor(ILI9341_YELLOW, tft.color565(255, 0, 10));
tft.print("Thermographie - stoppi");

tft.drawLine(250, 210 - 0, 258, 210 - 0, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 30, 258, 210 - 30, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 60, 258, 210 - 60, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 90, 258, 210 - 90, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 120, 258, 210 - 120, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 150, 258, 210 - 150, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 180, 258, 210 - 180, tft.color565(255, 255, 255));

tft.setCursor(80, 220);
tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0));
tft.print("T+ = ");


// drawing the colour-scale
// ========================
for (i = 0; i < 181; i++)
{
//value = random(180);
getColour(i);
tft.drawLine(240, 210 - i, 250, 210 - i, tft.color565(R_colour, G_colour, B_colour));
}

}

*/

// **********************************
// ************** LOOP **************
// **********************************

void loop()
{
for (byte x = 0 ; x < 2 ; x++) //Read both subpages
{
uint16_t mlx90640Frame[834];
int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame);
if (status < 0)
{
Serial.print("GetFrame Error: ");
Serial.println(status);
}

float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640);
float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640);

float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature
float emissivity = 0.95;

MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To);
}

// determine T_min and T_max and eliminate error pixels
// ====================================================

mlx90640To[1*32 + 21] = 0.5 * (mlx90640To[1*32 + 20] + mlx90640To[1*32 + 22]); // eliminate the error-pixels
mlx90640To[4*32 + 30] = 0.5 * (mlx90640To[4*32 + 29] + mlx90640To[4*32 + 31]); // eliminate the error-pixels
T_min = mlx90640To[0];
T_max = mlx90640To[0];

for (i = 1; i < 768; i++)
{
if((mlx90640To[i] > -41) && (mlx90640To[i] < 301))
{
if(mlx90640To[i] < T_min)
{
T_min = mlx90640To[i];
}

if(mlx90640To[i] > T_max)
{
T_max = mlx90640To[i];
}
}
else if(i > 0) // temperature out of range
{
mlx90640To[i] = mlx90640To[i-1];
}
else
{
mlx90640To[i] = mlx90640To[i+1];
}
}


// determine T_center
// ==================

T_center = mlx90640To[11* 32 + 15];

// drawing the picture
// ===================

for (i = 0 ; i < 24 ; i++)
{
for (j = 0; j < 32; j++)
{
mlx90640To[i*32 + j] = 180.0 * (mlx90640To[i*32 + j] - T_min) / (T_max - T_min);
getColour(mlx90640To[i*32 + j]);
// tft.fillRect(217 - j * 7, 35 + i * 7, 7, 7, tft.color565(R_colour, G_colour, B_colour));
}
}
/*
tft.drawLine(217 - 15*7 + 3.5 - 5, 11*7 + 35 + 3.5, 217 - 15*7 + 3.5 + 5, 11*7 + 35 + 3.5, tft.color565(255, 255, 255));
tft.drawLine(217 - 15*7 + 3.5, 11*7 + 35 + 3.5 - 5, 217 - 15*7 + 3.5, 11*7 + 35 + 3.5 + 5, tft.color565(255, 255, 255));
tft.fillRect(260, 25, 37, 10, tft.color565(0, 0, 0));
tft.fillRect(260, 205, 37, 10, tft.color565(0, 0, 0));
tft.fillRect(115, 220, 37, 10, tft.color565(0, 0, 0));

tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0));
tft.setCursor(265, 25);
tft.print(T_max, 1);
tft.setCursor(265, 205);
tft.print(T_min, 1);
tft.setCursor(120, 220);
tft.print(T_center, 1);

tft.setCursor(300, 25);
tft.print("C");
tft.setCursor(300, 205);
tft.print("C");
tft.setCursor(155, 220);
tft.print("C");
*/
delay(20);
}


// ===============================
// ===== determine the colour ====
// ===============================

void getColour(int j)
{
if (j >= 0 && j < 30)
{
R_colour = 0;
G_colour = 0;
B_colour = 20 + (120.0/30.0) * j;
}
if (j >= 30 && j < 60)
{
R_colour = (120.0 / 30) * (j - 30.0);
G_colour = 0;
B_colour = 140 - (60.0/30.0) * (j - 30.0);
}

if (j >= 60 && j < 90)
{
R_colour = 120 + (135.0/30.0) * (j - 60.0);
G_colour = 0;
B_colour = 80 - (70.0/30.0) * (j - 60.0);
}

if (j >= 90 && j < 120)
{
R_colour = 255;
G_colour = 0 + (60.0/30.0) * (j - 90.0);
B_colour = 10 - (10.0/30.0) * (j - 90.0);
}

if (j >= 120 && j < 150)
{
R_colour = 255;
G_colour = 60 + (175.0/30.0) * (j - 120.0);
B_colour = 0;
}

if (j >= 150 && j <= 180)
{
R_colour = 255;
G_colour = 235 + (20.0/30.0) * (j - 150.0);
B_colour = 0 + 255.0/30.0 * (j - 150.0);
}

}
//Returns true if the MLX90640 is detected on the I2C bus
boolean isConnected()
{
Wire.beginTransmission((uint8_t)MLX90640_address);
if (Wire.endTransmission() != 0)
return (false); //Sensor did not ACK
return (true);
}

+ 2
- 2
arduino/SR04_Example/SR04_Example.ino View File

@@ -1,6 +1,6 @@
#include "SR04.h"
#define TRIG_PIN 3
#define ECHO_PIN 4
#define TRIG_PIN D3
#define ECHO_PIN D4
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long a;


+ 157
- 0
arduino/ultraschall/2Ultrasonic_Sensor_an_rpi/2Ultrasonic_Sensor_an_rpi.ino View File

@@ -0,0 +1,157 @@
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

//Eigene zu trackende Entfernung festlegen
#define DISTANCE 155

const char* SSID = "smartroom";
const char* PSK = "smarthome";
const char* MQTT_BROKER = "192.168.252.1";
WiFiClient espClient;
PubSubClient client(espClient);

// defines pins numbers
const int trigPin = D3; //D4
const int echoPin1 = D4; //D3
const int echoPin2 = D2; //D2

long duration1;
long duration2;
int distance1;
int distance2;
int bool1 = 0;
int bool2 = 0;
char msg[50];
int value = 0;
long lastMsg = 0;

void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin1, INPUT); // Sets the echoPin as an Input
pinMode(echoPin2, INPUT); // Sets the echoPin as an Input
Serial.begin(115200);
setup_wifi();
client.setServer(MQTT_BROKER, 1883);
}

void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(SSID);
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, PSK);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}

void reconnect() {
while (!client.connected()) {
Serial.print("Reconnecting...");
if (!client.connect("ESP8266Client")) {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" retrying in 5 seconds");
delay(5000);
}
}
}


void loop() {

if (!client.connected()) {
reconnect();
}
client.loop();

// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);

// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

// Reads the echoPin, returns the sound wave travel time in microseconds
duration1 = pulseIn(echoPin1, HIGH);
duration2 = pulseIn(echoPin2, HIGH);
// Calculating the distance
distance1 = getDistance(duration1);
distance2 = getDistance(duration2);
// Prints the distance1 on the Serial Monitor
/* if ((distance1!= (distance_alt - 1)) && (distance1!= (distance_alt)) && (distance1!= (distance_alt + 1))) { //+-1 um störungen herauszufiltern
snprintf (msg, 50, "%d", distance);
Serial.print("Publish Motion: ");
Serial.println(msg);
client.publish("/home/data", msg);
delay(200);
} */
bool1 = presenceDetection(bool1, distance1);
bool2 = presenceDetection(bool2, distance2);

delay(80);
}

int presenceDetection(int bool1, int distance1){
if (bool1 == 0) {
//alternativ: if ((distance1!= (DISTANCE - 1)) && (distance1!= (DISTANCE)) && (distance1!= (DISTANCE + 1))) { //+-1
if (((distance1 > (DISTANCE + 2)) || (distance1 < (DISTANCE - 2))) && (distance1 < (DISTANCE + 2))) { //darf +- 2 um festgelegte entfernung schwanken, um störungen herauszufiltern
//Meldung an PI, dass die Distanz gestört ist
snprintf (msg, 50, "%d", 1);
client.publish("/gso/bb/104/ultraschall/1", msg);
//Serieller Monitor
Serial.print("Motion detected! Distance: ");
Serial.println(distance1);

//Flag auf 1
bool1 = 1;
return bool1;
}
else {
snprintf (msg, 50, "%d", 0);
client.publish("/gso/bb/104/ultraschall/1", msg);
return bool1;
}

}
else if (bool1 == 1) {
if (((distance1> (DISTANCE + 2)) || (distance1<(DISTANCE - 2)))&&(distance1<(DISTANCE + 2))) { //darf +- 2 um festgelegte entfernung schwanken, um störungen herauszufiltern
Serial.print("Still motion detected! Distance: ");
Serial.println(distance1);
//Meldung an PI, dass die Ausgangsdistanz wieder gemessen wird
snprintf (msg, 50, "%d", 1);
client.publish("/gso/bb/104/ultraschall/1", msg);

return bool1;
}
else {
//Meldung an PI, dass die Ausgangsdistanz wieder gemessen wird
snprintf (msg, 50, "%d", 0);
client.publish("/gso/bb/104/ultraschall/1", msg);

//Flag wieder auf 0
bool1 = 0;
return bool1;

}
}
}

int getDistance(int duration){
int distance = duration * 0.034 / 2;
return distance;
}

+ 41
- 18
arduino/ultraschall/Ultrasonic_Sensor_optimiert/Ultrasonic_Sensor_optimiert.ino View File

@@ -11,20 +11,24 @@ WiFiClient espClient;
PubSubClient client(espClient);

// defines pins numbers
const int trigPin = 2; //D4
const int echoPin = 0; //D3
const int trigPin = D3; //D4
const int echoPin1 = D4; //D3

long duration1;

int distance1;

long duration;
int distance;
int bool1 = 0;

char msg[50];
int value = 0;
long lastMsg = 0;

void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(echoPin1, INPUT); // Sets the echoPin as an Input

Serial.begin(115200);
setup_wifi();
client.setServer(MQTT_BROKER, 1883);
@@ -79,45 +83,59 @@ void loop() {
digitalWrite(trigPin, LOW);

// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);

duration1 = pulseIn(echoPin1, HIGH);
// Calculating the distance
distance = duration * 0.034 / 2;
// Prints the distance on the Serial Monitor
/* if ((distance != (distance_alt - 1)) && (distance != (distance_alt)) && (distance != (distance_alt + 1))) { //+-1 um störungen herauszufiltern
distance1 = getDistance(duration1);

// Prints the distance1 on the Serial Monitor
/* if ((distance1!= (distance_alt - 1)) && (distance1!= (distance_alt)) && (distance1!= (distance_alt + 1))) { //+-1 um störungen herauszufiltern
snprintf (msg, 50, "%d", distance);
Serial.print("Publish Motion: ");
Serial.println(msg);
client.publish("/home/data", msg);
delay(200);
} */
bool1 = presenceDetection(bool1, distance1);


delay(80);
}

int presenceDetection(int bool1, int distance1){
if (bool1 == 0) {
//alternativ: if ((distance != (DISTANCE - 1)) && (distance != (DISTANCE)) && (distance != (DISTANCE + 1))) { //+-1
if (((DISTANCE + 2) < distance) || ((DISTANCE - 2) > distance)) { //darf +- 2 um festgelegte entfernung schwanken, um störungen herauszufiltern
//alternativ: if ((distance1!= (DISTANCE - 1)) && (distance1!= (DISTANCE)) && (distance1!= (DISTANCE + 1))) { //+-1
if (((distance1 > (DISTANCE + 2)) || (distance1 < (DISTANCE - 2))) && (distance1 < (DISTANCE + 2))) { //darf +- 2 um festgelegte entfernung schwanken, um störungen herauszufiltern
//Meldung an PI, dass die Distanz gestört ist
snprintf (msg, 50, "%d", 1);
client.publish("/gso/bb/104/ultraschall/1", msg);
//Serieller Monitor
Serial.print("Motion detected! Distance: ");
Serial.println(distance);
Serial.println(distance1);

//Flag auf 1
bool1 = 1;
bool1 = 1;
return bool1;
}
else {
snprintf (msg, 50, "%d", 0);
client.publish("/gso/bb/104/ultraschall/1", msg);
return bool1;
}

}
else if (bool1 == 1) {
if (((DISTANCE + 2) < distance) || ((DISTANCE - 2) > distance)) { //darf +- 2 um festgelegte entfernung schwanken, um störungen herauszufiltern
if (((distance1> (DISTANCE + 2)) || (distance1<(DISTANCE - 2)))) { //darf +- 2 um festgelegte entfernung schwanken, um störungen herauszufiltern
Serial.print("Still motion detected! Distance: ");
Serial.println(distance);
Serial.println(distance1);
//Meldung an PI, dass die Ausgangsdistanz wieder gemessen wird
snprintf (msg, 50, "%d", 1);
client.publish("/gso/bb/104/ultraschall/1", msg);

return bool1;
}
else {
//Meldung an PI, dass die Ausgangsdistanz wieder gemessen wird
@@ -126,8 +144,13 @@ void loop() {

//Flag wieder auf 0
bool1 = 0;
return bool1;

}
}
delay(100);
}

int getDistance(int duration){
int distance = duration * 0.034 / 2;
return distance;
}

+ 313
- 0
arduino/wärmebildkamera/Arduino_ESP32_MLX90640/Arduino_ESP32_MLX90640.ino View File

@@ -0,0 +1,313 @@
#include <Wire.h>
#include "MLX90640_API.h"
#include "MLX90640_I2C_Driver.h"
#include "SPI.h"
//#include "Adafruit_GFX.h"
//#include "Adafruit_ILI9341.h"

// For the ESP-WROVER_KIT, these are the default.
/*#define TFT_CS 15
#define TFT_DC 2
#define TFT_MOSI 13
#define TFT_CLK 14
#define TFT_RST 26
#define TFT_MISO 12
#define TFT_LED 27*/

/*Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);*/

const byte MLX90640_address = 0x33; //Default 7-bit unshifted address of the MLX90640

#define TA_SHIFT 8 //Default shift for MLX90640 in open air

static float mlx90640To[768];
paramsMLX90640 mlx90640;

int xPos, yPos; // Abtastposition
int R_colour, G_colour, B_colour; // RGB-Farbwert
int i, j; // Zählvariable
float T_max, T_min; // maximale bzw. minimale gemessene Temperatur
float T_center; // Temperatur in der Bildschirmmitte




// ***************************************
// **************** SETUP ****************
// ***************************************

void setup()
{
Serial.begin(115200);
Wire.begin();
Wire.setClock(400000); //Increase I2C clock speed to 400kHz

while (!Serial); //Wait for user to open terminal
Serial.println("MLX90640 IR Array Example");

if (isConnected() == false)
{
Serial.println("MLX90640 not detected at default I2C address. Please check wiring. Freezing.");
while (1);
}
Serial.println("MLX90640 online!");

//Get device parameters - We only have to do this once
int status;
uint16_t eeMLX90640[832];
status = MLX90640_DumpEE(MLX90640_address, eeMLX90640);
if (status != 0)
Serial.println("Failed to load system parameters");
if (status == 0)
Serial.println("dumpee_okay");

status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640);
if (status != 0)
{
Serial.println("Parameter extraction failed");
Serial.print(" status = ");
Serial.println(status);
}

//Once params are extracted, we can release eeMLX90640 array

MLX90640_I2CWrite(0x33, 0x800D, 6401); // writes the value 1901 (HEX) = 6401 (DEC) in the register at position 0x800D to enable reading out the temperatures!!!
// ===============================================================================================================================================================

//MLX90640_SetRefreshRate(MLX90640_address, 0x00); //Set rate to 0.25Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x01); //Set rate to 0.5Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x02); //Set rate to 1Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x03); //Set rate to 2Hz effective - Works
MLX90640_SetRefreshRate(MLX90640_address, 0x04); //Set rate to 4Hz effective - Works
//MLX90640_SetRefreshRate(MLX90640_address, 0x05); //Set rate to 8Hz effective - Works at 800kHz
//MLX90640_SetRefreshRate(MLX90640_address, 0x06); //Set rate to 16Hz effective - Works at 800kHz
//MLX90640_SetRefreshRate(MLX90640_address, 0x07); //Set rate to 32Hz effective - fails

//pinMode(TFT_LED, OUTPUT);
//digitalWrite(TFT_LED, HIGH);

/*tft.begin();

tft.setRotation(1);

tft.fillScreen(ILI9341_BLACK);
tft.fillRect(0, 0, 319, 13, tft.color565(255, 0, 10));
tft.setCursor(100, 3);
tft.setTextSize(1);
tft.setTextColor(ILI9341_YELLOW, tft.color565(255, 0, 10));
tft.print("Thermographie - stoppi");

tft.drawLine(250, 210 - 0, 258, 210 - 0, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 30, 258, 210 - 30, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 60, 258, 210 - 60, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 90, 258, 210 - 90, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 120, 258, 210 - 120, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 150, 258, 210 - 150, tft.color565(255, 255, 255));
tft.drawLine(250, 210 - 180, 258, 210 - 180, tft.color565(255, 255, 255));

tft.setCursor(80, 220);
tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0));
tft.print("T+ = ");


// drawing the colour-scale
// ========================
for (i = 0; i < 181; i++)
{
//value = random(180);
getColour(i);
tft.drawLine(240, 210 - i, 250, 210 - i, tft.color565(R_colour, G_colour, B_colour));
}


*/
}
// **********************************
// ************** LOOP **************
// **********************************

void loop(){
for (byte x = 0 ; x < 2 ; x++) //Read both subpages
{
uint16_t mlx90640Frame[834];
int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame);
if (status < 0)
{
Serial.print("GetFrame Error: ");
Serial.println(status);
}

float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640);
float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640);

float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature
float emissivity = 0.95;

MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To);
}

// determine T_min and T_max and eliminate error pixels
// ====================================================

mlx90640To[1*32 + 21] = 0.5 * (mlx90640To[1*32 + 20] + mlx90640To[1*32 + 22]); // eliminate the error-pixels
mlx90640To[4*32 + 30] = 0.5 * (mlx90640To[4*32 + 29] + mlx90640To[4*32 + 31]); // eliminate the error-pixels
T_min = mlx90640To[0];
T_max = mlx90640To[0];

for (i = 1; i < 768; i++)
{
if((mlx90640To[i] > -41) && (mlx90640To[i] < 301))
{
if(mlx90640To[i] < T_min)
{
T_min = mlx90640To[i];
}

if(mlx90640To[i] > T_max)
{
T_max = mlx90640To[i];
}
}
else if(i > 0) // temperature out of range
{
mlx90640To[i] = mlx90640To[i-1];
}
else
{
mlx90640To[i] = mlx90640To[i+1];
}
}


// determine T_center
// ==================

T_center = mlx90640To[11* 32 + 15];

// drawing the picture
// ===================

for (i = 0 ; i < 24 ; i++)
{
for (j = 0; j < 32; j++)
{
mlx90640To[i*32 + j] = 180.0 * (mlx90640To[i*32 + j] - T_min) / (T_max - T_min);
getColour(mlx90640To[i*32 + j]);
// tft.fillRect(217 - j * 7, 35 + i * 7, 7, 7, tft.color565(R_colour, G_colour, B_colour));
}
}
/*
tft.drawLine(217 - 15*7 + 3.5 - 5, 11*7 + 35 + 3.5, 217 - 15*7 + 3.5 + 5, 11*7 + 35 + 3.5, tft.color565(255, 255, 255));
tft.drawLine(217 - 15*7 + 3.5, 11*7 + 35 + 3.5 - 5, 217 - 15*7 + 3.5, 11*7 + 35 + 3.5 + 5, tft.color565(255, 255, 255));
tft.fillRect(260, 25, 37, 10, tft.color565(0, 0, 0));
tft.fillRect(260, 205, 37, 10, tft.color565(0, 0, 0));
tft.fillRect(115, 220, 37, 10, tft.color565(0, 0, 0));

tft.setTextColor(ILI9341_WHITE, tft.color565(0, 0, 0));
tft.setCursor(265, 25);
tft.print(T_max, 1);
tft.setCursor(265, 205);
tft.print(T_min, 1);
tft.setCursor(120, 220);
tft.print(T_center, 1);

tft.setCursor(300, 25);
tft.print("C");
tft.setCursor(300, 205);
tft.print("C");
tft.setCursor(155, 220);
tft.print("C");
*/
delay(20);
}


// ===============================
// ===== determine the colour ====
// ===============================

void getColour(int j)
{
if (j >= 0 && j < 30)
{
R_colour = 0;
G_colour = 0;
B_colour = 20 + (120.0/30.0) * j;
}
if (j >= 30 && j < 60)
{
R_colour = (120.0 / 30) * (j - 30.0);
G_colour = 0;
B_colour = 140 - (60.0/30.0) * (j - 30.0);
}

if (j >= 60 && j < 90)
{
R_colour = 120 + (135.0/30.0) * (j - 60.0);
G_colour = 0;
B_colour = 80 - (70.0/30.0) * (j - 60.0);
}

if (j >= 90 && j < 120)
{
R_colour = 255;
G_colour = 0 + (60.0/30.0) * (j - 90.0);
B_colour = 10 - (10.0/30.0) * (j - 90.0);
}

if (j >= 120 && j < 150)
{
R_colour = 255;
G_colour = 60 + (175.0/30.0) * (j - 120.0);
B_colour = 0;
}

if (j >= 150 && j <= 180)
{
R_colour = 255;
G_colour = 235 + (20.0/30.0) * (j - 150.0);
B_colour = 0 + 255.0/30.0 * (j - 150.0);
}

}
//Returns true if the MLX90640 is detected on the I2C bus
boolean isConnected()
{
Wire.beginTransmission((uint8_t)MLX90640_address);
if (Wire.endTransmission() != 0)
return (false); //Sensor did not ACK
return (true);
}

BIN
arduino/wärmebildkamera/Arduino_ESP32_MLX90640/MLX90640_API.zip View File


BIN
arduino/wärmebildkamera/Arduino_ESP32_MLX90640/MLX90640_I2C_Driver.zip View File


+ 113
- 0
arduino/wärmebildkamera/Example1_BasicReadings/Example1_BasicReadings.ino View File

@@ -0,0 +1,113 @@

/*
Read the temperature pixels from the MLX90640 IR array
By: Nathan Seidle
SparkFun Electronics
Date: May 22nd, 2018
License: MIT. See license file for more information but you can
basically do whatever you want with this code.

Feel like supporting open source hardware?
Buy a board from SparkFun! https://www.sparkfun.com/products/14769

This example initializes the MLX90640 and outputs the 768 temperature values
from the 768 pixels.

This example will work with a Teensy 3.1 and above. The MLX90640 requires some
hefty calculations and larger arrays. You will need a microcontroller with 20,000
bytes or more of RAM.

This relies on the driver written by Melexis and can be found at:
https://github.com/melexis/mlx90640-library

Hardware Connections:
Connect the SparkFun Qwiic Breadboard Jumper (https://www.sparkfun.com/products/14425)
to the Qwiic board
Connect the male pins to the Teensy. The pinouts can be found here: https://www.pjrc.com/teensy/pinout.html
Open the serial monitor at 9600 baud to see the output
*/

#include <Wire.h>

#include "MLX90640_API.h"
#include "MLX90640_I2C_Driver.h"

const byte MLX90640_address = 0x33; //Default 7-bit unshifted address of the MLX90640

#define TA_SHIFT 8 //Default shift for MLX90640 in open air

static float mlx90640To[768];
paramsMLX90640 mlx90640;

void setup()
{
Wire.begin();
Wire.setClock(100000); //Increase I2C clock speed to 400kHz

Serial.begin(9600);
while (!Serial); //Wait for user to open terminal
Serial.println("MLX90640 IR Array Example");

if (isConnected() == false)
{
Serial.println("MLX90640 not detected at default I2C address. Please check wiring. Freezing.");
while (1);
}
Serial.println("MLX90640 online!");

//Get device parameters - We only have to do this once
int status;
uint16_t eeMLX90640[832];
status = MLX90640_DumpEE(MLX90640_address, eeMLX90640);
if (status != 0)
Serial.println("Failed to load system parameters");

status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640);
if (status != 0)
Serial.println("Parameter extraction failed");

//Once params are extracted, we can release eeMLX90640 array
}

void loop()
{
for (byte x = 0 ; x < 2 ; x++) //Read both subpages
{
uint16_t mlx90640Frame[834];
int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame);
if (status < 0)
{
Serial.print("GetFrame Error: ");
Serial.println(status);
}

float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640);
float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640);

float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature
float emissivity = 0.95;

MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, mlx90640To);
}

for (int x = 0 ; x < 10 ; x++)
{
Serial.print("Pixel ");
Serial.print(x);
Serial.print(": ");
Serial.print(mlx90640To[x], 2);
Serial.print("C");
Serial.println();
}

delay(1000);
}

//Returns true if the MLX90640 is detected on the I2C bus
boolean isConnected()
{
Wire.beginTransmission((uint8_t)MLX90640_address);
if (Wire.endTransmission() != 0)
return (false); //Sensor did not ACK
return (true);
}

BIN
arduino/wärmebildkamera/Example1_BasicReadings/MLX90640_API.zip View File


BIN
arduino/wärmebildkamera/Example1_BasicReadings/MLX90640_I2C_Driver.zip View File


+ 1183
- 0
arduino/wärmebildkamera/MLX90640_API.cpp
File diff suppressed because it is too large
View File


+ 64
- 0
arduino/wärmebildkamera/MLX90640_API.h View File

@@ -0,0 +1,64 @@
/**
* @copyright (C) 2017 Melexis N.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef _MLX640_API_H_
#define _MLX640_API_H_
typedef struct
{
int16_t kVdd;
int16_t vdd25;
float KvPTAT;
float KtPTAT;
uint16_t vPTAT25;
float alphaPTAT;
int16_t gainEE;
float tgc;
float cpKv;
float cpKta;
uint8_t resolutionEE;
uint8_t calibrationModeEE;
float KsTa;
float ksTo[4];
int16_t ct[4];
float alpha[768];
int16_t offset[768];
float kta[768];
float kv[768];
float cpAlpha[2];
int16_t cpOffset[2];
float ilChessC[3];
uint16_t brokenPixels[5];
uint16_t outlierPixels[5];
} paramsMLX90640;
int MLX90640_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
int MLX90640_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
int MLX90640_ExtractParameters(uint16_t *eeData, paramsMLX90640 *mlx90640);
float MLX90640_GetVdd(uint16_t *frameData, const paramsMLX90640 *params);
float MLX90640_GetTa(uint16_t *frameData, const paramsMLX90640 *params);
void MLX90640_GetImage(uint16_t *frameData, const paramsMLX90640 *params, float *result);
void MLX90640_CalculateTo(uint16_t *frameData, const paramsMLX90640 *params, float emissivity, float tr, float *result);
int MLX90640_SetResolution(uint8_t slaveAddr, uint8_t resolution);
int MLX90640_GetCurResolution(uint8_t slaveAddr);
int MLX90640_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate);
int MLX90640_GetRefreshRate(uint8_t slaveAddr);
int MLX90640_GetSubPageNumber(uint16_t *frameData);
int MLX90640_GetCurMode(uint8_t slaveAddr);
int MLX90640_SetInterleavedMode(uint8_t slaveAddr);
int MLX90640_SetChessMode(uint8_t slaveAddr);
#endif

+ 102
- 0
arduino/wärmebildkamera/MLX90640_I2C_Driver.cpp View File

@@ -0,0 +1,102 @@
/**
@copyright (C) 2017 Melexis N.V.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

#include <Arduino.h>
#include <Wire.h>
#include "MLX90640_I2C_Driver.h"

void MLX90640_I2CInit()
{

}

//Read a number of words from startAddress. Store into Data array.
//Returns 0 if successful, -1 if error
int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data)
{

//Caller passes number of 'unsigned ints to read', increase this to 'bytes to read'
uint16_t bytesRemaining = nWordsRead * 2;

//It doesn't look like sequential read works. Do we need to re-issue the address command each time?

uint16_t dataSpot = 0; //Start at beginning of array

//Setup a series of chunked I2C_BUFFER_LENGTH byte reads
while (bytesRemaining > 0)
{
Wire.beginTransmission(_deviceAddress);
Wire.write(startAddress >> 8); //MSB
Wire.write(startAddress & 0xFF); //LSB
Wire.endTransmission(false)
uint16_t numberOfBytesToRead = bytesRemaining;
if (numberOfBytesToRead > I2C_BUFFER_LENGTH) numberOfBytesToRead = I2C_BUFFER_LENGTH;

Wire.requestFrom((uint8_t)_deviceAddress, numberOfBytesToRead);
if (Wire.available())
{
for (uint16_t x = 0 ; x < numberOfBytesToRead / 2; x++)
{
//Store data into array
data[dataSpot] = Wire.read() << 8; //MSB
data[dataSpot] |= Wire.read(); //LSB

dataSpot++;
}
}

bytesRemaining -= numberOfBytesToRead;

startAddress += numberOfBytesToRead / 2;
}

return (0); //Success
}

//Set I2C Freq, in kHz
//MLX90640_I2CFreqSet(1000) sets frequency to 1MHz
void MLX90640_I2CFreqSet(int freq)
{
//i2c.frequency(1000 * freq);
Wire.setClock((long)1000 * freq);
}

//Write two bytes to a two byte address
int MLX90640_I2CWrite(uint8_t _deviceAddress, unsigned int writeAddress, uint16_t data)
{
Wire.beginTransmission((uint8_t)_deviceAddress);
Wire.write(writeAddress >> 8); //MSB
Wire.write(writeAddress & 0xFF); //LSB
Wire.write(data >> 8); //MSB
Wire.write(data & 0xFF); //LSB
if (Wire.endTransmission() != 0)
{
//Sensor did not ACK
Serial.println("Error: Sensor did not ack");
return (-1);
}

uint16_t dataCheck;
MLX90640_I2CRead(_deviceAddress, writeAddress, 1, &dataCheck);
if (dataCheck != data)
{
//Serial.println("The write request didn't stick");
return -2;
}

return (0); //Success
}

+ 51
- 0
arduino/wärmebildkamera/MLX90640_I2C_Driver.h View File

@@ -0,0 +1,51 @@
/**
@copyright (C) 2017 Melexis N.V.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/
#ifndef _MLX90640_I2C_Driver_H_
#define _MLX90640_I2C_Driver_H_

#include <stdint.h>

//Define the size of the I2C buffer based on the platform the user has
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)

//I2C_BUFFER_LENGTH is defined in Wire.H
#define I2C_BUFFER_LENGTH BUFFER_LENGTH

#elif defined(__SAMD21G18A__)

//SAMD21 uses RingBuffer.h
#define I2C_BUFFER_LENGTH SERIAL_BUFFER_SIZE

#elif __MK20DX256__
//Teensy 3.2
#define I2C_BUFFER_LENGTH 32

#else

//The catch-all default is 32
#define I2C_BUFFER_LENGTH 32

#endif
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


void MLX90640_I2CInit(void);
int MLX90640_I2CRead(uint8_t slaveAddr, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data);
int MLX90640_I2CWrite(uint8_t slaveAddr, unsigned int writeAddress, uint16_t data);
void MLX90640_I2CFreqSet(int freq);
#endif

+ 9
- 0
arduino/wärmebildkamera/mlx90640/mlx90640.ino View File

@@ -0,0 +1,9 @@
void setup() {
// put your setup code here, to run once:

}

void loop() {
// put your main code here, to run repeatedly:

}

Loading…
Cancel
Save