class TelloCV(object): """ TelloTracker builds keyboard controls on top of TelloPy as well as generating images from the video stream and enabling opencv support """ def __init__(self): self.prev_flight_data = None self.record = False self.tracking = False self.keydown = False self.date_fmt = '%Y-%m-%d_%H%M%S' self.speed = 50 self.go_speed = 80 self.drone = Tello() self.init_drone() self.init_controls() self.battery = self.drone.get_battery() self.frame_read = self.drone.get_frame_read() self.forward_time = 0 self.forward_flag = True self.takeoff_time = 0 self.command_time = 0 self.command_flag = False # trackingimport libh264decoder a color # green_lower = (30, 50, 50) # green_upper = (80, 255, 255) # red_lower = (0, 50, 50) # red_upper = (20, 255, 255) blue_lower = np.array([0, 0, 0]) upper_blue = np.array([255, 255, 180]) bh_lower = (180, 30, 100) bh_upper = (275, 50, 100) self.track_cmd = "" self.tracker = Tracker(960, 720, blue_lower, upper_blue) self.speed_list = [5, 10, 15, 20, 25] self.frame_center = 480, 360 self.error = 60 def init_drone(self): """Connect, uneable streaming and subscribe to events""" # self.drone.log.set_level(2) self.drone.connect() self.drone.streamon() def on_press(self, keyname): """handler for keyboard listener""" if self.keydown: return try: self.keydown = True keyname = str(keyname).strip('\'') print('+' + keyname) if keyname == 'Key.esc': self.drone.quit() exit(0) if keyname in self.controls: key_handler = self.controls[keyname] if isinstance(key_handler, str): getattr(self.drone, key_handler)(self.speed) else: key_handler(self.speed) except AttributeError: print('special key {0} pressed'.format(keyname)) def on_release(self, keyname): """Reset on key up from keyboard listener""" self.keydown = False keyname = str(keyname).strip('\'') print('-' + keyname) if keyname in self.controls: key_handler = self.controls[keyname] if isinstance(key_handler, str): getattr(self.drone, key_handler)(0) else: key_handler(0) def init_controls(self): """Define keys and add listener""" self.controls = { 'w': lambda speed: self.drone.move_forward(speed), 's': lambda speed: self.drone.move_back(speed), 'a': lambda speed: self.drone.move_left(speed), 'd': lambda speed: self.drone.move_right(speed), 'Key.space': 'up', 'Key.shift': 'down', 'Key.shift_r': 'down', 'q': 'counter_clockwise', 'e': 'clockwise', 'i': lambda speed: self.drone.flip_forward(), 'k': lambda speed: self.drone.flip_back(), 'j': lambda speed: self.drone.flip_left(), 'l': lambda speed: self.drone.flip_right(), # arrow keys for fast turns and altitude adjustments 'Key.left': lambda speed: self.drone.rotate_counter_clockwise(speed), 'Key.right': lambda speed: self.drone.rotate_clockwise(speed), 'Key.up': lambda speed: self.drone.move_up(speed), 'Key.down': lambda speed: self.drone.move_down(speed), 'Key.tab': lambda speed: self.drone.takeoff(), # 'Key.tab': self.drone.takeoff(60), 'Key.backspace': lambda speed: self.drone.land(), 'p': lambda speed: self.palm_land(speed), 't': lambda speed: self.toggle_tracking(speed), 'r': lambda speed: self.toggle_recording(speed), 'z': lambda speed: self.toggle_zoom(speed), 'Key.enter': lambda speed: self.take_picture(speed) } self.key_listener = keyboard.Listener(on_press=self.on_press, on_release=self.on_release) self.key_listener.start() # self.key_listener.join() def process_frame(self): """convert frame to cv2 image and show""" # print("TRACKING START") frame = self.frame_read.frame # self.drone.move_up(self.speed) # image = self.write_hud(image) # if self.record: # self.record_vid(frame) return frame def move_up(self): self.drone.move_up(self.speed) def take_off(self): self.drone.takeoff() def go(self): self.drone.move_forward(self.go_speed) def move_left(self): self.drone.move_left(270) # speed 테스트해서 조절하기 def go_window9(self): self.drone.move_forward() def rotate_right(self): self.drone.rotate_clockwise() def rotate_left(self): self.drone.rotate_counter_clockwise() def landing(self): self.drone.land() def write_hud(self, frame): """Draw drone info, tracking and record on frame""" stats = self.prev_flight_data.split('|') stats.append("Tracking:" + str(self.tracking)) if self.drone.zoom: stats.append("VID") else: stats.append("PIC") if self.record: diff = int(time.time() - self.start_time) mins, secs = divmod(diff, 60) stats.append("REC {:02d}:{:02d}".format(mins, secs)) 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 toggle_recording(self, speed): """Handle recording keypress, creates output stream and file""" if speed == 0: return self.record = not self.record if self.record: datename = [os.getenv('HOME'), datetime.datetime.now().strftime(self.date_fmt)] self.out_name = '{}/Pictures/tello-{}.mp4'.format(*datename) print("Outputting video to:", self.out_name) self.out_file = av.open(self.out_name, 'w') self.start_time = time.time() self.out_stream = self.out_file.add_stream( 'mpeg4', self.vid_stream.rate) self.out_stream.pix_fmt = 'yuv420p' self.out_stream.width = self.vid_stream.width self.out_stream.height = self.vid_stream.height if not self.record: print("Video saved to ", self.out_name) self.out_file.close() self.out_stream = None def record_vid(self, frame): """ convert frames to packets and write to file """ new_frame = av.VideoFrame( width=frame.width, height=frame.height, format=frame.format.name) for i in range(len(frame.planes)): new_frame.planes[i].update(frame.planes[i]) pkt = None try: pkt = self.out_stream.encode(new_frame) except IOError as err: print("encoding failed: {0}".format(err)) if pkt is not None: try: self.out_file.mux(pkt) except IOError: print('mux failed: ' + str(pkt)) def take_picture(self, speed): """Tell drone to take picture, image sent to file handler""" if speed == 0: return self.drone.take_picture() def palm_land(self, speed): """Tell drone to land""" if speed == 0: return self.drone.palm_land() def toggle_tracking(self, speed): """ Handle tracking keypress""" if speed == 0: # handle key up event return self.tracking = not self.tracking print("tracking:", self.tracking) return def toggle_zoom(self, speed): """ In "video" mode the self.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 self.drone.set_video_mode(not self.drone.zoom) def flight_data_handler(self, event, sender, data): """Listener to flight data from the drone.""" text = str(data) if self.prev_flight_data != text: self.prev_flight_data = text def handle_flight_received(self, event, sender, data): """Create a file in ~/Pictures/ to receive image from the drone""" path = '%s/Pictures/tello-%s.jpeg' % ( os.getenv('HOME'), datetime.datetime.now().strftime(self.date_fmt)) with open(path, 'wb') as out_file: out_file.write(data) print('Saved photo to %s' % path) def enable_mission_pads(self): self.drone.enable_mission_pads() def disable_mission_pads(self): self.drone.disable_mission_pads() def go_xyz_speed_mid(self, x, y, z, speed, mid): self.drone.go_xyz_speed_mid(x, y, z, speed, mid) # if function return True, set drone center to object's center def track_mid(self, x, y): midx, midy = 480, 360 distance_x = abs(midx - x) distance_y = abs(midy - y) print(x, y, distance_x, distance_y) move_done = True if y > midy + self.error + 15: self.drone.move_down(20) move_done = False elif y < midy - self.error + 5: self.drone.move_up(20) move_done = False elif x < midx - self.error: self.drone.move_left(20) move_done = False elif x > midx + self.error: self.drone.move_right(20) move_done = False return move_done def track_x(self, x, left_count, right_count): midx = 480 move_done = True if x < midx - 100: self.drone.move_left(20) left_count += 1 move_done = False elif x > midx + 100: self.drone.move_right(20) right_count += 1 move_done = False return move_done def go_slow(self): self.drone.move_forward(30) def go_fast(self): self.drone.move_forward(200)
import tkinter, time, winsound def warning(): for n in range(4): # 4 short beeps winsound.Beep(1500, 500) time.sleep(0.5) winsound.Beep(1500, 1000) # 1 long beep tello = Tello() tello.connect() # Activate the mission pads tello.enable_mission_pads() tello.set_mission_pad_detection_direction(0) # use downward camera # Take off warning() tello.takeoff() tello.send_rc_control(0, 30, 0, 0) # Move forward pad = tello.get_mission_pad_id() # Look for a mission pad while pad != 1: # While we don't see pad 1 if pad == 4: # If we see pad 4 winsound.Beep(2500, 500) pad = tello.get_mission_pad_id() # Take another look # Land tello.disable_mission_pads() tello.land() tello.end()