Example #1
0
class Gamelist():
    def __init__(self, drive, platform):
        GameListData.game_list_data_json = GameListData().get_game_list()
        self.json_game_list_data = GameListData.game_list_data_json

        if drive == 'USB(*)':
            self.drive_to_show = '/dev_' + drive.lower().replace('(*)', '')
        else:
            self.drive_to_show = '/dev_' + drive.lower() + '/'

        self.platform_to_show = platform + '_games'
        self.WCM_BASE_PATH  = AppPaths.wcm_gui
        self.last_selection = (None, 0)
        self.list_of_items = []

        self.selected_title_id   = None
        self.selected_title      = None
        self.selected_path       = None
        self.selected_filename   = None
        self.drive_system_path_array = None

        self.is_cleared = False


    def create_main_frame(self, entry_field_title_id, entry_field_title, entry_field_filename, entry_field_iso_path, entry_field_platform, drive_system_array):
        self.entry_field_title_id       = entry_field_title_id
        self.entry_field_title          = entry_field_title
        self.entry_field_filename       = entry_field_filename
        self.entry_field_iso_path       = entry_field_iso_path
        self.entry_field_platform       = entry_field_platform
        self.drive_system_path_array    = drive_system_array

        self.corrected_index = []
        self.main_frame = Frame()

        self.popup_menu = Menu(self.main_frame, tearoff=0)

        self.popup_menu.add_command(label="Delete",
                                    command=self.delete_selected)
        self.popup_menu.add_command(label="Rename",
                                    command=self.rename_selected)
        # self.popup_menu.add_command(label="Refetch",
        #                             command=self.refetch)
        # self.popup_menu.add_command(label="Select All",
        #                             command=self.select_all)




        s = Scrollbar(self.main_frame)
        self._listbox = Listbox(self.main_frame, width=465)
        self._listbox.bind('<Enter>', self._bound_to_mousewheel)
        self._listbox.bind('<Leave>', self._unbound_to_mousewheel)
        self._listbox.bind("<Button-3>", self.popup) # Button-2 on Aqua

        s.pack(side=RIGHT, fill=Y)
        self._listbox.pack(side=LEFT, fill=Y)

        s['command'] = self._listbox.yview
        self._listbox['yscrollcommand'] = s.set



        # default filters
        if 'ALL_games' == self.platform_to_show:
            # iterate all platforms
            for platform in self.json_game_list_data:
                for list_game in self.json_game_list_data[platform]:
                    # titles in the list has been designed to be unique
                    if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']:
                        self.add_item(list_game['title'])

        else:
            for list_game in self.json_game_list_data[self.platform_to_show]:
                if '/dev_all/' == self.drive_to_show or self.drive_to_show in list_game['path']:
                    self.add_item(list_game['title'])

        for x in range(19 - self._listbox.size()):
            self.add_item('')


        # adding shade to every other row of the list
        for x in range(0, self._listbox.size()):
            if x % 2 == 0:
                self._listbox.itemconfig(x, {'fg': 'white'}, background='#001738')
            else:
                self._listbox.itemconfig(x, {'fg': 'white'}, background='#001F4C')

        self.label = Label(self.main_frame)
        self.selection_poller()

        return self.main_frame

    def selection_poller(self):
        self.label.after(200, self.selection_poller)
        self.new_selection = self._listbox.curselection()
        # cursor har been initiated
        if self._listbox.curselection() is not ():
            if self.new_selection[0] is not self.last_selection[0] or self.is_cleared:
                self.entry_fields_update(self.new_selection)
                self.is_cleared = False
                self.last_selection = self.new_selection


    def entry_fields_update(self, new_selection):
        for platform in self.json_game_list_data:

            for list_game in self.json_game_list_data[platform]:
                self.selected_title = self._listbox.get(new_selection[0])
                tmp_title = list_game['title']

                match = self.selected_title == str(tmp_title)
                if match:
                    self.selected_title_id   = str(list_game['title_id']).replace('-', '')
                    self.selected_title      = str(list_game['title'])
                    self.selected_path       = str(list_game['path'])
                    self.selected_filename   = str(list_game['filename'])
                    self.selected_platform   = str(list_game['platform'])

                    # parse drive and system from json data
                    path_array = filter(None, self.selected_path.split('/'))
                    self.drive_system_path_array[0] = path_array[0]
                    self.drive_system_path_array[1] = path_array[1]
                    self.drive_system_path_array[2] = '/'.join(path_array[2:len(path_array)]).replace('//', '')


                    self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1)
                    self.entry_field_title_id.delete(0, END)
                    self.entry_field_title_id.insert(0, self.selected_title_id)

                    self.entry_field_title.delete(0, END)
                    self.entry_field_title.insert(0, self.selected_title)

                    self.entry_field_filename.delete(0, END)
                    self.entry_field_filename.insert(0, self.selected_filename)

                    self.entry_field_platform.delete(0, END)
                    self.entry_field_platform.insert(0, self.selected_platform)

                    return True



    def get_selected_path(self):
        return self.current_iso_path

    def get_listbox(self):
        return self._listbox

    def get_ascending_index(self, list_of_items, item, ignore_case=True):
        lo = 0
        hi = len(list_of_items)

        if ignore_case:
            item = item.lower()
            while lo < hi:
                mid = (lo + hi) // 2

                if item < list_of_items[mid].lower():
                    hi = mid
                else:
                    lo = mid + 1
        else:
            while lo < hi:
                mid = (lo + hi) // 2

                if item < list_of_items[mid]:
                    hi = mid
                else:
                    lo = mid + 1
        return lo

    def add_item(self, item):
        if item != '':
            self.list_of_items = self._listbox.get(0, END)
            # getting ascending index in order to sort alphabetically
            index = self.get_ascending_index(self.list_of_items, item)

            self._listbox.insert(index, item)
        else:
            self._listbox.insert(END, item)

    def get_items(self):
        return self.list_of_items

    def _bound_to_mousewheel(self, event):
        self._listbox.bind_all("<MouseWheel>", self._on_mousewheel)

    def _unbound_to_mousewheel(self, event):
        self._listbox.unbind_all("<MouseWheel>")

    def _on_mousewheel(self, event):
        self._listbox.yview_scroll(int(-1*(event.delta/30)), "units")

    def popup(self, event):
        try:
            self._listbox.selection_clear(0, END)
            self._listbox.selection_set(self._listbox.nearest(event.y))
            self._listbox.activate(self._listbox.nearest(event.y))
        finally:
            if self._listbox.get(self._listbox.curselection()[0]) is not '':
                self.popup_menu.tk_popup(event.x_root + 43, event.y_root + 12, 0)
                self.popup_menu.grab_release()
                self.popup_menu.focus_set()

    def delete_selected(self):
        import tkMessageBox
        game_folder_path = os.path.join(AppPaths.game_work_dir, '..')
        response = tkMessageBox.askyesno('Delete game folder', 'Delete \'' + self.entry_field_title.get() + '\'?\n\nFolder path: ' + os.path.realpath(game_folder_path))
        # yes
        if response:
            # remove game from visual game list
            for i in self._listbox.curselection()[::-1]:
                self._listbox.delete(i)
                removed_index = i

            # remove game from json game list
            platform_key = self.entry_field_platform.get() + '_games'
            self.json_game_list_data[platform_key] = [x for x in self.json_game_list_data[platform_key] if x['title'] != self.selected_title]

            # update the json game list file
            with open(GameListData.GAME_LIST_DATA_PATH, 'w') as newFile:
                json_text = json.dumps(self.json_game_list_data, indent=4, separators=(",", ":"))
                newFile.write(json_text)

            # remove the game build folder too
            if AppPaths.game_work_dir != os.path.join(AppPaths.wcm_gui, 'work_dir'):
                if os.path.isdir(game_folder_path):
                    if 'webman-classics-maker' in game_folder_path:
                        shutil.rmtree(game_folder_path)
                # clear entry_fields
                self.clear_entries_and_path()
                # set cursor
                self._listbox.select_set(removed_index) #This only sets focus on the first item.

    def rename_selected(self):
        self.entry_field_title.selection_range(0, END)
        self.entry_field_title.focus_set()

    def select_all(self):
        self._listbox.selection_set(0, 'end')


    def clear_entries_and_path(self):
        self.entry_field_title_id.delete(0, len(self.entry_field_title_id.get())-1)
        self.entry_field_title_id.delete(0, END)
        self.entry_field_title.delete(0, END)
        self.entry_field_platform.delete(0, END)
        self.entry_field_filename.delete(0, END)

        self.is_cleared = True



    def get_selected_build_dir_path(self):
        self.build_dir_path = ''
        if self.selected_filename not in {'', None}:
            filename = self.selected_filename
            title_id = self.selected_title_id.replace('-', '')
            build_base_path = AppPaths.builds

            tmp_filename = filename
            # removes the file extension from tmp_filename
            for file_ext in GlobalVar.file_extensions:
                if filename.upper().endswith(file_ext):
                    tmp_filename = filename[0:len(filename)-len(file_ext)]
                    break
            game_folder_name = tmp_filename.replace(' ', '_') + '_(' + title_id.replace('-', '') + ')'

            self.build_dir_path = os.path.join(build_base_path, game_folder_name)
        return self.build_dir_path
Example #2
0
class IviGui:
    def __init__(self, master):
        self.master = master
        master.title("U2001A power measurement")

        # Label and Entry for inputting relative/attenuator value
        self.atten = Label(master, text="Relative (dB):")
        self.atten.grid(row=1, column=1)
        self.entry = Entry(master)
        self.entry.insert(0, '0')
        self.entry.grid(row=1, column=2)

        # Main display label. Shows relative measurement with dot during updates
        self.label = Label(master,
                           text=" \n-NaN dBm",
                           font=("Arial", 32),
                           height=3,
                           width=20)
        self.label.grid(row=2, column=1, columnspan=2)
        # Smaller secondary display to show real measurement by device
        self.label2 = Label(master, text=" \n-NaN dBm", font=("Arial", 16))
        self.label2.grid(row=3, column=1, columnspan=2)

        print usbtmc.list_resources()  # List USBTMC resources to connect to.
        self.instr = usbtmc.Instrument(
            'USB::10893::11032::INSTR'
        )  # Your device to connect to. Pick from the list.
        self.instr.timeout = 60 * 1000  # Some devices are slow, some configurations are slow, timeout in ms.
        print self.instr.ask(
            "*IDN?"
        )  # Print out what device itself thinks its name is for validation.

        # Keysight U2001A trigger setup - free running trigger
        self.instr.write("INIT[1]:CONT 1")
        self.instr.write("TRIG[1]:SOUR IMM")

        # Init the variables
        self.measurement = -100
        self.original_background = self.entry.cget("background")

        # Start first measurement
        self.update()

    # This method polls the device and updates display. Polling can take long time.
    def update(self):
        self.measurement = self.instr.ask("MEAS?")
        #print "%.2f" % float(self.measurement)      # Debug printout to check the connection.

        self.update_number(True)
        self.label.after(100, self.remove_dot)

    # 100 ms after getting a measurement from the device, remove the dot above the measurement.
    # This provided clear indication to user about when the data was updated.
    def remove_dot(self):
        self.update_number(False)
        self.label.after(100, self.update)

    # Deal with getting the relative number from the Entry and updating all the displays.
    def update_number(self, dot=False):
        try:
            relative_value = float(self.entry.get())
            self.entry.config(background=self.original_background)

            if dot:
                self.label.config(text=".\n%.2f dBm" %
                                  (float(self.measurement) - relative_value))
            else:
                self.label.config(text=" \n%.2f dBm" %
                                  (float(self.measurement) - relative_value))

        # If the relative box shows gibberish, just display the measurement.
        except ValueError:
            self.entry.config(background="#A44")

            if dot:
                self.label.config(text=".\n%.2f dBm" % float(self.measurement))
            else:
                self.label.config(text=" \n%.2f dBm" % float(self.measurement))

        self.label2.config(text="%.2f dBm" % float(self.measurement))
class DroneGUI:
    def __init__(self, master):
        self.master = master
        master.title("Drone GUI")

        ## Initialising framework of GUI
        self.frame1 = Frame(master,
                            height=480,
                            width=200,
                            bd=2,
                            relief="sunken")
        self.frame1.grid(row=3, column=1, rowspan=15)
        self.frame1.grid_propagate(False)

        explanation_label = Label(
            master,
            justify='left',
            text=
            "How you control the drone \nW - move forwards \nS - move down \nA - move let \nD - move right \nI - move up \nK - move down \nJ - rotate counterclockwise \nL - rotate clockwise \nENTER - Takeoff/Land"
        )
        explanation_label.grid(row=4, column=1, rowspan=15)

        self.abort_button = Button(master,
                                   text="ABORT",
                                   command=self.abort_auto_flight,
                                   bg="grey",
                                   fg="lightgrey",
                                   state="disabled")
        self.abort_button.grid(row=17, column=1)

        frame2 = Frame(master, height=480, width=200, bd=2, relief="sunken")
        frame2.grid(row=3, column=3, rowspan=15)
        frame2.grid_propagate(False)

        self.select_target_button = Button(master,
                                           text="Select target",
                                           command=self.select_target)
        self.select_target_button.grid(row=4, column=3)

        self.distance_label = Label(master, text="Distance: NA")
        self.distance_label.grid(row=6, column=3)

        self.battery_label = Label(master, text="Battery level: NA")
        self.battery_label.grid(row=8, column=3)

        header_label = Label(master, text="Choosing target for drone")
        header_label.grid(row=1, column=8)

        self.close_button = Button(master, text="Close", command=master.quit)
        self.close_button.grid(row=1, column=20)

        self.image_label = Label(text="", height=480, width=640)
        self.image_label.grid(row=3, column=6, columnspan=15, rowspan=15)

        ## Initialising variables for selecting target
        self.imgClick = False
        self.bridge = CvBridge()
        self.enable_video_stream = None
        self.prev_img = None
        self.select_target_bool = False

        self.circle_center = [None, None]

        ## Initialising variables for autonoumous flight
        self.flying = False
        self.auto_flying = False
        self.abort_bool = False

        ## Enabling keyboard control of drone
        self.master.bind("<Key>", self.move_drone)
        self.master.bind("<KeyRelease>", self.key_release)
        self.master.bind("<Return>", self.return_key_pressed)

        ## Initialising of publishers and subscribers
        self.distance_sub = rospy.Subscriber('distance', Pose,
                                             self.update_distance_label)
        self.pid_enable_sub = rospy.Subscriber('pid_enable', Bool,
                                               self.pid_enabled)
        self.battery_sub = rospy.Subscriber(
            'bebop/CommonStates/BatteryLevelChanged', UInt8,
            self.update_battery_label)

        self.target_sub = rospy.Subscriber("target", Pose, self.draw_target)

        self.image_sub = rospy.Subscriber('/webcam/image_raw', SensorImage,
                                          self.image_subscriber_callback)

        self.gui_target_pub = rospy.Publisher('gui_target',
                                              Pose,
                                              queue_size=10)
        self.abort_pub = rospy.Publisher('abort', Bool, queue_size=10)
        self.drone_vel_pub = rospy.Publisher('bebop/cmd_vel',
                                             Twist,
                                             queue_size=10)
        self.takeoff_pub = rospy.Publisher('bebop/takeoff',
                                           Empty,
                                           queue_size=10)
        self.land_pub = rospy.Publisher('bebop/land', Empty, queue_size=10)

        rospy.init_node('gui', anonymous=True)
        self.rate = rospy.Rate(10)
        rospy.loginfo("GUI initialised")

        self.abort_pub.publish(self.abort_bool)

    def image_subscriber_callback(self, image):
        cv_image = CvBridge().imgmsg_to_cv2(image, "rgb8")
        # cv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
        if self.circle_center[0] != None:
            cv2.circle(
                cv_image,
                (int(self.circle_center[0]), int(self.circle_center[1])), 3,
                (0, 255, 0), 10)
        self.img = Image.fromarray(cv_image)
        # print("got image")

    def draw_target(self, data):
        self.circle_center = [data.position.x, data.position.y]

    def update_image(self):
        ## Updating the image from the 'drone_cam_sub.py', if it's new. The update is automatic with a frequency 20 Hz (50 ms)
        frequency = 20
        try:
            if self.img != self.prev_img:
                self.imgtk = ImageTk.PhotoImage(self.img)
                self.image_label.pic = self.imgtk
                self.image_label.configure(image=self.imgtk)
                self.prev_img = self.img
        except:
            print("Image not updated")
        self.enable_video_stream = self.image_label.after(
            int(1000 / frequency), self.update_image)

    def select_target(self):
        ## Allows the user to select target, and interrupt selection if wanted
        if not self.select_target_bool:
            rospy.loginfo("User is selecting target")
            self.select_target_bool = True
            self.imgClick = True
            self.select_target_button.configure(text="Cancel")
            self.image_label.bind("<Button-1>", self.target_selected)
            self.image_label.configure(cursor="dotbox")
        else:
            rospy.loginfo("User cancelled selection")
            self.select_target_bool = False
            self.imgClick = False
            self.select_target_button.configure(text="Select target")
            self.image_label.unbind("<Button-1>")
            self.image_label.configure(cursor="")

    def target_selected(self, event):
        ## Once target has been selected, variables and functions need to be reset.
        ## By un-commenting line 158 control will be disabled, once autonomous flight is enabled
        ## (For now it is possible to interfere with the drone by using the keyboard)
        self.select_target_bool = False

        rospy.loginfo("User selected target")
        self.imgClick = False
        save_pos(event)
        self.publish_pos()
        self.update_image()
        self.select_target_button.configure(text="Select target")
        self.image_label.unbind("<Button-1>")
        self.image_label.configure(cursor="")
        #self.auto_flying = True

    def move_drone(self, event):
        ## if auto_flying = True no other option than pressing 'g' is possible
        if self.flying and not self.auto_flying:
            cmd = Twist()
            factor = 0.5
            rospy.loginfo("User pressed " + repr(event.char))
            if event.char == 'a':
                cmd.linear.y = factor
            elif event.char == 'd':
                cmd.linear.y = -factor
            elif event.char == 'w':
                cmd.linear.x = factor
            elif event.char == 's':
                cmd.linear.x = -factor
            elif event.char == 'j':
                cmd.angular.z = factor
            elif event.char == 'l':
                cmd.angular.z = -factor
            elif event.char == 'i':
                cmd.linear.z = factor
            elif event.char == 'k':
                cmd.linear.z = -factor
            elif event.char == 'g':
                if not self.abort_bool:
                    self.abort_auto_flight()
                cmd.linear.x = -factor
            self.drone_vel_pub.publish(cmd)
        elif self.flying:
            if event.char == 'g':
                if not self.abort_bool:
                    self.abort_auto_flight()
                cmd.linear.x = -factor
            self.drone_vel_pub.publish(cmd)

    def key_release(self, event):
        cmd = Twist()
        cmd.linear.x = 0
        cmd.linear.y = 0
        cmd.linear.z = 0
        cmd.angular.z = 0
        self.drone_vel_pub.publish(cmd)

    def return_key_pressed(self, event):
        ## enabling takeoff and landing
        if not self.flying:
            self.flying = True
            e = Empty()
            self.takeoff_pub.publish(e)
        else:
            self.abort_pub.publish(True)

            self.flying = False
            e = Empty()
            self.land_pub.publish(e)

    def abort_auto_flight(self):
        ## aborting autonousmous flight and allowing the user the have full control of the drone again
        rospy.loginfo("Aborting")

        self.abort_bool = True
        self.abort_pub.publish(self.abort_bool)

        cmd = Twist()
        cmd.linear.x = 0
        cmd.linear.y = 0
        cmd.linear.z = 0
        cmd.angular.z = 0
        self.drone_vel_pub.publish(cmd)

    def pid_enabled(self, data):
        ## cheching whether the move_to_target program is running
        data = str(data)
        if data == 'data: True':
            self.abort_button.configure(state="active", bg="grey", fg="black")
        if data == False and self.abort_bool == True:
            self.abort_bool = False
            self.abort_pub.publish(self.abort_bool)

    def update_distance_label(self, data):
        self.distance_label.configure(
            text='Distance: {:02.2f} m'.format(data.position.x))

    def update_battery_label(self, data):
        self.battery_label.configure(text='Battery level: {}'.format(data))

    def publish_pos(self):
        #publishing the position of the target position in pixels
        if not rospy.is_shutdown():
            p = Pose()
            p.position.x = pos_x
            p.position.y = pos_y
            self.gui_target_pub.publish(p)
            self.rate.sleep()
Example #4
0
class DroneGUI:
    def __init__(self, master):
        self.master = master
        master.title("Drone GUI")

        ## Initialising framework of GUI
        frame1 = Frame(master, height=350, width=210, bd=2, relief="sunken")
        frame1.grid(row=10, column=2, rowspan=6)
        frame1.grid_propagate(False)

        ## Buttons
        self.select_target_button = Button(master,
                                           text="Select target",
                                           command=self.select_target)
        self.select_target_button.grid(row=4, column=2)

        self.start_auto_button = Button(master,
                                        text="Start autonomous flight",
                                        command=self.start_autonomous)
        self.start_auto_button.grid(row=5, column=2)
        self.approach_button = Button(master,
                                      text="Approach target",
                                      command=self.set_approach)
        self.approach_button.grid(row=6, column=2)

        self.e1 = Entry(master)
        self.e1.grid(row=7, column=2)
        self.e1.bind("<Return>", self.get_target_distance)

        self.close_button = Button(master,
                                   text="Close",
                                   command=self.close_gui)
        self.close_button.grid(row=8, column=2)

        self.battery_label = Label(master, text="Battery level: NA")
        self.battery_label.grid(row=10, column=2)

        self.x_distance_label = Label(master, text="X Distance: NA")
        self.x_distance_label.grid(row=11, column=2)

        self.y_distance_label = Label(master, text="Y Distance: NA")
        self.y_distance_label.grid(row=12, column=2)

        self.z_distance_label = Label(master, text="Z Distance: NA")
        self.z_distance_label.grid(row=13, column=2)

        self.yaw_distance_label = Label(master, text="Yaw angle: NA")
        self.yaw_distance_label.grid(row=14, column=2)

        self.flight_status_label = Label(master, text="Autonomous mode: 0")
        self.flight_status_label.grid(row=15, column=2)

        header_label = Label(master, text="Choosing target for drone")
        header_label.grid(row=1, column=5)

        self.bb_data = (None, None, None, None)

        self.image_label = Label(text="", height=720, width=1280)
        # self.image_label = Label(text = "", height = 480, width = 640)
        # self.image_label = Label(text = "", height = 448, width = 800)
        # self.image_label = Label(text = "", height = 1200, width = 1600)
        self.image_label.grid(row=3, column=5, columnspan=15, rowspan=15)

        self.control_status = 0
        self.xTarget = 0

        ## Initialising variables for selecting target
        self.imgClick = False
        self.bridge = CvBridge()
        self.enable_video_stream = None
        self.prev_img = None
        self.select_target_bool = False

        self.circle_center = [None, None]

        self.pos_x = -1
        self.pos_y = -1

        # Subscribers
        self.battery_sub = rospy.Subscriber('/dji_sdk/battery_state',
                                            BatteryState,
                                            self.update_battery_label)
        self.target_sub = rospy.Subscriber("/visual_tracker/target", Twist,
                                           self.draw_target)
        self.distance_error_sub = rospy.Subscriber(
            "/visual_tracker/distance_error", Point,
            self.update_distance_error)
        self.image_sub = rospy.Subscriber('/camera/image_decompressed',
                                          SensorImage,
                                          self.image_subscriber_callback)

        self.distance_sub = rospy.Subscriber('/laser_wall/wall_position',
                                             Float32MultiArray,
                                             self.update_distance_label)

        # Publishers
        self.gui_target_pub = rospy.Publisher('/visual_tracker/gui_target',
                                              Point,
                                              queue_size=1)
        self.frame_pub = rospy.Publisher('/visual_tracker/frame_num',
                                         UInt8,
                                         queue_size=1)
        self.control_status_msg = rospy.Publisher(
            '/visual_tracker/target_tracking_msg', UInt8, queue_size=1)

        rospy.init_node('gui_v2', anonymous=False)

        rospy.Timer(rospy.Duration(1.0 / 30.0),
                    self.control_status_publish_callback)

        rospy.loginfo("GUI initialised")

    def save_pos(self, event):
        ## updating the position of the target point from position of mouse click on image
        self.pos_x = event.x
        self.pos_y = event.y

    def get_target_distance(self, entry):
        val = int(eval(self.e1.get()))
        if (val < 1 or val > 5):
            self.e1.delete(0, 10)
            self.e1.insert("Invalid value")
        else:
            self.xTarget = val

    def close_gui(self):
        self.control_status = 0
        msg = UInt8()
        for i in range(1, 10):
            msg.data = self.control_status
            self.control_status_msg.publish(msg)
            rospy.sleep(rospy.Duration(0.05))
        self.master.quit()

    def control_status_publish_callback(self, time_event):
        self.flight_status_label.configure(
            text="Autonomous mode: {}".format(self.control_status))
        msg = UInt8()
        msg.data = self.control_status
        self.control_status_msg.publish(msg)

    def start_autonomous(self):
        if (self.control_status < 1 and self.circle_center[0] != None):
            self.control_status = 1
            rospy.loginfo("Autonomous tracking started")
        else:
            rospy.loginfo("No target selected")

    def set_approach(self):
        if (self.control_status > 0 and self.xTarget != 0):
            self.control_status = 1 + self.xTarget
        elif (self.xTarget == 0):
            rospy.loginfo("Approach distance not set")
        else:
            rospy.loginfo("No target selected or autonomous control not set")

    def image_subscriber_callback(self, image):
        cv_image = CvBridge().imgmsg_to_cv2(image, "rgb8")
        cv2.circle(cv_image, (640, 360), 1, (255, 0, 0), 10)
        if self.circle_center[0] != None:
            cv2.circle(
                cv_image,
                (int(self.circle_center[0]), int(self.circle_center[1])), 3,
                self.circ_color, 10)
            if self.bb_data[0] != None:
                cv2.rectangle(cv_image, (self.bb_data[0], self.bb_data[1]),
                              (self.bb_data[0] + self.bb_data[2],
                               self.bb_data[1] + self.bb_data[3]),
                              self.circ_color, 2)
        self.img = Image.fromarray(cv_image)

    def draw_target(self, data):
        self.circle_center = [data.linear.x, data.linear.y]
        if data.linear.z:
            self.circ_color = (0, 255, 0)
        else:
            self.circ_color = (255, 0, 0)
        if data.angular.z:
            self.bb_data = (int(data.linear.x - data.angular.x / 2),
                            int(data.linear.y - data.angular.y / 2),
                            int(data.angular.x), int(data.angular.y))
        else:
            self.bb_data = (None, None, None, None)

    def update_image(self):
        ## Updating the image from the 'drone_cam_sub.py', if it's new. The update is automatic with a frequency 20 Hz (50 ms)
        frequency = 30.0
        try:
            if self.img != self.prev_img:
                self.imgtk = ImageTk.PhotoImage(self.img)
                self.image_label.pic = self.imgtk
                self.image_label.configure(image=self.imgtk)
                self.prev_img = self.img
        except:
            print("Image not updated")
        self.enable_video_stream = self.image_label.after(
            int(1000 / frequency), self.update_image)

    def select_target(self):
        ## Allows the user to select target, and interrupt selection if wanted
        if not self.select_target_bool:
            rospy.loginfo("User is selecting target")
            self.select_target_bool = True
            self.imgClick = True
            self.select_target_button.configure(text="Cancel")
            self.image_label.bind("<Button-1>", self.target_selected)
            self.image_label.configure(cursor="dotbox")
        else:
            rospy.loginfo("User cancelled selection")
            self.select_target_bool = False
            self.imgClick = False
            self.select_target_button.configure(text="Select target")
            self.image_label.unbind("<Button-1>")
            self.image_label.configure(cursor="")

    def target_selected(self, event):
        ## Once target has been selected, variables and functions need to be reset.
        ## By un-commenting line 158 control will be disabled, once autonomous flight is enabled
        ## (For now it is possible to interfere with the drone by using the keyboard)
        self.select_target_bool = False

        rospy.loginfo("User selected target")
        self.imgClick = False
        self.save_pos(event)
        self.publish_pos()
        self.update_image()
        self.select_target_button.configure(text="Select target")
        self.image_label.unbind("<Button-1>")
        self.image_label.configure(cursor="")

    def update_distance_label(self, data):
        self.x_distance_label.configure(
            text='X Distance:\n{:02.2f} m'.format(data.data[4]))
        self.yaw_distance_label.configure(
            text='Yaw angle:\n{:02.2f} deg'.format(data.data[2]))

    def update_distance_error(self, data):
        # self.x_distance_label.configure( text = 'X Distance:\n{:02.2f} m'.format(data.x))
        self.y_distance_label.configure(
            text='Y Distance:\n{:02.2f} m'.format(data.y))
        self.z_distance_label.configure(
            text='Z Distance:\n{:02.2f} m'.format(data.z))

    def update_battery_label(self, data):
        self.battery_label.configure(
            text='Battery level:\n{} %'.format(data.percentage))

    def publish_pos(self):
        #publishing the position of the target position in pixels
        if not rospy.is_shutdown():
            p = Point()
            p.x = self.pos_x
            p.y = self.pos_y
            p.z = 0
            self.gui_target_pub.publish(p)
            rospy.loginfo("New Gui target published (%d, %d)", self.pos_x,
                          self.pos_y)
Example #5
0
class ROIApp(object):

    def __init__(self, source_dir):
        self.state = "Selecting"

        self.image_types = ["ppm", "jpg", "jpeg", "png", "bmp"]  # Add more
        self.source_dir = source_dir
        self.gt_filename = os.path.join(self.source_dir, "gt.txt")
        images = self.get_images()
        self.image_fullpaths = (
            os.path.join(self.source_dir, image_filename)
            for image_filename in images)
        self.current_image_fullpath = None
        self.gt_file = open(self.gt_filename, 'a')
        self.gt_writer = csv.writer(self.gt_file, delimiter=";")

        self.root = Tk()
        self.root.bind("<Escape>", lambda e: self.quit())
        self.root.bind("<KP_Enter>", self.on_kp_enter)
        self.root.bind("<Return>", self.on_kp_enter)
        self.root.wm_title("ROI Tool")
        self.root.protocol("WM_DELETE_WINDOW", self.quit)  # Confirm?

        # Frame for the input field and buttons
        self.input_frame = Frame(self.root)
        self.input_frame.pack(side="top")

        self.label = Label(self.input_frame, text="Class:")
        self.label.pack(side="left")
        self.entry_field = Entry(self.input_frame)
        self.entry_field.pack(side="left")

        self.image_label = Label(self.root)
        self.image_label.pack(side="bottom")
        self.image_label.bind("<ButtonPress-1>", self.on_button_press)
        self.image_label.bind("<ButtonRelease-1>", self.on_button_release)

        self.image = None
        self.imagetk = None
        self.draw = None

        self.ref_pts = []
        self.ref_start = None
        self.ref_pts_iter = None
        self.current_ref_pt = None
        self.gt_rows = []

        try:
            self.next_image()
        except StopIteration:
            print("No images were found (extensions %s) "
                  "or all the images found were already parsed, check file "
                  "%s" % (", ".join(self.image_types), self.gt_filename))
            self.quit()
            sys.exit(1)
        self.show_frame()

    def quit(self):
        self.gt_file.close()
        self.root.quit()

    def ask_for_next_category(self):
        """Ask for next category if another ref point exists,
        else move onto next image"""
        try:
            self.current_ref_pt = self.ref_pts_iter.next()
            self.draw.rectangle(self.current_ref_pt, outline="red")
            self.entry_field.select_range(0, "end")
            self.entry_field.focus()
        except StopIteration:
            self.state = "Selecting"
            try:
                self.next_image()
            except StopIteration:
                print(
                    "Done, regions of interest written in %s" %
                    self.gt_filename)
                self.quit()

    def on_kp_enter(self, event):
        if self.state == "Categorizing":
            category = self.entry_field.get()
            image_path = self.current_image_fullpath.split("/")[-1]
            data = ((image_path,) + self.current_ref_pt[0] +
                    self.current_ref_pt[1] + (category,))
            self.gt_rows.append(data)
            self.draw.rectangle(self.current_ref_pt, outline="blue")
            self.ask_for_next_category()
        else:
            self.state = "Categorizing"
            self.ref_pts_iter = iter(self.ref_pts)
            self.ref_pts = []
            self.ask_for_next_category()

    def get_images(self):
        try:
            gt_file = open(self.gt_filename, 'r')
            reader = csv.reader(gt_file, delimiter=";")
            already_parsed = [row[0] for row in reader]
        except IOError:
            already_parsed = []
        return [filename for filename in os.listdir(self.source_dir) if
                (filename.split(".")[-1] in self.image_types and
                 filename not in already_parsed)]

    def next_image(self):
        self.gt_writer.writerows(self.gt_rows)
        self.gt_rows = []
        self.current_image_fullpath = self.image_fullpaths.next()
        self.image = Image.open(self.current_image_fullpath)
        self.draw = ImageDraw.Draw(self.image)

    def show_frame(self):
        self.imagetk = ImageTk.PhotoImage(image=self.image)
        self.image_label.configure(image=self.imagetk)
        self.image_label.after(10, self.show_frame)

    def on_button_press(self, event):
        if self.state == "Selecting":
            self.ref_start = (event.x, event.y)

    def on_button_release(self, event):
        if self.state == "Selecting":
            # Make sure ROI doesn't exceed pixture coordinates and that
            # the corners go from top left to bottom right
            ref_end = (event.x, event.y)
            ref_pt = self.top_left_to_bottom_right(ref_end)
            self.ref_pts.append(ref_pt)

            # Draw rectangle around ROI
            self.draw.rectangle(
                self.ref_pts[-1],
                outline="green")

    def top_left_to_bottom_right(self, ref_end):
        """Returns the tuple:
            (top_left, bottom_right) where top_left and bottom_right
            are coordinate tuples"""
        x1 = max(0, min(self.ref_start[0], ref_end[0]))
        x2 = min(max(self.ref_start[0], ref_end[0]), self.image.size[0])
        y1 = max(0, min(self.ref_start[1], ref_end[1]))
        y2 = min(max(self.ref_start[1], ref_end[1]), self.image.size[1])
        return ((x1, y1), (x2, y2))