def make_env(): env = gym.make("BreakoutDeterministic-v4") env = PreprocessAtari(env) env = FrameBuffer(env, n_frames=4, dim_order='tensorflow') return env
if check_shapes: assert predicted_next_qvalues.data.dim( ) == 2, "make sure you predicted q-values for all actions in next state" assert next_state_values.data.dim( ) == 1, "make sure you computed V(s') as maximum over just the actions axis and not all axes" assert target_qvalues_for_actions.data.dim( ) == 1, "there's something wrong with target q-values, they must be a vector" return loss if __name__ == '__main__': env = gym.make("BreakoutDeterministic-v0") # create raw env env = PreprocessAtari(env) env = FrameBuffer(env, n_frames=4, dim_order='pytorch') observation_shape = env.observation_space.shape n_actions = env.action_space.n state_dim = observation_shape env.reset() obs, _, _, _ = env.step(env.action_space.sample()) agent = DQNAgent(state_dim, n_actions, epsilon=0.5) target_network = DQNAgent(state_dim, n_actions) exp_replay = ReplayBuffer(10) for _ in range(30): exp_replay.add(env.reset(), env.action_space.sample(), 1.0, env.reset(),
def __init__(self, width, height, aa=1): """ :param width and height: size of the window in pixels. :param aa: antialiasing level, a higher value will give better result but also slow down the animation. (aa=2 is recommended) """ pyglet.window.Window.__init__(self, width, height, caption="Wythoff Explorer", resizable=True, visible=False, vsync=False) self._start_time = time.clock() self._frame_count = 0 # count number of frames rendered so far self._speed = 1 # control speed of the animation self.aa = aa # shader A draws the UI self.shaderA = Shader(["./glsl/wythoff.vert"], ["./glsl/common.frag", "./glsl/BufferA.frag"]) # shadwr B draws the polyhedra self.shaderB = Shader(["./glsl/wythoff.vert"], ["./glsl/common.frag", "./glsl/BufferB.frag"]) # shader C puts them together self.shaderC = Shader(["./glsl/wythoff.vert"], ["./glsl/common.frag", "./glsl/main.frag"]) self.font_texture = create_image_texture(FONT_TEXTURE) self.iChannel0 = pyglet.image.Texture.create_for_size( gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB) self.iChannel1 = pyglet.image.Texture.create_for_size( gl.GL_TEXTURE_2D, width, height, gl.GL_RGBA32F_ARB) gl.glActiveTexture(gl.GL_TEXTURE0) gl.glBindTexture(self.iChannel0.target, self.iChannel0.id) gl.glActiveTexture(gl.GL_TEXTURE1) gl.glBindTexture(self.iChannel1.target, self.iChannel1.id) gl.glActiveTexture(gl.GL_TEXTURE2) gl.glBindTexture(gl.GL_TEXTURE_2D, self.font_texture) # frame buffer A renders the UI to texture iChannel0 with FrameBuffer() as self.bufferA: self.bufferA.attach_texture(self.iChannel0) # frame buffer B render the polyhedra to texture iChannel1 with FrameBuffer() as self.bufferB: self.bufferB.attach_texture(self.iChannel1) # initialize the shaders with self.shaderA: self.shaderA.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1]) self.shaderA.uniformf("iResolution", width, height, 0.0) self.shaderA.uniformf("iTime", 0.0) self.shaderA.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0) self.shaderA.uniformi("iChannel0", 0) self.shaderA.uniformi("iFrame", 0) with self.shaderB: self.shaderB.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1]) self.shaderB.uniformf("iResolution", width, height, 0.0) self.shaderB.uniformf("iTime", 0.0) self.shaderB.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0) self.shaderB.uniformi("iChannel0", 0) self.shaderB.uniformi("AA", self.aa) with self.shaderC: self.shaderC.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1]) self.shaderC.uniformf("iResolution", width, height, 0.0) self.shaderC.uniformf("iTime", 0.0) self.shaderC.uniformf("iMouse", 0.0, 0.0, 0.0, 0.0) self.shaderC.uniformi("iChannel0", 0) self.shaderC.uniformi("iChannel1", 1) self.shaderC.uniformi("iTexture", 2)
def __init__(self, width, height, scale=1.5, conf=1, mask=None, flip=False, video=False, sample_rate=None, video_rate=None): """ Parameters ---------- :width & height: size of the window in pixels. :scale: scaling factor of the texture. :conf: line number of the config in the file (`config.txt`). :mask: a user-specified image that is used to control the growth of the pattern. :flip: flip the white/black pixels in the mask image, only meaningful if there is a mask image. :video: whether the video is turned on or off. :sample_rate: sample a frame from the animation every these frames. :video_rate: frames per second of the video. """ pyglet.window.Window.__init__(self, width, height, caption="GrayScott Simulation", resizable=True, visible=False, vsync=False) # use two shaders, one for doing the computations and one for rendering to the screen. self.reaction_shader = Shader(["./glsl/reaction.vert"], ["./glsl/reaction.frag"]) self.render_shader = Shader(["./glsl/render.vert"], ["./glsl/render.frag"]) self.tex_width, self.tex_height = int(width / scale), int(height / scale) try: self.species, self.palette = self.load_config(conf) print("> Current species: " + self.species + "\n") except: conf = "unstable: #00000000 #00FF0033 #FFFF0035 #FF000066 #FFFFFF99" self.species, self.palette = parse(conf) print("> Failed to load the config, using the default one.\n") self.species_list = list(ALL_SPECIES.keys()) # create the uv_texture uv_grid = np.zeros((self.tex_height, self.tex_width, 4), dtype=np.float32) uv_grid[:, :, 0] = 1.0 rand_rows = np.random.choice(range(self.tex_height), 5) rand_cols = np.random.choice(range(self.tex_width), 5) uv_grid[rand_rows, rand_cols, 1] = 1.0 self.uv_texture = create_texture_from_ndarray(uv_grid) # create the mask_texture mask_grid = np.ones_like(uv_grid) if mask is not None: img = Image.open(mask).convert("L").resize( (self.tex_width, self.tex_height)) img = (np.asarray(img) / 255.0).astype(np.float32) if flip: img = 1.0 - img mask_grid[:, :, 0] = img[::-1] self.mask_texture = create_texture_from_ndarray(mask_grid) # bind the two textures gl.glActiveTexture(gl.GL_TEXTURE0) gl.glBindTexture(self.uv_texture.target, self.uv_texture.id) gl.glActiveTexture(gl.GL_TEXTURE1) gl.glBindTexture(self.mask_texture.target, self.mask_texture.id) # use an invisible buffer to do the computations. with FrameBuffer() as self.fbo: self.fbo.attach_texture(self.uv_texture) # we need this because the program samples the position of the mouse in discrete times. self.mouse_down = False # initialize the two shaders with self.reaction_shader: self.reaction_shader.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1]) self.reaction_shader.vertex_attrib("texcoord", [0, 0, 1, 0, 0, 1, 1, 1]) self.reaction_shader.uniformi("uv_texture", 0) self.reaction_shader.uniformi("mask_texture", 1) self.reaction_shader.uniformf("iResolution", self.tex_width, self.tex_height, 0) self.reaction_shader.uniformf("iMouse", -1, -1) self.reaction_shader.uniformf("params", *ALL_SPECIES[self.species]) with self.render_shader: self.render_shader.vertex_attrib("position", [-1, -1, 1, -1, -1, 1, 1, 1]) self.render_shader.vertex_attrib("texcoord", [0, 0, 1, 0, 0, 1, 1, 1]) self.render_shader.uniformi("uv_texture", 0) self.render_shader.uniformfv("palette", 5, self.palette) self.video_on = video self.buffer = pyglet.image.get_buffer_manager().get_color_buffer() self.sample_rate = sample_rate self.video_rate = video_rate self.frame_count = 0 if video: self.ffmpeg_pipe = self.create_new_pipe() self.start_time = time.time()
def __init__(self): super(OpenMVIDE, self).__init__() ############################################################################################################ ## Connector detector # Connector detects camera connect/disconnect self.connector = OpenMVConnector() self.connector.start() # Catch connect / disconnect notifications self.connector.found.connect(self.do_connect) self.connector.not_found.connect(self.do_disconnect) ############################################################################################################ ## Paths # default working directory self.dir = os.path.dirname(os.path.realpath(__file__)) + '/' # default icons dir self.icon_dir = self.dir + 'icons/' # default examples location self.example_dir = self.dir + 'examples/' # default scripts location self.script_dir = self.dir + 'scripts/' # Location for binary firmware self.flash_dir = self.dir + '../bin/' # Location for config file self.config_file = 'openmv.config' # script filename self.filename = '' ############################################################################################################ ## Configuration default = {'board': 'openmv1', 'filename': '', 'recent': '', 'bin': '', 'auto_flash': 'False', 'auto_connect': 'True', 'width': '800', 'height': '600', 'scale': '1', 'serial_port': '/dev/openmvcam'} # load config config = self.load_config(default) ############################################################################################################ ## State variables # Connect status self.connected = False # Script run status self.running = False # Frame buffer self.image = None # Recent scripts self.recent = set() files = config.get('main', 'recent') for f in files.split(','): if f: self.recent.add(f) # Recent binary self.flash_file = config.get('main', 'bin') # Serial port self.serial_port = config.get('main', 'serial_port') # Board version self.board = config.get('main', 'board') # default auto connect behavior self.auto_connect = config.getboolean('main', 'auto_connect') self.connector.set_auto_connect(self.auto_connect) # default auto flash behavior self.auto_flash = config.getboolean('main', 'auto_flash') ############################################################################################################ ## Components # Editor self.editor = PyEditor(self) self.editor.setMinimumWidth(300) self.editor.setMinimumHeight(200) self.editor.document().contentsChanged.connect(self.update_ui) # FrameBuffer self.framebuffer = FrameBuffer() self.framebuffer.set_scale(config.getfloat('main', 'scale')) self.framebuffer.show() self.framebuffer.error.connect(self.do_disconnect) ############################################################################################################ ## Actions self.exit_action = QAction(QIcon(self.icon_dir + 'Exit.png'), 'Exit', self) self.exit_action.setStatusTip('Exit application') self.exit_action.setShortcut('Ctrl+Q') self.exit_action.triggered.connect(self.do_quit) self.connect_action = QAction(QIcon(self.icon_dir + 'Connect.png'), 'Connect', self) self.connect_action.setStatusTip('Connect to camera') self.connect_action.triggered.connect(self.do_connect) self.reset_action = QAction(QIcon(self.icon_dir + 'Eject.png'), 'Reset', self) self.reset_action.setStatusTip('Reset camera and disconnect') self.reset_action.triggered.connect(self.do_disconnect) self.flash_action = QAction(QIcon(self.icon_dir + 'Lightning.png'), 'Flash', self) self.flash_action.setStatusTip('Flash new firmware') self.flash_action.triggered.connect(self.do_flash) self.run_action = QAction(QIcon(self.icon_dir + 'Run.png'), 'Run', self) self.run_action.setStatusTip('Run script') self.run_action.triggered.connect(self.do_run) self.stop_action = QAction(QIcon(self.icon_dir + 'Stop.png'), 'Stop', self) self.stop_action.setStatusTip('Stop script') self.stop_action.triggered.connect(self.do_stop) self.new_action = QAction(QIcon(self.icon_dir + 'NewDocument.png'), 'New', self) self.new_action.setStatusTip('New script') self.new_action.triggered.connect(self.do_new) self.open_action = QAction(QIcon(self.icon_dir + 'Open.png'), 'Open...', self) self.open_action.setStatusTip('Open script') self.open_action.setShortcut('Ctrl+O') self.open_action.triggered.connect(self.do_open) self.save_action = QAction(QIcon(self.icon_dir + 'Save.png'), 'Save', self) self.save_action.setStatusTip('Save script') self.save_action.setShortcut('Ctrl+S') self.save_action.triggered.connect(self.do_save) self.save_as_action = QAction(QIcon(self.icon_dir + 'SaveAs.png'), 'Save As...', self) self.save_as_action.setStatusTip('Save script as new file') self.save_as_action.triggered.connect(self.do_save_as) self.zoom_in_action = QAction(QIcon(self.icon_dir + 'ZoomIn.png'), 'Zoom In', self) self.zoom_in_action.setStatusTip('Make frame buffer preview bigger') self.zoom_in_action.triggered.connect(self.do_zoom_in) self.zoom_out_action = QAction(QIcon(self.icon_dir + 'ZoomOut.png'), 'Zoom Out', self) self.zoom_out_action.setStatusTip('Make frame buffer preview smaller') self.zoom_out_action.triggered.connect(self.do_zoom_out) self.zoom_reset_action = QAction(QIcon(self.icon_dir + 'ZoomReset.png'), 'Zoom Reset', self) self.zoom_reset_action.setStatusTip('Reset frame buffer preview size') self.zoom_reset_action.triggered.connect(self.do_zoom_reset) self.cut_action = QAction(QIcon(self.icon_dir+'Cut.png'), 'Cut', self) self.cut_action.triggered.connect(self.editor.cut) self.cut_action.setShortcut(QKeySequence.Cut) self.paste_action = QAction(QIcon(self.icon_dir+'Paste.png'), 'Paste', self) self.paste_action.triggered.connect(self.editor.paste) self.paste_action.setShortcut(QKeySequence.Paste) self.copy_action = QAction(QIcon(self.icon_dir+'Copy.png'), 'Copy', self) self.copy_action.triggered.connect(self.editor.copy) self.copy_action.setShortcut(QKeySequence.Copy) self.auto_flash_action = QAction('Auto-flash', self) self.auto_flash_action.setStatusTip('Automatically detect DFU mode and flash firmware') self.auto_flash_action.triggered.connect(self.do_auto_flash) self.auto_flash_action.setCheckable(True) self.auto_flash_action.setDisabled(True) self.auto_connect_action = QAction('Auto-connect', self) self.auto_connect_action.setStatusTip('Automatically connect to OpenMV when detected') self.auto_connect_action.triggered.connect(self.do_auto_connect) self.auto_connect_action.setCheckable(True) self.about_action = QAction(QIcon(self.icon_dir+'About.png'), 'About', self) self.about_action.triggered.connect(self.do_about) ############################################################################################################ ## Toolbars self.toolbar1 = self.addToolBar('toolbar1') self.toolbar1.addAction(self.connect_action) self.toolbar1.addAction(self.reset_action) self.toolbar1.addAction(self.flash_action) self.toolbar1.addAction(self.run_action) self.toolbar1.addAction(self.stop_action) self.toolbar2 = self.addToolBar('toolbar2') self.toolbar2.addAction(self.new_action) self.toolbar2.addAction(self.open_action) self.toolbar2.addAction(self.save_action) self.toolbar3 = self.addToolBar('toolbar3') self.toolbar3.addAction(self.zoom_reset_action) self.toolbar3.addAction(self.zoom_out_action) self.toolbar3.addAction(self.zoom_in_action) ############################################################################################################ ## Menus menu_bar = self.menuBar() file_menu = menu_bar.addMenu('&File') file_menu.addAction(self.new_action) file_menu.addAction(self.open_action) file_menu.addAction(self.save_action) file_menu.addAction(self.save_as_action) file_menu.addSeparator() self.example_menu = QMenu('Examples') self.recent_menu = QMenu('Recent') file_menu.addMenu(self.example_menu) file_menu.addMenu(self.recent_menu) file_menu.addSeparator() file_menu.addAction(self.exit_action) edit_menu = menu_bar.addMenu('&Edit') edit_menu.addAction(self.cut_action) edit_menu.addAction(self.copy_action) edit_menu.addAction(self.paste_action) openmv_menu = menu_bar.addMenu('&Tools') openmv_menu.addAction(self.connect_action) openmv_menu.addAction(self.reset_action) openmv_menu.addAction(self.flash_action) openmv_menu.addAction(self.auto_connect_action) openmv_menu.addAction(self.auto_flash_action) view_menu = menu_bar.addMenu('&View') view_menu.addAction(self.zoom_in_action) view_menu.addAction(self.zoom_out_action) view_menu.addAction(self.zoom_reset_action) help_menu = menu_bar.addMenu('&Help') help_menu.addAction(self.about_action) # Dynamically update dyanmic menus file_menu.aboutToShow.connect(self.update_example_menu) file_menu.aboutToShow.connect(self.update_recent_menu) # Connect dynamic menu items with correct handlers self.example_menu.triggered.connect(self.do_open_example) self.recent_menu.triggered.connect(self.do_open_recent) ############################################################################################################ ## Main Window # Status bar self.statusBar() # Geometry self.setGeometry(50, 50, config.getint('main', 'width'), config.getint('main', 'height')) # Vertical box for framebuffer pvbox = QVBoxLayout() pvbox.addWidget(self.framebuffer) pvbox.addStretch(1) # Horizontal box for editor + framebuffer hbox = QHBoxLayout() hbox.addWidget(self.editor) hbox.addLayout(pvbox) self.terminal = SerialTerminal(self) self.terminal.setMinimumHeight(100) self.terminal.setMaximumHeight(200) self.terminal.show() self.serial = Serial() self.terminal.error.connect(self.do_disconnect) # Vertical box for hbox + terminal vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(self.terminal) w = QWidget() w.setLayout(vbox) self.setCentralWidget(w) # UI Statuses self.update_ui() self.show()
class OpenMVIDE(QMainWindow): def __init__(self): super(OpenMVIDE, self).__init__() ############################################################################################################ ## Connector detector # Connector detects camera connect/disconnect self.connector = OpenMVConnector() self.connector.start() # Catch connect / disconnect notifications self.connector.found.connect(self.do_connect) self.connector.not_found.connect(self.do_disconnect) ############################################################################################################ ## Paths # default working directory self.dir = os.path.dirname(os.path.realpath(__file__)) + '/' # default icons dir self.icon_dir = self.dir + 'icons/' # default examples location self.example_dir = self.dir + 'examples/' # default scripts location self.script_dir = self.dir + 'scripts/' # Location for binary firmware self.flash_dir = self.dir + '../bin/' # Location for config file self.config_file = 'openmv.config' # script filename self.filename = '' ############################################################################################################ ## Configuration default = {'board': 'openmv1', 'filename': '', 'recent': '', 'bin': '', 'auto_flash': 'False', 'auto_connect': 'True', 'width': '800', 'height': '600', 'scale': '1', 'serial_port': '/dev/openmvcam'} # load config config = self.load_config(default) ############################################################################################################ ## State variables # Connect status self.connected = False # Script run status self.running = False # Frame buffer self.image = None # Recent scripts self.recent = set() files = config.get('main', 'recent') for f in files.split(','): if f: self.recent.add(f) # Recent binary self.flash_file = config.get('main', 'bin') # Serial port self.serial_port = config.get('main', 'serial_port') # Board version self.board = config.get('main', 'board') # default auto connect behavior self.auto_connect = config.getboolean('main', 'auto_connect') self.connector.set_auto_connect(self.auto_connect) # default auto flash behavior self.auto_flash = config.getboolean('main', 'auto_flash') ############################################################################################################ ## Components # Editor self.editor = PyEditor(self) self.editor.setMinimumWidth(300) self.editor.setMinimumHeight(200) self.editor.document().contentsChanged.connect(self.update_ui) # FrameBuffer self.framebuffer = FrameBuffer() self.framebuffer.set_scale(config.getfloat('main', 'scale')) self.framebuffer.show() self.framebuffer.error.connect(self.do_disconnect) ############################################################################################################ ## Actions self.exit_action = QAction(QIcon(self.icon_dir + 'Exit.png'), 'Exit', self) self.exit_action.setStatusTip('Exit application') self.exit_action.setShortcut('Ctrl+Q') self.exit_action.triggered.connect(self.do_quit) self.connect_action = QAction(QIcon(self.icon_dir + 'Connect.png'), 'Connect', self) self.connect_action.setStatusTip('Connect to camera') self.connect_action.triggered.connect(self.do_connect) self.reset_action = QAction(QIcon(self.icon_dir + 'Eject.png'), 'Reset', self) self.reset_action.setStatusTip('Reset camera and disconnect') self.reset_action.triggered.connect(self.do_disconnect) self.flash_action = QAction(QIcon(self.icon_dir + 'Lightning.png'), 'Flash', self) self.flash_action.setStatusTip('Flash new firmware') self.flash_action.triggered.connect(self.do_flash) self.run_action = QAction(QIcon(self.icon_dir + 'Run.png'), 'Run', self) self.run_action.setStatusTip('Run script') self.run_action.triggered.connect(self.do_run) self.stop_action = QAction(QIcon(self.icon_dir + 'Stop.png'), 'Stop', self) self.stop_action.setStatusTip('Stop script') self.stop_action.triggered.connect(self.do_stop) self.new_action = QAction(QIcon(self.icon_dir + 'NewDocument.png'), 'New', self) self.new_action.setStatusTip('New script') self.new_action.triggered.connect(self.do_new) self.open_action = QAction(QIcon(self.icon_dir + 'Open.png'), 'Open...', self) self.open_action.setStatusTip('Open script') self.open_action.setShortcut('Ctrl+O') self.open_action.triggered.connect(self.do_open) self.save_action = QAction(QIcon(self.icon_dir + 'Save.png'), 'Save', self) self.save_action.setStatusTip('Save script') self.save_action.setShortcut('Ctrl+S') self.save_action.triggered.connect(self.do_save) self.save_as_action = QAction(QIcon(self.icon_dir + 'SaveAs.png'), 'Save As...', self) self.save_as_action.setStatusTip('Save script as new file') self.save_as_action.triggered.connect(self.do_save_as) self.zoom_in_action = QAction(QIcon(self.icon_dir + 'ZoomIn.png'), 'Zoom In', self) self.zoom_in_action.setStatusTip('Make frame buffer preview bigger') self.zoom_in_action.triggered.connect(self.do_zoom_in) self.zoom_out_action = QAction(QIcon(self.icon_dir + 'ZoomOut.png'), 'Zoom Out', self) self.zoom_out_action.setStatusTip('Make frame buffer preview smaller') self.zoom_out_action.triggered.connect(self.do_zoom_out) self.zoom_reset_action = QAction(QIcon(self.icon_dir + 'ZoomReset.png'), 'Zoom Reset', self) self.zoom_reset_action.setStatusTip('Reset frame buffer preview size') self.zoom_reset_action.triggered.connect(self.do_zoom_reset) self.cut_action = QAction(QIcon(self.icon_dir+'Cut.png'), 'Cut', self) self.cut_action.triggered.connect(self.editor.cut) self.cut_action.setShortcut(QKeySequence.Cut) self.paste_action = QAction(QIcon(self.icon_dir+'Paste.png'), 'Paste', self) self.paste_action.triggered.connect(self.editor.paste) self.paste_action.setShortcut(QKeySequence.Paste) self.copy_action = QAction(QIcon(self.icon_dir+'Copy.png'), 'Copy', self) self.copy_action.triggered.connect(self.editor.copy) self.copy_action.setShortcut(QKeySequence.Copy) self.auto_flash_action = QAction('Auto-flash', self) self.auto_flash_action.setStatusTip('Automatically detect DFU mode and flash firmware') self.auto_flash_action.triggered.connect(self.do_auto_flash) self.auto_flash_action.setCheckable(True) self.auto_flash_action.setDisabled(True) self.auto_connect_action = QAction('Auto-connect', self) self.auto_connect_action.setStatusTip('Automatically connect to OpenMV when detected') self.auto_connect_action.triggered.connect(self.do_auto_connect) self.auto_connect_action.setCheckable(True) self.about_action = QAction(QIcon(self.icon_dir+'About.png'), 'About', self) self.about_action.triggered.connect(self.do_about) ############################################################################################################ ## Toolbars self.toolbar1 = self.addToolBar('toolbar1') self.toolbar1.addAction(self.connect_action) self.toolbar1.addAction(self.reset_action) self.toolbar1.addAction(self.flash_action) self.toolbar1.addAction(self.run_action) self.toolbar1.addAction(self.stop_action) self.toolbar2 = self.addToolBar('toolbar2') self.toolbar2.addAction(self.new_action) self.toolbar2.addAction(self.open_action) self.toolbar2.addAction(self.save_action) self.toolbar3 = self.addToolBar('toolbar3') self.toolbar3.addAction(self.zoom_reset_action) self.toolbar3.addAction(self.zoom_out_action) self.toolbar3.addAction(self.zoom_in_action) ############################################################################################################ ## Menus menu_bar = self.menuBar() file_menu = menu_bar.addMenu('&File') file_menu.addAction(self.new_action) file_menu.addAction(self.open_action) file_menu.addAction(self.save_action) file_menu.addAction(self.save_as_action) file_menu.addSeparator() self.example_menu = QMenu('Examples') self.recent_menu = QMenu('Recent') file_menu.addMenu(self.example_menu) file_menu.addMenu(self.recent_menu) file_menu.addSeparator() file_menu.addAction(self.exit_action) edit_menu = menu_bar.addMenu('&Edit') edit_menu.addAction(self.cut_action) edit_menu.addAction(self.copy_action) edit_menu.addAction(self.paste_action) openmv_menu = menu_bar.addMenu('&Tools') openmv_menu.addAction(self.connect_action) openmv_menu.addAction(self.reset_action) openmv_menu.addAction(self.flash_action) openmv_menu.addAction(self.auto_connect_action) openmv_menu.addAction(self.auto_flash_action) view_menu = menu_bar.addMenu('&View') view_menu.addAction(self.zoom_in_action) view_menu.addAction(self.zoom_out_action) view_menu.addAction(self.zoom_reset_action) help_menu = menu_bar.addMenu('&Help') help_menu.addAction(self.about_action) # Dynamically update dyanmic menus file_menu.aboutToShow.connect(self.update_example_menu) file_menu.aboutToShow.connect(self.update_recent_menu) # Connect dynamic menu items with correct handlers self.example_menu.triggered.connect(self.do_open_example) self.recent_menu.triggered.connect(self.do_open_recent) ############################################################################################################ ## Main Window # Status bar self.statusBar() # Geometry self.setGeometry(50, 50, config.getint('main', 'width'), config.getint('main', 'height')) # Vertical box for framebuffer pvbox = QVBoxLayout() pvbox.addWidget(self.framebuffer) pvbox.addStretch(1) # Horizontal box for editor + framebuffer hbox = QHBoxLayout() hbox.addWidget(self.editor) hbox.addLayout(pvbox) self.terminal = SerialTerminal(self) self.terminal.setMinimumHeight(100) self.terminal.setMaximumHeight(200) self.terminal.show() self.serial = Serial() self.terminal.error.connect(self.do_disconnect) # Vertical box for hbox + terminal vbox = QVBoxLayout() vbox.addLayout(hbox) vbox.addWidget(self.terminal) w = QWidget() w.setLayout(vbox) self.setCentralWidget(w) # UI Statuses self.update_ui() self.show() def load_config(self, default): config = ConfigParser(default) config.add_section('main') try: config.read(self.config_file) except (IOError, OSError, ConfigParser.Error) as e: pass print("Failed to open config file: %s" % e) finally: return config def save_config(self): config = ConfigParser() config.add_section('main') config.set('main', 'serial_port', self.serial_port) config.set('main', 'auto_connect', self.auto_connect) config.set('main', 'auto_flash', self.auto_flash) config.set('main', 'height', self.height()) config.set('main', 'width', self.width()) config.set('main', 'scale', self.framebuffer.scale) config.set('main', 'recent', ','.join(self.recent)) config.set('main', 'bin', self.flash_file) try: with open(self.config_file, 'w') as f: config.write(f) except (IOError, OSError) as e: print('Failed to save config file %s' % e) def update_ui(self): self.run_action.setEnabled(self.connected) self.stop_action.setEnabled(self.connected and self.running) self.connect_action.setEnabled(not self.connected) self.reset_action.setEnabled(self.connected) self.flash_action.setEnabled(self.connected) self.save_action.setEnabled(self.editor.document().isModified()) self.zoom_in_action.setEnabled(self.connected) self.zoom_out_action.setEnabled(self.connected) self.zoom_reset_action.setEnabled(self.connected) self.auto_connect_action.setChecked(self.auto_connect) self.auto_flash_action.setChecked(self.auto_flash) if self.connected: con = '[connected]' else: con = '[disconnected]' if self.filename: fn = os.path.basename(self.filename) else: fn = 'untitled.py' self.setWindowTitle('OpenMV IDE (' + fn + ') - ' + con) def update_example_menu(self): if os.path.isdir(self.example_dir): self.example_menu.clear() files = sorted(os.listdir(self.example_dir)) self.example_menu.setEnabled(len(files) > 0) for f in files: if f.endswith(".py"): action = QAction(f, self) self.example_menu.addAction(action) def update_recent_menu(self): self.recent_menu.clear() self.recent_menu.setEnabled(len(self.recent) > 0) for f in self.recent: self.recent_menu.addAction(QAction(f, self)) def do_auto_connect(self): self.auto_connect = not self.auto_connect self.connector.set_auto_connect(self.auto_connect) self.update_ui() def do_connect(self): if not self.connected: self.connected = True try: # init OpenMV openmv.init() sleep(0.2) # interrupt any running code openmv.stop_script() sleep(0.2) # first, check to see if self.serial_port is in the list of enumerated ports # then try to open it. If that fails, or if the port isn't in the enumerated # list, then prompt the user for a port ports = [] for p in list_ports.comports(): name = p[0] try: ser = Serial(name, 115200, timeout=1) ser.close() ports.append(p) except (IOError, OSError): pass print(ports) self.serial = Serial(self.serial_port, 115200, timeout=1) self.terminal.start(self.serial) except IOError as e: print('error connecting OpenMV Cam: %s' % e) self.connected = False else: self.update_ui() self.statusBar().showMessage('OpenMV Cam connected.') self.framebuffer.start_updater() def do_disconnect(self): if self.connected: self.connected = False self.update_ui() self.framebuffer.stop_updater() openmv.stop_script() sleep(0.2) # release OpenMV openmv.release() sleep(0.2) openmv.reset() sleep(0.2) self.connector.start() self.statusBar().showMessage('Camera disconnected.') try: if self.serial and self.serial.isOpen(): print('Disconnecting terminal') self.serial.close() self.terminal.reset() except IOError as e: print('error disconnecting OpenMV Serial: %s' % e) def do_auto_flash(self): self.auto_flash = not self.auto_flash self.update_ui() def do_flash(self): self.update_ui() if self.connected: dialog = QDialog(self) filename = QLineEdit() filename = QLineEdit() chooser = QFileDialog() filename.setText(self.flash_file) chooser.setDirectory(self.flash_dir) browse = QPushButton('&...') browse.pressed.connect(chooser.exec_) chooser.fileSelected.connect(filename.setText) hlayout1 = QHBoxLayout() hlayout1.addWidget(filename, stretch=1) hlayout1.addWidget(browse) ok_button = QPushButton('&Ok') cancel_button = QPushButton('&Cancel') hlayout2 = QHBoxLayout() hlayout2.addWidget(ok_button) hlayout2.addWidget(cancel_button) vlayout = QVBoxLayout() vlayout.addLayout(hlayout1) vlayout.addLayout(hlayout2) dialog.setLayout(vlayout) ok_button.pressed.connect(dialog.accept) cancel_button.pressed.connect(dialog.reject) dialog.exec_() dialog.hide() if dialog.result() == QDialog.Accepted: print('Accepted') file = filename.text() try: with open(file, 'r') as f: buf = f.read() except (IOError, OSError) as e: QErrorMessage(self).showMessage('Error opening binary file:\n%s' % e) print('Error opening binary file: %s' % e) else: self.flash_file = file self.flash_update(buf) else: print('Rejected') def flash_update(self, buf): flash_offsets = [0x08000000, 0x08004000, 0x08008000, 0x0800C000, 0x08010000, 0x08020000, 0x08040000, 0x08060000, 0x08080000, 0x080A0000, 0x080C0000, 0x080E0000] # Erasing total = len(flash_offsets) progress = QProgressDialog(self) progress.setRange(0, total) progress.setValue(0) progress.setModal(True) progress.show() progress.setAutoReset(False) progress.setLabelText('Initializing') # call dfu-util openmv.enter_dfu() sleep(1.0) # Initialize pydfu.init() progress.setLabelText('Erasing') progress.setValue(0) pg = 0 for offset in flash_offsets: progress.setValue(pg) pydfu.page_erase(flash_offsets[pg]) pg += 1 offset = 0 size = len(buf) progress.setRange(0, size) progress.setLabelText('Downloading') while offset < size: progress.setValue(offset) pg_size = min(64, size - offset) page = buf[offset:offset + pg_size] pydfu.write_page(page, offset) offset += pg_size progress.hide() pydfu.exit_dfu() def do_run(self): buf = str(self.editor.toPlainText()) # interrupt any running code openmv.stop_script() sleep(0.1) # exec script openmv.exec_script(buf) self.running = True self.update_ui() def do_stop(self): openmv.stop_script() self.running = False self.update_ui() def check_modified(self): result = True if self.editor.document().isModified(): msg = QMessageBox(self) msg.setText('The document has been modified.') msg.setIcon(QMessageBox.Warning) msg.setInformativeText('Do you want to save your changes?') msg.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msg.setDefaultButton(QMessageBox.Save) msg.exec_() ret = msg.result() if ret == QMessageBox.Save: self.do_save() result = True elif ret == QMessageBox.Discard: result = True elif ret == QMessageBox.Cancel: result = False else: print('%s' % ret) return result def do_new(self): if self.check_modified(): self.editor.setPlainText('') self.filename = '' self.update_ui() def do_open(self): if self.check_modified(): if os.path.exists(self.script_dir): my_dir = self.script_dir else: my_dir = self.example_dir filename = QFileDialog.getOpenFileName(parent=self, caption=self.tr('Open Micro Python Script'), directory=my_dir, filter=self.tr("Python scripts (*.py)")) self.open_file(filename) def open_file(self, filename): if filename: try: infile = open(filename, 'r') except (IOError, OSError) as e: QErrorMessage(self).showMessage('Error opening file:\n%s' % e) else: self.editor.setPlainText(infile.read()) # store new filename self.filename = str(filename) self.update_ui() self.recent.add(self.filename) def do_save_as(self): self.do_save(True) def do_save(self, save_as=False): if save_as: filename = '' else: filename = self.filename ## TODO: Address file-exists-replace? scenario # filename will be empty if we haven't saved the document yet if not filename: filename = QFileDialog.getSaveFileName(parent=self, caption=self.tr('Save Micro Python Script'), directory=self.script_dir, filter=self.tr("Python scripts (*.py)")) if filename: try: outfile = open(filename, 'w') outfile.write(self.editor.toPlainText()) # store new filename self.filename = str(filename) self.editor.document().setModified(False) self.update_ui() except (IOError, OSError) as e: QErrorMessage(self).showMessage('Error saving file:\n%s' % e) def do_open_example(self, action): assert isinstance(action, QAction) if self.check_modified(): self.open_file(self.example_dir + action.text()) def do_open_recent(self, action): assert isinstance(action, QAction) if self.check_modified(): self.open_file(action.text()) def do_quit(self): if self.check_modified(): if self.connected: self.do_disconnect() self.save_config() self.framebuffer.quit() QApplication.quit() def do_zoom_in(self): self.framebuffer.increase_scale(0.5) def do_zoom_out(self): self.framebuffer.decrease_scale(0.5) def do_zoom_reset(self): self.framebuffer.reset_scale() def interrupt_handler(self, signum, frame): print('CTRL-C caught') def do_about(self): msg = QMessageBox(self) msg.setText('OpenMV IDE (PyQt)') msg.setIcon(QMessageBox.Question) msg.setInformativeText('Michael Shimniok') msg.setStandardButtons(QMessageBox.Ok) msg.setDefaultButton(QMessageBox.Ok) msg.exec_() def closeEvent(self, event): result = QMessageBox.question(self, "Confirm Exit...", "Are you sure you want to exit ?", QMessageBox.Yes, QMessageBox.No) event.ignore() if result == QMessageBox.Yes: self.do_quit()