Project tutorial
Boilarm

Boilarm

Never again do you have to check whether your water is boiling. Put on your headphones and let your phone notify you!

  • 198 views
  • 0 comments
  • 1 respect

Components and supplies

About this project

Introduction

Have you ever had to wait for your water to boil to make some pasta, but you hate waiting for it? Or, has it ever happened to you that you put the water pot on the stove, put on your headphones and forget you ever left it there? If these bring some resemblance to you then we have the perfect product for you!The Arduino BLE paired with our mobile app allows you to do other important things while the water is heating up. When the water boils, the app simply tells you that the water is boiling, even if you're in another room.So put the water on the stove, turn on our device, put on your headphones and relax. We'll take of the rest. :)

Machine Learning

If you are wondering how accurately we can know if the water is boiling, you needn't worry. Our test have shown that our model is 97.37% accurate.

We used an extensive amount of different situation to train our model to accurately recognize when the water is boiling.

How to use

It is really simple. First you need to turn on your Arduino and connect it to your phone using Bluetooth. You will see the following:

Once that is done, you can put your water to boil and leave the Arduino close to the pot as seen in the image bellow:

When the water is boiling, your phone will inform you by turning you screen red:

Enjoy your pasta!

Code

Boiling Water RecognitionArduino
This is the arduino code used to recognize if water is boiling and send the information to your phone.
#define EIDSP_QUANTIZE_FILTERBANK   0

/* Includes ---------------------------------------------------------------- */
#include <PDM.h>
#include <vrenje_vode_inference.h>
#include <ArduinoBLE.h>
#include <BLEDevice.h>

/** Audio buffers, pointers and selectors */
typedef struct {
    int16_t *buffer;
    uint8_t buf_ready;
    uint32_t buf_count;
    uint32_t n_samples;
} inference_t;

static inference_t inference;
static signed short sampleBuffer[2048];
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal
BLEDevice central;
BLEService batteryService("180F");
BLEUnsignedCharCharacteristic batteryLevelChar("2A19", BLERead | BLENotify);


/**
 * @brief      Arduino setup function
 */
void setup()
{

 
    // put your setup code here, to run once:
    Serial.begin(115200);

    Serial.println("Edge Impulse Inferencing Demo");

    // summary of inferencing settings (from model_metadata.h)
    ei_printf("Inferencing settings:\n");
    ei_printf("\tInterval: %.2f ms.\n", (float)EI_CLASSIFIER_INTERVAL_MS);
    ei_printf("\tFrame size: %d\n", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
    ei_printf("\tSample length: %d ms.\n", EI_CLASSIFIER_RAW_SAMPLE_COUNT / 16);
    ei_printf("\tNo. of classes: %d\n", sizeof(ei_classifier_inferencing_categories) / sizeof(ei_classifier_inferencing_categories[0]));

    if (microphone_inference_start(EI_CLASSIFIER_RAW_SAMPLE_COUNT) == false) {
        ei_printf("ERR: Failed to setup audio sampling\r\n");
        return;
    }

    if (!BLE.begin()) {
     Serial.println("starting BLE failed!");
     while (1);
    }
    pinMode(LED_BUILTIN, OUTPUT);
    BLE.setLocalName("Vrenje");
    BLE.setAdvertisedService(batteryService); 
    batteryService.addCharacteristic(batteryLevelChar); 
    BLE.addService(batteryService); // Add the battery service
    BLE.advertise(); 
    Serial.println("Bluetooth device active, waiting for connections...");
    while (1) {
     central = BLE.central();
     if (central) {
     Serial.print("Connected to central: ");
     Serial.println(central.address());
     digitalWrite(LED_BUILTIN, HIGH);
     break;
     }
    }


}

/**
 * @brief      Arduino main function. Runs the inferencing loop.
 */
void loop()
{
    ei_printf("Starting inferencing in 2 seconds...\n");

    delay(2000);

    ei_printf("Recording...\n");

    bool m = microphone_inference_record();
    if (!m) {
        ei_printf("ERR: Failed to record audio...\n");
        return;
    }

    ei_printf("Recording done\n");

    signal_t signal;
    signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT;
    signal.get_data = &microphone_audio_signal_get_data;
    ei_impulse_result_t result = { 0 };

    EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn);
    if (r != EI_IMPULSE_OK) {
        ei_printf("ERR: Failed to run classifier (%d)\n", r);
        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");
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
        ei_printf("    %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
    }

    // BLE:
    if ( result.classification[0].value > result.classification[1].value ) {
        if (central.connected()) batteryLevelChar.writeValue(1);
      }
    if ( result.classification[0].value < result.classification[1].value ) {
        if (central.connected()) batteryLevelChar.writeValue(0);
      }

   
    
#if EI_CLASSIFIER_HAS_ANOMALY == 1
    ei_printf("    anomaly score: %.3f\n", result.anomaly);
#endif
}

/**
 * @brief      Printf function uses vsnprintf and output using Arduino Serial
 *
 * @param[in]  format     Variable argument list
 */
void ei_printf(const char *format, ...) {
    static char print_buf[1024] = { 0 };

    va_list args;
    va_start(args, format);
    int r = vsnprintf(print_buf, sizeof(print_buf), format, args);
    va_end(args);

    if (r > 0) {
        Serial.write(print_buf);
    }
}

/**
 * @brief      PDM buffer full callback
 *             Get data and call audio thread callback
 */
static void pdm_data_ready_inference_callback(void)
{
    int bytesAvailable = PDM.available();

    // read into the sample buffer
    int bytesRead = PDM.read((char *)&sampleBuffer[0], bytesAvailable);

    if (inference.buf_ready == 0) {
        for(int i = 0; i < bytesRead>>1; i++) {
            inference.buffer[inference.buf_count++] = sampleBuffer[i];

            if(inference.buf_count >= inference.n_samples) {
                inference.buf_count = 0;
                inference.buf_ready = 1;
                break;
            }
        }
    }
}

/**
 * @brief      Init inferencing struct and setup/start PDM
 *
 * @param[in]  n_samples  The n samples
 *
 * @return     { description_of_the_return_value }
 */
static bool microphone_inference_start(uint32_t n_samples)
{
    inference.buffer = (int16_t *)malloc(n_samples * sizeof(int16_t));

    if(inference.buffer == NULL) {
        return false;
    }

    inference.buf_count  = 0;
    inference.n_samples  = n_samples;
    inference.buf_ready  = 0;

    // configure the data receive callback
    PDM.onReceive(&pdm_data_ready_inference_callback);

    // optionally set the gain, defaults to 20
    PDM.setGain(80);
    PDM.setBufferSize(4096);

    // initialize PDM with:
    // - one channel (mono mode)
    // - a 16 kHz sample rate
    if (!PDM.begin(1, EI_CLASSIFIER_FREQUENCY)) {
        ei_printf("Failed to start PDM!");
        microphone_inference_end();

        return false;
    }

    return true;
}

/**
 * @brief      Wait on new data
 *
 * @return     True when finished
 */
static bool microphone_inference_record(void)
{
    inference.buf_ready = 0;
    inference.buf_count = 0;

    while(inference.buf_ready == 0) {
        delay(10);
    }

    return true;
}

/**
 * Get raw audio signal data
 */
static int microphone_audio_signal_get_data(size_t offset, size_t length, float *out_ptr)
{
    numpy::int16_to_float(&inference.buffer[offset], out_ptr, length);

    return 0;
}

/**
 * @brief      Stop PDM and release buffers
 */
static void microphone_inference_end(void)
{
    PDM.end();
    free(inference.buffer);
}

#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_MICROPHONE
#error "Invalid model for current sensor."
#endif
Android App APK
This is the APK required to install the app on your Android phone

Schematics

Schematic
Only a Bluetooth connection is needed.
Schematic gaqykghba9

Comments

Similar projects you might like

BeeMonitor

Project tutorial by Team 🐬 Delfinčki 🐬

  • 6,295 views
  • 1 comment
  • 16 respects

Text Teleporter

Project tutorial by Advik Singhania

  • 4,059 views
  • 8 comments
  • 5 respects

Infrared Remote

Project tutorial by 4 developers

  • 6,892 views
  • 0 comments
  • 37 respects

4x4x4 LED cube with Arduino Uno and 1sheeld

Project tutorial by Hassan Ibrahim

  • 42,964 views
  • 6 comments
  • 72 respects

Control Arduino Robot Arm with Android App

Project tutorial by Slant Concepts

  • 30,864 views
  • 8 comments
  • 44 respects
Add projectSign up / Login