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.
Files changed (140) hide show
  1. cfclient/__init__.py +16 -11
  2. cfclient/configs/config.json +4 -3
  3. cfclient/configs/input/Generic_OS_X.json +1 -0
  4. cfclient/configs/input/Joystick.json +1 -0
  5. cfclient/configs/input/PS3_Mode_1.json +1 -0
  6. cfclient/configs/input/PS3_Mode_2.json +1 -0
  7. cfclient/configs/input/PS3_Mode_3.json +1 -0
  8. cfclient/configs/input/PS4_Mode_1.json +1 -0
  9. cfclient/configs/input/PS4_Mode_2.json +1 -0
  10. cfclient/configs/input/PS4_shoulder_btns_yaw.json +1 -0
  11. cfclient/configs/input/xbox360_mode1.json +1 -0
  12. cfclient/configs/log/PID_tuning/Attitude.json +46 -0
  13. cfclient/configs/log/PID_tuning/Attitude_rate.json +46 -0
  14. cfclient/configs/log/PID_tuning/Position.json +46 -0
  15. cfclient/configs/log/PID_tuning/Velocity.json +46 -0
  16. cfclient/configs/log/PID_tuning_components/Pitch.json +22 -0
  17. cfclient/configs/log/PID_tuning_components/Pitch_rate.json +22 -0
  18. cfclient/configs/log/PID_tuning_components/Position_x.json +22 -0
  19. cfclient/configs/log/PID_tuning_components/Position_y.json +22 -0
  20. cfclient/configs/log/PID_tuning_components/Position_z.json +22 -0
  21. cfclient/configs/log/PID_tuning_components/Roll.json +22 -0
  22. cfclient/configs/log/PID_tuning_components/Roll_rate.json +22 -0
  23. cfclient/configs/log/PID_tuning_components/Velocity_x.json +22 -0
  24. cfclient/configs/log/PID_tuning_components/Velocity_y.json +22 -0
  25. cfclient/configs/log/PID_tuning_components/Velocity_z.json +22 -0
  26. cfclient/configs/log/PID_tuning_components/Yaw.json +22 -0
  27. cfclient/configs/log/PID_tuning_components/Yaw_rate.json +22 -0
  28. cfclient/gui.py +44 -9
  29. cfclient/headless.py +3 -12
  30. cfclient/resources/log_param_doc.json +1 -0
  31. cfclient/ui/connectivity_manager.py +198 -0
  32. cfclient/ui/dialogs/about.py +53 -36
  33. cfclient/ui/dialogs/about.ui +23 -3
  34. cfclient/ui/dialogs/anchor_position_dialog.py +252 -0
  35. cfclient/ui/dialogs/anchor_position_dialog.ui +138 -0
  36. cfclient/ui/dialogs/basestation_mode_dialog.py +185 -0
  37. cfclient/ui/dialogs/basestation_mode_dialog.ui +186 -0
  38. cfclient/ui/dialogs/bootloader.py +448 -85
  39. cfclient/ui/dialogs/bootloader.ui +387 -134
  40. cfclient/ui/dialogs/cf2config.py +4 -4
  41. cfclient/ui/dialogs/cf2config.ui +3 -4
  42. cfclient/ui/dialogs/inputconfigdialogue.py +24 -19
  43. cfclient/ui/dialogs/inputconfigdialogue.ui +53 -30
  44. cfclient/ui/dialogs/lighthouse_bs_geometry_dialog.py +220 -0
  45. cfclient/ui/dialogs/lighthouse_bs_geometry_dialog.ui +110 -0
  46. cfclient/ui/dialogs/lighthouse_system_type_dialog.py +93 -0
  47. cfclient/ui/dialogs/lighthouse_system_type_dialog.ui +121 -0
  48. cfclient/ui/dialogs/logconfigdialogue.py +401 -101
  49. cfclient/ui/dialogs/logconfigdialogue.ui +117 -72
  50. cfclient/ui/icons/bl.webp +0 -0
  51. cfclient/ui/icons/bolt.webp +0 -0
  52. cfclient/ui/icons/cf21.webp +0 -0
  53. cfclient/ui/icons/checkmark_black.png +0 -0
  54. cfclient/ui/icons/checkmark_white.png +0 -0
  55. cfclient/ui/icons/create.png +0 -0
  56. cfclient/ui/icons/delete.png +0 -0
  57. cfclient/ui/icons/flapper.webp +0 -0
  58. cfclient/ui/icons/tag.webp +0 -0
  59. cfclient/ui/main.py +328 -258
  60. cfclient/ui/main.ui +184 -80
  61. cfclient/ui/pluginhelper.py +7 -1
  62. cfclient/ui/pose_logger.py +116 -0
  63. cfclient/ui/tab_toolbox.py +208 -0
  64. cfclient/ui/tabs/ColorLEDTab.py +752 -0
  65. cfclient/ui/tabs/ConsoleTab.py +48 -13
  66. cfclient/ui/{toolboxes → tabs}/CrtpSharkToolbox.py +19 -34
  67. cfclient/ui/tabs/ExampleTab.py +9 -16
  68. cfclient/ui/tabs/FlightTab.py +437 -325
  69. cfclient/ui/tabs/GpsTab.py +14 -20
  70. cfclient/ui/tabs/LEDRingTab.py +277 -0
  71. cfclient/ui/tabs/LogBlockDebugTab.py +20 -27
  72. cfclient/ui/tabs/LogBlockTab.py +35 -35
  73. cfclient/ui/tabs/LogClientTab.py +85 -0
  74. cfclient/ui/tabs/LogTab.py +50 -27
  75. cfclient/ui/tabs/ParamTab.py +443 -57
  76. cfclient/ui/tabs/PlotTab.py +23 -25
  77. cfclient/ui/tabs/TuningTab.py +292 -0
  78. cfclient/ui/tabs/__init__.py +12 -2
  79. cfclient/ui/tabs/colorLEDTab.ui +624 -0
  80. cfclient/ui/tabs/consoleTab.ui +46 -0
  81. cfclient/ui/tabs/flightActionContainer.ui +103 -0
  82. cfclient/ui/tabs/flightTab.ui +724 -237
  83. cfclient/ui/tabs/{ledTab.ui → ledRingTab.ui} +63 -46
  84. cfclient/ui/tabs/lighthouse_tab.py +714 -0
  85. cfclient/ui/tabs/lighthouse_tab.ui +430 -0
  86. cfclient/ui/tabs/locopositioning_tab.py +606 -389
  87. cfclient/ui/tabs/locopositioning_tab.ui +370 -253
  88. cfclient/ui/tabs/logClientTab.ui +52 -0
  89. cfclient/ui/tabs/logTab.ui +1 -1
  90. cfclient/ui/tabs/paramTab.ui +204 -3
  91. cfclient/ui/tabs/tuningTab.ui +773 -0
  92. cfclient/ui/widgets/ai.py +37 -39
  93. cfclient/ui/widgets/hexspinbox.py +16 -10
  94. cfclient/ui/widgets/plotter.ui +39 -47
  95. cfclient/ui/widgets/plotwidget.py +57 -22
  96. cfclient/ui/widgets/super_slider.py +112 -0
  97. cfclient/ui/wizards/__init__.py +0 -0
  98. cfclient/ui/wizards/bslh_1.png +0 -0
  99. cfclient/ui/wizards/bslh_2.png +0 -0
  100. cfclient/ui/wizards/bslh_3.png +0 -0
  101. cfclient/ui/wizards/bslh_4.png +0 -0
  102. cfclient/ui/wizards/bslh_5.png +0 -0
  103. cfclient/ui/wizards/lighthouse_geo_bs_estimation_wizard.py +465 -0
  104. cfclient/utils/config_manager.py +5 -4
  105. cfclient/utils/input/__init__.py +77 -19
  106. cfclient/utils/input/inputinterfaces/wiimote.py +2 -2
  107. cfclient/utils/input/inputreaderinterface.py +17 -7
  108. cfclient/utils/input/inputreaders/__init__.py +17 -0
  109. cfclient/utils/logconfigreader.py +245 -25
  110. cfclient/utils/logdatawriter.py +3 -1
  111. cfclient/utils/periodictimer.py +1 -1
  112. cfclient/utils/ui.py +336 -0
  113. cfclient/utils/zmq_led_driver.py +5 -0
  114. cfclient/utils/zmq_param.py +6 -0
  115. cfclient/version.py +34 -1
  116. cfclient-2025.12.1.dist-info/METADATA +70 -0
  117. cfclient-2025.12.1.dist-info/RECORD +152 -0
  118. {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/WHEEL +1 -1
  119. {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/entry_points.txt +0 -1
  120. cfclient-2025.12.1.dist-info/licenses/LICENSE.txt +350 -0
  121. {cfclient-2017.4.dist-info → cfclient-2025.12.1.dist-info}/top_level.txt +1 -0
  122. cfconfig/Makefile +51 -0
  123. cfconfig/configblock.py +111 -0
  124. cfloader/__init__.py +41 -55
  125. cfzmq/__init__.py +22 -14
  126. cfclient/ui/dialogs/cf1config.py +0 -265
  127. cfclient/ui/dialogs/cf1config.ui +0 -260
  128. cfclient/ui/tab.py +0 -96
  129. cfclient/ui/tabs/LEDTab.py +0 -169
  130. cfclient/ui/toolboxes/ConsoleToolbox.py +0 -69
  131. cfclient/ui/toolboxes/DebugDriverToolbox.py +0 -107
  132. cfclient/ui/toolboxes/__init__.py +0 -45
  133. cfclient/ui/toolboxes/consoleToolbox.ui +0 -62
  134. cfclient/ui/toolboxes/debugDriverToolbox.ui +0 -86
  135. cfclient-2017.4.dist-info/DESCRIPTION.rst +0 -3
  136. cfclient-2017.4.dist-info/METADATA +0 -22
  137. cfclient-2017.4.dist-info/RECORD +0 -104
  138. cfclient-2017.4.dist-info/metadata.json +0 -1
  139. /cfclient/{icon-256.png → ui/icons/icon-256.png} +0 -0
  140. /cfclient/ui/{toolboxes → tabs}/crtpSharkToolbox.ui +0 -0
@@ -7,7 +7,7 @@
7
7
  # +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
8
8
  # || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
9
9
  #
10
- # Copyright (C) 2011-2013 Bitcraze AB
10
+ # Copyright (C) 2011-2023 Bitcraze AB
11
11
  #
12
12
  # Crazyflie Nano Quadcopter Client
13
13
  #
@@ -30,14 +30,14 @@ pre-configured.
30
30
 
31
31
  import logging
32
32
 
33
- from cfclient.ui.tab import Tab
33
+ from cfclient.ui.tab_toolbox import TabToolbox
34
34
  from cfclient.ui.widgets.plotwidget import PlotWidget
35
- from PyQt5 import uic
36
- from PyQt5.QtCore import pyqtSignal
37
- from PyQt5.QtCore import QAbstractItemModel
38
- from PyQt5.QtCore import QModelIndex
39
- from PyQt5.QtCore import Qt
40
- from PyQt5.QtWidgets import QMessageBox
35
+ from PyQt6 import uic
36
+ from PyQt6.QtCore import pyqtSignal
37
+ from PyQt6.QtCore import QAbstractItemModel
38
+ from PyQt6.QtCore import QModelIndex
39
+ from PyQt6.QtCore import Qt
40
+ from PyQt6.QtWidgets import QMessageBox
41
41
 
42
42
  import cfclient
43
43
 
@@ -46,8 +46,7 @@ __all__ = ['PlotTab']
46
46
 
47
47
  logger = logging.getLogger(__name__)
48
48
 
49
- plot_tab_class = uic.loadUiType(cfclient.module_path +
50
- "/ui/tabs/plotTab.ui")[0]
49
+ plot_tab_class = uic.loadUiType(cfclient.module_path + "/ui/tabs/plotTab.ui")[0]
51
50
 
52
51
 
53
52
  class LogConfigModel(QAbstractItemModel):
@@ -60,6 +59,7 @@ class LogConfigModel(QAbstractItemModel):
60
59
  def add_block(self, block):
61
60
  self._nodes.append(block)
62
61
  self.layoutChanged.emit()
62
+ self._nodes.sort(key=lambda conf: conf.name.lower())
63
63
 
64
64
  def parent(self, index):
65
65
  """Re-implemented method to get the parent of the given index"""
@@ -67,7 +67,7 @@ class LogConfigModel(QAbstractItemModel):
67
67
 
68
68
  def remove_block(self, block):
69
69
  """Remove a block from the view"""
70
- raise NotImplementedError()
70
+ self._nodes.remove(block)
71
71
 
72
72
  def columnCount(self, parent):
73
73
  """Re-implemented method to get the number of columns"""
@@ -99,7 +99,7 @@ class LogConfigModel(QAbstractItemModel):
99
99
  node = index.internalPointer() # noqa
100
100
  if not index.isValid() or not 0 <= index.row() < len(self._nodes):
101
101
  return None
102
- if role == Qt.DisplayRole:
102
+ if role == Qt.ItemDataRole.DisplayRole:
103
103
  return self._nodes[index.row()].name
104
104
  return None
105
105
 
@@ -112,7 +112,7 @@ class LogConfigModel(QAbstractItemModel):
112
112
  return self._nodes[i]
113
113
 
114
114
 
115
- class PlotTab(Tab, plot_tab_class):
115
+ class PlotTab(TabToolbox, plot_tab_class):
116
116
  """Tab for plotting logging data"""
117
117
 
118
118
  _log_data_signal = pyqtSignal(int, object, object)
@@ -132,38 +132,33 @@ class PlotTab(Tab, plot_tab_class):
132
132
  (180, 60, 240), # purple
133
133
  ]
134
134
 
135
- def __init__(self, tabWidget, helper, *args):
136
- super(PlotTab, self).__init__(*args)
135
+ def __init__(self, helper):
136
+ super(PlotTab, self).__init__(helper, 'Plotter')
137
137
  self.setupUi(self)
138
138
 
139
- self.tabName = "Plotter"
140
- self.menuName = "Plotter"
141
-
142
139
  self._log_error_signal.connect(self._logging_error)
143
140
 
144
141
  self._plot = PlotWidget(fps=30)
145
142
  # Check if we could find the PyQtImport. If not, then
146
143
  # set this tab as disabled
147
- self.enabled = self._plot.can_enable
144
+ is_enabled = self._plot.can_enable
148
145
 
149
146
  self._model = LogConfigModel()
150
147
  self.dataSelector.setModel(self._model)
151
148
  self._log_data_signal.connect(self._log_data_received)
152
- self.tabWidget = tabWidget
153
- self.helper = helper
154
149
  self.plotLayout.addWidget(self._plot)
155
150
 
156
151
  # Connect external signals if we can use the tab
157
- if self.enabled:
152
+ if is_enabled:
158
153
  self._disconnected_signal.connect(self._disconnected)
159
- self.helper.cf.disconnected.add_callback(
154
+ self._helper.cf.disconnected.add_callback(
160
155
  self._disconnected_signal.emit)
161
156
 
162
157
  self._connected_signal.connect(self._connected)
163
- self.helper.cf.connected.add_callback(
158
+ self._helper.cf.connected.add_callback(
164
159
  self._connected_signal.emit)
165
160
 
166
- self.helper.cf.log.block_added_cb.add_callback(self._config_added)
161
+ self._helper.cf.log.block_added_cb.add_callback(self._config_added)
167
162
  self.dataSelector.currentIndexChanged.connect(
168
163
  self._selection_changed)
169
164
 
@@ -245,6 +240,9 @@ class PlotTab(Tab, plot_tab_class):
245
240
  logger.debug("Callback for new config [%s]", logconfig.name)
246
241
  self._model.add_block(logconfig)
247
242
 
243
+ def remove_config(self, logconfig):
244
+ self._model.remove_block(logconfig)
245
+
248
246
  def _logging_error(self, log_conf, msg):
249
247
  """Callback from the log layer when an error occurs"""
250
248
  QMessageBox.about(
@@ -0,0 +1,292 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # ,---------, ____ _ __
4
+ # | ,-^-, | / __ )(_) /_______________ _____ ___
5
+ # | ( O ) | / __ / / __/ ___/ ___/ __ `/_ / / _ \
6
+ # | / ,--' | / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
7
+ # +------` /_____/_/\__/\___/_/ \__,_/ /___/\___/
8
+ #
9
+ # Copyright (C) 2022-2023 Bitcraze AB
10
+ #
11
+ # This program is free software: you can redistribute it and/or modify
12
+ # it under the terms of the GNU General Public License as published by
13
+ # the Free Software Foundation, in version 3.
14
+ #
15
+ # This program is distributed in the hope that it will be useful,
16
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ # GNU General Public License for more details.
19
+ #
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
22
+
23
+ """
24
+ Tab for tuning PID controller, mainly for larger quads.
25
+ """
26
+
27
+ import logging
28
+
29
+ from PyQt6 import QtWidgets
30
+ from PyQt6 import uic
31
+ from PyQt6.QtCore import pyqtSignal, Qt
32
+ import time
33
+
34
+ import cfclient
35
+ from cfclient.ui.tab_toolbox import TabToolbox
36
+ from cfclient.ui.widgets.super_slider import SuperSlider
37
+ from cflib.crazyflie import Crazyflie, Param
38
+ from cflib.utils.callbacks import Syncer
39
+
40
+ __author__ = 'Bitcraze AB'
41
+ __all__ = ['TuningTab']
42
+
43
+ logger = logging.getLogger(__name__)
44
+
45
+ tuning_tab_class = uic.loadUiType(cfclient.module_path + "/ui/tabs/tuningTab.ui")[0]
46
+
47
+
48
+ class SliderParamMapper:
49
+ def __init__(self, slider: SuperSlider, group: str, name: str):
50
+ self.param_group = group
51
+ self.param_name = name
52
+ self.full_param_name = f'{group}.{name}'
53
+
54
+ self.slider = slider
55
+ self.slider.value_changed_cb.add_callback(self.slider_changed)
56
+
57
+ # Prevents param changes that comes back from the CF to set the parameter and create a feedback loop
58
+ self.receive_block_time = 0.0
59
+
60
+ self.linked_mapper = None
61
+ self.linked_checkbox: QtWidgets.QCheckBox = None
62
+
63
+ self.cf = None
64
+
65
+ def connected(self, cf: Crazyflie):
66
+ self.cf = cf
67
+ return self.param_group, self.param_name
68
+
69
+ def disconnected(self):
70
+ self.cf = None
71
+
72
+ def link_with(self, other_mapper: 'SliderParamMapper', checkbox: QtWidgets.QCheckBox):
73
+ self.linked_mapper = other_mapper
74
+ self.linked_checkbox = checkbox
75
+
76
+ other_mapper.linked_mapper = self
77
+ other_mapper.linked_checkbox = checkbox
78
+
79
+ def enable_ui(self, enabled):
80
+ self.slider.setEnabled(enabled)
81
+
82
+ # Called when the user has modified the value in the UI
83
+ def slider_changed(self, value):
84
+ if self.cf is not None:
85
+ if self.cf.is_connected():
86
+ self.receive_block_time = time.time() + 0.4
87
+ self.cf.param.set_value(self.full_param_name, value)
88
+
89
+ if self.linked_mapper is not None:
90
+ self.linked_mapper.linked_update(value)
91
+
92
+ # Called when a parameter in the CF has changed, this is also true if we initiated the param update
93
+ def param_updated_cb(self, full_param_name, value):
94
+ if time.time() > self.receive_block_time:
95
+ self.slider.set_value(float(value))
96
+
97
+ if self.linked_mapper is not None:
98
+ self.linked_mapper.linked_update(value)
99
+
100
+ # Called by another SliderParamMapper that is linked
101
+ def linked_update(self, value):
102
+ if self.linked_checkbox is not None and self.linked_checkbox.checkState() == Qt.CheckState.Checked:
103
+ self.slider.set_value(float(value))
104
+ if self.cf is not None and self.cf.is_connected():
105
+ self.receive_block_time = time.time() + 0.4
106
+ self.cf.param.set_value(self.full_param_name, value)
107
+
108
+
109
+ class TuningTab(TabToolbox, tuning_tab_class):
110
+ """Tab for plotting logging data"""
111
+
112
+ _connected_signal = pyqtSignal(str)
113
+ _disconnected_signal = pyqtSignal(str)
114
+
115
+ _param_updated_signal = pyqtSignal(str, object)
116
+
117
+ def __init__(self, helper):
118
+ super(TuningTab, self).__init__(helper, 'Tuning')
119
+ self.setupUi(self)
120
+
121
+ # Always wrap callbacks from Crazyflie API though QT Signal/Slots
122
+ # to avoid manipulating the UI when rendering it
123
+ self._connected_signal.connect(self._connected)
124
+ self._disconnected_signal.connect(self._disconnected)
125
+ self._param_updated_signal.connect(self._param_updated_cb)
126
+
127
+ # Connect the Crazyflie API callbacks to the signals
128
+ self._helper.cf.connected.add_callback(
129
+ self._connected_signal.emit)
130
+
131
+ self._helper.cf.disconnected.add_callback(
132
+ self._disconnected_signal.emit)
133
+
134
+ # A dictionary mapping the full param name to a SliderParamMapper
135
+ self.mappers = self._set_up_param_mappings()
136
+
137
+ self.store_button.clicked.connect(self._store_button_clicked)
138
+ self.clear_stored_button.clicked.connect(self._clear_stored_button_clicked)
139
+ self.default_values_button.clicked.connect(self._default_values_button_clicked)
140
+ self._enable_ui_objects(False)
141
+
142
+ def _set_up_param_mappings(self):
143
+ mappers: dict[str, SliderParamMapper] = {}
144
+
145
+ # Rate PID
146
+ mappers.update(self._create_slider(self.grid_rate, 1, 1, 0, 1000, 'pid_rate', 'roll_kp'))
147
+ mappers.update(self._create_slider(self.grid_rate, 1, 2, 0, 1000, 'pid_rate', 'roll_ki'))
148
+ mappers.update(self._create_slider(self.grid_rate, 1, 3, 0, 10, 'pid_rate', 'roll_kd'))
149
+
150
+ mappers.update(self._create_slider(self.grid_rate, 2, 1, 0, 1000, 'pid_rate', 'pitch_kp'))
151
+ mappers.update(self._create_slider(self.grid_rate, 2, 2, 0, 1000, 'pid_rate', 'pitch_ki'))
152
+ mappers.update(self._create_slider(self.grid_rate, 2, 3, 0, 10, 'pid_rate', 'pitch_kd'))
153
+
154
+ mappers.update(self._create_slider(self.grid_rate, 3, 1, 0, 200, 'pid_rate', 'yaw_kp'))
155
+ mappers.update(self._create_slider(self.grid_rate, 3, 2, 0, 100, 'pid_rate', 'yaw_ki'))
156
+ mappers.update(self._create_slider(self.grid_rate, 3, 3, 0, 10, 'pid_rate', 'yaw_kd'))
157
+
158
+ self._link(mappers, 'pid_rate.roll_kp', 'pid_rate.pitch_kp', self.rate_link_checkbox)
159
+ self._link(mappers, 'pid_rate.roll_ki', 'pid_rate.pitch_ki', self.rate_link_checkbox)
160
+ self._link(mappers, 'pid_rate.roll_kd', 'pid_rate.pitch_kd', self.rate_link_checkbox)
161
+
162
+ # Attitude PID
163
+ mappers.update(self._create_slider(self.grid_attitude, 1, 1, 0, 10, 'pid_attitude', 'roll_kp'))
164
+ mappers.update(self._create_slider(self.grid_attitude, 1, 2, 0, 10, 'pid_attitude', 'roll_ki'))
165
+ mappers.update(self._create_slider(self.grid_attitude, 1, 3, 0, 10, 'pid_attitude', 'roll_kd'))
166
+
167
+ mappers.update(self._create_slider(self.grid_attitude, 2, 1, 0, 10, 'pid_attitude', 'pitch_kp'))
168
+ mappers.update(self._create_slider(self.grid_attitude, 2, 2, 0, 10, 'pid_attitude', 'pitch_ki'))
169
+ mappers.update(self._create_slider(self.grid_attitude, 2, 3, 0, 10, 'pid_attitude', 'pitch_kd'))
170
+
171
+ mappers.update(self._create_slider(self.grid_attitude, 3, 1, 0, 10, 'pid_attitude', 'yaw_kp'))
172
+ mappers.update(self._create_slider(self.grid_attitude, 3, 2, 0, 10, 'pid_attitude', 'yaw_ki'))
173
+ mappers.update(self._create_slider(self.grid_attitude, 3, 3, 0, 10, 'pid_attitude', 'yaw_kd'))
174
+
175
+ self._link(mappers, 'pid_attitude.roll_kp', 'pid_attitude.pitch_kp', self.attitude_link_checkbox)
176
+ self._link(mappers, 'pid_attitude.roll_ki', 'pid_attitude.pitch_ki', self.attitude_link_checkbox)
177
+ self._link(mappers, 'pid_attitude.roll_kd', 'pid_attitude.pitch_kd', self.attitude_link_checkbox)
178
+
179
+ # Position control PID
180
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 1, 1, 0, 10, 'posCtlPid', 'xKp'))
181
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 1, 2, 0, 10, 'posCtlPid', 'xKi'))
182
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 1, 3, 0, 10, 'posCtlPid', 'xKd'))
183
+
184
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 2, 1, 0, 10, 'posCtlPid', 'yKp'))
185
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 2, 2, 0, 10, 'posCtlPid', 'yKi'))
186
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 2, 3, 0, 10, 'posCtlPid', 'yKd'))
187
+
188
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 3, 1, 0, 10, 'posCtlPid', 'zKp'))
189
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 3, 2, 0, 10, 'posCtlPid', 'zKi'))
190
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 3, 3, 0, 10, 'posCtlPid', 'zKd'))
191
+
192
+ mappers.update(self._create_slider(self.grid_pos_ctrl, 5, 1, 0, 65536, 'posCtlPid', 'thrustBase'))
193
+
194
+ self._link(mappers, 'posCtlPid.xKp', 'posCtlPid.yKp', self.position_link_checkbox)
195
+ self._link(mappers, 'posCtlPid.xKi', 'posCtlPid.yKi', self.position_link_checkbox)
196
+ self._link(mappers, 'posCtlPid.xKd', 'posCtlPid.yKd', self.position_link_checkbox)
197
+
198
+ # Velocity control PID
199
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 1, 1, 0, 50, 'velCtlPid', 'vxKp'))
200
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 1, 2, 0, 50, 'velCtlPid', 'vxKi'))
201
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 1, 3, 0, 10, 'velCtlPid', 'vxKd'))
202
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 1, 4, 0, 10, 'velCtlPid', 'vxKFF'))
203
+
204
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 2, 1, 0, 50, 'velCtlPid', 'vyKp'))
205
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 2, 2, 0, 50, 'velCtlPid', 'vyKi'))
206
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 2, 3, 0, 10, 'velCtlPid', 'vyKd'))
207
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 2, 4, 0, 10, 'velCtlPid', 'vyKFF'))
208
+
209
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 3, 1, 0, 50, 'velCtlPid', 'vzKp'))
210
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 3, 2, 0, 50, 'velCtlPid', 'vzKi'))
211
+ mappers.update(self._create_slider(self.grid_vel_ctrl, 3, 3, 0, 10, 'velCtlPid', 'vzKd'))
212
+
213
+ self._link(mappers, 'velCtlPid.vxKp', 'velCtlPid.vyKp', self.velocity_link_checkbox)
214
+ self._link(mappers, 'velCtlPid.vxKi', 'velCtlPid.vyKi', self.velocity_link_checkbox)
215
+ self._link(mappers, 'velCtlPid.vxKd', 'velCtlPid.vyKd', self.velocity_link_checkbox)
216
+ self._link(mappers, 'velCtlPid.vxKFF', 'velCtlPid.vyKFF', self.velocity_link_checkbox)
217
+
218
+ return mappers
219
+
220
+ def _connected(self, link_uri):
221
+ """Callback when the Crazyflie has been connected"""
222
+ for mapper in self.mappers.values():
223
+ param_group, param_name = mapper.connected(self._helper.cf)
224
+ self._helper.cf.param.add_update_callback(
225
+ group=param_group, name=param_name, cb=self._param_updated_signal.emit)
226
+
227
+ self._enable_ui_objects(True)
228
+
229
+ def _disconnected(self, link_uri):
230
+ """Callback for when the Crazyflie has been disconnected"""
231
+ for mapper in self.mappers.values():
232
+ mapper.disconnected()
233
+
234
+ self._enable_ui_objects(False)
235
+ # TODO set default values?
236
+
237
+ def _create_slider(self, gridLayout, row, col, min_val, max_val, param_group: str, param_name: str):
238
+ initial_val = (min_val + max_val) / 2.0
239
+ slider = SuperSlider(min_val, max_val, initial_val)
240
+ gridLayout.addWidget(slider, row, col)
241
+
242
+ slider_mapper = SliderParamMapper(slider, param_group, param_name)
243
+
244
+ return {slider_mapper.full_param_name: slider_mapper}
245
+
246
+ def _param_updated_cb(self, full_param_name, value):
247
+ if full_param_name in self.mappers:
248
+ self.mappers[full_param_name].param_updated_cb(full_param_name, value)
249
+
250
+ def _link(self, mappers, first, other, checkbox):
251
+ first_mapper = mappers[first]
252
+ other_mapper = mappers[other]
253
+
254
+ first_mapper.link_with(other_mapper, checkbox)
255
+
256
+ def _store_button_clicked(self):
257
+ param: Param = self._helper.cf.param
258
+ for full_param_name in self.mappers.keys():
259
+ # syncer = Syncer()
260
+ param.persistent_store(full_param_name)
261
+
262
+ def _clear_stored_button_clicked(self):
263
+ param: Param = self._helper.cf.param
264
+ for full_param_name in self.mappers.keys():
265
+ param.persistent_clear(full_param_name)
266
+
267
+ def _default_values_button_clicked(self):
268
+ param: Param = self._helper.cf.param
269
+ for full_param_name in self.mappers.keys():
270
+ # For some reason we run into problems if we try to get all params in one go. Pace by getting them
271
+ # one by one.
272
+ syncer = Syncer()
273
+ param.get_default_value(full_param_name, syncer.success_cb)
274
+ syncer.wait()
275
+ self._param_updated_cb(*syncer.success_args)
276
+
277
+ def _enable_ui_objects(self, enabled):
278
+ objects = [
279
+ self.rate_link_checkbox,
280
+ self.attitude_link_checkbox,
281
+ self.position_link_checkbox,
282
+ self.velocity_link_checkbox,
283
+ self.store_button,
284
+ self.clear_stored_button,
285
+ self.default_values_button,
286
+ ]
287
+
288
+ for item in objects:
289
+ item.setEnabled(enabled)
290
+
291
+ for mapper in self.mappers.values():
292
+ mapper.enable_ui(enabled)
@@ -30,15 +30,20 @@ Dropping a new .py file into this directory will automatically list and load
30
30
  it into the UI when it is started.
31
31
  """
32
32
  from .ConsoleTab import ConsoleTab
33
+ from .CrtpSharkToolbox import CrtpSharkToolbox
33
34
  # from .ExampleTab import ExampleTab
34
35
  from .FlightTab import FlightTab
35
36
  # from .GpsTab import GpsTab
36
- from .LEDTab import LEDTab
37
+ from .LEDRingTab import LEDRingTab
37
38
  from .LogBlockTab import LogBlockTab
38
39
  from .LogTab import LogTab
39
40
  from .ParamTab import ParamTab
40
41
  from .PlotTab import PlotTab
41
42
  from .locopositioning_tab import LocoPositioningTab
43
+ from .LogClientTab import LogClientTab
44
+ from .lighthouse_tab import LighthouseTab
45
+ from .TuningTab import TuningTab
46
+ from .ColorLEDTab import ColorLEDTab
42
47
 
43
48
  __author__ = 'Bitcraze AB'
44
49
  __all__ = []
@@ -48,10 +53,15 @@ available = [
48
53
  # ExampleTab,
49
54
  FlightTab,
50
55
  # GpsTab,
51
- LEDTab,
56
+ LEDRingTab,
57
+ ColorLEDTab,
52
58
  LogBlockTab,
53
59
  LogTab,
54
60
  ParamTab,
55
61
  PlotTab,
56
62
  LocoPositioningTab,
63
+ LighthouseTab,
64
+ LogClientTab,
65
+ TuningTab,
66
+ CrtpSharkToolbox,
57
67
  ]