14. Interface and application programming
This week I made an application with GUI to send commands to my microcontroller. While it's unlikely that my final project would need an application, it was still nice to learn the very basics of PyQt as that is a powerful tool for all future python application / interface needs.
Group work
For this weeks group work we decided to work together as one group to cover more platforms and share the learnings. Each member chose atleast one way of making an application for their embedded device to communicate with.
Programming
I wanted to use python as it's both familiar and I think it makes the most sense of the options I know. For the interface I went with PyQt as that's something I have wanted to learn for a while and finally had a good motivation to do so.
So the plan is to make an application that communicates with my microcontroller.
At the end I set the program to send a '1' or a '0' to turn the LED on/off.
The microcontroller would return a more complex message "LED,0,1" or "LED,0,0"
indicating that the command has been received.
Additionally a newline symbol \n
would trigger the microcontroller
to send the status of the LED without changing it.
This allowed the program to ask for the status when needed.
Python
I had to install the following python packages
- PyQt5
- Graphical User Inteface (GUI)
- PySerial
- Serial communication with the microcontroller
- PyInstaller
- Building an executable
Before installing those I went ahead and created a python virtual environment:
Keep in mind that I'm using Windows Powershell.
So now the command line would look something like this
To deactivate the venv, just type deactivate
.
This now allows me to install whatever libraries, packages and dependencies I need for this specific project and keep them separated from other projects on my computer.
So only after that I could install the needed packages:
PyQt5
I began by swiftly going through atleast the beginning of this tutorial-
From that tutorial this example was the bare minimum to get the beginnings of an application running:
import sys
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
self.setCentralWidget(button)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Running it via python myapp.py
looked like this.
Not so breathtaking quite yet, but it's a start.
I continued the tutorial and learned things like how to add widgets like buttons or labels, and layouts to position those. Further, I learned how to connect signals from these widgets, like button presses, to my own python methods. Now I could actually make the buttons do something.
PySerial
To allow the python application to communicate with the microcontroller I used the PySerial module. From that website this short introduction was enough to know how to use it for my application.
So naturally need to instance the serial.
Then only later configure COM port and open.
And finally when disconnecting the serial.
So, how to know which COM port to use?
You could use something like the Device manager in Windows,
but PySerial happens to come with this nice tool
python -m serial.tools.list_ports
to list available ports.
Before unplugging the microcontroller:
After plugging in the microcontroller:
So now I know the port for that microcontroller on this computer is COM5.
One thing I did not figure out was how I could use this module tool from the python program. It would allow me to list the available ports as a drop-down menu in the application. However, for this I think it's sufficient to have only the number selection.
Result
Now I also have what I need to make this application. Naturally the microcontroller code was made on the side, but let's got through that after the python.
I am aware that not all the code should be under the only class, but I found that to be the quickest way to get this program together. It can always be improved later™.
So here is the entire python program:
aplikaatio.py | |
---|---|
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
|
The last addition was that timer to read the serial port.
I will present the application in a later section.
Microcontroller
Embedded programming was documented earlier in week 4. Some additional details of the serial communication were also presented on the previous week.
For this week I simply needed the microcontroller to act on predefined commands to turn on / off the NeoPixel (or other LED). There is not much new to that but I made the code myself.
Here is the finalized program on the microcontrollers side.
Also link to the code file here:
Building
Here is the link to the python code file:
This command will create an executable file (.exe on Windows) under ./dist/ directory:
It takes a moment to build. After that the .exe is all you need. The PyQt is kind of overkill for this kind of application and there is some amount of unnecessary overhead which results the application .exe file size being around 35 MB. Not huge but still too much to upload on this site.
Final result
Here is the demonstration using the built .exe file.
Notice how the led status is updated correctly upon reconnecting. Also trying to connect to an unavailable port does not cause crash. Main attraction of this simple beginnings of an application is the user experience with the buttons. Meaning, that you cannot click the wrong buttons and the buttons tell you information that you need without cluttering the window.
There was some modifications needed as the assignment required the use of a self-made pcb. In my PCB the only output I have is the IR led, so I used that. I made the changes to the code (commented) and here is a video showing it working:
End of week 14.