This project is a mobile Drone Remote Controller that sends commands to a fixed wing plane using a web server. The mobile app was developed in Python, and all the codes are in the main.py
file in the kivi_app/
directory.
After cloning the repository, cd
into the kivi_app/
directory and create a venv
in the directory. Install the requirements.txt
using pip
. This requirements.txt
contains all the dependencies necessary to run the app directly using Python
. However, the goal is to run the mobile version of the app, thus the next step discusses how to build the mobile android app. If you intend to test the app directly on the desktop, you should leave the address of the web server as it is in the main.py
file as shown below to use the localhost address.
url = f'http://localhost:8000/{route}' # address of localhost
Before attempting to build the mobile app, ensure to change the web server's address in line 167 in the main.py
file to use the alias address of the localhost as shown below:
url = f'http://10.0.2.2:8000/{route}' # alias address of localhost
To build the Kivy app for Android and test it on an Android Studio emulator, you will need to use the Buildozer
tool. Buildozer is a tool for packaging Kivy apps for mobile devices. Buildozer tool is part of the packages in the requirements.txt
file that was installed earlier so you do not have to install it again. The kivi_app
directory has already been initialized and the configuration spec
to build the android app has been created which is the buildozer.spec
file.
To build the app for Android, run the following command:
buildozer android debug deploy run
This will build an APK file, deploy it to a connected Android device or emulator, and run it.
To run the app on the Android Studio emulator, first start the emulator from Android Studio. Then, after the Buildozer command completes, you can manually install the generated APK on the emulator using the adb
command-line tool:
adb install bin/yourpackagename-debug.apk
Replace <yourpackagename>
with the package name generated in the bin/
directory.
Once the APK is installed, you can find your app in the app drawer of the emulator and run it like any other Android app.
The app is already configured to be able to connect to the web server through the alias
address of the localhost
address, thus no any other configuration is needed to be done on the emulator side. We tested the mobile app using Nexus 5 API 28 emulator on Android Studio, hence we recommend testing the app using thesame.
Before you begin, ensure that you have a macOS machine with the latest version of Xcode installed. Also, make sure you have Homebrew installed.
-
Install autoconf, automake and libtool:
brew install autoconf automake libtool pkg-config
-
Install Kivy-ios:
pip install kivy-ios
-
Create a new directory where you want to place the Kivy-ios build and navigate into it:
mkdir kivy-ios-build cd kivy-ios-build
-
Use Kivy-ios to create a new Xcode project:
toolchain create <YourProjectName> <path/to/your/main.py>
Replace
<YourProjectName>
with the name you want to give your project and<path/to/your/main.py>
with the path to your main.py file. -
Build your Xcode project:
cd <YourProjectName> open <YourProjectName>.xcodeproj
This will open your project in Xcode.
-
Ensure that the web server's address in
line 167
in themain.py
file is set to use the alias address of the localhost as shown below, as iOS simulator doesn't support10.0.2.2
(alias for Android emulator):url = f'http://localhost:8000/{route}' # alias address of localhost
-
In Xcode, select an iOS simulator from the target dropdown and click the 'Run' button. This will launch the iOS simulator and run your app.
Please note that Kivy-ios doesn't support all Kivy modules. If your app uses a module that isn't supported, you'll need to build a recipe for it. A recipe is a set of instructions that tells Kivy-ios how to build a module. This can be a complex process and is beyond the scope of this document.
The web server was implemented using Flask. To setup and test the web server use the following steps below after cloning the repo:
- Create a Python virtual environment
python3 -m venv venv
- Activate the environment
source venv/bin/activate
- Install the dependecies in the requirements file
pip install -r requirements.txt
- Start the Flask server by running the
main.py
file. Note that the Flask server is configured to useport 8000
, thus the server would run onhttp://localhost:8000
. You can change it if necessary. To run the web server, use the command below:
python3 server.py
- When the user click the "Arm Drone" button, the application sends a HTTP request to the web server.
- The server processes the request and sends it to the drone and returns a success or failure response to the app.
- There is also a
text label
at the top of the mobile app that displays messages to the user from the web server. - Ensure to click the
Arm Drone
button on the mobile app to arm the drone before trying to use any of thecontrols
button. If a user tries to use the controls without arming the drone, the app informs the user to arm the drone first before attempting to fly the drone. - At the top right corner of the app screen, there are buttons to set the
step-sizes
for percentage increase/decrease of the individual control surfaces. - All the controls such as
throttle
,elevator
,rudder
, andaileron
have been implemented.
The drone used in this project is the ArduPilot simulated drone. The simulator has to be running first and the drone shown on the map, before attempting to arm the drone from the mobile application. Remember to ensure that the web server is also running as it serves as the intermediary between the mobile app and the drone.
The server provides a simple API for controlling the SITL drone using a web service. The following routes are supported for controlling the drone.
Arms the drone.
- status: "success" or "error"
- message: A string describing the result of the operation
Sets the aileron control surface.
- aileron: Integer (0-100) representing the percentage of aileron control
- status: "success" or "error"
- message: A string describing the result of the operation
Sets the elevator control surface.
- elevator: Integer (0-100) representing the percentage of elevator control
- status: "success" or "error"
- message: A string describing the result of the operation
Sets the throttle control.
- throttle: Integer (0-100) representing the percentage of throttle control
- status: "success" or "error"
- message: A string describing the result of the operation
Sets the rudder control surface.
- rudder: Integer (0-100) representing the percentage of rudder control
- status: "success" or "error"
- message: A string describing the result of the operation
All control surface parameters (aileron, elevator, throttle, and rudder) must be within the range of 0 to 100, inclusive.
If a control surface parameter is out of range, the server will return an error with a status code of 400 and an error message.
If the drone is not armed, the server will return an error with a status code of 400 and an error message.
For other errors, the server will return an error with a status code of 500 and an error message.
For our app, the mobile interface basically follows this consistency rule, and the layout is clear and is composed of consistent element. All of the drone control and step size adjustment buttons have the same appearance and functionality. The button press events are handled using the same method structure, making the program predictable for the user.
For our app, the interface is quite straightforward and simple to use. Basically, this mobile app is not needed to add shortcuts. Each button is focused on single function and is located at index interface. There are no specific keyboard shortcuts or gesture-based shortcuts implemented.
Feedback is provided through the response_label
label. Every time a request is sent to the server (e.g., to arm
the drone, change the throttle
, rudder
, elevator
, or aileron
), the response from the server is displayed in the response_label
text field.
Aside the Arming
the drone first before attempting to fly, our UI does not appear to have any dialogs or sequences of action that need to yield closure. However, we could argue that the 'Arm Drone' button could be seen as initiating a sequence, and the feedback given through the response_label
to Arm
the drone first and the response received when the drone is armed, can be seen to provide closure.
For error messages, our app provides concise messages to users. The feedback label displays messages returned from the server, which could include error messages like trying to fly the drone without arming it. However, there are no specific UI elements for handling or displaying errors, such as dialogs or pop-ups. Also, there's no much mechanism at the frontend for handling incorrect user input or invalid operations (like trying to decrease the step size below 1 or above 100 evn though this is handled implicitly to not allow the app to crash.
This principle is supported. For instance, if a user increases the throttle or any of the step-size controls and decides that was a mistake, they can easily decrease it again.
The interface supports an internal locus of control by allowing the user to directly manipulate the drone's throttle, rudder, elevator, and ailerons, and to adjust the step sizes for these controls. Users should feel in control of the system.
Our UI is relatively simple with clearly labeled controls, which helps to reduce the short-term memory load. However, a possible improvement could be to display the current settings (like the current throttle, rudder, elevator, and aileron percentages) so the user does not have to remember them.