mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
feat: setting map according to motor limits
This commit is contained in:
@ -6,33 +6,74 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>1289</width>
|
||||||
<height>266</height>
|
<height>596</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Motor Controller</string>
|
<string>Motor Controller</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_status">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<property name="text">
|
<item>
|
||||||
<string>Motor Position</string>
|
<widget class="QLabel" name="label_status">
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="alignment">
|
<string>Motor Position</string>
|
||||||
<set>Qt::AlignCenter</set>
|
</property>
|
||||||
</property>
|
<property name="alignment">
|
||||||
</widget>
|
<set>Qt::AlignCenter</set>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
</widget>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,1">
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Go</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="GraphicsLayoutWidget" name="glw">
|
<widget class="GraphicsLayoutWidget" name="glw">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="1,10,10">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>General</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Decimal precision</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="motorControl">
|
<widget class="QGroupBox" name="motorControl">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -92,7 +133,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Motor Limits</string>
|
<string>Motor Limits</string>
|
||||||
@ -120,13 +161,34 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QSpinBox" name="spinBox_samxN"/>
|
<widget class="QSpinBox" name="spinBox_x_min">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-1000</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="1" column="2">
|
||||||
<widget class="QSpinBox" name="spinBox_samyP"/>
|
<widget class="QSpinBox" name="spinBox_y_max">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-1000</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="3">
|
<item row="2" column="3">
|
||||||
<widget class="QSpinBox" name="spinBox_samxP"/>
|
<widget class="QSpinBox" name="spinBox_x_max">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-1000</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="3">
|
<item row="1" column="3">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3">
|
||||||
@ -136,12 +198,12 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="2">
|
<item row="3" column="2">
|
||||||
<widget class="QSpinBox" name="spinBox_samyN"/>
|
<widget class="QSpinBox" name="spinBox_y_min">
|
||||||
</item>
|
<property name="minimum">
|
||||||
<item row="2" column="2">
|
<number>-1000</number>
|
||||||
<widget class="QPushButton" name="pushButton">
|
</property>
|
||||||
<property name="text">
|
<property name="maximum">
|
||||||
<string>Update</string>
|
<number>1000</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -150,6 +212,94 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Saved</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Go to selected</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="tableWidget">
|
||||||
|
<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>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Queue</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset Queue</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="tableWidget_2">
|
||||||
|
<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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from PyQt5 import QtGui
|
||||||
from PyQt5.QtCore import pyqtSignal
|
from PyQt5.QtCore import pyqtSignal
|
||||||
from PyQt5.QtWidgets import QApplication, QWidget
|
from PyQt5.QtWidgets import QApplication, QWidget
|
||||||
from pyqtgraph.Qt import QtCore, QtWidgets, uic
|
from pyqtgraph.Qt import QtCore, QtWidgets, uic
|
||||||
@ -17,7 +18,14 @@ class MotorApp(QWidget):
|
|||||||
uic.loadUi(os.path.join(current_path, "motor_controller.ui"), self)
|
uic.loadUi(os.path.join(current_path, "motor_controller.ui"), self)
|
||||||
|
|
||||||
# UI
|
# UI
|
||||||
|
self.start_x, self.start_y = self.get_xy()
|
||||||
|
self.limit_x, self.limit_y = self.get_motor_limits(dev.samx), self.get_motor_limits(
|
||||||
|
dev.samy
|
||||||
|
)
|
||||||
|
|
||||||
|
self.label_status.setText(
|
||||||
|
f"Motor position: ({dev.samx.position():.2f}, {dev.samy.position():.2f})"
|
||||||
|
)
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
@ -31,13 +39,17 @@ class MotorApp(QWidget):
|
|||||||
self.image_map = pg.ImageItem()
|
self.image_map = pg.ImageItem()
|
||||||
self.plot_map.addItem(self.image_map)
|
self.plot_map.addItem(self.image_map)
|
||||||
|
|
||||||
self.image_map_data = np.zeros((100, 100), dtype=np.float32)
|
# self.image_map_data = np.zeros((100, 100), dtype=np.float32)
|
||||||
x, y = self.get_xy() # Assuming get_xy returns the motor position
|
# x, y = self.get_xy() # Assuming get_xy returns the motor position
|
||||||
self.update_image_map(x, y)
|
# self.update_image_map(x, y)
|
||||||
self.image_map.setImage(self.image_map_data.T) # Set the image
|
# self.image_map.setImage(self.image_map_data.T) # Set the image
|
||||||
|
|
||||||
|
# self.init_motor_map()
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
# Signals
|
# Signals
|
||||||
##########################
|
##########################
|
||||||
|
|
||||||
# Buttons - Motor Movement
|
# Buttons - Motor Movement
|
||||||
self.toolButton_right.clicked.connect(
|
self.toolButton_right.clicked.connect(
|
||||||
lambda: self.move_motor(dev.samx, self.spinBox_step.value())
|
lambda: self.move_motor(dev.samx, self.spinBox_step.value())
|
||||||
@ -52,6 +64,32 @@ class MotorApp(QWidget):
|
|||||||
lambda: self.move_motor(dev.samy, -self.spinBox_step.value())
|
lambda: self.move_motor(dev.samy, -self.spinBox_step.value())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# SpinBoxes - Motor Limits #TODO make spinboxes own limits updated, currently is [-1000, 1000]
|
||||||
|
# manually set limits before readout #TODO will be removed when spinboxes have own limits
|
||||||
|
# dev.samx.low_limit = -100
|
||||||
|
# dev.samx.high_limit = 100
|
||||||
|
# dev.samy.low_limit = -100
|
||||||
|
# dev.samy.high_limit = 100
|
||||||
|
|
||||||
|
# display initial 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])
|
||||||
|
# # change limits of motors for all motors and spinboxes
|
||||||
|
self.spinBox_x_min.valueChanged.connect(
|
||||||
|
lambda x: self.update_motor_limits(dev.samx, low_limit=x)
|
||||||
|
)
|
||||||
|
self.spinBox_x_max.valueChanged.connect(
|
||||||
|
lambda x: self.update_motor_limits(dev.samx, high_limit=x)
|
||||||
|
)
|
||||||
|
self.spinBox_y_min.valueChanged.connect(
|
||||||
|
lambda x: self.update_motor_limits(dev.samy, low_limit=x)
|
||||||
|
)
|
||||||
|
self.spinBox_y_max.valueChanged.connect(
|
||||||
|
lambda x: self.update_motor_limits(dev.samy, high_limit=x)
|
||||||
|
)
|
||||||
|
|
||||||
# Map
|
# Map
|
||||||
self.motor_position.connect(lambda x: self.update_image_map(*self.get_xy()))
|
self.motor_position.connect(lambda x: self.update_image_map(*self.get_xy()))
|
||||||
|
|
||||||
@ -70,8 +108,87 @@ class MotorApp(QWidget):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.init_motor_map()
|
||||||
|
|
||||||
|
def init_motor_map(self):
|
||||||
|
# Get motor limits
|
||||||
|
limit_x_min, limit_x_max = self.get_motor_limits(dev.samx)
|
||||||
|
limit_y_min, limit_y_max = self.get_motor_limits(dev.samy)
|
||||||
|
|
||||||
|
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.image_map_data = np.full(
|
||||||
|
(map_width, map_height), self.background_value, dtype=np.float32
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set the initial position on the map
|
||||||
|
x, y = self.get_xy()
|
||||||
|
self.prev_x, self.prev_y = x, y
|
||||||
|
self.update_image_map(x, y)
|
||||||
|
|
||||||
|
# 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.image_map.setTransform(self.tr)
|
||||||
|
|
||||||
|
self.image_map.dataTransform()
|
||||||
|
|
||||||
|
def update_image_map(self, x, y):
|
||||||
|
"""Update the image map with the new motor position"""
|
||||||
|
|
||||||
|
# Define the dimming factor
|
||||||
|
dimming_factor = 0.80
|
||||||
|
|
||||||
|
# Apply the dimming factor only to pixels above the background value
|
||||||
|
self.image_map_data[self.image_map_data > self.background_value] *= dimming_factor
|
||||||
|
|
||||||
|
# Mapping of motor coordinates to pixel coordinates
|
||||||
|
pixel_x = int(x - self.offset_x)
|
||||||
|
pixel_y = int(y - self.offset_y)
|
||||||
|
|
||||||
|
# Set the bright pixel at the new position
|
||||||
|
self.image_map_data[pixel_x, pixel_y] = 255
|
||||||
|
|
||||||
|
# Update the display
|
||||||
|
self.image_map.updateImage(self.image_map_data, levels=(0, 255))
|
||||||
|
|
||||||
|
def get_motor_limits(self, motor):
|
||||||
|
"""Get the limits of a motor"""
|
||||||
|
high_limit = motor.high_limit
|
||||||
|
low_limit = motor.low_limit
|
||||||
|
|
||||||
|
return low_limit, high_limit
|
||||||
|
|
||||||
|
def update_motor_limits(self, motor, low_limit=None, high_limit=None):
|
||||||
|
# Get current limits
|
||||||
|
current_low_limit, current_high_limit = motor.limits[0], motor.limits[1]
|
||||||
|
|
||||||
|
# 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 move_motor(self, motor, value: float) -> None:
|
def move_motor(self, motor, value: float) -> None:
|
||||||
scans.mv(motor, value, relative=True)
|
try:
|
||||||
|
status = scans.mv(motor, value, relative=True)
|
||||||
|
|
||||||
|
while status.status not in ["COMPLETED", "STOPPED"]:
|
||||||
|
print(status.status)
|
||||||
|
|
||||||
|
# return status
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
motor_position = motor.position()
|
motor_position = motor.position()
|
||||||
|
|
||||||
self.motor_position.emit(motor_position)
|
self.motor_position.emit(motor_position)
|
||||||
@ -83,22 +200,6 @@ class MotorApp(QWidget):
|
|||||||
y = dev.samy.position()
|
y = dev.samy.position()
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
def update_image_map(self, x, y):
|
|
||||||
"""Update the image map with the new motor position"""
|
|
||||||
|
|
||||||
# Reduce the brightness of all pixels by a fixed fraction (e.g., 5%)
|
|
||||||
self.image_map_data *= 0.8
|
|
||||||
|
|
||||||
# Modify this mapping as needed
|
|
||||||
pixel_x = int(x)
|
|
||||||
pixel_y = int(y)
|
|
||||||
|
|
||||||
# Set the bright pixel at the new position
|
|
||||||
self.image_map_data[pixel_x, pixel_y] = 255
|
|
||||||
|
|
||||||
# Update the display
|
|
||||||
self.image_map.setImage(self.image_map_data)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from bec_widgets.bec_dispatcher import bec_dispatcher
|
from bec_widgets.bec_dispatcher import bec_dispatcher
|
||||||
|
Reference in New Issue
Block a user