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 | |
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
| Datatype | Name | Description |
|---|---|---|
std::vector<int>* | answers | Pointer to the vector containing yes/no answers |
Returns
| Datatype | Description |
|---|---|
uint8_t | The 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 | |
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
| Datatype | Name | Description |
|---|---|---|
&detector | detector | Pointer to the detector object. |
int | answer | Answer that should be given YES (1) or NO (0). |
CRBG | color | The 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 | |
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
| Datatype | Description |
|---|---|
int | ID of selected question |
Example usage
1 2 3 | |
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
| Datatype | Name | Description |
|---|---|---|
int | question_id | Integer which is the ID of the selected question |
std::vector<int>* | answers | Pointer to the vector containing yes/no answers |
Returns
| Datatype | Description |
|---|---|
bool | Boolean if the update was successful. |
Example usage
1 2 3 4 5 6 7 8 | |
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
| Datatype | Name | Description |
|---|---|---|
int | question_id | Integer which is the ID of the selected question |
Returns
void
Example usage
1 2 3 4 5 6 | |
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
| Datatype | Description |
|---|---|
uint8_t | the 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
| Datatype | Description |
|---|---|
bool | The 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
| Datatype | Description |
|---|---|
bool | Boolean 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 | |
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
| Name | Description |
|---|---|
| ArduinoJson | Used for JSON serialization and deserialization |
| WifiManager | Used for initializing WiFi connection |
| HTTPClient | Used for making HTTP requests |
Example import
1 2 3 | |
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
| Datatype | Name | Description |
|---|---|---|
bool | answer | Defines if answer is yes (1) or no(0). |
const char* | url_send | URL to send data to. |
Returns
| Datatype | Description |
|---|---|
int | Integer 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
| Datatype | Name | Description |
|---|---|---|
const char* | url_receive | URL to receive data from. |
Returns
| Datatype | Description |
|---|---|
DynamicJsonDocument | DynamicJsonDocument containing received data. |
Example Usage
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
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
| Name | Description |
|---|---|
| FastLED | Used for controlling different types of LEDs |
Example import
1 | |
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
| Datatype | Name | Description |
|---|---|---|
CRGB | color | The color to set the LED strip (using CRGB from FastLED). |
int | time | The duration in milliseconds for which the color should be displayed. |
Returns
void
Example Usage
1 2 3 4 5 6 7 8 9 | |
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
| Name | Description |
|---|---|
| LiquidCrystal_I2C | Used for controlling I2C LCD displays |
Example import
1 | |
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
| Datatype | Name | Description |
|---|---|---|
String | message | The 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 | |
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
| Name | Description |
|---|---|
| ToneESP32 | Used 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 | |
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
| Datatype | Name | Description |
|---|---|---|
int | answer | The answer given, which indicates the specific melody to be played |
Returns
void
Example usage
1 2 3 4 5 6 7 8 9 | |