Skip to content

Commit

Permalink
Update test flight script to final version!
Browse files Browse the repository at this point in the history
  • Loading branch information
BlockadeRunner committed May 9, 2024
1 parent 35747cd commit d3965c7
Showing 1 changed file with 37 additions and 140 deletions.
177 changes: 37 additions & 140 deletions main_app.py
Original file line number Diff line number Diff line change
@@ -1,158 +1,55 @@
###################################################
# Autonomous Drone Main Control Hub #
# #
# Co-Authors: Jake Richardson, Alex Passin, #
# and Alex Longo. #
# Author: Alex Longo #
# #
# Date: 3/6/2024 #
# Date: 9/4/2024 #
# #
# Description: TBD #
# Description: Main script used for conducting #
# payload testing. Script uses my #
# DroneFlightController class to #
# establish a connection and #
# interface with the drone. Then it #
# tells the drone to takeoff, fly #
# five feet forward, turn 90 deg. #
# to the right, fly three feet #
# forward, and land. #
###################################################

# Old Imports:
#from djitellopy import tello
#from easytello import tello
#import DroneFlightController

# New Imports:
import time
import cv2
# Imports:
import DroneFlightController
import threading
from djitellopy import tello
from tkinter import *
from PIL import Image, ImageTk
import keyboard

class MainApp:
def __init__(self):
# Prepare our GUI window
self.root = Tk() # Initialize the Tkinter window
self.root.title("Tello Drone Control GUI with Video Stream") # Add a title to the window
self.root.minsize(800, 600) # Set the minimum gui size
# Create a Key Listener for Emergency Drone Shutoff
def key_listener():
while True:
keyboard.wait("e") # Wait for the "E" Key Press
drone.emergency() # Activate Emergency shutoff for Drone

# Initialize the video stream capture label
self.cap_lbl = Label(self.root)
# Main Script For Payload Transport Test Flight
if __name__ == "__main__":

# Setup a new drone object and establish a connection to the drone
drone = DroneFlightController.DroneFlightController()

# Prepare our drone object
self.drone = tello.Tello() # Initialize the drone
self.drone.connect() # Connect to the drone
self.drone.streamon() # Turn on the drones video stream
# Create a thread to listen for keyboard input continuously
key_thread = threading.Thread(target=key_listener, daemon=True)
key_thread.start()

# Initialize variables involving drone functionalities
self.frame = self.drone.get_frame_read() # variable to get the video frames from the drone
# Send Takeoff Command
drone.takeoff()

### **** NEW **** ###
# this is to store the joystick rc values as they are updated in realtime.
self.rc_controls = [0, 0, 0, 0] # the initial movement velocity values for lr, fb, ud, and yaw motions
### ************* ###
# Send Command to Fly 5ft (152 cm) forward
drone.forward(152)

def takeoff_land(self):
"""Set the command for the takeoff/land button depending on the drones flying state"""
if self.drone.is_flying:
threading.Thread(target=lambda: self.drone.land()).start()
else:
threading.Thread(target=lambda: self.drone.takeoff()).start()
# Send Command to Turn 90 deg. to the right
drone.cw(90)

### **** NEW METHOD **** ###
def update_joystick(self):
"""Method to update joystick values."""
try:

# Map joystick values to specific RC control channels
self.rc_controls[0] = right_joystick_x # lr RC value
self.rc_controls[1] = right_joystick_y # fb RC value
self.rc_controls[2] = left_joystick_y # ud RC value
self.rc_controls[3] = left_joystick_x # yaw RC value

# If rc control values aren't zero then send them to the drone using the send_rc_control(lr, fb, ud, yv) command.
if self.rc_controls != [0, 0, 0, 0]:
self.drone.send_rc_control(self.rc_controls[0], self.rc_controls[1], self.rc_controls[2], self.rc_controls[3])

# and if not zero then send the equivalent command for the drone to hover in place
else:
self.drone.send_rc_control(0, 0, 0, 0)
# Call the update_joystick method again after a delay (50 milliseconds)
self.root.after(50, self.update_joystick)

# Handle exceptions that may occur during joystick update
except Exception as joystickUpdateException:
print(f"Exception occurred when updating joystick values.\nJoystickUpdateException: {joystickUpdateException}")
### ************* ###

def run_app(self):
"""Method to run the application."""
try:
# Pack the video stream label to the GUI window
self.cap_lbl.pack(anchor="center")

# Call the video_stream method to start displaying video
self.video_stream()

### **** NEW **** ###
# Call the update_joystick method to start the joystick control
self.update_joystick()
### ************* ###

# Start the tkinter main loop
self.root.mainloop()
except Exception as runAppException:
print(f"Exception occurred when running the application.\nrunAppException: {runAppException}")
finally:
# When the root window is exited out of ensure to clean up any resources.
self.cleanup()

def video_stream(self):
"""Method to display video stream."""
try:
# Define the height and width to resize the current frame to
h = 480
w = 720

# Read a frame from our drone
frame = self.frame.frame

frame = cv2.resize(frame, (w, h))

# Convert the current frame to the rgb colorspace
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)

# Convert this to a Pillow Image object
img = Image.fromarray(cv2image)

# Convert this then to a Tkinter compatible PhotoImage object
imgtk = ImageTk.PhotoImage(image=img)

# Place the image label at the center of the window
self.cap_lbl.pack(anchor="center", pady=15)

# Set it to the photo image
self.cap_lbl.imgtk = imgtk

# Configure the photo image as the displayed image
self.cap_lbl.configure(image=imgtk)

# Update the video stream label with the current frame
# by recursively calling the method itself with a delay.
self.cap_lbl.after(5, self.video_stream)
except Exception as videoStreamException:
print(f"Exception occurred when updating the video stream.\nvideoStreamException: {videoStreamException}")

def cleanup(self) -> None:
"""Method for cleaning up resources."""
try:
# Release any resources
print("Cleaning up resources...")
self.drone.end()
self.root.quit() # Quit the Tkinter main loop
exit()
except Exception as e:
print(f"Error performing cleanup: {e}")


if __name__ == "__main__":
# Initialize the GUI
gui = MainApp()

# Call the run_app method to run tkinter mainloop
gui.run_app()
# Send Command to Fly 3ft (91 cm) forward
drone.forward(91)

# Send Land Command
drone.land()

0 comments on commit d3965c7

Please sign in to comment.