mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-03-08 01:37:52 +01:00
Merge branch 'motor_controle'
This commit is contained in:
768
bec_widgets/examples/motor_movement/motor_controller.ui
Normal file
768
bec_widgets/examples/motor_movement/motor_controller.ui
Normal file
@@ -0,0 +1,768 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Form</class>
|
||||
<widget class="QWidget" name="Form">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1129</width>
|
||||
<height>550</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Motor Controller</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="8,5,8">
|
||||
<item>
|
||||
<widget class="GraphicsLayoutWidget" name="glw">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="Controls">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>221</width>
|
||||
<height>471</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorSelection">
|
||||
<property name="title">
|
||||
<string>Motor Selection</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Motor Y</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="comboBox_motor_x"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="comboBox_motor_y"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Motor X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QPushButton" name="pushButton_connecMotors">
|
||||
<property name="text">
|
||||
<string>Connect Motors</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorControl">
|
||||
<property name="title">
|
||||
<string>Motor Relative</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_enableArrows">
|
||||
<property name="text">
|
||||
<string>Move with arrow keys</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item row="1" column="2" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
|
||||
<widget class="QToolButton" name="toolButton_up">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::UpArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="2" alignment="Qt::AlignHCenter|Qt::AlignVCenter">
|
||||
<widget class="QToolButton" name="toolButton_down">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::DownArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QToolButton" name="toolButton_left">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::LeftArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="toolButton_right">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="arrowType">
|
||||
<enum>Qt::RightArrow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_step">
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>13</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorControl_absolute">
|
||||
<property name="title">
|
||||
<string>Move Absolute</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="pushButton_go_absolute">
|
||||
<property name="text">
|
||||
<string>Go</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_absolute_x">
|
||||
<property name="minimum">
|
||||
<double>-500.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>500.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QDoubleSpinBox" name="spinBox_absolute_y">
|
||||
<property name="minimum">
|
||||
<double>-500.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>500.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_stop">
|
||||
<property name="text">
|
||||
<string>Stop Movement</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget_tables">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_coordinates">
|
||||
<attribute name="title">
|
||||
<string>Coordinates</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget_coordinates">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::MultiSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Tag</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Show</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Move</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_settings">
|
||||
<attribute name="title">
|
||||
<string>Settings</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="motorLimits">
|
||||
<property name="title">
|
||||
<string>Motor Limits</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_y_min">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>-100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="pushButton_updateLimits">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="spinBox_x_max">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_Y_max">
|
||||
<property name="text">
|
||||
<string>+ Y</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_y_max">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QSpinBox" name="spinBox_x_min">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>-100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="label_Y_min">
|
||||
<property name="text">
|
||||
<string>- Y</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_X_min">
|
||||
<property name="text">
|
||||
<string>- X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="label_X_max">
|
||||
<property name="text">
|
||||
<string>+ X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Motor Config</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_3">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="spinBox_6">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Speed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_speed_x">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="spinBox_update_frequency_x">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="spinBox_speed_y">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Y</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Max Points</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="spinBox_num_dim_points">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Update Frequency</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tolerance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="doubleSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="spinBox_update_frequency_y">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="pushButton_update_config">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Decimal Precision</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>N dim</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="spinBox_max_points">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Scatter Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="spinBox_scatter_size">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>15</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_queue">
|
||||
<attribute name="title">
|
||||
<string>Queue</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_5">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset Queue</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget_2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>queueID</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>scanID</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>is_scan</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>scan_number</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>IQ status</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>GraphicsLayoutWidget</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>pyqtgraph.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
674
bec_widgets/examples/motor_movement/motor_example.py
Normal file
674
bec_widgets/examples/motor_movement/motor_example.py
Normal file
@@ -0,0 +1,674 @@
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
from enum import Enum
|
||||
import pyqtgraph as pg
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtCore import QThread, pyqtSlot
|
||||
from PyQt5.QtCore import pyqtSignal, Qt
|
||||
from PyQt5.QtWidgets import QApplication, QWidget
|
||||
from pyqtgraph.Qt import QtWidgets, uic
|
||||
|
||||
from PyQt5.QtGui import QKeySequence
|
||||
from PyQt5.QtWidgets import QShortcut
|
||||
|
||||
from bec_lib.core import MessageEndpoints, BECMessage
|
||||
|
||||
|
||||
# TODO - General features
|
||||
# - setting motor speed and frequency
|
||||
# - setting motor acceleration
|
||||
# - updating motor precision
|
||||
# - put motor status (moving, stopped, etc)
|
||||
# - add spinBox for motor scatter size
|
||||
# - add mouse interactions with the plot -> click to select coordinates, double click to move?
|
||||
# - adjust right click actions
|
||||
# - implement logic to check if motor actually has limits
|
||||
|
||||
|
||||
class MotorApp(QWidget):
|
||||
coordinates_updated = pyqtSignal(float, float)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
current_path = os.path.dirname(__file__)
|
||||
uic.loadUi(os.path.join(current_path, "motor_controller.ui"), self)
|
||||
|
||||
# Motor Control Thread
|
||||
self.motor_thread = MotorControl()
|
||||
|
||||
self.motor_x, self.motor_y = None, None
|
||||
self.limit_x, self.limit_y = None, None
|
||||
|
||||
# Coordinates tracking
|
||||
self.motor_positions = np.array([])
|
||||
self.max_points = 5000 # Maximum number of points to keep
|
||||
self.num_dim_points = 15 # Number of points to dim gradually
|
||||
self.scatter_size = 5
|
||||
|
||||
# QThread for motor movement + signals
|
||||
self.motor_thread.motors_loaded.connect(self.get_available_motors)
|
||||
self.motor_thread.motors_selected.connect(self.get_selected_motors)
|
||||
self.motor_thread.limits_retrieved.connect(self.update_limits)
|
||||
self.motor_thread.speed_retrieved.connect(self.update_speed)
|
||||
self.motor_thread.update_frequency_retrieved.connect(self.update_update_frequency)
|
||||
|
||||
# UI
|
||||
self.init_ui()
|
||||
self.tag_N = 1 # position label for saved coordinates
|
||||
|
||||
# Get all motors available
|
||||
self.motor_thread.retrieve_all_motors()
|
||||
|
||||
def connect_motor(self, motor_x_name: str, motor_y_name: str):
|
||||
self.motor_thread.connect_motors(motor_x_name, motor_y_name)
|
||||
self.motor_thread.retrieve_motor_limits(self.motor_x, self.motor_y)
|
||||
self.motor_thread.retrieve_motor_speed(self.motor_x, self.motor_y)
|
||||
self.motor_thread.retrieve_motor_update_frequency(self.motor_x, self.motor_y)
|
||||
self.init_motor_map()
|
||||
|
||||
self.motorControl.setEnabled(True)
|
||||
self.motorControl_absolute.setEnabled(True)
|
||||
self.tabWidget_tables.setTabEnabled(1, True)
|
||||
|
||||
self.generate_table_coordinate(
|
||||
self.tableWidget_coordinates,
|
||||
self.motor_thread.retrieve_coordinates(),
|
||||
tag=f"{motor_x_name},{motor_y_name}",
|
||||
precision=0,
|
||||
)
|
||||
|
||||
@pyqtSlot(object, object)
|
||||
def get_selected_motors(self, motor_x, motor_y):
|
||||
self.motor_x, self.motor_y = motor_x, motor_y
|
||||
|
||||
@pyqtSlot(list, list)
|
||||
def get_available_motors(self, motors_x, motors_y):
|
||||
self.comboBox_motor_x.addItems(motors_x)
|
||||
self.comboBox_motor_y.addItems(motors_y)
|
||||
|
||||
@pyqtSlot(list, list)
|
||||
def update_limits(self, x_limits: list, y_limits: list) -> None:
|
||||
self.limit_x = x_limits
|
||||
self.limit_y = y_limits
|
||||
self.spinBox_x_min.setValue(self.limit_x[0])
|
||||
self.spinBox_x_max.setValue(self.limit_x[1])
|
||||
self.spinBox_y_min.setValue(self.limit_y[0])
|
||||
self.spinBox_y_max.setValue(self.limit_y[1])
|
||||
|
||||
for spinBox in (
|
||||
self.spinBox_x_min,
|
||||
self.spinBox_x_max,
|
||||
self.spinBox_y_min,
|
||||
self.spinBox_y_max,
|
||||
):
|
||||
spinBox.setStyleSheet("")
|
||||
|
||||
# TODO - names can be get from MotorController
|
||||
self.label_Y_max.setText(f"+ ({self.motor_y.name})")
|
||||
self.label_Y_min.setText(f"- ({self.motor_y.name})")
|
||||
self.label_X_max.setText(f"+ ({self.motor_x.name})")
|
||||
self.label_X_min.setText(f"- ({self.motor_x.name})")
|
||||
|
||||
self.init_motor_map() # reinitialize the map with the new limits
|
||||
|
||||
@pyqtSlot(int, int)
|
||||
def update_speed(self, speed_x, speed_y):
|
||||
self.spinBox_speed_x.setValue(speed_x)
|
||||
self.spinBox_speed_y.setValue(speed_y)
|
||||
for spinBox in (self.spinBox_speed_x, self.spinBox_speed_y):
|
||||
spinBox.setStyleSheet("")
|
||||
|
||||
@pyqtSlot(int, int)
|
||||
def update_update_frequency(self, update_frequency_x, update_frequency_y):
|
||||
self.spinBox_update_frequency_x.setValue(update_frequency_x)
|
||||
self.spinBox_update_frequency_y.setValue(update_frequency_y)
|
||||
for spinBox in (self.spinBox_update_frequency_x, self.spinBox_update_frequency_y):
|
||||
spinBox.setStyleSheet("")
|
||||
|
||||
@pyqtSlot()
|
||||
def enable_motor_control(self):
|
||||
self.motorControl.setEnabled(True)
|
||||
|
||||
def enable_motor_controls(self, disable: bool) -> None:
|
||||
self.motorControl.setEnabled(disable)
|
||||
self.motorSelection.setEnabled(disable)
|
||||
|
||||
# Disable or enable all controls within the motorControl_absolute group box
|
||||
for widget in self.motorControl_absolute.findChildren(QtWidgets.QWidget):
|
||||
widget.setEnabled(disable)
|
||||
|
||||
# Enable the pushButton_stop if the motor is moving
|
||||
self.pushButton_stop.setEnabled(not disable)
|
||||
|
||||
def move_motor_absolute(self, x: float, y: float) -> None:
|
||||
self.enable_motor_controls(False)
|
||||
target_coordinates = (x, y)
|
||||
self.motor_thread.move_to_coordinates(target_coordinates)
|
||||
|
||||
def move_motor_relative(self, motor, value: float) -> None:
|
||||
self.enable_motor_controls(False)
|
||||
self.motor_thread.move_relative(motor, value)
|
||||
|
||||
def update_plot_setting(self, max_points, num_dim_points, scatter_size):
|
||||
self.max_points = max_points
|
||||
self.num_dim_points = num_dim_points
|
||||
self.scatter_size = scatter_size
|
||||
|
||||
for spinBox in (
|
||||
self.spinBox_max_points,
|
||||
self.spinBox_num_dim_points,
|
||||
self.spinBox_scatter_size,
|
||||
):
|
||||
spinBox.setStyleSheet("")
|
||||
|
||||
def init_ui(self) -> None:
|
||||
"""Setup all ui elements"""
|
||||
# TODO can be separated to multiple functions
|
||||
|
||||
##########################
|
||||
# 2D Plot
|
||||
##########################
|
||||
|
||||
self.label_coorditanes = self.glw.addLabel(f"Motor position: (X, Y)", row=0, col=0)
|
||||
self.plot_map = self.glw.addPlot(row=1, col=0)
|
||||
self.limit_map = pg.ImageItem()
|
||||
self.plot_map.addItem(self.limit_map)
|
||||
self.motor_map = pg.ScatterPlotItem(
|
||||
size=self.scatter_size, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 255)
|
||||
)
|
||||
self.plot_map.addItem(self.motor_map)
|
||||
self.plot_map.showGrid(x=True, y=True)
|
||||
|
||||
##########################
|
||||
# Motor General setting
|
||||
##########################
|
||||
|
||||
# TODO make function to update precision
|
||||
self.precision = 2 # self.spinBox_precision.value() # Define the decimal precision
|
||||
|
||||
##########################
|
||||
# Motor movements signals
|
||||
##########################
|
||||
|
||||
self.toolButton_right.clicked.connect(
|
||||
lambda: self.move_motor_relative(self.motor_x, self.spinBox_step.value())
|
||||
)
|
||||
self.toolButton_left.clicked.connect(
|
||||
lambda: self.move_motor_relative(self.motor_x, -self.spinBox_step.value())
|
||||
)
|
||||
self.toolButton_up.clicked.connect(
|
||||
lambda: self.move_motor_relative(self.motor_y, self.spinBox_step.value())
|
||||
)
|
||||
self.toolButton_down.clicked.connect(
|
||||
lambda: self.move_motor_relative(self.motor_y, -self.spinBox_step.value())
|
||||
)
|
||||
|
||||
# Switch between key shortcuts active
|
||||
self.checkBox_enableArrows.stateChanged.connect(self.update_arrow_key_shortcuts)
|
||||
self.update_arrow_key_shortcuts()
|
||||
|
||||
# Move to absolute coordinates
|
||||
self.pushButton_go_absolute.clicked.connect(
|
||||
lambda: self.move_motor_absolute(
|
||||
self.spinBox_absolute_x.value(), self.spinBox_absolute_y.value()
|
||||
)
|
||||
)
|
||||
self.pushButton_go_absolute.clicked.connect(self.save_absolute_coordinates)
|
||||
self.pushButton_go_absolute.setShortcut("Ctrl+G")
|
||||
self.pushButton_go_absolute.setToolTip("Ctrl+G")
|
||||
|
||||
self.motor_thread.move_finished.connect(lambda: self.enable_motor_controls(True))
|
||||
|
||||
# Stop Button
|
||||
self.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
|
||||
|
||||
##########################
|
||||
# Motor Configs
|
||||
##########################
|
||||
|
||||
# SpinBoxes - Motor Limits #TODO make spinboxes own limits updated, currently is [-1000, 1000]
|
||||
|
||||
# SpinBoxes change color to yellow before updated, limits are updated with update button
|
||||
self.spinBox_x_min.valueChanged.connect(lambda: self.param_changed(self.spinBox_x_min))
|
||||
self.spinBox_x_max.valueChanged.connect(lambda: self.param_changed(self.spinBox_x_max))
|
||||
self.spinBox_y_min.valueChanged.connect(lambda: self.param_changed(self.spinBox_y_min))
|
||||
self.spinBox_y_max.valueChanged.connect(lambda: self.param_changed(self.spinBox_y_max))
|
||||
|
||||
# SpinBoxes - Motor Speed
|
||||
self.spinBox_speed_x.valueChanged.connect(lambda: self.param_changed(self.spinBox_speed_x))
|
||||
self.spinBox_speed_y.valueChanged.connect(lambda: self.param_changed(self.spinBox_speed_y))
|
||||
|
||||
# SpinBoxes - Motor Update Frequency
|
||||
self.spinBox_update_frequency_x.valueChanged.connect(
|
||||
lambda: self.param_changed(self.spinBox_update_frequency_x)
|
||||
)
|
||||
self.spinBox_update_frequency_y.valueChanged.connect(
|
||||
lambda: self.param_changed(self.spinBox_update_frequency_y)
|
||||
)
|
||||
|
||||
# SpinBoxes - Max Points and N Dim Points
|
||||
self.spinBox_max_points.valueChanged.connect(
|
||||
lambda: self.param_changed(self.spinBox_max_points)
|
||||
)
|
||||
self.spinBox_num_dim_points.valueChanged.connect(
|
||||
lambda: self.param_changed(self.spinBox_num_dim_points)
|
||||
)
|
||||
self.spinBox_scatter_size.valueChanged.connect(
|
||||
lambda: self.param_changed(self.spinBox_scatter_size)
|
||||
)
|
||||
|
||||
# Config updates
|
||||
self.pushButton_updateLimits.clicked.connect(
|
||||
lambda: self.update_all_motor_limits(
|
||||
x_limit=[self.spinBox_x_min.value(), self.spinBox_x_max.value()],
|
||||
y_limit=[self.spinBox_y_min.value(), self.spinBox_y_max.value()],
|
||||
)
|
||||
)
|
||||
|
||||
self.pushButton_update_config.clicked.connect(
|
||||
lambda: self.update_plot_setting(
|
||||
max_points=self.spinBox_max_points.value(),
|
||||
num_dim_points=self.spinBox_num_dim_points.value(),
|
||||
scatter_size=self.spinBox_scatter_size.value(),
|
||||
)
|
||||
)
|
||||
|
||||
self.pushButton_update_config.clicked.connect(
|
||||
lambda: self.update_all_config(
|
||||
speed=[self.spinBox_speed_x.value(), self.spinBox_speed_y.value()],
|
||||
update_frequency=[
|
||||
self.spinBox_update_frequency_x.value(),
|
||||
self.spinBox_update_frequency_y.value(),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
# TODO map with floats as well -> or decide system for higher precision
|
||||
self.motor_thread.coordinates_updated.connect(
|
||||
lambda x, y: self.update_image_map(round(x, self.precision), round(y, self.precision))
|
||||
)
|
||||
|
||||
# Motor connections
|
||||
self.pushButton_connecMotors.clicked.connect(
|
||||
lambda: self.connect_motor(
|
||||
self.comboBox_motor_x.currentText(), self.comboBox_motor_y.currentText()
|
||||
)
|
||||
)
|
||||
|
||||
# Check if there are any motors connected
|
||||
if self.motor_x or self.motor_y is None:
|
||||
self.motorControl.setEnabled(False)
|
||||
self.motorControl_absolute.setEnabled(False)
|
||||
self.tabWidget_tables.setTabEnabled(1, False)
|
||||
|
||||
# Keyboard shortcuts
|
||||
delete_shortcut = QShortcut(QKeySequence("Delete"), self)
|
||||
backspace_shortcut = QShortcut(QKeySequence("Backspace"), self)
|
||||
delete_shortcut.activated.connect(self.delete_selected_row)
|
||||
backspace_shortcut.activated.connect(self.delete_selected_row)
|
||||
|
||||
def init_motor_map(self):
|
||||
# Get motor limits
|
||||
limit_x_min, limit_x_max = self.motor_thread.get_motor_limits(self.motor_x)
|
||||
limit_y_min, limit_y_max = self.motor_thread.get_motor_limits(self.motor_y)
|
||||
|
||||
self.offset_x = limit_x_min
|
||||
self.offset_y = limit_y_min
|
||||
|
||||
# Define the size of the image map based on the motor's limits
|
||||
map_width = limit_x_max - limit_x_min + 1
|
||||
map_height = limit_y_max - limit_y_min + 1
|
||||
|
||||
# Create an empty image map
|
||||
self.background_value = 15
|
||||
self.limit_map_data = np.full(
|
||||
(map_width, map_height), self.background_value, dtype=np.float32
|
||||
)
|
||||
self.limit_map.setImage(self.limit_map_data)
|
||||
|
||||
# Set the initial position on the map
|
||||
init_pos = self.motor_thread.retrieve_coordinates()
|
||||
self.motor_positions = np.array([init_pos])
|
||||
self.brushes = [pg.mkBrush(255, 255, 255, 255)]
|
||||
|
||||
self.motor_map.setData(pos=self.motor_positions, brush=self.brushes)
|
||||
|
||||
# Translate and scale the image item to match the motor coordinates
|
||||
self.tr = QtGui.QTransform()
|
||||
self.tr.translate(limit_x_min, limit_y_min)
|
||||
self.limit_map.setTransform(self.tr)
|
||||
|
||||
def update_image_map(self, x, y):
|
||||
# Update label
|
||||
self.label_coorditanes.setText(f"Motor position: ({x}, {y})")
|
||||
|
||||
# Add new point with full brightness
|
||||
new_pos = np.array([x, y])
|
||||
self.motor_positions = np.vstack((self.motor_positions, new_pos))
|
||||
|
||||
# If the number of points exceeds max_points, delete the oldest points
|
||||
if len(self.motor_positions) > self.max_points:
|
||||
self.motor_positions = self.motor_positions[-self.max_points :]
|
||||
|
||||
# Determine brushes based on position in the array
|
||||
self.brushes = [pg.mkBrush(50, 50, 50, 255)] * len(self.motor_positions)
|
||||
|
||||
# Calculate the decrement step based on self.num_dim_points
|
||||
decrement_step = (255 - 50) / self.num_dim_points
|
||||
|
||||
for i in range(1, min(self.num_dim_points + 1, len(self.motor_positions) + 1)):
|
||||
brightness = max(50, 255 - decrement_step * (i - 1))
|
||||
self.brushes[-i] = pg.mkBrush(brightness, brightness, brightness, 255)
|
||||
|
||||
self.brushes[-1] = pg.mkBrush(255, 255, 255, 255) # Newest point is always full brightness
|
||||
|
||||
self.motor_map.setData(pos=self.motor_positions, brush=self.brushes, size=self.scatter_size)
|
||||
|
||||
def update_all_motor_limits(self, x_limit: list = None, y_limit: list = None) -> None:
|
||||
self.motor_thread.update_all_motor_limits(x_limit=x_limit, y_limit=y_limit)
|
||||
|
||||
def update_all_config(self, speed: list = None, update_frequency: list = None) -> None:
|
||||
# TODO now only speed and update frequency
|
||||
self.motor_thread.update_all_config(speed=speed, update_frequency=update_frequency)
|
||||
|
||||
def update_arrow_key_shortcuts(self):
|
||||
if self.checkBox_enableArrows.isChecked():
|
||||
# Set the arrow key shortcuts for motor movement
|
||||
self.toolButton_right.setShortcut(Qt.Key_Right)
|
||||
self.toolButton_left.setShortcut(Qt.Key_Left)
|
||||
self.toolButton_up.setShortcut(Qt.Key_Up)
|
||||
self.toolButton_down.setShortcut(Qt.Key_Down)
|
||||
else:
|
||||
# Clear the shortcuts
|
||||
self.toolButton_right.setShortcut("")
|
||||
self.toolButton_left.setShortcut("")
|
||||
self.toolButton_up.setShortcut("")
|
||||
self.toolButton_down.setShortcut("")
|
||||
|
||||
def generate_table_coordinate(
|
||||
self, table: QtWidgets.QTableWidget, coordinates: tuple, tag: str = None, precision: int = 0
|
||||
) -> None:
|
||||
current_row_count = table.rowCount()
|
||||
|
||||
table.setRowCount(current_row_count + 1)
|
||||
|
||||
checkBox = QtWidgets.QCheckBox()
|
||||
checkBox.setChecked(True)
|
||||
button = QtWidgets.QPushButton("Go")
|
||||
|
||||
table.setItem(current_row_count, 0, QtWidgets.QTableWidgetItem(str(tag)))
|
||||
table.setCellWidget(current_row_count, 1, checkBox)
|
||||
table.setItem(
|
||||
current_row_count, 2, QtWidgets.QTableWidgetItem(str(f"{coordinates[0]:.{precision}f}"))
|
||||
)
|
||||
table.setItem(
|
||||
current_row_count, 3, QtWidgets.QTableWidgetItem(str(f"{coordinates[1]:.{precision}f}"))
|
||||
)
|
||||
table.setCellWidget(current_row_count, 4, button)
|
||||
|
||||
# hook signals of table
|
||||
button.clicked.connect(
|
||||
lambda: self.move_motor_absolute(
|
||||
float(table.item(current_row_count, 2).text()),
|
||||
float(table.item(current_row_count, 3).text()),
|
||||
)
|
||||
)
|
||||
table.resizeColumnsToContents()
|
||||
|
||||
def delete_selected_row(self):
|
||||
selected_rows = self.tableWidget_coordinates.selectionModel().selectedRows()
|
||||
|
||||
# If you allow multiple selections, you may want to loop through all selected rows
|
||||
for row in reversed(selected_rows): # Reverse to delete from the end
|
||||
self.tableWidget_coordinates.removeRow(row.row())
|
||||
|
||||
def save_absolute_coordinates(self):
|
||||
self.generate_table_coordinate(
|
||||
self.tableWidget_coordinates,
|
||||
(self.spinBox_absolute_x.value(), self.spinBox_absolute_y.value()),
|
||||
tag=f"Pos {self.tag_N}",
|
||||
precision=0,
|
||||
)
|
||||
|
||||
self.tag_N += 1
|
||||
|
||||
@staticmethod
|
||||
def param_changed(ui_element):
|
||||
ui_element.setStyleSheet("background-color: #FFA700;")
|
||||
|
||||
|
||||
class MotorActions(Enum):
|
||||
MOVE_TO_COORDINATES = "move_to_coordinates"
|
||||
MOVE_RELATIVE = "move_relative"
|
||||
|
||||
|
||||
class MotorControl(QThread):
|
||||
coordinates_updated = pyqtSignal(float, float) # Signal to emit current coordinates
|
||||
limits_retrieved = pyqtSignal(list, list) # Signal to emit current limits
|
||||
speed_retrieved = pyqtSignal(int, int) # Signal to emit current speed
|
||||
update_frequency_retrieved = pyqtSignal(int, int) # Signal to emit current update frequency
|
||||
move_finished = pyqtSignal() # Signal to emit when the move is finished
|
||||
motors_loaded = pyqtSignal(list, list) # Signal to emit when the motors are loaded
|
||||
motors_selected = pyqtSignal(object, object) # Signal to emit when the motors are selected
|
||||
# progress_updated = pyqtSignal(int) #TODO Signal to emit progress percentage
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
):
|
||||
super().__init__(parent)
|
||||
|
||||
self.action = None
|
||||
self._initialize_motor()
|
||||
|
||||
def motor_by_string(self, motor_x_name: str, motor_y_name: str) -> tuple:
|
||||
motor_x_index = self.all_motors_names.index(motor_x_name)
|
||||
motor_y_index = self.all_motors_names.index(motor_y_name)
|
||||
|
||||
motor_x = self.all_motors[motor_x_index]
|
||||
motor_y = self.all_motors[motor_y_index]
|
||||
return motor_x, motor_y
|
||||
|
||||
def connect_motors(self, motor_x_name: str, motor_y_name: str) -> None:
|
||||
self.motor_x, self.motor_y = self.motor_by_string(motor_x_name, motor_y_name)
|
||||
|
||||
(self.current_x, self.current_y) = self.get_coordinates()
|
||||
|
||||
if self.motors_consumer is not None:
|
||||
self.motors_consumer.shutdown()
|
||||
|
||||
self.motors_consumer = client.connector.consumer(
|
||||
topics=[
|
||||
MessageEndpoints.device_readback(self.motor_x.name),
|
||||
MessageEndpoints.device_readback(self.motor_y.name),
|
||||
],
|
||||
cb=self._device_status_callback_motors,
|
||||
parent=self,
|
||||
)
|
||||
|
||||
self.motors_consumer.start()
|
||||
|
||||
self.motors_selected.emit(self.motor_x, self.motor_y)
|
||||
|
||||
def get_all_motors(self) -> list:
|
||||
all_motors = client.device_manager.devices.acquisition_group("motor")
|
||||
return all_motors
|
||||
|
||||
def get_all_motors_names(self) -> list:
|
||||
all_motors = client.device_manager.devices.acquisition_group("motor")
|
||||
all_motors_names = [motor.name for motor in all_motors]
|
||||
return all_motors_names
|
||||
|
||||
def retrieve_all_motors(self):
|
||||
self.all_motors = self.get_all_motors()
|
||||
self.all_motors_names = self.get_all_motors_names()
|
||||
self.motors_loaded.emit(self.all_motors_names, self.all_motors_names)
|
||||
|
||||
return self.all_motors, self.all_motors_names
|
||||
|
||||
def get_coordinates(self) -> tuple:
|
||||
"""Get current motor position"""
|
||||
x = self.motor_x.read(cached=True)["value"]
|
||||
y = self.motor_y.read(cached=True)["value"]
|
||||
return x, y
|
||||
|
||||
def retrieve_coordinates(self) -> tuple:
|
||||
"""Get current motor position for export to main app"""
|
||||
return self.current_x, self.current_y
|
||||
|
||||
def get_motor_limits(self, motor) -> list:
|
||||
"""Get the limits of a motor"""
|
||||
return motor.limits
|
||||
|
||||
def get_motor_config(self, motor) -> dict:
|
||||
"""Get the configuration of a motor""" # TODO at this moment just for speed and update_frequency
|
||||
return motor.get_device_config()
|
||||
|
||||
def update_all_config(self, speed: list = None, update_frequency: list = None) -> None:
|
||||
# TODO now only speed and update frequency
|
||||
if speed is not None:
|
||||
self.motor_x.set_device_config({"speed": speed[0]})
|
||||
self.motor_y.set_device_config({"speed": speed[1]})
|
||||
|
||||
if update_frequency is not None:
|
||||
self.motor_x.set_device_config({"update_frequency": update_frequency[0]})
|
||||
self.motor_y.set_device_config({"update_frequency": update_frequency[1]})
|
||||
|
||||
self.retrieve_motor_speed(self.motor_x, self.motor_y)
|
||||
self.retrieve_motor_update_frequency(self.motor_x, self.motor_y)
|
||||
|
||||
def retrieve_motor_speed(
|
||||
self, motor_x, motor_y
|
||||
) -> None: # TODO can be migrated to some general config function
|
||||
"""Get the speed of a motor"""
|
||||
speed_x = motor_x.get_device_config()["speed"]
|
||||
speed_y = motor_y.get_device_config()["speed"]
|
||||
self.speed_retrieved.emit(int(speed_x), int(speed_y))
|
||||
|
||||
def retrieve_motor_update_frequency(
|
||||
self, motor_x, motor_y
|
||||
) -> None: # TODO can be migrated to some general config function
|
||||
"""Get the speed of a motor"""
|
||||
update_frequency_x = motor_x.get_device_config()["update_frequency"]
|
||||
update_frequency_y = motor_y.get_device_config()["update_frequency"]
|
||||
self.update_frequency_retrieved.emit(int(update_frequency_x), int(update_frequency_y))
|
||||
|
||||
def retrieve_motor_limits(self, motor_x, motor_y):
|
||||
limit_x = self.get_motor_limits(motor_x)
|
||||
limit_y = self.get_motor_limits(motor_y)
|
||||
self.limits_retrieved.emit(limit_x, limit_y)
|
||||
|
||||
def update_motor_limits(self, motor, low_limit=None, high_limit=None) -> None:
|
||||
current_low_limit, current_high_limit = self.get_motor_limits(motor)
|
||||
|
||||
# Check if the low limit has changed and is not None
|
||||
if low_limit is not None and low_limit != current_low_limit:
|
||||
motor.low_limit = low_limit
|
||||
|
||||
# Check if the high limit has changed and is not None
|
||||
if high_limit is not None and high_limit != current_high_limit:
|
||||
motor.high_limit = high_limit
|
||||
|
||||
def update_all_motor_limits(self, x_limit: list = None, y_limit: list = None) -> None:
|
||||
current_position = self.get_coordinates()
|
||||
|
||||
if x_limit is not None:
|
||||
if current_position[0] < x_limit[0] or current_position[0] > x_limit[1]:
|
||||
raise ValueError("Current motor position is outside the new limits (X)")
|
||||
else:
|
||||
self.update_motor_limits(self.motor_x, low_limit=x_limit[0], high_limit=x_limit[1])
|
||||
|
||||
if y_limit is not None:
|
||||
if current_position[1] < y_limit[0] or current_position[1] > y_limit[1]:
|
||||
raise ValueError("Current motor position is outside the new limits (Y)")
|
||||
else:
|
||||
self.update_motor_limits(self.motor_y, low_limit=y_limit[0], high_limit=y_limit[1])
|
||||
|
||||
self.retrieve_motor_limits(self.motor_x, self.motor_y)
|
||||
|
||||
def move_to_coordinates(self, target_coordinates: tuple):
|
||||
self.action = MotorActions.MOVE_TO_COORDINATES
|
||||
self.target_coordinates = target_coordinates
|
||||
self.start()
|
||||
|
||||
def move_relative(self, motor, value: float):
|
||||
self.action = MotorActions.MOVE_RELATIVE
|
||||
self.motor = motor
|
||||
self.value = value
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
if self.action == MotorActions.MOVE_TO_COORDINATES:
|
||||
self._move_motor_coordinate()
|
||||
elif self.action == MotorActions.MOVE_RELATIVE:
|
||||
self._move_motor_relative(self.motor, self.value)
|
||||
|
||||
def set_target_coordinates(self, target_coordinates: tuple) -> None:
|
||||
self.target_coordinates = target_coordinates
|
||||
|
||||
def _initialize_motor(self) -> None:
|
||||
self.motor_x, self.motor_y = None, None
|
||||
self.current_x, self.current_y = None, None
|
||||
|
||||
self.motors_consumer = None
|
||||
|
||||
# Get all available motors in the client
|
||||
self.all_motors = self.get_all_motors()
|
||||
self.all_motors_names = self.get_all_motors_names()
|
||||
self.retrieve_all_motors() # send motor list to GUI
|
||||
|
||||
self.target_coordinates = None
|
||||
|
||||
def _move_motor_coordinate(self) -> None:
|
||||
"""Move the motor to the specified coordinates"""
|
||||
status = scans.mv(
|
||||
self.motor_x,
|
||||
self.target_coordinates[0],
|
||||
self.motor_y,
|
||||
self.target_coordinates[1],
|
||||
relative=False,
|
||||
)
|
||||
|
||||
status.wait()
|
||||
self.move_finished.emit()
|
||||
|
||||
def _move_motor_relative(self, motor, value: float) -> None:
|
||||
status = scans.mv(motor, value, relative=True)
|
||||
|
||||
status.wait()
|
||||
self.move_finished.emit()
|
||||
|
||||
def stop_movement(self):
|
||||
queue.request_scan_abortion()
|
||||
queue.request_queue_reset()
|
||||
|
||||
@staticmethod
|
||||
def _device_status_callback_motors(msg, *, parent, **_kwargs) -> None:
|
||||
deviceMSG = BECMessage.DeviceMessage.loads(msg.value)
|
||||
if parent.motor_x.name in deviceMSG.content["signals"]:
|
||||
parent.current_x = deviceMSG.content["signals"][parent.motor_x.name]["value"]
|
||||
elif parent.motor_y.name in deviceMSG.content["signals"]:
|
||||
parent.current_y = deviceMSG.content["signals"][parent.motor_y.name]["value"]
|
||||
parent.coordinates_updated.emit(parent.current_x, parent.current_y)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from bec_lib import BECClient
|
||||
|
||||
# from bec_lib.core import ServiceConfig,RedisConnector
|
||||
|
||||
client = BECClient()
|
||||
# client.initialize(config=ServiceConfig(config_path="test_config.yaml"))
|
||||
|
||||
# Client initialization - by dispatcher
|
||||
# client = bec_dispatcher.client
|
||||
client.start()
|
||||
dev = client.device_manager.devices
|
||||
scans = client.scans
|
||||
queue = client.queue
|
||||
|
||||
app = QApplication([])
|
||||
window = MotorApp()
|
||||
window.show()
|
||||
app.exec_()
|
||||
@@ -12,12 +12,11 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
from pyqtgraph import mkPen
|
||||
from pyqtgraph.Qt import QtCore
|
||||
from crosshair import Crosshair
|
||||
from bec_widgets.qt_utils import Crosshair
|
||||
|
||||
|
||||
class ExampleApp(QWidget):
|
||||
def __init__(self):
|
||||
"""Example application for using the Crosshair class"""
|
||||
super().__init__()
|
||||
|
||||
# Layout
|
||||
0
bec_widgets/widgets/__init__.py
Normal file
0
bec_widgets/widgets/__init__.py
Normal file
Reference in New Issue
Block a user