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-2017 Bitcraze AB
10
+ # Copyright (C) 2011-2023 Bitcraze AB
11
11
  #
12
12
  # Crazyflie Nano Quadcopter Client
13
13
  #
@@ -30,15 +30,14 @@ buttons and axis to match controls for the Crazyflie.
30
30
  import logging
31
31
 
32
32
  import cfclient
33
- from PyQt5.QtCore import QThread
34
- from PyQt5.QtCore import QTimer
35
- from PyQt5.QtCore import pyqtSignal
36
- from PyQt5.QtWidgets import QMessageBox
33
+ from PyQt6.QtCore import Qt
34
+ from PyQt6.QtCore import QThread
35
+ from PyQt6.QtCore import QTimer
36
+ from PyQt6.QtCore import pyqtSignal
37
+ from PyQt6.QtWidgets import QMessageBox
37
38
  from cfclient.utils.config_manager import ConfigManager
38
- from PyQt5 import Qt
39
- from PyQt5 import QtWidgets
40
- from PyQt5 import uic
41
- from PyQt5.Qt import * # noqa
39
+ from PyQt6 import QtWidgets
40
+ from PyQt6 import uic
42
41
 
43
42
  __author__ = 'Bitcraze AB'
44
43
  __all__ = ['InputConfigDialogue']
@@ -107,8 +106,12 @@ class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
107
106
  "Press the button for Roll negative calibration"))
108
107
  self.detectKillswitch.clicked.connect(
109
108
  lambda: self._button_detect(
110
- "killswitch", "Killswitch",
111
- "Press the button for the killswitch (will disable motors)"))
109
+ "estop", "Disarm/Kill",
110
+ "Press the button to disarm/kill (will disable motors)"))
111
+ self.detectArm.clicked.connect(
112
+ lambda: self._button_detect(
113
+ "arm", "Arm system",
114
+ "Press the button to arm the system (will enable motor ouput)"))
112
115
  self.detectAlt1.clicked.connect(
113
116
  lambda: self._button_detect(
114
117
  "alt1", "Alternative function 1",
@@ -142,9 +145,10 @@ class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
142
145
  self.detectYaw, self.detectThrust,
143
146
  self.detectPitchPos, self.detectPitchNeg,
144
147
  self.detectRollPos, self.detectRollNeg,
145
- self.detectKillswitch, self.detectExitapp,
146
- self._detect_assisted_control, self.detectAlt1,
147
- self.detectAlt2, self.detectMuxswitch]
148
+ self.detectKillswitch, self.detectArm,
149
+ self.detectExitapp, self._detect_assisted_control,
150
+ self.detectAlt1, self.detectAlt2,
151
+ self.detectMuxswitch]
148
152
 
149
153
  self._button_to_detect = ""
150
154
  self._axis_to_detect = ""
@@ -178,7 +182,8 @@ class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
178
182
  "pitchNeg": self.pitchNeg,
179
183
  "rollPos": self.rollPos,
180
184
  "rollNeg": self.rollNeg,
181
- "killswitch": self.killswitch,
185
+ "estop": self.killswitch,
186
+ "arm": self.arm,
182
187
  "alt1": self.alt1,
183
188
  "alt2": self.alt2,
184
189
  "exitapp": self.exitapp,
@@ -205,16 +210,16 @@ class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
205
210
  self._combined_button = QtWidgets.QPushButton('Combined Axis ' +
206
211
  'Detection')
207
212
  self.cancelButton = QtWidgets.QPushButton('Cancel')
208
- self._popup.addButton(self.cancelButton, QMessageBox.DestructiveRole)
213
+ self._popup.addButton(self.cancelButton, QMessageBox.ButtonRole.DestructiveRole)
209
214
  self._popup.setWindowTitle(caption)
210
- self._popup.setWindowFlags(Qt.Dialog | Qt.MSWindowsFixedSizeDialogHint)
215
+ self._popup.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.MSWindowsFixedSizeDialogHint)
211
216
  if len(directions) > 1:
212
217
  self._popup.originalMessage = message
213
218
  message = self._popup.originalMessage % directions[0]
214
219
  self._combined_button.setCheckable(True)
215
220
  self._combined_button.blockSignals(True)
216
221
  self._popup.addButton(self._combined_button,
217
- QMessageBox.ActionRole)
222
+ QMessageBox.ButtonRole.ActionRole)
218
223
  self._popup.setText(message)
219
224
  self._popup.show()
220
225
 
@@ -295,7 +300,7 @@ class InputConfigDialogue(QtWidgets.QWidget, inputconfig_widget_class):
295
300
  scaled_value = InputConfigDialogue._scale(
296
301
  self._input.max_yaw_rate, scaled_value
297
302
  )
298
- self._axisindicators[v].setValue(scaled_value)
303
+ self._axisindicators[v].setValue(int(scaled_value))
299
304
 
300
305
  def _map_axis(self, function, key_id, scale):
301
306
  self._map["Input.AXIS-{}".format(key_id)] = {}
@@ -505,13 +505,13 @@
505
505
  <property name="geometry">
506
506
  <rect>
507
507
  <x>600</x>
508
- <y>158</y>
508
+ <y>150</y>
509
509
  <width>292</width>
510
- <height>202</height>
510
+ <height>221</height>
511
511
  </rect>
512
512
  </property>
513
513
  <layout class="QGridLayout" name="gridLayout_5">
514
- <item row="5" column="1">
514
+ <item row="6" column="1">
515
515
  <widget class="QPushButton" name="detectAlt2">
516
516
  <property name="enabled">
517
517
  <bool>false</bool>
@@ -521,7 +521,30 @@
521
521
  </property>
522
522
  </widget>
523
523
  </item>
524
- <item row="4" column="0">
524
+ <item row="2" column="1">
525
+ <widget class="QPushButton" name="detectKillswitch">
526
+ <property name="enabled">
527
+ <bool>false</bool>
528
+ </property>
529
+ <property name="text">
530
+ <string>Detect</string>
531
+ </property>
532
+ </widget>
533
+ </item>
534
+ <item row="7" column="0">
535
+ <widget class="QCheckBox" name="muxswitch">
536
+ <property name="enabled">
537
+ <bool>false</bool>
538
+ </property>
539
+ <property name="text">
540
+ <string>Mux switch</string>
541
+ </property>
542
+ <property name="checkable">
543
+ <bool>true</bool>
544
+ </property>
545
+ </widget>
546
+ </item>
547
+ <item row="5" column="0">
525
548
  <widget class="QCheckBox" name="alt1">
526
549
  <property name="enabled">
527
550
  <bool>false</bool>
@@ -534,8 +557,8 @@
534
557
  </property>
535
558
  </widget>
536
559
  </item>
537
- <item row="3" column="1">
538
- <widget class="QPushButton" name="detectExitapp">
560
+ <item row="1" column="1">
561
+ <widget class="QPushButton" name="_detect_assisted_control">
539
562
  <property name="enabled">
540
563
  <bool>false</bool>
541
564
  </property>
@@ -544,30 +567,33 @@
544
567
  </property>
545
568
  </widget>
546
569
  </item>
547
- <item row="2" column="1">
548
- <widget class="QPushButton" name="detectKillswitch">
570
+ <item row="6" column="0">
571
+ <widget class="QCheckBox" name="alt2">
549
572
  <property name="enabled">
550
573
  <bool>false</bool>
551
574
  </property>
552
575
  <property name="text">
553
- <string>Detect</string>
576
+ <string>Alt 2</string>
577
+ </property>
578
+ <property name="checkable">
579
+ <bool>true</bool>
554
580
  </property>
555
581
  </widget>
556
582
  </item>
557
- <item row="2" column="0">
558
- <widget class="QCheckBox" name="killswitch">
583
+ <item row="1" column="0">
584
+ <widget class="QCheckBox" name="_assisted_control">
559
585
  <property name="enabled">
560
586
  <bool>false</bool>
561
587
  </property>
562
588
  <property name="text">
563
- <string>Killswitch</string>
589
+ <string>Assisted control</string>
564
590
  </property>
565
591
  <property name="checkable">
566
592
  <bool>true</bool>
567
593
  </property>
568
594
  </widget>
569
595
  </item>
570
- <item row="3" column="0">
596
+ <item row="4" column="0">
571
597
  <widget class="QCheckBox" name="exitapp">
572
598
  <property name="enabled">
573
599
  <bool>false</bool>
@@ -580,21 +606,21 @@
580
606
  </property>
581
607
  </widget>
582
608
  </item>
583
- <item row="1" column="0">
584
- <widget class="QCheckBox" name="_assisted_control">
609
+ <item row="2" column="0">
610
+ <widget class="QCheckBox" name="killswitch">
585
611
  <property name="enabled">
586
612
  <bool>false</bool>
587
613
  </property>
588
614
  <property name="text">
589
- <string>Assisted control</string>
615
+ <string>Emergency stop</string>
590
616
  </property>
591
617
  <property name="checkable">
592
618
  <bool>true</bool>
593
619
  </property>
594
620
  </widget>
595
621
  </item>
596
- <item row="1" column="1">
597
- <widget class="QPushButton" name="_detect_assisted_control">
622
+ <item row="7" column="1">
623
+ <widget class="QPushButton" name="detectMuxswitch">
598
624
  <property name="enabled">
599
625
  <bool>false</bool>
600
626
  </property>
@@ -603,21 +629,18 @@
603
629
  </property>
604
630
  </widget>
605
631
  </item>
606
- <item row="5" column="0">
607
- <widget class="QCheckBox" name="alt2">
632
+ <item row="5" column="1">
633
+ <widget class="QPushButton" name="detectAlt1">
608
634
  <property name="enabled">
609
635
  <bool>false</bool>
610
636
  </property>
611
637
  <property name="text">
612
- <string>Alt 2</string>
613
- </property>
614
- <property name="checkable">
615
- <bool>true</bool>
638
+ <string>Detect</string>
616
639
  </property>
617
640
  </widget>
618
641
  </item>
619
642
  <item row="4" column="1">
620
- <widget class="QPushButton" name="detectAlt1">
643
+ <widget class="QPushButton" name="detectExitapp">
621
644
  <property name="enabled">
622
645
  <bool>false</bool>
623
646
  </property>
@@ -626,21 +649,21 @@
626
649
  </property>
627
650
  </widget>
628
651
  </item>
629
- <item row="6" column="0">
630
- <widget class="QCheckBox" name="muxswitch">
652
+ <item row="3" column="0">
653
+ <widget class="QCheckBox" name="arm">
631
654
  <property name="enabled">
632
655
  <bool>false</bool>
633
656
  </property>
634
657
  <property name="text">
635
- <string>Mux switch</string>
658
+ <string>Arm/disarm</string>
636
659
  </property>
637
660
  <property name="checkable">
638
661
  <bool>true</bool>
639
662
  </property>
640
663
  </widget>
641
664
  </item>
642
- <item row="6" column="1">
643
- <widget class="QPushButton" name="detectMuxswitch">
665
+ <item row="3" column="1">
666
+ <widget class="QPushButton" name="detectArm">
644
667
  <property name="enabled">
645
668
  <bool>false</bool>
646
669
  </property>
@@ -0,0 +1,220 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # || ____ _ __
4
+ # +------+ / __ )(_) /_______________ _____ ___
5
+ # | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
6
+ # +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
7
+ # || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
8
+ #
9
+ # Copyright (C) 2021-2023 Bitcraze AB
10
+ #
11
+ # This program is free software; you can redistribute it and/or
12
+ # modify it under the terms of the GNU General Public License
13
+ # as published by the Free Software Foundation; either version 2
14
+ # of the License, or (at your option) any later version.
15
+ #
16
+ # This program is distributed in the hope that it will be useful,
17
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ # GNU General Public License for more details.
20
+ # You should have received a copy of the GNU General Public License
21
+ # along with this program; if not, write to the Free Software
22
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23
+ # MA 02110-1301, USA.
24
+
25
+ """
26
+ Dialog box used to configure base station geometry. Used from the lighthouse tab.
27
+ """
28
+ import logging
29
+
30
+ import cfclient
31
+ from PyQt6 import QtWidgets
32
+ from PyQt6 import uic
33
+ from PyQt6.QtCore import QVariant, Qt, QAbstractTableModel, pyqtSignal
34
+ from cflib.localization import LighthouseSweepAngleAverageReader
35
+ from cflib.crazyflie.mem import LighthouseBsGeometry
36
+ from cfclient.ui.wizards.lighthouse_geo_bs_estimation_wizard import LighthouseBasestationGeometryWizard
37
+
38
+ __author__ = 'Bitcraze AB'
39
+ __all__ = ['LighthouseBsGeometryDialog']
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ (basestation_geometry_widget_class, connect_widget_base_class) = (
44
+ uic.loadUiType(
45
+ cfclient.module_path + '/ui/dialogs/lighthouse_bs_geometry_dialog.ui')
46
+ )
47
+
48
+
49
+ class LighthouseBsGeometryTableModel(QAbstractTableModel):
50
+ def __init__(self, headers, parent=None, *args):
51
+ QAbstractTableModel.__init__(self, parent)
52
+ self._headers = headers
53
+ self._table_values = []
54
+ self._current_geos = {}
55
+ self._estimated_geos = {}
56
+
57
+ def rowCount(self, parent=None, *args, **kwargs):
58
+ return len(self._table_values)
59
+
60
+ def columnCount(self, parent=None, *args, **kwargs):
61
+ return len(self._headers)
62
+
63
+ def data(self, index, role=None):
64
+ if index.isValid():
65
+ value = self._table_values[index.row()][index.column()]
66
+ if role == Qt.ItemDataRole.DisplayRole:
67
+ return QVariant(value)
68
+
69
+ return QVariant()
70
+
71
+ def headerData(self, col, orientation, role=None):
72
+ if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole:
73
+ return QVariant(self._headers[col])
74
+ return QVariant()
75
+
76
+ def _compile_entry(self, current_geo, estimated_geo, index):
77
+ result = 'N/A'
78
+ if current_geo is not None:
79
+ result = '%.2f' % current_geo.origin[index]
80
+ if estimated_geo is not None:
81
+ result += ' -> %.2f' % estimated_geo.origin[index]
82
+
83
+ return result
84
+
85
+ def _add_table_value(self, current_geo, estimated_geo, id, table_values):
86
+ x = self._compile_entry(current_geo, estimated_geo, 0)
87
+ y = self._compile_entry(current_geo, estimated_geo, 1)
88
+ z = self._compile_entry(current_geo, estimated_geo, 2)
89
+
90
+ table_values.append([id + 1, x, y, z])
91
+
92
+ def _add_table_value_for_id(self, current_geos, estimated_geos, table_values, id):
93
+ current_geo = None
94
+ if id in current_geos:
95
+ current_geo = current_geos[id]
96
+
97
+ estimated_geo = None
98
+ if id in estimated_geos:
99
+ estimated_geo = estimated_geos[id]
100
+
101
+ if current_geo is not None or estimated_geo is not None:
102
+ self._add_table_value(current_geo, estimated_geo, id, table_values)
103
+
104
+ def _add_table_values(self, current_geos, estimated_geos, table_values):
105
+ current_ids = set(current_geos.keys())
106
+ estimated_ids = set(estimated_geos.keys())
107
+ all_ids = current_ids.union(estimated_ids)
108
+
109
+ for id in all_ids:
110
+ self._add_table_value_for_id(current_geos, estimated_geos, table_values, id)
111
+
112
+ def _update_table_data(self):
113
+ self.layoutAboutToBeChanged.emit()
114
+ self._table_values = []
115
+ self._add_table_values(self._current_geos, self._estimated_geos, self._table_values)
116
+ self._table_values.sort(key=lambda row: row[0])
117
+ self.layoutChanged.emit()
118
+
119
+ def set_estimated_geos(self, geos):
120
+ self._estimated_geos = geos
121
+ self._update_table_data()
122
+
123
+ def set_current_geos(self, geos):
124
+ self._current_geos = geos
125
+ self._update_table_data()
126
+
127
+
128
+ class LighthouseBsGeometryDialog(QtWidgets.QWidget, basestation_geometry_widget_class):
129
+
130
+ _sweep_angles_received_and_averaged_signal = pyqtSignal(object)
131
+ _base_station_geometery_received_signal = pyqtSignal(object)
132
+
133
+ def __init__(self, lighthouse_tab, *args):
134
+ super(LighthouseBsGeometryDialog, self).__init__(*args)
135
+ self.setupUi(self)
136
+
137
+ self._lighthouse_tab = lighthouse_tab
138
+
139
+ self._estimate_geometry_button.clicked.connect(self._estimate_geometry_button_clicked)
140
+
141
+ self._write_to_cf_button.clicked.connect(self._write_to_cf_button_clicked)
142
+
143
+ self._sweep_angles_received_and_averaged_signal.connect(self._sweep_angles_received_and_averaged_cb)
144
+ self._base_station_geometery_received_signal.connect(self._basestation_geometry_received_signal_cb)
145
+ self._close_button.clicked.connect(self.close)
146
+
147
+ self._sweep_angle_reader = LighthouseSweepAngleAverageReader(
148
+ self._lighthouse_tab._helper.cf, self._sweep_angles_received_and_averaged_signal.emit)
149
+
150
+ self._base_station_geometry_wizard = LighthouseBasestationGeometryWizard(
151
+ self._lighthouse_tab._helper.cf, self._base_station_geometery_received_signal.emit)
152
+
153
+ self._lh_geos = None
154
+ self._newly_estimated_geometry = {}
155
+
156
+ # Table handlers
157
+ self._headers = ['id', 'x', 'y', 'z']
158
+ self._data_model = LighthouseBsGeometryTableModel(self._headers, self)
159
+ self._table_view.setModel(self._data_model)
160
+
161
+ self._table_view.verticalHeader().setVisible(False)
162
+
163
+ header = self._table_view.horizontalHeader()
164
+ header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
165
+ header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeMode.Stretch)
166
+ header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeMode.Stretch)
167
+ header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeMode.Stretch)
168
+
169
+ self._update_ui()
170
+
171
+ def reset(self):
172
+ self._newly_estimated_geometry = {}
173
+ self._update_ui()
174
+
175
+ def _basestation_geometry_received_signal_cb(self, basestation_geometries):
176
+ self._newly_estimated_geometry = basestation_geometries
177
+ self.show()
178
+ self._update_ui()
179
+
180
+ def _sweep_angles_received_and_averaged_cb(self, averaged_angles):
181
+ self._averaged_angles = averaged_angles
182
+ self._newly_estimated_geometry = {}
183
+
184
+ for id, average_data in averaged_angles.items():
185
+ sensor_data = average_data[1]
186
+ rotation_bs_matrix, position_bs_vector = self._simple_estimator.estimate_geometry(sensor_data)
187
+ geo = LighthouseBsGeometry()
188
+ geo.rotation_matrix = rotation_bs_matrix
189
+ geo.origin = position_bs_vector
190
+ geo.valid = True
191
+ self._newly_estimated_geometry[id] = geo
192
+
193
+ self._update_ui()
194
+
195
+ def _estimate_geometry_button_clicked(self):
196
+ self._base_station_geometry_wizard.reset()
197
+ self._base_station_geometry_wizard.show()
198
+ self.hide()
199
+
200
+ def _write_to_cf_button_clicked(self):
201
+ if len(self._newly_estimated_geometry) > 0:
202
+ self._lighthouse_tab.write_and_store_geometry(self._newly_estimated_geometry)
203
+ self._newly_estimated_geometry = {}
204
+
205
+ self._update_ui()
206
+
207
+ def _update_ui(self):
208
+ self._write_to_cf_button.setEnabled(len(self._newly_estimated_geometry) > 0)
209
+ self._data_model.set_estimated_geos(self._newly_estimated_geometry)
210
+
211
+ def closeEvent(self, event):
212
+ self._stop_collection()
213
+
214
+ def _stop_collection(self):
215
+ self._sweep_angle_reader.stop_angle_collection()
216
+
217
+ def geometry_updated(self, geometry):
218
+ self._data_model.set_current_geos(geometry)
219
+
220
+ self._update_ui()
@@ -0,0 +1,110 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>Form</class>
4
+ <widget class="QWidget" name="Form">
5
+ <property name="windowModality">
6
+ <enum>Qt::ApplicationModal</enum>
7
+ </property>
8
+ <property name="geometry">
9
+ <rect>
10
+ <x>0</x>
11
+ <y>0</y>
12
+ <width>443</width>
13
+ <height>555</height>
14
+ </rect>
15
+ </property>
16
+ <property name="windowTitle">
17
+ <string>Basestation Geometry Managment</string>
18
+ </property>
19
+ <layout class="QVBoxLayout" name="verticalLayout_4">
20
+ <item>
21
+ <layout class="QVBoxLayout" name="verticalLayout">
22
+ <item>
23
+ <layout class="QHBoxLayout" name="horizontalLayout">
24
+ <item>
25
+ <widget class="QPushButton" name="_estimate_geometry_button">
26
+ <property name="text">
27
+ <string>Estimate Geometry</string>
28
+ </property>
29
+ </widget>
30
+ </item>
31
+ <item>
32
+ <spacer name="horizontalSpacer_2">
33
+ <property name="orientation">
34
+ <enum>Qt::Horizontal</enum>
35
+ </property>
36
+ <property name="sizeHint" stdset="0">
37
+ <size>
38
+ <width>40</width>
39
+ <height>20</height>
40
+ </size>
41
+ </property>
42
+ </spacer>
43
+ </item>
44
+ </layout>
45
+ </item>
46
+ <item>
47
+ <widget class="QTableView" name="_table_view"/>
48
+ </item>
49
+ <item>
50
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
51
+ <item>
52
+ <spacer name="horizontalSpacer_3">
53
+ <property name="orientation">
54
+ <enum>Qt::Horizontal</enum>
55
+ </property>
56
+ <property name="sizeHint" stdset="0">
57
+ <size>
58
+ <width>40</width>
59
+ <height>20</height>
60
+ </size>
61
+ </property>
62
+ </spacer>
63
+ </item>
64
+ </layout>
65
+ </item>
66
+ <item>
67
+ <widget class="Line" name="line">
68
+ <property name="orientation">
69
+ <enum>Qt::Horizontal</enum>
70
+ </property>
71
+ </widget>
72
+ </item>
73
+ <item>
74
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
75
+ <item>
76
+ <widget class="QPushButton" name="_write_to_cf_button">
77
+ <property name="text">
78
+ <string>Write to Crazyflie</string>
79
+ </property>
80
+ </widget>
81
+ </item>
82
+ <item>
83
+ <spacer name="horizontalSpacer">
84
+ <property name="orientation">
85
+ <enum>Qt::Horizontal</enum>
86
+ </property>
87
+ <property name="sizeHint" stdset="0">
88
+ <size>
89
+ <width>40</width>
90
+ <height>20</height>
91
+ </size>
92
+ </property>
93
+ </spacer>
94
+ </item>
95
+ <item>
96
+ <widget class="QPushButton" name="_close_button">
97
+ <property name="text">
98
+ <string>Close</string>
99
+ </property>
100
+ </widget>
101
+ </item>
102
+ </layout>
103
+ </item>
104
+ </layout>
105
+ </item>
106
+ </layout>
107
+ </widget>
108
+ <resources/>
109
+ <connections/>
110
+ </ui>