Dive-Dive-Dive! Drones for Beginners
I love drones, but I'd only ever graduated to flashing flight control software to tiny whoops and controlling them with an RC radio transmitter. Don't get me wrong, this is all kinds of awesome, but I wanted to dig a little deeper into controlling drones with computers for different sorts of applications.
Stack
I was very, very tempted to build a drone for this project. I can't recommend building a tiny whoop enough for anyone who's interested in the process, but before I got ahead of myself, I remembered this was a software project, not a hardware one. It's much easier to build on top of a platform where there is support and documentation versus needing to troubleshoot your own (in all likelihood unrefined) design.
Enter stage right, the DJI Tello. DJI literally acquired another company (Ryze) to utilise the Tello platform for education in STEM. It's small, light and most importantly, difficult to break. Pretty easy to repair as well, and for €80 on special, not badly priced!

The Tello will also allow us to use Python to interact with and control our drone. I was also tempted to see whether I could flash the Tello firmware to a tinywhoop, but for fear of integration hell, I fell back on keeping it simple.
Getting Started
First things first, I created a project folder and initiated a virtual environment for our Python project.
mkdir telloDrone
cd telloDrone
python3 -m venv telloDrone
source env/bin/activate
To clarify, we made a directory called telloDrone, navigated to it and initiated a virtual environment for our project. That last line navigates to a folder of scripts that help you control your virtual environment and calls the 'activate' script.
Once our virtual environment is active we can install a few packages we're going to need:
pip install opencv-python djitellopi pygame
Huge thank you to Damià Fuentes Escoté and the contributors who built this wrapper around the original Tello SDK.
From there, I started tinkering. After connecting my machine and the Tello over WiFi (the Tello creates its own WAN to which you connect) I checked to see if I could pull any info off the Tello with a quick script:
from djitellopy import tello
me = tello.Tello()
me.connect()
print(me.get_battery())
Which worked like a charm. The battery as a percentage is returned as a string in the console. After that it was time fly! With the built-in functions, we can take off, land and send rc commands. These commands are sent as an array of numbers that correspond to left and right, forward and backward, up and down and positive and negative yaw respectively:
from djitellopy import tello
from time import sleep
me = tello.Tello()
me.connect()
print(me.get_battery())
me.takeoff()
me.send_rc_control(0, 50, 0, 0)
sleep(2)
me.send_rc_control(0, 0, 0, 30)
sleep(2)
me.send_rc_control(0, 0, 0, 0)
sleep(2)
me.land()
From here, I wanted to see if I could get the drone to spin up, hover and touch back down using keypresses instead of pre-programmed commands. This step up would require me to keymap certain keys on my keyboard to functions associated with the Tello Package, in this case takeoff() and land().
First things first, we'd need a keypress module:
import pygame
def init():
pygame.init()
pygame.display.set_mode((400, 400))
def getKey(keyName):
ans = False
for eve in pygame.event.get():
pass
keyInput = pygame.key.get_pressed()
myKey = getattr(pygame, "K_{}".format(keyName))
if keyInput[myKey]:
ans = True
pygame.display.update()
return ans
if __name__ == "__main__":
init()
Which utilises the Pygame package to listen for keypresses and return the relevant keypress. I used this from a previous project and it produces a pretty reliable keypress module to drop into robotics projects. After which:
from djitellopy import tello
import KeyPressModule as kp
kp.init()
me = tello.Tello()
me.connect()
print(me.get_battery())
def getKeyboardInput():
if kp.getKey("l"):
me.land()
if kp.getKey("k"):
me.takeoff()
while True:
vals = getKeyboardInput()
me.send_rc_control(vals)
sleep(0.5)
We can use the "k" and "l" keys to take off and land!
From here, in order to get the Tello to move on demand, we need to set speed values for the motors. Forgive the current level of jank, some refactoring does take place in the future, but controlling a drone with a computer is just too cool to slow down.
from djitellopy import tello
import KeyPressModule as kp
from time import sleep
kp.init()
me = tello.Tello()
me.connect()
print(me.get_battery())
def getKeyboardInput():
lr, fb, ud, yv = 0, 0, 0, 0
speed = 50
if kp.getKey("LEFT"):
lr = -speed
if kp.getKey("RIGHT"):
lr = speed
if kp.getKey("DOWN"):
fb = -speed
if kp.getKey("UP"):
fb = speed
if kp.getKey("w"):
ud = speed
if kp.getKey("s"):
ud = -speed
if kp.getKey("a"):
yv = -speed
if kp.getKey("d"):
yv = speed
if kp.getKey("l"):
me.land()
if kp.getKey("k"):
me.takeoff()
return [lr, fb, ud, yv]
# RC Control Updater
while True:
vals = getKeyboardInput()
me.send_rc_control(vals[0], vals[1], vals[2], vals[3])
sleep(0.5)
by altering our speed variable, we can change how much 'whip' the control has, or how aggressively the drone responds to our commands.
So now we can fly! But right now, our drone is just a remote-control quad-copter. If we really want to control our drone, we need to control the camera. Enter OpenCV.
OpenCV is a computer vision package written in C and ported to Python, and we're going to use it to interpret the video feed from our drone. Now DJITelloPy has a built in function for turning on the camera called stream_on(), and from there we can grab that frame and render it in an OpenCV window! Voilà, we have video streaming to our machine!
from djitellopy import tello
from time import sleep
import cv2
me = tello.Tello()
me.connect()
print(me.get_battery())
me.stream_on()
while True:
img = me.get_frame_read().frame
img = cv2.resize(img, (360, 240))
cv2.imshow("Image", img)
cv2.waitKey(1)
By incorporating that into our main.py, we now have a functioning base to build on, controlling a Drone with Python.
This was a project I couldn't recommend enough to anyone getting started in Python, robotics or are just interested in a very high-level overview of how that shiny DJI Mavic actually works.
Considering I'm already using OpenCV, I think it might be time to start investigating some image recognition. In the next installment, I'm going to attempt to create a security drone that can recognise a human face.
After that, who knows, maybe that's when the robots rise up, but at least I'll have a little mate!
from djitellopy import tello
import KeyPressModule as kp
from time import sleep
import cv2
kp.init()
me = tello.Tello()
me.connect()
print(me.get_battery())
def getKeyboardInput():
lr, fb, ud, yv = 0, 0, 0, 0
speed = 50
if kp.getKey("LEFT"):
lr = -speed
if kp.getKey("RIGHT"):
lr = speed
if kp.getKey("DOWN"):
fb = -speed
if kp.getKey("UP"):
fb = speed
if kp.getKey("w"):
ud = speed
if kp.getKey("s"):
ud = -speed
if kp.getKey("a"):
yv = -speed
if kp.getKey("d"):
yv = speed
if kp.getKey("l"):
me.land()
if kp.getKey("k"):
me.takeoff()
return [lr, fb, ud, yv]
# RC Control Updater
while True:
vals = getKeyboardInput()
me.send_rc_control(vals[0], vals[1], vals[2], vals[3])
sleep(0.5)
# Stream from camera
while True:
img = me.get_frame_read().frame
img = cv2.resize(img, (360, 240))
cv2.imshow("Image", img)
cv2.waitKey(1)
For the code, I'll spin up a repo here