cgse 2024.7.0__py3-none-any.whl → 2025.0.2__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.
- README.md +27 -0
- bump.py +85 -0
- cgse-2025.0.2.dist-info/METADATA +38 -0
- cgse-2025.0.2.dist-info/RECORD +5 -0
- {cgse-2024.7.0.dist-info → cgse-2025.0.2.dist-info}/WHEEL +1 -2
- cgse-2024.7.0.dist-info/COPYING +0 -674
- cgse-2024.7.0.dist-info/COPYING.LESSER +0 -165
- cgse-2024.7.0.dist-info/METADATA +0 -144
- cgse-2024.7.0.dist-info/RECORD +0 -660
- cgse-2024.7.0.dist-info/entry_points.txt +0 -75
- cgse-2024.7.0.dist-info/top_level.txt +0 -2
- egse/__init__.py +0 -12
- egse/__main__.py +0 -32
- egse/aeu/aeu.py +0 -5238
- egse/aeu/aeu_awg.yaml +0 -265
- egse/aeu/aeu_crio.yaml +0 -273
- egse/aeu/aeu_cs.py +0 -627
- egse/aeu/aeu_devif.py +0 -321
- egse/aeu/aeu_main_ui.py +0 -903
- egse/aeu/aeu_metrics.py +0 -131
- egse/aeu/aeu_protocol.py +0 -463
- egse/aeu/aeu_psu.yaml +0 -204
- egse/aeu/aeu_ui.py +0 -873
- egse/aeu/arbdata/FccdRead.arb +0 -2
- egse/aeu/arbdata/FccdRead_min_points.arb +0 -2
- egse/aeu/arbdata/HeaterSync_FccdRead.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead25.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead31_25.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead37_50.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead43_75.arb +0 -2
- egse/aeu/arbdata/HeaterSync_ccdRead50.arb +0 -2
- egse/aeu/arbdata/Heater_FccdRead_min_points.arb +0 -2
- egse/aeu/arbdata/ccdRead25.arb +0 -2
- egse/aeu/arbdata/ccdRead25_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead31_25.arb +0 -2
- egse/aeu/arbdata/ccdRead31_25_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead37_50.arb +0 -2
- egse/aeu/arbdata/ccdRead37_50_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead43_75.arb +0 -2
- egse/aeu/arbdata/ccdRead43_75_150ms.arb +0 -2
- egse/aeu/arbdata/ccdRead50.arb +0 -2
- egse/aeu/arbdata/ccdRead50_150ms.arb +0 -2
- egse/alert/__init__.py +0 -1049
- egse/alert/alertman.yaml +0 -37
- egse/alert/alertman_cs.py +0 -233
- egse/alert/alertman_ui.py +0 -600
- egse/alert/gsm/beaglebone.py +0 -138
- egse/alert/gsm/beaglebone.yaml +0 -51
- egse/alert/gsm/beaglebone_cs.py +0 -108
- egse/alert/gsm/beaglebone_devif.py +0 -122
- egse/alert/gsm/beaglebone_protocol.py +0 -46
- egse/bits.py +0 -318
- egse/camera.py +0 -44
- egse/collimator/__init__.py +0 -0
- egse/collimator/fcul/__init__.py +0 -0
- egse/collimator/fcul/ogse.py +0 -1077
- egse/collimator/fcul/ogse.yaml +0 -14
- egse/collimator/fcul/ogse_cs.py +0 -154
- egse/collimator/fcul/ogse_devif.py +0 -358
- egse/collimator/fcul/ogse_protocol.py +0 -132
- egse/collimator/fcul/ogse_sim.py +0 -431
- egse/collimator/fcul/ogse_ui.py +0 -1108
- egse/command.py +0 -699
- egse/config.py +0 -410
- egse/confman/__init__.py +0 -1058
- egse/confman/confman.yaml +0 -70
- egse/confman/confman_cs.py +0 -240
- egse/confman/confman_ui.py +0 -381
- egse/confman/setup_ui.py +0 -565
- egse/control.py +0 -632
- egse/coordinates/__init__.py +0 -534
- egse/coordinates/avoidance.py +0 -100
- egse/coordinates/cslmodel.py +0 -127
- egse/coordinates/laser_tracker_to_dict.py +0 -122
- egse/coordinates/point.py +0 -707
- egse/coordinates/pyplot.py +0 -194
- egse/coordinates/referenceFrame.py +0 -1279
- egse/coordinates/refmodel.py +0 -737
- egse/coordinates/rotationMatrix.py +0 -85
- egse/coordinates/transform3d_addon.py +0 -419
- egse/csl/__init__.py +0 -50
- egse/csl/commanding.py +0 -78
- egse/csl/icons/hexapod-connected-selected.svg +0 -30
- egse/csl/icons/hexapod-connected.svg +0 -30
- egse/csl/icons/hexapod-homing-selected.svg +0 -68
- egse/csl/icons/hexapod-homing.svg +0 -68
- egse/csl/icons/hexapod-retract-selected.svg +0 -56
- egse/csl/icons/hexapod-retract.svg +0 -51
- egse/csl/icons/hexapod-zero-selected.svg +0 -56
- egse/csl/icons/hexapod-zero.svg +0 -56
- egse/csl/icons/logo-puna.svg +0 -92
- egse/csl/icons/stop.svg +0 -1
- egse/csl/initialisation.py +0 -102
- egse/csl/mech_pos_settings.yaml +0 -18
- egse/das.py +0 -1240
- egse/das.yaml +0 -7
- egse/data/conf/SETUP_CSL_00000_170620_150000.yaml +0 -5
- egse/data/conf/SETUP_CSL_00001_170620_151010.yaml +0 -69
- egse/data/conf/SETUP_CSL_00002_170620_151020.yaml +0 -69
- egse/data/conf/SETUP_CSL_00003_170620_151030.yaml +0 -69
- egse/data/conf/SETUP_CSL_00004_170620_151040.yaml +0 -69
- egse/data/conf/SETUP_CSL_00005_170620_151050.yaml +0 -69
- egse/data/conf/SETUP_CSL_00006_170620_151060.yaml +0 -69
- egse/data/conf/SETUP_CSL_00007_170620_151070.yaml +0 -69
- egse/data/conf/SETUP_CSL_00008_170620_151080.yaml +0 -75
- egse/data/conf/SETUP_CSL_00010_210308_083016.yaml +0 -138
- egse/data/conf/SETUP_INTA_00000_170620_150000.yaml +0 -4
- egse/data/conf/SETUP_SRON_00000_170620_150000.yaml +0 -4
- egse/decorators.py +0 -514
- egse/device.py +0 -269
- egse/dpu/__init__.py +0 -2698
- egse/dpu/ccd_ui.py +0 -514
- egse/dpu/dpu.py +0 -783
- egse/dpu/dpu.yaml +0 -153
- egse/dpu/dpu_cs.py +0 -272
- egse/dpu/dpu_ui.py +0 -671
- egse/dpu/fitsgen.py +0 -2096
- egse/dpu/fitsgen_ui.py +0 -399
- egse/dpu/hdf5_model.py +0 -332
- egse/dpu/hdf5_ui.py +0 -277
- egse/dpu/hdf5_viewer.py +0 -506
- egse/dpu/hk_ui.py +0 -468
- egse/dpu_commands.py +0 -81
- egse/dsi/__init__.py +0 -33
- egse/dsi/_libesl.py +0 -232
- egse/dsi/constants.py +0 -296
- egse/dsi/esl.py +0 -630
- egse/dsi/rmap.py +0 -444
- egse/dsi/rmapci.py +0 -39
- egse/dsi/spw.py +0 -335
- egse/dsi/spw_state.py +0 -29
- egse/dummy.py +0 -318
- egse/dyndummy.py +0 -179
- egse/env.py +0 -278
- egse/exceptions.py +0 -88
- egse/fdir/__init__.py +0 -26
- egse/fdir/fdir_manager.py +0 -85
- egse/fdir/fdir_manager.yaml +0 -37
- egse/fdir/fdir_manager_controller.py +0 -136
- egse/fdir/fdir_manager_cs.py +0 -164
- egse/fdir/fdir_manager_interface.py +0 -15
- egse/fdir/fdir_remote.py +0 -73
- egse/fdir/fdir_remote.yaml +0 -30
- egse/fdir/fdir_remote_controller.py +0 -30
- egse/fdir/fdir_remote_cs.py +0 -94
- egse/fdir/fdir_remote_interface.py +0 -9
- egse/fdir/fdir_remote_popup.py +0 -26
- egse/fee/__init__.py +0 -106
- egse/fee/f_fee_register.yaml +0 -43
- egse/fee/feesim.py +0 -914
- egse/fee/n_fee_hk.py +0 -768
- egse/fee/nfee.py +0 -188
- egse/filterwheel/__init__.py +0 -4
- egse/filterwheel/eksma/__init__.py +0 -49
- egse/filterwheel/eksma/fw8smc4.py +0 -657
- egse/filterwheel/eksma/fw8smc4.yaml +0 -121
- egse/filterwheel/eksma/fw8smc4_cs.py +0 -144
- egse/filterwheel/eksma/fw8smc4_devif.py +0 -473
- egse/filterwheel/eksma/fw8smc4_protocol.py +0 -82
- egse/filterwheel/eksma/fw8smc4_ui.py +0 -940
- egse/filterwheel/eksma/fw8smc5.py +0 -115
- egse/filterwheel/eksma/fw8smc5.yaml +0 -105
- egse/filterwheel/eksma/fw8smc5_controller.py +0 -307
- egse/filterwheel/eksma/fw8smc5_cs.py +0 -141
- egse/filterwheel/eksma/fw8smc5_interface.py +0 -65
- egse/filterwheel/eksma/fw8smc5_simulator.py +0 -29
- egse/filterwheel/eksma/fw8smc5_ui.py +0 -1065
- egse/filterwheel/eksma/testpythonfw.py +0 -215
- egse/fov/__init__.py +0 -65
- egse/fov/fov_hk.py +0 -710
- egse/fov/fov_ui.py +0 -859
- egse/fov/fov_ui_controller.py +0 -140
- egse/fov/fov_ui_model.py +0 -200
- egse/fov/fov_ui_view.py +0 -345
- egse/gimbal/__init__.py +0 -32
- egse/gimbal/symetrie/__init__.py +0 -26
- egse/gimbal/symetrie/alpha.py +0 -586
- egse/gimbal/symetrie/generic_gimbal_ui.py +0 -1521
- egse/gimbal/symetrie/gimbal.py +0 -877
- egse/gimbal/symetrie/gimbal.yaml +0 -168
- egse/gimbal/symetrie/gimbal_cs.py +0 -183
- egse/gimbal/symetrie/gimbal_protocol.py +0 -138
- egse/gimbal/symetrie/gimbal_ui.py +0 -361
- egse/gimbal/symetrie/pmac.py +0 -1006
- egse/gimbal/symetrie/pmac_regex.py +0 -83
- egse/graph.py +0 -132
- egse/gui/__init__.py +0 -47
- egse/gui/buttons.py +0 -378
- egse/gui/focalplane.py +0 -1285
- egse/gui/formatter.py +0 -10
- egse/gui/led.py +0 -162
- egse/gui/limitswitch.py +0 -143
- egse/gui/mechanisms.py +0 -587
- egse/gui/states.py +0 -148
- egse/gui/stripchart.py +0 -729
- egse/gui/styles.qss +0 -48
- egse/gui/switch.py +0 -112
- egse/h5.py +0 -274
- egse/help/__init__.py +0 -0
- egse/help/help_ui.py +0 -126
- egse/hexapod/__init__.py +0 -32
- egse/hexapod/symetrie/__init__.py +0 -137
- egse/hexapod/symetrie/alpha.py +0 -874
- egse/hexapod/symetrie/dynalpha.py +0 -1387
- egse/hexapod/symetrie/hexapod_ui.py +0 -1516
- egse/hexapod/symetrie/pmac.py +0 -1010
- egse/hexapod/symetrie/pmac_regex.py +0 -83
- egse/hexapod/symetrie/puna.py +0 -1167
- egse/hexapod/symetrie/puna.yaml +0 -193
- egse/hexapod/symetrie/puna_cs.py +0 -195
- egse/hexapod/symetrie/puna_protocol.py +0 -134
- egse/hexapod/symetrie/puna_ui.py +0 -433
- egse/hexapod/symetrie/punaplus.py +0 -107
- egse/hexapod/symetrie/zonda.py +0 -872
- egse/hexapod/symetrie/zonda.yaml +0 -337
- egse/hexapod/symetrie/zonda_cs.py +0 -172
- egse/hexapod/symetrie/zonda_devif.py +0 -414
- egse/hexapod/symetrie/zonda_protocol.py +0 -123
- egse/hexapod/symetrie/zonda_ui.py +0 -449
- egse/hk.py +0 -791
- egse/icons/aeu-cs-start.svg +0 -117
- egse/icons/aeu-cs-stop.svg +0 -118
- egse/icons/aeu-cs.svg +0 -107
- egse/icons/aeu_cs-started.svg +0 -112
- egse/icons/aeu_cs-stopped.svg +0 -112
- egse/icons/aeu_cs.svg +0 -55
- egse/icons/alert.svg +0 -1
- egse/icons/arrow-double-left.png +0 -0
- egse/icons/arrow-double-right.png +0 -0
- egse/icons/arrow-up.svg +0 -11
- egse/icons/backward.svg +0 -1
- egse/icons/busy.svg +0 -1
- egse/icons/cleaning.svg +0 -115
- egse/icons/color-scheme.svg +0 -1
- egse/icons/cs-connected-alert.svg +0 -91
- egse/icons/cs-connected-disabled.svg +0 -43
- egse/icons/cs-connected.svg +0 -89
- egse/icons/cs-not-connected.svg +0 -44
- egse/icons/double-left-arrow.svg +0 -1
- egse/icons/double-right-arrow.svg +0 -1
- egse/icons/erase-disabled.svg +0 -19
- egse/icons/erase.svg +0 -59
- egse/icons/fitsgen-start.svg +0 -47
- egse/icons/fitsgen-stop.svg +0 -48
- egse/icons/fitsgen.svg +0 -1
- egse/icons/forward.svg +0 -1
- egse/icons/fov-hk-start.svg +0 -33
- egse/icons/fov-hk-stop.svg +0 -37
- egse/icons/fov-hk.svg +0 -1
- egse/icons/front-desk.svg +0 -1
- egse/icons/home-actioned.svg +0 -15
- egse/icons/home-disabled.svg +0 -15
- egse/icons/home.svg +0 -13
- egse/icons/info.svg +0 -1
- egse/icons/invalid.png +0 -0
- egse/icons/led-green.svg +0 -20
- egse/icons/led-grey.svg +0 -20
- egse/icons/led-orange.svg +0 -20
- egse/icons/led-red.svg +0 -20
- egse/icons/led-square-green.svg +0 -134
- egse/icons/led-square-grey.svg +0 -134
- egse/icons/led-square-orange.svg +0 -134
- egse/icons/led-square-red.svg +0 -134
- egse/icons/limit-switch-all-green.svg +0 -115
- egse/icons/limit-switch-all-red.svg +0 -117
- egse/icons/limit-switch-el+.svg +0 -116
- egse/icons/limit-switch-el-.svg +0 -117
- egse/icons/location-marker.svg +0 -1
- egse/icons/logo-dpu.svg +0 -48
- egse/icons/logo-gimbal.svg +0 -112
- egse/icons/logo-huber.svg +0 -23
- egse/icons/logo-ogse.svg +0 -31
- egse/icons/logo-puna.svg +0 -92
- egse/icons/logo-tcs.svg +0 -29
- egse/icons/logo-zonda.svg +0 -66
- egse/icons/maximize.svg +0 -1
- egse/icons/meter.svg +0 -1
- egse/icons/more.svg +0 -45
- egse/icons/n-fee-hk-start.svg +0 -24
- egse/icons/n-fee-hk-stop.svg +0 -25
- egse/icons/n-fee-hk.svg +0 -83
- egse/icons/observing-off.svg +0 -46
- egse/icons/observing-on.svg +0 -46
- egse/icons/open-document-hdf5.png +0 -0
- egse/icons/open-document-hdf5.svg +0 -21
- egse/icons/ops-mode.svg +0 -1
- egse/icons/play-green.svg +0 -17
- egse/icons/plugged-disabled.svg +0 -27
- egse/icons/plugged.svg +0 -21
- egse/icons/pm_ui.svg +0 -1
- egse/icons/power-button-green.svg +0 -27
- egse/icons/power-button-red.svg +0 -27
- egse/icons/power-button.svg +0 -27
- egse/icons/radar.svg +0 -1
- egse/icons/radioactive.svg +0 -2
- egse/icons/reload.svg +0 -1
- egse/icons/remote-control-off.svg +0 -28
- egse/icons/remote-control-on.svg +0 -28
- egse/icons/repeat-blue.svg +0 -15
- egse/icons/repeat.svg +0 -1
- egse/icons/settings.svg +0 -1
- egse/icons/shrink.svg +0 -1
- egse/icons/shutter.svg +0 -1
- egse/icons/sign-off.svg +0 -1
- egse/icons/sign-on.svg +0 -1
- egse/icons/sim-mode.svg +0 -1
- egse/icons/small-buttons-go.svg +0 -20
- egse/icons/small-buttons-minus.svg +0 -51
- egse/icons/small-buttons-plus.svg +0 -51
- egse/icons/sponge.svg +0 -220
- egse/icons/start-button-disabled.svg +0 -84
- egse/icons/start-button.svg +0 -50
- egse/icons/stop-button-disabled.svg +0 -84
- egse/icons/stop-button.svg +0 -50
- egse/icons/stop-red.svg +0 -17
- egse/icons/stop.svg +0 -1
- egse/icons/switch-disabled-square.svg +0 -87
- egse/icons/switch-disabled.svg +0 -15
- egse/icons/switch-off-square.svg +0 -87
- egse/icons/switch-off.svg +0 -72
- egse/icons/switch-on-square.svg +0 -87
- egse/icons/switch-on.svg +0 -61
- egse/icons/temperature-control.svg +0 -44
- egse/icons/th_ui_logo.svg +0 -1
- egse/icons/unplugged.svg +0 -23
- egse/icons/unvalid.png +0 -0
- egse/icons/user-interface.svg +0 -1
- egse/icons/vacuum.svg +0 -1
- egse/icons/valid.png +0 -0
- egse/icons/zoom-to-pixel-dark.svg +0 -64
- egse/icons/zoom-to-pixel-white.svg +0 -36
- egse/images/big-rotation-stage.png +0 -0
- egse/images/connected-100.png +0 -0
- egse/images/cross.svg +0 -6
- egse/images/disconnected-100.png +0 -0
- egse/images/gui-icon.png +0 -0
- egse/images/home.svg +0 -6
- egse/images/info-icon.png +0 -0
- egse/images/led-black.svg +0 -89
- egse/images/led-green.svg +0 -85
- egse/images/led-orange.svg +0 -85
- egse/images/led-red.svg +0 -85
- egse/images/load-icon.png +0 -0
- egse/images/load-setup.png +0 -0
- egse/images/load.png +0 -0
- egse/images/pause.png +0 -0
- egse/images/play-button.svg +0 -8
- egse/images/play.png +0 -0
- egse/images/process-status.png +0 -0
- egse/images/restart.png +0 -0
- egse/images/search.png +0 -0
- egse/images/sma.png +0 -0
- egse/images/start.png +0 -0
- egse/images/stop-button.svg +0 -8
- egse/images/stop.png +0 -0
- egse/images/switch-off.svg +0 -48
- egse/images/switch-on.svg +0 -48
- egse/images/undo.png +0 -0
- egse/images/update-button.svg +0 -11
- egse/imageviewer/exposureselection.py +0 -475
- egse/imageviewer/imageviewer.py +0 -198
- egse/imageviewer/matchfocalplane.py +0 -179
- egse/imageviewer/subfieldposition.py +0 -133
- egse/lampcontrol/__init__.py +0 -4
- egse/lampcontrol/beaglebone/beaglebone.py +0 -178
- egse/lampcontrol/beaglebone/beaglebone.yaml +0 -62
- egse/lampcontrol/beaglebone/beaglebone_cs.py +0 -106
- egse/lampcontrol/beaglebone/beaglebone_devif.py +0 -150
- egse/lampcontrol/beaglebone/beaglebone_protocol.py +0 -73
- egse/lampcontrol/energetiq/__init__.py +0 -22
- egse/lampcontrol/energetiq/eq99.yaml +0 -98
- egse/lampcontrol/energetiq/lampEQ99.py +0 -283
- egse/lampcontrol/energetiq/lampEQ99_cs.py +0 -128
- egse/lampcontrol/energetiq/lampEQ99_devif.py +0 -158
- egse/lampcontrol/energetiq/lampEQ99_encode_decode_errors.py +0 -73
- egse/lampcontrol/energetiq/lampEQ99_protocol.py +0 -71
- egse/lampcontrol/energetiq/lampEQ99_ui.py +0 -465
- egse/lib/CentOS-7/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/CentOS-8/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/CentOS-8/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Debian/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Debian/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Debian/libetherspacelink_v35_21.dylib +0 -0
- egse/lib/Linux/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Linux/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/Ubuntu-20/ESL-RMAP_v34_86.dylib +0 -0
- egse/lib/Ubuntu-20/EtherSpaceLink_v34_86.dylib +0 -0
- egse/lib/gssw/python3-gssw_2.2.3+31f63c9f-1_all.deb +0 -0
- egse/lib/ximc/__pycache__/pyximc.cpython-38 2.pyc +0 -0
- egse/lib/ximc/__pycache__/pyximc.cpython-38.pyc +0 -0
- egse/lib/ximc/libximc.framework/Frameworks/libbindy.dylib +0 -0
- egse/lib/ximc/libximc.framework/Frameworks/libxiwrapper.dylib +0 -0
- egse/lib/ximc/libximc.framework/Headers/ximc.h +0 -5510
- egse/lib/ximc/libximc.framework/Resources/Info.plist +0 -42
- egse/lib/ximc/libximc.framework/Resources/keyfile.sqlite +0 -0
- egse/lib/ximc/libximc.framework/libbindy.so +0 -0
- egse/lib/ximc/libximc.framework/libximc +0 -0
- egse/lib/ximc/libximc.framework/libximc.so +0 -0
- egse/lib/ximc/libximc.framework/libximc.so.7.0.0 +0 -0
- egse/lib/ximc/libximc.framework/libxiwrapper.so +0 -0
- egse/lib/ximc/pyximc.py +0 -922
- egse/listener.py +0 -179
- egse/logger/__init__.py +0 -243
- egse/logger/log_cs.py +0 -321
- egse/metrics.py +0 -102
- egse/mixin.py +0 -464
- egse/monitoring.py +0 -95
- egse/ni/alarms/__init__.py +0 -26
- egse/ni/alarms/cdaq9375.py +0 -300
- egse/ni/alarms/cdaq9375.yaml +0 -89
- egse/ni/alarms/cdaq9375_cs.py +0 -130
- egse/ni/alarms/cdaq9375_devif.py +0 -183
- egse/ni/alarms/cdaq9375_protocol.py +0 -48
- egse/obs_inspection.py +0 -165
- egse/observer.py +0 -41
- egse/obsid.py +0 -163
- egse/powermeter/__init__.py +0 -0
- egse/powermeter/ni/__init__.py +0 -38
- egse/powermeter/ni/cdaq9184.py +0 -224
- egse/powermeter/ni/cdaq9184.yaml +0 -73
- egse/powermeter/ni/cdaq9184_cs.py +0 -130
- egse/powermeter/ni/cdaq9184_devif.py +0 -201
- egse/powermeter/ni/cdaq9184_protocol.py +0 -48
- egse/powermeter/ni/cdaq9184_ui.py +0 -544
- egse/powermeter/thorlabs/__init__.py +0 -25
- egse/powermeter/thorlabs/pm100a.py +0 -380
- egse/powermeter/thorlabs/pm100a.yaml +0 -132
- egse/powermeter/thorlabs/pm100a_cs.py +0 -136
- egse/powermeter/thorlabs/pm100a_devif.py +0 -127
- egse/powermeter/thorlabs/pm100a_protocol.py +0 -80
- egse/powermeter/thorlabs/pm100a_ui.py +0 -725
- egse/process.py +0 -451
- egse/procman/__init__.py +0 -834
- egse/procman/cannot_start_process_popup.py +0 -43
- egse/procman/procman.yaml +0 -49
- egse/procman/procman_cs.py +0 -201
- egse/procman/procman_ui.py +0 -2081
- egse/protocol.py +0 -605
- egse/proxy.py +0 -531
- egse/randomwalk.py +0 -140
- egse/reg.py +0 -585
- egse/reload.py +0 -122
- egse/reprocess.py +0 -693
- egse/resource.py +0 -333
- egse/rmap.py +0 -406
- egse/rst.py +0 -135
- egse/search.py +0 -182
- egse/serialdevice.py +0 -190
- egse/services.py +0 -247
- egse/services.yaml +0 -68
- egse/settings.py +0 -379
- egse/settings.yaml +0 -980
- egse/setup.py +0 -1181
- egse/shutter/__init__.py +0 -0
- egse/shutter/thorlabs/__init__.py +0 -19
- egse/shutter/thorlabs/ksc101.py +0 -205
- egse/shutter/thorlabs/ksc101.yaml +0 -105
- egse/shutter/thorlabs/ksc101_cs.py +0 -136
- egse/shutter/thorlabs/ksc101_devif.py +0 -201
- egse/shutter/thorlabs/ksc101_protocol.py +0 -71
- egse/shutter/thorlabs/ksc101_ui.py +0 -548
- egse/shutter/thorlabs/sc10.py +0 -82
- egse/shutter/thorlabs/sc10.yaml +0 -52
- egse/shutter/thorlabs/sc10_controller.py +0 -81
- egse/shutter/thorlabs/sc10_cs.py +0 -108
- egse/shutter/thorlabs/sc10_interface.py +0 -25
- egse/shutter/thorlabs/sc10_simulator.py +0 -30
- egse/simulator.py +0 -41
- egse/slack.py +0 -61
- egse/socketdevice.py +0 -218
- egse/sockets.py +0 -218
- egse/spw.py +0 -1401
- egse/stages/__init__.py +0 -12
- egse/stages/aerotech/ensemble.py +0 -245
- egse/stages/aerotech/ensemble.yaml +0 -205
- egse/stages/aerotech/ensemble_controller.py +0 -275
- egse/stages/aerotech/ensemble_cs.py +0 -110
- egse/stages/aerotech/ensemble_interface.py +0 -132
- egse/stages/aerotech/ensemble_parameters.py +0 -433
- egse/stages/aerotech/ensemble_simulator.py +0 -27
- egse/stages/aerotech/mgse_sim.py +0 -188
- egse/stages/arun/smd3.py +0 -110
- egse/stages/arun/smd3.yaml +0 -68
- egse/stages/arun/smd3_controller.py +0 -470
- egse/stages/arun/smd3_cs.py +0 -112
- egse/stages/arun/smd3_interface.py +0 -53
- egse/stages/arun/smd3_simulator.py +0 -27
- egse/stages/arun/smd3_stop.py +0 -16
- egse/stages/huber/__init__.py +0 -49
- egse/stages/huber/smc9300.py +0 -920
- egse/stages/huber/smc9300.yaml +0 -63
- egse/stages/huber/smc9300_cs.py +0 -178
- egse/stages/huber/smc9300_devif.py +0 -345
- egse/stages/huber/smc9300_protocol.py +0 -113
- egse/stages/huber/smc9300_sim.py +0 -547
- egse/stages/huber/smc9300_ui.py +0 -973
- egse/state.py +0 -173
- egse/statemachine.py +0 -274
- egse/storage/__init__.py +0 -1067
- egse/storage/persistence.py +0 -2295
- egse/storage/storage.yaml +0 -79
- egse/storage/storage_cs.py +0 -231
- egse/styles/dark.qss +0 -343
- egse/styles/default.qss +0 -48
- egse/synoptics/__init__.py +0 -417
- egse/synoptics/syn.yaml +0 -9
- egse/synoptics/syn_cs.py +0 -195
- egse/system.py +0 -1611
- egse/tcs/__init__.py +0 -14
- egse/tcs/tcs.py +0 -879
- egse/tcs/tcs.yaml +0 -14
- egse/tcs/tcs_cs.py +0 -202
- egse/tcs/tcs_devif.py +0 -292
- egse/tcs/tcs_protocol.py +0 -180
- egse/tcs/tcs_sim.py +0 -177
- egse/tcs/tcs_ui.py +0 -543
- egse/tdms.py +0 -171
- egse/tempcontrol/__init__.py +0 -23
- egse/tempcontrol/agilent/agilent34970.py +0 -109
- egse/tempcontrol/agilent/agilent34970.yaml +0 -44
- egse/tempcontrol/agilent/agilent34970_cs.py +0 -114
- egse/tempcontrol/agilent/agilent34970_devif.py +0 -182
- egse/tempcontrol/agilent/agilent34970_protocol.py +0 -96
- egse/tempcontrol/agilent/agilent34972.py +0 -111
- egse/tempcontrol/agilent/agilent34972.yaml +0 -44
- egse/tempcontrol/agilent/agilent34972_cs.py +0 -115
- egse/tempcontrol/agilent/agilent34972_devif.py +0 -189
- egse/tempcontrol/agilent/agilent34972_protocol.py +0 -98
- egse/tempcontrol/beaglebone/beaglebone.py +0 -341
- egse/tempcontrol/beaglebone/beaglebone.yaml +0 -110
- egse/tempcontrol/beaglebone/beaglebone_cs.py +0 -117
- egse/tempcontrol/beaglebone/beaglebone_protocol.py +0 -134
- egse/tempcontrol/beaglebone/beaglebone_ui.py +0 -674
- egse/tempcontrol/digalox/digalox.py +0 -115
- egse/tempcontrol/digalox/digalox.yaml +0 -36
- egse/tempcontrol/digalox/digalox_cs.py +0 -108
- egse/tempcontrol/digalox/digalox_protocol.py +0 -56
- egse/tempcontrol/keithley/__init__.py +0 -33
- egse/tempcontrol/keithley/daq6510.py +0 -662
- egse/tempcontrol/keithley/daq6510.yaml +0 -105
- egse/tempcontrol/keithley/daq6510_cs.py +0 -163
- egse/tempcontrol/keithley/daq6510_devif.py +0 -343
- egse/tempcontrol/keithley/daq6510_protocol.py +0 -79
- egse/tempcontrol/keithley/daq6510_sim.py +0 -186
- egse/tempcontrol/lakeshore/__init__.py +0 -33
- egse/tempcontrol/lakeshore/lsci.py +0 -361
- egse/tempcontrol/lakeshore/lsci.yaml +0 -162
- egse/tempcontrol/lakeshore/lsci_cs.py +0 -174
- egse/tempcontrol/lakeshore/lsci_devif.py +0 -292
- egse/tempcontrol/lakeshore/lsci_protocol.py +0 -76
- egse/tempcontrol/lakeshore/lsci_ui.py +0 -387
- egse/tempcontrol/ni/__init__.py +0 -0
- egse/tempcontrol/spid/spid.py +0 -109
- egse/tempcontrol/spid/spid.yaml +0 -81
- egse/tempcontrol/spid/spid_controller.py +0 -279
- egse/tempcontrol/spid/spid_cs.py +0 -136
- egse/tempcontrol/spid/spid_protocol.py +0 -107
- egse/tempcontrol/spid/spid_ui.py +0 -723
- egse/tempcontrol/srs/__init__.py +0 -22
- egse/tempcontrol/srs/ptc10.py +0 -867
- egse/tempcontrol/srs/ptc10.yaml +0 -227
- egse/tempcontrol/srs/ptc10_cs.py +0 -128
- egse/tempcontrol/srs/ptc10_devif.py +0 -116
- egse/tempcontrol/srs/ptc10_protocol.py +0 -39
- egse/tempcontrol/srs/ptc10_ui.py +0 -906
- egse/ups/apc/apc.py +0 -236
- egse/ups/apc/apc.yaml +0 -45
- egse/ups/apc/apc_cs.py +0 -101
- egse/ups/apc/apc_protocol.py +0 -125
- egse/user.yaml +0 -7
- egse/vacuum/beaglebone/beaglebone.py +0 -149
- egse/vacuum/beaglebone/beaglebone.yaml +0 -44
- egse/vacuum/beaglebone/beaglebone_cs.py +0 -108
- egse/vacuum/beaglebone/beaglebone_devif.py +0 -159
- egse/vacuum/beaglebone/beaglebone_protocol.py +0 -192
- egse/vacuum/beaglebone/beaglebone_ui.py +0 -638
- egse/vacuum/instrutech/igm402.py +0 -91
- egse/vacuum/instrutech/igm402.yaml +0 -90
- egse/vacuum/instrutech/igm402_controller.py +0 -124
- egse/vacuum/instrutech/igm402_cs.py +0 -108
- egse/vacuum/instrutech/igm402_interface.py +0 -49
- egse/vacuum/instrutech/igm402_simulator.py +0 -36
- egse/vacuum/keller/kellerBus.py +0 -256
- egse/vacuum/keller/leo3.py +0 -100
- egse/vacuum/keller/leo3.yaml +0 -38
- egse/vacuum/keller/leo3_controller.py +0 -81
- egse/vacuum/keller/leo3_cs.py +0 -101
- egse/vacuum/keller/leo3_interface.py +0 -33
- egse/vacuum/mks/evision.py +0 -86
- egse/vacuum/mks/evision.yaml +0 -75
- egse/vacuum/mks/evision_cs.py +0 -101
- egse/vacuum/mks/evision_devif.py +0 -313
- egse/vacuum/mks/evision_interface.py +0 -60
- egse/vacuum/mks/evision_simulator.py +0 -24
- egse/vacuum/mks/evision_ui.py +0 -701
- egse/vacuum/pfeiffer/acp40.py +0 -87
- egse/vacuum/pfeiffer/acp40.yaml +0 -60
- egse/vacuum/pfeiffer/acp40_controller.py +0 -117
- egse/vacuum/pfeiffer/acp40_cs.py +0 -109
- egse/vacuum/pfeiffer/acp40_interface.py +0 -40
- egse/vacuum/pfeiffer/acp40_simulator.py +0 -37
- egse/vacuum/pfeiffer/tc400.py +0 -87
- egse/vacuum/pfeiffer/tc400.yaml +0 -83
- egse/vacuum/pfeiffer/tc400_controller.py +0 -136
- egse/vacuum/pfeiffer/tc400_cs.py +0 -109
- egse/vacuum/pfeiffer/tc400_interface.py +0 -70
- egse/vacuum/pfeiffer/tc400_simulator.py +0 -35
- egse/vacuum/pfeiffer/tpg261.py +0 -80
- egse/vacuum/pfeiffer/tpg261.yaml +0 -66
- egse/vacuum/pfeiffer/tpg261_controller.py +0 -150
- egse/vacuum/pfeiffer/tpg261_cs.py +0 -109
- egse/vacuum/pfeiffer/tpg261_interface.py +0 -59
- egse/vacuum/pfeiffer/tpg261_simulator.py +0 -23
- egse/version.py +0 -174
- egse/visitedpositions.py +0 -398
- egse/windowing.py +0 -213
- egse/zmq/__init__.py +0 -28
- egse/zmq/spw.py +0 -160
- egse/zmq_ser.py +0 -41
- scripts/alerts/cold.yaml +0 -278
- scripts/alerts/example_alerts.yaml +0 -54
- scripts/alerts/transition.yaml +0 -14
- scripts/alerts/warm.yaml +0 -49
- scripts/analyse_n_fee_hk_data.py +0 -52
- scripts/check_hdf5_files.py +0 -192
- scripts/check_register_sync.py +0 -47
- scripts/check_tcs_calib_coef.py +0 -90
- scripts/correct_ccd_cold_temperature_cal.py +0 -157
- scripts/create_hdf5_report.py +0 -293
- scripts/csl_model.py +0 -420
- scripts/csl_restore_setup.py +0 -229
- scripts/export-grafana-dashboards.py +0 -49
- scripts/fdir/cs_recovery/fdir_cs_recovery.py +0 -54
- scripts/fdir/fdir_table.yaml +0 -70
- scripts/fdir/fdir_test_recovery.py +0 -10
- scripts/fdir/hw_recovery/fdir_agilent_hw_recovery.py +0 -73
- scripts/fdir/limit_recovery/fdir_agilent_limit.py +0 -61
- scripts/fdir/limit_recovery/fdir_bb_heater_limit.py +0 -59
- scripts/fdir/limit_recovery/fdir_ensemble_limit.py +0 -33
- scripts/fdir/limit_recovery/fdir_pressure_limit_recovery.py +0 -71
- scripts/fix_csv.py +0 -80
- scripts/ias/correct_ccd_temp_cal_elfique.py +0 -43
- scripts/ias/correct_ccd_temp_cal_floreffe.py +0 -43
- scripts/ias/correct_trp_swap_achel.py +0 -199
- scripts/inta/correct_ccd_temp_cal_duvel.py +0 -43
- scripts/inta/correct_ccd_temp_cal_gueuze.py +0 -43
- scripts/n_fee_supply_voltage_calculation.py +0 -92
- scripts/playground.py +0 -30
- scripts/print_hdf5_hk_data.py +0 -68
- scripts/print_register_map.py +0 -43
- scripts/remove_lines_between_matches.py +0 -188
- scripts/sron/commanding/control_heaters.py +0 -44
- scripts/sron/commanding/pumpdown.py +0 -46
- scripts/sron/commanding/set_pid_setpoint.py +0 -19
- scripts/sron/commanding/shutdown_bbb_heaters.py +0 -10
- scripts/sron/commanding/shutdown_pumps.py +0 -33
- scripts/sron/correct_mgse_coordinates_brigand_chimay.py +0 -272
- scripts/sron/correct_trp_swap_brigand.py +0 -204
- scripts/sron/gimbal_conversions.py +0 -75
- scripts/sron/tm_gen/tm_gen_agilent.py +0 -37
- scripts/sron/tm_gen/tm_gen_heaters.py +0 -4
- scripts/sron/tm_gen/tm_gen_spid.py +0 -13
- scripts/update_operational_cgse.py +0 -268
- scripts/update_operational_cgse_old.py +0 -273
|
@@ -1,1521 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from typing import Dict
|
|
3
|
-
from typing import List
|
|
4
|
-
from typing import Optional
|
|
5
|
-
from typing import Union
|
|
6
|
-
|
|
7
|
-
from PyQt5.QtCore import QEvent
|
|
8
|
-
from PyQt5.QtCore import QSize
|
|
9
|
-
from PyQt5.QtCore import QTimer
|
|
10
|
-
from PyQt5.QtCore import Qt
|
|
11
|
-
from PyQt5.QtGui import QIcon
|
|
12
|
-
from PyQt5.QtGui import QPixmap
|
|
13
|
-
from PyQt5.QtWidgets import QAction
|
|
14
|
-
from PyQt5.QtWidgets import QComboBox
|
|
15
|
-
from PyQt5.QtWidgets import QFrame
|
|
16
|
-
from PyQt5.QtWidgets import QGroupBox
|
|
17
|
-
from PyQt5.QtWidgets import QHBoxLayout
|
|
18
|
-
from PyQt5.QtWidgets import QLabel
|
|
19
|
-
from PyQt5.QtWidgets import QLineEdit
|
|
20
|
-
from PyQt5.QtWidgets import QMainWindow
|
|
21
|
-
from PyQt5.QtWidgets import QPushButton
|
|
22
|
-
from PyQt5.QtWidgets import QSizePolicy
|
|
23
|
-
from PyQt5.QtWidgets import QTabWidget
|
|
24
|
-
from PyQt5.QtWidgets import QVBoxLayout
|
|
25
|
-
from PyQt5.QtWidgets import QWidget
|
|
26
|
-
|
|
27
|
-
from egse.decorators import deprecate
|
|
28
|
-
from egse.gui import show_warning_message
|
|
29
|
-
from egse.gui.buttons import ToggleButton
|
|
30
|
-
from egse.gui.buttons import TouchButton
|
|
31
|
-
from egse.gui.led import LED
|
|
32
|
-
from egse.gui.led import ShapeEnum
|
|
33
|
-
from egse.help.help_ui import HELP_TOPICS
|
|
34
|
-
from egse.help.help_ui import HelpWindow
|
|
35
|
-
from egse.observer import Observable
|
|
36
|
-
from egse.observer import Observer
|
|
37
|
-
from egse.resource import get_resource
|
|
38
|
-
from egse.state import UnknownStateError
|
|
39
|
-
|
|
40
|
-
MODULE_LOGGER = logging.getLogger(__name__)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class VLine(QFrame):
|
|
44
|
-
"""Presents a simple Vertical Bar that can be used in e.g. the status bar."""
|
|
45
|
-
|
|
46
|
-
def __init__(self):
|
|
47
|
-
super().__init__()
|
|
48
|
-
self.setFrameShape(self.VLine | self.Sunken)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class Container(QWidget):
|
|
52
|
-
"""
|
|
53
|
-
An empty container that is used currently as a place-holder for a QWidget that is to be
|
|
54
|
-
implemented.
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
def __init__(self, text):
|
|
58
|
-
super().__init__()
|
|
59
|
-
|
|
60
|
-
self.hbox = QHBoxLayout()
|
|
61
|
-
self.hbox.setSpacing(0)
|
|
62
|
-
self.hbox.setContentsMargins(0, 0, 0, 0)
|
|
63
|
-
self.setLayout(self.hbox)
|
|
64
|
-
|
|
65
|
-
self.button = QPushButton(text)
|
|
66
|
-
self.hbox.addWidget(self.button)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class ValidationIcon(QWidget):
|
|
70
|
-
"""
|
|
71
|
-
This Icon is used
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
def __init__(self):
|
|
75
|
-
super().__init__()
|
|
76
|
-
|
|
77
|
-
self._valid = QPixmap(str(get_resource(":/icons/valid.png")))
|
|
78
|
-
self._invalid = QPixmap(str(get_resource(":/icons/invalid.png")))
|
|
79
|
-
self._disabled = QPixmap(str(get_resource(":/icons/unvalid.png")))
|
|
80
|
-
|
|
81
|
-
self._label = QLabel()
|
|
82
|
-
|
|
83
|
-
self.disable()
|
|
84
|
-
|
|
85
|
-
hbox = QHBoxLayout()
|
|
86
|
-
hbox.setSpacing(0)
|
|
87
|
-
hbox.setContentsMargins(0, 0, 0, 0)
|
|
88
|
-
hbox.addWidget(self._label)
|
|
89
|
-
|
|
90
|
-
self.setLayout(hbox)
|
|
91
|
-
|
|
92
|
-
def eventFilter(self, source, event):
|
|
93
|
-
if event.type() == QEvent.FocusOut:
|
|
94
|
-
self.disable()
|
|
95
|
-
return True
|
|
96
|
-
|
|
97
|
-
def validate(self):
|
|
98
|
-
self._label.setPixmap(self._valid)
|
|
99
|
-
|
|
100
|
-
def invalidate(self):
|
|
101
|
-
self._label.setPixmap(self._invalid)
|
|
102
|
-
|
|
103
|
-
def disable(self):
|
|
104
|
-
self._label.setPixmap(self._disabled)
|
|
105
|
-
self._label.setToolTip("No validation was performed.")
|
|
106
|
-
|
|
107
|
-
def setToolTip(self, message: str) -> None:
|
|
108
|
-
self._label.setToolTip(message)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class Positioning(QWidget):
|
|
112
|
-
"""
|
|
113
|
-
The Positioning widget which allows to manually command the Gimbal to a certain position,
|
|
114
|
-
absolute or relative.
|
|
115
|
-
"""
|
|
116
|
-
|
|
117
|
-
def __init__(self, view, observable):
|
|
118
|
-
super().__init__()
|
|
119
|
-
self.observable = observable
|
|
120
|
-
self.view = view
|
|
121
|
-
|
|
122
|
-
# initialize instance variables used by this class
|
|
123
|
-
|
|
124
|
-
self.manual_mode: QGroupBox = None
|
|
125
|
-
self.manual_mode_positions_widget: QFrame = None
|
|
126
|
-
self.manual_mode_positions: List = None
|
|
127
|
-
|
|
128
|
-
self.combo_absolute_relative: QComboBox = None
|
|
129
|
-
|
|
130
|
-
self.validate_label = None
|
|
131
|
-
|
|
132
|
-
self.specific_positions: QGroupBox = None
|
|
133
|
-
self.specific_positions_widget: QFrame = None
|
|
134
|
-
|
|
135
|
-
self.init_gui()
|
|
136
|
-
|
|
137
|
-
def init_gui(self):
|
|
138
|
-
"""Initialize the main user interface for this component."""
|
|
139
|
-
|
|
140
|
-
# Setup the Manual Mode GroupBox widget
|
|
141
|
-
|
|
142
|
-
hbox = QHBoxLayout()
|
|
143
|
-
|
|
144
|
-
self.manual_mode = QGroupBox("Manual Mode")
|
|
145
|
-
self.manual_mode.setLayout(hbox)
|
|
146
|
-
self.manual_mode.setObjectName("ManualModeGroupBox")
|
|
147
|
-
|
|
148
|
-
self.manual_mode_positions_widget = self.create_manual_mode_position_widget()
|
|
149
|
-
|
|
150
|
-
hbox.addWidget(self.manual_mode_positions_widget)
|
|
151
|
-
|
|
152
|
-
# Setup the Specific Positions GroupBox widget
|
|
153
|
-
|
|
154
|
-
hbox = QHBoxLayout()
|
|
155
|
-
|
|
156
|
-
self.specific_positions = QGroupBox("Specific Positions")
|
|
157
|
-
self.specific_positions.setLayout(hbox)
|
|
158
|
-
self.manual_mode.setObjectName("SpecificPositionsGroupBox")
|
|
159
|
-
|
|
160
|
-
self.specific_positions_widget = self.create_specific_positions_widget()
|
|
161
|
-
|
|
162
|
-
hbox.addWidget(self.specific_positions_widget)
|
|
163
|
-
|
|
164
|
-
# Finally, within the Positions widget, a VBoxLayout holds the manual mode and the
|
|
165
|
-
# specific positions widgets.
|
|
166
|
-
|
|
167
|
-
vbox = QVBoxLayout()
|
|
168
|
-
|
|
169
|
-
vbox.addWidget(self.manual_mode)
|
|
170
|
-
vbox.addWidget(self.specific_positions)
|
|
171
|
-
|
|
172
|
-
self.setLayout(vbox)
|
|
173
|
-
|
|
174
|
-
def create_specific_positions_widget(self):
|
|
175
|
-
hbox = QHBoxLayout()
|
|
176
|
-
|
|
177
|
-
self.combo_specific_position = QComboBox()
|
|
178
|
-
self.combo_specific_position.addItems(["User ZERO"])
|
|
179
|
-
self.combo_specific_position.setMinimumContentsLength(18)
|
|
180
|
-
self.combo_specific_position.adjustSize()
|
|
181
|
-
|
|
182
|
-
self.move_to_button = QPushButton("Move To")
|
|
183
|
-
self.move_to_button.setToolTip(
|
|
184
|
-
"Move to the specific position that is selected in the combobox."
|
|
185
|
-
"<ul>"
|
|
186
|
-
"<li><strong>ZERO</strong> moves Rx and Ry to user position 0.0"
|
|
187
|
-
"</ul>"
|
|
188
|
-
)
|
|
189
|
-
self.move_to_button.clicked.connect(self.handle_move_to_specific_position)
|
|
190
|
-
|
|
191
|
-
hbox.addWidget(self.combo_specific_position)
|
|
192
|
-
hbox.addWidget(self.move_to_button)
|
|
193
|
-
|
|
194
|
-
frame = QFrame()
|
|
195
|
-
frame.setObjectName("SpecificPositions")
|
|
196
|
-
frame.setLayout(hbox)
|
|
197
|
-
|
|
198
|
-
return frame
|
|
199
|
-
|
|
200
|
-
def create_manual_mode_position_widget(self) -> QFrame:
|
|
201
|
-
"""Creates the internal frame for the manual mode box."""
|
|
202
|
-
|
|
203
|
-
vbox = QVBoxLayout()
|
|
204
|
-
|
|
205
|
-
self.manual_mode_positions = [
|
|
206
|
-
[QLabel("Rx"), QLineEdit(), QLabel("deg")],
|
|
207
|
-
[QLabel("Ry"), QLineEdit(), QLabel("deg")],
|
|
208
|
-
]
|
|
209
|
-
|
|
210
|
-
for mm_pos in self.manual_mode_positions:
|
|
211
|
-
hbox = QHBoxLayout()
|
|
212
|
-
hbox.addWidget(mm_pos[0])
|
|
213
|
-
hbox.addWidget(mm_pos[1])
|
|
214
|
-
hbox.addWidget(mm_pos[2])
|
|
215
|
-
mm_pos[0].setMinimumWidth(20)
|
|
216
|
-
mm_pos[1].setText("0.0000")
|
|
217
|
-
mm_pos[1].setStyleSheet("QLabel { background-color : LightGray; }")
|
|
218
|
-
mm_pos[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
219
|
-
mm_pos[1].setMinimumWidth(50)
|
|
220
|
-
vbox.addLayout(hbox)
|
|
221
|
-
|
|
222
|
-
# Add the two buttons, (1) Copy, and (2) Clear
|
|
223
|
-
|
|
224
|
-
hbox = QHBoxLayout()
|
|
225
|
-
|
|
226
|
-
copy_button = QPushButton("Copy")
|
|
227
|
-
copy_button.setToolTip("Copy the positions from Object [in User].")
|
|
228
|
-
copy_button.clicked.connect(self.handle_copy_positions)
|
|
229
|
-
|
|
230
|
-
clear_button = QPushButton("Clear")
|
|
231
|
-
clear_button.setToolTip("Clear the input fields.")
|
|
232
|
-
clear_button.clicked.connect(self.handle_clear_inputs)
|
|
233
|
-
|
|
234
|
-
hbox.addWidget(copy_button)
|
|
235
|
-
hbox.addStretch()
|
|
236
|
-
hbox.addWidget(clear_button)
|
|
237
|
-
|
|
238
|
-
vbox.addLayout(hbox)
|
|
239
|
-
|
|
240
|
-
# Make sure the hboxes defined above stay nicely together when vertically resizing the
|
|
241
|
-
# Frame.
|
|
242
|
-
|
|
243
|
-
vbox.addStretch()
|
|
244
|
-
|
|
245
|
-
# Add the QComboBox to select either absolute or relative movement
|
|
246
|
-
|
|
247
|
-
hbox = QHBoxLayout()
|
|
248
|
-
|
|
249
|
-
self.combo_absolute_relative = QComboBox()
|
|
250
|
-
self.combo_absolute_relative.addItems(["Absolute", "Relative"])
|
|
251
|
-
self.combo_absolute_relative.setMinimumContentsLength(15)
|
|
252
|
-
self.combo_absolute_relative.adjustSize()
|
|
253
|
-
|
|
254
|
-
self.move_button = QPushButton("Move")
|
|
255
|
-
self.move_button.setToolTip(
|
|
256
|
-
"When you press this button, the Gimbal will start moving \n"
|
|
257
|
-
"to the position you have given in manual mode above.\n"
|
|
258
|
-
"Depending on the control setting, the movement will be absolute or relative."
|
|
259
|
-
)
|
|
260
|
-
self.move_button.clicked.connect(self.handle_movement)
|
|
261
|
-
|
|
262
|
-
hbox.addWidget(self.combo_absolute_relative)
|
|
263
|
-
hbox.addWidget(self.move_button)
|
|
264
|
-
|
|
265
|
-
vbox.addLayout(hbox)
|
|
266
|
-
|
|
267
|
-
# Add the two buttons, (1) Move, and (2) Validate Movement.
|
|
268
|
-
|
|
269
|
-
hbox = QHBoxLayout()
|
|
270
|
-
|
|
271
|
-
self.validate_button = QPushButton("Validate Movement...")
|
|
272
|
-
self.validate_button.setToolTip(
|
|
273
|
-
"When you press this button, the Gimbal controller will validate the input position "
|
|
274
|
-
"in manual mode.\n"
|
|
275
|
-
"Depending on the control setting, the movement will be absolute or relative."
|
|
276
|
-
)
|
|
277
|
-
self.validate_button.clicked.connect(self.handle_validate)
|
|
278
|
-
|
|
279
|
-
self.validate_label = ValidationIcon()
|
|
280
|
-
self.validate_label.installEventFilter(self.validate_label)
|
|
281
|
-
|
|
282
|
-
hbox.addWidget(self.validate_label)
|
|
283
|
-
hbox.addWidget(self.validate_button)
|
|
284
|
-
|
|
285
|
-
vbox.addLayout(hbox)
|
|
286
|
-
|
|
287
|
-
frame = QFrame()
|
|
288
|
-
frame.setObjectName("ManualPositions")
|
|
289
|
-
frame.setLayout(vbox)
|
|
290
|
-
|
|
291
|
-
return frame
|
|
292
|
-
|
|
293
|
-
def disable_movement(self):
|
|
294
|
-
self.move_button.setDisabled(True)
|
|
295
|
-
self.move_to_button.setDisabled(True)
|
|
296
|
-
self.validate_button.setDisabled(True)
|
|
297
|
-
|
|
298
|
-
def enable_movement(self):
|
|
299
|
-
self.move_button.setEnabled(True)
|
|
300
|
-
self.move_to_button.setEnabled(True)
|
|
301
|
-
self.validate_button.setEnabled(True)
|
|
302
|
-
|
|
303
|
-
def set_position_validation_icon(self, error_codes, tooltip: str = None):
|
|
304
|
-
|
|
305
|
-
if error_codes:
|
|
306
|
-
self.validate_label.setFocus()
|
|
307
|
-
self.validate_label.invalidate()
|
|
308
|
-
self.validate_label.setToolTip(format_tooltip(tooltip or error_codes))
|
|
309
|
-
else:
|
|
310
|
-
self.validate_label.setFocus()
|
|
311
|
-
self.validate_label.validate()
|
|
312
|
-
self.validate_label.setToolTip("Movement command is valid.")
|
|
313
|
-
|
|
314
|
-
def get_manual_inputs(self):
|
|
315
|
-
"""Returns the input positions as a list of floats."""
|
|
316
|
-
try:
|
|
317
|
-
pos = [
|
|
318
|
-
float(mm_pos[1].text().replace(",", ".")) for mm_pos in self.manual_mode_positions
|
|
319
|
-
]
|
|
320
|
-
except ValueError as exc:
|
|
321
|
-
MODULE_LOGGER.error(f"Incorrect manual position input given: {exc}")
|
|
322
|
-
|
|
323
|
-
description = "Input errors in manual positions"
|
|
324
|
-
info_text = (
|
|
325
|
-
"Some of the values that you have filled into the manual position fields are "
|
|
326
|
-
"invalid. The fields can only contain floating point numbers, both '.' and ',"
|
|
327
|
-
"' are allowed."
|
|
328
|
-
)
|
|
329
|
-
show_warning_message(description, info_text)
|
|
330
|
-
|
|
331
|
-
return None
|
|
332
|
-
|
|
333
|
-
return pos
|
|
334
|
-
|
|
335
|
-
def handle_move_to_specific_position(self):
|
|
336
|
-
|
|
337
|
-
# Check which movement was requested
|
|
338
|
-
|
|
339
|
-
selected_text = self.combo_specific_position.currentText()
|
|
340
|
-
if "ZERO" in selected_text:
|
|
341
|
-
action = "goto_zero_position"
|
|
342
|
-
self.observable.actionObservers({action: 2})
|
|
343
|
-
else:
|
|
344
|
-
logging.warning(f"Unknown specific position ({selected_text})")
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
def handle_movement(self):
|
|
349
|
-
# Read out the values in manual mode into an array of floats
|
|
350
|
-
# Users may use comma or point as a decimal delimiter
|
|
351
|
-
|
|
352
|
-
pos = self.get_manual_inputs()
|
|
353
|
-
if pos is None:
|
|
354
|
-
return
|
|
355
|
-
|
|
356
|
-
# Check which movement was requested
|
|
357
|
-
|
|
358
|
-
selected_text = self.combo_absolute_relative.currentText()
|
|
359
|
-
if selected_text == "Absolute":
|
|
360
|
-
movement = "move_absolute"
|
|
361
|
-
elif selected_text == "Relative":
|
|
362
|
-
movement = "move_relative"
|
|
363
|
-
|
|
364
|
-
self.observable.actionObservers({movement: pos})
|
|
365
|
-
|
|
366
|
-
def handle_validate(self):
|
|
367
|
-
pos = self.get_manual_inputs()
|
|
368
|
-
if pos is None:
|
|
369
|
-
return
|
|
370
|
-
|
|
371
|
-
# Check which movement was requested
|
|
372
|
-
|
|
373
|
-
selected_text = self.combo_absolute_relative.currentText()
|
|
374
|
-
if selected_text == "Absolute":
|
|
375
|
-
validation = "check_absolute_movement"
|
|
376
|
-
elif selected_text == "Relative":
|
|
377
|
-
validation = "check_relative_movement"
|
|
378
|
-
|
|
379
|
-
self.observable.actionObservers({validation: pos})
|
|
380
|
-
|
|
381
|
-
def handle_copy_positions(self):
|
|
382
|
-
for pos, mm_pos in zip(self.view.user_positions, self.manual_mode_positions):
|
|
383
|
-
mm_pos[1].setText(pos[1].text())
|
|
384
|
-
|
|
385
|
-
self.validate_label.disable()
|
|
386
|
-
self.manual_mode_positions_widget.repaint()
|
|
387
|
-
|
|
388
|
-
def handle_clear_inputs(self):
|
|
389
|
-
for mm_pos in self.manual_mode_positions:
|
|
390
|
-
mm_pos[1].setText("0.0000")
|
|
391
|
-
|
|
392
|
-
self.validate_label.disable()
|
|
393
|
-
self.manual_mode_positions_widget.repaint()
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
class SpeedSettings(QWidget):
|
|
397
|
-
|
|
398
|
-
def __init__(self, view, observable):
|
|
399
|
-
super().__init__()
|
|
400
|
-
self.observable = observable
|
|
401
|
-
self.view = view
|
|
402
|
-
|
|
403
|
-
self.set_speed_widget: Optional[QGroupBox] = None
|
|
404
|
-
self.set_speed_widget = self.create_set_speed_widget()
|
|
405
|
-
|
|
406
|
-
vbox = QVBoxLayout()
|
|
407
|
-
|
|
408
|
-
hbox = QHBoxLayout()
|
|
409
|
-
hbox.addWidget(self.set_speed_widget)
|
|
410
|
-
hbox.addStretch()
|
|
411
|
-
|
|
412
|
-
# Add the Fetch and Apply for the Speed to the HBOX here
|
|
413
|
-
|
|
414
|
-
vbox_speed = QVBoxLayout()
|
|
415
|
-
|
|
416
|
-
fetch_button = QPushButton("Fetch")
|
|
417
|
-
fetch_button.setToolTip("Fetch speed settings from the Controller.")
|
|
418
|
-
fetch_button.clicked.connect(self.handle_fetch_speed_settings)
|
|
419
|
-
|
|
420
|
-
apply_button = QPushButton("Apply")
|
|
421
|
-
apply_button.setToolTip("Apply BOTH speed settings to the Controller.")
|
|
422
|
-
apply_button.clicked.connect(self.handle_apply_speed_settings)
|
|
423
|
-
|
|
424
|
-
vbox_speed.addWidget(fetch_button)
|
|
425
|
-
vbox_speed.addWidget(apply_button)
|
|
426
|
-
|
|
427
|
-
hbox.addLayout(vbox_speed)
|
|
428
|
-
|
|
429
|
-
vbox.addLayout(hbox)
|
|
430
|
-
|
|
431
|
-
self.setLayout(vbox)
|
|
432
|
-
|
|
433
|
-
def create_set_speed_widget(self):
|
|
434
|
-
"""Creates the widget for the user set/get speed box."""
|
|
435
|
-
|
|
436
|
-
vbox = QVBoxLayout()
|
|
437
|
-
|
|
438
|
-
self.user_set_speed = [
|
|
439
|
-
[QLabel("Rotation Speed (sr): "), QLineEdit(), QLabel("°/s")]]
|
|
440
|
-
|
|
441
|
-
for speed in self.user_set_speed:
|
|
442
|
-
hbox = QHBoxLayout()
|
|
443
|
-
hbox.addWidget(speed[0])
|
|
444
|
-
hbox.addWidget(speed[1])
|
|
445
|
-
hbox.setSpacing(0)
|
|
446
|
-
hbox.addWidget(speed[2])
|
|
447
|
-
speed[0].setMinimumWidth(150)
|
|
448
|
-
speed[1].setText("0.0000")
|
|
449
|
-
speed[1].setStyleSheet("QLabel { background-color : LightGray; }")
|
|
450
|
-
speed[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
451
|
-
speed[1].setFixedWidth(100)
|
|
452
|
-
vbox.addLayout(hbox)
|
|
453
|
-
|
|
454
|
-
gbox_set_speed = QGroupBox("Set Speed parameters", self)
|
|
455
|
-
gbox_set_speed.setLayout(vbox)
|
|
456
|
-
|
|
457
|
-
return gbox_set_speed
|
|
458
|
-
|
|
459
|
-
def get_speed_settings_input(self):
|
|
460
|
-
|
|
461
|
-
sr = float(self.user_set_speed[0][1].text())
|
|
462
|
-
|
|
463
|
-
return sr
|
|
464
|
-
|
|
465
|
-
def set_speed(self, sr):
|
|
466
|
-
self.user_set_speed[0][1].setText(str(sr))
|
|
467
|
-
self.set_speed_widget.repaint()
|
|
468
|
-
|
|
469
|
-
def handle_apply_speed_settings(self):
|
|
470
|
-
|
|
471
|
-
# Read out the values in the speed settings group
|
|
472
|
-
|
|
473
|
-
sr = self.get_speed_settings_input()
|
|
474
|
-
|
|
475
|
-
self.observable.actionObservers({"set_speed": (sr)})
|
|
476
|
-
|
|
477
|
-
def handle_fetch_speed_settings(self):
|
|
478
|
-
|
|
479
|
-
self.observable.actionObservers({"fetch_speed": True})
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
class GimbalOffsets(QWidget):
|
|
483
|
-
"""This Widget allow to set the Gimbal offsets."""
|
|
484
|
-
|
|
485
|
-
def __init__(self, view, observable):
|
|
486
|
-
super().__init__()
|
|
487
|
-
self.observable = observable
|
|
488
|
-
self.view = view
|
|
489
|
-
|
|
490
|
-
# initialize instance variables used by this class
|
|
491
|
-
|
|
492
|
-
self.offsets_widget: QGroupBox = None
|
|
493
|
-
self.offsets: List = None
|
|
494
|
-
|
|
495
|
-
self.init_gui()
|
|
496
|
-
|
|
497
|
-
def init_gui(self):
|
|
498
|
-
"""Initialize the main interface for this component."""
|
|
499
|
-
|
|
500
|
-
vbox = QVBoxLayout()
|
|
501
|
-
|
|
502
|
-
self.offsets_widget = self.create_offsets_widget()
|
|
503
|
-
|
|
504
|
-
vbox_icons = QVBoxLayout()
|
|
505
|
-
vbox_icons.addStretch()
|
|
506
|
-
|
|
507
|
-
hbox = QHBoxLayout()
|
|
508
|
-
|
|
509
|
-
hbox.addWidget(self.offsets_widget)
|
|
510
|
-
hbox.addLayout(vbox_icons)
|
|
511
|
-
|
|
512
|
-
vbox.addLayout(hbox)
|
|
513
|
-
|
|
514
|
-
apply_button = QPushButton("Apply")
|
|
515
|
-
apply_button.setToolTip("Apply the Coordinates Systems to the Controller.")
|
|
516
|
-
apply_button.clicked.connect(self.handle_apply_offsets)
|
|
517
|
-
|
|
518
|
-
fetch_button = QPushButton("Fetch")
|
|
519
|
-
fetch_button.setToolTip("Fetch the Coordinates Systems from the Controller.")
|
|
520
|
-
fetch_button.clicked.connect(self.handle_fetch_offsets)
|
|
521
|
-
|
|
522
|
-
hbox = QHBoxLayout()
|
|
523
|
-
hbox.addWidget(fetch_button)
|
|
524
|
-
hbox.addStretch()
|
|
525
|
-
hbox.addWidget(apply_button)
|
|
526
|
-
vbox.addLayout(hbox)
|
|
527
|
-
|
|
528
|
-
vbox.addStretch(1)
|
|
529
|
-
|
|
530
|
-
self.setLayout(vbox)
|
|
531
|
-
|
|
532
|
-
def set_offsets(self, offsets):
|
|
533
|
-
for usr, value in zip(self.offsets, offsets):
|
|
534
|
-
usr[1].setText(str(value))
|
|
535
|
-
self.offsets_widget.repaint()
|
|
536
|
-
|
|
537
|
-
def create_offsets_widget(self) -> QWidget:
|
|
538
|
-
"""Creates the widget for the gimbal offsets in the user reference system."""
|
|
539
|
-
|
|
540
|
-
vbox = QVBoxLayout()
|
|
541
|
-
|
|
542
|
-
self.offsets = [
|
|
543
|
-
[QLabel("Rx"), QLineEdit(), QLabel("deg")],
|
|
544
|
-
[QLabel("Ry"), QLineEdit(), QLabel("deg")],
|
|
545
|
-
]
|
|
546
|
-
|
|
547
|
-
for mm_pos in self.offsets:
|
|
548
|
-
hbox = QHBoxLayout()
|
|
549
|
-
hbox.addWidget(mm_pos[0])
|
|
550
|
-
hbox.addWidget(mm_pos[1])
|
|
551
|
-
hbox.addWidget(mm_pos[2])
|
|
552
|
-
mm_pos[0].setMinimumWidth(20)
|
|
553
|
-
mm_pos[1].setText("0.0000")
|
|
554
|
-
mm_pos[1].setStyleSheet("QLabel { background-color : LightGray; }")
|
|
555
|
-
mm_pos[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
556
|
-
mm_pos[1].setMinimumWidth(50)
|
|
557
|
-
vbox.addLayout(hbox)
|
|
558
|
-
|
|
559
|
-
# Make sure the hboxes defined above stay nicely together when vertically resizing the
|
|
560
|
-
# Frame.
|
|
561
|
-
|
|
562
|
-
# vbox.addStretch()
|
|
563
|
-
|
|
564
|
-
gbox_offsets = QGroupBox("Gimbal offsets", self)
|
|
565
|
-
gbox_offsets.setLayout(vbox)
|
|
566
|
-
gbox_offsets.setToolTip("The gimbal offsets for user positions")
|
|
567
|
-
|
|
568
|
-
return gbox_offsets
|
|
569
|
-
|
|
570
|
-
def get_offsets_inputs(self):
|
|
571
|
-
"""Returns the GUI offsets as a list of 2 floats.
|
|
572
|
-
|
|
573
|
-
Returns:
|
|
574
|
-
A list containing two floats, the first corresponding to the offset
|
|
575
|
-
of the X axis, the second corresponding to the offset of the Y axis.
|
|
576
|
-
"""
|
|
577
|
-
try:
|
|
578
|
-
offsets = [
|
|
579
|
-
float(pos[1].text().replace(",", ".")) for pos in self.offsets
|
|
580
|
-
]
|
|
581
|
-
except ValueError as exc:
|
|
582
|
-
MODULE_LOGGER.error(
|
|
583
|
-
f"Incorrect manual input given for gimbal offsets" f": {exc}"
|
|
584
|
-
)
|
|
585
|
-
|
|
586
|
-
description = "Input errors for gimbal offsets"
|
|
587
|
-
info_text = (
|
|
588
|
-
"Some of the values that you have filled into the fields for the gimbal "
|
|
589
|
-
"offsets are invalid. The fields can only contain floating point numbers, "
|
|
590
|
-
"both '.' and ',' are allowed."
|
|
591
|
-
)
|
|
592
|
-
show_warning_message(description, info_text)
|
|
593
|
-
|
|
594
|
-
return None, None
|
|
595
|
-
|
|
596
|
-
return offsets
|
|
597
|
-
|
|
598
|
-
def handle_apply_offsets(self):
|
|
599
|
-
|
|
600
|
-
# Read out the values in manual mode into an array of floats
|
|
601
|
-
# Users may use comma or point as a decimal delimiter
|
|
602
|
-
|
|
603
|
-
offsets = self.get_offsets_inputs()
|
|
604
|
-
if offsets is None:
|
|
605
|
-
return
|
|
606
|
-
|
|
607
|
-
self.observable.actionObservers({"configure_offsets": (offsets)})
|
|
608
|
-
|
|
609
|
-
def handle_fetch_offsets(self):
|
|
610
|
-
|
|
611
|
-
self.observable.actionObservers({"fetch_offsets": True})
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
class MotorTemperatures(QWidget):
|
|
615
|
-
"""This Widget allows to monitor Gimbal motor tempertures."""
|
|
616
|
-
|
|
617
|
-
def __init__(self, view, observable):
|
|
618
|
-
super().__init__()
|
|
619
|
-
self.observable = observable
|
|
620
|
-
self.view = view
|
|
621
|
-
|
|
622
|
-
# initialize instance variables used by this class
|
|
623
|
-
|
|
624
|
-
self.temps_widget: QGroupBox = None
|
|
625
|
-
self.motors: List = None
|
|
626
|
-
|
|
627
|
-
self.init_gui()
|
|
628
|
-
|
|
629
|
-
def init_gui(self):
|
|
630
|
-
"""Initialize the main interface for this component."""
|
|
631
|
-
|
|
632
|
-
vbox = QVBoxLayout()
|
|
633
|
-
|
|
634
|
-
self.temps_widget = self.create_temps_widget()
|
|
635
|
-
|
|
636
|
-
vbox_icons = QVBoxLayout()
|
|
637
|
-
vbox_icons.addStretch()
|
|
638
|
-
|
|
639
|
-
hbox = QHBoxLayout()
|
|
640
|
-
|
|
641
|
-
hbox.addWidget(self.temps_widget)
|
|
642
|
-
hbox.addLayout(vbox_icons)
|
|
643
|
-
|
|
644
|
-
vbox.addLayout(hbox)
|
|
645
|
-
|
|
646
|
-
fetch_button = QPushButton("Fetch")
|
|
647
|
-
fetch_button.setToolTip("Fetch the current temperatures.")
|
|
648
|
-
fetch_button.clicked.connect(self.handle_fetch_temperatures)
|
|
649
|
-
|
|
650
|
-
hbox = QHBoxLayout()
|
|
651
|
-
hbox.addWidget(fetch_button)
|
|
652
|
-
hbox.addStretch()
|
|
653
|
-
vbox.addLayout(hbox)
|
|
654
|
-
|
|
655
|
-
vbox.addStretch(1)
|
|
656
|
-
|
|
657
|
-
self.setLayout(vbox)
|
|
658
|
-
|
|
659
|
-
def set_temperatures(self, temps):
|
|
660
|
-
if temps is None or len(temps) != 2:
|
|
661
|
-
for idx, mtemp in enumerate(self.motors):
|
|
662
|
-
mtemp[1].setText(fr'N/A')
|
|
663
|
-
else:
|
|
664
|
-
for idx, mtemp in enumerate(self.motors):
|
|
665
|
-
mtemp[1].setText(fr'{temps[idx]:.2f}')
|
|
666
|
-
self.temps_widget.repaint()
|
|
667
|
-
|
|
668
|
-
def create_temps_widget(self) -> QWidget:
|
|
669
|
-
"""Creates the widget for the Gimbal motor temperatures."""
|
|
670
|
-
|
|
671
|
-
vbox = QVBoxLayout()
|
|
672
|
-
|
|
673
|
-
self.motors = [
|
|
674
|
-
[QLabel("X axis"), QLineEdit(), QLabel("º C")],
|
|
675
|
-
[QLabel("Y axis"), QLineEdit(), QLabel("º C")],
|
|
676
|
-
]
|
|
677
|
-
|
|
678
|
-
for mts in self.motors:
|
|
679
|
-
hbox = QHBoxLayout()
|
|
680
|
-
hbox.addWidget(mts[0])
|
|
681
|
-
hbox.addWidget(mts[1])
|
|
682
|
-
hbox.addWidget(mts[2])
|
|
683
|
-
mts[0].setMinimumWidth(20)
|
|
684
|
-
mts[1].setText("N/A")
|
|
685
|
-
mts[1].setStyleSheet("QLabel { background-color : LightGray; }")
|
|
686
|
-
mts[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
687
|
-
mts[1].setMinimumWidth(50)
|
|
688
|
-
vbox.addLayout(hbox)
|
|
689
|
-
|
|
690
|
-
# Make sure the hboxes defined above stay nicely together when vertically resizing the
|
|
691
|
-
# Frame.
|
|
692
|
-
|
|
693
|
-
# vbox.addStretch()
|
|
694
|
-
|
|
695
|
-
gbox_temperatures = QGroupBox("Motor temperatures", self)
|
|
696
|
-
gbox_temperatures.setLayout(vbox)
|
|
697
|
-
gbox_temperatures.setToolTip("State of the motor temperatures")
|
|
698
|
-
|
|
699
|
-
return gbox_temperatures
|
|
700
|
-
|
|
701
|
-
def handle_fetch_temperatures(self):
|
|
702
|
-
self.observable.actionObservers({"fetch_temperatures": True})
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
class ActuatorStates(QWidget):
|
|
706
|
-
"""This Widget allows to view the state of all six actuators."""
|
|
707
|
-
def __init__(self, labels: List[str] = None):
|
|
708
|
-
super().__init__()
|
|
709
|
-
|
|
710
|
-
# initialize instance variables used by this class
|
|
711
|
-
|
|
712
|
-
self.status_labels = labels
|
|
713
|
-
self.leds: List[List] = []
|
|
714
|
-
|
|
715
|
-
vbox = QVBoxLayout()
|
|
716
|
-
vbox.addWidget(QLabel("Actuator States"))
|
|
717
|
-
vbox.setAlignment(Qt.AlignTop | Qt.AlignLeft)
|
|
718
|
-
|
|
719
|
-
self.create_states_widget = self.create_states()
|
|
720
|
-
vbox.addWidget(self.create_states_widget)
|
|
721
|
-
self.setLayout(vbox)
|
|
722
|
-
|
|
723
|
-
def create_states(self):
|
|
724
|
-
vbox = QVBoxLayout()
|
|
725
|
-
|
|
726
|
-
hbox = QHBoxLayout()
|
|
727
|
-
hbox.addWidget(QLabel(""))
|
|
728
|
-
|
|
729
|
-
for actuator_index in range(1, 3):
|
|
730
|
-
|
|
731
|
-
actuator_number = QLabel(str(actuator_index))
|
|
732
|
-
actuator_number.setAlignment(Qt.AlignHCenter)
|
|
733
|
-
actuator_number.setMinimumSize(20, 20)
|
|
734
|
-
actuator_number.setMaximumSize(20, 20)
|
|
735
|
-
# LED(self, size=QSize(20, 20), shape=ShapeEnum.SQUARE)
|
|
736
|
-
hbox.addWidget(actuator_number)
|
|
737
|
-
hbox.setSpacing(2)
|
|
738
|
-
vbox.addLayout(hbox)
|
|
739
|
-
|
|
740
|
-
for state in self.status_labels:
|
|
741
|
-
hbox = QHBoxLayout()
|
|
742
|
-
hbox.addWidget(QLabel(state))
|
|
743
|
-
actuator_leds = [
|
|
744
|
-
LED(self, size=QSize(20, 20), shape=ShapeEnum.SQUARE)
|
|
745
|
-
for _ in range(2)
|
|
746
|
-
]
|
|
747
|
-
for led in actuator_leds:
|
|
748
|
-
hbox.addWidget(led)
|
|
749
|
-
hbox.setSpacing(2)
|
|
750
|
-
self.leds.append(actuator_leds)
|
|
751
|
-
vbox.addLayout(hbox)
|
|
752
|
-
|
|
753
|
-
create_states = QGroupBox()
|
|
754
|
-
create_states.setLayout(vbox)
|
|
755
|
-
|
|
756
|
-
return create_states
|
|
757
|
-
|
|
758
|
-
def set_states(self, states: List):
|
|
759
|
-
|
|
760
|
-
# States is a List of Lists, each inside list contains a dict with the states and
|
|
761
|
-
# another list with the states.
|
|
762
|
-
|
|
763
|
-
# zip(*states) will transpose the states
|
|
764
|
-
|
|
765
|
-
for leds, new_states in zip(self.leds, zip(*states)):
|
|
766
|
-
for led, state in zip(leds, new_states):
|
|
767
|
-
led.set_color(state)
|
|
768
|
-
|
|
769
|
-
def reset_states(self):
|
|
770
|
-
pass
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
def format_tooltip(value: Union[str, Dict, List] = None) -> str:
|
|
774
|
-
if value is None:
|
|
775
|
-
return ""
|
|
776
|
-
|
|
777
|
-
from rich.console import Console
|
|
778
|
-
|
|
779
|
-
console = Console(width=60, force_terminal=False, force_jupyter=False)
|
|
780
|
-
with console.capture() as capture:
|
|
781
|
-
console.print(value)
|
|
782
|
-
|
|
783
|
-
return capture.get()
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
class GimbalUIModel:
|
|
787
|
-
def __init__(self, connection_type: str, device):
|
|
788
|
-
self._connection_type = connection_type
|
|
789
|
-
self._device = device
|
|
790
|
-
|
|
791
|
-
@property
|
|
792
|
-
def connection_type(self):
|
|
793
|
-
return self._connection_type
|
|
794
|
-
|
|
795
|
-
@property
|
|
796
|
-
def device(self):
|
|
797
|
-
return self._device
|
|
798
|
-
|
|
799
|
-
def is_simulator(self):
|
|
800
|
-
return self.device.is_simulator()
|
|
801
|
-
|
|
802
|
-
def is_cs_connected(self):
|
|
803
|
-
return self.device.is_cs_connected() if self.connection_type == "proxy" else False
|
|
804
|
-
|
|
805
|
-
def is_device_connected(self):
|
|
806
|
-
return self.device.is_connected()
|
|
807
|
-
|
|
808
|
-
@deprecate(alternative="reconnect_device")
|
|
809
|
-
def reconnect(self):
|
|
810
|
-
self.reconnect_device()
|
|
811
|
-
|
|
812
|
-
def reconnect_device(self):
|
|
813
|
-
self.device.reconnect()
|
|
814
|
-
return self.device.is_connected()
|
|
815
|
-
|
|
816
|
-
def reconnect_cs(self):
|
|
817
|
-
self.device.reconnect_cs()
|
|
818
|
-
return self.device.is_cs_connected()
|
|
819
|
-
|
|
820
|
-
def disconnect(self):
|
|
821
|
-
self.device.disconnect()
|
|
822
|
-
|
|
823
|
-
def disconnect_cs(self):
|
|
824
|
-
self.device.disconnect_cs()
|
|
825
|
-
|
|
826
|
-
def has_commands(self):
|
|
827
|
-
if self.connection_type == "proxy":
|
|
828
|
-
return self.device.has_commands()
|
|
829
|
-
return True
|
|
830
|
-
|
|
831
|
-
def load_commands(self):
|
|
832
|
-
if self.connection_type == "proxy":
|
|
833
|
-
self.device.load_commands()
|
|
834
|
-
|
|
835
|
-
def get_states(self):
|
|
836
|
-
try:
|
|
837
|
-
_, states = self.device.get_general_state()
|
|
838
|
-
except TypeError:
|
|
839
|
-
states = None
|
|
840
|
-
return states
|
|
841
|
-
|
|
842
|
-
def configure_offsets(self, offsets):
|
|
843
|
-
return self.device.configure_offsets(*offsets)
|
|
844
|
-
|
|
845
|
-
def get_offsets(self):
|
|
846
|
-
return self.device.get_offsets()
|
|
847
|
-
|
|
848
|
-
def get_user_positions(self):
|
|
849
|
-
return self.device.get_user_positions()
|
|
850
|
-
|
|
851
|
-
def get_machine_positions(self):
|
|
852
|
-
return self.device.get_machine_positions()
|
|
853
|
-
|
|
854
|
-
def get_motor_temperatures(self):
|
|
855
|
-
return self.device.get_motor_temperatures()
|
|
856
|
-
|
|
857
|
-
def get_actuator_length(self):
|
|
858
|
-
return self.device.get_actuator_length()
|
|
859
|
-
|
|
860
|
-
def get_actuator_states(self):
|
|
861
|
-
states = self.device.get_actuator_state()
|
|
862
|
-
states = [x[1] for x in states]
|
|
863
|
-
return states
|
|
864
|
-
|
|
865
|
-
def get_speed(self):
|
|
866
|
-
raise NotImplementedError
|
|
867
|
-
|
|
868
|
-
def activate_control_loop(self):
|
|
869
|
-
self.device.activate_control_loop()
|
|
870
|
-
|
|
871
|
-
def deactivate_control_loop(self):
|
|
872
|
-
self.device.deactivate_control_loop()
|
|
873
|
-
|
|
874
|
-
def check_absolute_movement(self, pos):
|
|
875
|
-
rc, rc_dict = self.device.check_absolute_movement(*pos)
|
|
876
|
-
MODULE_LOGGER.debug(rc)
|
|
877
|
-
MODULE_LOGGER.debug(rc_dict)
|
|
878
|
-
return rc_dict
|
|
879
|
-
|
|
880
|
-
def check_relative_movement(self, pos):
|
|
881
|
-
rc, rc_dict = self.device.check_relative_movement(*pos)
|
|
882
|
-
MODULE_LOGGER.debug(rc)
|
|
883
|
-
MODULE_LOGGER.debug(rc_dict)
|
|
884
|
-
return rc_dict
|
|
885
|
-
|
|
886
|
-
def move_absolute(self, pos):
|
|
887
|
-
self.device.move_absolute(*pos)
|
|
888
|
-
|
|
889
|
-
def move_relative(self, pos):
|
|
890
|
-
self.device.move_relative(*pos)
|
|
891
|
-
|
|
892
|
-
def goto_zero_position(self):
|
|
893
|
-
self.device.goto_zero_position()
|
|
894
|
-
|
|
895
|
-
def set_speed(self, sr):
|
|
896
|
-
self.device.set_speed(sr)
|
|
897
|
-
|
|
898
|
-
def homing(self):
|
|
899
|
-
self.device.homing()
|
|
900
|
-
|
|
901
|
-
def clear_error(self):
|
|
902
|
-
self.device.clear_error()
|
|
903
|
-
|
|
904
|
-
def reset(self):
|
|
905
|
-
self.device.reset()
|
|
906
|
-
|
|
907
|
-
def stop(self):
|
|
908
|
-
self.device.stop()
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
class GimbalUIController(Observer):
|
|
912
|
-
def __init__(self, model: GimbalUIModel, view):
|
|
913
|
-
self._model = model
|
|
914
|
-
self._view = view
|
|
915
|
-
self._view.addObserver(self)
|
|
916
|
-
|
|
917
|
-
self.help_window = HelpWindow(topic_url=HELP_TOPICS["home"])
|
|
918
|
-
|
|
919
|
-
self.states_capture_timer = None
|
|
920
|
-
self.timer_interval = 200
|
|
921
|
-
self.create_timer()
|
|
922
|
-
|
|
923
|
-
try:
|
|
924
|
-
if self.model.is_device_connected():
|
|
925
|
-
self.view.update_status_bar(mode=self.model.connection_type.capitalize())
|
|
926
|
-
self.view.check_device_action()
|
|
927
|
-
else:
|
|
928
|
-
self.view.uncheck_device_action()
|
|
929
|
-
|
|
930
|
-
if self.model.is_cs_connected():
|
|
931
|
-
self.view.check_cs_action()
|
|
932
|
-
else:
|
|
933
|
-
self.view.uncheck_cs_action()
|
|
934
|
-
|
|
935
|
-
MODULE_LOGGER.info(f"{self.model.is_device_connected()=}, {self.model.is_cs_connected()=}")
|
|
936
|
-
|
|
937
|
-
if model.connection_type in ["direct", "simulator"]:
|
|
938
|
-
view.disable_cs_action()
|
|
939
|
-
|
|
940
|
-
if self.has_connection():
|
|
941
|
-
self.view.set_connection_state("connected")
|
|
942
|
-
self.start_timer()
|
|
943
|
-
else:
|
|
944
|
-
self.view.set_connection_state("disconnected")
|
|
945
|
-
self.stop_timer()
|
|
946
|
-
except NotImplementedError:
|
|
947
|
-
MODULE_LOGGER.warning(
|
|
948
|
-
"There was no connection to the control server during startup, "
|
|
949
|
-
"GUI starts in disconnected mode."
|
|
950
|
-
)
|
|
951
|
-
self.view.uncheck_cs_action()
|
|
952
|
-
self.view.uncheck_device_action()
|
|
953
|
-
self.view.set_connection_state("disconnected")
|
|
954
|
-
|
|
955
|
-
def has_connection(self):
|
|
956
|
-
"""
|
|
957
|
-
Returns True if the controller has a connection to the device. This takes into account
|
|
958
|
-
that the control server might be disabled when the controller is directly connected to
|
|
959
|
-
the device or to a simulator.
|
|
960
|
-
"""
|
|
961
|
-
if self.view.is_cs_action_enabled():
|
|
962
|
-
return bool(self.model.is_device_connected() and self.model.is_cs_connected())
|
|
963
|
-
else:
|
|
964
|
-
return bool(self.model.is_device_connected())
|
|
965
|
-
|
|
966
|
-
@property
|
|
967
|
-
def model(self):
|
|
968
|
-
return self._model
|
|
969
|
-
|
|
970
|
-
@property
|
|
971
|
-
def view(self):
|
|
972
|
-
return self._view
|
|
973
|
-
|
|
974
|
-
def set_help_topic_home(self, topic: str):
|
|
975
|
-
self.help_window.set_topic_home(topic)
|
|
976
|
-
|
|
977
|
-
def create_timer(self):
|
|
978
|
-
"""Create a Timer that will update the States every second."""
|
|
979
|
-
|
|
980
|
-
self.states_capture_timer = QTimer()
|
|
981
|
-
# This is only needed when the Timer needs to run in another Thread
|
|
982
|
-
# self.states_capture_timer.moveToThread(self)
|
|
983
|
-
self.states_capture_timer.timeout.connect(self.update_values)
|
|
984
|
-
self.states_capture_timer.setInterval(self.timer_interval)
|
|
985
|
-
|
|
986
|
-
def start_timer(self):
|
|
987
|
-
self.states_capture_timer.start()
|
|
988
|
-
|
|
989
|
-
def stop_timer(self):
|
|
990
|
-
self.states_capture_timer.stop()
|
|
991
|
-
|
|
992
|
-
def update_values(self):
|
|
993
|
-
"""Updates the common view widgets."""
|
|
994
|
-
|
|
995
|
-
if not self.has_connection():
|
|
996
|
-
self.view.set_connection_state("disconnected")
|
|
997
|
-
self.stop_timer()
|
|
998
|
-
|
|
999
|
-
if not self.model.is_device_connected(): self.view.disable_device_action()
|
|
1000
|
-
if not self.model.is_cs_connected(): self.view.uncheck_cs_action()
|
|
1001
|
-
|
|
1002
|
-
return
|
|
1003
|
-
|
|
1004
|
-
states = self.model.get_states()
|
|
1005
|
-
|
|
1006
|
-
if states:
|
|
1007
|
-
self.view.updateStates(states)
|
|
1008
|
-
|
|
1009
|
-
actuator_states = self.model.get_actuator_states()
|
|
1010
|
-
self.view.update_actuator_states(actuator_states)
|
|
1011
|
-
|
|
1012
|
-
upos = self.model.get_user_positions()
|
|
1013
|
-
mpos = self.model.get_machine_positions()
|
|
1014
|
-
alen = self.model.get_actuator_length()
|
|
1015
|
-
temp = self.model.get_motor_temperatures()
|
|
1016
|
-
|
|
1017
|
-
# the updatePositions() checks for None, no need to do that here
|
|
1018
|
-
|
|
1019
|
-
self.view.updatePositions(upos, mpos, alen)
|
|
1020
|
-
self.view.updateTemperatures(temp)
|
|
1021
|
-
|
|
1022
|
-
def update(self, changed_object):
|
|
1023
|
-
|
|
1024
|
-
text = changed_object.text()
|
|
1025
|
-
|
|
1026
|
-
if text == "STOP":
|
|
1027
|
-
self.model.stop()
|
|
1028
|
-
|
|
1029
|
-
if text == "INFO":
|
|
1030
|
-
self.help_window.show()
|
|
1031
|
-
|
|
1032
|
-
if text == "DEVICE-CONNECT":
|
|
1033
|
-
print(f"Pressed {text}")
|
|
1034
|
-
|
|
1035
|
-
if changed_object.is_selected():
|
|
1036
|
-
MODULE_LOGGER.debug("Reconnecting the Gimbal model.")
|
|
1037
|
-
if self.model.reconnect_device():
|
|
1038
|
-
self.view.set_connection_state("connected")
|
|
1039
|
-
if not self.model.has_commands():
|
|
1040
|
-
self.model.load_commands()
|
|
1041
|
-
self.start_timer()
|
|
1042
|
-
else:
|
|
1043
|
-
self.view.device_connection.set_selected(False)
|
|
1044
|
-
else:
|
|
1045
|
-
MODULE_LOGGER.debug("Disconnecting the Gimbal model.")
|
|
1046
|
-
self.stop_timer()
|
|
1047
|
-
self.model.disconnect()
|
|
1048
|
-
self.view.set_connection_state("disconnected")
|
|
1049
|
-
return
|
|
1050
|
-
|
|
1051
|
-
if text == "CS-CONNECT":
|
|
1052
|
-
if changed_object.is_selected():
|
|
1053
|
-
MODULE_LOGGER.debug("Reconnecting the Gimbal Control Server.")
|
|
1054
|
-
self.model.reconnect_cs()
|
|
1055
|
-
if not self.model.has_commands():
|
|
1056
|
-
self.model.load_commands()
|
|
1057
|
-
self.start_timer()
|
|
1058
|
-
if self.model.is_device_connected() and self.model.is_cs_connected():
|
|
1059
|
-
self.view.set_connection_state("connected")
|
|
1060
|
-
self.view.device_connection.enable()
|
|
1061
|
-
else:
|
|
1062
|
-
MODULE_LOGGER.debug("Disconnecting the Gimbal Control Server.")
|
|
1063
|
-
self.stop_timer()
|
|
1064
|
-
self.model.disconnect_cs()
|
|
1065
|
-
self.view.device_connection.disable()
|
|
1066
|
-
self.view.set_connection_state("disconnected")
|
|
1067
|
-
|
|
1068
|
-
if text == "CONTROL":
|
|
1069
|
-
if changed_object.is_selected():
|
|
1070
|
-
self.model.activate_control_loop()
|
|
1071
|
-
else:
|
|
1072
|
-
self.model.deactivate_control_loop()
|
|
1073
|
-
|
|
1074
|
-
if text == "HOMING":
|
|
1075
|
-
self.model.homing()
|
|
1076
|
-
|
|
1077
|
-
if text == "CLEAR-ERRORS":
|
|
1078
|
-
self.model.clear_error()
|
|
1079
|
-
|
|
1080
|
-
if text == "Reset":
|
|
1081
|
-
# FIXME: This causes a problem in the GUI EventLoop as the reset waits for 30 seconds
|
|
1082
|
-
# before it finishes. This will hang the EventLoop for 30 seconds with a spinning
|
|
1083
|
-
# wheel. Do we need to run the gimbal commands (or some) in a separate thread?
|
|
1084
|
-
# Other commands like move to position will also take some time and cause the GUI
|
|
1085
|
-
# to apear hanging...
|
|
1086
|
-
#
|
|
1087
|
-
# It is known that time.sleep() should not be used in GUI applications.
|
|
1088
|
-
# Use QTimer.singleShot() instead.
|
|
1089
|
-
|
|
1090
|
-
self.model.reset()
|
|
1091
|
-
|
|
1092
|
-
def do(self, actions):
|
|
1093
|
-
|
|
1094
|
-
for action, value in actions.items():
|
|
1095
|
-
MODULE_LOGGER.debug(f"do {action} with {value}")
|
|
1096
|
-
if action == "move_absolute":
|
|
1097
|
-
self.model.move_absolute(value)
|
|
1098
|
-
self.view.update_status_bar(message=f"command: {action}{value}")
|
|
1099
|
-
elif action == "move_relative":
|
|
1100
|
-
self.model.move_relative(value)
|
|
1101
|
-
self.view.update_status_bar(message=f"command: {action}{value}")
|
|
1102
|
-
elif action == "check_absolute_movement":
|
|
1103
|
-
rc_dict = self.model.check_absolute_movement(value)
|
|
1104
|
-
self.view.update_status_bar(message=f"command: {action}{value}")
|
|
1105
|
-
self.view.positioning.set_position_validation_icon(rc_dict)
|
|
1106
|
-
elif action == "check_relative_movement":
|
|
1107
|
-
rc_dict = self.model.check_relative_movement(value)
|
|
1108
|
-
self.view.update_status_bar(message=f"command: {action}{value}")
|
|
1109
|
-
self.view.positioning.set_position_validation_icon(rc_dict)
|
|
1110
|
-
elif action == "set_speed":
|
|
1111
|
-
sr = value
|
|
1112
|
-
MODULE_LOGGER.info(f"Set speed: {sr=}")
|
|
1113
|
-
self.model.set_speed(sr)
|
|
1114
|
-
self.view.update_status_bar(message=f"command: {action}{value}")
|
|
1115
|
-
elif action == "fetch_speed":
|
|
1116
|
-
sr, sr_min, sr_max = self.model.get_speed()
|
|
1117
|
-
self.view.set_speed(sr)
|
|
1118
|
-
elif action == "goto_zero_position":
|
|
1119
|
-
self.model.goto_zero_position()
|
|
1120
|
-
elif action == "configure_offsets":
|
|
1121
|
-
self.model.configure_offsets(value)
|
|
1122
|
-
elif action == "fetch_offsets":
|
|
1123
|
-
offsets = self.model.get_offsets()
|
|
1124
|
-
self.view.set_offsets(offsets)
|
|
1125
|
-
elif action == "fetch_temperatures":
|
|
1126
|
-
temps = self.model.get_motor_temperatures()
|
|
1127
|
-
self.view.set_temperatures(temps)
|
|
1128
|
-
else:
|
|
1129
|
-
MODULE_LOGGER.warning(f"Unknown action {action}")
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
class GimbalUIView(QMainWindow, Observable):
|
|
1133
|
-
def __init__(self):
|
|
1134
|
-
super().__init__()
|
|
1135
|
-
|
|
1136
|
-
self.setGeometry(300, 300, 300, 200)
|
|
1137
|
-
|
|
1138
|
-
self.mode_label = QLabel("")
|
|
1139
|
-
self.user_positions = None
|
|
1140
|
-
|
|
1141
|
-
# Widget for Manual Positioning, Configuration TAB
|
|
1142
|
-
|
|
1143
|
-
self.positioning = None
|
|
1144
|
-
self.configuration = None
|
|
1145
|
-
|
|
1146
|
-
self.gimbal_offsets: GimbalOffsets = None
|
|
1147
|
-
self.speed_settings = None
|
|
1148
|
-
|
|
1149
|
-
# Widget for the Advanced TAB
|
|
1150
|
-
|
|
1151
|
-
self.actuator_states = None
|
|
1152
|
-
|
|
1153
|
-
# Widget fot the temperature log TAB
|
|
1154
|
-
|
|
1155
|
-
self.temperature_log: MotorTemperatures = None
|
|
1156
|
-
|
|
1157
|
-
def onClick(self, icon: Union[QIcon, bool]):
|
|
1158
|
-
|
|
1159
|
-
sender = self.sender()
|
|
1160
|
-
|
|
1161
|
-
MODULE_LOGGER.log(0, f"type(sender) = {type(sender)}")
|
|
1162
|
-
MODULE_LOGGER.log(0, f"sender.text() = {sender.text()}")
|
|
1163
|
-
MODULE_LOGGER.log(0, f"sender.isCheckable() = {sender.isCheckable()}")
|
|
1164
|
-
MODULE_LOGGER.log(0, f"sender.isChecked() = {sender.isChecked()}")
|
|
1165
|
-
MODULE_LOGGER.log(0, f"type(icon) = {type(icon)}")
|
|
1166
|
-
|
|
1167
|
-
# This will trigger the update() method on all the observers
|
|
1168
|
-
|
|
1169
|
-
self.notifyObservers(sender)
|
|
1170
|
-
|
|
1171
|
-
def createStatusBar(self):
|
|
1172
|
-
|
|
1173
|
-
self.statusBar().setStyleSheet("border: 0; background-color: #FFF8DC;")
|
|
1174
|
-
self.statusBar().setStyleSheet("QStatusBar::item {border: none;}")
|
|
1175
|
-
self.statusBar().addPermanentWidget(VLine())
|
|
1176
|
-
self.statusBar().addPermanentWidget(self.mode_label)
|
|
1177
|
-
|
|
1178
|
-
def createToolbar(self):
|
|
1179
|
-
|
|
1180
|
-
# The Switch On/OFF is in this case used for the Control ON/OFF action.
|
|
1181
|
-
|
|
1182
|
-
self.control = ToggleButton(
|
|
1183
|
-
name="CONTROL",
|
|
1184
|
-
status_tip="enable-disable the control loop on the servo motors",
|
|
1185
|
-
selected=get_resource(":/icons/switch-on.svg"),
|
|
1186
|
-
not_selected=get_resource(":/icons/switch-off.svg"),
|
|
1187
|
-
disabled=get_resource(":/icons/switch-disabled.svg")
|
|
1188
|
-
)
|
|
1189
|
-
self.control.clicked.connect(self.onClick)
|
|
1190
|
-
|
|
1191
|
-
# The Home action is used to command the Homing to the Gimbal.
|
|
1192
|
-
|
|
1193
|
-
self.homing = TouchButton(
|
|
1194
|
-
name="HOMING",
|
|
1195
|
-
status_tip="perform a homing operation",
|
|
1196
|
-
selected=get_resource(":/icons/home.svg"),
|
|
1197
|
-
disabled=get_resource(":/icons/home-disabled.svg"),
|
|
1198
|
-
)
|
|
1199
|
-
self.homing.clicked.connect(self.onClick)
|
|
1200
|
-
|
|
1201
|
-
# The Clear action is used to command the ClearErrors to the Gimbal.
|
|
1202
|
-
|
|
1203
|
-
self.clear_errors = TouchButton(
|
|
1204
|
-
name="CLEAR-ERRORS",
|
|
1205
|
-
status_tip="clear the error list on the controller",
|
|
1206
|
-
selected=get_resource(":/icons/erase.svg"),
|
|
1207
|
-
disabled=get_resource(":/icons/erase-disabled.svg"),
|
|
1208
|
-
)
|
|
1209
|
-
self.clear_errors.clicked.connect(self.onClick)
|
|
1210
|
-
|
|
1211
|
-
# The Reconnect action is used to reconnect to the control server
|
|
1212
|
-
|
|
1213
|
-
self.cs_connection = ToggleButton(
|
|
1214
|
-
name="CS-CONNECT",
|
|
1215
|
-
status_tip="connect-disconnect gimbal control server.",
|
|
1216
|
-
selected=get_resource(":/icons/cs-connected.svg"),
|
|
1217
|
-
not_selected=get_resource(":/icons/cs-not-connected.svg"),
|
|
1218
|
-
disabled=get_resource(":/icons/cs-connected-disabled.svg")
|
|
1219
|
-
)
|
|
1220
|
-
self.cs_connection.clicked.connect(self.onClick)
|
|
1221
|
-
|
|
1222
|
-
# The Reconnect action is used to reconnect the device
|
|
1223
|
-
|
|
1224
|
-
self.device_connection = ToggleButton(
|
|
1225
|
-
name="DEVICE-CONNECT",
|
|
1226
|
-
status_tip="connect-disconnect the gimbal controller",
|
|
1227
|
-
selected=get_resource(":/icons/plugged.svg"),
|
|
1228
|
-
not_selected=get_resource(":/icons/unplugged.svg"),
|
|
1229
|
-
disabled=get_resource(":/icons/plugged-disabled.svg")
|
|
1230
|
-
)
|
|
1231
|
-
self.device_connection.clicked.connect(self.onClick)
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
# The STOP button is used to immediately stop the current motion
|
|
1235
|
-
|
|
1236
|
-
stop_button = QIcon(str(get_resource(":/icons/stop.svg")))
|
|
1237
|
-
|
|
1238
|
-
self.stop_action = QAction(stop_button, "STOP", self)
|
|
1239
|
-
self.stop_action.setToolTip("STOP Movement")
|
|
1240
|
-
self.stop_action.triggered.connect(self.onClick)
|
|
1241
|
-
|
|
1242
|
-
# The HELP button is used to show the on-line help in a browser window
|
|
1243
|
-
|
|
1244
|
-
help_button = QIcon(str(get_resource(":/icons/info.svg")))
|
|
1245
|
-
|
|
1246
|
-
self.help_action = QAction(help_button, "INFO", self)
|
|
1247
|
-
self.help_action.setToolTip("Browse the on-line documentation")
|
|
1248
|
-
self.help_action.triggered.connect(self.onClick)
|
|
1249
|
-
|
|
1250
|
-
# spacer widget to help with aligning STOP button to the right
|
|
1251
|
-
|
|
1252
|
-
spacer = QWidget()
|
|
1253
|
-
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
1254
|
-
|
|
1255
|
-
self.toolbar = self.addToolBar("MainToolbar")
|
|
1256
|
-
self.toolbar.addWidget(self.control)
|
|
1257
|
-
self.toolbar.addWidget(self.homing)
|
|
1258
|
-
self.toolbar.addWidget(self.clear_errors)
|
|
1259
|
-
self.toolbar.addWidget(self.device_connection)
|
|
1260
|
-
self.toolbar.addWidget(self.cs_connection)
|
|
1261
|
-
self.toolbar.addWidget(spacer)
|
|
1262
|
-
self.toolbar.addAction(self.stop_action)
|
|
1263
|
-
self.toolbar.addAction(self.help_action)
|
|
1264
|
-
|
|
1265
|
-
return self.toolbar
|
|
1266
|
-
|
|
1267
|
-
def createUserPositionWidget(self):
|
|
1268
|
-
|
|
1269
|
-
vbox_labels = QVBoxLayout()
|
|
1270
|
-
vbox_values = QVBoxLayout()
|
|
1271
|
-
vbox_units = QVBoxLayout()
|
|
1272
|
-
hbox = QHBoxLayout()
|
|
1273
|
-
|
|
1274
|
-
self.user_positions = [
|
|
1275
|
-
[QLabel("Rx"), QLabel(), QLabel("deg")],
|
|
1276
|
-
[QLabel("Ry"), QLabel(), QLabel("deg")],
|
|
1277
|
-
]
|
|
1278
|
-
|
|
1279
|
-
for upos in self.user_positions:
|
|
1280
|
-
vbox_labels.addWidget(upos[0])
|
|
1281
|
-
vbox_values.addWidget(upos[1])
|
|
1282
|
-
upos[1].setStyleSheet("QLabel { background-color : LightGrey; }")
|
|
1283
|
-
upos[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
1284
|
-
upos[1].setMinimumWidth(80)
|
|
1285
|
-
vbox_units.addWidget(upos[2])
|
|
1286
|
-
|
|
1287
|
-
# Make sure the labels stay nicely together when vertically resizing the Frame.
|
|
1288
|
-
vbox_labels.addStretch(1)
|
|
1289
|
-
vbox_values.addStretch(1)
|
|
1290
|
-
vbox_units.addStretch(1)
|
|
1291
|
-
|
|
1292
|
-
hbox.addLayout(vbox_labels)
|
|
1293
|
-
hbox.addLayout(vbox_values)
|
|
1294
|
-
hbox.addLayout(vbox_units)
|
|
1295
|
-
|
|
1296
|
-
# Make sure the leds and labels stay nicely together when horizontally resizing the Frame.
|
|
1297
|
-
hbox.addStretch(1)
|
|
1298
|
-
|
|
1299
|
-
gbox_positions = QGroupBox("Object [in User]", self)
|
|
1300
|
-
gbox_positions.setLayout(hbox)
|
|
1301
|
-
gbox_positions.setToolTip(
|
|
1302
|
-
"The position of the Object Coordinate System in the User Coordinate System."
|
|
1303
|
-
)
|
|
1304
|
-
|
|
1305
|
-
return gbox_positions
|
|
1306
|
-
|
|
1307
|
-
def createMachinePositionWidget(self):
|
|
1308
|
-
|
|
1309
|
-
vbox_labels = QVBoxLayout()
|
|
1310
|
-
vbox_values = QVBoxLayout()
|
|
1311
|
-
vbox_units = QVBoxLayout()
|
|
1312
|
-
hbox = QHBoxLayout()
|
|
1313
|
-
|
|
1314
|
-
self.mach_positions = [
|
|
1315
|
-
[QLabel("Rx"), QLabel(), QLabel("deg")],
|
|
1316
|
-
[QLabel("Ry"), QLabel(), QLabel("deg")],
|
|
1317
|
-
]
|
|
1318
|
-
|
|
1319
|
-
for mpos in self.mach_positions:
|
|
1320
|
-
vbox_labels.addWidget(mpos[0])
|
|
1321
|
-
vbox_values.addWidget(mpos[1])
|
|
1322
|
-
mpos[1].setStyleSheet("QLabel { background-color : LightGrey; }")
|
|
1323
|
-
mpos[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
1324
|
-
mpos[1].setMinimumWidth(80)
|
|
1325
|
-
vbox_units.addWidget(mpos[2])
|
|
1326
|
-
|
|
1327
|
-
# Make sure the labels stay nicely together when vertically resizing the Frame.
|
|
1328
|
-
vbox_labels.addStretch(1)
|
|
1329
|
-
vbox_values.addStretch(1)
|
|
1330
|
-
vbox_units.addStretch(1)
|
|
1331
|
-
|
|
1332
|
-
hbox.addLayout(vbox_labels)
|
|
1333
|
-
hbox.addLayout(vbox_values)
|
|
1334
|
-
hbox.addLayout(vbox_units)
|
|
1335
|
-
|
|
1336
|
-
# Make sure the leds and labels stay nicely together when horizontally resizing the Frame.
|
|
1337
|
-
hbox.addStretch(1)
|
|
1338
|
-
|
|
1339
|
-
gbox_positions = QGroupBox("Platform [in Machine]", self)
|
|
1340
|
-
gbox_positions.setLayout(hbox)
|
|
1341
|
-
gbox_positions.setToolTip(
|
|
1342
|
-
"The position of the Platform Coordinate System in the Machine Coordinate System."
|
|
1343
|
-
)
|
|
1344
|
-
|
|
1345
|
-
return gbox_positions
|
|
1346
|
-
|
|
1347
|
-
def createActuatorLengthWidget(self):
|
|
1348
|
-
|
|
1349
|
-
vbox_labels = QVBoxLayout()
|
|
1350
|
-
vbox_values = QVBoxLayout()
|
|
1351
|
-
vbox_units = QVBoxLayout()
|
|
1352
|
-
hbox = QHBoxLayout()
|
|
1353
|
-
|
|
1354
|
-
self.actuator_lengths = [
|
|
1355
|
-
[QLabel("L1"), QLabel(), QLabel("mm")],
|
|
1356
|
-
[QLabel("L2"), QLabel(), QLabel("mm")],
|
|
1357
|
-
]
|
|
1358
|
-
|
|
1359
|
-
for alength in self.actuator_lengths:
|
|
1360
|
-
vbox_labels.addWidget(alength[0])
|
|
1361
|
-
vbox_values.addWidget(alength[1])
|
|
1362
|
-
alength[1].setStyleSheet("QLabel { background-color : LightGrey; }")
|
|
1363
|
-
alength[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
1364
|
-
alength[1].setMinimumWidth(80)
|
|
1365
|
-
vbox_units.addWidget(alength[2])
|
|
1366
|
-
|
|
1367
|
-
# Make sure the labels stay nicely together when vertically resizing the Frame.
|
|
1368
|
-
vbox_labels.addStretch(1)
|
|
1369
|
-
vbox_values.addStretch(1)
|
|
1370
|
-
vbox_units.addStretch(1)
|
|
1371
|
-
|
|
1372
|
-
hbox.addLayout(vbox_labels)
|
|
1373
|
-
hbox.addLayout(vbox_values)
|
|
1374
|
-
hbox.addLayout(vbox_units)
|
|
1375
|
-
|
|
1376
|
-
# Make sure the leds and labels stay nicely together when horizontally resizing the Frame.
|
|
1377
|
-
hbox.addStretch(1)
|
|
1378
|
-
|
|
1379
|
-
gbox_lengths = QGroupBox("Actuator Length", self)
|
|
1380
|
-
gbox_lengths.setLayout(hbox)
|
|
1381
|
-
|
|
1382
|
-
return gbox_lengths
|
|
1383
|
-
|
|
1384
|
-
def createMotorTemperatureWidget(self):
|
|
1385
|
-
vbox_labels = QVBoxLayout()
|
|
1386
|
-
vbox_values = QVBoxLayout()
|
|
1387
|
-
vbox_units = QVBoxLayout()
|
|
1388
|
-
hbox = QHBoxLayout()
|
|
1389
|
-
|
|
1390
|
-
self.motors = [
|
|
1391
|
-
[QLabel("Tx"), QLabel("N/A"), QLabel("º C")],
|
|
1392
|
-
[QLabel("Ty"), QLabel("N/A"), QLabel("º C")],
|
|
1393
|
-
]
|
|
1394
|
-
|
|
1395
|
-
for mtemp in self.motors:
|
|
1396
|
-
vbox_labels.addWidget(mtemp[0])
|
|
1397
|
-
vbox_values.addWidget(mtemp[1])
|
|
1398
|
-
mtemp[1].setStyleSheet("QLabel { background-color : LightGrey; }")
|
|
1399
|
-
mtemp[1].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
|
1400
|
-
mtemp[1].setMinimumWidth(80)
|
|
1401
|
-
vbox_units.addWidget(mtemp[2])
|
|
1402
|
-
|
|
1403
|
-
# Make sure the labels stay nicely together when vertically resizing the Frame.
|
|
1404
|
-
vbox_labels.addStretch(1)
|
|
1405
|
-
vbox_values.addStretch(1)
|
|
1406
|
-
vbox_units.addStretch(1)
|
|
1407
|
-
|
|
1408
|
-
hbox.addLayout(vbox_labels)
|
|
1409
|
-
hbox.addLayout(vbox_values)
|
|
1410
|
-
hbox.addLayout(vbox_units)
|
|
1411
|
-
|
|
1412
|
-
# Make sure the leds and labels stay nicely together when horizontally resizing the Frame.
|
|
1413
|
-
hbox.addStretch(1)
|
|
1414
|
-
|
|
1415
|
-
gbox_motors = QGroupBox("Motor temperature", self)
|
|
1416
|
-
gbox_motors.setLayout(hbox)
|
|
1417
|
-
|
|
1418
|
-
return gbox_motors
|
|
1419
|
-
|
|
1420
|
-
def create_tabbed_widget(self):
|
|
1421
|
-
|
|
1422
|
-
self.tabs = QTabWidget()
|
|
1423
|
-
self.tabs.setTabsClosable(False)
|
|
1424
|
-
self.tabs.setMovable(False)
|
|
1425
|
-
self.tabs.setDocumentMode(True)
|
|
1426
|
-
self.tabs.setElideMode(Qt.ElideRight)
|
|
1427
|
-
self.tabs.setUsesScrollButtons(True)
|
|
1428
|
-
|
|
1429
|
-
self.positioning = Positioning(self, self)
|
|
1430
|
-
self.tabs.addTab(self.positioning, "Positions")
|
|
1431
|
-
self.gimbal_offsets = GimbalOffsets(self, self)
|
|
1432
|
-
self.temperature_log = MotorTemperatures(self, self)
|
|
1433
|
-
self.speed_settings = SpeedSettings(self, self)
|
|
1434
|
-
self.configuration = QWidget()
|
|
1435
|
-
vbox = QVBoxLayout()
|
|
1436
|
-
vbox.setSpacing(0)
|
|
1437
|
-
vbox.addWidget(self.gimbal_offsets)
|
|
1438
|
-
vbox.addWidget(self.speed_settings)
|
|
1439
|
-
self.configuration.setLayout(vbox)
|
|
1440
|
-
self.tabs.addTab(self.configuration, "Configuration")
|
|
1441
|
-
self.tabs.currentChanged.connect(self.reload_settings_for_tab)
|
|
1442
|
-
|
|
1443
|
-
# Actuator states are initialised in the sub-class because the states are different
|
|
1444
|
-
# for the Alpha and Aplha+ controllers
|
|
1445
|
-
|
|
1446
|
-
self.tabs.addTab(self.actuator_states, "Advanced State")
|
|
1447
|
-
|
|
1448
|
-
self.tabs.addTab(self.temperature_log, "Temperature Log")
|
|
1449
|
-
|
|
1450
|
-
return self.tabs
|
|
1451
|
-
|
|
1452
|
-
def reload_settings_for_tab(self, tab_idx):
|
|
1453
|
-
MODULE_LOGGER.info(f"Reload for tab: {tab_idx}")
|
|
1454
|
-
if self.configuration is self.tabs.widget(tab_idx):
|
|
1455
|
-
self.gimbal_offsets.handle_fetch_offsets()
|
|
1456
|
-
self.speed_settings.handle_fetch_speed_settings()
|
|
1457
|
-
|
|
1458
|
-
def set_offsets(self, offsets):
|
|
1459
|
-
self.gimbal_offsets.set_offsets(offsets)
|
|
1460
|
-
|
|
1461
|
-
def set_temperatures(self, temperatures):
|
|
1462
|
-
self.temperature_log.set_temperatures(temperatures)
|
|
1463
|
-
|
|
1464
|
-
def set_speed(self, sr):
|
|
1465
|
-
self.speed_settings.set_speed(sr)
|
|
1466
|
-
|
|
1467
|
-
def is_cs_action_enabled(self):
|
|
1468
|
-
return self.cs_connection.isEnabled()
|
|
1469
|
-
|
|
1470
|
-
def disable_cs_action(self):
|
|
1471
|
-
self.cs_connection.disable()
|
|
1472
|
-
|
|
1473
|
-
def enable_cs_action(self):
|
|
1474
|
-
self.cs_connection.enable()
|
|
1475
|
-
|
|
1476
|
-
def check_cs_action(self):
|
|
1477
|
-
self.cs_connection.set_selected()
|
|
1478
|
-
|
|
1479
|
-
def uncheck_cs_action(self):
|
|
1480
|
-
self.cs_connection.set_selected(False)
|
|
1481
|
-
|
|
1482
|
-
def disable_device_action(self):
|
|
1483
|
-
self.device_connection.disable()
|
|
1484
|
-
|
|
1485
|
-
def enable_device_action(self):
|
|
1486
|
-
self.device_connection.enabled()
|
|
1487
|
-
|
|
1488
|
-
def check_device_action(self):
|
|
1489
|
-
self.device_connection.set_selected()
|
|
1490
|
-
|
|
1491
|
-
def uncheck_device_action(self):
|
|
1492
|
-
self.device_connection.set_selected(False)
|
|
1493
|
-
|
|
1494
|
-
def set_connection_state(self, state):
|
|
1495
|
-
# enable or disable all actions that involve a device or cs connection
|
|
1496
|
-
# don't change the action buttons for the device nor the cs, that is handled
|
|
1497
|
-
# in the caller because it might be a device connection loss that causes this state
|
|
1498
|
-
# or a control server, or both...
|
|
1499
|
-
|
|
1500
|
-
MODULE_LOGGER.info(f"{state=}")
|
|
1501
|
-
|
|
1502
|
-
if state == "connected":
|
|
1503
|
-
self.control.enable()
|
|
1504
|
-
self.homing.enable()
|
|
1505
|
-
self.clear_errors.enable()
|
|
1506
|
-
self.positioning.enable_movement()
|
|
1507
|
-
elif state == "disconnected":
|
|
1508
|
-
self.control.disable()
|
|
1509
|
-
self.homing.disable()
|
|
1510
|
-
self.clear_errors.disable()
|
|
1511
|
-
self.positioning.disable_movement()
|
|
1512
|
-
else:
|
|
1513
|
-
raise UnknownStateError(
|
|
1514
|
-
f"Unknown State ({state}), expected 'connected' or 'disconnected'."
|
|
1515
|
-
)
|
|
1516
|
-
|
|
1517
|
-
def update_actuator_states(self, states):
|
|
1518
|
-
if states is None:
|
|
1519
|
-
return
|
|
1520
|
-
|
|
1521
|
-
self.actuator_states.set_states(states)
|