IoT Sharing

Hot

Monday, July 29, 2019

Demo 47: Deep learning - Computer vision with ESP32 and tensorflow.js

3:58 AM 1
1. Introduction
- Deep learning is a hot topic and esp32 is a hot IoT MCU. Recently many applications related to computer vision are deployed on ESP32 (face detection, face recognition, ...). In this post I will show you a new approach to deploy Deep learning - Computer vision applications on ESP32 such as object classification (SqueezeNet), object detection and recognition (YOLOv3). After reading this post I am sure you can deploy hot network such as YOLOv3 on ESP32.
- My approach is using TensorFlow.js is a library for developing and training ML models in JavaScript, and deploying in browser.
- In this post, I will create a simple Deep learning - Computer vision application that is object classification using SqueezeNet. The esp32 will act as a webserver and when the client connect to it, a slideshow of objects will start and the objects will be classified using SqueezeNet.
You can do similar steps for YOLOv3, but instead of reading pictures from sdcard, you will use esp32-camera module and pass each camera frame to YOLOv3 model created by tensorflow.js.
 Figure: Deep learning - Computer vision with ESP32 and tensorflow.js
2. Hardware
You need a micro sdcard module as in Demo 7: How to use Arduino ESP32 to store data to microsdcard (Software SPI and Hardware SPI)
In this demo, I used Hardware SPI so please connect pins as below:
MICROSD CS    -      ESP32 IO5
MICROSD SCK   -     ESP32 IO18
MICROSD MOSI  -    ESP32 IO23
MICROSD MISO   -   ESP32 IO19
MICROSD Vcc   -      ESP32 3.3V
MICROSD GND   -    ESP32 GND
3. Software
- In order to make this demo, you have to review some demos:
Demo 12: How to turn the Arduino ESP32 into a Web Server
Demo 7: How to use Arduino ESP32 to store data to microsdcard (Software SPI and Hardware SPI)
- Knowledge of Jquery and Javascript.
- Material for deep learning part make by me: https://github.com/nhatuan84/tensorflowjs-squeezenet (or you can use the outputs that I generated)
- Knowledge of Deep learning. If you don't know, just follow me. I had another blog about Machine Leaning. It is here.
- I had to modify the webserver library in Demo 12: How to turn the Arduino ESP32 into a Web Server so that It can be used for this demo.
- Here are the steps:
  + Download all the resources here and unzip it.
  + Reinstall the ESP32WebServer.zip (in resources) for Arduino (you may uninstall old ESP32WebServer library).
  + Copy files: group1-shard1of2.bin, group1-shard2of2.bin, model.json, index.html, 1.jpg, 2.jpg, 3.jpg (in resources) to sdcard.
  + Create an Arduino project with code:
  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
#include <WiFiClient.h>
#include <ESP32WebServer.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include "FS.h"
#include <SD.h>
#include <SPI.h>

const char* ssid = "ssid";
const char* password = "pass";

ESP32WebServer server(80);
File root;

void handleRoot() {
  root = SD.open("/index.html");
  if (root) {  
    /* respond the content of file to client by calling streamFile()*/
    size_t sent = server.streamFile(root, "text/html");
    /* close the file */
    root.close();
  } else {
    Serial.println("error opening index");
  }
}

bool loadFromSDCARD(String path){
  path.toLowerCase();
  Serial.println(path);
  String dataType = "text/plain";
  if(path.endsWith("/")) path += "/index.html";
  if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  else if(path.endsWith(".jpg")) dataType = "image/jpeg";
  else if(path.endsWith(".txt")) dataType = "text/plain";
  else if(path.endsWith(".zip")) dataType = "application/zip";  
  if(path == "/favicon.ico")
    return false;
  
  root = SD.open((String("/") + path).c_str());
  if (!root){
    Serial.println("failed to open file");
    return false;
  }

  if (server.streamFile(root, dataType) != root.size()) {
    Serial.println("Sent less data than expected!");
  }

  root.close();
  return true;
}

void handleNotFound(){
  if(loadFromSDCARD(server.uri())) return;
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.println(message);
}

void setup(void){
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  //use IP or iotsharing.local to access webserver
  if (MDNS.begin("iotsharing")) {
    Serial.println("MDNS responder started");
  }
  if (!SD.begin()) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  //handle uri  
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void){
  server.handleClient();
}
  + Open web browser and type the IP address from Terminal, you will see:

Figure: esp32-tensorflowjs-squeezenet prediction

Read More

Saturday, July 6, 2019

Demo 46: How to turn ESP with a sdcard or SPIFFS to a web file server

10:11 AM 0
1. Introduction
In this post I will show you how to turn ESP with a sdcard or SPIFFS to a web file server.
Figure: ESP web file server
With this file server you can upload data to sdcard or SPIFFS or download data from sdcard or SPIFFS easily.
I am going to reuse the other posts, so you need to review them:
Demo 12: How to turn the Arduino ESP32 into a Web Server
Demo 7: How to use Arduino ESP32 to store data to sdcard
Demo 45: Copy data from/to SPIFFS without using mkspiffs (web file server)
2. Hardware
If you are using SPIFFS, you can refer Demo 45: Copy data from/to SPIFFS without using mkspiffs (web file server)
If you are using sdcard, please connect ESP with sdcard module as Demo 7: How to use Arduino ESP32 to store data to sdcard
3. Software
Here is the full source code with comments:

  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
181
182
#include <WiFiClient.h>
#include <ESP32WebServer.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include <SPI.h>
#include <mySD.h>

String serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
    "<input type='file' name='update'>"
    "<input type='submit' value='Upload'>"
"</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
"$('form').submit(function(e){"
    "e.preventDefault();"
      "var form = $('#upload_form')[0];"
      "var data = new FormData(form);"
      " $.ajax({"
            "url: '/update',"
            "type: 'POST',"               
            "data: data,"
            "contentType: false,"                  
            "processData:false,"  
            "xhr: function() {"
                "var xhr = new window.XMLHttpRequest();"
                "xhr.upload.addEventListener('progress', function(evt) {"
                    "if (evt.lengthComputable) {"
                        "var per = evt.loaded / evt.total;"
                        "$('#prg').html('progress: ' + Math.round(per*100) + '%');"
                    "}"
               "}, false);"
               "return xhr;"
            "},"                                
            "success:function(d, s) {"    
                "console.log('success!')"
           "},"
            "error: function (a, b, c) {"
            "}"
          "});"
"});"
"</script>";

const char* ssid = "TRUONG AN";
const char* password = "0909505150";

ESP32WebServer server(80);
File root;
bool opened = false;

String printDirectory(File dir, int numTabs) {
  String response = "";
  dir.rewindDirectory();
  
  while(true) {
     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       //Serial.println("**nomorefiles**");
       break;
     }
     for (uint8_t i=0; i<numTabs; i++) {
       Serial.print('\t');   // we'll have a nice indentation
     }
     // Recurse for directories, otherwise print the file size
     if (entry.isDirectory()) {
       printDirectory(entry, numTabs+1);
     } else {
       response += String("<a href='") + String(entry.name()) + String("'>") + String(entry.name()) + String("</a>") + String("</br>");
     }
     entry.close();
   }
   return String("List files:</br>") + response + String("</br></br> Upload file:") + serverIndex;
}

void handleRoot() {
  root = SD.open("/");
  String res = printDirectory(root, 0);
  server.send(200, "text/html", res);
}

bool loadFromSDCARD(String path){
  path.toLowerCase();
  String dataType = "text/plain";
  if(path.endsWith("/")) path += "index.htm";

  if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  else if(path.endsWith(".jpg")) dataType = "image/jpeg";
  else if(path.endsWith(".txt")) dataType = "text/plain";
  else if(path.endsWith(".zip")) dataType = "application/zip";  
  Serial.println(dataType);
  File dataFile = SD.open(path.c_str());

  if (!dataFile)
    return false;

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial.println("Sent less data than expected!");
  }

  dataFile.close();
  return true;
}

void handleNotFound(){
  if(loadFromSDCARD(server.uri())) return;
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.println(message);
}

void setup(void){
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  //use IP or iotsharing.local to access webserver
  if (MDNS.begin("iotsharing")) {
    Serial.println("MDNS responder started");
  }
  if (!SD.begin(26, 14, 13, 27)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  //handle uri  
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  /*handling uploading file */
  server.on("/update", HTTP_POST, [](){
    server.sendHeader("Connection", "close");
  },[](){
    HTTPUpload& upload = server.upload();
    if(opened == false){
      opened = true;
      root = SD.open((String("/") + upload.filename).c_str(), FILE_WRITE);  
      if(!root){
        Serial.println("- failed to open file for writing");
        return;
      }
    } 
    if(upload.status == UPLOAD_FILE_WRITE){
      if(root.write(upload.buf, upload.currentSize) != upload.currentSize){
        Serial.println("- failed to write");
        return;
      }
    } else if(upload.status == UPLOAD_FILE_END){
      root.close();
      Serial.println("UPLOAD_FILE_END");
      opened = false;
    }
  });
  server.begin();
  Serial.println("HTTP server started");
}

void loop(void){
  server.handleClient();
}
4. Result
Type "iotsharing.local" in web-browser you will see this.
Figure: GUI of demo

Read More

Wednesday, July 3, 2019

Demo 45: Copy data from/to SPIFFS without using mkspiffs (web file server)

7:03 AM 0
1. Introduction
This tutorial assumed that you are familiar with SPIFFS Filesystem (a file system intended for SPI NOR flash devices on embedded targets).
If you want to store small data, you can use SPIFFS instead of sdcard module.
In order to use sdcard module, refer Demo 7: How to use Arduino ESP32 to store data to sdcard
If you are using SPIFFS, you may face the inconvenient situation that you want to copy data from/to SPIFFS. You have to install ESP32FS as a plugin of Arduino-version and then do the following steps:
  + Download the ESP32FS-x.x.zip at the link.
  + Unzip and copy unziped folder to "where_to_installed_Arduino/tools/"
then it will become "where_to_installed_Arduino/tools/ESP32FS/tool/esp32fs.jarESP32FS/tool/esp32fs.jar"
  + Download mkspiffs tool at here. Unzip and copy it to "where_to_install_esp/tools"
  + Create a Sketch project named "xyz". A folder named "xyz" will be created.
  + Create a folder named "data" and copied the files that you want to copy to SPIFFS into "data" folder.
  + From Arduino menu, choose Tools > ESP32 Sketch Data Upload
Note: when copying files to SPIFFS, keep pressing the Boot button on ESP module.
This tutorial will help you to copy files from/to (2 directions) SPIFFS easier.
Figure: copy files to/from SPIFFS as Web File Server
2. Hardware
You only need a ESP32 module.
3. Software
I will use webserver to create a web file server.
Please refer Demo 12: How to turn the Arduino ESP32 into a Web Server
Here is the full source code with comments:

  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
181
182
183
184
185
186
187
188
#include <WiFiClient.h>
#include <ESP32WebServer.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include "FS.h"
#include "SPIFFS.h"

String serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
    "<input type='file' name='update'>"
    "<input type='submit' value='Upload'>"
"</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
"$('form').submit(function(e){"
    "e.preventDefault();"
      "var form = $('#upload_form')[0];"
      "var data = new FormData(form);"
      " $.ajax({"
            "url: '/update',"
            "type: 'POST',"               
            "data: data,"
            "contentType: false,"                  
            "processData:false,"  
            "xhr: function() {"
                "var xhr = new window.XMLHttpRequest();"
                "xhr.upload.addEventListener('progress', function(evt) {"
                    "if (evt.lengthComputable) {"
                        "var per = evt.loaded / evt.total;"
                        "$('#prg').html('progress: ' + Math.round(per*100) + '%');"
                    "}"
               "}, false);"
               "return xhr;"
            "},"                                
            "success:function(d, s) {"    
                "console.log('success!')"
           "},"
            "error: function (a, b, c) {"
            "}"
          "});"
"});"
"</script>";

const char* ssid = "707";
const char* password = "0000000000";
bool opened = false;
File file;

#define FORMAT_SPIFFS_IF_FAILED true
ESP32WebServer server(80);

String listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    String response = "";
    Serial.printf("Listing directory: %s\r\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("- failed to open directory");
        return "";
    }
    if(!root.isDirectory()){
        Serial.println(" - not a directory");
        return "";
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.name(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("\tSIZE: ");
            Serial.println(file.size());
            response += String("<a href='") + String(file.name()) + String("'>") + String(file.name()) + String("</a>") + String("</br>");
        }
        file = root.openNextFile();
    }
    return String("List files:</br>") + response + String("</br></br> Upload file:") + serverIndex;
}

void handleRoot() {
  String res = listDir(SPIFFS, "/", 0);
  server.send(200, "text/html", res);
}

bool loadFromSPIFFS(String path){
  String dataType = "text/plain";
  if(path.endsWith("/")) path += "index.htm";

  if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  else if(path.endsWith(".jpg")) dataType = "image/jpeg";
  else if(path.endsWith(".txt")) dataType = "text/plain";
  else if(path.endsWith(".zip")) dataType = "application/zip";  

  File dataFile = SPIFFS.open(path.c_str());

  if (!dataFile)
    return false;

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial.println("Sent less data than expected!");
  }

  dataFile.close();
  return true;
}

void handleNotFound(){
  if(loadFromSPIFFS(server.uri())) return;
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.println(message);
}

void setup(void){
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  
  //use IP or iotsharing.local to access webserver
  if (MDNS.begin("iotsharing")) {
    Serial.println("MDNS responder started");
  }
  //init spiffs
  if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
    Serial.println("SPIFFS Mount Failed");
    return;
  }
  //handle uri  
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  /*handling uploading file */
  server.on("/update", HTTP_POST, [](){
    server.sendHeader("Connection", "close");
    opened = false;
  },[](){
    HTTPUpload& upload = server.upload();
    if(opened == false){
        opened = true;
        file = SPIFFS.open(String("/") + upload.filename, FILE_WRITE);
        if(!file){
            Serial.println("- failed to open file for writing");
            return;
        }
    } 
    if(upload.status == UPLOAD_FILE_WRITE){
      if(file.write(upload.buf, upload.currentSize) != upload.currentSize){
        Serial.println("- failed to write");
        return;
      }
    } else if(upload.status == UPLOAD_FILE_END){
        opened = false;
    }
  });
  server.begin();
  Serial.println("HTTP server started");
}

void loop(void){
  server.handleClient();
}
4. Result
Type "iotsharing.local" in web-browser you will see this.
Figure: GUI of demo

Read More

Saturday, June 29, 2019

Demo 44: Play "Happy Birthday" by ESP with Sigma-delta Modulation

7:33 AM 0
1. Introduction
In this post, we will play "Happy Birthday" melody by ESP with Sigma-delta Modulation. Actually, you can use "digitalWrite" but Sigma-delta Modulation make the output smoother.
The mechanism to play melody you can find here.
2. Hardware
We will use cheap Audio Power Amplifier LM386 to aplify the melody.
Figure: LM386 Low Voltage Audio Power Amplifier
Pins are connected as:
ESP32 G27 connect LM386 IN
ESP32 5V (or 3.3 V) connect LM386 Vcc
ESP32 GND connect LM386 GND
3. Software
In order to use Sigma-delta Modulation in ESP please refer this.
Here is the full source code:
 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
int speakerPin = 27;

//"happy birthday melody notes"
char notes[] = "GGAGcB GGAGdc GGxecBA yyecdc";
int beats[] = { 2, 2, 8, 8, 8, 16, 1, 8, 2, 8, 8, 8, 16, 1, 2, 2, 8, 8, 8, 8, 16, 1, 8, 2, 8, 8, 8, 16 };

void playTone(int tone) {
  for (long i = 0; i < 100; i++) {
    sigmaDeltaWrite(0, 0);
    delayMicroseconds(tone);
    sigmaDeltaWrite(0, 100);
    delayMicroseconds(tone);
  }
}

void playNote(char note) {
  //notes
  char note_name[] = {'C',  'D',  'E',  'F',  'G',  'A',  'B',  'c',  'd',  'e',  'f',  'g',  'a',  'b', 'x',  'y' }; 
  int timeHigh[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956,  834,  765,  593,  468,  346,  224, 655 , 715 };
  // play the tone corresponding to the note name
  for (int i = 0; i < sizeof(note_name); i++) {
    if (note_name[i] == note) {
      playTone(timeHigh[i]);
    }
  }
}

void setup() {
  sigmaDeltaSetup(0, 12000);
  //attach pin speakerPin to channel 0
  sigmaDeltaAttachPin(speakerPin, 0);
  //initialize channel 0 to off
  sigmaDeltaWrite(0, 0);
}

void loop() {
  for (int i = 0; i < strlen(notes); i++) {
    // space is rest note
    if (notes[i] == ' ') {
      delay(beats[i] * 100); 
    } else {
      playNote(notes[i]);
    }
    // pause between notes
    delay(100);
  }
}
Read More

Saturday, June 15, 2019

Demo 43: How to apply Kalman Filter to ESP to make sensor measurement more accurate

8:57 AM 0
1. Introduction
Kalman filtering is an algorithm that uses a series of measurements (including statistical noise and other inaccuracies) observed over time to make estimates of unknown variables more accurate than just use a single measurement.
Figure: Blue line is sensor data from ADC with noise and Brown line is sensor data after applying Kalman Filter
In order to understand more about the equations and calculations, please refer this.
This post will make a simple demo of applying Kalman Filter to ESP to make sensor measurement from a LDR (Light Dependent Resistor) more accurate.
Figure: LDR sensor
Figure: ESP32 module
2. Hardware
ESP32 3.3V connect LDR Vcc
ESP32 GND connect LDR GND
ESP32 G34(ADC pin) connect LDR A0
3. Software
I will use the Kalman Filter here (download as zip file). The calculation of this library is similar to the reference.
In order to install downloaded zip file choose: Sketch - Include Library - Add .Zip Library.
From Library code, the constructor: "SimpleKalmanFilter(float mea_e, float est_e, float q)" where mea_e is value-initialization Ro of Rest_e is value-initialization Pko of Pk, q is value-initialization Qo of in reference. These are parameters that you need to adjust to get good result. You can try with these values to see the differences:
"SimpleKalmanFilter(3, 3, 0.09)"
"SimpleKalmanFilter(3, 3, 0.01)"
"SimpleKalmanFilter(1, 1, 0.01)"
and finally I found "SimpleKalmanFilter(2, 2, 0.01)" gave best result.
Here is the source code. You can read comments to understand.
 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
#include <SimpleKalmanFilter.h>

//the ADC pin of esp32
#define ADC_PIN 34
// update Serial Ploter every 100ms
#define UPDATE_TIME  100

long current;
//init Kalman with params, you can modify params to make better result
SimpleKalmanFilter kalman(2, 2, 0.01);

void setup() {
  Serial.begin(115200);
  Serial.print(0);  // To freeze the lower limit
  Serial.print(" ");
  Serial.print(3.3);  // To freeze the upper limit
  Serial.print(" ");
}

void loop() {
  //to make demo interesting we add random noise to measurement
  float rand_noise = random(-100,100)/100.0;
  
  // Reading LDR value, ADC of esp32 0-4095 according to 0-3.3V
  float measured_value = analogRead(ADC_PIN)/4095.0 * 3.3 + rand_noise;
  //Kalman update estimate
  float estimated_value = kalman.updateEstimate(measured_value);

  //update plotter
  if (millis() > current) {
    Serial.print(measured_value);
    Serial.print(",");
    Serial.print(estimated_value);
    Serial.println();
    
    current = millis() + UPDATE_TIME;
  }
}
4. Result
Figure: Blue line is sensor data from ADC with noise and Brown line is sensor data after applying Kalman Filter
Read More

Saturday, May 26, 2018

Demo 42: How to build an IoT Dashboard using Node-Red dashboard and ESP

4:54 AM 4
1. Introduction
In this post, we will learn how to build an IoT Dashboard using Node-Redand node-red-dashboard.
These set-up can be deployed on Raspberry Pi, Orange Pi, ... easily.
We will make a demo for this post, a simple smart home demo: a floor has 1 bulb and 1 temperature sensor. They will be control by a ESP32. This ESP32 send and receive data using MQTT protocol. A server with MQTT broker, Node-Red, NodeJS and a dashboard with a chart to monitor temperature and a switch to control the bulb.
Figure: Demo model
Note: This post will re-use the posts:
How to turn the Orange Pi/Raspberry Pi into an IoT node : To install Mosquito and use host name instead of remembering the IP address
Demo 8: How to use TCP/IP with Arduino ESP32 : part 1.2 - Introduction to Node-Red (installation and usage)
Demo 14: How to use MQTT and Arduino ESP32 to build a simple Smart home system : build a smart home using Mosquito MQTT, ESP32 MQTT.
2. node-red-dashboard
Figure: node-red-dashboard
2.1 Concepts
With this dashboard:
+ Layout will be considered as a grid. It is in Dashboard Tab.
+ A group element has a width - by default 6 'units'.
+ A unit is 48px wide by default with a 6px gap.
+ A widget in the group also has a default 'auto'. It means it will fill the width of the group contained it, or you can set it to a fixed number of units.
2.2 Features
+ Layout: Tab, Link to other web pages.
+ Theme: Light, Dark or Custom Theme.
+ Widgets include Button, Chart, Form, Gauge, Notification, Switch ...
Note: the node-red-dashboard will be deployed at: http://localhost:1880/ui (change localhost accordingly)
2.3 Installation
Note: I instaled all things on my localhost
I assume that you did install NodeJS
Then install Mosquito broker following How to turn the Orange Pi/Raspberry Pi into an IoT node
Figure: ensuare MQTT broker is running 
Then you need to install Node-Red following Demo 8: How to use TCP/IP with Arduino ESP32 - part 1.
Then install node-red-dashboard. It requires Node-RED version 0.14 or more recent. Open Terminal and typing commands:
cd ~/.node-red
npm i node-red-dashboard
Then run Node-Red from Terminal using command:
node-red
You will see:
Figure: Node-Red started
Now open your web browser and go to the link http://127.0.0.1:1880/
If you use MDNS as in How to turn the Oavahi-daemonrange Pi/Raspberry Pi into an IoT node.
You will see:
Figure: left side is widgets area, right side is layout area, middile is working space of node-red-dashboard
3. Hardware
2 modules ESP32, an Raspberry Pi or Orange Pi or PC. I will use a Led for testing and generate temperature randomly.
4. Software:
We define MQTT topics and values:
    + For Led: "floor1/led" with value false-off, true-on
    + For temerature: "floor1/temp" with value is an integer or string
4.1 Node-Red side
The steps to create our model on Node-Red:
Step 1: Create 2 tabs (when deploying real website, it becomes 1 menu - 2 categories) standing for 2 floors.
Step 2: Create Tab 1 - Floor 1 has 2 groups: Group 1 contains 1 switch, Group 2 contains 1 chart.
Step 3: Create Tab 2 - Floor 2 has 2 groups: Group 1 contains 1 switch, Group 2 contains 1 Gauge.
Just follow red boxes and steps in order number.
 Figure: Node-Red GUI

Figure: Create Tab 1 - Floor 1
Figure: create Floor 1-Group 1-Switch
Figure: create MQTT publish when switch is pressed
Figure: create MQTT subscribe temperature sensor floor1/temp"
Figure: create a chart

Figure: deploy our model
Open Web Browser and go to the url: http://localhost:1880/ui
Our first draft:
Figure: first draft
Do similar things for Floor 2.
Change the theme to dark:
Figure: Dark theme
Our final model:
Figure: final model
Or you can import Node-Red model from script below:
[{"id":"bc6c4c2e.077c5","type":"mqtt in","z":"d4b07266.f397","name":"","topic":"floor2/temp","qos":"2","broker":"fc2a1412.370a68","x":284.5,"y":478,"wires":[["b9eef4aa.a11648"]]},{"id":"fc2a1412.370a68","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}] 

4.2 ESP32 side
ESP32 Arduino code:
  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
#include <WiFi.h>
#include <PubSubClient.h>

/* change it with your ssid-password */
const char* ssid = "dd-wrt";
const char* password = "0000000000";
/* this is the IP of PC/raspberry where you installed MQTT Server 
on Wins use "ipconfig" 
on Linux use "ifconfig" to get its IP address */
const char* mqtt_server = "192.168.1.107";
float temperature = 0;

/* create an instance of PubSubClient client */
WiFiClient espClient;
PubSubClient client(espClient);

/*LED GPIO pin*/
const char led = 4;

/* topics */
#define TEMP_TOPIC    "floor1/temp"
#define LED_TOPIC     "floor1/led" /* true=on, false=off */

long lastMsg = 0;
char msg[20];

void receivedCallback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message received: ");
  Serial.println(topic);

  Serial.print("payload: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  /* we got '1' -> on */
  if ((char)payload[0] == 't') {
    digitalWrite(led, HIGH); 
  } else {
    /* we got '0' -> on */
    digitalWrite(led, LOW);
  }

}

void mqttconnect() {
  /* Loop until reconnected */
  while (!client.connected()) {
    Serial.print("MQTT connecting ...");
    /* client ID */
    String clientId = "ESP32Client";
    /* connect now */
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      /* subscribe topic with default QoS 0*/
      client.subscribe(LED_TOPIC);
    } else {
      Serial.print("failed, status code =");
      Serial.print(client.state());
      Serial.println("try again in 5 seconds");
      /* Wait 5 seconds before retrying */
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  /* set led as output to control led on-off */
  pinMode(led, OUTPUT);

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

  /* configure the MQTT server with IPaddress and port */
  client.setServer(mqtt_server, 1883);
  /* this receivedCallback function will be invoked 
  when client received subscribed topic */
  client.setCallback(receivedCallback);
}
void loop() {
  /* if client was disconnected then try to reconnect again */
  if (!client.connected()) {
    mqttconnect();
  }
  /* this function will listen for incomming 
  subscribed topic-process-invoke receivedCallback */
  client.loop();
  /* we measure temperature every 3 secs
  we count until 3 secs reached to avoid blocking program if using delay()*/
  long now = millis();
  if (now - lastMsg > 3000) {
    lastMsg = now;
    temperature = random(0, 40);
    if (!isnan(temperature)) {
      snprintf (msg, 20, "%lf", temperature);
      /* publish the message */
      client.publish(TEMP_TOPIC, msg);
    }
  }
}
5. Result

Read More
Thường mất vài phút để quảng cáo xuất hiện trên trang nhưng thỉnh thoảng, việc này có thể mất đến 1 giờ. Hãy xem hướng dẫn triển khai mã của chúng tôi để biết thêm chi tiết. Ðã xong