14. Interface and Application Programming

On this week I learned how to create an interface using QT Designer and how to connect this interface to a microcontroller. To fully understand this week, you should check the week13. This week uses Serial communication beetween the interface and the microcontroller. To visit the group website, click here. Finally, for this week, you should install QT Designer and Python, to install Python, you can check the tutorial on my week11.

QT Designer

Qt Designer is part of Qt, which is a very popular, cross-platform graphical user interface (GUI) builder tool for applications with highly customizable interfaces. Qt Designer makes it very easy for a designer to define and even lay out the user interfaces of a program easily using the drag-and-drop interface, making the difficult task of creating complex designs quite easy. It supports all types of widgets: buttons to text fields and even layout managers. It can be easily added to the interface of an application. Designed UI can be saved in XML format, which can later be converted into Python or C++ code, therefore providing a versatile tool for quick prototyping to production-quality application development. One of its main features, Qt Designer, can be applied in several development environments including PyQt and PySide for Python and Qt for C++. This will allow developers to tap fully into components offered from a broad Qt library: internationalization, accessibility, and multimedia formats support. The Qt Designer provides features of signal editing, slot editing, and property editing. It offers support for custom widgets; it is a complete tool that lets the developers design user interfaces that are much more exact and functional. The Qt Designer is still the tool of choice for crafting clean, professional applications that run on any platform from desktop to mobile to embedded.

These are the parts of the QT Designer Interface. Each part is very important because it contains useful tools for the development of the interface:

  1. Main Toolbar: Pointed by the red arrow, this part provides quick access to commonly used actions, such as creating a new form, opening an existing form, saving, and switching between design and preview modes. It also includes buttons for aligning and distributing widgets.
  2. Widget Box: Pointed by the yellow arrow, it contains a list of all the widgets that can be used to build the interface. Widgets are grouped into categories such as Buttons, Display Widgets, Item Views, Containers, etc. Users can drag and drop these widgets to add them to the interface.
  3. Form Edito: Pointed by the purple arrow, this is the central part of the interface. This part is where developers can drop the widgets allowing to place and resize each widget.
  4. Property Editor: Pointed by the pink arrow, this is the part displays the properties of the currently selected widget. It allows to view and modify widget size, font, color, and behavior properties.
  5. Object Inspector: Pointed by the blue arrow, it provides a hierarchical view of all the widgets and layouts. It shows the relationships between widgets.

My Interface

I don't have a lot of experience using QT Designer and making interfaces, so I did something simple but useful. For this interface I used 3 horizontal sliders that would control the 3 different color (RGB) of a Neopixel LED. The interface design was very simple, it has the 3 sliders for the colors, 3 boxes to indicate which slider controls each color, and finally a button for saving the combination of colors.

For changing the style of any of the components, you can right click them and go to "ChangestyleSheet". This option will open a CSS code to modify the component.

Now, I am going to explain how I created my interface:

  • Background: The first thing I did, was creating a label used to change the background color.
  • Button: Now, I added the tittle using a text label an I added the "save" button. I added a style to this button in order to have a little click animation.
  • Sliders: Then, I added a label that will have inside the 3 horizontal sliders used for the color changing. These sliders doesn't have any stylesheet, but I changed the maximun and minimun values.
  • Colors: Finally, I added another label with 3 boxes that represents each of the RGB colors. This boxes are only used to know which color intensity you are changing.

Qt Designer will save the interface with a ".ui" extension. To connect the interface to a microcontroller, we will need to convert the interface to a ".py" extension. To do this, we will need to open the terminal, go to our interface folder and use the command "pip install PyQt6 pyserial". All the commands used on this section need Python installed, so if you don't have it, install it now!!

Once we install PyQt6 on the folder, it is time to convert the interface to Python. To do this, we used the followin command: "pyuic6 -x interface.ui -o interface.py". The Python file will be on the same folder of the ".ui" and will have the name you used on the command. To simulate the interface on the Python file, we can use the command "python interface.py" or "py interface.py".

If you change anything about the interface, you will have to convert the interface back to python using the aforementioned command, by doing this you will lose all the changes you have made. To avoid this, we will create another Python file in the same folder with the name "app.py" where we will paste this code:


from interfaz import *

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, *args, **kwargs):
        QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
        self.setupUi(self)
        # The Logic


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

In the code above, there is a part where it says "The Logoc", in that part is where we are going to use the Serial communication to control our PCB. Now, I am going to explain both of my codes. The Python one (the interface) and the Arduino one (the PCB).

Python Code:

    
    	self.serial = serial.Serial('COM22',9600)
            self.sld_red.sliderMoved.connect(self.sldred)
            self.sld_green.sliderMoved.connect(self.sldgreen)
            self.sld_blue.sliderMoved.connect(self.sldblue)
            self.btn_save.clicked.connect(self.sendColors)
    	
  • Setup: First, I set which of my computer's USB port will be used (the one that has connected the microcontroller). And the, I called four different functions. The only function necessary is the last one.
  • 
    	def sldred(self):
            sld_red = self.sld_red.value()
            print(sld_red)
        
        def sldgreen(self):
            sld_green = self.sld_green.value()
            print(sld_green)
    
    	...
    	
  • Sliders Function: For testing purposes, I created 3 different functions (one for eeach color) in whisch I read the value of the slider, I save that value on a variable and I print that variable. This was only to see if I was receiving the correect values from the interface.
  • 
    	def sendColors(self):
            red_value = self.sld_red.value()
            green_value = self.sld_green.value()
            blue_value = self.sld_blue.value()
            self.serial.write(f"{red_value},{green_value},{blue_value}\n".encode())
    	
  • Sending Colors Function: This was the most confusing part od the code. This function, saves each slider value on a different variable, it package all this values in a string separated with commas, and it sends that string to the microcontroller.

Arduino Code:

    
    #include < Adafruit_NeoPixel.h >
    
    #define PIN 12         // Define el pin para el LED NeoPixel
    int Power = 11;
    #define NUMPIXELS 1    // Número de píxeles NeoPixel
    String String_received="0";
    
    Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);		
    		
  • Library and Variables: First, I included the Adafruit Neopixel library. This will allow an easy LED Neopixel control. I also defined the LED Neopixel pin, the power pin (necessary to use the Xiao's Neopixel), the number of Neopixels (in this case only 1), the string used for the sliders and the setting for the Adafruit library.
  • 
    void setup() {
      pixels.begin();           
      Serial.begin(9600);   
      pinMode(Power,OUTPUT);
      digitalWrite(Power, HIGH);
    
    }
    		
  • Setup: On this part, I initialized the Neopixel and the Serial communication. I also defined the Power pin as an output to send it voltage (allowing the Neopixel to function).
  • 
    void loop() {
      if (Serial.available() > 0) {
        // Espera a recibir datos del formato "R,G,B\n"
        String_received = Serial.readStringUntil('\n');
        int firstCommaIndex = String_received.indexOf(',');
        int lastCommaIndex = String_received.lastIndexOf(',');
    
        int red = String_received.substring(0, firstCommaIndex).toInt();
        int green = String_received.substring(firstCommaIndex + 1, lastCommaIndex).toInt();
        int blue = String_received.substring(lastCommaIndex + 1).toInt();
    
        // Establece el color del primer pixel
        pixels.setPixelColor(0, pixels.Color(red, green, blue));
        pixels.show();  // Actualiza el color en los LEDs
        Serial.print(String_received);
    
      }
      Serial.print(String_received);
    }
    		
  • The Loop: I started checking if there was any data available on the serial port. If I detect data, I read it until I encounter a newline character ('\n'), which means the end of an RGB data transmission. I get the values for red, green, and blue from the string, using commas as delimiters to find the start and end of each number. I convert these string segments into integer numbers and assign them to different variables. Using these values, I set the color of the NeoPixel and updated the LED's state to display the new color. Finally, I send back the received data through the serial port for testing purposes.

Result

This is a video of the final result:

For finishing this week, I connected a Neopixel to my final project's PCB in order to complete all the tasks, the only change I made on the code was the Neopixel pin changing it to 3. Here are the photo of the PCB and its video working with the Neopixel (I connected the neopixel to one of the servo pins):

To download the files used for this week, you can click here.

Get in touch

Follow