Skip to content

Commit

Permalink
Control the drone using pygame, python 2.7 and 3.6 compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
damiafuentes committed Nov 18, 2018
1 parent 3dc074a commit 8c40625
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 146 deletions.
78 changes: 32 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,71 +1,57 @@
# TelloSDKPy
DJI Tello drone python interface using the official [Tello SDK](https://dl-cdn.ryzerobotics.com/downloads/tello/20180910/Tello%20SDK%20Documentation%20EN_1.3.pdf). This library has been tested.
DJI Tello drone python interface using the official [Tello SDK](https://dl-cdn.ryzerobotics.com/downloads/tello/20180910/Tello%20SDK%20Documentation%20EN_1.3.pdf).
Yes, this library has been tested with the drone.
Please see [example.py](https://github.com/damiafuentes/TelloSDKPy/blob/master/example.py) for a working example controlling the drone as a remote controller with the keyboard and the video stream in a window.

## Prerequisites

You will need python-opencv and threading packages:

```
$ pip install python-opencv
$ pip install threading
$ git clone https://github.com/damiafuentes/TelloSDKPy.git
$ cd TelloSDKPy
$ pip install requirements.txt
```

## Usage
```
$ git clone https://github.com/damiafuentes/TelloSDKPy.git
```

### Simple example

```
from TelloSDKPy.tello import Tello
import cv2
import time
tello = Tello()
tello.connect()
tello.set_speed(10)
tello.streamon()
frame_read = tello.get_frame_read()
while True:
if frame_read.stopped:
frame_read.stop()
break
cv2.imshow('Augmented reality', frame_read.frame)
ccv2.waitKey(1)
if ch == ord('t'):
tello.takeoff()
if ch == ord('l'):
tello.land()
if ch == ord('a'):
tello.move_left(20)
if ch == ord('d'):
tello.move_right(20)
if ch == ord('w'):
tello.move_forward(20)
if ch == ord('d'):
tello.move_back(20)
if ch == ord('e'):
tello.rotate_counter_clockwise(450)
if ch == ord('r'):
tello.rotate_clockwise(450)
if ch == ord('f'):
tello.move_up(20)
if ch == ord('g'):
tello.move_down(20)
if ch == 27:
frame_read.stopped = True
break
tello.takeoff()
time.sleep(5)
tello.move_left(100)
time.sleep(5)
tello.rotate_counter_clockwise(45)
time.sleep(5)
tello.land()
time.sleep(5)
tello.end()
```

Note: If you are using the streamon command and the response is 'Unknown command' means you have to update the Tello firmware. That can be done through the Tello app.
### Example using pygame and the video stream
Please see [example.py](https://github.com/damiafuentes/TelloSDKPy/blob/master/example.py).

The controls are:
- T: Takeoff
- L: Land
- Arrow keys: Forward, backward, left and right.
- A and D: Counter clockwise and clockwise rotations
- W and S: Up and down.

### Note
If you are using the ```streamon``` command and the response is ```Unknown command``` means you have to update the Tello firmware. That can be done through the Tello app.

## Author

Expand Down
34 changes: 24 additions & 10 deletions decorators.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
import sys


# Decorator to check method param type, raise needed exception type
# http://code.activestate.com/recipes/578809-decorator-to-check-method-param-types/
def accepts(**types):
def check_accepts(f):
argcount = f.func_code.co_argcount
if 'self' in f.func_code.co_varnames:
if sys.version_info >= (3, 0):
fun_code = f.__code__
fun_name = f.__name__
else:
fun_code = f.func_code
fun_name = f.func_name

argcount = fun_code.co_argcount
if 'self' in fun_code.co_varnames:
argcount -= 1

s = "accept number of arguments not equal with function number of arguments in ", f.func_name, ", argcount ", argcount
s = "accept number of arguments not equal with function number of arguments in ", fun_name, ", argcount ", \
argcount
assert len(types) == argcount, s

def new_f(*args, **kwds):
for i, v in enumerate(args):
if types.has_key(f.func_code.co_varnames[i]) and \
not isinstance(v, types[f.func_code.co_varnames[i]]):
raise TypeError("arg '%s'=%r does not match %s" % \
(f.func_code.co_varnames[i], v, types[f.func_code.co_varnames[i]]))
if fun_code.co_varnames[i] in types and \
not isinstance(v, types[fun_code.co_varnames[i]]):
raise TypeError("arg '%s'=%r does not match %s" % (fun_code.co_varnames[i], v,
types[fun_code.co_varnames[i]]))

for k, v in kwds.iteritems():
if types.has_key(k) and not isinstance(v, types[k]):
for k, v in kwds.items():
if k in types and not isinstance(v, types[k]):
raise TypeError("arg '%s'=%r does not match %s" % (k, v, types[k]))

return f(*args, **kwds)

new_f.func_name = f.func_name
if sys.version_info >= (3, 0):
new_f.__name__ = fun_name
else:
new_f.func_name = fun_name
return new_f

return check_accepts
206 changes: 154 additions & 52 deletions example.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,158 @@
from TelloSDKPy.tello import Tello
import time
import cv2
import pygame
from pygame.locals import *
import numpy as np
import time

# Speed of the drone
S = 60
# Frames per second of the pygame window display
FPS = 25


class FrontEnd(object):
""" Maintains the Tello display and moves it through the keyboard keys.
Press escape key to quit.
The controls are:
- T: Takeoff
- L: Land
- Arrow keys: Forward, backward, left and right.
- A and D: Counter clockwise and clockwise rotations
- W and S: Up and down.
"""

def __init__(self):
# Init pygame
pygame.init()

# Creat pygame window
pygame.display.set_caption("Tello video stream")
self.screen = pygame.display.set_mode([960, 720])

# Init Tello object that interacts with the Tello drone
self.tello = Tello()

# Drone velocities between -100~100
self.for_back_velocity = 0
self.left_right_velocity = 0
self.up_down_velocity = 0
self.yaw_velocity = 0
self.speed = 10

self.send_rc_control = False

# create update timer
pygame.time.set_timer(USEREVENT + 1, 50)

def run(self):

if not self.tello.connect():
print("Tello not connected")
return

if not self.tello.set_speed(self.speed):
print("Not set speed to lowest possible")
return

# In case streaming is on. This happens when we quit this program without the escape key.
if not self.tello.streamoff():
print("Could not stop video stream")
return

if not self.tello.streamon():
print("Could not start video stream")
return

frame_read = self.tello.get_frame_read()

should_stop = False
while not should_stop:

for event in pygame.event.get():
if event.type == USEREVENT + 1:
self.update()
elif event.type == QUIT:
should_stop = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
should_stop = True
else:
self.keydown(event.key)
elif event.type == KEYUP:
self.keyup(event.key)

if frame_read.stopped:
frame_read.stop()
break

self.screen.fill([0, 0, 0])
frame = cv2.cvtColor(frame_read.frame, cv2.COLOR_BGR2RGB)
frame = np.rot90(frame)
frame = pygame.surfarray.make_surface(frame)
self.screen.blit(frame, (0, 0))
pygame.display.update()

time.sleep(1 / FPS)

# Call it always before finishing. I deallocate resources.
self.tello.end()

def keydown(self, key):
""" Update velocities based on key pressed
Arguments:
key: pygame key
"""
if key == pygame.K_UP: # set forward velocity
self.for_back_velocity = S
elif key == pygame.K_DOWN: # set backward velocity
self.for_back_velocity = -S
elif key == pygame.K_LEFT: # set left velocity
self.left_right_velocity = -S
elif key == pygame.K_RIGHT: # set right velocity
self.left_right_velocity = S
elif key == pygame.K_w: # set up velocity
self.up_down_velocity = S
elif key == pygame.K_s: # set down velocity
self.up_down_velocity = -S
elif key == pygame.K_a: # set yaw clockwise velocity
self.yaw_velocity = -S
elif key == pygame.K_d: # set yaw counter clockwise velocity
self.yaw_velocity = S

def keyup(self, key):
""" Update velocities based on key released
Arguments:
key: pygame key
"""
if key == pygame.K_UP or key == pygame.K_DOWN: # set zero forward/backward velocity
self.for_back_velocity = 0
elif key == pygame.K_LEFT or key == pygame.K_RIGHT: # set zero left/right velocity
self.left_right_velocity = 0
elif key == pygame.K_w or key == pygame.K_s: # set zero up/down velocity
self.up_down_velocity = 0
elif key == pygame.K_a or key == pygame.K_d: # set zero yaw velocity
self.yaw_velocity = 0
elif key == pygame.K_t: # takeoff
self.tello.takeoff()
self.send_rc_control = True
elif key == pygame.K_l: # land
self.tello.land()
self.send_rc_control = False

def update(self):
""" Update routine. Send velocities to Tello."""
if self.send_rc_control:
self.tello.send_rc_control(self.left_right_velocity, self.for_back_velocity, self.up_down_velocity,
self.yaw_velocity)


def main():
frontend = FrontEnd()

# run frontend
frontend.run()


def start():
start_time = time.time()

tello = Tello()

if not tello.connect():
print("%s, Not connected" % (time.time() - start_time))
return

if not tello.streamon():
print("%s, Could not start video stream" % (time.time() - start_time))
return

frame_read = tello.get_frame_read()

while True:
if frame_read.stopped:
frame_read.stop()
break

cv2.imshow('Augmented reality', frame_read.frame)

ch = cv2.waitKey(1)
if ch == ord('t'):
tello.takeoff()
if ch == ord('l'):
tello.land()
if ch == ord('a'):
tello.move_left(20)
if ch == ord('d'):
tello.move_right(20)
if ch == ord('w'):
tello.move_forward(20)
if ch == ord('d'):
tello.move_back(20)
if ch == ord('e'):
tello.rotate_counter_clockwise(450)
if ch == ord('r'):
tello.rotate_clockwise(450)
if ch == ord('f'):
tello.move_up(20)
if ch == ord('g'):
tello.move_down(20)
if ch == 27:
frame_read.stopped = True
break

tello.end()


start()
if __name__ == '__main__':
main()
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
numpy==1.15.4
opencv-python==3.4.3.18
pygame==1.9.4
Loading

0 comments on commit 8c40625

Please sign in to comment.