The development of a harmful gas leak detector is a critical safety measure in various environments, including industrial workplaces and residential areas. This comprehensive guide will provide you with a detailed walk through on how to construct a gas leak detector using an Arduino Nano 33 BLE Sense, a Blues Notecard Wi-Fi, Edge Impulse, and a gas sensor.
Required Components1. Arduino Nano 33 BLE Sense: This is a compact yet powerful board that is perfect for IoT projects due to its flexibility and robust capabilities.
2. Blues Notecard WiFi: This device is designed to provide secure and reliable communication with the cloud, making it an essential component for IoT projects.
3. Edge Impulse: This is a leading platform for developing machine learning models for edge devices. It provides a user-friendly interface and a wide range of tools for data collection, model training, and deployment.
4. Gas Sensor (MiCS-4514): This is a robust sensor capable of detecting a variety of harmful gases. Its versatility makes it ideal for a wide range of applications.
Step 1: Hardware AssemblyThe first step in building your gas leak detector is to connect the MiCS-4514 gas sensor to the Arduino Nano 33 BLE Sense. The MiCS-4514 is a versatile gas sensor that can detect a wide range of gases, including methane, ethanol, hydrogen, ammonia, carbon monoxide, and nitrogen dioxide. This broad detection range makes it an excellent choice for a gas leak detector.
Gas sensor and Blues notecard can work with IIC communication.
Once your hardware is set up, the next step is to collect data samples. These samples should represent a range of gas levels, from normal to dangerous. This data will be used to train a machine learning model on Edge Impulse. The goal is to create a model that can accurately recognize harmful gas levels based on the data from the gas sensor.
1. Begin by uploading the acquisition script to your Arduino BLE 33 Sense.
2. Position the sensor unit in close proximity to the gas or substance you wish to detect.
3. Open the serial monitor. At this point, you should observe multiple gas sensor values displayed as CSV records.
4. Make sure to deselect the timestamp option.
5. Proceed to copy the data displayed on the serial monitor screen and paste it into a text file.
6. Save this text file as harmful.csv.
7. Add the following header to your file:
[ timestamp, CO2avg, C2H5OHavg, H2avg, NH3avg, CO2min, C2H5OHmin, H2min, NH3min, CO2max, C2H5OHmax, H2max, NH3max ]
8. Repeat this process for each gas you intend to detect.
Step 3: Implementing Machine Learning with Edge Impulse
After collecting your data, you can upload it to Edge Impulse Studio.
Here, you can use the platform’s tools to train a neural network classifier.
This trained model will empower your device to identify harmful gas levels within a remarkably short time frame of 5 seconds.
This rapid detection capability is crucial for ensuring timely responses to gas leaks.
Once your model is trained and validated, you can deploy it to your edge device. Edge Impulse provides a variety of deployment options, including Arduino, WebAssembly, and standalone C++ libraries.
After downloading the EI library, import the library to Arduino IDE.
Step 4: Configuring the Blue Wi-Fi NotecardThe Blue Wi-Fi Notecard plays a crucial role in your gas leak detector. It is responsible for transmitting the sensor data to the cloud. This data can then be accessed and analysed remotely, providing valuable insights into the gas levels in the monitored area. The Blue Wi-Fi Notecard can also receive instructions from the cloud server, allowing it to control various parameters of the gas leak detector.
Blues Notehub is a cloud service that securely sends and receives data, provides a console for fleet management, and secure connectors for routing data to 3rd-party cloud applications. Here’s a step-by-step guide on how to create a new project on Blues Notehub.
Create a Notehub AccountFirst, navigate to Notehub.io and sign up. You can either create an account using your email or sign up using GitHub.
After signing up, verify your email address by clicking on the link in the email you receive from support@blues.io.
Once your account is verified, you’re ready to create your first project. Projects are core to the functionality of Notehub as they provide a way to organise fleets of devices, distribute firmware, organise teams, and provide team access controls.
To create a new project, follow these steps:
1. Click on the “Create Project” button in the upper right corner.
2. The “Create Project” dialog will open.
3. Provide a name for the project in the “Project Name” input box.
4. Provide a unique identifier for the default ProductUID. Note: The ProductUID must be globally unique. To reduce collisions, Notehub prepends a generated namespace based on your account email.
5. Click the “Create Project” button.
After setting up the system, it’s crucial to test its functionality. You should expose the system to various gas levels and observe the readings on the serial port. The port should indicate any high sensor readings and alert you if a gas leak is detected. This testing phase is crucial for ensuring that your gas leak detector is working correctly and is ready for deployment.
Upload this following sketch in the Arduino Nano 33 BLE sense, change the Product ID, WiFi name and Password in the script.
#include "DFRobot_MICS.h"
#include <Gas_Leak_Detector_inferencing.h>
#include <SPI.h>
#include <Wire.h>
#include <Notecard.h>
#define usbSerial Serial
#ifndef PRODUCT_UID
#define PRODUCT_UID "xxxxxxxxxxxxxxxxx" // "com.my-company.my-name:my-project"
#pragma message "PRODUCT_UID is not defined in this example. Please ensure your Notecard has a product identifier set before running this example or define it in code here. More details at https://dev.blues.io/tools-and-sdks/samples/product-uid"
#endif
#define myProductID PRODUCT_UID
Notecard notecard;
#define CALIBRATION_TIME 3
#define Mics_I2C_ADDRESS ADDRESS_0
DFRobot_MICS_I2C mics(&Wire, 0x75);
# define ADC_PIN A0
# define POWER_PIN 10
# define pinBuzzer 2
int measuresNumber = 4;
int measuresCounter = 0;
int measuresTimeFrame = 1500; // 1.5 seconds
float defaultMin = 50000;
int printReadings = 1;
float scoreLimit = 0.80;
String line1 = "";
String line2 = "";
float co2Sum = 0;
float ch4Sum = 0;
float c2H5OHSum = 0;
float h2Sum = 0;
float nh3Sum = 0;
float no2Sum = 0;
float co2Min = defaultMin;
float ch4Min = defaultMin;
float c2H5OHMin = defaultMin;
float h2Min = defaultMin;
float nh3Min = defaultMin;
float no2Min = defaultMin;
float co2Max = 0;
float ch4Max = 0;
float c2H5OHMax = 0;
float h2Max = 0;
float nh3Max = 0;
float no2Max = 0;
float co2Avg = 0;
float ch4Avg = 0;
float c2H5OHAvg = 0;
float h2Avg = 0;
float nh3Avg = 0;
float no2Avg = 0;
float myScoreHarmful = 0;
float myScoreRegular = 0;
// Axis array
float features[18];
int raw_feature_get_data(size_t offset, size_t length, float *out_ptr) {
memcpy(out_ptr, features + offset, length * sizeof(float));
return 0;
}
void init1() {
J *req = notecard.newRequest("card.wifi");
if (myProductID[0])
{
JAddStringToObject(req, "ssid", "xxxxxx");
JAddStringToObject(req, "password", "12341234");
}
notecard.sendRequestWithRetry(req, 5); // 5 seconds
}
void setup()
{
// wait for serial
Serial.begin(115200);
Serial.println("------------------------------------");
while (!mics.begin()) {
Serial.println("No gas sensor detected");
delay(1000);
} Serial.println("Gas sensor connected");
uint8_t mode = mics.getPowerState();
if (mode == SLEEP_MODE) {
mics.wakeUpMode();
Serial.println("Wake up sensor success");
} else {
Serial.println("The sensor is waking up");
}
while (!mics.warmUpTime(CALIBRATION_TIME)) {
Serial.println("Calibrating...");
delay(1000);
}
delay(2000);
// Set up for debug output (if available).
#ifdef usbSerial
usbSerial.begin(115200);
const size_t usb_timeout_ms = 3000;
for (const size_t start_ms = millis(); !usbSerial && (millis() - start_ms) < usb_timeout_ms;)
;
notecard.setDebugOutputStream(usbSerial);
#endif
notecard.begin();
init1();
J *req = notecard.newRequest("hub.set");
if (myProductID[0])
{
JAddStringToObject(req, "product", myProductID);
}
JAddStringToObject(req, "mode", "continuous");
notecard.sendRequestWithRetry(req, 5); // 5 seconds
}
void loop()
{
if (measuresCounter == measuresNumber) {
// reached limit, make calculations and inference
measuresCounter = 0;
// average
co2Avg = co2Sum / measuresNumber;
ch4Avg = ch4Sum / measuresNumber;
c2H5OHAvg = c2H5OHSum / measuresNumber;
h2Avg = h2Sum / measuresNumber;
nh3Avg = nh3Sum / measuresNumber;
no2Avg = no2Sum / measuresNumber;
// normalize min
if (co2Min == defaultMin) {
co2Min = 0;
};
if (ch4Min == defaultMin) {
ch4Min = 0;
};
if (c2H5OHMin == defaultMin) {
c2H5OHMin = 0;
};
if (h2Min == defaultMin) {
h2Min = 0;
};
if (nh3Min == defaultMin) {
nh3Min = 0;
};
if (no2Min == defaultMin) {
no2Min = 0;
};
// send to inference
features[0] = co2Avg;
features[1] = ch4Avg;
features[2] = c2H5OHAvg;
features[3] = h2Avg;
features[4] = nh3Avg;
features[5] = no2Avg;
features[6] = co2Min;
features[7] = ch4Min;
features[8] = c2H5OHMin;
features[9] = h2Min;
features[10] = nh3Min;
features[11] = no2Min;
features[12] = co2Max;
features[13] = ch4Max;
features[14] = c2H5OHMax;
features[15] = h2Max;
features[16] = nh3Max;
features[17] = no2Max;
Serial.println("Gas readings ok");
if (sizeof(features) / sizeof(float) != EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE) {
ei_printf("The size of your 'features' array is not correct. Expected %lu items, but had %lu\n",
EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, sizeof(features) / sizeof(float));
delay(1000);
return;
}
ei_impulse_result_t result = { 0 };
// the features are stored into flash, and we don't want to load everything into RAM
signal_t features_signal;
features_signal.total_length = sizeof(features) / sizeof(features[0]);
features_signal.get_data = &raw_feature_get_data;
// invoke the impulse
EI_IMPULSE_ERROR res = run_classifier(&features_signal, &result, false /* debug */);
ei_printf("run_classifier returned: %d\n", res);
if (res != 0) return;
// print the predictions
ei_printf("Predictions ");
ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
result.timing.dsp, result.timing.classification, result.timing.anomaly);
ei_printf(": \n");
ei_printf("[");
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
ei_printf("%.5f", result.classification[ix].value);
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf(", ");
#else
if (ix != EI_CLASSIFIER_LABEL_COUNT - 1) {
ei_printf(", ");
}
#endif
}
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf("%.3f", result.anomaly);
#endif
ei_printf("]\n");
myScoreRegular = 0;
myScoreHarmful = 0;
// human-readable predictions
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
if (result.classification[ix].label == "regular") {
myScoreRegular = result.classification[ix].value;
}// regular
if (result.classification[ix].label == "harmful") {
myScoreHarmful = result.classification[ix].value;
} // harmful
} // iterate labels
if (myScoreRegular > scoreLimit) {
J *req = notecard.newRequest("note.add");
if (req != NULL)
{
JAddBoolToObject(req, "sync", true);
J *body = JAddObjectToObject(req, "body");
if (body != NULL)
{
JAddStringToObject(body, "State", "Harmful Gas Detected");
JAddNumberToObject(body, "Harm_Score", 100);
}
notecard.sendRequest(req);
}
delay(5000);
}
#if EI_CLASSIFIER_HAS_ANOMALY == 1
ei_printf(" anomaly score: %.3f\n", result.anomaly);
#endif
delay(2000);
// reset counters
co2Sum = 0;
ch4Sum = 0;
c2H5OHSum = 0;
h2Sum = 0;
nh3Sum = 0;
no2Sum = 0;
co2Min = defaultMin;
ch4Min = defaultMin;
c2H5OHMin = defaultMin;
h2Min = defaultMin;
nh3Min = defaultMin;
no2Min = defaultMin;
co2Max = 0;
ch4Max = 0;
c2H5OHMax = 0;
h2Max = 0;
nh3Max = 0;
no2Max = 0;
delay(measuresTimeFrame);
}
else
{
// increase sample counter
measuresCounter++;
// gets data from sensor
float co2data = mics.getGasData(CO);
float ch4data = mics.getGasData(CH4);
float c2H5OHdata = mics.getGasData(C2H5OH);
float h2data = mics.getGasData(H2);
float nh3data = mics.getGasData(NH3);
float no2data = mics.getGasData(NO2);
// sum to calculate average
co2Sum = co2Sum + co2data;
ch4Sum = ch4Sum + ch4data;
c2H5OHSum = c2H5OHSum + c2H5OHdata;
h2Sum = h2Sum + h2data;
nh3Sum = nh3Sum + nh3data;
no2Sum = no2Sum + no2data;
if (printReadings == 1) {
Serial.println("----------------------- Plain Readings " + String(measuresCounter));
Serial.print(co2data);
Serial.print(",");
Serial.print(ch4data);
Serial.print(",");
Serial.print(c2H5OHdata);
Serial.print(",");
Serial.print(h2data);
Serial.print(",");
Serial.print(nh3data);
Serial.print(",");
Serial.print(no2data);
Serial.println("");
} // print readings
// higher than max
if (co2data > co2Max) {
co2Max = co2data;
}
if (ch4data > ch4Max) {
ch4Max = ch4data;
}
if (c2H5OHdata > c2H5OHMax) {
c2H5OHMax = c2H5OHdata;
}
if (h2data > h2Max) {
h2Max = h2data;
}
if (nh3data > nh3Max) {
nh3Max = nh3data;
}
if (no2data > no2Max) {
no2Max = no2data;
}
// lower than min
if (co2data > 0 and (co2data < co2Min)) {
co2Min = co2data;
}
if (ch4data > 0 and (ch4data < ch4Min)) {
ch4Min = ch4data;
}
if (c2H5OHdata > 0 and (c2H5OHdata < c2H5OHMin)) {
c2H5OHMin = c2H5OHdata;
}
if (h2data > 0 and (h2data < h2Min)) {
h2Min = h2data;
}
if (nh3data > 0 and (nh3data < nh3Min)) {
nh3Min = nh3data;
}
if (no2data > 0 and (no2data < no2Min)) {
no2Min = no2data;
}
}
delay(measuresTimeFrame / measuresNumber);
}
Once uploading the code, try to test the unit. Here is the serial terminal response when the harmful gas is detected.
And here is the notehub response.
To share the data to external services we can use Blues Route service.
We can use General HTTP service to share the data. For that use Webhooks.
Next, enter the credentials on the Blues Route page.
Then look at the events page, we can see the green check box, which shows all the routes are working fine.
Now, we can see all the Blues data in the Webhook page.
In addition to this data, we can add Twilio sms triggers to notify the users. Follow this tutorial to learn more about Twilio integration with Blues Notehub.
Creating a harmful gas leak detector using the Arduino Nano 33 BLE Sense, Blue Wi-Fi Notecard, Edge Impulse, and a gas sensor is not only a practical project but also a significant contribution to safety in homes and industries. With the integration of machine learning, this system can swiftly and accurately detect harmful gases, providing a reliable solution for monitoring air quality.
Comments