def thrustLoweringSlewRateLimitChanged(self): self.helper.inputDeviceReader.updateThrustLoweringSlewrateSignal.emit( self.percentageToThrust(self.thrustLoweringSlewRateLimit.value()), self.percentageToThrust(self.slewEnableLimit.value())) if (self.isInCrazyFlightmode == True): Config().set("slew_limit", self.slewEnableLimit.value()) Config().set("slew_rate", self.thrustLoweringSlewRateLimit.value())
def minMaxThrustChanged(self): self.helper.inputDeviceReader.updateMinMaxThrustSignal.emit( self.percentageToThrust(self.minThrust.value()), self.percentageToThrust(self.maxThrust.value())) if (self.isInCrazyFlightmode == True): Config().set("min_thrust", self.minThrust.value()) Config().set("max_thrust", self.maxThrust.value())
def _update_input(self, device="", config=""): self.joystickReader.stopInput() self._active_config = str(config) self._active_device = str(device) Config().set("input_device", self._active_device) Config().get("device_config_mapping")[ self._active_device] = self._active_config self.joystickReader.startInput(self._active_device, self._active_config) # update the checked state of the menu items for c in self._menu_mappings.actions(): c.setEnabled(True) if c.text() == self._active_config: c.setChecked(True) for c in self._menu_devices.actions(): c.setEnabled(True) if c.text() == self._active_device: c.setChecked(True) # update label if device == "" and config == "": self._statusbar_label.setText("No input device selected") elif config == "": self._statusbar_label.setText( "Using [%s] - No input config selected" % (self._active_device)) else: self._statusbar_label.setText( "Using [%s] with config [%s]" % (self._active_device, self._active_config))
def thrustLoweringSlewRateLimitChanged(self): self.helper.inputDeviceReader.set_thrust_slew_limiting( self.thrustLoweringSlewRateLimit.value(), self.slewEnableLimit.value()) if (self.isInCrazyFlightmode == True): Config().set("slew_limit", self.slewEnableLimit.value()) Config().set("slew_rate", self.thrustLoweringSlewRateLimit.value())
def run(self): def _get_flight_tab(): for tab in self.main.loadedTabs: if tab.tabName == "Flight Control": return tab raise Exception("Flight tab not found") while True: # Wait until a Crazyflie is connected try: if len(Config().get("link_uri")) > 0: uri = Config().get("link_uri") break except KeyError: time.sleep(1) print("DEBUG: URI = ".format(uri)) flight_tab = _get_flight_tab() while True: time.sleep(MonitorThread.POLL_INTERVAL) if flight_tab.actualRoll.displayText() and abs(float(flight_tab.actualRoll.displayText())) \ > MonitorThread.THRESHOLD or \ flight_tab.actualPitch.displayText() and abs(float(flight_tab.actualPitch.displayText())) \ > MonitorThread.THRESHOLD: print( "###Threshold exceeded - prepare for takeoff!###") time.sleep(5) """Send hover command for 10 seconds at rate of 10Hz""" for z in range(100): self.main.cf.commander.send_hover_setpoint( 0, 0, 0, 0.5) # (Vx, Vy, Yaw rate, Z) time.sleep(0.1) self.main.cf.commander.send_stop_setpoint() break # Replace this line with time.sleep() to re-enable angle monitoring
def connected(self, linkURI): # IMU & THRUST lg = LogConfig("Stabilizer", Config().get("ui_update_period")) 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") 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))
def toggleVisibility(self, checked): """Show or hide the tab.""" if checked: self.tabWidget.addTab(self, self.getTabName()) s = "" try: s = Config().get("open_tabs") if (len(s) > 0): s += "," except Exception as e: logger.warning("Exception while adding tab to config and " "reading tab config") # Check this since tabs in config are opened when app is started if (self.tabName not in s): s += "%s" % self.tabName Config().set("open_tabs", str(s)) if not checked: self.tabWidget.removeTab(self.tabWidget.indexOf(self)) try: parts = Config().get("open_tabs").split(",") except Exception as e: logger.warning("Exception while removing tab from config and " "reading tab config") parts = [] s = "" for p in parts: if (self.tabName != p): s += "%s," % p s = s[0:len(s) - 1] # Remove last comma Config().set("open_tabs", str(s))
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 __init__(self): QThread.__init__(self) # self.moveToThread(self) # TODO: Should be OS dependant print "setting input.py inputdevice" self.inputdevice = PyGameReader() self.startInputSignal.connect(self.startInput) self.stopInputSignal.connect(self.stopInput) self.updateMinMaxThrustSignal.connect(self.updateMinMaxThrust) self.update_trim_roll_signal.connect(self._update_trim_roll) self.update_trim_pitch_signal.connect(self._update_trim_pitch) self.updateMaxRPAngleSignal.connect(self.updateMaxRPAngle) self.updateThrustLoweringSlewrateSignal.connect( self.updateThrustLoweringSlewrate) self.updateMaxYawRateSignal.connect(self.updateMaxYawRate) self.maxRPAngle = 0 self.thrustDownSlew = 0 self.thrustSlewEnabled = False self.slewEnableLimit = 0 self.maxYawRate = 0 self.detectAxis = False self.emergencyStop = False self.oldThrust = 0 self._trim_roll = Config().get("trim_roll") self._trim_pitch = Config().get("trim_pitch") # TODO: The polling interval should be set from config file self.readTimer = QTimer() self.readTimer.setInterval(10) self.connect(self.readTimer, SIGNAL("timeout()"), self.readInput) self._discovery_timer = QTimer() self._discovery_timer.setInterval(1000) self.connect(self._discovery_timer, SIGNAL("timeout()"), self._do_device_discovery) self._discovery_timer.start() self._available_devices = {} # Check if user config exists, otherwise copy files if not os.path.isdir(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"): shutil.copy2(f, ConfigManager().configs_dir)
def connected(self, linkURI): # Reset Gains self.helper.cf.param.set_value("posCtlPid.zKd", str(0.0)) self.helper.cf.param.set_value("posCtlPid.zKi", str(0.5)) self.helper.cf.param.set_value("posCtlPid.zKp", str(40.0)) self.k1Combo.setValue(40.0) self.helper.cf.param.set_value("posCtlPid.zVelMax", str(15.0)) self.helper.cf.param.set_value("velCtlPid.vzKd", str(0.0)) self.helper.cf.param.set_value("velCtlPid.vzKi", str(0.0)) self.helper.cf.param.set_value("velCtlPid.vzKp", str(15.0)) self.k2Combo.setValue(15.0) self.k3Combo.setValue(0.0) # IMU & THRUST lg = LogConfig("Stabilizer", Config().get("ui_update_period")) 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") 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)) self._populate_assisted_mode_dropdown()
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) heightHoldPossible = False if self.helper.cf.mem.ow_search(vid=0xBC, pid=0x09): heightHoldPossible = True if not heightHoldPossible: self._assist_mode_combo.model().item(2).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 == 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 heightHoldPossible: defaultOption = 2 self._assist_mode_combo.setCurrentIndex(defaultOption) self._assist_mode_combo.currentIndexChanged.emit(defaultOption)
def setUIState(self, newState, linkURI=""): self.uiState = newState if (newState == UIState.DISCONNECTED): self.setWindowTitle("Not connected") self.menuItemConnect.setText("Connect to Crazyflie") self.connectButton.setText("Connect") self.menuItemQuickConnect.setEnabled(True) self.batteryBar.setValue(3000) self.linkQualityBar.setValue(0) self.menuItemBootloader.setEnabled(True) self.logConfigAction.setEnabled(False) if (len(Config().get("link_uri")) > 0): self.quickConnectButton.setEnabled(True) if (newState == UIState.CONNECTED): s = "Connected on %s" % linkURI self.setWindowTitle(s) self.menuItemConnect.setText("Disconnect") self.connectButton.setText("Disconnect") self.logConfigAction.setEnabled(True) if (newState == UIState.CONNECTING): s = "Connecting to %s" % linkURI self.setWindowTitle(s) self.menuItemConnect.setText("Cancel") self.connectButton.setText("Cancel") self.quickConnectButton.setEnabled(False) self.menuItemBootloader.setEnabled(False) self.menuItemQuickConnect.setEnabled(False)
def _inputdevice_selected(self, checked): """Called when a new input device has been selected from the menu. The data in the menu object is the associated map menu (directly under the item in the menu) and the raw device""" (map_menu, device, mux_menu) = self.sender().data() if not checked: if map_menu: map_menu.setEnabled(False) # Do not close the device, since we don't know exactly # how many devices the mux can have open. When selecting a # new mux the old one will take care of this. else: if map_menu: map_menu.setEnabled(True) (mux, sub_nodes) = mux_menu.data() for role_node in sub_nodes: for dev_node in role_node.children(): if type(dev_node) is QAction and dev_node.isChecked(): if device.id == dev_node.data()[1].id \ and dev_node is not self.sender(): dev_node.setChecked(False) role_in_mux = str(self.sender().parent().title()).strip() logger.info("Role of {} is {}".format(device.name, role_in_mux)) Config().set("input_device", str(device.name)) self._mapping_support = self.joystickReader.start_input( device.name, role_in_mux) self._update_input_device_footer()
def connected(self, linkURI): # MOTOR & THRUST lg = LogConfig("Motors", Config().get("ui_update_period")) lg.add_variable("stabilizer.thrust", "uint16_t") lg.add_variable("motor.m1") lg.add_variable("motor.m2") lg.add_variable("motor.m3") lg.add_variable("motor.m4") lg.add_variable("sys.canfly") self._hlCommander = PositionHlCommander( self.helper.cf, x=0.0, y=0.0, z=0.0, default_velocity=0.3, default_height=0.5, controller=PositionHlCommander.CONTROLLER_PID ) try: self.helper.cf.log.add_config(lg) lg.data_received_cb.add_callback(self._log_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))
def foundInterfaces(self, interfaces): selected_interface = self._selected_interface self.interfaceCombo.clear() self.interfaceCombo.addItem(INTERFACE_PROMPT_TEXT) formatted_interfaces = [] for i in interfaces: if len(i[1]) > 0: interface = "%s - %s" % (i[0], i[1]) else: interface = i[0] formatted_interfaces.append(interface) self.interfaceCombo.addItems(formatted_interfaces) if self._initial_scan: self._initial_scan = False try: selected_interface = Config().get("link_uri") except KeyError: pass newIndex = 0 if selected_interface is not None: try: newIndex = formatted_interfaces.index(selected_interface) + 1 except ValueError: pass self.interfaceCombo.setCurrentIndex(newIndex) self.uiState = UIState.DISCONNECTED self._update_ui_state()
def _update_input(self, device="", config=""): self._active_config = str(config) self._active_device = str(device) Config().set("input_device", str(self._active_device)) # update the checked state of the menu items for c in self._menu_mappings.actions(): c.setEnabled(True) if c.text() == self._active_config: c.setChecked(True) for c in self._menu_devices.actions(): c.setEnabled(True) if c.text() == self._active_device: c.setChecked(True) # update label if device == "" and config == "": self._statusbar_label.setText("No input device selected") elif config == "": self._statusbar_label.setText("Using [{}] - " "No input config selected".format (self._active_device)) else: self._statusbar_label.setText("Using [{}] with config [{}]".format (self._active_device, self._active_config))
def _update_ui_state(self, newState, linkURI=""): self.uiState = newState if newState == UIState.DISCONNECTED: self.setWindowTitle("Not connected") self.menuItemConnect.setText("Connect to Crazyflie") self.connectButton.setText("Connect") self.menuItemQuickConnect.setEnabled(True) self.batteryBar.setValue(3000) self._menu_cf2_config.setEnabled(False) self._menu_cf1_config.setEnabled(True) self.linkQualityBar.setValue(0) self.menuItemBootloader.setEnabled(True) self.logConfigAction.setEnabled(False) if len(Config().get("link_uri")) > 0: self.quickConnectButton.setEnabled(True) if newState == UIState.CONNECTED: s = "Connected on %s" % linkURI self.setWindowTitle(s) self.menuItemConnect.setText("Disconnect") self.connectButton.setText("Disconnect") self.logConfigAction.setEnabled(True) # Find out if there's an I2C EEPROM, otherwise don't show the # dialog. if len(self.cf.mem.get_mems(MemoryElement.TYPE_I2C)) > 0: self._menu_cf2_config.setEnabled(True) self._menu_cf1_config.setEnabled(False) if newState == UIState.CONNECTING: s = "Connecting to {} ...".format(linkURI) self.setWindowTitle(s) self.menuItemConnect.setText("Cancel") self.connectButton.setText("Cancel") self.quickConnectButton.setEnabled(False) self.menuItemBootloader.setEnabled(False) self.menuItemQuickConnect.setEnabled(False)
def _profileThrust(self): if self.uiState == UIState.CONNECTED: # send_setpoint(self, roll, pitch, yaw, thrust): roll = 0 pitch = 0 yaw = 0 count = 0 profileSeconds = int(self.countText.text()) sleepTimeSec = 0.1 min_thrust = Config().get("min_thrust") max_thrust = 65536.0 # Config().get("max_thrust") thrustPercentage = self.thrustSlider.value() thrustValue = int(round((max_thrust - min_thrust) * thrustPercentage / 100)) countMax = int(profileSeconds / sleepTimeSec) self.cf.commander.send_setpoint(0, 0, 0, 0) while count < countMax: self.cf.commander.send_setpoint(roll, pitch, yaw, thrustValue) time.sleep(sleepTimeSec) count += 1 self.cf.commander.send_setpoint(0, 0, 0, 0) #self.cf.commander.send_setpoint(roll, pitch, yaw, thrustValue) else: logger.info("Something went wrong") # FIXME
def _inputdevice_selected(self, checked): """Called when a new input device has been selected from the menu""" if not checked: return self._input_dev_stack.append(self.sender().text()) selected_device_name = str(self.sender().text()) self._active_device = selected_device_name # Save the device as "last used device" Config().set("input_device", str(selected_device_name)) # Read preferred config used for this controller from config, # if found then select this config in the menu self._mapping_support = self.joystickReader.start_input(selected_device_name) self._adjust_nbr_of_selected_devices() if self.joystickReader.get_mux_supported_dev_count() == 1: preferred_config = self.joystickReader.get_saved_device_mapping(selected_device_name) if preferred_config: for c in self._menu_mappings.actions(): if c.text() == preferred_config: c.setChecked(True)
def _theme_selected(self, *args): """ Callback when a theme is selected. """ for checkbox in self._theme_checkboxes: if checkbox.isChecked(): theme = checkbox.objectName() app = QtWidgets.QApplication.instance() app.setStyleSheet(UiUtils.select_theme(theme)) Config().set('theme', theme)
def readConfigAction(self): self.statusChanged.emit("Reading config block...", 0) data = self.loader.read_flash(self.loader.start_page + 117) if (data is not None): self.statusChanged.emit("Reading config block...done!", 100) if data[0:4] == "0xBC": [channel, speed, pitchTrim, rollTrim] = struct.unpack( "<BBff", data[5:15]) # Skip 0xBC and version at the beginning else: channel = Config().get("default_cf_channel") speed = Config().get("default_cf_speed") pitchTrim = Config().get("default_cf_trim") rollTrim = Config().get("default_cf_trim") self.updateConfigSignal.emit(channel, speed, pitchTrim, rollTrim) else: self.statusChanged.emit("Reading config block failed!", 0)
def uiSetupReady(self): flightComboIndex = self.flightModeCombo.findText( Config().get("flightmode"), Qt.MatchFixedString) if (flightComboIndex < 0): self.flightModeCombo.setCurrentIndex(0) self.flightModeCombo.currentIndexChanged.emit(0) else: self.flightModeCombo.setCurrentIndex(flightComboIndex) self.flightModeCombo.currentIndexChanged.emit(flightComboIndex)
def set_input_map(self, device_name, input_map_name): """Load and set an input device map with the given name""" settings = ConfigManager().get_settings(input_map_name) if settings: self.springy_throttle = settings["springythrottle"] self._input_map = ConfigManager().get_config(input_map_name) self._get_device_from_name(device_name).input_map = self._input_map self._get_device_from_name(device_name).input_map_name = input_map_name Config().get("device_config_mapping")[device_name] = input_map_name
def uiSetupReady(self): flightComboIndex = self.flightModeCombo.findText( Config().get("flightmode"), Qt.MatchFixedString) if (flightComboIndex < 0): self.flightModeCombo.setCurrentIndex(0) self.flightModeCombo.currentIndexChanged.emit(0) else: self.flightModeCombo.setCurrentIndex(flightComboIndex) self.flightModeCombo.currentIndexChanged.emit(flightComboIndex) try: assistmodeComboIndex = Config().get("assistedControl") self._assist_mode_combo.setCurrentIndex(assistmodeComboIndex) self._assist_mode_combo.currentIndexChanged.emit( assistmodeComboIndex) except KeyError: self._assist_mode_combo.setCurrentIndex(0) self._assist_mode_combo.currentIndexChanged.emit(0)
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 list(device_config_mapping.keys()): config = device_config_mapping[device_name] logging.debug("For [{}] we recommend [{}]".format(device_name, config)) return config
def _assist_mode_changed(self, item): mode = None if (item == 0): # Altitude hold mode = JoystickReader.ASSISTED_CONTROL_ALTHOLD if (item == 1): # Position hold mode = JoystickReader.ASSISTED_CONTROL_POSHOLD self.helper.inputDeviceReader.set_assisted_control(mode) Config().set("assistedControl", mode)
def _changeThrust(self): thrustPercentage = self.thrustSlider.value() labelTest = 'Thrust (' + str(thrustPercentage) + '%)' min_thrust = Config().get("min_thrust") max_thrust = 65536.0 # Config().get("max_thrust") # MAX_THRUST = 65536.0 thrustValue = int(round((max_thrust - min_thrust) * thrustPercentage / 100)) #thrustValueLabel = 'Thrust value = ' + str(thrustValue) self.thrustLabel.setText(labelTest)
def _set_address(self): address = 0xE7E7E7E7E7 try: link_uri = Config().get("link_uri") if len(link_uri) > 0: address = int(link_uri.split('/')[-1], 16) except Exception as err: logger.warn('failed to parse address from config: %s' % str(err)) finally: self.address.setValue(address)
def readConfigAction(self): self.statusChanged.emit("Reading config block...", 0) data = self._bl.read_cf1_config() if (data is not None): if data[0:4] == "0xBC": # Skip 0xBC and version at the beginning [channel, speed, pitchTrim, rollTrim] = struct.unpack("<BBff", data[5:15]) self.statusChanged.emit("Reading config block...done!", 100) else: channel = Config().get("default_cf_channel") speed = Config().get("default_cf_speed") pitchTrim = Config().get("default_cf_trim") rollTrim = Config().get("default_cf_trim") self.statusChanged.emit( "Could not find config block, showing defaults", 100) self.updateConfigSignal.emit(channel, speed, rollTrim, pitchTrim) else: self.statusChanged.emit("Reading config block failed!", 0)
def __init__(self, do_device_discovery=True): # TODO: Should be OS dependant self.inputdevice = PyGameReader() self.maxRPAngle = 0 self.thrustDownSlew = 0 self.thrustSlewEnabled = False self.slewEnableLimit = 0 self.maxYawRate = 0 self.detectAxis = False self.emergencyStop = False self.oldThrust = 0 self._trim_roll = Config().get("trim_roll") self._trim_pitch = Config().get("trim_pitch") # TODO: The polling interval should be set from config file self.readTimer = PeriodicTimer(0.01, self.readInput) if do_device_discovery: self._discovery_timer = PeriodicTimer(1.0, self._do_device_discovery) self._discovery_timer.start() self._available_devices = {} # Check if user config exists, otherwise copy files if not os.path.isdir(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"): 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()