Python interface

From Rsewiki
Revision as of 20:29, 29 November 2020 by S192320 (Talk | contribs)

Jump to: navigation, search

Qt GUI interface design

The Regbot desktop application is designed using the Qt-Designer app which uses the widgets from the Qt GUI framework. The application gives a possibility to quickly build interfaces using the drag-and-drop feature for placing necessary components in your interface. The Qt designer produces .ui files that can be translated to C++ or Python interface code. This user interface was designed using Python 3.7.9 and Qt version 5. To some extent, it was possible to use Visual Studio, but I ran into some problems with finding the necessary libraries for some tasks I wanted to use (like cv2, keyboard and some PyQT libraries). A Safe choice was to use one Python development platform on your PC, for example, Spyder (as it was necessary to use this for other courses).

UI.JPG

The translated UI file will be autogenerated with all the parameters that were set in Qt-Designer app like - object name, size, and many other parameters that correspond to each specific object. At first, to use Qt-Designer version 5 with python it is necessary to install the necessary python packages:

# Installing PyQt5 package
pip install pyqt5-tools
pip install pyqt5

After installing and designing your user-interface it is necessary to convert your user interface .ui file to a .py file, that can be run in your program. The translated .ui files can be auto-generated using the following commands:

# Generating Python interface file from Qt-Designer .ui file
pyuic5 -x "filename".ui -o "filename".py

Note that this file is generated in the directory where the terminal was opened, so make sure that you know where this file is located after using this command.

In the picture below, you can see an example of an auto-generated python interface file, that can later be included in the rest of your application as a user interface. By knowing the name of the object, the actual user interface now can also be tweaked by editing the Python code.

UIpy.JPG

If this auto-generated python file is run on its own, the user interface is executed as an output of this program.

Gui.JPG

To add functionality to the object of the user interface (like buttons, checkboxes, text fields, etc.), we can attach a function to the interface object to be executed, for example, if the check box is checked, or button is pressed. This can be done by taking the user interface object in the python .py file and passing your function to it as an argument.

By running the python class script, the first function that is run is "__init__". In "__init__" usually we define all other python classes that need to be initialized and defined. The following code is a template example of how to connect the user-interface object with the function in your program. The specific object-related function (clicked, released, pressed) varies from object to object.

# self."user-interface-file"."object-name"."function".connect(self."function name")

See the example below:

Code1.JPG

Programming GUI

As the whole Regbot firmware and bridge software is already programmed (see section "Navigation box software" on the main robobot page). And accessing the local@IP port 24001 we are able to receive and send byte-type messages to the network socket. Thus, by building a GUI, it is possible to control the robot remotely, read/test sensor values, read and write robot system parameters to its configuration.

The first thing that is needed to do is install the socket library and define/initialize is the network socket (internet connection) to the robobot bridge.

# import socket
  class GUIMainWindow(QtWidgets.QMainWindow):
       socket = socket.socket()

When that is done, we connect the actual "connect" button to the connectClient() function do all the necessary steps to establish a connection with the chosen IP address. The Connect client functions

  self.ui.connect_Cmd.clicked.connect(self.connectClient)

Connectclient.JPG

The connectClient() function implementation can be seen below. To make a stable socket connection, at first, it is required to get the address information parameters like - Adress Family, Socket Type and the Adress Info (IP and port). Then using the previously extracted parameters we define the actual network socket and connect with the IP adress using socket.socket.connect(IP). If the attempt to make a connection is faulted, it is necessary to close a connection using socket.close() function. In the code below some extra functions are implemented aswell, for example to change the frame color or text in the status label to indicate that the connection has successfully been made or not.

 def connectClient(self):
       if not self.wifiConnected:
           IP = str('192.168.43.101') # Connect automatically to this address
           #IP = str(self.ui.IP_Adress_field.text()) # Manual IP adress input
           # Getting address info for the connection
           for addressInfo in socket.getaddrinfo(IP, 24001, socket.AF_UNSPEC, socket.SOCK_STREAM): 
               print("Socket Info " + str(addressInfo)) # Printing the whole adress info 
               AddresFamily = addressInfo[0] # Extracting the Adress Family type
               print("# Adress Family ", AddresFamily)
               SocketType = addressInfo[1] # Extracting the Socket Type
               print("# Socket Type " , SocketType)
               IP = addressInfo[4] # both IP and port number
               print("# IP adress and port ", IP)
           try:      
               self.socket = socket.socket(AddresFamily, SocketType, 0) # Making a actual networ socket with necessary adress parameters.
               self.socket.settimeout(5)
           except OSError as msg:
               print("# Network Connection timeout - retry")
           try:  
               self.ConsoleMessage += "Connecting to Client..."
               self.ConsoleMessagePush = True
               print("Connecting to Client...")
               self.socket.connect(IP) # Connecting to the adress
               self.wifiConnected = True
               self.setConnectFrameColor(self.ui.IP_Connect_frame,QtGui.QColor(0,255,0,255))
               self.ui.IP_NetworkStatus_label.setText('Connected')
               print("Connected")
               self.ConsoleMessage += "Network is Connected\n"
               self.ConsoleMessage += "Socket Info " + str(addressInfo) + "\n"
               self.ConsoleMessagePush = True
           except OSError as msg:
               self.socket.close() # closing the connection if faulted
               self.ui.IP_NetworkStatus_label.setText('Faulted')

In a similar fashion the Disconnect button in the GUI is connected with the disconnectClient() function. To correctly close down the connection, it is required to shut down the socket using socket.shutdow() and then close the connection using socket.close(). As one can notice, other different functions are called in disconnectClient() function, which stops other features in the programm.

 def disconnectClient(self):
       if self.wifiConnected:
           print("Disconnecting...")
           self.ui.IP_NetworkStatus_label.setText('Disconnecting')
           self.wifiConnected = False
           self.video_StopRecording()
           self.socket.shutdown(2) # Shutting down the socket
           self.socket.close() # Closing down the connection
           self.setConnectFrameColor(self.ui.IP_Connect_frame,QtGui.QColor(200,0,0,255))
           self.ui.IP_NetworkStatus_label.setText('Disconnected')
           print("Disconnected")
           self.ConsoleMessage += "Network is Disconnected\n"
           self.ConsoleMessagePush = True


The messages in the code to the socket can be written using the socket function socket.send("MESSAGE-TEXT"). The most important thing that the string message has to be converted to a type byte to be able to successfully send the message to the socket.

 def connectionWrite(self,MESSAGE):
       MESSAGE = bytes(MESSAGE, 'utf-8')
       if self.wifiConnected:
           self.socket.send(MESSAGE)
       if (self.wifiConnected):
           if (self.ui.TX_checkBox.isChecked()):
               self.ConsoleMessage += "(tx)->"+ str(MESSAGE) +'\n'
               self.ConsoleMessagePush = True
       else:
           self.ConsoleMessage += "Network not connected, could not send message -" + str(MESSAGE)
       pass

Here it is visible the GUI of the

Debugger.JPG

Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox