cfclient 2017.4__py3-none-any.whl → 2025.12.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cfclient/__init__.py +16 -11
- cfclient/configs/config.json +4 -3
- cfclient/configs/input/Generic_OS_X.json +1 -0
- cfclient/configs/input/Joystick.json +1 -0
- cfclient/configs/input/PS3_Mode_1.json +1 -0
- cfclient/configs/input/PS3_Mode_2.json +1 -0
- cfclient/configs/input/PS3_Mode_3.json +1 -0
- cfclient/configs/input/PS4_Mode_1.json +1 -0
- cfclient/configs/input/PS4_Mode_2.json +1 -0
- cfclient/configs/input/PS4_shoulder_btns_yaw.json +1 -0
- cfclient/configs/input/xbox360_mode1.json +1 -0
- cfclient/configs/log/PID_tuning/Attitude.json +46 -0
- cfclient/configs/log/PID_tuning/Attitude_rate.json +46 -0
- cfclient/configs/log/PID_tuning/Position.json +46 -0
- cfclient/configs/log/PID_tuning/Velocity.json +46 -0
- cfclient/configs/log/PID_tuning_components/Pitch.json +22 -0
- cfclient/configs/log/PID_tuning_components/Pitch_rate.json +22 -0
- cfclient/configs/log/PID_tuning_components/Position_x.json +22 -0
- cfclient/configs/log/PID_tuning_components/Position_y.json +22 -0
- cfclient/configs/log/PID_tuning_components/Position_z.json +22 -0
- cfclient/configs/log/PID_tuning_components/Roll.json +22 -0
- cfclient/configs/log/PID_tuning_components/Roll_rate.json +22 -0
- cfclient/configs/log/PID_tuning_components/Velocity_x.json +22 -0
- cfclient/configs/log/PID_tuning_components/Velocity_y.json +22 -0
- cfclient/configs/log/PID_tuning_components/Velocity_z.json +22 -0
- cfclient/configs/log/PID_tuning_components/Yaw.json +22 -0
- cfclient/configs/log/PID_tuning_components/Yaw_rate.json +22 -0
- cfclient/gui.py +44 -9
- cfclient/headless.py +3 -12
- cfclient/resources/log_param_doc.json +1 -0
- cfclient/ui/connectivity_manager.py +198 -0
- cfclient/ui/dialogs/about.py +53 -36
- cfclient/ui/dialogs/about.ui +23 -3
- cfclient/ui/dialogs/anchor_position_dialog.py +252 -0
- cfclient/ui/dialogs/anchor_position_dialog.ui +138 -0
- cfclient/ui/dialogs/basestation_mode_dialog.py +185 -0
- cfclient/ui/dialogs/basestation_mode_dialog.ui +186 -0
- cfclient/ui/dialogs/bootloader.py +448 -85
- cfclient/ui/dialogs/bootloader.ui +387 -134
- cfclient/ui/dialogs/cf2config.py +4 -4
- cfclient/ui/dialogs/cf2config.ui +3 -4
- cfclient/ui/dialogs/inputconfigdialogue.py +24 -19
- cfclient/ui/dialogs/inputconfigdialogue.ui +53 -30
- cfclient/ui/dialogs/lighthouse_bs_geometry_dialog.py +220 -0
- cfclient/ui/dialogs/lighthouse_bs_geometry_dialog.ui +110 -0
- cfclient/ui/dialogs/lighthouse_system_type_dialog.py +93 -0
- cfclient/ui/dialogs/lighthouse_system_type_dialog.ui +121 -0
- cfclient/ui/dialogs/logconfigdialogue.py +401 -101
- cfclient/ui/dialogs/logconfigdialogue.ui +117 -72
- cfclient/ui/icons/bl.webp +0 -0
- cfclient/ui/icons/bolt.webp +0 -0
- cfclient/ui/icons/cf21.webp +0 -0
- cfclient/ui/icons/checkmark_black.png +0 -0
- cfclient/ui/icons/checkmark_white.png +0 -0
- cfclient/ui/icons/create.png +0 -0
- cfclient/ui/icons/delete.png +0 -0
- cfclient/ui/icons/flapper.webp +0 -0
- cfclient/ui/icons/tag.webp +0 -0
- cfclient/ui/main.py +328 -258
- cfclient/ui/main.ui +184 -80
- cfclient/ui/pluginhelper.py +7 -1
- cfclient/ui/pose_logger.py +116 -0
- cfclient/ui/tab_toolbox.py +208 -0
- cfclient/ui/tabs/ColorLEDTab.py +752 -0
- cfclient/ui/tabs/ConsoleTab.py +48 -13
- cfclient/ui/{toolboxes → tabs}/CrtpSharkToolbox.py +19 -34
- cfclient/ui/tabs/ExampleTab.py +9 -16
- cfclient/ui/tabs/FlightTab.py +437 -325
- cfclient/ui/tabs/GpsTab.py +14 -20
- cfclient/ui/tabs/LEDRingTab.py +277 -0
- cfclient/ui/tabs/LogBlockDebugTab.py +20 -27
- cfclient/ui/tabs/LogBlockTab.py +35 -35
- cfclient/ui/tabs/LogClientTab.py +85 -0
- cfclient/ui/tabs/LogTab.py +50 -27
- cfclient/ui/tabs/ParamTab.py +443 -57
- cfclient/ui/tabs/PlotTab.py +23 -25
- cfclient/ui/tabs/TuningTab.py +292 -0
- cfclient/ui/tabs/__init__.py +12 -2
- cfclient/ui/tabs/colorLEDTab.ui +624 -0
- cfclient/ui/tabs/consoleTab.ui +46 -0
- cfclient/ui/tabs/flightActionContainer.ui +103 -0
- cfclient/ui/tabs/flightTab.ui +724 -237
- cfclient/ui/tabs/{ledTab.ui → ledRingTab.ui} +63 -46
- cfclient/ui/tabs/lighthouse_tab.py +714 -0
- cfclient/ui/tabs/lighthouse_tab.ui +430 -0
- cfclient/ui/tabs/locopositioning_tab.py +606 -389
- cfclient/ui/tabs/locopositioning_tab.ui +370 -253
- cfclient/ui/tabs/logClientTab.ui +52 -0
- cfclient/ui/tabs/logTab.ui +1 -1
- cfclient/ui/tabs/paramTab.ui +204 -3
- cfclient/ui/tabs/tuningTab.ui +773 -0
- cfclient/ui/widgets/ai.py +37 -39
- cfclient/ui/widgets/hexspinbox.py +16 -10
- cfclient/ui/widgets/plotter.ui +39 -47
- cfclient/ui/widgets/plotwidget.py +57 -22
- cfclient/ui/widgets/super_slider.py +112 -0
- cfclient/ui/wizards/__init__.py +0 -0
- cfclient/ui/wizards/bslh_1.png +0 -0
- cfclient/ui/wizards/bslh_2.png +0 -0
- cfclient/ui/wizards/bslh_3.png +0 -0
- cfclient/ui/wizards/bslh_4.png +0 -0
- cfclient/ui/wizards/bslh_5.png +0 -0
- cfclient/ui/wizards/lighthouse_geo_bs_estimation_wizard.py +465 -0
- cfclient/utils/config_manager.py +5 -4
- cfclient/utils/input/__init__.py +77 -19
- cfclient/utils/input/inputinterfaces/wiimote.py +2 -2
- cfclient/utils/input/inputreaderinterface.py +17 -7
- cfclient/utils/input/inputreaders/__init__.py +17 -0
- cfclient/utils/logconfigreader.py +245 -25
- cfclient/utils/logdatawriter.py +3 -1
- cfclient/utils/periodictimer.py +1 -1
- cfclient/utils/ui.py +336 -0
- cfclient/utils/zmq_led_driver.py +5 -0
- cfclient/utils/zmq_param.py +6 -0
- cfclient/version.py +34 -1
- cfclient-2025.12.1.dist-info/METADATA +70 -0
- cfclient-2025.12.1.dist-info/RECORD +152 -0
- {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/WHEEL +1 -1
- {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/entry_points.txt +0 -1
- cfclient-2025.12.1.dist-info/licenses/LICENSE.txt +350 -0
- {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/top_level.txt +1 -0
- cfconfig/Makefile +51 -0
- cfconfig/configblock.py +111 -0
- cfloader/__init__.py +41 -55
- cfzmq/__init__.py +22 -14
- cfclient/ui/dialogs/cf1config.py +0 -265
- cfclient/ui/dialogs/cf1config.ui +0 -260
- cfclient/ui/tab.py +0 -96
- cfclient/ui/tabs/LEDTab.py +0 -169
- cfclient/ui/toolboxes/ConsoleToolbox.py +0 -69
- cfclient/ui/toolboxes/DebugDriverToolbox.py +0 -107
- cfclient/ui/toolboxes/__init__.py +0 -45
- cfclient/ui/toolboxes/consoleToolbox.ui +0 -62
- cfclient/ui/toolboxes/debugDriverToolbox.ui +0 -86
- cfclient-2017.4.dist-info/DESCRIPTION.rst +0 -3
- cfclient-2017.4.dist-info/METADATA +0 -22
- cfclient-2017.4.dist-info/RECORD +0 -104
- cfclient-2017.4.dist-info/metadata.json +0 -1
- /cfclient/{icon-256.png → ui/icons/icon-256.png} +0 -0
- /cfclient/ui/{toolboxes → tabs}/crtpSharkToolbox.ui +0 -0
cfclient/ui/tabs/FlightTab.py
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
|
|
8
8
|
# || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
|
|
9
9
|
#
|
|
10
|
-
# Copyright (C) 2011-
|
|
10
|
+
# Copyright (C) 2011-2025 Bitcraze AB
|
|
11
11
|
#
|
|
12
12
|
# Crazyflie Nano Quadcopter Client
|
|
13
13
|
#
|
|
@@ -30,23 +30,21 @@ The flight control tab shows telemetry data and flight settings.
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
import logging
|
|
33
|
+
from enum import Enum
|
|
33
34
|
|
|
34
|
-
from
|
|
35
|
-
from
|
|
36
|
-
from
|
|
35
|
+
from PyQt6 import uic
|
|
36
|
+
from PyQt6.QtCore import Qt, pyqtSignal
|
|
37
|
+
from PyQt6.QtWidgets import QMessageBox
|
|
37
38
|
|
|
38
39
|
import cfclient
|
|
39
40
|
from cfclient.ui.widgets.ai import AttitudeIndicator
|
|
40
41
|
|
|
41
|
-
from cfclient.utils.config import Config
|
|
42
42
|
from cflib.crazyflie.log import LogConfig
|
|
43
43
|
|
|
44
|
+
from cfclient.utils.config import Config
|
|
44
45
|
from cfclient.utils.input import JoystickReader
|
|
45
46
|
|
|
46
|
-
from cfclient.ui.
|
|
47
|
-
|
|
48
|
-
PARAM_NAME_ALT_HOLD_TARGET = "posCtl.targetZ"
|
|
49
|
-
LOG_NAME_ESTIMATED_Z = "posEstimatorAlt.estimatedZ"
|
|
47
|
+
from cfclient.ui.tab_toolbox import TabToolbox
|
|
50
48
|
|
|
51
49
|
__author__ = 'Bitcraze AB'
|
|
52
50
|
__all__ = ['FlightTab']
|
|
@@ -58,20 +56,50 @@ flight_tab_class = uic.loadUiType(cfclient.module_path +
|
|
|
58
56
|
|
|
59
57
|
MAX_THRUST = 65536.0
|
|
60
58
|
|
|
59
|
+
TOOLTIP_ALTITUDE_HOLD = """\
|
|
60
|
+
Keeps the Crazyflie at its current altitude.
|
|
61
|
+
Thrust control becomes height velocity control. The Crazyflie
|
|
62
|
+
uses the barometer for height control and uses body-fixed coordinates."""
|
|
63
|
+
|
|
64
|
+
TOOLTIP_POSITION_HOLD = """\
|
|
65
|
+
Keeps the Crazyflie at its current 3D position. Pitch/Roll/
|
|
66
|
+
Thrust control becomes X/Y/Z velocity control. Uses world coordinates."""
|
|
67
|
+
|
|
68
|
+
TOOLTIP_HEIGHT_HOLD = """\
|
|
69
|
+
When activated, keeps the Crazyflie at 40cm above the ground.
|
|
70
|
+
Thrust control becomes height velocity control. Requires a height
|
|
71
|
+
sensor like the Z-Ranger deck or flow deck. Uses body-fixed coordinates.."""
|
|
72
|
+
|
|
73
|
+
TOOLTIP_HOVER = """\
|
|
74
|
+
When activated, keeps the Crazyflie at 40cm above the ground and tries to
|
|
75
|
+
keep the position in X and Y as well. Thrust control becomes height velocity
|
|
76
|
+
control. Requires a flow deck. Uses body-fixed coordinates."""
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class CommanderAction(Enum):
|
|
80
|
+
TAKE_OFF = 1
|
|
81
|
+
LAND = 2
|
|
82
|
+
UP = 3
|
|
83
|
+
DOWN = 4
|
|
84
|
+
LEFT = 5
|
|
85
|
+
RIGHT = 6
|
|
86
|
+
FORWARD = 7
|
|
87
|
+
BACK = 8
|
|
61
88
|
|
|
62
|
-
|
|
89
|
+
|
|
90
|
+
class FlightTab(TabToolbox, flight_tab_class):
|
|
63
91
|
uiSetupReadySignal = pyqtSignal()
|
|
64
92
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
_althold_data_signal = pyqtSignal(int, object, object)
|
|
68
|
-
_baro_data_signal = pyqtSignal(int, object, object)
|
|
93
|
+
_log_data_signal = pyqtSignal(int, object, object)
|
|
94
|
+
_pose_data_signal = pyqtSignal(object, object)
|
|
69
95
|
|
|
70
96
|
_input_updated_signal = pyqtSignal(float, float, float, float)
|
|
71
97
|
_rp_trim_updated_signal = pyqtSignal(float, float)
|
|
72
98
|
_emergency_stop_updated_signal = pyqtSignal(bool)
|
|
99
|
+
_arm_updated_signal = pyqtSignal(bool)
|
|
73
100
|
_assisted_control_updated_signal = pyqtSignal(bool)
|
|
74
101
|
_heighthold_input_updated_signal = pyqtSignal(float, float, float, float)
|
|
102
|
+
_hover_input_updated_signal = pyqtSignal(float, float, float, float)
|
|
75
103
|
|
|
76
104
|
_log_error_signal = pyqtSignal(object, str)
|
|
77
105
|
|
|
@@ -82,123 +110,95 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
82
110
|
|
|
83
111
|
_limiting_updated = pyqtSignal(bool, bool, bool)
|
|
84
112
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
113
|
+
LOG_NAME_THRUST = 'stabilizer.thrust'
|
|
114
|
+
LOG_NAME_MOTOR_1 = 'motor.m1'
|
|
115
|
+
LOG_NAME_MOTOR_2 = 'motor.m2'
|
|
116
|
+
LOG_NAME_MOTOR_3 = 'motor.m3'
|
|
117
|
+
LOG_NAME_MOTOR_4 = 'motor.m4'
|
|
118
|
+
LOG_NAME_CAN_FLY = 'sys.canfly'
|
|
119
|
+
LOG_NAME_SUPERVISOR_INFO = 'supervisor.info'
|
|
91
120
|
|
|
92
|
-
|
|
93
|
-
self.helper
|
|
121
|
+
def __init__(self, helper):
|
|
122
|
+
super(FlightTab, self).__init__(helper, 'Flight Control')
|
|
123
|
+
self.setupUi(self)
|
|
94
124
|
|
|
95
125
|
self.disconnectedSignal.connect(self.disconnected)
|
|
96
126
|
self.connectionFinishedSignal.connect(self.connected)
|
|
97
127
|
# Incomming signals
|
|
98
|
-
self.
|
|
128
|
+
self._helper.cf.connected.add_callback(
|
|
99
129
|
self.connectionFinishedSignal.emit)
|
|
100
|
-
self.
|
|
130
|
+
self._helper.cf.disconnected.add_callback(self.disconnectedSignal.emit)
|
|
101
131
|
|
|
102
132
|
self._input_updated_signal.connect(self.updateInputControl)
|
|
103
|
-
self.
|
|
133
|
+
self._helper.inputDeviceReader.input_updated.add_callback(
|
|
104
134
|
self._input_updated_signal.emit)
|
|
105
135
|
self._rp_trim_updated_signal.connect(self.calUpdateFromInput)
|
|
106
|
-
self.
|
|
136
|
+
self._helper.inputDeviceReader.rp_trim_updated.add_callback(
|
|
107
137
|
self._rp_trim_updated_signal.emit)
|
|
108
138
|
self._emergency_stop_updated_signal.connect(self.updateEmergencyStop)
|
|
109
|
-
self.
|
|
139
|
+
self._helper.inputDeviceReader.emergency_stop_updated.add_callback(
|
|
110
140
|
self._emergency_stop_updated_signal.emit)
|
|
141
|
+
self._arm_updated_signal.connect(lambda: self.updateArm(from_controller=True))
|
|
142
|
+
self._helper.inputDeviceReader.arm_updated.add_callback(self._arm_updated_signal.emit)
|
|
111
143
|
|
|
112
|
-
self.
|
|
144
|
+
self._helper.inputDeviceReader.heighthold_input_updated.add_callback(
|
|
113
145
|
self._heighthold_input_updated_signal.emit)
|
|
114
146
|
self._heighthold_input_updated_signal.connect(
|
|
115
147
|
self._heighthold_input_updated)
|
|
148
|
+
self._helper.inputDeviceReader.hover_input_updated.add_callback(
|
|
149
|
+
self._hover_input_updated_signal.emit)
|
|
150
|
+
self._hover_input_updated_signal.connect(
|
|
151
|
+
self._hover_input_updated)
|
|
116
152
|
|
|
117
|
-
self.
|
|
153
|
+
self._helper.inputDeviceReader.assisted_control_updated.add_callback(
|
|
118
154
|
self._assisted_control_updated_signal.emit)
|
|
119
155
|
|
|
120
156
|
self._assisted_control_updated_signal.connect(
|
|
121
157
|
self._assisted_control_updated)
|
|
122
158
|
|
|
123
|
-
self.
|
|
124
|
-
self.
|
|
125
|
-
self._althold_data_signal.connect(self._althold_data_received)
|
|
126
|
-
self._motor_data_signal.connect(self._motor_data_received)
|
|
159
|
+
self._pose_data_signal.connect(self._pose_data_received)
|
|
160
|
+
self._log_data_signal.connect(self._log_data_received)
|
|
127
161
|
|
|
128
162
|
self._log_error_signal.connect(self._logging_error)
|
|
129
163
|
|
|
164
|
+
self._isConnected = False
|
|
165
|
+
|
|
130
166
|
# Connect UI signals that are in this tab
|
|
131
167
|
self.flightModeCombo.currentIndexChanged.connect(self.flightmodeChange)
|
|
132
168
|
self.minThrust.valueChanged.connect(self.minMaxThrustChanged)
|
|
133
169
|
self.maxThrust.valueChanged.connect(self.minMaxThrustChanged)
|
|
134
|
-
self.thrustLoweringSlewRateLimit.valueChanged.connect(
|
|
135
|
-
|
|
136
|
-
self.slewEnableLimit.valueChanged.connect(
|
|
137
|
-
self.thrustLoweringSlewRateLimitChanged)
|
|
170
|
+
self.thrustLoweringSlewRateLimit.valueChanged.connect(self.thrustLoweringSlewRateLimitChanged)
|
|
171
|
+
self.slewEnableLimit.valueChanged.connect(self.thrustLoweringSlewRateLimitChanged)
|
|
138
172
|
self.targetCalRoll.valueChanged.connect(self._trim_roll_changed)
|
|
139
173
|
self.targetCalPitch.valueChanged.connect(self._trim_pitch_changed)
|
|
140
174
|
self.maxAngle.valueChanged.connect(self.maxAngleChanged)
|
|
141
175
|
self.maxYawRate.valueChanged.connect(self.maxYawRateChanged)
|
|
142
176
|
self.uiSetupReadySignal.connect(self.uiSetupReady)
|
|
143
|
-
self.clientXModeCheckbox.toggled.connect(self.changeXmode)
|
|
144
177
|
self.isInCrazyFlightmode = False
|
|
178
|
+
|
|
179
|
+
# Command Based Flight Control
|
|
180
|
+
self._can_fly_deprecated = 0
|
|
181
|
+
self.commanderTakeOffButton.clicked.connect(lambda: self._flight_command(CommanderAction.TAKE_OFF))
|
|
182
|
+
self.commanderLandButton.clicked.connect(lambda: self._flight_command(CommanderAction.LAND))
|
|
183
|
+
self.commanderLeftButton.clicked.connect(lambda: self._flight_command(CommanderAction.LEFT))
|
|
184
|
+
self.commanderRightButton.clicked.connect(lambda: self._flight_command(CommanderAction.RIGHT))
|
|
185
|
+
self.commanderForwardButton.clicked.connect(lambda: self._flight_command(CommanderAction.FORWARD))
|
|
186
|
+
self.commanderBackButton.clicked.connect(lambda: self._flight_command(CommanderAction.BACK))
|
|
187
|
+
self.commanderUpButton.clicked.connect(lambda: self._flight_command(CommanderAction.UP))
|
|
188
|
+
self.commanderDownButton.clicked.connect(lambda: self._flight_command(CommanderAction.DOWN))
|
|
189
|
+
self._update_flight_commander(False)
|
|
190
|
+
|
|
191
|
+
# Supervisor
|
|
192
|
+
self._supervisor_info_bitfield = 0
|
|
193
|
+
self.armButton.clicked.connect(self.updateArm)
|
|
194
|
+
self._update_supervisor_and_arming(False)
|
|
195
|
+
|
|
145
196
|
self.uiSetupReady()
|
|
146
197
|
|
|
147
|
-
self.
|
|
148
|
-
|
|
149
|
-
self.
|
|
150
|
-
|
|
151
|
-
self.helper.cf.param.set_value("flightmode.x",
|
|
152
|
-
str(enabled)))
|
|
153
|
-
self.helper.cf.param.add_update_callback(
|
|
154
|
-
group="flightmode", name="xmode",
|
|
155
|
-
cb=(lambda name, checked:
|
|
156
|
-
self.crazyflieXModeCheckbox.setChecked(eval(checked))))
|
|
157
|
-
|
|
158
|
-
self.ratePidRadioButton.clicked.connect(
|
|
159
|
-
lambda enabled:
|
|
160
|
-
self.helper.cf.param.set_value("flightmode.ratepid",
|
|
161
|
-
str(enabled)))
|
|
162
|
-
|
|
163
|
-
self.angularPidRadioButton.clicked.connect(
|
|
164
|
-
lambda enabled:
|
|
165
|
-
self.helper.cf.param.set_value("flightmode.ratepid",
|
|
166
|
-
str(not enabled)))
|
|
167
|
-
|
|
168
|
-
self._led_ring_headlight.clicked.connect(
|
|
169
|
-
lambda enabled:
|
|
170
|
-
self.helper.cf.param.set_value("ring.headlightEnable",
|
|
171
|
-
str(enabled)))
|
|
172
|
-
|
|
173
|
-
self.helper.cf.param.add_update_callback(
|
|
174
|
-
group="flightmode", name="ratepid",
|
|
175
|
-
cb=(lambda name, checked:
|
|
176
|
-
self.ratePidRadioButton.setChecked(eval(checked))))
|
|
177
|
-
|
|
178
|
-
self.helper.cf.param.add_update_callback(
|
|
179
|
-
group="cpu", name="flash",
|
|
180
|
-
cb=self._set_enable_client_xmode)
|
|
181
|
-
|
|
182
|
-
self.helper.cf.param.add_update_callback(
|
|
183
|
-
group="ring", name="headlightEnable",
|
|
184
|
-
cb=(lambda name, checked:
|
|
185
|
-
self._led_ring_headlight.setChecked(eval(checked))))
|
|
186
|
-
|
|
187
|
-
self._ledring_nbr_effects = 0
|
|
188
|
-
|
|
189
|
-
self.helper.cf.param.add_update_callback(
|
|
190
|
-
group="ring",
|
|
191
|
-
name="effect",
|
|
192
|
-
cb=self._ring_effect_updated)
|
|
193
|
-
|
|
194
|
-
self.helper.cf.param.add_update_callback(
|
|
195
|
-
group="imu_sensors",
|
|
196
|
-
cb=self._set_available_sensors)
|
|
197
|
-
|
|
198
|
-
self.helper.cf.param.all_updated.add_callback(
|
|
199
|
-
self._ring_populate_dropdown)
|
|
200
|
-
|
|
201
|
-
self.logBaro = None
|
|
198
|
+
self._helper.cf.param.add_update_callback(group="imu_sensors", cb=self._set_available_sensors)
|
|
199
|
+
|
|
200
|
+
self._helper.cf.param.all_updated.add_callback(self._all_params_updated)
|
|
201
|
+
|
|
202
202
|
self.logAltHold = None
|
|
203
203
|
|
|
204
204
|
self.ai = AttitudeIndicator()
|
|
@@ -208,43 +208,32 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
208
208
|
self.targetCalPitch.setValue(Config().get("trim_pitch"))
|
|
209
209
|
self.targetCalRoll.setValue(Config().get("trim_roll"))
|
|
210
210
|
|
|
211
|
-
self.helper.inputDeviceReader.alt1_updated.add_callback(
|
|
212
|
-
self.alt1_updated)
|
|
213
|
-
self.helper.inputDeviceReader.alt2_updated.add_callback(
|
|
214
|
-
self.alt2_updated)
|
|
215
211
|
self._tf_state = 0
|
|
216
|
-
self._ring_effect = 0
|
|
217
212
|
|
|
218
|
-
# Connect callbacks for input device limiting of
|
|
219
|
-
self.
|
|
220
|
-
self._limiting_updated.emit)
|
|
213
|
+
# Connect callbacks for input device limiting of roll/pitch/yaw/thrust
|
|
214
|
+
self._helper.inputDeviceReader.limiting_updated.add_callback(self._limiting_updated.emit)
|
|
221
215
|
self._limiting_updated.connect(self._set_limiting_enabled)
|
|
222
216
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
else:
|
|
227
|
-
self.clientXModeCheckbox.setEnabled(False)
|
|
228
|
-
self.clientXModeCheckbox.setChecked(False)
|
|
217
|
+
self._helper.pose_logger.data_received_cb.add_callback(self._pose_data_signal.emit)
|
|
218
|
+
|
|
219
|
+
def _set_limiting_enabled(self, rp_limiting_enabled, yaw_limiting_enabled, thrust_limiting_enabled):
|
|
229
220
|
|
|
230
|
-
def _set_limiting_enabled(self, rp_limiting_enabled,
|
|
231
|
-
yaw_limiting_enabled,
|
|
232
|
-
thrust_limiting_enabled):
|
|
233
|
-
self.maxAngle.setEnabled(rp_limiting_enabled)
|
|
234
221
|
self.targetCalRoll.setEnabled(rp_limiting_enabled)
|
|
235
222
|
self.targetCalPitch.setEnabled(rp_limiting_enabled)
|
|
236
|
-
|
|
237
|
-
self.
|
|
238
|
-
self.
|
|
239
|
-
self.
|
|
240
|
-
self.
|
|
223
|
+
|
|
224
|
+
advanced_is_enabled = self.isInCrazyFlightmode
|
|
225
|
+
self.maxAngle.setEnabled(rp_limiting_enabled and advanced_is_enabled)
|
|
226
|
+
self.maxYawRate.setEnabled(yaw_limiting_enabled and advanced_is_enabled)
|
|
227
|
+
self.maxThrust.setEnabled(thrust_limiting_enabled and advanced_is_enabled)
|
|
228
|
+
self.minThrust.setEnabled(thrust_limiting_enabled and advanced_is_enabled)
|
|
229
|
+
self.slewEnableLimit.setEnabled(thrust_limiting_enabled and advanced_is_enabled)
|
|
230
|
+
self.thrustLoweringSlewRateLimit.setEnabled(thrust_limiting_enabled and advanced_is_enabled)
|
|
241
231
|
|
|
242
232
|
def thrustToPercentage(self, thrust):
|
|
243
233
|
return ((thrust / MAX_THRUST) * 100.0)
|
|
244
234
|
|
|
245
235
|
def uiSetupReady(self):
|
|
246
|
-
flightComboIndex = self.flightModeCombo.findText(
|
|
247
|
-
Config().get("flightmode"), Qt.MatchFixedString)
|
|
236
|
+
flightComboIndex = self.flightModeCombo.findText(Config().get("flightmode"), Qt.MatchFlag.MatchFixedString)
|
|
248
237
|
if (flightComboIndex < 0):
|
|
249
238
|
self.flightModeCombo.setCurrentIndex(0)
|
|
250
239
|
self.flightModeCombo.currentIndexChanged.emit(0)
|
|
@@ -252,86 +241,225 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
252
241
|
self.flightModeCombo.setCurrentIndex(flightComboIndex)
|
|
253
242
|
self.flightModeCombo.currentIndexChanged.emit(flightComboIndex)
|
|
254
243
|
|
|
244
|
+
def _flight_command(self, action):
|
|
245
|
+
current_z = self._helper.pose_logger.position[2]
|
|
246
|
+
move_dist = 0.5
|
|
247
|
+
move_vel = 0.5
|
|
248
|
+
|
|
249
|
+
if action == CommanderAction.TAKE_OFF:
|
|
250
|
+
self._helper.cf.param.set_value('commander.enHighLevel', '1')
|
|
251
|
+
z_target = current_z + move_dist
|
|
252
|
+
self._helper.cf.high_level_commander.takeoff(z_target, move_dist / move_vel)
|
|
253
|
+
elif action == CommanderAction.LAND:
|
|
254
|
+
self._helper.cf.high_level_commander.land(0, current_z / move_vel)
|
|
255
|
+
elif action == CommanderAction.LEFT:
|
|
256
|
+
self._helper.cf.high_level_commander.go_to(0, move_dist, 0, 0, move_dist / move_vel, relative=True)
|
|
257
|
+
elif action == CommanderAction.RIGHT:
|
|
258
|
+
self._helper.cf.high_level_commander.go_to(0, -move_dist, 0, 0, move_dist / move_vel, relative=True)
|
|
259
|
+
elif action == CommanderAction.FORWARD:
|
|
260
|
+
self._helper.cf.high_level_commander.go_to(move_dist, 0, 0, 0, move_dist / move_vel, relative=True)
|
|
261
|
+
elif action == CommanderAction.BACK:
|
|
262
|
+
self._helper.cf.high_level_commander.go_to(-move_dist, 0, 0, 0, move_dist / move_vel, relative=True)
|
|
263
|
+
elif action == CommanderAction.UP:
|
|
264
|
+
self._helper.cf.high_level_commander.go_to(0, 0, move_dist, 0, move_dist / move_vel, relative=True)
|
|
265
|
+
elif action == CommanderAction.DOWN:
|
|
266
|
+
self._helper.cf.high_level_commander.go_to(0, 0, -move_dist, 0, move_dist / move_vel, relative=True)
|
|
267
|
+
|
|
255
268
|
def _logging_error(self, log_conf, msg):
|
|
256
269
|
QMessageBox.about(self, "Log error",
|
|
257
270
|
"Error when starting log config [%s]: %s" % (
|
|
258
271
|
log_conf.name, msg))
|
|
259
272
|
|
|
260
|
-
def
|
|
261
|
-
if self.isVisible():
|
|
262
|
-
self.actualM1.setValue(data[
|
|
263
|
-
self.actualM2.setValue(data[
|
|
264
|
-
self.actualM3.setValue(data[
|
|
265
|
-
self.actualM4.setValue(data[
|
|
273
|
+
def _log_data_received(self, timestamp, data, logconf):
|
|
274
|
+
if self.isVisible() and self._isConnected:
|
|
275
|
+
self.actualM1.setValue(data[self.LOG_NAME_MOTOR_1])
|
|
276
|
+
self.actualM2.setValue(data[self.LOG_NAME_MOTOR_2])
|
|
277
|
+
self.actualM3.setValue(data[self.LOG_NAME_MOTOR_3])
|
|
278
|
+
self.actualM4.setValue(data[self.LOG_NAME_MOTOR_4])
|
|
266
279
|
|
|
267
|
-
|
|
280
|
+
self.estimateThrust.setText(
|
|
281
|
+
"%.2f%%" % self.thrustToPercentage(data[self.LOG_NAME_THRUST]))
|
|
282
|
+
|
|
283
|
+
if data[self.LOG_NAME_CAN_FLY] != self._can_fly_deprecated:
|
|
284
|
+
self._can_fly_deprecated = data[self.LOG_NAME_CAN_FLY]
|
|
285
|
+
self._update_flight_commander(True)
|
|
286
|
+
|
|
287
|
+
if self.LOG_NAME_SUPERVISOR_INFO in data:
|
|
288
|
+
self._supervisor_info_bitfield = data[self.LOG_NAME_SUPERVISOR_INFO]
|
|
289
|
+
|
|
290
|
+
self._update_supervisor_and_arming(True)
|
|
291
|
+
|
|
292
|
+
def _pose_data_received(self, pose_logger, pose):
|
|
268
293
|
if self.isVisible():
|
|
269
|
-
estimated_z =
|
|
270
|
-
|
|
294
|
+
estimated_z = pose[2]
|
|
295
|
+
roll = pose[3]
|
|
296
|
+
pitch = pose[4]
|
|
297
|
+
|
|
298
|
+
self.estimateX.setText(("%.2f" % pose[0]))
|
|
299
|
+
self.estimateY.setText(("%.2f" % pose[1]))
|
|
300
|
+
self.estimateZ.setText(("%.2f" % estimated_z))
|
|
301
|
+
self.estimateRoll.setText(("%.2f" % roll))
|
|
302
|
+
self.estimatePitch.setText(("%.2f" % pitch))
|
|
303
|
+
self.estimateYaw.setText(("%.2f" % pose[5]))
|
|
304
|
+
|
|
271
305
|
self.ai.setBaro(estimated_z, self.is_visible())
|
|
306
|
+
self.ai.setRollPitch(-roll, pitch, self.is_visible())
|
|
272
307
|
|
|
273
308
|
def _heighthold_input_updated(self, roll, pitch, yaw, height):
|
|
274
309
|
if (self.isVisible() and
|
|
275
|
-
self.
|
|
276
|
-
|
|
277
|
-
|
|
310
|
+
(self._helper.inputDeviceReader.get_assisted_control() ==
|
|
311
|
+
self._helper.inputDeviceReader.ASSISTED_CONTROL_HEIGHTHOLD)):
|
|
312
|
+
|
|
313
|
+
self.targetRoll.setText(("%0.2f deg" % roll))
|
|
314
|
+
self.targetPitch.setText(("%0.2f deg" % pitch))
|
|
315
|
+
self.targetYaw.setText(("%0.2f deg/s" % yaw))
|
|
316
|
+
self.targetHeight.setText(("%.2f m" % height))
|
|
278
317
|
self.ai.setHover(height, self.is_visible())
|
|
279
318
|
|
|
280
|
-
|
|
319
|
+
self._change_input_labels(using_hover_assist=False)
|
|
320
|
+
|
|
321
|
+
def _hover_input_updated(self, vx, vy, yaw, height):
|
|
281
322
|
if (self.isVisible() and
|
|
282
|
-
self.
|
|
283
|
-
|
|
284
|
-
target = data[PARAM_NAME_ALT_HOLD_TARGET]
|
|
285
|
-
if target > 0:
|
|
286
|
-
if not self.targetHeight.isEnabled():
|
|
287
|
-
self.targetHeight.setEnabled(True)
|
|
288
|
-
self.targetHeight.setText(("%.2f" % target))
|
|
289
|
-
self.ai.setHover(target, self.is_visible())
|
|
290
|
-
elif self.targetHeight.isEnabled():
|
|
291
|
-
self.targetHeight.setEnabled(False)
|
|
292
|
-
self.targetHeight.setText("Not set")
|
|
293
|
-
self.ai.setHover(0, self.is_visible())
|
|
294
|
-
|
|
295
|
-
def _imu_data_received(self, timestamp, data, logconf):
|
|
296
|
-
if self.isVisible():
|
|
297
|
-
self.actualRoll.setText(("%.2f" % data["stabilizer.roll"]))
|
|
298
|
-
self.actualPitch.setText(("%.2f" % data["stabilizer.pitch"]))
|
|
299
|
-
self.actualYaw.setText(("%.2f" % data["stabilizer.yaw"]))
|
|
300
|
-
self.actualThrust.setText("%.2f%%" %
|
|
301
|
-
self.thrustToPercentage(
|
|
302
|
-
data["stabilizer.thrust"]))
|
|
323
|
+
(self._helper.inputDeviceReader.get_assisted_control() ==
|
|
324
|
+
self._helper.inputDeviceReader.ASSISTED_CONTROL_HOVER)):
|
|
303
325
|
|
|
304
|
-
self.
|
|
305
|
-
|
|
326
|
+
self.targetRoll.setText(("%0.2f m/s" % vy))
|
|
327
|
+
self.targetPitch.setText(("%0.2f m/s" % vx))
|
|
328
|
+
self.targetYaw.setText(("%0.2f deg/s" % yaw))
|
|
329
|
+
self.targetHeight.setText(("%.2f m" % height))
|
|
330
|
+
self.ai.setHover(height, self.is_visible())
|
|
306
331
|
|
|
307
|
-
|
|
308
|
-
# IMU & THRUST
|
|
309
|
-
lg = LogConfig("Stabilizer", Config().get("ui_update_period"))
|
|
310
|
-
lg.add_variable("stabilizer.roll", "float")
|
|
311
|
-
lg.add_variable("stabilizer.pitch", "float")
|
|
312
|
-
lg.add_variable("stabilizer.yaw", "float")
|
|
313
|
-
lg.add_variable("stabilizer.thrust", "uint16_t")
|
|
332
|
+
self._change_input_labels(using_hover_assist=True)
|
|
314
333
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
334
|
+
def _change_input_labels(self, using_hover_assist):
|
|
335
|
+
if using_hover_assist:
|
|
336
|
+
pitch, roll, yaw = 'Velocity X', 'Velocity Y', 'Velocity Z'
|
|
337
|
+
else:
|
|
338
|
+
pitch, roll, yaw = 'Pitch', 'Roll', 'Yaw'
|
|
339
|
+
|
|
340
|
+
self.inputPitchLabel.setText(pitch)
|
|
341
|
+
self.inputRollLabel.setText(roll)
|
|
342
|
+
self.inputYawLabel.setText(yaw)
|
|
343
|
+
|
|
344
|
+
def _update_supervisor_and_arming(self, connected):
|
|
345
|
+
if not connected:
|
|
346
|
+
self.armButton.setStyleSheet("")
|
|
347
|
+
self.armButton.setText("Arm")
|
|
348
|
+
self.armButton.setEnabled(False)
|
|
349
|
+
self._supervisor_state.setText("")
|
|
350
|
+
self._supervisor_state.setStyleSheet("")
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
self._supervisor_state.setText("")
|
|
354
|
+
if self._is_tumbled():
|
|
355
|
+
self._supervisor_state.setText("Tumbled")
|
|
324
356
|
|
|
325
|
-
|
|
357
|
+
if self._is_locked():
|
|
358
|
+
self.armButton.setText("")
|
|
359
|
+
self.armButton.setEnabled(False)
|
|
360
|
+
self.armButton.setStyleSheet("")
|
|
361
|
+
self._supervisor_state.setText("Locked-please reboot")
|
|
362
|
+
self._supervisor_state.setStyleSheet("background-color: red")
|
|
363
|
+
return
|
|
364
|
+
else:
|
|
365
|
+
self._supervisor_state.setStyleSheet("")
|
|
366
|
+
|
|
367
|
+
if self._is_crashed():
|
|
368
|
+
self.armButton.setText("Recover")
|
|
369
|
+
if self._is_tumbled():
|
|
370
|
+
self.armButton.setEnabled(False)
|
|
371
|
+
self.armButton.setStyleSheet("")
|
|
372
|
+
self._supervisor_state.setText("Crashed, flip over to recover")
|
|
373
|
+
else:
|
|
374
|
+
self.armButton.setEnabled(True)
|
|
375
|
+
self.armButton.setStyleSheet("background-color: red")
|
|
376
|
+
self._supervisor_state.setText("Crashed, click Recover")
|
|
377
|
+
|
|
378
|
+
self._supervisor_state.setStyleSheet("background-color: red")
|
|
379
|
+
return
|
|
380
|
+
|
|
381
|
+
if self._is_flying():
|
|
382
|
+
self.armButton.setEnabled(True)
|
|
383
|
+
self.armButton.setText("Emergency stop")
|
|
384
|
+
self.armButton.setStyleSheet("background-color: red")
|
|
385
|
+
self._supervisor_state.setText("Flying")
|
|
386
|
+
return
|
|
387
|
+
|
|
388
|
+
if self._is_armed():
|
|
389
|
+
self.armButton.setStyleSheet("background-color: red")
|
|
390
|
+
if self._auto_arming():
|
|
391
|
+
self.armButton.setEnabled(False)
|
|
392
|
+
self.armButton.setText("Auto armed")
|
|
393
|
+
else:
|
|
394
|
+
self.armButton.setEnabled(True)
|
|
395
|
+
self.armButton.setText("Disarm")
|
|
396
|
+
else:
|
|
397
|
+
self.armButton.setText("Arm")
|
|
398
|
+
if self._can_arm():
|
|
399
|
+
self.armButton.setEnabled(True)
|
|
400
|
+
self.armButton.setStyleSheet("background-color: lightgreen")
|
|
401
|
+
else:
|
|
402
|
+
self.armButton.setStyleSheet("")
|
|
403
|
+
self.armButton.setEnabled(False)
|
|
404
|
+
|
|
405
|
+
def _update_flight_commander(self, connected):
|
|
406
|
+
self.commanderBox.setToolTip(str())
|
|
407
|
+
if not connected:
|
|
408
|
+
self.commanderBox.setEnabled(False)
|
|
409
|
+
return
|
|
410
|
+
|
|
411
|
+
if self._can_fly_deprecated == 0:
|
|
412
|
+
self.commanderBox.setEnabled(False)
|
|
413
|
+
self.commanderBox.setToolTip('The Crazyflie reports that flight is not possible')
|
|
414
|
+
return
|
|
415
|
+
|
|
416
|
+
# We cannot know if we have a positioning deck until we get params
|
|
417
|
+
if not self._helper.cf.param.is_updated:
|
|
418
|
+
self.commanderBox.setEnabled(False)
|
|
419
|
+
return
|
|
420
|
+
|
|
421
|
+
# flowV1 flowV2 LightHouse LPS
|
|
422
|
+
position_decks = ['bcFlow', 'bcFlow2', 'bcLighthouse4', 'bcLoco', 'bcDWM1000']
|
|
423
|
+
for deck in position_decks:
|
|
424
|
+
if int(self._helper.cf.param.values['deck'][deck]) == 1:
|
|
425
|
+
self.commanderBox.setEnabled(True)
|
|
426
|
+
break
|
|
427
|
+
else:
|
|
428
|
+
self.commanderBox.setToolTip('You need a positioning deck to use Command Based Flight')
|
|
429
|
+
self.commanderBox.setEnabled(False)
|
|
430
|
+
return
|
|
431
|
+
|
|
432
|
+
# To prevent conflicting commands from the controller and the flight panel
|
|
433
|
+
if JoystickReader().available_devices():
|
|
434
|
+
self.commanderBox.setToolTip(
|
|
435
|
+
'Cannot use both a controller and Command Based Flight'
|
|
436
|
+
)
|
|
437
|
+
self.commanderBox.setEnabled(False)
|
|
438
|
+
return
|
|
439
|
+
|
|
440
|
+
def connected(self, linkURI):
|
|
441
|
+
self._isConnected = True
|
|
442
|
+
# MOTOR & THRUST
|
|
326
443
|
lg = LogConfig("Motors", Config().get("ui_update_period"))
|
|
327
|
-
lg.add_variable(
|
|
328
|
-
lg.add_variable(
|
|
329
|
-
lg.add_variable(
|
|
330
|
-
lg.add_variable(
|
|
444
|
+
lg.add_variable(self.LOG_NAME_THRUST, "uint16_t")
|
|
445
|
+
lg.add_variable(self.LOG_NAME_MOTOR_1)
|
|
446
|
+
lg.add_variable(self.LOG_NAME_MOTOR_2)
|
|
447
|
+
lg.add_variable(self.LOG_NAME_MOTOR_3)
|
|
448
|
+
lg.add_variable(self.LOG_NAME_MOTOR_4)
|
|
449
|
+
lg.add_variable(self.LOG_NAME_CAN_FLY)
|
|
450
|
+
|
|
451
|
+
# Add supervisor info if it exists to keep backwards compatibility
|
|
452
|
+
if self._helper.cf.log.toc.get_element_by_complete_name(self.LOG_NAME_SUPERVISOR_INFO):
|
|
453
|
+
lg.add_variable(self.LOG_NAME_SUPERVISOR_INFO)
|
|
454
|
+
# Full supervisor info available after V7, hide supervisor info for earlier versions
|
|
455
|
+
update_supervisor_info = self._helper.cf.platform.get_protocol_version() >= 7
|
|
456
|
+
self._supervisor_state.setVisible(update_supervisor_info)
|
|
457
|
+
self._supervisor_label1.setVisible(update_supervisor_info)
|
|
458
|
+
self._supervisor_label2.setVisible(update_supervisor_info)
|
|
331
459
|
|
|
332
460
|
try:
|
|
333
|
-
self.
|
|
334
|
-
lg.data_received_cb.add_callback(self.
|
|
461
|
+
self._helper.cf.log.add_config(lg)
|
|
462
|
+
lg.data_received_cb.add_callback(self._log_data_signal.emit)
|
|
335
463
|
lg.error_cb.add_callback(self._log_error_signal.emit)
|
|
336
464
|
lg.start()
|
|
337
465
|
except KeyError as e:
|
|
@@ -339,78 +467,41 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
339
467
|
except AttributeError as e:
|
|
340
468
|
logger.warning(str(e))
|
|
341
469
|
|
|
342
|
-
|
|
470
|
+
def _enable_estimators(self, should_enable):
|
|
471
|
+
self.estimateX.setEnabled(should_enable)
|
|
472
|
+
self.estimateY.setEnabled(should_enable)
|
|
473
|
+
self.estimateZ.setEnabled(should_enable)
|
|
343
474
|
|
|
344
475
|
def _set_available_sensors(self, name, available):
|
|
345
|
-
logger.
|
|
476
|
+
logger.debug("[%s]: %s", name, available)
|
|
346
477
|
available = eval(available)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
self.actualHeight.setEnabled(False)
|
|
351
|
-
else:
|
|
352
|
-
self.actualHeight.setEnabled(True)
|
|
353
|
-
self.helper.inputDeviceReader.set_alt_hold_available(available)
|
|
354
|
-
if (not self.logBaro and not self.logAltHold):
|
|
355
|
-
# The sensor is available, set up the logging
|
|
356
|
-
self.logBaro = LogConfig("Baro", 200)
|
|
357
|
-
self.logBaro.add_variable(LOG_NAME_ESTIMATED_Z, "float")
|
|
358
|
-
|
|
359
|
-
try:
|
|
360
|
-
self.helper.cf.log.add_config(self.logBaro)
|
|
361
|
-
self.logBaro.data_received_cb.add_callback(
|
|
362
|
-
self._baro_data_signal.emit)
|
|
363
|
-
self.logBaro.error_cb.add_callback(
|
|
364
|
-
self._log_error_signal.emit)
|
|
365
|
-
self.logBaro.start()
|
|
366
|
-
except KeyError as e:
|
|
367
|
-
logger.warning(str(e))
|
|
368
|
-
except AttributeError as e:
|
|
369
|
-
logger.warning(str(e))
|
|
370
|
-
self.logAltHold = LogConfig("AltHold", 200)
|
|
371
|
-
self.logAltHold.add_variable(PARAM_NAME_ALT_HOLD_TARGET,
|
|
372
|
-
"float")
|
|
373
|
-
|
|
374
|
-
try:
|
|
375
|
-
self.helper.cf.log.add_config(self.logAltHold)
|
|
376
|
-
self.logAltHold.data_received_cb.add_callback(
|
|
377
|
-
self._althold_data_signal.emit)
|
|
378
|
-
self.logAltHold.error_cb.add_callback(
|
|
379
|
-
self._log_error_signal.emit)
|
|
380
|
-
self.logAltHold.start()
|
|
381
|
-
except KeyError as e:
|
|
382
|
-
logger.warning(str(e))
|
|
383
|
-
except AttributeError as e:
|
|
384
|
-
logger.warning(str(e))
|
|
478
|
+
|
|
479
|
+
self._enable_estimators(True)
|
|
480
|
+
self._helper.inputDeviceReader.set_alt_hold_available(available)
|
|
385
481
|
|
|
386
482
|
def disconnected(self, linkURI):
|
|
483
|
+
self._isConnected = False
|
|
387
484
|
self.ai.setRollPitch(0, 0)
|
|
388
485
|
self.actualM1.setValue(0)
|
|
389
486
|
self.actualM2.setValue(0)
|
|
390
487
|
self.actualM3.setValue(0)
|
|
391
488
|
self.actualM4.setValue(0)
|
|
392
|
-
|
|
393
|
-
self.
|
|
394
|
-
self.
|
|
395
|
-
self.
|
|
396
|
-
self.
|
|
489
|
+
|
|
490
|
+
self.estimateRoll.setText("")
|
|
491
|
+
self.estimatePitch.setText("")
|
|
492
|
+
self.estimateYaw.setText("")
|
|
493
|
+
self.estimateThrust.setText("")
|
|
494
|
+
self.estimateX.setText("")
|
|
495
|
+
self.estimateY.setText("")
|
|
496
|
+
self.estimateZ.setText("")
|
|
497
|
+
|
|
397
498
|
self.targetHeight.setText("Not Set")
|
|
398
499
|
self.ai.setHover(0, self.is_visible())
|
|
399
500
|
self.targetHeight.setEnabled(False)
|
|
400
|
-
|
|
401
|
-
self.
|
|
402
|
-
|
|
501
|
+
|
|
502
|
+
self._enable_estimators(False)
|
|
503
|
+
|
|
403
504
|
self.logAltHold = None
|
|
404
|
-
self._led_ring_effect.setEnabled(False)
|
|
405
|
-
self._led_ring_effect.clear()
|
|
406
|
-
try:
|
|
407
|
-
self._led_ring_effect.currentIndexChanged.disconnect(
|
|
408
|
-
self._ring_effect_changed)
|
|
409
|
-
except TypeError:
|
|
410
|
-
# Signal was not connected
|
|
411
|
-
pass
|
|
412
|
-
self._led_ring_effect.setCurrentIndex(-1)
|
|
413
|
-
self._led_ring_headlight.setEnabled(False)
|
|
414
505
|
|
|
415
506
|
try:
|
|
416
507
|
self._assist_mode_combo.currentIndexChanged.disconnect(
|
|
@@ -421,17 +512,46 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
421
512
|
self._assist_mode_combo.setEnabled(False)
|
|
422
513
|
self._assist_mode_combo.clear()
|
|
423
514
|
|
|
515
|
+
self._update_flight_commander(False)
|
|
516
|
+
|
|
517
|
+
self._supervisor_info_bitfield = 0
|
|
518
|
+
self._update_supervisor_and_arming(False)
|
|
519
|
+
|
|
520
|
+
def _can_arm(self):
|
|
521
|
+
return bool(self._supervisor_info_bitfield & 0x0001)
|
|
522
|
+
|
|
523
|
+
def _is_armed(self):
|
|
524
|
+
return bool(self._supervisor_info_bitfield & 0x0002)
|
|
525
|
+
|
|
526
|
+
def _auto_arming(self):
|
|
527
|
+
return bool(self._supervisor_info_bitfield & 0x0004)
|
|
528
|
+
|
|
529
|
+
def _can_fly(self):
|
|
530
|
+
return bool(self._supervisor_info_bitfield & 0x0008)
|
|
531
|
+
|
|
532
|
+
def _is_flying(self):
|
|
533
|
+
return bool(self._supervisor_info_bitfield & 0x0010)
|
|
534
|
+
|
|
535
|
+
def _is_tumbled(self):
|
|
536
|
+
return bool(self._supervisor_info_bitfield & 0x0020)
|
|
537
|
+
|
|
538
|
+
def _is_locked(self):
|
|
539
|
+
return bool(self._supervisor_info_bitfield & 0x0040)
|
|
540
|
+
|
|
541
|
+
def _is_crashed(self):
|
|
542
|
+
return bool(self._supervisor_info_bitfield & 0x0080)
|
|
543
|
+
|
|
424
544
|
def minMaxThrustChanged(self):
|
|
425
|
-
self.
|
|
426
|
-
self.
|
|
545
|
+
self._helper.inputDeviceReader.min_thrust = self.minThrust.value()
|
|
546
|
+
self._helper.inputDeviceReader.max_thrust = self.maxThrust.value()
|
|
427
547
|
if (self.isInCrazyFlightmode is True):
|
|
428
548
|
Config().set("min_thrust", self.minThrust.value())
|
|
429
549
|
Config().set("max_thrust", self.maxThrust.value())
|
|
430
550
|
|
|
431
551
|
def thrustLoweringSlewRateLimitChanged(self):
|
|
432
|
-
self.
|
|
552
|
+
self._helper.inputDeviceReader.thrust_slew_rate = (
|
|
433
553
|
self.thrustLoweringSlewRateLimit.value())
|
|
434
|
-
self.
|
|
554
|
+
self._helper.inputDeviceReader.thrust_slew_limit = (
|
|
435
555
|
self.slewEnableLimit.value())
|
|
436
556
|
if (self.isInCrazyFlightmode is True):
|
|
437
557
|
Config().set("slew_limit", self.slewEnableLimit.value())
|
|
@@ -439,24 +559,24 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
439
559
|
|
|
440
560
|
def maxYawRateChanged(self):
|
|
441
561
|
logger.debug("MaxYawrate changed to %d", self.maxYawRate.value())
|
|
442
|
-
self.
|
|
562
|
+
self._helper.inputDeviceReader.max_yaw_rate = self.maxYawRate.value()
|
|
443
563
|
if (self.isInCrazyFlightmode is True):
|
|
444
564
|
Config().set("max_yaw", self.maxYawRate.value())
|
|
445
565
|
|
|
446
566
|
def maxAngleChanged(self):
|
|
447
567
|
logger.debug("MaxAngle changed to %d", self.maxAngle.value())
|
|
448
|
-
self.
|
|
568
|
+
self._helper.inputDeviceReader.max_rp_angle = self.maxAngle.value()
|
|
449
569
|
if (self.isInCrazyFlightmode is True):
|
|
450
570
|
Config().set("max_rp", self.maxAngle.value())
|
|
451
571
|
|
|
452
572
|
def _trim_pitch_changed(self, value):
|
|
453
573
|
logger.debug("Pitch trim updated to [%f]" % value)
|
|
454
|
-
self.
|
|
574
|
+
self._helper.inputDeviceReader.trim_pitch = value
|
|
455
575
|
Config().set("trim_pitch", value)
|
|
456
576
|
|
|
457
577
|
def _trim_roll_changed(self, value):
|
|
458
578
|
logger.debug("Roll trim updated to [%f]" % value)
|
|
459
|
-
self.
|
|
579
|
+
self._helper.inputDeviceReader.trim_roll = value
|
|
460
580
|
Config().set("trim_roll", value)
|
|
461
581
|
|
|
462
582
|
def calUpdateFromInput(self, rollCal, pitchCal):
|
|
@@ -466,12 +586,14 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
466
586
|
self.targetCalPitch.setValue(pitchCal)
|
|
467
587
|
|
|
468
588
|
def updateInputControl(self, roll, pitch, yaw, thrust):
|
|
469
|
-
self.targetRoll.setText(("%0.2f" % roll))
|
|
470
|
-
self.targetPitch.setText(("%0.2f" % pitch))
|
|
471
|
-
self.targetYaw.setText(("%0.2f" % yaw))
|
|
589
|
+
self.targetRoll.setText(("%0.2f deg" % roll))
|
|
590
|
+
self.targetPitch.setText(("%0.2f deg" % pitch))
|
|
591
|
+
self.targetYaw.setText(("%0.2f deg/s" % yaw))
|
|
472
592
|
self.targetThrust.setText(("%0.2f %%" %
|
|
473
593
|
self.thrustToPercentage(thrust)))
|
|
474
|
-
self.thrustProgress.setValue(thrust)
|
|
594
|
+
self.thrustProgress.setValue(int(thrust))
|
|
595
|
+
|
|
596
|
+
self._change_input_labels(using_hover_assist=False)
|
|
475
597
|
|
|
476
598
|
def setMotorLabelsEnabled(self, enabled):
|
|
477
599
|
self.M1label.setEnabled(enabled)
|
|
@@ -487,11 +609,21 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
487
609
|
def updateEmergencyStop(self, emergencyStop):
|
|
488
610
|
if emergencyStop:
|
|
489
611
|
self.setMotorLabelsEnabled(False)
|
|
490
|
-
self.
|
|
491
|
-
|
|
612
|
+
self._helper.cf.loc.send_emergency_stop()
|
|
613
|
+
# TODO krri disarm?
|
|
492
614
|
else:
|
|
493
615
|
self.setMotorLabelsEnabled(True)
|
|
494
|
-
|
|
616
|
+
|
|
617
|
+
def updateArm(self, from_controller=False):
|
|
618
|
+
if self._is_flying() and not from_controller:
|
|
619
|
+
self._helper.cf.loc.send_emergency_stop()
|
|
620
|
+
elif self._is_crashed():
|
|
621
|
+
self._helper.cf.platform.send_crash_recovery_request()
|
|
622
|
+
elif self._is_armed():
|
|
623
|
+
self._helper.cf.platform.send_arming_request(False)
|
|
624
|
+
elif self._can_arm():
|
|
625
|
+
self.armButton.setStyleSheet("background-color: orange")
|
|
626
|
+
self._helper.cf.platform.send_arming_request(True)
|
|
495
627
|
|
|
496
628
|
def flightmodeChange(self, item):
|
|
497
629
|
Config().set("flightmode", str(self.flightModeCombo.itemText(item)))
|
|
@@ -536,111 +668,89 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
536
668
|
mode = JoystickReader.ASSISTED_CONTROL_POSHOLD
|
|
537
669
|
if (item == 2): # Position hold
|
|
538
670
|
mode = JoystickReader.ASSISTED_CONTROL_HEIGHTHOLD
|
|
671
|
+
if (item == 3): # Position hold
|
|
672
|
+
mode = JoystickReader.ASSISTED_CONTROL_HOVER
|
|
539
673
|
|
|
540
|
-
self.
|
|
674
|
+
self._helper.inputDeviceReader.set_assisted_control(mode)
|
|
541
675
|
Config().set("assistedControl", mode)
|
|
542
676
|
|
|
543
677
|
def _assisted_control_updated(self, enabled):
|
|
544
|
-
if self.
|
|
678
|
+
if self._helper.inputDeviceReader.get_assisted_control() == \
|
|
545
679
|
JoystickReader.ASSISTED_CONTROL_POSHOLD:
|
|
546
680
|
self.targetThrust.setEnabled(not enabled)
|
|
547
681
|
self.targetRoll.setEnabled(not enabled)
|
|
548
682
|
self.targetPitch.setEnabled(not enabled)
|
|
549
|
-
elif self.
|
|
550
|
-
JoystickReader.ASSISTED_CONTROL_HEIGHTHOLD
|
|
683
|
+
elif ((self._helper.inputDeviceReader.get_assisted_control() ==
|
|
684
|
+
JoystickReader.ASSISTED_CONTROL_HEIGHTHOLD) or
|
|
685
|
+
(self._helper.inputDeviceReader.get_assisted_control() ==
|
|
686
|
+
JoystickReader.ASSISTED_CONTROL_HOVER)):
|
|
551
687
|
self.targetThrust.setEnabled(not enabled)
|
|
688
|
+
self.targetHeight.setEnabled(enabled)
|
|
689
|
+
print('Chaning enable for target height: %s' % enabled)
|
|
552
690
|
else:
|
|
553
|
-
self.
|
|
554
|
-
|
|
555
|
-
@pyqtSlot(bool)
|
|
556
|
-
def changeXmode(self, checked):
|
|
557
|
-
self.helper.cf.commander.set_client_xmode(checked)
|
|
558
|
-
Config().set("client_side_xmode", checked)
|
|
559
|
-
logger.info("Clientside X-mode enabled: %s", checked)
|
|
691
|
+
self._helper.cf.param.set_value("flightmode.althold", int(enabled))
|
|
560
692
|
|
|
561
|
-
def
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
str(new_index))
|
|
566
|
-
|
|
567
|
-
def alt2_updated(self, state):
|
|
568
|
-
self.helper.cf.param.set_value("ring.headlightEnable", str(state))
|
|
693
|
+
def _all_params_updated(self):
|
|
694
|
+
self._populate_assisted_mode_dropdown()
|
|
695
|
+
self._update_flight_commander(True)
|
|
696
|
+
self._update_supervisor_and_arming(True)
|
|
569
697
|
|
|
570
|
-
def
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
return
|
|
698
|
+
def _populate_assisted_mode_dropdown(self):
|
|
699
|
+
self._assist_mode_combo.addItem("Altitude hold", 0)
|
|
700
|
+
self._assist_mode_combo.addItem("Position hold", 1)
|
|
701
|
+
self._assist_mode_combo.addItem("Height hold", 2)
|
|
702
|
+
self._assist_mode_combo.addItem("Hover", 3)
|
|
576
703
|
|
|
577
|
-
#
|
|
578
|
-
self.
|
|
579
|
-
self.
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
1: "White spinner",
|
|
583
|
-
2: "Color spinner",
|
|
584
|
-
3: "Tilt effect",
|
|
585
|
-
4: "Brightness effect",
|
|
586
|
-
5: "Color spinner 2",
|
|
587
|
-
6: "Double spinner",
|
|
588
|
-
7: "Solid color effect",
|
|
589
|
-
8: "Factory test",
|
|
590
|
-
9: "Battery status",
|
|
591
|
-
10: "Boat lights",
|
|
592
|
-
11: "Alert",
|
|
593
|
-
12: "Gravity",
|
|
594
|
-
13: "LED tab"}
|
|
595
|
-
|
|
596
|
-
for i in range(nbr + 1):
|
|
597
|
-
name = "{}: ".format(i)
|
|
598
|
-
if i in hardcoded_names:
|
|
599
|
-
name += hardcoded_names[i]
|
|
600
|
-
else:
|
|
601
|
-
name += "N/A"
|
|
602
|
-
self._led_ring_effect.addItem(name, i)
|
|
704
|
+
# Add the tooltips to the assist-mode items.
|
|
705
|
+
self._assist_mode_combo.setItemData(0, TOOLTIP_ALTITUDE_HOLD, Qt.ItemDataRole.ToolTipRole)
|
|
706
|
+
self._assist_mode_combo.setItemData(1, TOOLTIP_POSITION_HOLD, Qt.ItemDataRole.ToolTipRole)
|
|
707
|
+
self._assist_mode_combo.setItemData(2, TOOLTIP_HEIGHT_HOLD, Qt.ItemDataRole.ToolTipRole)
|
|
708
|
+
self._assist_mode_combo.setItemData(3, TOOLTIP_HOVER, Qt.ItemDataRole.ToolTipRole)
|
|
603
709
|
|
|
604
|
-
|
|
605
|
-
|
|
710
|
+
heightHoldPossible = False
|
|
711
|
+
hoverPossible = False
|
|
606
712
|
|
|
607
|
-
self.
|
|
608
|
-
|
|
609
|
-
self.
|
|
610
|
-
self._led_ring_headlight.setEnabled(True)
|
|
713
|
+
if int(self._helper.cf.param.values["deck"]["bcZRanger"]) == 1:
|
|
714
|
+
heightHoldPossible = True
|
|
715
|
+
self._helper.inputDeviceReader.set_hover_max_height(1.0)
|
|
611
716
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
i = self._led_ring_effect.itemData(index)
|
|
616
|
-
logger.info("Changed effect to {}".format(i))
|
|
617
|
-
if i != int(self.helper.cf.param.values["ring"]["effect"]):
|
|
618
|
-
self.helper.cf.param.set_value("ring.effect", str(i))
|
|
717
|
+
if int(self._helper.cf.param.values["deck"]["bcZRanger2"]) == 1:
|
|
718
|
+
heightHoldPossible = True
|
|
719
|
+
self._helper.inputDeviceReader.set_hover_max_height(2.0)
|
|
619
720
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
721
|
+
if int(self._helper.cf.param.values["deck"]["bcFlow"]) == 1:
|
|
722
|
+
heightHoldPossible = True
|
|
723
|
+
hoverPossible = True
|
|
724
|
+
self._helper.inputDeviceReader.set_hover_max_height(1.0)
|
|
623
725
|
|
|
624
|
-
|
|
625
|
-
self._assist_mode_combo.addItem("Altitude hold", 0)
|
|
626
|
-
self._assist_mode_combo.addItem("Position hold", 1)
|
|
627
|
-
self._assist_mode_combo.addItem("Height hold", 2)
|
|
628
|
-
heightHoldPossible = False
|
|
629
|
-
if self.helper.cf.mem.ow_search(vid=0xBC, pid=0x09):
|
|
726
|
+
if int(self._helper.cf.param.values["deck"]["bcFlow2"]) == 1:
|
|
630
727
|
heightHoldPossible = True
|
|
728
|
+
hoverPossible = True
|
|
729
|
+
self._helper.inputDeviceReader.set_hover_max_height(2.0)
|
|
631
730
|
|
|
632
731
|
if not heightHoldPossible:
|
|
633
732
|
self._assist_mode_combo.model().item(2).setEnabled(False)
|
|
634
733
|
else:
|
|
635
734
|
self._assist_mode_combo.model().item(0).setEnabled(False)
|
|
636
735
|
|
|
736
|
+
if not hoverPossible:
|
|
737
|
+
self._assist_mode_combo.model().item(3).setEnabled(False)
|
|
738
|
+
else:
|
|
739
|
+
self._assist_mode_combo.model().item(0).setEnabled(False)
|
|
740
|
+
|
|
637
741
|
self._assist_mode_combo.currentIndexChanged.connect(
|
|
638
742
|
self._assist_mode_changed)
|
|
639
743
|
self._assist_mode_combo.setEnabled(True)
|
|
640
744
|
|
|
641
745
|
try:
|
|
642
746
|
assistmodeComboIndex = Config().get("assistedControl")
|
|
643
|
-
if assistmodeComboIndex ==
|
|
747
|
+
if assistmodeComboIndex == 3 and not hoverPossible:
|
|
748
|
+
self._assist_mode_combo.setCurrentIndex(0)
|
|
749
|
+
self._assist_mode_combo.currentIndexChanged.emit(0)
|
|
750
|
+
elif assistmodeComboIndex == 0 and hoverPossible:
|
|
751
|
+
self._assist_mode_combo.setCurrentIndex(3)
|
|
752
|
+
self._assist_mode_combo.currentIndexChanged.emit(3)
|
|
753
|
+
elif assistmodeComboIndex == 2 and not heightHoldPossible:
|
|
644
754
|
self._assist_mode_combo.setCurrentIndex(0)
|
|
645
755
|
self._assist_mode_combo.currentIndexChanged.emit(0)
|
|
646
756
|
elif assistmodeComboIndex == 0 and heightHoldPossible:
|
|
@@ -652,7 +762,9 @@ class FlightTab(Tab, flight_tab_class):
|
|
|
652
762
|
assistmodeComboIndex)
|
|
653
763
|
except KeyError:
|
|
654
764
|
defaultOption = 0
|
|
655
|
-
if
|
|
765
|
+
if hoverPossible:
|
|
766
|
+
defaultOption = 3
|
|
767
|
+
elif heightHoldPossible:
|
|
656
768
|
defaultOption = 2
|
|
657
769
|
self._assist_mode_combo.setCurrentIndex(defaultOption)
|
|
658
770
|
self._assist_mode_combo.currentIndexChanged.emit(defaultOption)
|