Skip to content

    Embedded code

    The main embedded code is written in an Arduino sketch file (.ino). This is then supplemented by classes from C++ files.

    Class diagram

    classDiagram
        class main {
            + setup()
            + network_task()
            + loop()
            + get_servo_position(std::vector*) : uint8_t
            + handle_detection(detector& , int , CRGB)
            + get_question_id() : int
            + update_answers(int, std::vector* ) : bool
            + check_selected_question(int)
        }
    
        class network {
            + wifi_connect(uint8_t)
            + data_send(bool, const char*): int
            + data_receive(const char*): DynamicJsonDocument
        }
    
        class detector {
            - uint8_t cup_pin
            - bool current_state
            - bool last_state
    
            - get_pin(): uint8_t
    
            + detector(uint8_t)
            + get_current_state(): bool
            + detect_state_change(): bool
        }
    
        class indicator {
            - int led_pin
            - setup()
    
            + set_color(CRGB color, int time)
        }
    
        class lcd {
            + setup()
            + lcd_printer()
            + lcd_clear()
    
        }
    
        class buzzer {
            + setup()
            + play_sound(int)
        }
    
        detector --> main
        network --> main
        indicator --> main
        lcd --> main
        buzzer --> main
    
    

    main.ino

    This serves as the main program that runs on the ESP32-S3. This includes a couple of functions.

    Libraries

    All libraries which are included in the main.ino file, excluding our own classes and standard Arduino library. | Name | Description | | -------- | -------------------------------------------- | | vector | Used for making a vector, which acts as a dynamic array | | ESP32Servo | Used for controlling a servo, special library for ESP32 |

    Example import
    1
    2
    #include <vector>
    #include <ESP32Servo.h>
    

    get_servo_position()

    This function calculates the servo position based on the amount of yes/no answers the device has detected. Since our servo can move 0-180 degrees, the function returns a number between 0-180.

    It does this by taking a vector of answers, which are simply zeroes or ones (1 means YES answers, and 0 means NO answers). It parses through this vector and calculates the percentage of YES answers. This percentage is used to return a number between 0-180 for the servo position.

    Parameters
    DatatypeNameDescription
    std::vector<int>*answersPointer to the vector containing yes/no answers
    Returns
    DatatypeDescription
    uint8_tThe servo position, integer between 0-180
    Example usage
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include <ESP32Servo.h>
    #include <vector>
    
    Servo servo;
    std::vector<int> answers; // Stores answers
    
    servo.attach(SERVO_PIN);
    
    while(true) {
        if (yes_detected) {
            answers.push_back(1); // 1 = yes
        }
    
        if (no_detected){
            answers.push_back(0); // 0 = no
        }
    
        servo.write(get_servo_position(&answers));
    }
    

    handle_detection()

    This function contains the actions which are performed when a cup is dropped into the device. So it checks if the conditions of the detector are met and then it plays a sound on the buzzer, changes the lights,adds an answer to the vector and sends the answer to the database.

    Parameters
    DatatypeNameDescription
    &detectordetectorPointer to the detector object.
    intanswerAnswer that should be given YES (1) or NO (0).
    CRBGcolorThe color of the LED strip which should be played during detection.
    Returns

    void

    Example usage
     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
    #include "include/detector.h"
    #include "include/network.h"
    #include "include/indicator.h"
    #include "include/buzzer.h"
    #include <vector>
    
    std::vector<int> answers;
    
    // Initialize cup detectors
    detector yes_detector = detector(YES_DETECTOR_PIN);
    detector no_detector = detector(NO_DETECTOR_PIN);
    
    // Initialize buzzer
    buzzer buzz = buzzer(BUZZER_PIN);
    
    // Initialize network
    network nwork;
    
    // Initialize led indicator, pin number is defaulted to 47 in the class.
    indicator led_indicator(LED_STRIP);
    
    loop() {
        // Handle YES/NO answer detection
        handle_detection(yes_detector, 1, CRGB::Green);
        handle_detection(no_detector, 0, CRGB::Red);
    }
    

    get_question_id()

    This function makes a request to the backend to get the ID of the selected question. It then returns this integer.

    Parameters

    void

    Returns
    DatatypeDescription
    intID of selected question
    Example usage
    1
    2
    3
    #include "include/network.h"
    
    int current_question_id = get_question_id();
    

    update_answers()

    This function clears the vector of answers, and fills this vector with answers stored in database. These answers are the answers already given to the selected question. It takes a pointer to the answer vector, and the stored id of the selected question as parameters. It returns a true if it has succeeded with this task.

    Parameters
    DatatypeNameDescription
    intquestion_idInteger which is the ID of the selected question
    std::vector<int>*answersPointer to the vector containing yes/no answers
    Returns
    DatatypeDescription
    boolBoolean if the update was successful.
    Example usage
    1
    2
    3
    4
    5
    6
    7
    8
    #include "include/network.h"
    
    std::vector<int> answers;
    
    do {
        // Update all answers corresponding to the question.
        answer_get_success = update_answers(question_id, &answers);
    } while (!answer_get_success);
    

    check_selected_answer()

    This function makes a call to get the ID of the selected question, and checks if this has changed with the given ID. If this has changed it will use update_answers() to fetch the answers associated with the selected question.

    Parameters
    DatatypeNameDescription
    intquestion_idInteger which is the ID of the selected question
    Returns

    void

    Example usage
    1
    2
    3
    4
    5
    6
    #include "include/network.h"
    
    for (;;) {
        check_selected_question(&question_id);
        delay(5000);
    }
    

    Classes

    detector class

    This class initializes an object to detect a single cup. This is then used to detect if a cup is passed through at a predefined place. It takes a GPIO pin number as a parameter in the constructor.

    To do this it makes use of an infrared beam break sensor. This sensor consists of a infrared receiver and transmitter. This receiver is connected to a digital input with a pull up resistor, which gives a boolean value.

    Note

    In our implementation this class is used for the infrared beam break sensor. However it is not exclusive to this sensor, and can be used by any type of digital input, for example a button.

    Libraries

    none

    get_pin()

    This function gives the GPIO pin number of the specific object. This can be used for debugging.

    Parameters

    void

    Returns
    DatatypeDescription
    uint8_tthe pin number of the sensor

    get_current_state()

    This function gives the current state of the receiver. It returns the boolean value. False (0) means that the beam is broken, and true (1) means that the beam is unbroken.

    Parameters

    void

    Returns
    DatatypeDescription
    boolThe status of the sensor.

    detect_state_change()

    In our implementation the state change of the receiver is important, since it indicates if a cup is moved between the sensor. This function check for a change in the state, and returns true if the state has changed.

    Parameters

    void

    Returns
    DatatypeDescription
    boolBoolean if the state of the pin has changed.

    Example usage

    To demonstrate the basic usage of this class, see the code example below:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    #include "Arduino.h"
    #include "include/detector.h"
    
    // Make objects for each cup,
    // specify the GPIO pin in the constructor
    detector cup1 = detector(2);
    detector cup2 = detector(4);
    
    // Uses the 'detect_state_change' function to detect change in sensor state (0 or 1)
    if (cup1.detect_state_change()) {
        // do something, for example, print current sensor state.
        Serial.println(cup1.get_current_state());
    }
    

    network class

    This class will serve the purpose to handle all network communications from and to the arduino device. It will use HTTP to call upon scripts or websites. The wifi module will start and manage the WiFi connection. It uses the WiFi manager library to function.

    Libraries

    NameDescription
    ArduinoJsonUsed for JSON serialization and deserialization
    WifiManagerUsed for initializing WiFi connection
    HTTPClientUsed for making HTTP requests
    Example import
    1
    2
    3
    #include <ArduinoJson.h>
    #include <WiFiManager.h>
    #include <HTTPClient.h>
    

    wifi_connect()

    This function makes use of the WiFi manager to connect to a WiFi network

    Parameters

    void

    Returns

    void

    data_send()

    This function will enable the user to send data to a php script elsewhere. The data will be sent as a JSON object and will send an answer to the project backend, which is 0 or 1. If this function fails in sending the file or fails in general it will return a status message and it will print output in the serial bus with the baud speed of 9600.

    Parameters
    DatatypeNameDescription
    boolanswerDefines if answer is yes (1) or no(0).
    const char*url_sendURL to send data to.
    Returns
    DatatypeDescription
    intInteger representing status of the send request.

    The integers that are returned are the following: | Return | Action | Reason | | -------- | ------------------ | ------------------------------- | | 1 | Message delivered | - | | 0 | Error with sending | issue with php or json | | -1 | General Error | Possibly no internet connection |

    data_receive()

    The receive function will GET a json object from an outside script. This function will return a dynamic JSON file which contains all the information. One can use the dynamic file to read out the contents straight to an int or string. These can be used in other function calls or any other purpose where a normal value is required. It will return a nullpointer when it fails so that the code will continue to run.

    Parameters
    DatatypeNameDescription
    const char*url_receiveURL to receive data from.
    Returns
    DatatypeDescription
    DynamicJsonDocumentDynamicJsonDocument containing received data.

    Example Usage

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    #include "Arduino.h"
    #include "include/network.h"
    
    // please provide valid paths to the php scripts.
    network example_name;
    
    example_name.wifi_connect(); // To enable wifi connection
    
    // To send data to a php script
    example_name.data_send(true, "url_here");
    
    // To receive data and create an json object out of it
    example_name.data_receive("url_here");
    

    indicator Class

    This class will enable the device to toggle LEDs on a led strip using a single pin to send and toggle color data.

    Note

    The pin can't be changed to a new pin unless changed in the class itself.

    Libraries

    NameDescription
    FastLEDUsed for controlling different types of LEDs
    Example import
    1
    #include <FastLED.h>
    

    set_color()

    This function will enable the user to pick a color the LEDs must show. The user is also able to add a time greater than 0 to trigger a small animation.

    Parameters
    DatatypeNameDescription
    CRGBcolorThe color to set the LED strip (using CRGB from FastLED).
    inttimeThe duration in milliseconds for which the color should be displayed.
    Returns

    void

    Example Usage

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include "include/indicator.h"
    
    indicator led_indicator(LED_STRIP_PIN);
    
    void loop() {
        led_indicator.setColor(CRGB::Blue, 110); // Turns leds blue with intervals of 110ms between each led.
        delay(500);
        led_indicator.setColor(CRGB::Black, 0); // Black turns leds off.
    }
    

    lcd class

    This class is used to display messages about on the LCD screen. It can turn the LCD on and print messages on the LCD in a user friendly way.

    Note

    The class lcd is made, but not actually used in the latest version of the product. This can be used to implement a LCD in the future

    Libraries

    NameDescription
    LiquidCrystal_I2CUsed for controlling I2C LCD displays
    Example import
    1
    #include <LiquidCrystal_I2C.h>
    

    setup()

    This function initializes the LCD and turns the backlight on.

    Parameters

    void

    Returns

    void

    lcd_printer()

    This function prints a defined message on the LCD. This function uses pagination in order to display messages that are longer than 32 characters. Something that is also used is proper word splitting in order to improve the user experience. Essentially, normally a sentence at the end of a row will be cut-off in the middle of a word. This is not user-friendly, which is why this method will split the row properly at the end of a word.

    Parameters
    DatatypeNameDescription
    StringmessageThe message to be displayed
    Returns

    void

    lcd_clear()

    This function clears all the text from the LCD display

    Parameters

    void

    Returns

    void

    Example usage

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    #include "include/lcd.h"
    
    // Initialize the object
    lcd lcd_example;
    
    // Initialize the LCD and turn the backlight on
    lcd_example.setup();
    
    // Splits a specific message into proper rows and prints the message onto the LCD using pagination and proper word splitting
    lcd_example.lcdPrinter("Hello World");
    

    buzzer class

    This class is used to play different melodies on a buzzer. The melody will change depending on if the user voted "Yes" or "No". Other notes are already defined in case we want to change the melodies. The GPIO pin is given in the constructor

    Libraries

    NameDescription
    ToneESP32Used for playing tones on the ESP32

    Note

    This class makes use of the ToneESP32 library, since it would otherwise interfere with the servo. With this library we can use a different hardware timer for the buzzer. Normal tone would work as well on the ESP32.

    Example import
    1
    #include <ToneESP32.h>
    

    play_sound()

    Plays one of the two pre-defined melodies depending on the given parameter. 1 is for the melody if the user voted "Yes". 0 is for the melody if the user voted "No". This method uses a standard note length and delay for now.

    Parameters
    DatatypeNameDescription
    intanswerThe answer given, which indicates the specific melody to be played
    Returns

    void

    Example usage

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include "include/buzzer.h"
    
    // Initialize the object
    buzzer buzz = buzzer(BUZZER_PIN);
    
    if (yes_detected) {
        // Plays melody for YES
        buzzer.play_sound(1);
    }