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