def device_discovery(self, devs): group = QActionGroup(self._menu_devices, exclusive=True) for d in devs: node = QAction(d["name"], self._menu_devices, checkable=True) node.toggled.connect(self._inputdevice_selected) group.addAction(node) self._menu_devices.addAction(node) if (d["name"] == Config().get("input_device")): self._current_input_device = d["name"] if (len(self._current_input_device) == 0): self._current_input_device = self._menu_devices.actions()[0].text() device_config_mapping = Config().get("device_config_mapping") if (device_config_mapping): if (self._current_input_device in device_config_mapping.keys()): self._current_input_config = device_config_mapping[ str(self._current_input_device)] else: self._current_input_config = self._menu_mappings.actions()[0].text() else: self._current_input_config = self._menu_mappings.actions()[0].text() # Now we know what device to use and what mapping, trigger the events to # change the menus and start the input for c in self._menu_mappings.actions(): c.setEnabled(True) if (c.text() == self._current_input_config): c.setChecked(True) for c in self._menu_devices.actions(): if (c.text() == self._current_input_device): c.setChecked(True)
def device_discovery(self, devs): group = QActionGroup(self._menu_devices, exclusive=False) for d in devs: node = QAction(d.name, self._menu_devices, checkable=True) node.toggled.connect(self._inputdevice_selected) group.addAction(node) self._menu_devices.addAction(node) if d.name == Config().get("input_device"): self._active_device = d.name if len(self._active_device) == 0: self._active_device = str(self._menu_devices.actions()[0].text()) device_config_mapping = Config().get("device_config_mapping") if device_config_mapping: if self._active_device in device_config_mapping.keys(): self._current_input_config = device_config_mapping[ self._active_device] else: self._current_input_config = self._menu_mappings.actions()[0]\ .text() else: self._current_input_config = self._menu_mappings.actions()[0].text() # Now we know what device to use and what mapping, trigger the events # to change the menus and start the input for c in self._menu_devices.actions(): if c.text() == self._active_device: c.setChecked(True) for c in self._menu_mappings.actions(): c.setEnabled(True) if c.text() == self._current_input_config: c.setChecked(True)
def _get_saved_device_mapping(self, device_name): """Return the saved mapping for a given device""" config = None device_config_mapping = Config().get("device_config_mapping") if device_name in device_config_mapping.keys(): config = device_config_mapping[device_name] logging.debug("For [{}] we recommend [{}]".format(device_name, config)) return config
def _inputdevice_selected(self, checked): if not checked: return self.joystickReader.stopInput() sender = self.sender() self._active_device = sender.text() device_config_mapping = Config().get("device_config_mapping") if self._active_device in device_config_mapping.keys(): self._current_input_config = device_config_mapping[str(self._active_device)] else: self._current_input_config = self._menu_mappings.actions()[0].text() Config().set("input_device", str(self._active_device)) for c in self._menu_mappings.actions(): if c.text() == self._current_input_config: c.setChecked(True) self.joystickReader.startInput(str(sender.text()), self._current_input_config) self._statusbar_label.setText("Using [%s] with config [%s]" % (self._active_device, self._current_input_config))
def set(self, key, value): """ Set the value of a config parameter """ strval = value if (isinstance(value, QString)): strval = str(value) Config.set(self, key, strval)
def device_discovery(self, devs): """Called when new devices have been added""" for menu in self._all_role_menus: role_menu = menu["rolemenu"] mux_menu = menu["muxmenu"] dev_group = QActionGroup(role_menu) dev_group.setExclusive(True) for d in devs: dev_node = QAction(d.name, role_menu, checkable=True, enabled=True) role_menu.addAction(dev_node) dev_group.addAction(dev_node) dev_node.toggled.connect(self._inputdevice_selected) map_node = None if d.supports_mapping: map_node = QMenu(" Input map", role_menu, enabled=False) map_group = QActionGroup(role_menu) map_group.setExclusive(True) # Connect device node to map node for easy # enabling/disabling when selection changes and device # to easily enable it dev_node.setData((map_node, d)) for c in ConfigManager().get_list_of_configs(): node = QAction(c, map_node, checkable=True, enabled=True) node.toggled.connect(self._inputconfig_selected) map_node.addAction(node) # Connect all the map nodes back to the device # action node where we can access the raw device node.setData(dev_node) map_group.addAction(node) # If this device hasn't been found before, then # select the default mapping for it. if d not in self._available_devices: last_map = Config().get("device_config_mapping") if d.name in last_map and last_map[d.name] == c: node.setChecked(True) role_menu.addMenu(map_node) dev_node.setData((map_node, d, mux_menu)) # Update the list of what devices we found # to avoid selecting default mapping for all devices when # a new one is inserted self._available_devices = () for d in devs: self._available_devices += (d, ) # Only enable MUX nodes if we have enough devies to cover # the roles for mux_node in self._all_mux_nodes: (mux, sub_nodes) = mux_node.data() if len(mux.supported_roles()) <= len(self._available_devices): mux_node.setEnabled(True) # TODO: Currently only supports selecting default mux if self._all_mux_nodes[0].isEnabled(): self._all_mux_nodes[0].setChecked(True) # If the previous length of the available devies was 0, then select # the default on. If that's not available then select the first # on in the list. # TODO: This will only work for the "Normal" mux so this will be # selected by default if Config().get("input_device") in [d.name for d in devs]: for dev_menu in self._all_role_menus[0]["rolemenu"].actions(): if dev_menu.text() == Config().get("input_device"): dev_menu.setChecked(True) else: # Select the first device in the first mux (will always be "Normal" # mux) self._all_role_menus[0]["rolemenu"].actions()[0].setChecked(True) logger.info("Select first device") self._update_input_device_footer()
def closeEvent(self, event): self.hide() self.cf.close_link() Config().save_file()
def __init__(self, *args): super(MainUI, self).__init__(*args) self.setupUi(self) # Restore window size if present in the config file try: size = Config().get("window_size") self.resize(size[0], size[1]) except KeyError: pass ###################################################### # By lxrocks # 'Skinny Progress Bar' tweak for Yosemite # Tweak progress bar - artistic I am not - so pick your own colors !!! # Only apply to Yosemite ###################################################### import platform if platform.system() == 'Darwin': (Version, junk, machine) = platform.mac_ver() logger.info("This is a MAC - checking if we can apply Progress " "Bar Stylesheet for Yosemite Skinny Bars ") yosemite = (10, 10, 0) tVersion = tuple(map(int, (Version.split(".")))) if tVersion >= yosemite: logger.info("Found Yosemite - applying stylesheet") tcss = """ QProgressBar { border: 1px solid grey; border-radius: 5px; text-align: center; } QProgressBar::chunk { background-color: """ + COLOR_BLUE + """; } """ self.setStyleSheet(tcss) else: logger.info("Pre-Yosemite - skinny bar stylesheet not applied") ###################################################### self.cf = Crazyflie(ro_cache=None, rw_cache=cfclient.config_path + "/cache") cflib.crtp.init_drivers( enable_debug_driver=Config().get("enable_debug_driver")) zmq_params = ZMQParamAccess(self.cf) zmq_params.start() zmq_leds = ZMQLEDDriver(self.cf) zmq_leds.start() self.scanner = ScannerThread() self.scanner.interfaceFoundSignal.connect(self.foundInterfaces) self.scanner.start() # Create and start the Input Reader self._statusbar_label = QLabel("No input-device found, insert one to" " fly.") self.statusBar().addWidget(self._statusbar_label) self.joystickReader = JoystickReader() self._active_device = "" # self.configGroup = QActionGroup(self._menu_mappings, exclusive=True) self._mux_group = QActionGroup(self._menu_inputdevice) self._mux_group.setExclusive(True) # TODO: Need to reload configs # ConfigManager().conf_needs_reload.add_callback(self._reload_configs) self.connect_input = QShortcut("Ctrl+I", self.connectButton, self._connect) self.cf.connection_failed.add_callback( self.connectionFailedSignal.emit) self.connectionFailedSignal.connect(self._connection_failed) self._input_device_error_signal.connect( self._display_input_device_error) self.joystickReader.device_error.add_callback( self._input_device_error_signal.emit) self._input_discovery_signal.connect(self.device_discovery) self.joystickReader.device_discovery.add_callback( self._input_discovery_signal.emit) # Hide the 'File' menu on OS X, since its only item, 'Exit', gets # merged into the application menu. if sys.platform == 'darwin': self.menuFile.menuAction().setVisible(False) # Connect UI signals self.logConfigAction.triggered.connect(self._show_connect_dialog) self.interfaceCombo.currentIndexChanged['QString'].connect( self.interfaceChanged) self.connectButton.clicked.connect(self._connect) self.scanButton.clicked.connect(self._scan) self.menuItemConnect.triggered.connect(self._connect) self.menuItemConfInputDevice.triggered.connect( self._show_input_device_config_dialog) self.menuItemExit.triggered.connect(self.closeAppRequest) self.batteryUpdatedSignal.connect(self._update_battery) self._menuitem_rescandevices.triggered.connect(self._rescan_devices) self._menuItem_openconfigfolder.triggered.connect( self._open_config_folder) self.address.setValue(0xE7E7E7E7E7) self._auto_reconnect_enabled = Config().get("auto_reconnect") self.autoReconnectCheckBox.toggled.connect( self._auto_reconnect_changed) self.autoReconnectCheckBox.setChecked(Config().get("auto_reconnect")) self._disable_input = False self.joystickReader.input_updated.add_callback( lambda *args: self._disable_input or self.cf.commander. send_setpoint(*args)) self.joystickReader.assisted_input_updated.add_callback( lambda *args: self._disable_input or self.cf.commander. send_velocity_world_setpoint(*args)) self.joystickReader.heighthold_input_updated.add_callback( lambda *args: self._disable_input or self.cf.commander. send_zdistance_setpoint(*args)) self.joystickReader.hover_input_updated.add_callback( self.cf.commander.send_hover_setpoint) # Connection callbacks and signal wrappers for UI protection self.cf.connected.add_callback(self.connectionDoneSignal.emit) self.connectionDoneSignal.connect(self._connected) self.cf.disconnected.add_callback(self.disconnectedSignal.emit) self.disconnectedSignal.connect(self._disconnected) self.cf.connection_lost.add_callback(self.connectionLostSignal.emit) self.connectionLostSignal.connect(self._connection_lost) self.cf.connection_requested.add_callback( self.connectionInitiatedSignal.emit) self.connectionInitiatedSignal.connect(self._connection_initiated) self._log_error_signal.connect(self._logging_error) self.batteryBar.setTextVisible(False) self.batteryBar.setStyleSheet(progressbar_stylesheet(COLOR_BLUE)) self.linkQualityBar.setTextVisible(False) self.linkQualityBar.setStyleSheet(progressbar_stylesheet(COLOR_BLUE)) # Connect link quality feedback self.cf.link_quality_updated.add_callback(self.linkQualitySignal.emit) self.linkQualitySignal.connect( lambda percentage: self.linkQualityBar.setValue(percentage)) self._selected_interface = None self._initial_scan = True self._scan() # Parse the log configuration files self.logConfigReader = LogConfigReader(self.cf) self._current_input_config = None self._active_config = None self._active_config = None self.inputConfig = None # Add things to helper so tabs can access it cfclient.ui.pluginhelper.cf = self.cf cfclient.ui.pluginhelper.inputDeviceReader = self.joystickReader cfclient.ui.pluginhelper.logConfigReader = self.logConfigReader cfclient.ui.pluginhelper.mainUI = self self.logConfigDialogue = LogConfigDialogue(cfclient.ui.pluginhelper) self._bootloader_dialog = BootloaderDialog(cfclient.ui.pluginhelper) self._cf2config_dialog = Cf2ConfigDialog(cfclient.ui.pluginhelper) self._cf1config_dialog = Cf1ConfigDialog(cfclient.ui.pluginhelper) self.menuItemBootloader.triggered.connect(self._bootloader_dialog.show) self._about_dialog = AboutDialog(cfclient.ui.pluginhelper) self.menuItemAbout.triggered.connect(self._about_dialog.show) self._menu_cf2_config.triggered.connect(self._cf2config_dialog.show) self._menu_cf1_config.triggered.connect(self._cf1config_dialog.show) # Load and connect tabs self.tabsMenuItem = QMenu("Tabs", self.menuView, enabled=True) self.menuView.addMenu(self.tabsMenuItem) # self.tabsMenuItem.setMenu(QtWidgets.QMenu()) tabItems = {} self.loadedTabs = [] for tabClass in cfclient.ui.tabs.available: tab = tabClass(self.tabs, cfclient.ui.pluginhelper) item = QtWidgets.QAction(tab.getMenuName(), self, checkable=True) item.toggled.connect(tab.toggleVisibility) self.tabsMenuItem.addAction(item) tabItems[tab.getTabName()] = item self.loadedTabs.append(tab) if not tab.enabled: item.setEnabled(False) # First instantiate all tabs and then open them in the correct order try: for tName in Config().get("open_tabs").split(","): t = tabItems[tName] if (t is not None and t.isEnabled()): # Toggle though menu so it's also marked as open there t.toggle() except Exception as e: logger.warning("Exception while opening tabs [{}]".format(e)) # Loading toolboxes (A bit of magic for a lot of automatic) self.toolboxesMenuItem = QMenu("Toolboxes", self.menuView, enabled=True) self.menuView.addMenu(self.toolboxesMenuItem) self.toolboxes = [] for t_class in cfclient.ui.toolboxes.toolboxes: toolbox = t_class(cfclient.ui.pluginhelper) dockToolbox = MyDockWidget(toolbox.getName()) dockToolbox.setWidget(toolbox) self.toolboxes += [ dockToolbox, ] # Add menu item for the toolbox item = QtWidgets.QAction(toolbox.getName(), self) item.setCheckable(True) item.triggered.connect(self.toggleToolbox) self.toolboxesMenuItem.addAction(item) dockToolbox.closed.connect(lambda: self.toggleToolbox(False)) # Setup some introspection item.dockToolbox = dockToolbox item.menuItem = item dockToolbox.dockToolbox = dockToolbox dockToolbox.menuItem = item # References to all the device sub-menus in the "Input device" menu self._all_role_menus = () # Used to filter what new devices to add default mapping to self._available_devices = () # Keep track of mux nodes so we can enable according to how many # devices we have self._all_mux_nodes = () # Check which Input muxes are available self._mux_group = QActionGroup(self._menu_inputdevice) self._mux_group.setExclusive(True) for m in self.joystickReader.available_mux(): node = QAction(m.name, self._menu_inputdevice, checkable=True, enabled=False) node.toggled.connect(self._mux_selected) self._mux_group.addAction(node) self._menu_inputdevice.addAction(node) self._all_mux_nodes += (node, ) mux_subnodes = () for name in m.supported_roles(): sub_node = QMenu(" {}".format(name), self._menu_inputdevice, enabled=False) self._menu_inputdevice.addMenu(sub_node) mux_subnodes += (sub_node, ) self._all_role_menus += ({ "muxmenu": node, "rolemenu": sub_node }, ) node.setData((m, mux_subnodes)) self._mapping_support = True
def flightmodeChange(self, item): Config().set("flightmode", str(self.flightModeCombo.itemText(item))) logger.debug("Changed flightmode to %s", self.flightModeCombo.itemText(item)) self.isInCrazyFlightmode = False if (item == 0): # Normal self.maxAngle.setValue(Config().get("normal_max_rp")) self.maxThrust.setValue(Config().get("normal_max_thrust")) self.minThrust.setValue(Config().get("normal_min_thrust")) self.slewEnableLimit.setValue(Config().get("normal_slew_limit")) self.thrustLoweringSlewRateLimit.setValue( Config().get("normal_slew_rate")) self.maxYawRate.setValue(Config().get("normal_max_yaw")) if (item == 1): # Advanced self.maxAngle.setValue(Config().get("max_rp")) self.maxThrust.setValue(Config().get("max_thrust")) self.minThrust.setValue(Config().get("min_thrust")) self.slewEnableLimit.setValue(Config().get("slew_limit")) self.thrustLoweringSlewRateLimit.setValue( Config().get("slew_rate")) self.maxYawRate.setValue(Config().get("max_yaw")) self.isInCrazyFlightmode = True if (item == 0): newState = False else: newState = True self.maxThrust.setEnabled(newState) self.maxAngle.setEnabled(newState) self.minThrust.setEnabled(newState) self.thrustLoweringSlewRateLimit.setEnabled(newState) self.slewEnableLimit.setEnabled(newState) self.maxYawRate.setEnabled(newState)
def _trim_pitch_changed(self, value): logger.debug("Pitch trim updated to [%f]" % value) self.helper.inputDeviceReader.trim_pitch = value Config().set("trim_pitch", value)
def maxYawRateChanged(self): logger.debug("MaxYawrate changed to %d", self.maxYawRate.value()) self.helper.inputDeviceReader.max_yaw_rate = self.maxYawRate.value() if (self.isInCrazyFlightmode is True): Config().set("max_yaw", self.maxYawRate.value())
def __init__(self, tabWidget, helper, *args): super(FlightTab, self).__init__(*args) self.setupUi(self) self.tabName = "Flight Control" self.menuName = "Flight Control" self.tabWidget = tabWidget self.helper = helper self.disconnectedSignal.connect(self.disconnected) self.connectionFinishedSignal.connect(self.connected) # Incomming signals self.helper.cf.connected.add_callback( self.connectionFinishedSignal.emit) self.helper.cf.disconnected.add_callback(self.disconnectedSignal.emit) self._input_updated_signal.connect(self.updateInputControl) self.helper.inputDeviceReader.input_updated.add_callback( self._input_updated_signal.emit) self._rp_trim_updated_signal.connect(self.calUpdateFromInput) self.helper.inputDeviceReader.rp_trim_updated.add_callback( self._rp_trim_updated_signal.emit) self._emergency_stop_updated_signal.connect(self.updateEmergencyStop) self.helper.inputDeviceReader.emergency_stop_updated.add_callback( self._emergency_stop_updated_signal.emit) self.helper.inputDeviceReader.heighthold_input_updated.add_callback( self._heighthold_input_updated_signal.emit) self._heighthold_input_updated_signal.connect( self._heighthold_input_updated) self.helper.inputDeviceReader.hover_input_updated.add_callback( self._hover_input_updated_signal.emit) self._hover_input_updated_signal.connect(self._hover_input_updated) self.helper.inputDeviceReader.assisted_control_updated.add_callback( self._assisted_control_updated_signal.emit) self._assisted_control_updated_signal.connect( self._assisted_control_updated) self._imu_data_signal.connect(self._imu_data_received) self._baro_data_signal.connect(self._baro_data_received) self._motor_data_signal.connect(self._motor_data_received) self._log_error_signal.connect(self._logging_error) # Connect UI signals that are in this tab self.flightModeCombo.currentIndexChanged.connect(self.flightmodeChange) self.minThrust.valueChanged.connect(self.minMaxThrustChanged) self.maxThrust.valueChanged.connect(self.minMaxThrustChanged) self.thrustLoweringSlewRateLimit.valueChanged.connect( self.thrustLoweringSlewRateLimitChanged) self.slewEnableLimit.valueChanged.connect( self.thrustLoweringSlewRateLimitChanged) self.targetCalRoll.valueChanged.connect(self._trim_roll_changed) self.targetCalPitch.valueChanged.connect(self._trim_pitch_changed) self.maxAngle.valueChanged.connect(self.maxAngleChanged) self.maxYawRate.valueChanged.connect(self.maxYawRateChanged) self.uiSetupReadySignal.connect(self.uiSetupReady) self.isInCrazyFlightmode = False self.uiSetupReady() self.ratePidRadioButton.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightmode.ratepid", str(enabled))) self.angularPidRadioButton.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightmode.ratepid", str(not enabled))) self._led_ring_headlight.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "ring.headlightEnable", str(enabled))) self.helper.cf.param.add_update_callback( group="flightmode", name="ratepid", cb=(lambda name, checked: self.ratePidRadioButton.setChecked( eval(checked)))) self.helper.cf.param.add_update_callback( group="ring", name="headlightEnable", cb=(lambda name, checked: self._led_ring_headlight.setChecked( eval(checked)))) self._ledring_nbr_effects = 0 self.helper.cf.param.add_update_callback(group="ring", name="effect", cb=self._ring_effect_updated) self.helper.cf.param.add_update_callback( group="imu_sensors", cb=self._set_available_sensors) self.helper.cf.param.all_updated.add_callback(self._all_params_updated) self.logBaro = None self.logAltHold = None self.ai = AttitudeIndicator() self.verticalLayout_4.addWidget(self.ai) self.splitter.setSizes([1000, 1]) self.targetCalPitch.setValue(Config().get("trim_pitch")) self.targetCalRoll.setValue(Config().get("trim_roll")) self.helper.inputDeviceReader.alt1_updated.add_callback( self.alt1_updated) self.helper.inputDeviceReader.alt2_updated.add_callback( self.alt2_updated) self._tf_state = 0 self._ring_effect = 0 # Connect callbacks for input device limiting of rpöö/pitch/yaw/thust self.helper.inputDeviceReader.limiting_updated.add_callback( self._limiting_updated.emit) self._limiting_updated.connect(self._set_limiting_enabled)
def __init__(self, tabWidget, helper, *args): super(AutoFlightTab, self).__init__(*args) self.setupUi(self) global TheTab, natnet, copter TheTab = self self.tabName = "Auto Flight Control" self.menuName = "Auto Flight Control" self.tabWidget = tabWidget self.helper = helper self.disconnectedSignal.connect(self.disconnected) self.connectionFinishedSignal.connect(self.connected) # Incomming signals self.helper.cf.connectSetupFinished.add_callback( self.connectionFinishedSignal.emit) self.helper.cf.disconnected.add_callback(self.disconnectedSignal.emit) self.helper.inputDeviceReader.inputUpdateSignal.connect( self.updateInputControl) self.helper.inputDeviceReader.calUpdateSignal.connect( self.calUpdateFromInput) self.helper.inputDeviceReader.emergencyStopSignal.connect( self.updateEmergencyStop) self._imu_data_signal.connect(self._imu_data_received) self._motor_data_signal.connect(self._motor_data_received) # Connect UI signals that are in this tab self.flightModeCombo.currentIndexChanged.connect(self.flightmodeChange) self.minThrust.valueChanged.connect(self.minMaxThrustChanged) self.maxThrust.valueChanged.connect(self.minMaxThrustChanged) self.thrustLoweringSlewRateLimit.valueChanged.connect( self.thrustLoweringSlewRateLimitChanged) self.slewEnableLimit.valueChanged.connect( self.thrustLoweringSlewRateLimitChanged) self.targetCalRoll.valueChanged.connect(self._trim_roll_changed) self.targetCalPitch.valueChanged.connect(self._trim_pitch_changed) self.maxAngle.valueChanged.connect(self.maxAngleChanged) self.maxYawRate.valueChanged.connect(self.maxYawRateChanged) self.uiSetupReadySignal.connect(self.uiSetupReady) self.clientXModeCheckbox.toggled.connect(self.changeXmode) self.isInCrazyFlightmode = False self.uiSetupReady() self.clientXModeCheckbox.setChecked(Config().get("client_side_xmode")) self.crazyflieXModeCheckbox.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightctrl.xmode", str(enabled))) self.helper.cf.param.add_update_callback( "flightctrl.xmode", lambda name, checked: self.crazyflieXModeCheckbox.setChecked( eval(checked))) self.ratePidRadioButton.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightctrl.ratepid", str(enabled))) self.angularPidRadioButton.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightctrl.ratepid", str(not enabled))) self.helper.cf.param.add_update_callback( "flightctrl.ratepid", lambda name, checked: self.ratePidRadioButton.setChecked( eval(checked))) self.ai = AttitudeIndicator() self.gridLayout.addWidget(self.ai, 0, 1) self.targetCalPitch.setValue(Config().get("trim_pitch")) self.targetCalRoll.setValue(Config().get("trim_roll")) """ ADDITION: automode ui """ self.automodeCheckBox.toggled.connect(self.changeAutoMode) self.loopmodeCheckBox.toggled.connect(self.changeLoopMode) self.followmodeCheckBox.toggled.connect(self.changeFollowMode) self.launchButton.clicked.connect(self.launchButtonClicked) self.upButton.clicked.connect(self.upButtonClicked) self.downButton.clicked.connect(self.downButtonClicked) self.frontButton.clicked.connect(self.frontButtonClicked) self.backButton.clicked.connect(self.backButtonClicked) self.rightButton.clicked.connect(self.rightButtonClicked) self.leftButton.clicked.connect(self.leftButtonClicked) self.setAButton.clicked.connect(self.setAButtonClicked) self.setBButton.clicked.connect(self.setBButtonClicked) self.goAButton.clicked.connect(self.goAButtonClicked) self.goBButton.clicked.connect(self.goBButtonClicked) self.neutralThrustBox.valueChanged.connect(self.neutralThrustChanged) self.thrustScaleBox.valueChanged.connect(self.thrustScaleChanged) self.horzScaleBox.valueChanged.connect(self.horzScaleChanged) self.velocityScaleBox.valueChanged.connect(self.velocityScaleChanged) self.velocitySmoothBox.valueChanged.connect(self.velocitySmoothChanged) self.lastUIUpdate = time() """ ADDITION: replace joy stick object's input device with our wrapper class """ print "AutoFlightTab wrapping device" d = self.helper.inputDeviceReader.inputdevice w = DeviceWrapper(d) w.automode = False self.helper.inputDeviceReader.inputdevice = w """ ADDITION: initialize tracker fields of interface """ self.position.setText("received tracker position") self.orientation.setText("received tracker orientation") """ ADDITION: create thread to run command socket """ cmdthread = threading.Thread(target=natnet.manage_cmd_socket, args=[copter]) # cmdthread = threading.Thread(None, manage_cmd_socket, None) cmdthread.setDaemon(True) cmdthread.start()
def __init__(self, tabWidget, helper, *args): super(ExampleTab, self).__init__(*args) self.setupUi(self) self.tabName = "SUTD AFC3D" self.menuName = "SUTD AFC3D" self.tabWidget = tabWidget self.helper = helper self.disconnectedSignal.connect(self.disconnected) self.connectionFinishedSignal.connect(self.connected) # Incoming signals self.helper.cf.connected.add_callback( self.connectionFinishedSignal.emit) self.helper.cf.disconnected.add_callback(self.disconnectedSignal.emit) self._input_updated_signal.connect(self.updateInputControl) self.helper.inputDeviceReader.input_updated.add_callback( self._input_updated_signal.emit) self._rp_trim_updated_signal.connect(self.calUpdateFromInput) self.helper.inputDeviceReader.rp_trim_updated.add_callback( self._rp_trim_updated_signal.emit) self._emergency_stop_updated_signal.connect(self.updateEmergencyStop) self.helper.inputDeviceReader.emergency_stop_updated.add_callback( self._emergency_stop_updated_signal.emit) self.helper.inputDeviceReader.heighthold_input_updated.add_callback( self._heighthold_input_updated_signal.emit) self._heighthold_input_updated_signal.connect( self._heighthold_input_updated) self.helper.inputDeviceReader.hover_input_updated.add_callback( self._hover_input_updated_signal.emit) self._hover_input_updated_signal.connect(self._hover_input_updated) self.helper.inputDeviceReader.assisted_control_updated.add_callback( self._assisted_control_updated_signal.emit) self._assisted_control_updated_signal.connect( self._assisted_control_updated) self._imu_data_signal.connect(self._imu_data_received) self._baro_data_signal.connect(self._baro_data_received) self._motor_data_signal.connect(self._motor_data_received) self._log_error_signal.connect(self._logging_error) # PlotWidget Stuff self._plot = PlotWidget(fps=30) # Check if we could find the PyQtImport. If not, then # set this tab as disabled self.enabled = self._plot.can_enable self._model = LogConfigModel() self.dataSelector.setModel(self._model) self.plotLayout.addWidget(self._plot) self._log_data_signal.connect(self._log_data_received) self._plotter_log_error_signal.connect(self._plotter_logging_error) if self.enabled: self._disconnected_signal.connect(self._disconnected) self.helper.cf.disconnected.add_callback( self._disconnected_signal.emit) self._connected_signal.connect(self._connected) self.helper.cf.connected.add_callback(self._connected_signal.emit) self.helper.cf.log.block_added_cb.add_callback(self._config_added) self.dataSelector.currentIndexChanged.connect( self._selection_changed) self._previous_config = None self._started_previous = False # Connect UI signals that are in this tab #self.flightModeCombo.currentIndexChanged.connect(self.flightmodeChange) # self.minThrust.valueChanged.connect(self.minMaxThrustChanged) # self.maxThrust.valueChanged.connect(self.minMaxThrustChanged) # self.thrustLoweringSlewRateLimit.valueChanged.connect( # self.thrustLoweringSlewRateLimitChanged) # self.slewEnableLimit.valueChanged.connect( # self.thrustLoweringSlewRateLimitChanged) self.targetCalRoll.valueChanged.connect(self._trim_roll_changed) self.inputTypeComboBox.currentIndexChanged.connect( self.inputtypeChange) self.stepHeightCombo.valueChanged.connect(self._step_height_changed) self.frequencyCombo.valueChanged.connect(self._sine_frequency_changed) self.referenceHeightCheckbox.toggled.connect( lambda: self._use_ref_input(self.referenceHeightCheckbox.isChecked( ))) self.targetCalPitch.valueChanged.connect(self._trim_pitch_changed) self.updateGainsBtn.clicked.connect(self._controller_gain_changed) self.k1Combo.valueChanged.connect(self._k123_gain_changed) self.k2Combo.valueChanged.connect(self._k123_gain_changed) self.k3Combo.valueChanged.connect(self._k123_gain_changed) # self.maxAngle.valueChanged.connect(self.maxAngleChanged) # self.maxYawRate.valueChanged.connect(self.maxYawRateChanged) #self.uiSetupReadySignal.connect(self.uiSetupReady) self.clientXModeCheckbox.toggled.connect(self.changeXmode) self.isInCrazyFlightmode = False self.uiSetupReady() # self.clientXModeCheckbox.setChecked(Config().get("client_side_xmode")) # # self.crazyflieXModeCheckbox.clicked.connect( # lambda enabled: # self.helper.cf.param.set_value("flightmode.x", # str(enabled))) # self.helper.cf.param.add_update_callback( # group="flightmode", name="xmode", # cb=(lambda name, checked: # self.crazyflieXModeCheckbox.setChecked(eval(checked)))) # # self.ratePidRadioButton.clicked.connect( # lambda enabled: # self.helper.cf.param.set_value("flightmode.ratepid", # str(enabled))) # # self.angularPidRadioButton.clicked.connect( # lambda enabled: # self.helper.cf.param.set_value("flightmode.ratepid", # str(not enabled))) # # self._led_ring_headlight.clicked.connect( # lambda enabled: # self.helper.cf.param.set_value("ring.headlightEnable", # str(enabled))) # self.helper.cf.param.add_update_callback( # group="flightmode", name="ratepid", # cb=(lambda name, checked: # self.ratePidRadioButton.setChecked(eval(checked)))) # self.helper.cf.param.add_update_callback( # group="cpu", name="flash", # cb=self._set_enable_client_xmode) # self.helper.cf.param.add_update_callback( # group="ring", name="headlightEnable", # cb=(lambda name, checked: # self._led_ring_headlight.setChecked(eval(checked)))) self._ledring_nbr_effects = 0 # self.helper.cf.param.add_update_callback( # group="ring", # name="effect", # cb=self._ring_effect_updated) self.helper.cf.param.add_update_callback( group="imu_sensors", cb=self._set_available_sensors) # self.helper.cf.param.all_updated.add_callback( # self._ring_populate_dropdown) self.logBaro = None self.logAltHold = None self.ai = AttitudeIndicator() self.verticalLayout_2.addWidget(self.ai) # self.logo = QLabel(self) # pixmap = QPixmap('C:\dev\crazyflie-clients-python\src\cfclient/SUTDLogo.png') # self.logo.setPixmap(pixmap.scaled(150, 150, Qt.KeepAspectRatio)) # self.verticalLayout.addWidget(self.logo) self.splitter.setSizes([1000, 1]) self.targetCalPitch.setValue(Config().get("trim_pitch")) self.targetCalRoll.setValue(Config().get("trim_roll")) self.helper.inputDeviceReader.alt1_updated.add_callback( self.alt1_updated) self.helper.inputDeviceReader.alt2_updated.add_callback( self.alt2_updated) self._tf_state = 0 self._ring_effect = 0
def connected(self, linkURI): # IMU & THRUST lg = LogConfig("Stabilizer", 10) #Config().get("ui_update_period")) # lg = LogConfig("Stabilizer", 10) lg.add_variable("stabilizer.roll", "float") lg.add_variable("stabilizer.pitch", "float") lg.add_variable("stabilizer.yaw", "float") lg.add_variable("stabilizer.thrust", "uint16_t") lg.add_variable("oa.front", "uint16_t") lg.add_variable("oa.back", "uint16_t") lg.add_variable("oa.right", "uint16_t") lg.add_variable("oa.left", "uint16_t") # lg.add_variable("stateEstimate.vx", "float") # lg.add_variable("stateEstimate.vy", "float") try: self.helper.cf.log.add_config(lg) lg.data_received_cb.add_callback(self._imu_data_signal.emit) lg.error_cb.add_callback(self._log_error_signal.emit) lg.start() except KeyError as e: logger.warning(str(e)) except AttributeError as e: logger.warning(str(e)) # MOTOR lg = LogConfig("Motors", Config().get("ui_update_period")) lg.add_variable("motor.m1") lg.add_variable("motor.m2") lg.add_variable("motor.m3") lg.add_variable("motor.m4") try: self.helper.cf.log.add_config(lg) lg.data_received_cb.add_callback(self._motor_data_signal.emit) lg.error_cb.add_callback(self._log_error_signal.emit) lg.start() except KeyError as e: logger.warning(str(e)) except AttributeError as e: logger.warning(str(e)) # OA # lg = LogConfig("Oa", Config().get("ui_update_period")) # lg.add_variable("oa.front", "uint16_t") # lg.add_variable("oa.back", "uint16_t") # lg.add_variable("oa.right", "uint16_t") # lg.add_variable("oa.left", "uint16_t") # # try: # self.helper.cf.log.add_config(lg) # lg.data_received_cb.add_callback(self._imu_data_signal.emit) # lg.error_cb.add_callback(self._log_error_signal.emit) # lg.start() # except KeyError as e: # logger.warning(str(e)) # except AttributeError as e: # logger.warning(str(e)) self._populate_assisted_mode_dropdown() # rospy.init_node('ranges', anonymous=False, disable_signals=False) self.pub = rospy.Publisher('ranges', oa, queue_size=10)
def __init__(self, *args): super(MainUI, self).__init__(*args) self.setupUi(self) self.cfg = Config() self.cf = Crazyflie( ro_cache=roslib.packages.get_pkg_dir('crazyflie_ros') + "/lib/cflib/cache", rw_cache=roslib.packages.get_pkg_dir('crazyflie_ros') + "/lib/cache") cflib.crtp.init_drivers() # Create the connection dialogue self.connectDialogue = ConnectDialogue() # Create and start the Input Reader self._statusbar_label = QLabel("Loading device and config") self.statusBar().addWidget(self._statusbar_label) self.joystickReader = JoystickReader() self._active_device = "" self.configGroup = QActionGroup(self._menu_mappings, exclusive=True) self._load_input_data() self._update_input ConfigManager().conf_needs_reload.add_callback(self._reload_configs) # Connections for the Connect Dialogue self.connectDialogue.requestConnectionSignal.connect(self.cf.open_link) self.connectionDoneSignal.connect(self.connectionDone) self.cf.connectionFailed.add_callback(self.connectionFailedSignal.emit) self.connectionFailedSignal.connect(self.connectionFailed) self.joystickReader.inputDeviceErrorSignal.connect( self.inputDeviceError) self.joystickReader.discovery_signal.connect(self.device_discovery) # Connect UI signals self.menuItemConnect.triggered.connect(self.connectButtonClicked) self.logConfigAction.triggered.connect(self.doLogConfigDialogue) self.connectButton.clicked.connect(self.connectButtonClicked) self.quickConnectButton.clicked.connect(self.quickConnect) self.menuItemQuickConnect.triggered.connect(self.quickConnect) self.menuItemConfInputDevice.triggered.connect(self.configInputDevice) self.menuItemExit.triggered.connect(self.closeAppRequest) self.batteryUpdatedSignal.connect(self.updateBatteryVoltage) self._menuitem_rescandevices.triggered.connect(self._rescan_devices) # Do not queue data from the controller output to the Crazyflie wrapper to avoid latency self.joystickReader.sendControlSetpointSignal.connect( self.cf.commander.send_setpoint, Qt.DirectConnection) # Connection callbacks and signal wrappers for UI protection self.cf.connectSetupFinished.add_callback( self.connectionDoneSignal.emit) self.connectionDoneSignal.connect(self.connectionDone) self.cf.disconnected.add_callback(self.disconnectedSignal.emit) self.disconnectedSignal.connect( lambda linkURI: self.setUIState(UIState.DISCONNECTED, linkURI)) self.cf.connectionLost.add_callback(self.connectionLostSignal.emit) self.connectionLostSignal.connect(self.connectionLost) self.cf.connectionInitiated.add_callback( self.connectionInitiatedSignal.emit) self.connectionInitiatedSignal.connect( lambda linkURI: self.setUIState(UIState.CONNECTING, linkURI)) # Connect link quality feedback self.cf.linkQuality.add_callback(self.linkQualitySignal.emit) self.linkQualitySignal.connect( lambda percentage: self.linkQualityBar.setValue(percentage)) # Set UI state in disconnected buy default self.setUIState(UIState.DISCONNECTED) # Parse the log configuration files self.logConfigReader = LogConfigReader() self.logConfigReader.readConfigFiles() # Add things to helper so tabs can access it cfclient.ui.pluginhelper.cf = self.cf cfclient.ui.pluginhelper.inputDeviceReader = self.joystickReader cfclient.ui.pluginhelper.logConfigReader = self.logConfigReader self.logConfigDialogue = LogConfigDialogue(cfclient.ui.pluginhelper) self._bootloader_dialog = BootloaderDialog(cfclient.ui.pluginhelper) self.menuItemBootloader.triggered.connect(self._bootloader_dialog.show) self._about_dialog = AboutDialog(cfclient.ui.pluginhelper) self.menuItemAbout.triggered.connect(self._about_dialog.show) #Loading toolboxes (A bit of magic for a lot of automatic) self.toolboxes = [] self.toolboxesMenuItem.setMenu(QtGui.QMenu()) for t_class in cfclient.ui.toolboxes.toolboxes: toolbox = t_class(cfclient.ui.pluginhelper) dockToolbox = MyDockWidget(toolbox.getName()) dockToolbox.setWidget(toolbox) self.toolboxes += [ dockToolbox, ] #Add menu item for the toolbox item = QtGui.QAction(toolbox.getName(), self) item.setCheckable(True) item.triggered.connect(self.toggleToolbox) self.toolboxesMenuItem.menu().addAction(item) dockToolbox.closed.connect(lambda: self.toggleToolbox(False)) #Setup some introspection item.dockToolbox = dockToolbox item.menuItem = item dockToolbox.dockToolbox = dockToolbox dockToolbox.menuItem = item # Load and connect tabs self.tabsMenuItem.setMenu(QtGui.QMenu()) tabItems = {} self.loadedTabs = [] for tabClass in cfclient.ui.tabs.available: tab = tabClass(self.tabs, cfclient.ui.pluginhelper) item = QtGui.QAction(tab.getMenuName(), self) item.setCheckable(True) item.toggled.connect(tab.toggleVisibility) self.tabsMenuItem.menu().addAction(item) tabItems[tab.getTabName()] = item self.loadedTabs.append(tab) # First instantiate all the tabs and then open them in the correct order try: for tName in Config().get("open_tabs").split(","): t = tabItems[tName] if (t != None): t.toggle( ) # Toggle though menu so it's also marked as open there except Exception as e: logger.warning("Exception while opening tabs [%s]", e)
def device_discovery(self, devs): """Called when new devices have been added""" for menu in self._all_role_menus: role_menu = menu["rolemenu"] mux_menu = menu["muxmenu"] dev_group = QActionGroup(role_menu, exclusive=True) for d in devs: dev_node = QAction(d.name, role_menu, checkable=True, enabled=True) role_menu.addAction(dev_node) dev_group.addAction(dev_node) dev_node.toggled.connect(self._inputdevice_selected) map_node = None if d.supports_mapping: map_node = QMenu(" Input map", role_menu, enabled=False) map_group = QActionGroup(role_menu, exclusive=True) # Connect device node to map node for easy # enabling/disabling when selection changes and device # to easily enable it dev_node.setData((map_node, d)) for c in ConfigManager().get_list_of_configs(): node = QAction(c, map_node, checkable=True, enabled=True) node.toggled.connect(self._inputconfig_selected) map_node.addAction(node) # Connect all the map nodes back to the device # action node where we can access the raw device node.setData(dev_node) map_group.addAction(node) # If this device hasn't been found before, then # select the default mapping for it. if d not in self._available_devices: last_map = Config().get("device_config_mapping") if last_map.has_key(d.name) and last_map[d.name] == c: node.setChecked(True) role_menu.addMenu(map_node) dev_node.setData((map_node, d, mux_menu)) # Update the list of what devices we found # to avoid selecting default mapping for all devices when # a new one is inserted self._available_devices = () for d in devs: self._available_devices += (d, ) # Only enable MUX nodes if we have enough devies to cover # the roles for mux_node in self._all_mux_nodes: (mux, sub_nodes) = mux_node.data().toPyObject() if len(mux.supported_roles()) <= len(self._available_devices): mux_node.setEnabled(True) # TODO: Currently only supports selecting default mux if self._all_mux_nodes[0].isEnabled(): self._all_mux_nodes[0].setChecked(True) # If the previous length of the available devies was 0, then select # the default on. If that's not available then select the first # on in the list. # TODO: This will only work for the "Normal" mux so this will be # selected by default if Config().get("input_device") in [d.name for d in devs]: for dev_menu in self._all_role_menus[0]["rolemenu"].actions(): if dev_menu.text() == Config().get("input_device"): dev_menu.setChecked(True) else: # Select the first device in the first mux (will always be "Normal" # mux) self._all_role_menus[0]["rolemenu"].actions()[0].setChecked(True) logger.info("Select first device") self._update_input_device_footer()
def changeXmode(self, checked): self.helper.cf.commander.set_client_xmode(checked) Config().set("client_side_xmode", checked) logger.info("Clientside X-mode enabled: %s", checked)
def _quick_connect(self): try: self.cf.open_link(Config().get("link_uri")) except KeyError: self.cf.open_link("")
def minMaxThrustChanged(self): self.helper.inputDeviceReader.min_thrust = self.minThrust.value() self.helper.inputDeviceReader.max_thrust = self.maxThrust.value() if (self.isInCrazyFlightmode is True): Config().set("min_thrust", self.minThrust.value()) Config().set("max_thrust", self.maxThrust.value())
def maxAngleChanged(self): logger.debug("MaxAngle changed to %d", self.maxAngle.value()) self.helper.inputDeviceReader.updateMaxRPAngleSignal.emit( self.maxAngle.value()) if (self.isInCrazyFlightmode == True): Config().set("max_rp", self.maxAngle.value())
def maxAngleChanged(self): logger.debug("MaxAngle changed to %d", self.maxAngle.value()) self.helper.inputDeviceReader.max_rp_angle = self.maxAngle.value() if (self.isInCrazyFlightmode is True): Config().set("max_rp", self.maxAngle.value())
def __init__(self, tabWidget, helper, *args): super(FlightTab, self).__init__(*args) self.setupUi(self) # self.pub_imu = rospy.Publisher('/cf/imu', imu_msg) # self.pub_imu_target = rospy.Publisher('/cf/imu_target', imu_target_msg) # self.pub_motor = rospy.Publisher('/cf/motor', motor_msg) rospy.init_node('crazy_flie') self.tabName = "Flight Control" self.menuName = "Flight Control" self.tabWidget = tabWidget self.helper = helper self.disconnectedSignal.connect(self.disconnected) self.connectionFinishedSignal.connect(self.connected) # Incomming signals self.helper.cf.connectSetupFinished.add_callback( self.connectionFinishedSignal.emit) self.helper.cf.disconnected.add_callback(self.disconnectedSignal.emit) self.helper.inputDeviceReader.inputUpdateSignal.connect( self.updateInputControl) self.helper.inputDeviceReader.calUpdateSignal.connect( self.calUpdateFromInput) self.helper.inputDeviceReader.emergencyStopSignal.connect( self.updateEmergencyStop) self._imu_data_signal.connect(self._imu_data_received) self._motor_data_signal.connect(self._motor_data_received) # Connect UI signals that are in this tab self.flightModeCombo.currentIndexChanged.connect(self.flightmodeChange) self.minThrust.valueChanged.connect(self.minMaxThrustChanged) self.maxThrust.valueChanged.connect(self.minMaxThrustChanged) self.thrustLoweringSlewRateLimit.valueChanged.connect( self.thrustLoweringSlewRateLimitChanged) self.slewEnableLimit.valueChanged.connect( self.thrustLoweringSlewRateLimitChanged) self.targetCalRoll.valueChanged.connect(self._trim_roll_changed) self.targetCalPitch.valueChanged.connect(self._trim_pitch_changed) self.maxAngle.valueChanged.connect(self.maxAngleChanged) self.maxYawRate.valueChanged.connect(self.maxYawRateChanged) self.uiSetupReadySignal.connect(self.uiSetupReady) self.clientXModeCheckbox.toggled.connect(self.changeXmode) self.isInCrazyFlightmode = False self.uiSetupReady() self.clientXModeCheckbox.setChecked(Config().get("client_side_xmode")) self.crazyflieXModeCheckbox.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightctrl.xmode", str(enabled))) self.helper.cf.param.add_update_callback( "flightctrl.xmode", lambda name, checked: self.crazyflieXModeCheckbox.setChecked( eval(checked))) self.ratePidRadioButton.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightctrl.ratepid", str(enabled))) self.angularPidRadioButton.clicked.connect( lambda enabled: self.helper.cf.param.set_value( "flightctrl.ratepid", str(not enabled))) self.helper.cf.param.add_update_callback( "flightctrl.ratepid", lambda name, checked: self.ratePidRadioButton.setChecked( eval(checked))) self.ai = AttitudeIndicator() self.gridLayout.addWidget(self.ai, 0, 1) self.targetCalPitch.setValue(Config().get("trim_pitch")) self.targetCalRoll.setValue(Config().get("trim_roll"))
def _trim_roll_changed(self, value): logger.debug("Roll trim updated to [%f]" % value) self.helper.inputDeviceReader.trim_roll = value Config().set("trim_roll", value)
from cfclient.utils.config import Config ZMQ_PULL_PORT = 1024 + 189 logger = logging.getLogger(__name__) enabled = False try: import zmq enabled = True except Exception as e: logger.warning( "Not enabling ZMQ param access, import failed ({})".format(e)) if not Config().get("enable_zmq_param"): enabled = False logger.info("ZMQ param disabled in config file") class _PullReader(Thread): def __init__(self, receiver, callback, *args): super(_PullReader, self).__init__(*args) self._receiver = receiver self._cb = callback self.daemon = True self.lock = Lock() def run(self): while True: self.lock.acquire()
def _populate_assisted_mode_dropdown(self): self._assist_mode_combo.addItem("Altitude hold", 0) self._assist_mode_combo.addItem("Position hold", 1) self._assist_mode_combo.addItem("Height hold", 2) self._assist_mode_combo.addItem("Hover", 3) # Add the tooltips to the assist-mode items. self._assist_mode_combo.setItemData(0, TOOLTIP_ALTITUDE_HOLD, Qt.ToolTipRole) self._assist_mode_combo.setItemData(1, TOOLTIP_POSITION_HOLD, Qt.ToolTipRole) self._assist_mode_combo.setItemData(2, TOOLTIP_HEIGHT_HOLD, Qt.ToolTipRole) self._assist_mode_combo.setItemData(3, TOOLTIP_HOVER, Qt.ToolTipRole) heightHoldPossible = False hoverPossible = False if int(self.helper.cf.param.values["deck"]["bcZRanger"]) == 1: heightHoldPossible = True self.helper.inputDeviceReader.set_hover_max_height(1.0) if int(self.helper.cf.param.values["deck"]["bcZRanger2"]) == 1: heightHoldPossible = True self.helper.inputDeviceReader.set_hover_max_height(2.0) if int(self.helper.cf.param.values["deck"]["bcFlow"]) == 1: heightHoldPossible = True hoverPossible = True self.helper.inputDeviceReader.set_hover_max_height(1.0) if int(self.helper.cf.param.values["deck"]["bcFlow2"]) == 1: heightHoldPossible = True hoverPossible = True self.helper.inputDeviceReader.set_hover_max_height(2.0) if not heightHoldPossible: self._assist_mode_combo.model().item(2).setEnabled(False) else: self._assist_mode_combo.model().item(0).setEnabled(False) if not hoverPossible: self._assist_mode_combo.model().item(3).setEnabled(False) else: self._assist_mode_combo.model().item(0).setEnabled(False) self._assist_mode_combo.currentIndexChanged.connect( self._assist_mode_changed) self._assist_mode_combo.setEnabled(True) try: assistmodeComboIndex = Config().get("assistedControl") if assistmodeComboIndex == 3 and not hoverPossible: self._assist_mode_combo.setCurrentIndex(0) self._assist_mode_combo.currentIndexChanged.emit(0) elif assistmodeComboIndex == 0 and hoverPossible: self._assist_mode_combo.setCurrentIndex(3) self._assist_mode_combo.currentIndexChanged.emit(3) elif assistmodeComboIndex == 2 and not heightHoldPossible: self._assist_mode_combo.setCurrentIndex(0) self._assist_mode_combo.currentIndexChanged.emit(0) elif assistmodeComboIndex == 0 and heightHoldPossible: self._assist_mode_combo.setCurrentIndex(2) self._assist_mode_combo.currentIndexChanged.emit(2) else: self._assist_mode_combo.setCurrentIndex(assistmodeComboIndex) self._assist_mode_combo.currentIndexChanged.emit( assistmodeComboIndex) except KeyError: defaultOption = 0 if hoverPossible: defaultOption = 3 elif heightHoldPossible: defaultOption = 2 self._assist_mode_combo.setCurrentIndex(defaultOption) self._assist_mode_combo.currentIndexChanged.emit(defaultOption)
Input interface that supports receiving commands via ZMQ. """ import logging import time import pprint from threading import Thread from cfclient.utils.config import Config try: import zmq except Exception as e: raise Exception("ZMQ library probably not installed ({})".format(e)) if not Config().get("enable_zmq_input"): raise Exception("ZMQ input disabled in config file") __author__ = 'Bitcraze AB' __all__ = ['ZMQReader'] ZMQ_PULL_PORT = 1024 + 188 logger = logging.getLogger(__name__) MODULE_MAIN = "ZMQReader" MODULE_NAME = "ZMQ" class _PullReader(Thread): def __init__(self, receiver, callback, *args):
def _auto_reconnect_changed(self, checked): self._auto_reconnect_enabled = checked Config().set("auto_reconnect", checked) logger.info("Auto reconnect enabled: {}".format(checked))
def set_default_theme(self): try: theme = Config().get('theme') except KeyError: theme = 'Default' self._check_theme(theme)
def resizeEvent(self, event): Config().set( "window_size", [event.size().width(), event.size().height()])
def __init__(self, do_device_discovery=True, cf=None): # TODO: Should be OS dependant self.inputdevice = AiController(cf) self._min_thrust = 0 self._max_thrust = 0 self._thrust_slew_rate = 0 self._thrust_slew_enabled = False self._thrust_slew_limit = 0 self._emergency_stop = False self._has_pressure_sensor = False self._old_thrust = 0 self._old_alt_hold = False self._trim_roll = Config().get("trim_roll") self._trim_pitch = Config().get("trim_pitch") if (Config().get("flightmode") is "Normal"): self._max_yaw_rate = Config().get("normal_max_yaw") self._max_rp_angle = Config().get("normal_max_rp") # Values are stored at %, so use the functions to set the values self.set_thrust_limits(Config().get("normal_min_thrust"), Config().get("normal_max_thrust")) self.set_thrust_slew_limiting(Config().get("normal_slew_rate"), Config().get("normal_slew_limit")) else: self._max_yaw_rate = Config().get("max_yaw") self._max_rp_angle = Config().get("max_rp") # Values are stored at %, so use the functions to set the values self.set_thrust_limits(Config().get("min_thrust"), Config().get("max_thrust")) self.set_thrust_slew_limiting(Config().get("slew_rate"), Config().get("slew_limit")) self._dev_blacklist = None if (len(Config().get("input_device_blacklist")) > 0): self._dev_blacklist = re.compile( Config().get("input_device_blacklist")) logger.info("Using device blacklist [{}]".format( Config().get("input_device_blacklist"))) self._available_devices = {} # TODO: The polling interval should be set from config file self._read_timer = PeriodicTimer(0.01, self.read_input) if do_device_discovery: self._discovery_timer = PeriodicTimer(1.0, self._do_device_discovery) self._discovery_timer.start() # Check if user config exists, otherwise copy files if not os.path.exists(ConfigManager().configs_dir): logger.info("No user config found, copying dist files") os.makedirs(ConfigManager().configs_dir) for f in glob.glob(sys.path[0] + "/cfclient/configs/input/[A-Za-z]*.json"): dest = os.path.join(ConfigManager().configs_dir, os.path.basename(f)) if not os.path.isfile(dest): logger.debug("Copying %s", f) shutil.copy2(f, ConfigManager().configs_dir) ConfigManager().get_list_of_configs() self.input_updated = Caller() self.rp_trim_updated = Caller() self.emergency_stop_updated = Caller() self.device_discovery = Caller() self.device_error = Caller() self.althold_updated = Caller()
def __init__(self, *args): super(MainUI, self).__init__(*args) self.setupUi(self) # Restore window size if present in the config file try: size = Config().get("window_size") self.resize(size[0], size[1]) except KeyError: pass self.cf = Crazyflie(ro_cache=None, rw_cache=cfclient.config_path + "/cache") cflib.crtp.init_drivers( enable_debug_driver=Config().get("enable_debug_driver")) zmq_params = ZMQParamAccess(self.cf) zmq_params.start() zmq_leds = ZMQLEDDriver(self.cf) zmq_leds.start() self.scanner = ScannerThread() self.scanner.interfaceFoundSignal.connect(self.foundInterfaces) self.scanner.start() # Create and start the Input Reader self._statusbar_label = QLabel("No input-device found, insert one to" " fly.") self.statusBar().addWidget(self._statusbar_label) self.joystickReader = JoystickReader() self._active_device = "" # self.configGroup = QActionGroup(self._menu_mappings, exclusive=True) self._mux_group = QActionGroup(self._menu_inputdevice) self._mux_group.setExclusive(True) # TODO: Need to reload configs # ConfigManager().conf_needs_reload.add_callback(self._reload_configs) self.connect_input = QShortcut("Ctrl+I", self.connectButton, self._connect) self.cf.connection_failed.add_callback( self.connectionFailedSignal.emit) self.connectionFailedSignal.connect(self._connection_failed) self._input_device_error_signal.connect( self._display_input_device_error) self.joystickReader.device_error.add_callback( self._input_device_error_signal.emit) self._input_discovery_signal.connect(self.device_discovery) self.joystickReader.device_discovery.add_callback( self._input_discovery_signal.emit) # Connect UI signals self.logConfigAction.triggered.connect(self._show_connect_dialog) self.interfaceCombo.currentIndexChanged['QString'].connect( self.interfaceChanged) self.connectButton.clicked.connect(self._connect) self.scanButton.clicked.connect(self._scan) self.menuItemConnect.triggered.connect(self._connect) self.menuItemConfInputDevice.triggered.connect( self._show_input_device_config_dialog) self.menuItemExit.triggered.connect(self.closeAppRequest) self.batteryUpdatedSignal.connect(self._update_battery) self._menuitem_rescandevices.triggered.connect(self._rescan_devices) self._menuItem_openconfigfolder.triggered.connect( self._open_config_folder) self.address.setValue(0xE7E7E7E7E7) self._auto_reconnect_enabled = Config().get("auto_reconnect") self.autoReconnectCheckBox.toggled.connect( self._auto_reconnect_changed) self.autoReconnectCheckBox.setChecked(Config().get("auto_reconnect")) self._disable_input = False self.joystickReader.input_updated.add_callback( lambda *args: self._disable_input or self.cf.commander. send_setpoint(*args)) self.joystickReader.assisted_input_updated.add_callback( lambda *args: self._disable_input or self.cf.commander. send_velocity_world_setpoint(*args)) self.joystickReader.heighthold_input_updated.add_callback( lambda *args: self._disable_input or self.cf.commander. send_zdistance_setpoint(*args)) self.joystickReader.hover_input_updated.add_callback( self.cf.commander.send_hover_setpoint) # Connection callbacks and signal wrappers for UI protection self.cf.connected.add_callback(self.connectionDoneSignal.emit) self.connectionDoneSignal.connect(self._connected) self.cf.disconnected.add_callback(self.disconnectedSignal.emit) self.disconnectedSignal.connect(self._disconnected) self.cf.connection_lost.add_callback(self.connectionLostSignal.emit) self.connectionLostSignal.connect(self._connection_lost) self.cf.connection_requested.add_callback( self.connectionInitiatedSignal.emit) self.connectionInitiatedSignal.connect(self._connection_initiated) self._log_error_signal.connect(self._logging_error) self.batteryBar.setTextVisible(False) self.linkQualityBar.setTextVisible(False) # Connect link quality feedback self.cf.link_quality_updated.add_callback(self.linkQualitySignal.emit) self.linkQualitySignal.connect( lambda percentage: self.linkQualityBar.setValue(percentage)) self._selected_interface = None self._initial_scan = True self._scan() # Parse the log configuration files self.logConfigReader = LogConfigReader(self.cf) self._current_input_config = None self._active_config = None self._active_config = None self.inputConfig = None # Add things to helper so tabs can access it cfclient.ui.pluginhelper.cf = self.cf cfclient.ui.pluginhelper.inputDeviceReader = self.joystickReader cfclient.ui.pluginhelper.logConfigReader = self.logConfigReader cfclient.ui.pluginhelper.pose_logger = PoseLogger(self.cf) cfclient.ui.pluginhelper.mainUI = self self.logConfigDialogue = LogConfigDialogue(cfclient.ui.pluginhelper) self._bootloader_dialog = BootloaderDialog(cfclient.ui.pluginhelper) self._cf2config_dialog = Cf2ConfigDialog(cfclient.ui.pluginhelper) self.menuItemBootloader.triggered.connect(self._bootloader_dialog.show) self._about_dialog = AboutDialog(cfclient.ui.pluginhelper) self.menuItemAbout.triggered.connect(self._about_dialog.show) self._menu_cf2_config.triggered.connect(self._cf2config_dialog.show) # Load and connect tabs self.tabsMenuItem = QMenu("Tabs", self.menuView, enabled=True) self.menuView.addMenu(self.tabsMenuItem) tabItems = {} self.loadedTabs = [] for tabClass in cfclient.ui.tabs.available: tab = tabClass(self.tabs, cfclient.ui.pluginhelper) # Set reference for plot-tab. if isinstance(tab, cfclient.ui.tabs.PlotTab): cfclient.ui.pluginhelper.plotTab = tab item = QtWidgets.QAction(tab.getMenuName(), self, checkable=True) item.toggled.connect(tab.toggleVisibility) self.tabsMenuItem.addAction(item) tabItems[tab.getTabName()] = item self.loadedTabs.append(tab) if not tab.enabled: item.setEnabled(False) # First instantiate all tabs and then open them in the correct order try: for tName in Config().get("open_tabs").split(","): t = tabItems[tName] if (t is not None and t.isEnabled()): # Toggle though menu so it's also marked as open there t.toggle() except Exception as e: logger.warning("Exception while opening tabs [{}]".format(e)) # Loading toolboxes (A bit of magic for a lot of automatic) self.toolboxesMenuItem = QMenu("Toolboxes", self.menuView, enabled=True) self.menuView.addMenu(self.toolboxesMenuItem) self.toolboxes = [] for t_class in cfclient.ui.toolboxes.toolboxes: toolbox = t_class(cfclient.ui.pluginhelper) dockToolbox = MyDockWidget(toolbox.getName()) dockToolbox.setWidget(toolbox) self.toolboxes += [ dockToolbox, ] # Add menu item for the toolbox item = QtWidgets.QAction(toolbox.getName(), self) item.setCheckable(True) item.triggered.connect(self.toggleToolbox) self.toolboxesMenuItem.addAction(item) dockToolbox.closed.connect(lambda: self.toggleToolbox(False)) # Setup some introspection item.dockToolbox = dockToolbox item.menuItem = item dockToolbox.dockToolbox = dockToolbox dockToolbox.menuItem = item # References to all the device sub-menus in the "Input device" menu self._all_role_menus = () # Used to filter what new devices to add default mapping to self._available_devices = () # Keep track of mux nodes so we can enable according to how many # devices we have self._all_mux_nodes = () # Check which Input muxes are available self._mux_group = QActionGroup(self._menu_inputdevice) self._mux_group.setExclusive(True) for m in self.joystickReader.available_mux(): node = QAction(m.name, self._menu_inputdevice, checkable=True, enabled=False) node.toggled.connect(self._mux_selected) self._mux_group.addAction(node) self._menu_inputdevice.addAction(node) self._all_mux_nodes += (node, ) mux_subnodes = () for name in m.supported_roles(): sub_node = QMenu(" {}".format(name), self._menu_inputdevice, enabled=False) self._menu_inputdevice.addMenu(sub_node) mux_subnodes += (sub_node, ) self._all_role_menus += ({ "muxmenu": node, "rolemenu": sub_node }, ) node.setData((m, mux_subnodes)) self._mapping_support = True # Add checkbuttons for theme-selection. self._theme_group = QActionGroup(self.menuThemes) self._theme_group.setExclusive(True) self._theme_checkboxes = [] for theme in UiUtils.THEMES: node = QAction(theme, self.menuThemes, checkable=True) node.setObjectName(theme) node.toggled.connect(self._theme_selected) self._theme_checkboxes.append(node) self._theme_group.addAction(node) self.menuThemes.addAction(node)
def __init__(self, do_device_discovery=True): self._input_device = None self.min_thrust = 0 self.max_thrust = 0 self._thrust_slew_rate = 0 self.thrust_slew_enabled = False self.thrust_slew_limit = 0 self.has_pressure_sensor = False self.max_rp_angle = 0 self.max_yaw_rate = 0 self._old_thrust = 0 self._old_raw_thrust = 0 self._old_alt_hold = False self.springy_throttle = True self.trim_roll = Config().get("trim_roll") self.trim_pitch = Config().get("trim_pitch") self._input_map = None self._mux = [ NoMux(self), TakeOverSelectiveMux(self), TakeOverMux(self) ] # Set NoMux as default self._selected_mux = self._mux[0] if Config().get("flightmode") is "Normal": self.max_yaw_rate = Config().get("normal_max_yaw") self.max_rp_angle = Config().get("normal_max_rp") # Values are stored at %, so use the functions to set the values self.min_thrust = Config().get("normal_min_thrust") self.max_thrust = Config().get("normal_max_thrust") self.thrust_slew_limit = Config().get("normal_slew_limit") self.thrust_slew_rate = Config().get("normal_slew_rate") else: self.max_yaw_rate = Config().get("max_yaw") self.max_rp_angle = Config().get("max_rp") # Values are stored at %, so use the functions to set the values self.min_thrust = Config().get("min_thrust") self.max_thrust = Config().get("max_thrust") self.thrust_slew_limit = Config().get("slew_limit") self.thrust_slew_rate = Config().get("slew_rate") self._dev_blacklist = None if len(Config().get("input_device_blacklist")) > 0: self._dev_blacklist = re.compile( Config().get("input_device_blacklist")) logger.info("Using device blacklist [{}]".format( Config().get("input_device_blacklist"))) self._available_devices = {} # TODO: The polling interval should be set from config file self._read_timer = PeriodicTimer(0.01, self.read_input) if do_device_discovery: self._discovery_timer = PeriodicTimer(1.0, self._do_device_discovery) self._discovery_timer.start() # Check if user config exists, otherwise copy files if not os.path.exists(ConfigManager().configs_dir): logger.info("No user config found, copying dist files") os.makedirs(ConfigManager().configs_dir) for f in glob.glob(cfclient.module_path + "/configs/input/[A-Za-z]*.json"): dest = os.path.join(ConfigManager().configs_dir, os.path.basename(f)) if not os.path.isfile(dest): logger.debug("Copying %s", f) shutil.copy2(f, ConfigManager().configs_dir) ConfigManager().get_list_of_configs() self.input_updated = Caller() self.rp_trim_updated = Caller() self.emergency_stop_updated = Caller() self.device_discovery = Caller() self.device_error = Caller() self.althold_updated = Caller() self.alt1_updated = Caller() self.alt2_updated = Caller() # Call with 3 bools (rp_limiting, yaw_limiting, thrust_limiting) self.limiting_updated = Caller()
def __init__(self, tabWidget, helper, *args): super(SwarmTab, self).__init__(*args) self.setupUi(self) self.tabName = "Swarm" self.menuName = "Swarm" self.tabWidget = tabWidget self.helper = helper print("helper:", helper) self.disconnectedSignal.connect(self.disconnected) self.connectionFinishedSignal.connect(self.connected) # Incoming signals self.helper.cf.connected.add_callback( self.connectionFinishedSignal.emit) self.helper.cf.disconnected.add_callback(self.disconnectedSignal.emit) self._input_updated_signal.connect(self.updateInputControl) self.helper.inputDeviceReader.input_updated.add_callback( self._input_updated_signal.emit) self._rp_trim_updated_signal.connect(self.calUpdateFromInput) self.helper.inputDeviceReader.rp_trim_updated.add_callback( self._rp_trim_updated_signal.emit) self._emergency_stop_updated_signal.connect(self.updateEmergencyStop) self.helper.inputDeviceReader.emergency_stop_updated.add_callback( self._emergency_stop_updated_signal.emit) self.helper.inputDeviceReader.heighthold_input_updated.add_callback( self._heighthold_input_updated_signal.emit) self._heighthold_input_updated_signal.connect( self._heighthold_input_updated) self.helper.inputDeviceReader.hover_input_updated.add_callback( self._hover_input_updated_signal.emit) self._hover_input_updated_signal.connect(self._hover_input_updated) self.helper.inputDeviceReader.assisted_control_updated.add_callback( self._assisted_control_updated_signal.emit) self._assisted_control_updated_signal.connect( self._assisted_control_updated) self._imu_data_signal.connect(self._imu_data_received) self._baro_data_signal.connect(self._baro_data_received) self._motor_data_signal.connect(self._motor_data_received) self._log_error_signal.connect(self._logging_error) # PlotWidget Stuff self._plot = PlotWidget(fps=30) # Check if we could find the PyQtImport. If not, then # set this tab as disabled self.enabled = self._plot.can_enable self._model = LogConfigModel() self.dataSelector.setModel(self._model) self.plotLayout.addWidget(self._plot) self._log_data_signal.connect(self._log_data_received) self._plotter_log_error_signal.connect(self._plotter_logging_error) if self.enabled: self._disconnected_signal.connect(self._disconnected) self.helper.cf.disconnected.add_callback( self._disconnected_signal.emit) self._connected_signal.connect(self._connected) self.helper.cf.connected.add_callback(self._connected_signal.emit) self.helper.cf.log.block_added_cb.add_callback(self._config_added) self.dataSelector.currentIndexChanged.connect( self._selection_changed) self._previous_config = None self._started_previous = False self.targetCalRoll.valueChanged.connect(self._trim_roll_changed) self.inputTypeComboBox.currentIndexChanged.connect( self.inputtypeChange) self.stepHeightCombo.valueChanged.connect(self._step_height_changed) self.frequencyCombo.valueChanged.connect(self._sine_frequency_changed) self.referenceHeightCheckbox.toggled.connect( lambda: self._use_ref_input(self.referenceHeightCheckbox.isChecked( ))) self.targetCalPitch.valueChanged.connect(self._trim_pitch_changed) self.updateGainsBtn.clicked.connect(self._controller_gain_changed) self.k1Combo.valueChanged.connect(self._k123_gain_changed) self.k2Combo.valueChanged.connect(self._k123_gain_changed) self.k3Combo.valueChanged.connect(self._k123_gain_changed) # self.maxAngle.valueChanged.connect(self.maxAngleChanged) # self.maxYawRate.valueChanged.connect(self.maxYawRateChanged) self.uiSetupReadySignal.connect(self.uiSetupReady) self.clientXModeCheckbox.toggled.connect(self.changeXmode) self.isInCrazyFlightmode = False self.uiSetupReady() self._ledring_nbr_effects = 0 self.helper.cf.param.add_update_callback( group="imu_sensors", cb=self._set_available_sensors) self.helper.cf.param.all_updated.add_callback(self._all_params_updated) self.logBaro = None self.logAltHold = None self.ai = AttitudeIndicator() self.verticalLayout_2.addWidget(self.ai) self.splitter.setSizes([1000, 1]) self.targetCalPitch.setValue(Config().get("trim_pitch")) self.targetCalRoll.setValue(Config().get("trim_roll")) self.helper.inputDeviceReader.alt1_updated.add_callback( self.alt1_updated) self.helper.inputDeviceReader.alt2_updated.add_callback( self.alt2_updated) self._tf_state = 0 self._ring_effect = 0
import logging from threading import Thread, Lock ZMQ_PULL_PORT = 1024 + 190 logger = logging.getLogger(__name__) enabled = False try: import zmq enabled = True except Exception as e: logger.warning("Not enabling ZMQ LED driver access," "import failed ({})".format(e)) if not Config().get("enable_zmq_led"): enabled = False logger.info("ZMQ led disabled in config file") class _PullReader(Thread): """Blocking thread for reading from ZMQ socket""" def __init__(self, receiver, callback, *args): """Initialize""" super(_PullReader, self).__init__(*args) self._receiver = receiver self._cb = callback self.daemon = True self.lock = Lock()