14. Interface and Application Programming¶
Group Assignment¶
This week, I learned how to use the Unity game engine to visualize data from a 6-DOF IMU sensor in real time, connected via Arduino. I learned how to read accelerometer and gyroscope data through the serial port and use it to control objects in a 3D scene. We created a simple environment in Unity, imported a 3D model, added physics, and wrote a control script. However, the 6 DOF IMU turned out to be not very reliable, the data was unstable and prone to drift. A 9-DOF IMU with a magnetometer would help track orientation more accurately. In the future, I’d like to use Unity not only for visualization but also as an interface for interacting with physical devices, creating simulations, and debugging prototypes.
Individual Assignment¶
I already explained the main part of the interface during the Networking and Communications week. At that time, I demonstrated how the user can interact with the system using a smartphone. The interface is based on virtual pins and connects to the ESP32-C3 via Wi-Fi. All functions were tested: the data is displayed correctly, and the control system works reliably. The interface is intuitive and fits well into the overall system logic.
Blynk IoT¶
For this, I decided to use Blynk IoT — a platform for remote control and monitoring of devices over the internet. It allows easy connection of microcontrollers, such as the ESP32, to a mobile application without the need for complex coding. With Blynk, I can create custom control interfaces (such as buttons, sliders, and charts) on my smartphone and control devices via Wi-Fi.
First, it is necessary to register on the Blynk website, download the mobile app to your phone, and most importantly, install the Blynk library in Arduino IDE to work with the code.
To do this, I opened the Arduino IDE, went to the Library Manager, typed Blynk by Volodymyr Shymanskyy in the search bar, and installed it.
To create a template in Blynk, you can use either the browser version or the mobile app. I tried both options.
Blynk App¶
I open the Blynk app on my smartphone. Since I already have an account, I simply log in by entering my credentials.
-
Create a new device. After logging in, the main screen of the app displays a “Create New Device” button. By pressing this button, I start the process of creating a new device.
-
Name the template. On the next screen, I am prompted to enter a name for my new template. I name it, for example, “ESP32c3” so I can easily identify which device I’m working with, and then press “Continue” to move to the next step.
-
Choose the tile design. Now, the app asks me to select a tile design for the device. I choose “Button”, as I want to create a button for control, but at this stage, I could also select other components, such as sliders or graphs, depending on what I need to control the device.
-
Move to the workspace. After choosing the tile design, I enter the workspace where I can configure and add additional components. The workspace shows various control elements, such as buttons, sliders, gauges, graphs, and more. I can place, move, and adjust these elements according to my needs.
-
Add components. To add a new component, I simply tap the plus sign on the green background that appears on the screen and drag the selected component to the desired location in the workspace. This allows me to quickly and easily set up the interface for controlling my device.
Since I first created the template on the website, I decided to try uploading it.
-
First, I press the +Add Device button to add a new device.
-
Then, I select the Manual from Template option because I want to upload the template I created earlier.
-
After that, I am prompted to select the template, and I choose the one I created before.
-
After selecting the template, I press on it again to confirm my choice.
-
Finally, I press the Create button to create the device with this template.
-
After pressing Create, I am redirected to the template page.
-
On this page, I click on the green icon with a key symbol, which has the Switch to Developer Zone function.
-
As I mentioned earlier, in the workspace, I add a switch to control the device.
-
At the bottom of the workspace, there is a settings icon — I click on it to configure the template.
-
The Settings window opens, where I can adjust the main parameters of the template.
-
Then there is the The Design window, where I can change the main color and add icons to the template.
-
The Datastreams window is used to add a virtual pin to the button (the name may be different because I created a new virtual pin).
-
The Code window allows me to copy the Template ID, Name, and AuthToken to add them to the code.
-
When I press the button in edit mode, the button settings window opens.
-
In this window, I can change the button’s mode: the first option is Push, where the button is active only while it’s pressed; the second option is Switch, which works like a regular toggle switch. The other two options are available in the paid version. A bit above, I can select a Virtual Pin by clicking on this field.
-
If no VDatastreams has been created yet, I can either select or create a new one right in this window by pressing + Create Virtual Pin Datastream.
-
Here, everything is similar to the web version: I enter the pin name, data type, minimum and maximum values, and the default value. After setting everything up, I press Save and go back to the button settings window.
-
This is how the button settings window looks after all the changes.
-
By clicking on Design, I can customize the appearance of the button:
-
I can add a name for the button, meaning I can set the text that will be displayed on the button in its ON and OFF states.
-
Change the text size on the button.
-
Change the button’s color.
-
After making all the changes, I press the arrow at the top of the screen to exit the edit mode and switch to working mode.
TDS Meter¶
I’m using a TDS meter that I ordered from AliExpress. This sensor is designed to measure the Total Dissolved Solids (TDS) level in water and is well-suited for projects based on Arduino and ESP32.
To display the readings from the TDS sensor, I chose the Gauge element. This element is ideal for clear data visualization, as it shows the values on a scale that updates in real time. This allows me to instantly see changes in water salinity levels without needing any additional data processing or interpretation. Such a solution makes monitoring water quality as convenient and intuitive as possible, all the necessary information is displayed directly on the smartphone screen, which is especially useful when using the system at home.
- I press the green button with the plus sign to open the interface component menu.
- From the list of available components, I select Gauge, as it’s suitable for displaying TDS readings.
- Then, I drag and drop it to the desired position on the workspace.
- After that, I tap on the component itself to open its settings and link a data source.
- In the Datastreams section, I create a new datastream through which the sensor values will be transmitted.
- Here I create a new virtual pin, set the type of data to be transmitted, specify the minimum and maximum values, and give the component a clear name.
- In the Units section, I select the measurement unit Parts Per Million (ppm), and tap the checkmark to save the parameters.
- Then I tap the component again to open its configuration settings.
- I go to the Design tab to customize the appearance of the component to match the overall style of the interface.
- There, I specify exactly what the component should display, give it a clear label, and, as mentioned earlier, adjust the color scheme according to my preferences or the visual style of the project.
Creating Calibration Solutions¶
To calibrate the TDS sensor, I prepared several solutions with different salt concentrations manually. Distilled water was used as the base, and regular table salt (NaCl) was used as the dissolved substance, as it is commonly used to simulate total dissolved solids in water.
- Base Solution – 10,000 ppm First, I prepared a stock solution with a concentration of 10,000 ppm by dissolving 1 gram of table salt in 100 grams of distilled water. This ratio corresponds to 1% or 10,000 milligrams of salt per liter (ppm).
-
Diluted Working Solutions Then, from the stock solution, I created diluted calibration solutions with the following concentrations:
-
500 ppm — 5 ml of the base solution + 95 ml of distilled water
-
1000 ppm — 10 ml of the base solution + 90 ml of distilled water
-
1500 ppm — 15 ml of the base solution + 85 ml of distilled water
-
In this way, I obtained three standard reference solutions for calibrating the sensor.
Programming Part¶
I asked ChatGPT to generate code for working with the TDS sensor, including a section that calculates a recommended calibration factor. This gave me a basic structure for the program and a starting point for fine-tuning the measurement accuracy.
Prompt
Please generate Arduino C++ code for reading a TDS sensor connected to GPIO3 on an ESP32-C3. The code must: Read the analog raw value from the sensor pin. Convert the raw ADC reading to voltage assuming a 3.3V reference voltage and a 12-bit ADC resolution (0–4095). Calculate the TDS value in ppm using a predefined calibration factor. Use a predefined known standard TDS ppm value (e.g., 1500 ppm) for calibration reference. Calculate a recommended calibration factor based on the measured voltage and the known standard value. Print to Serial Monitor every second the raw ADC value, the calculated voltage, the TDS value in ppm, and the recommended calibration factor. Include clear and detailed comments explaining each step in the code.#define TDS_PIN 3 // GPIO3 pin where the TDS sensor is connected
#define KNOWN_TDS_PPM 1500 // Known reference solution value, e.g., 1500 ppm
#define TDS_CALIBRATION_FACTOR 0.705 // Initial calibration factor to convert voltage to ppm
void setup() {
Serial.begin(115200); // Start the serial communication at 115200 baud rate
}
void loop() {
int rawValue = analogRead(TDS_PIN); // Read the raw ADC value from the TDS pin (range: 0–4095)
float voltage = rawValue * 3.3 / 4095.0; // Convert the raw ADC value to voltage (ESP32-C3 uses 3.3V ADC)
float tdsValue = (voltage * 1000.0) * TDS_CALIBRATION_FACTOR; // Calculate TDS in ppm using the calibration factor
float recommendedFactor = KNOWN_TDS_PPM / (voltage * 1000.0); // Calculate the recommended factor based on known solution
Serial.print("Raw ADC: "); // Print label for raw ADC value
Serial.print(rawValue); // Print raw ADC reading
Serial.print(" Voltage: "); // Print label for voltage
Serial.print(voltage, 3); // Print voltage with 3 decimal places
Serial.print(" V"); // Indicate voltage unit
Serial.print(" TDS: "); // Print label for TDS value
Serial.print(tdsValue); // Print calculated TDS in ppm
Serial.print(" ppm"); // Indicate ppm unit
Serial.print(" | Recommended Factor: "); // Print label for recommended calibration factor
Serial.println(recommendedFactor, 3); // Print recommended factor with 3 decimal places
delay(1000); // Wait 1 second before taking the next measurement
}
The TDS sensor is first immersed in a solution with a concentration of 500 ppm, which is one of the pre-prepared calibration solutions. After placing the sensor into the liquid, it is necessary to wait a few seconds for the readings to stabilize. This is because the sensor needs some time to adapt to the new environment and temperature of the solution before it can display more accurate values.
Before each new measurement, it is recommended to thoroughly rinse the sensor in a liquid with zero dissolved solids, that is, in distilled water. This step helps remove any residue from the previous solution from the sensor’s surface and avoids cross-contamination between measurements. Such cleaning improves the accuracy of the readings and makes the measurement process more reliable, especially when working with solutions of different concentrations.
Results¶
-
0ppm - In distilled water, the sensor shows values in the range of 3 to 9 ppm. This margin of error is considered acceptable, especially for a low-cost sensor.
-
500ppm - When placed in a 500 ppm solution, the sensor displays values in the range of 535 to 565 ppm.
-
1000ppm - In a 1000 ppm solution, the readings are approximately 705 to 765 ppm.
Conclusion¶
To display the data from the TDS meter, the Gauge element in the Blynk application was used, which allows visualizing the readings in a convenient format. This interface makes the process of monitoring water quality more accessible and understandable for the user. Thanks to this, interacting with the system becomes simpler, and the information is perceived more easily. Overall, the chosen display method helps provide a more comfortable and intuitive user experience for the project.
I was unable to calibrate the sensor with high accuracy because I prepared the calibration solutions myself. During preparation, some inaccuracies could have occurred, for example, imprecise weighing of the salt, slight deviations in water volume, or insufficient mixing. These inaccuracies might have affected the final sensor readings and reduced the calibration accuracy.
Therefore, the recommended calibration factor should be considered as an approximate guideline rather than an absolutely precise value. If higher measurement accuracy is required, it is advisable to repeat the calibration process using ready-made standard solutions with known concentrations purchased from reliable suppliers. This will help minimize errors and achieve more accurate and reproducible results when working with the sensor.