initial commit
This commit is contained in:
103
Readme.md
Normal file
103
Readme.md
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
EPICS simulator
|
||||||
|
---------------
|
||||||
|
This provides very dummy images and motor(to be done) records
|
||||||
|
|
||||||
|
cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/EpicsSim/iocBoot/iocSwissMxSim
|
||||||
|
./st.cmd
|
||||||
|
|
||||||
|
simulate camera (with EPICS simulator)
|
||||||
|
--------------------------------------
|
||||||
|
cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX
|
||||||
|
EPICS_CA_ADDR_LIST=localhost
|
||||||
|
./simCam.py
|
||||||
|
|
||||||
|
test camera display
|
||||||
|
-------------------
|
||||||
|
cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX
|
||||||
|
EPICS_CA_ADDR_LIST=localhost
|
||||||
|
./camera.py -u -b SwissMxSim
|
||||||
|
|
||||||
|
|
||||||
|
https://git.psi.ch/SwissMX/swissmx_cristallina/-/wikis/Instructions%20on%20how%20to%20use%20software
|
||||||
|
|
||||||
|
|
||||||
|
caQtDM -macro 'P=SAR-EXPMX' /photonics/home/gac-cristall/Documents/swissmx_cristallina/gui/SwissMX_ChipMotion.ui
|
||||||
|
caQtDM -macro 'P=SAR-EXPMX' ESB_MX_exp.ui
|
||||||
|
|
||||||
|
Camera:
|
||||||
|
caget SARES30-CAMS156-SMX-OAV:CAMERASTATUS
|
||||||
|
caget SARES30-CAMS156-SMX-OAV:PICTURE
|
||||||
|
|
||||||
|
Zoom:
|
||||||
|
caget SAR-EXPMX-FETURA:POS_RB
|
||||||
|
|
||||||
|
|
||||||
|
wlp2s0: MAC: 80:38:fb:d6:01:78 wlan-corp 129.129.64.249
|
||||||
|
enx00e04c680519: MAC: 00:e0:4c:68:05:19
|
||||||
|
|
||||||
|
|
||||||
|
import pyqtgraph.examples
|
||||||
|
pyqtgraph.examples.run()
|
||||||
|
Benchmark -> VideoSpeedTest
|
||||||
|
|
||||||
|
rsync -vai /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX/ saresc-cons-02:/tmp/zamofing_t/
|
||||||
|
|
||||||
|
|
||||||
|
/opt/gfa/python-3.5/latest/bin/python camera.py --base-pv SARES30-CAMS156-SMX-OAV
|
||||||
|
|
||||||
|
BASE=~/Documents/prj/SwissFEL/epics_ioc_modules/LakeShore
|
||||||
|
cd $BASE/iocBoot/iocLakeShore1
|
||||||
|
../../bin/UB20-x86_64/LakeShore st.cmd
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[saresc-cons-02 ~]$ ioc records 'SARES30-CAMS156-SMX-OAV:.*'
|
||||||
|
|
||||||
|
|
||||||
|
SARES30-CAMS156-SMX-OAV:PICTURE waveform CCD Picure Col SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:FPICTURE waveform CCD Picture SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:RF_FPICTURE waveform Reduced frequency FPICTURE SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:WIDTH ai Nr. of Pixel width SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:HEIGHT ai Nr. of Pixel height SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:EXPOSURE ao Exposure SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:CAMROI_X_START ao ROI X Start SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:CAMROI_X_END ao ROI X End SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:CAMROI_Y_START ao ROI Y Start SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:CAMROI_Y_END ao ROI Y End SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:BINX ao Binning X SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
SARES30-CAMS156-SMX-OAV:BINY ao Binning Y SARES30-CPCW-CAMS156-SMX-OAV office
|
||||||
|
|
||||||
|
waveform:
|
||||||
|
Native DBF type: DBF_SHORT
|
||||||
|
Number of elements: 5000
|
||||||
|
|
||||||
|
SARES30-CAMS156-SMX-OAV:WIDTH 2448
|
||||||
|
SARES30-CAMS156-SMX-OAV:HEIGHT 2048
|
||||||
|
|
||||||
|
caqtdm camsf
|
||||||
|
caqtdm -macro 'NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV' /sf/controls/config/qt/Camera/CameraMiniView_RF.ui
|
||||||
|
caqtdm -macro 'NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV' /sf/controls/config/qt/Camera/CameraExpert_RF.ui
|
||||||
|
|
||||||
|
03 last file: /sf/controls/config/qt/Camera/CameraMiniView_RF.ui, macro: NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV
|
||||||
|
|
||||||
|
|
||||||
|
07-07-2022 12:14:03 last file: /sf/controls/config/qt/Camera/CameraMiniView_RF.ui, macro: NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV
|
||||||
|
mkdir EpicsSim
|
||||||
|
cd EpicsSim
|
||||||
|
makeBaseApp.pl -t ioc SwissMxSim
|
||||||
|
makeBaseApp.pl -a UB20-x86_64 -i -t ioc -p SwissMxSim SwissMxSim
|
||||||
|
|
||||||
|
cd ~/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/EpicsSim/iocBoot/iocSwissMxSim
|
||||||
|
./st.cmd
|
||||||
|
|
||||||
|
EPICS_CA_ADDR_LIST=localhost
|
||||||
|
ipython3
|
||||||
|
import epics
|
||||||
|
p = epics.PV('SwissMxSim:PICTURE', auto_monitor=False)
|
||||||
|
print(p.info)
|
||||||
|
import numpy as np
|
||||||
|
a=np.arange(10000,dtype=np.uint16)
|
||||||
|
p.put(a)
|
||||||
|
print(p.get())
|
||||||
|
https://pyepics.github.io/pyepics/arrays.html
|
||||||
|
|
||||||
203
camera.py
Executable file
203
camera.py
Executable file
@@ -0,0 +1,203 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""
|
||||||
|
Hi Zac,
|
||||||
|
|
||||||
|
at the moment there is no channel for the min or max values. The reason for this is the binning. With this you change these numbers.
|
||||||
|
At the end you need 3*2 numbers :
|
||||||
|
Physical resolution
|
||||||
|
Max resolution for ROI
|
||||||
|
Resolution of your image
|
||||||
|
And the logic how you can change the numbers ;-)
|
||||||
|
|
||||||
|
The simples trick for getting the max resolution is to set binning to 1 and write big numbers in the ROI (REGIONX_END / REGIONY_END) channels . They will be corrected to the max resolution.
|
||||||
|
|
||||||
|
Sorry for this. When you want all numbers, I can think about the export of the whole "mess". Inside the IOC there is the central checking routine. Sometimes it could be helpful to have this in EPICS.
|
||||||
|
|
||||||
|
Best regards
|
||||||
|
Helge
|
||||||
|
"""
|
||||||
|
|
||||||
|
import enum
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import epics
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
global imv
|
||||||
|
|
||||||
|
|
||||||
|
class camera_server(object):
|
||||||
|
|
||||||
|
def __init__(self, basename="ESB-MX-CAM"):
|
||||||
|
self._pv=pv=dict()
|
||||||
|
os.environ['EPICS_CA_ADDR_LIST'] = 'localhost'
|
||||||
|
if basename[-1]!=':': basename+=':'
|
||||||
|
self._transformations = []
|
||||||
|
pv['pic']=epics.PV(basename+"FPICTURE", auto_monitor=True, callback=self.new_frame_callback)
|
||||||
|
for k,v in (('w','WIDTH'),('h','HEIGHT'),):
|
||||||
|
pv[k]=epics.PV(basename+v)
|
||||||
|
return
|
||||||
|
|
||||||
|
def new_frame_callback(self, **kwargs):
|
||||||
|
"""kargs contains:
|
||||||
|
pvname: the name of the pv
|
||||||
|
value: the latest value
|
||||||
|
char_value: string representation of value
|
||||||
|
count: the number of data elements
|
||||||
|
ftype: the numerical CA type indicating the data type
|
||||||
|
type: the python type for the data
|
||||||
|
status: the status of the PV (1 for OK)
|
||||||
|
precision: number of decimal places of precision for floating point values
|
||||||
|
units: string for PV units
|
||||||
|
severity: PV severity
|
||||||
|
timestamp: timestamp from CA server.
|
||||||
|
read_access: read access (True/False)
|
||||||
|
write_access: write access (True/False)
|
||||||
|
access: string description of read- and write-access
|
||||||
|
host: host machine and CA port serving PV
|
||||||
|
enum_strs: the list of enumeration strings
|
||||||
|
upper_disp_limit: upper display limit
|
||||||
|
lower_disp_limit: lower display limit
|
||||||
|
upper_alarm_limit: upper alarm limit
|
||||||
|
lower_alarm_limit: lower alarm limit
|
||||||
|
upper_warning_limit: upper warning limit
|
||||||
|
lower_warning_limit: lower warning limit
|
||||||
|
upper_ctrl_limit: upper control limit
|
||||||
|
lower_ctrl_limit: lower control limit
|
||||||
|
chid: integer channel ID
|
||||||
|
cb_info: (index, self) tuple containing callback ID
|
||||||
|
and the PV object"""
|
||||||
|
print('new_frame_callback')
|
||||||
|
try:
|
||||||
|
pv=self._pv
|
||||||
|
w, h = int(pv['w'].value), int(pv['h'].value)
|
||||||
|
pic = pv['pic'].get(count=w * h, as_numpy=True).reshape((h, w))
|
||||||
|
if pic.dtype==np.int16:
|
||||||
|
pic.dtype=np.uint16
|
||||||
|
self.pic=pic
|
||||||
|
print(pic[-1][-1])
|
||||||
|
imv.setImage(pic)
|
||||||
|
except:
|
||||||
|
logger.warning("failed to fetch image")
|
||||||
|
|
||||||
|
def get_image(self):
|
||||||
|
pv=self._pv
|
||||||
|
try:
|
||||||
|
pic = self.pic
|
||||||
|
except:
|
||||||
|
self.new_frame_callback()
|
||||||
|
pic = self.pic
|
||||||
|
for t in self._transformations:
|
||||||
|
if Transforms.ROTATE_90 == t:
|
||||||
|
pic = np.rot90(pic, 1)
|
||||||
|
elif Transforms.ROTATE_180 == t:
|
||||||
|
pic = np.rot90(pic, 2)
|
||||||
|
elif Transforms.ROTATE_270 == t:
|
||||||
|
pic = np.rot90(pic, 3)
|
||||||
|
elif Transforms.FLIP_LR == t:
|
||||||
|
pic = np.fliplr(pic)
|
||||||
|
elif Transforms.FLIP_UD == t:
|
||||||
|
pic = np.flipud(pic)
|
||||||
|
elif Transforms.TRANSPOSE == t:
|
||||||
|
pic = pic.transpose()
|
||||||
|
return pic
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import time, os, PIL
|
||||||
|
|
||||||
|
logging.basicConfig(format="%(asctime)s $(levelname)s %(message)s", level=logging.DEBUG)
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--ui", "-u", help="qt test", action="store_true")
|
||||||
|
parser.add_argument("--base-pv","-b",help="PV prefix for images; default=ESB-MX-CAM",type=str,default="ESB-MX-CAM",)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
print('STARTING')
|
||||||
|
os.environ['EPICS_CA_ADDR_LIST']='localhost'
|
||||||
|
cam = camera_server(basename=args.base_pv)
|
||||||
|
#pv = cam._pv
|
||||||
|
#w, h = int(pv['w'].value), int(pv['h'].value)
|
||||||
|
#a = np.arange(w*h, dtype=np.uint16)
|
||||||
|
#pv['pic'].put(a)
|
||||||
|
#print(pv['pic'].get())
|
||||||
|
|
||||||
|
if not args.ui:
|
||||||
|
n = 1
|
||||||
|
base = time.strftime("/tmp/image_%Y%m%d_%H%M%S_{:05d}.png")
|
||||||
|
while True:
|
||||||
|
fname = base.format(n)
|
||||||
|
img=cam.get_image()
|
||||||
|
print(type(img))
|
||||||
|
type(img)
|
||||||
|
print(img,img.dtype)
|
||||||
|
PIL.Image.fromarray(img).save(fname)
|
||||||
|
logging.info("acquired {}".format(fname))
|
||||||
|
try:
|
||||||
|
input("<enter> for next image, ctrl-c to abort")
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
exit(0)
|
||||||
|
n += 1
|
||||||
|
else:
|
||||||
|
import sys
|
||||||
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
|
import pyqtgraph as pg
|
||||||
|
print(pg.__version__)
|
||||||
|
|
||||||
|
# Interpret image data as row-major instead of col-major
|
||||||
|
pg.setConfigOptions(imageAxisOrder='row-major')
|
||||||
|
|
||||||
|
app = QtGui.QApplication([])
|
||||||
|
|
||||||
|
## Create window with ImageView widget
|
||||||
|
win = QtGui.QMainWindow()
|
||||||
|
win.resize(800,800)
|
||||||
|
imv = pg.ImageView()
|
||||||
|
win.setCentralWidget(imv)
|
||||||
|
win.show()
|
||||||
|
win.setWindowTitle('pyqtgraph example: ImageView')
|
||||||
|
|
||||||
|
## Create random 3D data set with noisy signals
|
||||||
|
img = pg.gaussianFilter(np.random.normal(size=(200, 200)), (5, 5)) * 20 + 100
|
||||||
|
img = img[np.newaxis,:,:]
|
||||||
|
decay = np.exp(-np.linspace(0,0.3,100))[:,np.newaxis,np.newaxis]
|
||||||
|
data = np.random.normal(size=(100, 200, 200))
|
||||||
|
data += img * decay
|
||||||
|
data += 2
|
||||||
|
|
||||||
|
## Add time-varying signal
|
||||||
|
sig = np.zeros(data.shape[0])
|
||||||
|
sig[30:] += np.exp(-np.linspace(1,10, 70))
|
||||||
|
sig[40:] += np.exp(-np.linspace(1,10, 60))
|
||||||
|
sig[70:] += np.exp(-np.linspace(1,10, 30))
|
||||||
|
|
||||||
|
sig = sig[:,np.newaxis,np.newaxis] * 3
|
||||||
|
data[:,50:60,30:40] += sig
|
||||||
|
|
||||||
|
|
||||||
|
## Display the data and assign each frame a time value from 1.0 to 3.0
|
||||||
|
imv.setImage(data, xvals=np.linspace(1., 3., data.shape[0]))
|
||||||
|
imv.setImage(cam.get_image())
|
||||||
|
|
||||||
|
## Set a custom color map
|
||||||
|
colors = [
|
||||||
|
(0, 0, 0),
|
||||||
|
(45, 5, 61),
|
||||||
|
(84, 42, 55),
|
||||||
|
(150, 87, 60),
|
||||||
|
(208, 171, 141),
|
||||||
|
(255, 255, 255)
|
||||||
|
]
|
||||||
|
cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=colors)
|
||||||
|
imv.setColorMap(cmap)
|
||||||
|
|
||||||
|
## Start Qt event loop unless running in interactive mode.
|
||||||
|
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
||||||
|
QtGui.QApplication.instance().exec_()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
34
simCam.py
Executable file
34
simCam.py
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# *-----------------------------------------------------------------------*
|
||||||
|
# | |
|
||||||
|
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
# | |
|
||||||
|
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
|
||||||
|
# *-----------------------------------------------------------------------*
|
||||||
|
import os,epics
|
||||||
|
import time
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
print('STARTING')
|
||||||
|
os.environ['EPICS_CA_ADDR_LIST'] = 'localhost'
|
||||||
|
|
||||||
|
pv=dict()
|
||||||
|
basename='SwissMxSim:'
|
||||||
|
#pv['pic'] = epics.PV(basename + "FPICTURE", auto_monitor=True, callback=self.new_frame_callback)
|
||||||
|
pv['pic'] = epics.PV(basename + "FPICTURE")
|
||||||
|
for k, v in (('w', 'WIDTH'), ('h', 'HEIGHT'),):
|
||||||
|
pv[k] = epics.PV(basename + v)
|
||||||
|
|
||||||
|
pv['w'].put(300)
|
||||||
|
pv['h'].put(400)
|
||||||
|
|
||||||
|
w, h = int(pv['w'].value), int(pv['h'].value)
|
||||||
|
|
||||||
|
|
||||||
|
for j in range(100):
|
||||||
|
for i in range(20):
|
||||||
|
a = np.arange(w * h, dtype=np.uint16)//i
|
||||||
|
pv['pic'].put(a)
|
||||||
|
print(pv['pic'].get())
|
||||||
|
time.sleep(.01)
|
||||||
Reference in New Issue
Block a user