def __init__(self): """constructor""" Subject.__init__(self) #these hold tuples that indicate the next command/request # to be issued. The string is the function to be called, and the # dictionary contains the arguments (**kwargs) self.current_command = ("none", {}) self.current_request = ("none", {}) #storage of pictures self.image_store = ImageStore() #set default interface #self.interface = SerialInterface("/dev/ttyUSB0", 115200) #self.interface = FrameGrabberInterface() self.interface = DebugInterface()
def new_project(self, path): # create the project in the filesystem try: os.mkdir(path) except OSError as e: self.notify("NEW_PROJECT", status=False) return False if not (path[-1] == '/'): path = path + '/' open(path + 'imagestore.obj', 'w') open(path + 'save_file.isp', 'w') # initialize the imagestore self.image_store = ImageStore() self.save_project(path) self.image_store.set_project_path(path) print "about to notify" # notify self.notify("NEW_PROJECT", status=True) return True
class Communicator(Subject): """class for communicating with the airplane and storing airplane data""" def __init__(self): """constructor""" Subject.__init__(self) #these hold tuples that indicate the next command/request # to be issued. The string is the function to be called, and the # dictionary contains the arguments (**kwargs) self.current_command = ("none", {}) self.current_request = ("none", {}) #storage of pictures self.image_store = ImageStore() #set default interface #self.interface = SerialInterface("/dev/ttyUSB0", 115200) #self.interface = FrameGrabberInterface() self.interface = DebugInterface() def set_interface(self, interface, **kwargs): """sets the interface used to communicate with the plane""" if interface == "none": self.interface = NoneInterface() elif interface == "serial": self.interface = SerialInterface(**kwargs) elif interface == "framegrabber": self.interface = FrameGrabberInterface() elif interface == "debug": self.interface = DebugInterface() #* #* New/Save/Load functions #* def new_project(self, path): # create the project in the filesystem try: os.mkdir(path) except OSError as e: self.notify("NEW_PROJECT", status=False) return False if not (path[-1] == '/'): path = path + '/' open(path + 'imagestore.obj', 'w') open(path + 'save_file.isp', 'w') # initialize the imagestore self.image_store = ImageStore() self.save_project(path) self.image_store.set_project_path(path) print "about to notify" # notify self.notify("NEW_PROJECT", status=True) return True def save_project(self, path=None): if not path: path = self.image_store.project_path file_handler = open(path + 'imagestore.obj', 'w') pickle.dump(self.image_store, file_handler) # notify self.notify("SAVE_PROJECT", status=True) def load_project(self, path): if not (path[-13:] == "save_file.isp"): self.notify("LOAD_PROJECT", status=False) return #print "invalid save file" #return False file_handler = open(path[:-13] + 'imagestore.obj', 'r') self.image_store = pickle.load(file_handler) # notify self.notify("LOAD_PROJECT", status=True) #* #* Functions to be called by a "controller" to initiate Communicator actions #* def toggle_power(self, **kwargs): """ command the Communicator to toggle power on the camera args: (none)""" self.current_command = ("_execute_toggle_power", kwargs) def set_mode(self, **kwargs): """ set the mode of the camera, 0 for mass storage device or 1 for usb args: mode""" self.current_command = ("_execute_set_mode", kwargs) def take_picture(self, **kwargs): """command the Communicator to make the plane take a picture. args: (none)""" self.current_command = ("_execute_take_picture", kwargs) def toggle_record(self, **kwargs): """ turn camera recording on or off args: (none)""" self.current_command = ("_execute_toggle_record", kwargs) def pan(self, **kwargs): """ pan to set point args: value""" self.current_command = ("_execute_pan", kwargs) def tilt(self, **kwargs): """ tilt to set point args: value""" self.current_command = ("_execute_tilt", kwargs) #def resume_search(self, **kwargs): # """command the Communicator to make the plane to resume # its search path. # # args: # (none)""" # self.current_command = ("_execute_resume_search", kwargs) #def lock_target(self, **kwargs): # """command the Communicator to make the plane seek a target. # # args: # xa, ya""" # self.current_command = ("_execute_lock_target", kwargs) def download_to_flc(self, **kwargs): """command the Communicator to make the plane transfer pictures from the camera memory stick to the flight linux computer. args: (none)""" self.current_command = ("_execute_download_to_flc", kwargs) def generate_crop(self, **kwargs): """command the Communicator to make the plane generate a crop of an existing image based on pixels coordinates representing two corners of a rectangle. args: picture_num, xa, ya, xb, yb""" self.current_command = ("_execute_generate_crop", kwargs) def download_image(self, **kwargs): """ command the Communicator to make the plane send down a section of an image. args: picture_num, crop_num""" self.current_request = ("_execute_download_image", kwargs) #def camera_zoom_in(self, **kwargs): # """command the Communicator to zoom camera in by increment. # # args: # increment""" # self.current_command = ("_execute_camera_zoom_in", kwargs) #def camera_zoom_out(self, **kwargs): # """command the Communicator to zoom camera in by increment. # # args: # increment""" # self.current_command = ("_execute_camera_zoom_out", kwargs) #* #* Private functions called by the Communicator to initiate commands #* through the selected 'interface' and relay data back to observers #* def _execute_toggle_power(self, **kwargs): """ command the Communicator to toggle power on the camera args: (none)""" #reset command flag / command acknowledged self.current_command = ("none", {}) print "Communicator sending request to toggle camera power" try: self.interface.toggle_power() self.notify("POWER_TOGGLED") except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) def _execute_set_mode(self, **kwargs): """ set the mode of the camera, 0 for mass storage device or 1 for usb args: mode""" #reset command flag / command acknowledged self.current_command = ("none", {}) #for notational convenience mode = kwargs['mode'] print "Communicator sending request to change the camera mode" try: self.interface.set_mode(mode) self.notify("MODE_SET", mode=mode) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) def _execute_take_picture(self, **kwargs): """command the plane to take a picture args: (none)""" #reset command flag / command acknowledged self.current_command = ("none", {}) print "Communicator sending request to take picture" try: #send the number of the picture about to be taken for data checking self.interface.take_picture(self.image_store.picture_count) #add a new picture to image store pic_num = self.image_store.add_picture() print "pic_num is %d" % (pic_num,) pict = self.image_store.get_picture(pic_num) print pict.gps_x print pict.gps_y # SPECIAL CASE: if we are using the frame grabber interface if isinstance(self.interface, FrameGrabberInterface): # update the picture with the path to the screenshot pic_name = pic_num + 1 if pic_name < 10: self.image_store.get_crop(pic_num, 1).path = self.image_store.project_path + 'shot000' + str(pic_name) + '.png' elif pic_name < 100: self.image_store.get_crop(pic_num, 1).path = self.image_store.project_path + 'shot00' + str(pic_name) + '.png' else: self.image_store.get_crop(pic_num, 1).path = self.image_store.project_path + 'shot0' + str(pic_name) + '.png' # set the crop properties crop = self.image_store.get_crop(pic_num, 1) crop.set_for_manual() self.notify("PICTURE_TAKEN", picture_num=pic_num) # SPECIAL CASE: if we are using the frame grabber interface # we need to get the info too if isinstance(self.interface, FrameGrabberInterface): pic = self.image_store.get_picture(pic_num) pic.plane_orientation = self.interface.heading pic.gps_x = self.interface.latitude pic.gps_y = self.interface.longitude #self.notify("INFO_RECEIVED") except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) def _execute_toggle_record(self, **kwargs): """ turn camera recording on or off args: (none)""" #reset command flag / command acknowledged self.current_command = ("none", {}) print "Communicator sending request to turn record mode on/off" try: self.interface.toggle_record() self.notify("RECORD_TOGGLED") except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) def _execute_pan(self, **kwargs): """ pan to set point args: value""" #reset command flag / command acknowledged self.current_command = ("none", {}) #for notational convenience value = kwargs['value'] print "Communicator sending request to pan to %d degrees" % (value,) try: self.interface.pan(value) self.notify("CAMERA_PAN", value=value) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) def _execute_tilt(self, **kwargs): """ tilt to set point args: value""" #reset command flag / command acknowledged self.current_command = ("none", {}) #for notational convenience value = kwargs['value'] print "Communicator sending request to tilt to %d degrees" % (value,) try: self.interface.tilt(value) self.notify("CAMERA_TILT", value=value) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) #def _execute_resume_search(self, **kwargs): # """command the plane to go into search mode # # args: # (none)""" # # #reset command flag / command acknowledged # self.current_command = ("none", {}) # # print "Communicator sending request to resume search" # try: # self.interface.resume_search() # # self.notify("SEARCH_RESUMED") # except InterfaceError as e: # self.notify("INTERFACE_ERROR", \ # msg=e.value, \ # function=sys._getframe().f_code.co_name) #def _execute_lock_target(self, **kwargs): # """command the plane to lock onto a target based on pixel values. # # args: # xa, ya""" # # #reset command flag / command acknowledged # self.current_command = ("none", {}) # # #for notational convenience # xa = kwargs['xa'] # ya = kwargs['ya'] # print "Communicator sending request to lock target" # # try: # self.interface.lock_target(xa, ya) # # self.notify("LOCKED_TARGET") # except InterfaceError as e: # self.notify("INTERFACE_ERROR", \ # msg=e.value, \ # function=sys._getframe().f_code.co_name) def _execute_download_to_flc(self, **kwargs): """command the plane to download images from the camera memory stick to the flight linux computer. args: (none)""" #reset command flag / command acknowledged self.current_command = ("none", {}) print "Communicator sending request to download to flc" try: self.interface.download_to_flc() #generate make thumbnails available for all pictures that have # been taken (if this is called more than once it will loop from # 0 again, but it's not a big deal because a picture can never # become unavailable once it is available) for i in range(0, self.image_store.picture_count): self.image_store.get_crop(i, 1).available = True self.notify("DOWNLOADED_TO_FLC", picture_count=self.image_store.picture_count) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) def _execute_generate_crop(self, **kwargs): """command the plane to generate a crop from an image based on pixel data representing 2 corners of a square args: picture_num, xa, ya, xb, yb """ #reset command flag / command acknowledged self.current_command = ("none", {}) #for notational convenience picture_num = kwargs['picture_num'] xa = kwargs['xa'] ya = kwargs['ya'] xb = kwargs['xb'] yb = kwargs['yb'] print "generating a new crop for %d" % (picture_num,) try: self.interface.generate_crop(picture_num=picture_num, \ xa=xa, ya=ya, xb=xb, yb=yb) #add a new crop to the crop_list crop_num = len(self.image_store.picture_list[picture_num].crop_list) self.image_store.picture_list[picture_num].add_crop(xa, ya) self.image_store.get_crop(picture_num, crop_num).available = True self.image_store.get_crop(picture_num, crop_num).path = \ self.image_store.project_path + "pic" + str(picture_num) \ + "crop" + str(crop_num) + ".jpg" self.notify("CROP_GENERATED", \ picture_num=picture_num, crop_num=crop_num) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) def _execute_download_image(self, **kwargs): """command the plane to transmit a section of an image args: picture_num, crop_num """ #reset request flag / request acknowledged self.current_request = ("none", {}) #for notational convenience picture_num = kwargs['picture_num'] crop_num = kwargs['crop_num'] print "sending request to download image" #check if the picture in question is available for download if (self.image_store.get_crop(picture_num, crop_num).available == True): #if the picture has size 0, initialize the picture for download if (self.image_store.get_crop(picture_num, crop_num).size == 0): #get the size and update the model print "initializing picture %d, crop %d" % (picture_num, crop_num) try: #if the crop is 0, we're downloading the thumbnail, we want # all the info relevant to the picture (i.e. plane angles, # camera angles, and gps info at the time the pic was taken if crop_num == 1: (gpsx_str, gpsy_str, pan_str, tilt_str, \ yaw_str, pitch_str, roll_str, \ plane_orientation_str, altitude_str) = \ self.interface.request_info(picture_num) gps_x = float(gpsx_str) gps_y = float(gpsy_str) pan = float(pan_str) tilt = float(tilt_str) yaw = float(yaw_str) pitch = float(pitch_str) roll = float(roll_str) plane_orientation = float(plane_orientation_str) altitude = float(altitude_str) picture = self.image_store.get_picture(picture_num) picture.gps_x = gps_x picture.gps_y = gps_y picture.pan = pan picture.tilt = tilt picture.yaw = yaw picture.pitch = pitch picture.roll = roll picture.plane_orientation = plane_orientation picture.altitude = altitude self.notify("INFO_RECEIVED", \ picture_num = picture_num, \ gps_x = gps_x, \ gps_y = gps_y, \ pan = pan, \ tilt = tilt, \ yaw = yaw, \ pitch = pitch, \ roll = roll) print "requesting size of picture %d, crop %d" % (picture_num, crop_num) #now we get the size of the crop (crop_size_str,) = self.interface.request_size(picture_num, crop_num) crop_size = int(crop_size_str) self.image_store.get_crop(picture_num, crop_num).size = crop_size #now that we have the size calculate the amount of # segments needed to dl the full pic self.image_store.get_crop(picture_num, crop_num).calculate_total_segments() #notify observers self.notify("SIZE_CALCULATED", \ picture_num=picture_num, \ crop_num=crop_num, \ size=crop_size) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) #the picture has size info, download it else: segment_num = self.image_store.get_crop(picture_num, crop_num).segments_downloaded print "downloading segment %d of picture %d crop %d" % (segment_num, picture_num, crop_num) try: (segment_data,) = self.interface.download_segment( \ picture_num = picture_num, \ crop_num = crop_num, \ segment_num = segment_num) #store the data with the corresponding picture self.image_store.get_crop(picture_num, crop_num).save_segment(segment_data, segment_num) percent_complete = self.image_store.get_crop(picture_num, crop_num).get_percent_complete() #check for completion if self.image_store.get_crop(picture_num, crop_num).segments_downloaded == \ self.image_store.get_crop(picture_num, crop_num).total_segments(): print "picture %d crop %d completed downloading" % (picture_num,crop_num) self.image_store.get_crop(picture_num, crop_num).completed = True #notify observers self.notify("IMAGE_DOWNLOADED", \ picture_num=picture_num, \ crop_num=crop_num, \ percent_complete=percent_complete) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) #def _execute_camera_zoom_in(self, **kwargs): # """command the plane to zoom camera in. # # args: # increment""" # # #reset command flag / command acknowledged # self.current_command = ("none", {}) # # #for notational convenience # increment = kwargs['increment'] # print "Communicator sending request to zoom in" # # try: # self.interface.camera_zoom_in(increment) # self.notify("CAMERA_ZOOM_IN") # # except InterfaceError as e: # self.notify("INTERFACE_ERROR", \ # msg=e.value, \ # function=sys._getframe().f_code.co_name) #def _execute_camera_zoom_out(self, **kwargs): # """command the plane to zoom camera out. # # args: # increment""" # # #reset command flag / command acknowledged # self.current_command = ("none", {}) # # #for notational convenience # increment = kwargs['increment'] # print "Communicator sending request to zoom out" # # try: # self.interface.camera_zoom_out(increment) # self.notify("CAMERA_ZOOM_OUT") # # except InterfaceError as e: # self.notify("INTERFACE_ERROR", \ # msg=e.value, \ # function=sys._getframe().f_code.co_name) def _execute_ping(self): """ping the plane and transmit back the latency.""" #reset command flag / command acknowledged self.current_command = ("none", {}) try: #record the latency latency = self.interface.ping() self.notify("PING", latency=latency) except InterfaceError as e: self.notify("INTERFACE_ERROR", \ msg=e.value, \ function=sys._getframe().f_code.co_name) #* #* Main Loop #* def main(self): """main loop that processes commands coming in from controllers""" while True: # prevent loop from using 100% cpu time.sleep(.1) # handle the current command or request if self.current_command[0] != "none": #calls the method with the same name as the string # stored in current_command and passes arguments from kwargs getattr(self, self.current_command[0])(**self.current_command[1]) elif self.current_request[0] != "none": #calls the method with the same name as the string # stored in current_request and passes arguments from kwargs getattr(self, self.current_request[0])(**self.current_request[1]) else: #ping the plane #self._execute_ping() pass