Skip to content

Commit

Permalink
tello drone tutorials
Browse files Browse the repository at this point in the history
  • Loading branch information
ufuk23 committed May 20, 2021
0 parents commit bf25368
Show file tree
Hide file tree
Showing 11 changed files with 651 additions and 0 deletions.
42 changes: 42 additions & 0 deletions ayncIO.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import asyncio
from threading import Thread
import cv2 # requires python-opencv
from tello_asyncio import Tello, VIDEO_URL
import time
##############################################################################
# drone control in worker thread

def fly():
async def main():
drone = Tello()
try:
await drone.connect()
await drone.start_video()
#await drone.takeoff()
#await drone.turn_clockwise(360)
#await drone.land()
time.sleep(20)
finally:
await drone.stop_video()
await drone.disconnect()

asyncio.run(main())

fly_thread = Thread(target=fly, daemon=True)
fly_thread.start()

##############################################################################
# Video capture and GUI in main thread

capture = cv2.VideoCapture(VIDEO_URL)
capture.open(VIDEO_URL)

while True:
grabbed, frame = capture.read()
if grabbed:
cv2.imshow('tello-asyncio', frame)
if cv2.waitKey(1) != -1:
break

capture.release()
cv2.destroyAllWindows()
13 changes: 13 additions & 0 deletions djiTello.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from djitellopy import tello
import cv2

me = tello.Tello()
me.connect()
print(me.get_battery())

me.streamon()

while True:
img = me.get_frame_read().frame
cv2.imshow("Image", img)
cv2.waitKey(1)
18 changes: 18 additions & 0 deletions easyTelloTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import speech_recognition as sr
import os
from easytello import tello
import time


drone = tello.Tello()

#drone.land()

print("land")
#drone.takeoff()
time.sleep(3)

print("land")

# Turning on stream
drone.streamon()
267 changes: 267 additions & 0 deletions keyboardTello.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
"""
tellopy sample using keyboard and video player
Requires mplayer to record/save video.
Controls:
- tab to lift off
- WASD to move the drone
- space/shift to ascend/descent slowly
- Q/E to yaw slowly
- arrow keys to ascend, descend, or yaw quickly
- backspace to land, or P to palm-land
- enter to take a picture
- R to start recording video, R again to stop recording
(video and photos will be saved to a timestamped file in ~/Pictures/)
- Z to toggle camera zoom state
(zoomed-in widescreen or high FOV 4:3)
"""

import time
import sys
import tellopy
import pygame
import pygame.display
import pygame.key
import pygame.locals
import pygame.font
import os
import datetime
from subprocess import Popen, PIPE
# from tellopy import logger

# log = tellopy.logger.Logger('TelloUI')

prev_flight_data = None
font = None
wid = None
date_fmt = '%Y-%m-%d_%H%M%S'

def toggle_recording(drone, speed):
global video_recorder
global date_fmt
if speed == 0:
return

if video_recorder:
# already recording, so stop
video_recorder.stdin.close()
status_print('Video saved to %s' % video_recorder.video_filename)
video_recorder = None
return

# start a new recording
filename = '%s/Pictures/tello-%s.mp4' % (os.getenv('HOME'),
datetime.datetime.now().strftime(date_fmt))
video_recorder = Popen([
'mencoder', '-', '-vc', 'x264', '-fps', '30', '-ovc', 'copy',
'-of', 'lavf', '-lavfopts', 'format=mp4',
# '-ffourcc', 'avc1',
# '-really-quiet',
'-o', filename,
], stdin=PIPE)
video_recorder.video_filename = filename
status_print('Recording video to %s' % filename)

def take_picture(drone, speed):
if speed == 0:
return
drone.take_picture()

def palm_land(drone, speed):
if speed == 0:
return
drone.palm_land()

def toggle_zoom(drone, speed):
# In "video" mode the drone sends 1280x720 frames.
# In "photo" mode it sends 2592x1936 (952x720) frames.
# The video will always be centered in the window.
# In photo mode, if we keep the window at 1280x720 that gives us ~160px on
# each side for status information, which is ample.
# Video mode is harder because then we need to abandon the 16:9 display size
# if we want to put the HUD next to the video.
if speed == 0:
return
drone.set_video_mode(not drone.zoom)
pygame.display.get_surface().fill((0,0,0))
pygame.display.flip()

controls = {
'w': 'forward',
's': 'backward',
'a': 'left',
'd': 'right',
'space': 'up',
'left shift': 'down',
'right shift': 'down',
'q': 'counter_clockwise',
'e': 'clockwise',
# arrow keys for fast turns and altitude adjustments
'left': lambda drone, speed: drone.counter_clockwise(speed*2),
'right': lambda drone, speed: drone.clockwise(speed*2),
'up': lambda drone, speed: drone.up(speed*2),
'down': lambda drone, speed: drone.down(speed*2),
'tab': lambda drone, speed: drone.takeoff(),
'backspace': lambda drone, speed: drone.land(),
'p': palm_land,
'r': toggle_recording,
'z': toggle_zoom,
'enter': take_picture,
'return': take_picture,
}

class FlightDataDisplay(object):
# previous flight data value and surface to overlay
_value = None
_surface = None
# function (drone, data) => new value
# default is lambda drone,data: getattr(data, self._key)
_update = None
def __init__(self, key, format, colour=(255,255,255), update=None):
self._key = key
self._format = format
self._colour = colour

if update:
self._update = update
else:
self._update = lambda drone,data: getattr(data, self._key)

def update(self, drone, data):
new_value = self._update(drone, data)
if self._value != new_value:
self._value = new_value
self._surface = font.render(self._format % (new_value,), True, self._colour)
return self._surface

def flight_data_mode(drone, *args):
return (drone.zoom and "VID" or "PIC")

def flight_data_recording(*args):
return (video_recorder and "REC 00:00" or "") # TODO: duration of recording

def update_hud(hud, drone, flight_data):
(w,h) = (158,0) # width available on side of screen in 4:3 mode
blits = []
for element in hud:
surface = element.update(drone, flight_data)
if surface is None:
continue
blits += [(surface, (0, h))]
# w = max(w, surface.get_width())
h += surface.get_height()
h += 64 # add some padding
overlay = pygame.Surface((w, h), pygame.SRCALPHA)
overlay.fill((0,0,0)) # remove for mplayer overlay mode
for blit in blits:
overlay.blit(*blit)
pygame.display.get_surface().blit(overlay, (0,0))
pygame.display.update(overlay.get_rect())

def status_print(text):
pygame.display.set_caption(text)

hud = [
FlightDataDisplay('height', 'ALT %3d'),
FlightDataDisplay('ground_speed', 'SPD %3d'),
FlightDataDisplay('battery_percentage', 'BAT %3d%%'),
FlightDataDisplay('wifi_strength', 'NET %3d%%'),
FlightDataDisplay(None, 'CAM %s', update=flight_data_mode)
]

def flightDataHandler(event, sender, data):
global prev_flight_data
text = str(data)
if prev_flight_data != text:
update_hud(hud, sender, data)
prev_flight_data = text

def videoFrameHandler(event, sender, data):
global video_player
global video_recorder
if video_player is None:
cmd = [ 'mplayer', '-fps', '35', '-really-quiet' ]
if wid is not None:
cmd = cmd + [ '-wid', str(wid) ]
video_player = Popen(cmd + ['-'], stdin=PIPE)

try:
video_player.stdin.write(data)
except IOError as err:
status_print(str(err))
video_player = None

try:
if video_recorder:
video_recorder.stdin.write(data)
except IOError as err:
status_print(str(err))
video_recorder = None

def handleFileReceived(event, sender, data):
global date_fmt
# Create a file in ~/Pictures/ to receive image data from the drone.
path = '%s/Pictures/tello-%s.jpeg' % (
os.getenv('HOME'),
datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S'))
with open(path, 'wb') as fd:
fd.write(data)
status_print('Saved photo to %s' % path)

def main():
pygame.init()
pygame.display.init()
pygame.display.set_mode((1280, 720))
pygame.font.init()

global font
font = pygame.font.SysFont("dejavusansmono", 32)

global wid
if 'window' in pygame.display.get_wm_info():
wid = pygame.display.get_wm_info()['window']
print("Tello video WID:", wid)

drone = tellopy.Tello()
drone.connect()
# drone.start_video()
drone.subscribe(drone.EVENT_FLIGHT_DATA, flightDataHandler)
# drone.subscribe(drone.EVENT_VIDEO_FRAME, videoFrameHandler)
drone.subscribe(drone.EVENT_FILE_RECEIVED, handleFileReceived)
speed = 30

try:
while 1:
time.sleep(0.01) # loop with pygame.event.get() is too mush tight w/o some sleep
for e in pygame.event.get():
# WASD for movement
if e.type == pygame.locals.KEYDOWN:
print('+' + pygame.key.name(e.key))
keyname = pygame.key.name(e.key)
if keyname == 'escape':
drone.quit()
exit(0)
if keyname in controls:
key_handler = controls[keyname]
if type(key_handler) == str:
getattr(drone, key_handler)(speed)
else:
key_handler(drone, speed)

elif e.type == pygame.locals.KEYUP:
print('-' + pygame.key.name(e.key))
keyname = pygame.key.name(e.key)
if keyname in controls:
key_handler = controls[keyname]
if type(key_handler) == str:
getattr(drone, key_handler)(0)
else:
key_handler(drone, 0)
except e:
print(str(e))
finally:
print('Shutting down connection to drone...')
drone.quit()
exit(1)

if __name__ == '__main__':
main()
16 changes: 16 additions & 0 deletions land.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from time import sleep
import tellopy


def test():
drone = tellopy.Tello()
try:
drone.connect()
drone.wait_for_connection(60.0)
drone.land()
sleep(5)
finally:
drone.quit()

if __name__ == '__main__':
test()
Loading

0 comments on commit bf25368

Please sign in to comment.