Ejemplo n.º 1
0
class Config:
    def __init__(self):
        self.time_of_initialization = time.time()
        self.props = self.read_properties()

        self.use_drone = True
        self.drone_flying = False
        self.drone = None

        self.calculate_additional_props()

        if self.use_drone:
            self.connect_to_drone()
        else:
            self.cap = cv2.VideoCapture(0)

    def connect_to_drone(self):
        self.drone = Tello()
        self.drone.connect()
        self.drone.streamon()
        self.cap = self.drone.get_frame_read()
        self.drone_takeoff()
        self.drone.move_up(100)

    def drone_respond_ready(self):
        return time.time(
        ) - self.time_of_initialization > self.props["drone"]["respond_delay"]

    def frame(self):
        if self.use_drone:
            frame = self.cap.frame
        else:
            ret, frame = self.cap.read()

        return frame

    def stop_streaming(self):
        if self.use_drone:
            self.drone.streamoff()
        else:
            self.cap.release()

    def drone_emergency_stop(self):
        self.drone.emergency()
        self.drone_flying = False

    def drone_takeoff(self):
        self.drone.takeoff()
        self.drone_flying = True

    def read_properties(self):
        with open('./config/properties.json') as json_file:
            props = json.load(json_file)

        return props

    def calculate_additional_props(self):
        self.props["img"]["height"] = 300
        self.props["img"]["frame_center_x"] = self.props["img"]["width"] * 0.5
        self.props["img"]["frame_center_y"] = self.props["img"]["height"] * 0.5
class FrontEnd(object):
    """ Maintains the Tello display and moves it through the keyboard keys.
        Press escape key to quit.
        The controls are:
            - Tab:      Takeoff
            - Shift:    Land
            - Space:    Emergency Shutdown
            - WASD:     Forward, backward, left and right
            - Q and E:  Counter clockwise and clockwise rotations
            - R and F:  Up and down
            - T:        Start/Stop tracking
            - C:        Select central pixel value as new color for tracking
            - #:        Switch controllable parameter
            - + and -:  Raise or Lower controllable parameter
    """
    def __init__(self):
        # Init pygame
        pygame.init()

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

        # general config
        self.internalSpeed = 100
        self.FPS = 20
        self.hud_size = (800, 600)

        # config of controllable parameters
        self.controll_params = {
            'Speed': 100,
            'Color': 0,
        }
        self.controll_params_d = {
            'Speed': 10,
            'Color': 1,
        }
        self.controll_params_m = {
            'Speed': 100,
            'Color': 2,
        }

        # tracker config
        self.color_lower = {
            'blue': (100, 200, 50),
            'red': (0, 200, 100),
            'yellow': (20, 200, 130),
        }
        self.color_upper = {
            'blue': (140, 255, 255),
            'red': (20, 255, 255),
            'yellow': (40, 255, 255),
        }

        self.current_color = np.array(self.color_lower['blue']) + np.array(
            self.color_upper['blue'])
        for i in range(0, 3):
            self.current_color[i] = self.current_color[i] / 2
        self.crange = (10, 50, 50)

        # other params (no need to config)
        self.current_parameter = 0
        self.param_keys = list(self.controll_params.keys())
        self.color_keys = list(self.color_lower.keys())
        self.central_color = (0, 0, 0)
        self.midx = int(self.hud_size[0] / 2)
        self.midy = int(self.hud_size[1] / 2)
        self.xoffset = 0
        self.yoffset = 0
        self.target_radius = 120
        self.for_back_velocity = 0
        self.left_right_velocity = 0
        self.up_down_velocity = 0
        self.yaw_velocity = 0
        self.send_rc_control = False
        self.isTracking = False

        # Creat pygame window
        pygame.display.set_caption("Tello video stream")
        self.screen = pygame.display.set_mode(self.hud_size)

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

#
#      888b     d888          d8b               888
#      8888b   d8888          Y8P               888
#      88888b.d88888                            888
#      888Y88888P888  8888b.  888 88888b.       888      .d88b.   .d88b.  88888b.
#      888 Y888P 888     "88b 888 888 "88b      888     d88""88b d88""88b 888 "88b
#      888  Y8P  888 .d888888 888 888  888      888     888  888 888  888 888  888
#      888   "   888 888  888 888 888  888      888     Y88..88P Y88..88P 888 d88P
#      888       888 "Y888888 888 888  888      88888888 "Y88P"   "Y88P"  88888P"
#                                                                         888
#                                                                         888
#                                                                         888
#

    def run(self):
        """
        Main loop.
        Contains reading the incoming frames, the call for tracking and basic keyboard stuff.
        """

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

        if not self.tello.set_speed(self.internalSpeed):
            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()

        self.should_stop = False
        while not self.should_stop:

            # read frame
            img = cv2.cvtColor(frame_read.frame, cv2.COLOR_BGR2RGB)
            img = cv2.resize(img, self.hud_size, interpolation=cv2.INTER_AREA)

            # get output from tracking
            if self.isTracking:
                self.track(img)

            # produce hud
            self.frame = self.write_hud(img.copy())
            self.frame = np.fliplr(self.frame)
            self.frame = np.rot90(self.frame)
            self.frame = pygame.surfarray.make_surface(self.frame)
            self.screen.fill([0, 0, 0])
            self.screen.blit(self.frame, (0, 0))
            pygame.display.update()

            # handle input from dronet or user
            for event in pygame.event.get():
                if event.type == USEREVENT + 1:
                    self.send_input()
                elif event.type == QUIT:
                    self.should_stop = True
                elif event.type == KEYDOWN:
                    if (event.key == K_ESCAPE) or (event.key == K_BACKSPACE):
                        self.should_stop = True
                    else:
                        self.keydown(event.key)
                elif event.type == KEYUP:
                    self.keyup(event.key)

                # shutdown stream
                if frame_read.stopped:
                    frame_read.stop()
                    break

            # wait a little
            time.sleep(1 / self.FPS)

        # always call before finishing to deallocate resources
        self.tello.end()

    def track(self, frame):
        """
        HSV color space tracking.
        """
        # resize the frame, blur it, and convert it to the HSV
        # color space
        blurred = cv2.GaussianBlur(frame, (11, 11), 0)
        hsv = cv2.cvtColor(blurred, cv2.COLOR_RGB2HSV)
        self.central_color = hsv[self.midy, self.midx, :]

        # construct a mask for the color then perform
        # a series of dilations and erosions to remove any small
        # blobs left in the mask
        mask = cv2.inRange(hsv, self.current_color - self.crange,
                           self.current_color + self.crange)
        mask = cv2.erode(mask, None, iterations=3)
        mask = cv2.dilate(mask, None, iterations=3)

        # find contours in the mask and initialize the current
        # (x, y) center of the ball
        image, cnts, hierarchy = cv2.findContours(mask.copy(),
                                                  cv2.RETR_EXTERNAL,
                                                  cv2.CHAIN_APPROX_SIMPLE)

        center = None

        radius = 0
        velocity = 0
        # only proceed if at least one contour was found
        if len(cnts) > 0:
            # update color from mean color
            mask_upstate = cv2.bitwise_and(hsv, hsv, mask=mask)
            mean = cv2.mean(mask_upstate)
            multiplier = float(mask.size) / (cv2.countNonZero(mask) + 0.001)
            mean = np.array([multiplier * x for x in mean])

            self.update_color(mean)
            print(self.current_color)

            # find the largest contour in the mask, then use
            # it to compute the minimum enclosing circle and
            # centroid
            c = max(cnts, key=cv2.contourArea)

            ((x, y), radius) = cv2.minEnclosingCircle(c)
            M = cv2.moments(c)

            center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))

            # only proceed if the radius meets a minimum size
            if radius > 40:
                # draw the circle and centroid on the frame,
                # then update the list of tracked points
                cv2.circle(frame, (int(x), int(y)), int(radius), (0, 255, 0),
                           2)

                self.xoffset = int(center[0] - self.midx)
                self.yoffset = int(self.midy - center[1])
                velocity = clamp(self.target_radius - radius, -40,
                                 60) / 100 * self.controll_params['Speed']
            else:
                self.xoffset = 0
                self.yoffset = 0
                velocity = 0
        else:
            self.xoffset = 0
            self.yoffset = 0
            velocity = 0

        xfact = self.xoffset / self.hud_size[0] * self.controll_params[
            'Speed'] * 2
        yfact = self.yoffset / self.hud_size[0] * self.controll_params[
            'Speed'] * 2

        self.for_back_velocity = int(velocity)
        self.yaw_velocity = int(xfact)
        self.up_down_velocity = int(yfact)

#
#      8888888                            888         888b     d888          888    888                    888
#        888                              888         8888b   d8888          888    888                    888
#        888                              888         88888b.d88888          888    888                    888
#        888   88888b.  88888b.  888  888 888888      888Y88888P888  .d88b.  888888 88888b.   .d88b.   .d88888 .d8888b
#        888   888 "88b 888 "88b 888  888 888         888 Y888P 888 d8P  Y8b 888    888 "88b d88""88b d88" 888 88K
#        888   888  888 888  888 888  888 888         888  Y8P  888 88888888 888    888  888 888  888 888  888 "Y8888b.
#        888   888  888 888 d88P Y88b 888 Y88b.       888   "   888 Y8b.     Y88b.  888  888 Y88..88P Y88b 888      X88
#      8888888 888  888 88888P"   "Y88888  "Y888      888       888  "Y8888   "Y888 888  888  "Y88P"   "Y88888  88888P'
#                       888
#                       888
#                       888
#

    def keydown(self, key):
        """ Update velocities based on key pressed
        Arguments:
            key: pygame key
        """
        if key == pygame.K_w:  # set forward velocity
            self.isTracking = False
            self.for_back_velocity = self.controll_params['Speed']
        elif key == pygame.K_s:  # set backward velocity
            self.isTracking = False
            self.for_back_velocity = -self.controll_params['Speed']
        elif key == pygame.K_a:  # set left velocity
            self.isTracking = False
            self.left_right_velocity = -self.controll_params['Speed']
        elif key == pygame.K_d:  # set right velocity
            self.isTracking = False
            self.left_right_velocity = self.controll_params['Speed']
        elif key == pygame.K_r:  # set up velocity
            self.isTracking = False
            self.up_down_velocity = self.controll_params['Speed']
        elif key == pygame.K_f:  # set down velocity
            self.isTracking = False
            self.up_down_velocity = -self.controll_params['Speed']
        elif key == pygame.K_e:  # set yaw clockwise velocity
            self.isTracking = False
            self.yaw_velocity = self.controll_params['Speed']
        elif key == pygame.K_q:  # set yaw counter clockwise velocity
            self.isTracking = False
            self.yaw_velocity = -self.controll_params['Speed']
        elif key == pygame.K_TAB:  # takeoff
            self.tello.takeoff()
            self.send_rc_control = True
        elif key == pygame.K_LSHIFT:  # land
            self.isTracking = False
            self.tello.land()
            self.send_rc_control = False
        elif key == pygame.K_SPACE:  # emergency shutdown
            self.isTracking = False
            self.tello.emergency()
            self.send_rc_control = False
            self.should_stop = True
        elif key == pygame.K_BACKSPACE:  # emergency shutdown
            self.isTracking = False
            self.send_rc_control = False
            self.should_stop = True
        elif key == pygame.K_t:  # arm tracking
            self.isTracking = not self.isTracking
            self.for_back_velocity = 0
            self.yaw_velocity = 0
            self.up_down_velocity = 0
        elif key == pygame.K_c:  # get new color
            self.set_color(self.central_color)
            self.for_back_velocity = 0
            self.yaw_velocity = 0
            self.up_down_velocity = 0
        elif key == pygame.K_HASH:  # switch parameters
            if self.current_parameter == 0:
                self.current_parameter = 1
            else:
                self.current_parameter = 0
        elif key == pygame.K_PLUS:  # raise current parameter
            what = self.param_keys[self.current_parameter]
            if self.controll_params[what] < self.controll_params_m[what] - 0.01:
                self.controll_params[what] = self.controll_params[
                    what] + self.controll_params_d[what]
                if (what == 'Color'):
                    self.reset_color()
        elif key == pygame.K_MINUS:  # lower current parameter
            what = self.param_keys[self.current_parameter]
            if self.controll_params[what] > 0.01:
                self.controll_params[what] = self.controll_params[
                    what] - self.controll_params_d[what]
                if (what == 'Color'):
                    self.reset_color()

    def keyup(self, key):
        """ Update velocities based on key released
        Arguments:
            key: pygame key
        """
        if key == pygame.K_w or key == pygame.K_s:  # set zero forward/backward velocity
            self.for_back_velocity = 0
        elif key == pygame.K_a or key == pygame.K_d:  # set zero left/right velocity
            self.left_right_velocity = 0
        elif key == pygame.K_r or key == pygame.K_f:  # set zero up/down velocity
            self.up_down_velocity = 0
        elif key == pygame.K_q or key == pygame.K_e:  # set zero yaw velocity
            self.yaw_velocity = 0

    def send_input(self):
        """ Update routine. Send velocities to Tello."""
        #print("V: " + str(self.for_back_velocity) + "; Y: " + str(self.yaw_velocity))
        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)


#
#        888    888          888                                888b     d888          888    888                    888
#        888    888          888                                8888b   d8888          888    888                    888
#        888    888          888                                88888b.d88888          888    888                    888
#        8888888888  .d88b.  888 88888b.   .d88b.  888d888      888Y88888P888  .d88b.  888888 88888b.   .d88b.   .d88888 .d8888b
#        888    888 d8P  Y8b 888 888 "88b d8P  Y8b 888P"        888 Y888P 888 d8P  Y8b 888    888 "88b d88""88b d88" 888 88K
#        888    888 88888888 888 888  888 88888888 888          888  Y8P  888 88888888 888    888  888 888  888 888  888 "Y8888b.
#        888    888 Y8b.     888 888 d88P Y8b.     888          888   "   888 Y8b.     Y88b.  888  888 Y88..88P Y88b 888      X88
#        888    888  "Y8888  888 88888P"   "Y8888  888          888       888  "Y8888   "Y888 888  888  "Y88P"   "Y88888  88888P'
#                                888
#                                888
#                                888
#

    def update_color(self, val):
        """
        Adjusts the currently tracked color to input.
        """
        if (cv2.mean(val) != 0):
            for i in range(0, 2):
                self.current_color[i] = clamp(
                    val[i], self.color_lower[self.color_keys[
                        self.controll_params['Color']]][i], self.color_upper[
                            self.color_keys[self.controll_params['Color']]][i])

    def set_color(self, val):
        self.current_color = np.array(val)
        print(val)

    def reset_color(self):
        self.current_color = np.array(
            self.color_lower[self.color_keys[self.controll_params['Color']]]
        ) + np.array(
            self.color_upper[self.color_keys[self.controll_params['Color']]])
        for i in range(0, 3):
            self.current_color[i] = self.current_color[i] / 2

    def write_hud(self, frame):
        """Draw drone info and record on frame"""
        stats = ["TelloTracker"]
        if self.isTracking:
            stats.append("Tracking active.")
            stats.append("Speed: {:03d}".format(self.controll_params['Speed']))
            stats.append("Color: " +
                         self.color_keys[self.controll_params['Color']])
            self.draw_arrows(frame)
        else:
            stats.append("Tracking disabled.")
            img = cv2.circle(frame, (self.midx, self.midy), 10, (0, 0, 255), 1)

        stats.append(self.param_keys[self.current_parameter] +
                     ": {:4.1f}".format(self.controll_params[self.param_keys[
                         self.current_parameter]]))
        for idx, stat in enumerate(stats):
            text = stat.lstrip()
            cv2.putText(frame,
                        text, (0, 30 + (idx * 30)),
                        cv2.FONT_HERSHEY_SIMPLEX,
                        1.0, (255, 0, 0),
                        lineType=30)
        return frame

    def draw_arrows(self, frame):
        """Show the direction vector output in the cv2 window"""
        #cv2.putText(frame,"Color:", (0, 35), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, thickness=2)
        cv2.arrowedLine(frame, (self.midx, self.midy),
                        (self.midx + self.xoffset, self.midy - self.yoffset),
                        (255, 0, 0), 5)
        return frame
Ejemplo n.º 3
0
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):

		kp_x = .25;
		ki_x = 0;
		kd_x =  .05;

		kp_y = .5;
		ki_y = 0;
		kd_y =  .1;

		kp_z = .5;
		ki_z = 0;
		kd_z =  .1;

		bias_x = 0;
		bias_y = 0;
		bias_z = 0;

		prev_error_x = 0;
		prev_error_y = 0;
		prev_error_z = 0;

		integral_x = 0;
		integral_y = 0;
		integral_z = 0;



		desired_x = 0;
		desired_y = 0;
		desired_z = 75;



		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)

			img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
			gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
			size = img.shape


			avg1 = np.float32(gray)
			avg2 = np.float32(gray)
			res = cv2.aruco.detectMarkers(gray, aruco_dict, parameters = arucoParams)
			imgWithAruco = gray # assign imRemapped_color to imgWithAruco directly
			#if len(res[0]) > 0:
				#print (res[0])


			focal_length = size[1]
			center = (size[1]/2, size[0]/2)
			camera_matrix = np.array(
							[[focal_length, 0, center[0]],
							[0, focal_length, center[1]],
							[0, 0, 1]], dtype = "double"
							)

			if res[1] != None: # if aruco marker detected
				im_src = imgWithAruco
				im_dst = imgWithAruco

				pts_dst = np.array([[res[0][0][0][0][0], res[0][0][0][0][1]], [res[0][0][0][1][0], res[0][0][0][1][1]], [res[0][0][0][2][0], res[0][0][0][2][1]], [res[0][0][0][3][0], res[0][0][0][3][1]]])
				pts_src = pts_dst
				h, status = cv2.findHomography(pts_src, pts_dst)

				imgWithAruco = cv2.warpPerspective(im_src, h, (im_dst.shape[1], im_dst.shape[0]))

				rvec, tvec, _ = cv2.aruco.estimatePoseSingleMarkers(res[0], markerLength, camera_matrix, dist_coeffs)
				print(tvec[0][0][0],tvec[0][0][1],tvec[0][0][2])
				img = cv2.aruco.drawAxis(imgWithAruco, camera_matrix, dist_coeffs, rvec, tvec, 10)
				cameraPose = cameraPoseFromHomography(h)

				if autopilot:
					#PID controller
					x = tvec[0][0][0];
					y = tvec[0][0][1];
					z = tvec[0][0][2];

					iteration_time = 1/FPS;

					error_x = desired_x - x;
					integral_x = integral_x + (error_x * iteration_time );
					derivative_x = (error_x - prev_error_x) / iteration_time;
					output_x = kp_x*error_x + ki_x*integral_x + kd_x*derivative_x + bias_x;
					prev_error_x = error_x;

					error_y = desired_y - y;
					integral_y = integral_y + (error_y * iteration_time );
					derivative_y = (error_y - prev_error_y) / iteration_time;
					output_y = kp_y*error_y + ki_y*integral_y + kd_y*derivative_y + bias_y;
					prev_error_y = error_y;

					error_z = desired_z - z;
					integral_z = integral_z + (error_z * iteration_time );
					derivative_z = (error_z - prev_error_z) / iteration_time;
					output_z = kp_z*error_z + ki_z*integral_z + kd_z*derivative_z + bias_z;
					prev_error_z = error_z;

					#speed can only be 10-100, if outside of range, set to 10 or 100
					if output_x>100:
						output_x = 100;
					elif output_x<-100:
						output_x = -100;
						"""
					elif output_x<10 and output_x>0:
						output_x = 10;
					elif output_x>-10 and output_x<0:
						output_x = -10;
						"""

					if output_y>100:
						output_y = 100;
					elif output_y<-100:
						output_y = -100;
					elif output_y<10 and output_y>0:
						output_y = 10;
					elif output_y>-10 and output_y<0:
						output_y = -10;

					if output_z>100:
						output_z = 100;
					elif output_z<-100:
						output_z = -100;
					elif output_z<10 and output_z>0:
						output_z = 10;
					elif output_z>-10 and output_z<0:
						output_z = -10;


					self.left_right_velocity = int(-output_x);
					if output_x>10 or output_x<-10:
						self.yaw_velocity = int(-output_x);

					self.up_down_velocity = int(output_y);
					self.for_back_velocity = int(-output_z);


			faces = face_cascade.detectMultiScale(gray, 1.3, 5)
			for (x,y,w,h) in faces:
				img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
				roi_gray = gray[y:y+h, x:x+w]
				roi_color = img[y:y+h, x:x+w]
				eyes = eye_cascade.detectMultiScale(roi_gray)
				for (ex,ey,ew,eh) in eyes:
					cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)


			img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
			frame = np.rot90(img)
			frame = np.flipud(frame)

			frame = pygame.surfarray.make_surface(frame)
			self.screen.blit(frame, (0, 0))
			pygame.display.update()
			#cv2.imshow('img', img)

			time.sleep(1 / FPS)

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

	def keydown(self, key):
		""" Update velocities based on key pressed
		Arguments:
			key: pygame key
		"""
		if key == pygame.K_SPACE:
			autopilot = ~autopilot;
		if ~autopilot:
			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
			elif key == pygame.K_r:		#release R to make the drone flip to the right (flex)
				self.tello.flip_right


	def keyup(self, key):
		""" Update velocities based on key released
		Arguments:
			key: pygame key
		"""
		if ~autopilot:
			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
			elif key == pygame.K_e:		#release E to turn off all motors (for our automated landing)
				self.tello.emergency()
				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)
Ejemplo n.º 4
0
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])  # ((width, height) of window))

        # 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
        if not self.tello.streamoff(
        ):  # In case streaming is on. This happens when we quit this program without the escape key.
            print("Could not stop video stream")
            return
        if not self.tello.streamon():
            print("Could not start video stream")
            return

        kp_xyz = [.15, .5, .4]  #proportional constants
        ki_xyz = [0, 0, 0]  #integral constants
        kd_xyz = [.05, .1, .1]  #derivative constants

        desired_xyz = [0, 0, 30]  #desired xyz distance from aruco
        land_xyz = [
            100, 100, 100
        ]  #range needed within desired to cut motors + attempt landing

        bias_xyz = [0, 0, 0]
        integral_xyz = [0, 0, 0]
        prev_error_xyz = [0, 0, 0]
        error_xyz = [0, 0, 0]

        plt.ion()  #interactive mode on
        t = 0
        #time (used for plotting)
        plt.pause(0.001)
        t = t + 0.001

        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])

            img = frame_read.frame
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            size = img.shape

            avg1 = np.float32(gray)
            avg2 = np.float32(gray)
            res = cv2.aruco.detectMarkers(gray,
                                          aruco_dict,
                                          parameters=arucoParams)
            imgWithAruco = img  # assign imRemapped_color to imgWithAruco directly
            #if len(res[0]) > 0:
            #print (res[0])

            focal_length = size[1]
            center = (size[1] / 2, size[0] / 2)
            camera_matrix = np.array([[focal_length, 0, center[0]],
                                      [0, focal_length, center[1]], [0, 0, 1]],
                                     dtype="double")

            if res[1] != None:  # if aruco marker detected
                im_src = imgWithAruco
                im_dst = imgWithAruco

                pts_dst = np.array([[res[0][0][0][0][0], res[0][0][0][0][1]],
                                    [res[0][0][0][1][0], res[0][0][0][1][1]],
                                    [res[0][0][0][2][0], res[0][0][0][2][1]],
                                    [res[0][0][0][3][0], res[0][0][0][3][1]]])
                pts_src = pts_dst
                h, status = cv2.findHomography(pts_src, pts_dst)

                imgWithAruco = cv2.warpPerspective(
                    im_src, h, (im_dst.shape[1], im_dst.shape[0]))

                rvec, tvec, _ = cv2.aruco.estimatePoseSingleMarkers(
                    res[0], markerLength, camera_matrix, dist_coeffs)
                img = cv2.aruco.drawAxis(imgWithAruco, camera_matrix,
                                         dist_coeffs, rvec, tvec, 10)
                cameraPose = cameraPoseFromHomography(h)

                #PID controller

                xyz = []
                xyz.append(tvec[0][0][0])
                xyz.append(tvec[0][0][1])
                xyz.append(tvec[0][0][2])

                plt.subplot(311)
                plt.plot(t, xyz[0], 'rs')
                plt.subplot(312)
                plt.plot(t, xyz[1], 'gs')
                plt.subplot(313)
                plt.plot(t, xyz[2], 'bs')

                iteration_time = 1 / FPS

                error_xyz = []
                derivative_xyz = []
                output_xyz = []
                for i in range(3):
                    error_xyz.append(desired_xyz[i] - xyz[i])
                    integral_xyz[i] = integral_xyz[i] + (error_xyz[i] *
                                                         iteration_time)
                    derivative_xyz.append(error_xyz[i] - prev_error_xyz[i])
                    output_xyz.append(kp_xyz[i] * error_xyz[i] +
                                      ki_xyz[i] * integral_xyz[i] +
                                      kd_xyz[i] * derivative_xyz[i] +
                                      bias_xyz[i])
                    prev_error_xyz[i] = error_xyz[i]

                    #speed can only be 10-100, if outside of range, set to 10 or 100
                    if output_xyz[i] > 100:
                        output_xyz[i] = 100
                    elif output_xyz[i] < -100:
                        output_xyz[i] = -100
                    elif output_xyz[i] < 10 and output_xyz[i] > 0:
                        output_xyz[i] = 10
                    elif output_xyz[i] > -10 and output_xyz[i] < 0:
                        output_xyz[i] = -10

                self.left_right_velocity = int(-output_xyz[0])
                self.yaw_velocity = int(-output_xyz[0])

                self.up_down_velocity = int(output_xyz[1])
                self.for_back_velocity = int(-output_xyz[2])

                if xyz[0] < desired_xyz[0] + land_xyz[0] and xyz[
                        0] > desired_xyz[0] - land_xyz[0] and xyz[
                            1] < desired_xyz[1] + land_xyz[1] and xyz[
                                1] > xyz[1] - land_xyz[1] and xyz[
                                    2] < desired_xyz[2] + land_xyz[2] and xyz[
                                        2] > desired_xyz[2] - land_xyz[2]:
                    self.tello.land()
                    self.send_rc_control = False

                print("x: ", xyz[0], "y:", xyz[1], "z:", xyz[2], sep="\t")

                #consider using gain scheduling (different constants at different distances)

            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            frame = np.rot90(img)
            frame = np.flipud(frame)
            frame = pygame.surfarray.make_surface(frame)

            self.screen.blit(frame, (0, 0))
            pygame.display.update()

            #xyz graphing
            plt.show()
            plt.pause(1 / FPS)
            t = t + 1 / FPS

        #deallocate resources.
        self.tello.end()
        cv2.destroyAllWindows()

    def keydown(self, key):
        """ Update velocities based on key pressed
		Arguments:
			key: pygame key
		"""

    def keyup(self, key):
        """ Update velocities based on key released
		Arguments:
			key: pygame key
		"""

        if 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 = True
        elif key == pygame.K_e:  #release E to turn off all motors (for our automated landing)
            self.tello.emergency()
            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)
Ejemplo n.º 5
0
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
        hover = 0
        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)

            img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            size = img.shape

            avg1 = np.float32(gray)
            avg2 = np.float32(gray)
            res = cv2.aruco.detectMarkers(gray,
                                          aruco_dict,
                                          parameters=arucoParams)
            imgWithAruco = gray  # assign imRemapped_color to imgWithAruco directly
            #if len(res[0]) > 0:
            #print (res[0])

            focal_length = size[1]
            center = (size[1] / 2, size[0] / 2)
            camera_matrix = np.array([[focal_length, 0, center[0]],
                                      [0, focal_length, center[1]], [0, 0, 1]],
                                     dtype="double")

            if res[1] != None:  # if aruco marker detected
                im_src = imgWithAruco
                im_dst = imgWithAruco

                pts_dst = np.array([[res[0][0][0][0][0], res[0][0][0][0][1]],
                                    [res[0][0][0][1][0], res[0][0][0][1][1]],
                                    [res[0][0][0][2][0], res[0][0][0][2][1]],
                                    [res[0][0][0][3][0], res[0][0][0][3][1]]])
                pts_src = pts_dst
                h, status = cv2.findHomography(pts_src, pts_dst)

                imgWithAruco = cv2.warpPerspective(
                    im_src, h, (im_dst.shape[1], im_dst.shape[0]))

                rvec, tvec, _ = cv2.aruco.estimatePoseSingleMarkers(
                    res[0], markerLength, camera_matrix, dist_coeffs)
                print(tvec[0][0][0], tvec[0][0][1], tvec[0][0][2])
                img = cv2.aruco.drawAxis(imgWithAruco, camera_matrix,
                                         dist_coeffs, rvec, tvec, 10)
                cameraPose = cameraPoseFromHomography(h)

                if tvec[0][0][2] > ZHI:
                    self.for_back_velocity = -S
                elif tvec[0][0][2] < ZLO:
                    self.for_back_velocity = S
                else:
                    self.for_back_velocity = 0
                if tvec[0][0][1] > YHI:
                    self.up_down_velocity = S
                elif tvec[0][0][1] < YLO:
                    self.up_down_velocity = -S
                else:
                    self.up_down_velocity = 0
                if tvec[0][0][0] > XHI:
                    self.left_right_velocity = -S
                elif tvec[0][0][0] < XLO:
                    self.left_right_velocity = S
                else:
                    self.left_right_velocity = 0
                hover = 0
            hover = hover + 1
            if hover == 1:
                self.for_back_velocity = -self.for_back_velocity
                self.left_right_velocity = -self.left_right_velocity
                self.up_down_velocity = -self.up_down_velocity
            faces = face_cascade.detectMultiScale(gray, 1.3, 5)
            for (x, y, w, h) in faces:
                img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0),
                                    2)
                roi_gray = gray[y:y + h, x:x + w]
                roi_color = img[y:y + h, x:x + w]
                eyes = eye_cascade.detectMultiScale(roi_gray)
                for (ex, ey, ew, eh) in eyes:
                    cv2.rectangle(roi_color, (ex, ey), (ex + ew, ey + eh),
                                  (0, 255, 0), 2)

            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            frame = np.rot90(img)
            frame = np.flipud(frame)

            frame = pygame.surfarray.make_surface(frame)
            self.screen.blit(frame, (0, 0))
            pygame.display.update()
            #cv2.imshow('img', img)

            time.sleep(1 / FPS)

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

    def keydown(self, key):
        """ Update velocities based on key pressed
		Arguments:
			key: pygame key
		"""

    def keyup(self, key):
        """ Update velocities based on key released
		Arguments:
			key: pygame key
		"""

        if 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
        elif key == pygame.K_e:  #release E to turn off all motors (for our automated landing)
            self.tello.emergency()
            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)
drone.send_rc_control(0, 0, 0, 0)
while True:
    #get the drone fottage
    frameRead = drone.get_frame_read()
    myFrame = frameRead.frame
    #resize the image to make it look somewhat good (still not good)
    img = cv2.resize(myFrame, (WIDTH, HEIGHT))

    #start counter checker
    if startCounter == 0:
        drone.takeoff()
        startCounter = 1

    #showing the drone footage
    cv2.imshow("Drone Footage", img)

    #enter a command for the drone to do this will block the footage since it is an input (VERY BAD)
    cmd = input("<CMD>: ")
    #very hacky way of doing it not recomended for use
    eval(f"drone.{translateCommands(cmd)}")

    #press q to quit the program, but first input command, since it stalls on that
    if cv2.waitKey(1) & 0xFF == ord('q'):
        me.land()
        break

#press enter to ACTIVATE EMERGENCY LANDING
land = input("ACTIVATE EMERGENCY LANDING: ")
drone.emergency()
Ejemplo n.º 7
0
class Display(object):
    """ Tello display
        Press escape key to quit.
        The controls implemented:
            - T: Takeoff
            - L: Land
            - W, S, A, D: Forward, backward, left and right (x,y)
            - Arrow Keys: Up and down. (z)
            - Q and E: Counter clockwise and clockwise rotations (yaw)     
    """
    def __init__(self):
        # Init pygame
        pygame.init()

        # Create 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.y_velocity = 0
        self.x_velocity = 0
        self.z_velocity = 0
        self.yaw_velocity = 0
        self.speed = 50
        self.S = 10

        self.send_rc_control = False

        # Ticker implementation
        pygame.time.set_timer(pygame.USEREVENT + 1, 1000 // FPS)

    def run(self):
        self.tello.connect()
        self.tello.set_speed(self.speed)

        # In case streaming is on. This happens when we quit this program without the escape key.
        self.tello.streamoff()
        self.tello.streamon()

        frame_read = self.tello.get_frame_read()

        stop = False
        while not stop:

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

            if frame_read.stopped:
                break

            self.screen.fill([0, 0, 0])

            frame = frame_read.frame
            img_input = frame.copy()
            img_input = model.prepare_input(img_input)
            keypoints = model.predict_singlepose(img_input)

            BATTERY = "Battery: {}%; Speed: {}".format(
                self.tello.get_battery(), self.S)
            cv2.putText(frame, BATTERY, (5, 420 - 5), cv2.FONT_HERSHEY_SIMPLEX,
                        1, (0, 0, 255), 2)

            model.draw_pose(frame, keypoints)
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = np.rot90(frame)
            frame = np.flipud(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. To deallocate resources.
        self.tello.end()

    def keydown(self, key):
        """ Update values based on key pressed
        Arguments:
            key: pygame key
        """
        if key == pygame.K_a:  # set left velocity
            self.x_velocity = -self.S
        elif key == pygame.K_d:  # set right velocity
            self.x_velocity = self.S
        elif key == pygame.K_w:  # set forward velocity
            self.y_velocity = self.S
        elif key == pygame.K_s:  # set backward velocity
            self.y_velocity = -self.S
        elif key == pygame.K_UP:  # set up velocity
            self.z_velocity = self.S
        elif key == pygame.K_DOWN:  # set down velocity
            self.z_velocity = -self.S
        elif key == pygame.K_LEFT:  # set yaw counter clockwise velocity
            self.yaw_velocity = -self.S
        elif key == pygame.K_RIGHT:  # set yaw clockwise velocity
            self.yaw_velocity = self.S
        elif key == pygame.K_1:  # set  velocity
            self.S = 10
        elif key == pygame.K_2:  # set  velocity
            self.S = 20
        elif key == pygame.K_3:  # set  velocity
            self.S = 30
        elif key == pygame.K_4:  # set  velocity
            self.S = 40
        elif key == pygame.K_5:  # set  velocity
            self.S = 50
        elif key == pygame.K_6:  # set  velocity
            self.S = 60
        elif key == pygame.K_7:  # set  velocity
            self.S = 70
        elif key == pygame.K_8:  # set  velocity
            self.S = 80
        elif key == pygame.K_9:  # set  velocity
            self.S = 90
        elif key == pygame.K_0:  # set  velocity
            self.S = 100
        elif key == pygame.K_BACKSPACE:
            self.tello.emergency()

    def keyup(self, key):
        """ Update values for key release
        Arguments:
            key: pygame key
        """
        if key == pygame.K_a or key == pygame.K_d:  # set zero left/right velocity
            self.x_velocity = 0
        elif key == pygame.K_w or key == pygame.K_s:  # set zero forward/backward velocity
            self.y_velocity = 0
        elif key == pygame.K_UP or key == pygame.K_DOWN:  # set zero up/down velocity
            self.z_velocity = 0
        elif key == pygame.K_RIGHT or key == pygame.K_LEFT:  # 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
            not self.tello.land()
            self.send_rc_control = False

        elif key == pygame.K_DELETE:
            self.tello.send_rc_control(0, 0, 0, 100)
            time.sleep(0.5)
            self.tello.land()

    def update(self):
        """ Update and send all the events to the tello"""
        if self.send_rc_control:
            self.tello.send_rc_control(self.x_velocity, self.y_velocity,
                                       self.z_velocity, self.yaw_velocity)
Ejemplo n.º 8
0
                        print("Landing...")
                        mdrone.for_back_velocity = 0
                        mdrone.yaw_velocity = 0
                        mdrone.land()
                        mdrone.send_rc_control = False

                # WAIT FOR THE 'Q' BUTTON TO STOP
                if cv2.waitKey(1) or k == ord('q'):
                    mdrone.land()
                    cv2.destroyAllWindows()
                    mdrone.end()
                    break

                time.sleep(2)
    elif cmd == ord('l'):
        mdrone.emergency()
        mdrone.land()
        mdrone.end()
        cv2.destroyAllWindows()
        break
    else:
        continue








Ejemplo n.º 9
0
            yaw_velocity = 0
        else:
            left_right_velocity = 0
            for_back_velocity = 0
            up_down_velocity = 0
            yaw_velocity = 0

    # Send the velocities to drone
    if tello.send_rc_control:
        tello.send_rc_control(left_right_velocity, for_back_velocity,
                              up_down_velocity, yaw_velocity)

    counter = counter + 1

    # Display the image
    cv2.imshow('Drone X', video_user)

    # comming soon (emergency bottom)
    if cv2.waitKey(20) & 0xFF == 'e':
        tello.emergency()

    # coming soon (quit video)
    if cv2.waitKey(20) & 0xFF == 27:
        break

# Release
# And then to destroy
tello.stop_video_capture()
video_user.release()
cv2.destroyAllWindows()
Ejemplo n.º 10
0
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 = np.flipud(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
        elif key == pygame.K_e:		#release E to turn off all motors (for our automated landing)
            self.tello.emergency()
            self.send_rc_control = False
        elif key == pygame.K_r:		#release R to make the drone flip to the right (flex)
            self.tello.flip_right

    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)