Added new implementation of smaract

This commit is contained in:
2020-11-17 10:37:36 +01:00
parent 6efb6e38c7
commit 37e9e75dd2
5 changed files with 390 additions and 85 deletions
+24 -7
View File
@@ -376,11 +376,21 @@ class PvRecord:
# @default_representation
@spec_convenience
class PvEnum:
def __init__(self, pvname, name=None):
def __init__(self, pvname, pvname_set=None, name=None):
self.Id = pvname
self._pv = PV(pvname)
self.name = name
self.enum_strs = self._pv.enum_strs
if pvname_set:
self._pv_set = PV(pvname_set)
tstrs = self._pv_set.enum_strs
if not (tstrs == self.enum_strs):
raise Exception("pv enum setter strings do not match the values!")
else:
self._pv_set = None
if name:
enumname = self.name
else:
@@ -402,8 +412,11 @@ class PvEnum:
def set_target_value(self, value, hold=False):
""" Adjustable convention"""
value = self.validate(value)
changer = lambda value: self._pv.put(value, wait=True)
if self._pv_set:
tpv = self._pv_set
else:
tpv = self._pv
changer = lambda value: tpv.put(value, wait=True)
return Changer(
target=value, parent=self, changer=changer, hold=hold, stopper=None
)
@@ -425,6 +438,7 @@ class PvEnum:
s += "{:>4} {} {}\n".format(val, sel, name)
return s
class PvString:
def __init__(self, pvname, name=None, elog=None):
self.name = name
@@ -441,7 +455,7 @@ class PvString:
return Changer(
target=value, parent=self, changer=changer, hold=hold, stopper=None
)
def __repr__(self):
return self.get_current_value()
@@ -451,6 +465,7 @@ class PvString:
else:
return self.get_current_value()
@default_representation
@spec_convenience
class AdjustableVirtual:
@@ -536,8 +551,10 @@ class AdjustableGetSet:
self._set = foo_set
self._get = foo_get
def set_target_value(self,value):
return Changer(target=value, parent=self, changer=self._set, hold=False, stopper=None)
def set_target_value(self, value):
return Changer(
target=value, parent=self, changer=self._set, hold=False, stopper=None
)
def get_current_value(self):
return self._get()
+296 -17
View File
@@ -12,7 +12,9 @@ from ..utilities.KeyPress import KeyPress
import sys, colorama
from .. import global_config
from ..elements.assembly import Assembly
import time
from .adjustable import PvRecord, PvEnum, PvString
import numpy as np
if hasattr(global_config, "elog"):
elog = global_config.elog
@@ -54,13 +56,279 @@ def _keywordChecker(kw_key_list_tups):
@spec_convenience
@update_changes
class MotorRecord_new(Assembly):
class SmaractStreamdevice(Assembly):
def __init__(
self,
pvname,
accuracy=1e-3,
name=None,
elog=None,
alias_fields={
"readback": "MOTRBV",
"user_set_pos": "SET_POS",
"user_direction": "DIR",
},
):
super().__init__(name=name)
self.settings.append(self)
self.pvname = pvname
self._elog = elog
for an, af in alias_fields.items():
self.alias.append(
Alias(an, channel=":".join([pvname, af]), channeltype="CA")
)
self._currentChange = None
# self.description = EpicsString(pvname + ".DESC")
self._append(PvEnum, self.pvname + ":DIR", name="direction", is_setting=True)
self._append(
PvRecord, self.pvname + ":SET_POS", name="set_pos", is_setting=True
)
self._append(
PvRecord, self.pvname + ":GET_HOMED", name="speed", is_setting=False
)
self._append(
PvRecord,
self.pvname + ":FRM_BACK.PROC",
name="home_backward",
is_setting=False,
)
self._append(
PvRecord,
self.pvname + ":FRM_FORW.PROC",
name="home_forward",
is_setting=False,
)
self._append(
PvRecord, self.pvname + ":GET_HOMED", name="is_homed", is_setting=False
)
self._append(
PvRecord,
self.pvname + ":CALIBRATE.PROC",
name="calibrate_sensor",
is_setting=False,
)
self._append(
PvRecord,
self.pvname + ":CL_MAX_FREQ",
name="maximum_frequency",
is_setting=False,
)
self._append(
PvRecord,
self.pvname + ":HOLD",
name="holding_time_ms",
is_setting=True,
)
self._append(
PvRecord,
self.pvname + ":AMPLITUDE",
name="voltage_4KADU_per_100V",
is_setting=True,
)
self._append(
PvRecord,
self.pvname + ":DRIVE",
name="_drive",
is_setting=False,
)
self._append(
PvRecord,
self.pvname + ":MOTRBV",
name="_readback",
is_setting=False,
)
self._append(
PvEnum, self.pvname + ":STAGE_TYPE", name="stage_type", is_setting=True
)
self._append(
PvEnum, self.pvname + ":STATUS", name="status_channel", is_setting=False
)
self._append(
PvEnum,
self.pvname + ":GET_SENSOR_TYPE",
pvname_set=self.pvname + ":SET_SENSOR_TYPE",
name="sensor_type",
is_setting=True,
)
self._append(PvRecord, self.pvname + ":LLM", name="limit_low", is_setting=False)
self._append(
PvRecord, self.pvname + ":HLM", name="limit_high", is_setting=False
)
self.accuracy = accuracy
self._stop_pv = PV(self.pvname + ":STOP.PROC")
self.stop = lambda: self._stop_pv.put(1)
def set_target_value(self, value, hold=False, check=True):
def changer(value):
self._drive.set_target_value(value)
# self._status_message = _status_messages[self._status]
# if self._status < 0:
# raise AdjustableError(self._status_message)
# elif self._status > 0:
# print("\n")
# print(self._status_message)
changer = lambda value: self.move(value, check=check)
return Changer(
target=value,
parent=self,
changer=changer,
hold=hold,
stopper=self.stop,
)
def get_current_value(self):
return self._readback.get_current_value()
def get_close_to(self, value, accuracy):
movedone = 1
if np.abs(value - self.get_current_value()) > accuracy:
movedone = 0
return movedone
def move(self, value, check=True, update_value_time=0.05, timeout=120):
if check:
lim_low, lim_high = self.get_limits()
if not (lim_low < value) and (value < lim_high):
raise AdjustableError("Soft limits violated!")
t_start = time.time()
self._drive.set_target_value(value)
while not self.get_close_to(value, self.accuracy):
if (time.time() - t_start) > timeout:
raise AdjustableError(
f"motion timeout reached in smaract {self.name}:{self.pvname}"
)
time.sleep(update_value_time)
def add_value_callback(self, callback, index=None):
return self._readback._pv.add_callback(callback=callback, index=index)
def clear_value_callback(self, index=None):
if index:
self._readback._pv.remove_callback(index)
else:
self._readback._pv.clear_callbacks()
def get_limits(self):
return self.limit_low.get_current_value(), self.limit_high.get_current_value()
def set_limits(self, low_limit, high_limit, relative_to_present=False):
if relative_to_present:
tval = self.get_current_value()
low_limit += tval
high_limit += tval
self.limit_low.set_target_value(low_limit)
self.limit_high.set_target_value(high_limit)
# return string with motor value as variable representation
def __str__(self):
# """ return short info for the current motor"""
s = f"{self.name}"
s += f"\t@ {colorama.Style.BRIGHT}{self.get_current_value():1.6g}{colorama.Style.RESET_ALL}"
# # s += "\tuser limits (low,high) : {:1.6g},{:1.6g}\n".format(*self.get_limits())
s += f"\n{colorama.Style.DIM}low limit {colorama.Style.RESET_ALL}"
s += ValueInRange(*self.get_limits()).get_str(self.get_current_value())
s += f" {colorama.Style.DIM}high limit{colorama.Style.RESET_ALL}"
# # s += "\tuser limits (low,high) : {:1.6g},{1.6g}".format(self.get_limits())
return s
def __repr__(self):
print(str(self))
return object.__repr__(self)
def __call__(self, value):
self._currentChange = self.set_target_value(value)
def _tweak_ioc(self, step_value=None):
pv = PV(self.pvname + ":TWV")
pvf = PV(self.pvname + ":TWF.PROC")
pvr = PV(self.pvname + ":TWR.PROC")
if not step_value:
step_value = pv.get()
print(f"Tweaking {self.name} at step size {step_value}", end="\r")
help = "q = exit; up = step*2; down = step/2, left = neg dir, right = pos dir\n"
help = help + "g = go abs, s = set"
print(f"tweaking {self.name}")
print(help)
print(f"Starting at {self.get_current_value()}")
step_value = float(step_value)
oldstep = 0
k = KeyPress()
cll = colorama.ansi.clear_line()
class Printer:
def print(self, **kwargs):
print(
cll + f"stepsize: {self.stepsize}; current: {kwargs['value']}",
end="\r",
)
p = Printer()
print(" ")
p.stepsize = step_value
p.print(value=self.get_current_value())
ind_callback = self.add_value_callback(p.print)
pv.put(step_value)
while k.isq() is False:
if oldstep != step_value:
p.stepsize = step_value
p.print(value=self.get_current_value())
oldstep = step_value
k.waitkey()
if k.isu():
step_value = step_value * 2.0
pv.put(step_value)
elif k.isd():
step_value = step_value / 2.0
pv.put(step_value)
elif k.isr():
pvf.put(1)
elif k.isl():
pvr.put(1)
elif k.iskey("g"):
print("enter absolute position (char to abort go to)")
sys.stdout.flush()
v = sys.stdin.readline()
try:
v = float(v.strip())
self.set_target_value(v)
except:
print("value cannot be converted to float, exit go to mode ...")
sys.stdout.flush()
elif k.iskey("s"):
print("enter new set value (char to abort setting)")
sys.stdout.flush()
v = sys.stdin.readline()
try:
v = float(v[0:-1])
self.reset_current_value_to(v)
except:
print("value cannot be converted to float, exit go to mode ...")
sys.stdout.flush()
elif k.isq():
break
else:
print(help)
self.clear_value_callback(index=ind_callback)
print(f"final position: {self.get_current_value()}")
print(f"final tweak step: {pv.get()}")
def tweak(self, *args, **kwargs):
return self._tweak_ioc(*args, **kwargs)
@spec_convenience
@update_changes
class MotorRecord(Assembly):
def __init__(
self,
pvname,
name=None,
elog=None,
alias_fields={"readback": "RBV", "user_offset": "OFF"},
alias_fields={"readback": "RBV", "user_offset": "OFF", "user_direction": "DIR"},
):
super().__init__(name=name)
self.settings.append(self)
@@ -74,17 +342,24 @@ class MotorRecord_new(Assembly):
)
self._currentChange = None
# self.description = EpicsString(pvname + ".DESC")
self._append(PvEnum,self.pvname+'.DIR',name='direction',is_setting=True)
self._append(PvRecord,self.pvname+'.OFF',name='offset',is_setting=True)
self._append(PvRecord,self.pvname+'.VELO',name='speed',is_setting=False)
self._append(PvRecord,self.pvname+'.ACCL',name='acceleration_time',is_setting=False)
self._append(PvRecord,self.pvname+'.LLM',name='limit_low',is_setting=False)
self._append(PvRecord,self.pvname+'.HLM',name='limit_high',is_setting=False)
self._append(PvEnum,self.pvname+'.SPMG',name='motor_state',is_setting=False)
self._append(PvString,self.pvname+'.EGU',name='unit',is_setting=False)
self._append(PvString,self.pvname+'.DESC',name='description',is_setting=False)
self._append(PvEnum, self.pvname + ".DIR", name="direction", is_setting=True)
self._append(PvRecord, self.pvname + ".OFF", name="offset", is_setting=True)
self._append(PvRecord, self.pvname + ".VELO", name="speed", is_setting=False)
self._append(
PvRecord, self.pvname + ".ACCL", name="acceleration_time", is_setting=False
)
self._append(PvRecord, self.pvname + ".LLM", name="limit_low", is_setting=False)
self._append(
PvRecord, self.pvname + ".HLM", name="limit_high", is_setting=False
)
self._append(
PvEnum, self.pvname + ".SPMG", name="motor_state", is_setting=False
)
self._append(PvString, self.pvname + ".EGU", name="unit", is_setting=False)
self._append(
PvString, self.pvname + ".DESC", name="description", is_setting=False
)
# Conventional methods and properties for all Adjustable objects
def set_target_value(self, value, hold=False, check=True):
""" Adjustable convention"""
@@ -144,9 +419,9 @@ class MotorRecord_new(Assembly):
def set_limits(
self, low_limit, high_limit, posType="user", relative_to_present=False
):
"""
"""
set limits. usage: set_limits(low_limit, high_limit)
"""
_keywordChecker([("posType", posType, _posTypes)])
ll_name, hl_name = "LLM", "HLM"
@@ -283,9 +558,13 @@ class MotorRecord_new(Assembly):
def tweak(self, *args, **kwargs):
return self._tweak_ioc(*args, **kwargs)
MotorRecord_new = MotorRecord
@spec_convenience
@update_changes
class MotorRecord:
class MotorRecord_old:
def __init__(
self,
pvname,
@@ -387,9 +666,9 @@ class MotorRecord:
def set_limits(
self, low_limit, high_limit, posType="user", relative_to_present=False
):
"""
"""
set limits. usage: set_limits(low_limit, high_limit)
"""
_keywordChecker([("posType", posType, _posTypes)])
ll_name, hl_name = "LLM", "HLM"
+54 -47
View File
@@ -13,13 +13,9 @@ from pint import UnitRegistry
ureg = UnitRegistry()
def addPvRecordToSelf(self,
pvsetname,
pvreadbackname=None,
accuracy=None,
sleeptime=0,
name=None
):
def addPvRecordToSelf(
self, pvsetname, pvreadbackname=None, accuracy=None, sleeptime=0, name=None
):
try:
self.__dict__[name] = PvRecord(
pvsetname,
@@ -27,11 +23,12 @@ def addPvRecordToSelf(self,
accuracy=accuracy,
sleeptime=sleeptime,
name=name,
)
)
self.alias.append(self.__dict__[name].alias)
except:
print(f"Warning! Could not find PV {name} (Id:{pvsetname} RB:{pvreadbackname})")
def addMotorRecordToSelf(self, Id=None, name=None):
self.__dict__[name] = MotorRecord(Id, name=name)
self.alias.append(self.__dict__[name].alias)
@@ -47,13 +44,9 @@ def addDelayStageToSelf(self, stage=None, name=None):
self.alias.append(self.__dict__[name].alias)
def addPvRecordToSelf(self,
pvsetname,
pvreadbackname=None,
accuracy=None,
sleeptime=0,
name=None
):
def addPvRecordToSelf(
self, pvsetname, pvreadbackname=None, accuracy=None, sleeptime=0, name=None
):
try:
self.__dict__[name] = PvRecord(
pvsetname,
@@ -61,14 +54,12 @@ def addPvRecordToSelf(self,
accuracy=accuracy,
sleeptime=sleeptime,
name=name,
)
)
self.alias.append(self.__dict__[name].alias)
except:
print(f"Warning! Could not find PV {name} (Id:{pvsetname} RB:{pvreadbackname})")
class DelayTime(AdjustableVirtual):
def __init__(
self, stage, direction=1, passes=2, reset_current_value_to=True, name=None
@@ -76,7 +67,7 @@ class DelayTime(AdjustableVirtual):
self._direction = direction
self._group_velo = 299798458 # m/s
self._passes = passes
self.Id = stage.Id + "_delay"
# self.Id = stage.Id + "_delay"
self._stage = stage
AdjustableVirtual.__init__(
self,
@@ -86,8 +77,20 @@ class DelayTime(AdjustableVirtual):
reset_current_value_to=reset_current_value_to,
name=name,
)
addPvRecordToSelf(self, pvsetname="SIN-TIMAST-TMA:Evt-22-Freq-SP", pvreadbackname ="SIN-TIMAST-TMA:Evt-22-Freq-I", accuracy= 0.5, name='frequency_pp')
addPvRecordToSelf(self, pvsetname="SIN-TIMAST-TMA:Evt-27-Freq-SP", pvreadbackname ="SIN-TIMAST-TMA:Evt-27-Freq-I", accuracy= 0.5, name='frequency_dark')
addPvRecordToSelf(
self,
pvsetname="SIN-TIMAST-TMA:Evt-22-Freq-SP",
pvreadbackname="SIN-TIMAST-TMA:Evt-22-Freq-I",
accuracy=0.5,
name="frequency_pp",
)
addPvRecordToSelf(
self,
pvsetname="SIN-TIMAST-TMA:Evt-27-Freq-SP",
pvreadbackname="SIN-TIMAST-TMA:Evt-27-Freq-I",
accuracy=0.5,
name="frequency_dark",
)
def _mm_to_s(self, mm):
return mm * 1e-3 * self._passes / self._group_velo * self._direction
@@ -117,7 +120,7 @@ class DelayTime(AdjustableVirtual):
class DelayCompensation(AdjustableVirtual):
"""Simple virtual adjustable for compensating delay adjustables. It assumes the first adjustable is the master for
"""Simple virtual adjustable for compensating delay adjustables. It assumes the first adjustable is the master for
getting the current value."""
def __init__(self, adjustables, directions, set_current_value=True, name=None):
@@ -184,7 +187,9 @@ class Laser_Exp:
self.alias.append(self.delay_bsen.alias)
try:
addMotorRecordToSelf(self, Id=self.Id + "-M522:MOTOR_1", name="_delay_thz_stg" )
addMotorRecordToSelf(
self, Id=self.Id + "-M522:MOTOR_1", name="_delay_thz_stg"
)
self.delay_thz = DelayTime(self._delay_thz_stg, name="delay_thz")
self.alias.append(self.delay_thz.alias)
except:
@@ -199,12 +204,12 @@ class Laser_Exp:
print("Problems initializing global delay stage")
# Implementation of delay compensation, this assumes for now that delays_glob and delay_tt actually delay in positive directions.
#try:
# try:
# self.delay_lxtt = DelayCompensation(
# [self.delay_glob, self.delay_tt], [-1, 1], name="delay_lxtt"
# )
# self.alias.append(self.delay_lxtt.alias)
#except:
# except:
# print("Problems initializing virtual pump delay stage")
# compressor
addMotorRecordToSelf(self, Id=self.Id + "-M532:MOT", name="compressor")
@@ -214,19 +219,19 @@ class Laser_Exp:
# addDelayStageToSelf(self, self.__dict__["_lam_delay_smarstg"], name="lam_delay_smar")
# self._lam_delayStg_Smar = SmarActRecord('SLAAR21-LMTS-LAM11')
# self.lam_delay_Smar = DelayStage(self._lam_delayStg_Smar)
#try:
# try:
# addMotorRecordToSelf(self, Id=self.Id + "-M548:MOT", name="_lam_delaystg")
# addDelayStageToSelf(
# self, self.__dict__["_lam_delaystg"], name="lam_delay"
# ) # this try except does not work
#except:
# except:
# print("Problems initializing LAM delay stage")
# self._lam_delayStg = MotorRecord(self.Id+'-M548:MOT')
# self.lam_delay = DelayStage(self._lam_delayStg)
# PALM delay stages
#addMotorRecordToSelf(self, Id=self.Id + "-M552:MOT", name="_palm_delaystg")
#addDelayStageToSelf(self, self.__dict__["_palm_delaystg"], name="palm_delay")
# addMotorRecordToSelf(self, Id=self.Id + "-M552:MOT", name="_palm_delaystg")
# addDelayStageToSelf(self, self.__dict__["_palm_delaystg"], name="palm_delay")
# self._palm_delayStg = MotorRecord(self.Id+'-M552:MOT')
# self.palm_delay = DelayStage(self._palm_delayStg)
@@ -245,33 +250,38 @@ class Laser_Exp:
### SmarAct stages used in the experiment ###
try:
for smar_name, smar_address in self.smar_config.items():
addSmarActRecordToSelf(self, Id=(self.IdSA + smar_address), name=smar_name)
addSmarActRecordToSelf(
self, Id=(self.IdSA + smar_address), name=smar_name
)
except Exception as expt:
print("Issue with initializing smaract stages from eco smar_config")
print(expt)
## IR beam pointing mirrors
#try:
# try:
# addPvRecordToSelf(self, pvsetname="SLAAR21-LMNP-ESBIR13:DRIVE", pvreadbackname ="SLAAR21-LMNP-ESBIR13:MOTRBV", accuracy= 10, name='IR_mirr1_ry')
# addPvRecordToSelf(self, pvsetname="SLAAR21-LMNP-ESBIR14:DRIVE", pvreadbackname ="SLAAR21-LMNP-ESBIR14:MOTRBV", accuracy= 10, name='IR_mirr1_rx')
#except:
# except:
# print("Issue intializing picomotor IR beam pointing mirrors")
# pass
try:
addSmarActRecordToSelf(self, Id='SARES23-ESB4', name='IR_mirr1_rx')
addSmarActRecordToSelf(self, Id='SARES23-LIC7', name='IR_mirr1_ry')
addSmarActRecordToSelf(self, Id="SARES23-ESB4", name="IR_mirr1_rx")
addSmarActRecordToSelf(self, Id="SARES23-LIC7", name="IR_mirr1_ry")
addSmarActRecordToSelf(self, Id='SARES23-ESB1', name='IR_mirr2_ry')
addSmarActRecordToSelf(self, Id='SARES23-ESB2', name='IR_mirr2_rz')
addSmarActRecordToSelf(self, Id='SARES23-ESB3', name='IR_mirr2_z')
addSmarActRecordToSelf(self, Id="SARES23-ESB1", name="IR_mirr2_ry")
addSmarActRecordToSelf(self, Id="SARES23-ESB2", name="IR_mirr2_rz")
addSmarActRecordToSelf(self, Id="SARES23-ESB3", name="IR_mirr2_z")
except:
print("Issue intializing SmarAct IR beam pointing mirrors")
pass
## beam pointing offsets
try:
def set_position_monitor_offsets(cam1_center=[None,None],cam2_center=[None,None]):
dims = ['x','y']
def set_position_monitor_offsets(
cam1_center=[None, None], cam2_center=[None, None]
):
dims = ["x", "y"]
channels_cam1_xy = [
"SLAAR21-LTIM01-EVR0:CALCS.INPB",
"SARES20-CVME-01-EVR0:CALCI.INPB",
@@ -282,30 +292,29 @@ class Laser_Exp:
]
print("Old crosshair position cam1")
for dim, tc, tv in zip(dims, channels_cam1_xy, cam1_center):
print(f'{dim}: {PV(tc).get()}')
print(f"{dim}: {PV(tc).get()}")
# PV(tc).put(bytes(str(tv), "utf8"))
print("Old crosshair position cam2")
for dim, tc, tv in zip(dims, channels_cam2_xy, cam2_center):
print(f'{dim}: {PV(tc).get()}')
print(f"{dim}: {PV(tc).get()}")
# PV(tc).put(bytes(str(tv), "utf8"))
print("New crosshair position cam1")
for dim, tc, tv in zip(dims, channels_cam1_xy, cam1_center):
if not tv:
break
print(f'{dim}: {tv}')
print(f"{dim}: {tv}")
PV(tc).put(bytes(str(tv), "utf8"))
print("New crosshair position cam2")
for dim, tc, tv in zip(dims, channels_cam2_xy, cam2_center):
if not tv:
break
print(f'{dim}: {tv}')
print(f"{dim}: {tv}")
PV(tc).put(bytes(str(tv), "utf8"))
self.set_position_monitor_offsets = set_position_monitor_offsets
except:
pass
def get_adjustable_positions_str(self):
ostr = "*****Laser motor positions******\n"
@@ -323,5 +332,3 @@ class Laser_Exp:
def __repr__(self):
return self.get_adjustable_positions_str()
+1 -1
View File
@@ -20,7 +20,7 @@ class DoubleCrystalMono(Assembly):
self,
pvname,
name=None,
energy_sp="SAROP21-ARAMIS:ENERGY_SP",
energy_sp="SGE-OP2E-ARAMIS:E_ENERGY_SP",
energy_rb="SAROP21-ARAMIS:ENERGY",
):
super().__init__(name=name)
+15 -13
View File
@@ -138,20 +138,22 @@ class KBMirrorBernina_new(Assembly):
self.d_win1 = d_win1
self.d_target = d_target
self._add(MotorRecord, pvname_hor + ":W_X", name="x_hor")
self._add(MotorRecord, pvname_hor + ":W_Y", name="y_hor")
self._add(MotorRecord, pvname_hor + ":W_RY", name="y_hor")
self._add(MotorRecord, pvname_hor + ":W_RY", name="pitch_hor")
self._add(MotorRecord, pvname_hor + ":W_RZ", name="roll_hor")
self._add(MotorRecord, pvname_hor + ":W_RX", name="yaw_hor")
self._add(MotorRecord, pvname_hor + ":BU", name="bend_upstream_hor")
self._add(MotorRecord, pvname_hor + ":BD", name="bend_downstream_hor")
self._append(MotorRecord, pvname_hor + ":W_X", name="x_hor")
self._append(MotorRecord, pvname_hor + ":W_Y", name="y_hor")
self._append(MotorRecord, pvname_hor + ":W_RY", name="y_hor")
self._append(MotorRecord, pvname_hor + ":W_RY", name="pitch_hor")
self._append(MotorRecord, pvname_hor + ":W_RZ", name="roll_hor")
self._append(MotorRecord, pvname_hor + ":W_RX", name="yaw_hor")
self._append(MotorRecord, pvname_hor + ":BU", name="bend_upstream_hor")
self._append(MotorRecord, pvname_hor + ":BD", name="bend_downstream_hor")
self._add(MotorRecord, pvname_hor + ":TY1", name="y1_phys_hor")
self._add(MotorRecord, pvname_hor + ":TY2", name="y2_phys_hor")
self._add(MotorRecord, pvname_hor + ":TY3", name="y3_phys_hor")
self._add(MotorRecord, pvname_hor + ":TX1", name="x1_phys_hor")
self._add(MotorRecord, pvname_hor + ":TX2", name="x2_phys_hor")
self._append(MotorRecord, pvname_hor + ":TY1", name="y1_phys_hor")
self._append(MotorRecord, pvname_hor + ":TY2", name="y2_phys_hor")
self._append(MotorRecord, pvname_hor + ":TY3", name="y3_phys_hor")
self._append(MotorRecord, pvname_hor + ":TX1", name="x1_phys_hor")
self._append(MotorRecord, pvname_hor + ":TX2", name="x2_phys_hor")
self._append()
self._add(
PvRecord,