mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-13 19:21:50 +02:00
feat: setting map according to motor limits
This commit is contained in:
@ -6,33 +6,74 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>266</height>
|
||||
<width>1289</width>
|
||||
<height>596</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Motor Controller</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_status">
|
||||
<property name="text">
|
||||
<string>Motor Position</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1,1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_status">
|
||||
<property name="text">
|
||||
<string>Motor Position</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<widget class="GraphicsLayoutWidget" name="glw">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</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>
|
||||
<widget class="QGroupBox" name="motorControl">
|
||||
<property name="title">
|
||||
@ -92,7 +133,7 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Motor Limits</string>
|
||||
@ -120,13 +161,34 @@
|
||||
</widget>
|
||||
</item>
|
||||
<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 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 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 row="1" column="3">
|
||||
<widget class="QLabel" name="label_3">
|
||||
@ -136,12 +198,12 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QSpinBox" name="spinBox_samyN"/>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
<widget class="QSpinBox" name="spinBox_y_min">
|
||||
<property name="minimum">
|
||||
<number>-1000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -150,6 +212,94 @@
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
from PyQt5 import QtGui
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import QApplication, QWidget
|
||||
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)
|
||||
|
||||
# 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()
|
||||
|
||||
def init_ui(self):
|
||||
@ -31,13 +39,17 @@ class MotorApp(QWidget):
|
||||
self.image_map = pg.ImageItem()
|
||||
self.plot_map.addItem(self.image_map)
|
||||
|
||||
self.image_map_data = np.zeros((100, 100), dtype=np.float32)
|
||||
x, y = self.get_xy() # Assuming get_xy returns the motor position
|
||||
self.update_image_map(x, y)
|
||||
self.image_map.setImage(self.image_map_data.T) # Set the image
|
||||
# self.image_map_data = np.zeros((100, 100), dtype=np.float32)
|
||||
# x, y = self.get_xy() # Assuming get_xy returns the motor position
|
||||
# self.update_image_map(x, y)
|
||||
# self.image_map.setImage(self.image_map_data.T) # Set the image
|
||||
|
||||
# self.init_motor_map()
|
||||
|
||||
##########################
|
||||
# Signals
|
||||
##########################
|
||||
|
||||
# Buttons - Motor Movement
|
||||
self.toolButton_right.clicked.connect(
|
||||
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())
|
||||
)
|
||||
|
||||
# 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
|
||||
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:
|
||||
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()
|
||||
|
||||
self.motor_position.emit(motor_position)
|
||||
@ -83,22 +200,6 @@ class MotorApp(QWidget):
|
||||
y = dev.samy.position()
|
||||
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__":
|
||||
from bec_widgets.bec_dispatcher import bec_dispatcher
|
||||
|
Reference in New Issue
Block a user