In a code review with Edward and Alex, some optimization potential in the sinqMotor.db file was discovered. This patch implements those improvements.
292 lines
13 KiB
Plaintext
Executable File
292 lines
13 KiB
Plaintext
Executable File
# The main asyn motor record. Some fields are populated from the substitution
|
|
# files via macros:
|
|
# - INSTR: Name of the instrument, e.g. "SQ:SINQTEST:"
|
|
# - M: Name of the motor in EPICS, e.g. "lin1"
|
|
# - DESC: Short description of the motor. If not given, this is equal to M
|
|
# - DIR: This value is usually set to "Pos". If the motor axis direction
|
|
# should be inverted, this value can be set to "Neg"
|
|
# - CONTROLLER: Name of the motor controller, e.g. "mcu1"
|
|
# - AXIS: Number of the axis, e.g. "1"
|
|
# - MRES: Motor record resolution. See the README.md for a detailed discussion
|
|
# - EGU: Engineering units. In case of a rotary axis, this is "degree", in
|
|
# case of a linear axis this is "mm".
|
|
# - RTRY: The maximum number of times the motor record will try again to move to
|
|
# the desired position. When the retry limit is reached, the motor record will
|
|
# declare the motion finished. If the desired position was not reached, the
|
|
# field MISS will be set to 1 and NICOS will emit a warning "Did not reach
|
|
# target position". If this value is set to 0, the retry deadband is never
|
|
# applied and therefore MISS will always be 0. The error message "Did not reach
|
|
# target position" will therefore never appear.
|
|
# - RDBD: Retry deadband: When the motor has finished a complete motion,
|
|
# possibly including backlash takeout, the motor record will compare its current
|
|
# position with the desired position. If the magnitude of the difference is
|
|
# greater than RDBD, the motor will try again, as if the user had requested a
|
|
# move from the now current position to the desired position. Only a limited
|
|
# number of retries will be performed (see RTRY). If the given value is smaller
|
|
# than MRES, it is set to MRES.
|
|
record(motor,"$(INSTR)$(M)")
|
|
{
|
|
field(DESC,"$(DESC=$(M))")
|
|
field(DTYP,"asynMotor")
|
|
field(DIR,"$(DIR=Pos)")
|
|
field(OUT,"@asyn($(CONTROLLER),$(AXIS))")
|
|
field(MRES,"$(MRES)")
|
|
field(EGU,"$(EGU)")
|
|
field(INIT,"")
|
|
field(PINI,"NO")
|
|
field(TWV,"1")
|
|
field(RTRY,"0")
|
|
field(RDBD,"0")
|
|
field(BDST,"0")
|
|
field(RMOD,"3") # Retry mode 3 ("In-Position"): This suppresses any retries from the motor record.
|
|
}
|
|
|
|
# This PV reads out the 10th bit of the MSTA field of the motor record, which
|
|
# is the "motorStatusProblem_" bit.
|
|
record(calc, "$(INSTR)$(M):StatusProblem")
|
|
{
|
|
field(INPA, "$(INSTR)$(M).MSTA CP")
|
|
field(CALC, "A >> 9")
|
|
}
|
|
|
|
# Call the reset function of the corresponding sinqAxis
|
|
# This record is coupled to the parameter library via motorReset_ -> MOTOR_RESET.
|
|
record(longout, "$(INSTR)$(M):Reset") {
|
|
field(DTYP, "asynInt32")
|
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_RESET")
|
|
field(PINI, "NO")
|
|
}
|
|
|
|
# This PV allows force-stopping the motor record from within the driver by setting
|
|
# the motorForceStop_ value in the parameter library to 1. It should be reset to 0 by the driver afterwards.
|
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
|
# This record is coupled to the parameter library via motorForceStop_ -> MOTOR_FORCE_STOP.
|
|
record(longin, "$(INSTR)$(M):StopRBV")
|
|
{
|
|
field(DTYP, "asynInt32")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_FORCE_STOP")
|
|
field(SCAN, "I/O Intr")
|
|
field(FLNK, "$(INSTR)$(M):Stop2Field")
|
|
}
|
|
record(longout, "$(INSTR)$(M):Stop2Field") {
|
|
field(DOL, "$(INSTR)$(M):StopRBV NPP")
|
|
field(OUT, "$(INSTR)$(M).STOP")
|
|
field(OMSL, "closed_loop")
|
|
}
|
|
|
|
# This record forwards the motor record resolution MRES to the parameter library
|
|
# entry "MOTOR_REC_RESOLUTION" (solution from https://epics.anl.gov/tech-talk/2020/msg00378.php)
|
|
# The value of MRES is needed inside the driver for various calculations (e.g.
|
|
# for calculating the estimated time of arrival inside the watchdog).
|
|
record(ao,"$(INSTR)$(M):RecResolution") {
|
|
field(DESC, "$(M) resolution")
|
|
field(DOL, "$(INSTR)$(M).MRES CP")
|
|
field(OMSL, "closed_loop")
|
|
field(DTYP, "asynFloat64")
|
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_REC_RESOLUTION")
|
|
}
|
|
|
|
# This record contains messages from the driver (usually error messages).
|
|
# The macro MSGTEXTSIZE can be used to set the maximum length of the message.
|
|
# if not provided, a default value of 200 is used.
|
|
# This record is coupled to the parameter library via motorMessageText_ -> MOTOR_MESSAGE_TEXT.
|
|
record(waveform, "$(INSTR)$(M)-MsgTxt") {
|
|
field(DTYP, "asynOctetRead")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_MESSAGE_TEXT")
|
|
field(FTVL, "CHAR")
|
|
field(NELM, "$(MSGTEXTSIZE=200)") # Should be the same as MAXBUF in the driver code
|
|
field(SCAN, "I/O Intr")
|
|
}
|
|
|
|
# User-writable switch which disables the motor for an input of zero and enables
|
|
# it otherwise. Some motors can't be disabled in certain states (e.g. during
|
|
# movement). This behaviour has to be implemented inside the driver.
|
|
# This record is coupled to the parameter library via motorEnable_ -> MOTOR_ENABLE.
|
|
record(longout, "$(INSTR)$(M):Enable") {
|
|
field(DTYP, "asynInt32")
|
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_ENABLE")
|
|
field(PINI, "NO")
|
|
}
|
|
|
|
# Readback value which returns 1 if the motor is disabled and 0 otherwise.
|
|
# This record is coupled to the parameter library via motorEnableRBV_ -> MOTOR_ENABLE_RBV.
|
|
record(longin, "$(INSTR)$(M):EnableRBV") {
|
|
field(DTYP, "asynInt32")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_ENABLE_RBV")
|
|
field(PINI, "NO")
|
|
field(SCAN, "I/O Intr")
|
|
}
|
|
|
|
# Some (older) motors cannot be disabled. This property has to be specified in
|
|
# the driver by setting the corresponding parameter library entry motorCanDisable_
|
|
# to 0 (its default value is 1).
|
|
# This record is coupled to the parameter library via motorCanDisable_ -> MOTOR_CAN_DISABLE.
|
|
record(longin, "$(INSTR)$(M):CanDisable") {
|
|
field(DTYP, "asynInt32")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_CAN_DISABLE")
|
|
field(PINI, "NO")
|
|
field(SCAN, "I/O Intr")
|
|
}
|
|
|
|
# For some motors, the user might be allowed to adjust the speed within the
|
|
# limits specified in the motor record as VBAS and VMAX. This functionality can
|
|
# be enabled by setting CANSETSPEED to 1. It is disabled by default.
|
|
# This record is coupled to the parameter library via motorCanSetSpeed_ -> MOTOR_CAN_SET_SPEED.
|
|
record(longout, "$(INSTR)$(M):CanSetSpeed") {
|
|
field(DTYP, "asynInt32")
|
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_CAN_SET_SPEED")
|
|
field(PINI, "YES")
|
|
field(ASG, "READONLY") # Field is initialized during IOC startup
|
|
field(VAL, "$(CANSETSPEED=0)")
|
|
}
|
|
|
|
# The timeout mechanism for movements can be enabled / disabled by setting
|
|
# this PV to 1 / 0.
|
|
# This record is coupled to the parameter library via motorEnableMovWatchdog -> MOTOR_ENABLE_MOV_WATCHDOG.
|
|
record(longout, "$(INSTR)$(M):EnableMovWatchdog") {
|
|
field(DTYP, "asynInt32")
|
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_ENABLE_MOV_WATCHDOG")
|
|
field(PINI, "YES")
|
|
field(VAL, "$(ENABLEMOVWATCHDOG=0)")
|
|
}
|
|
|
|
# For modern controllers, the high and low limits of the axis are read out
|
|
# directly from the hardware. However, since the axis might slightly
|
|
# "overshoot" when moving to a position next to the limits, the hardware might
|
|
# go into a "limits hit" error state. To prevent this, this value allows adding
|
|
# a small offset in EGU, which is subtracted from the high limit and added to the
|
|
# low limit.
|
|
# This record is coupled to the parameter library via motorLimitsOffset_ -> MOTOR_LIMITS_OFFSET.
|
|
record(ao, "$(INSTR)$(M):LimitsOffset") {
|
|
field(DTYP, "asynFloat64")
|
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_LIMITS_OFFSET")
|
|
field(PINI, "YES")
|
|
field(ASG, "READONLY") # Field is initialized during IOC startup
|
|
field(VAL, "$(LIMITSOFFSET=0)")
|
|
}
|
|
|
|
# This record pair reads the parameter library value for "motorHighLimitFromDriver_"
|
|
# and pushes it to the motor record field "DHLM". This can be used to read limits
|
|
# from the hardware and correspondingly update the motor record from the driver.
|
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
|
# This record is coupled to the parameter library via motorHighLimitFromDriver_ -> MOTOR_HIGH_LIMIT_FROM_DRIVER.
|
|
record(ai, "$(INSTR)$(M):DHLM_RBV")
|
|
{
|
|
field(DTYP, "asynFloat64")
|
|
field(VAL, "$(DHLM=0)")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_HIGH_LIMIT_FROM_DRIVER")
|
|
field(SCAN, "I/O Intr")
|
|
field(FLNK, "$(INSTR)$(M):PushDHLM2Field")
|
|
}
|
|
record(ao, "$(INSTR)$(M):PushDHLM2Field") {
|
|
field(DOL, "$(INSTR)$(M):DHLM_RBV NPP")
|
|
field(OUT, "$(INSTR)$(M).DHLM")
|
|
field(OMSL, "closed_loop")
|
|
}
|
|
|
|
# This record pair reads the parameter library value for "motorLowLimitFromDriver_"
|
|
# and pushes it to the motor record field "DLLM". This can be used to read limits
|
|
# from the hardware and correspondingly update the motor record from the driver.
|
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
|
# This record is coupled to the parameter library via motorLowLimitFromDriver_ -> MOTOR_LOW_LIMIT_FROM_DRIVER.
|
|
record(ai, "$(INSTR)$(M):DLLM_RBV")
|
|
{
|
|
field(DTYP, "asynFloat64")
|
|
field(VAL, "$(DLLM=0)")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_LOW_LIMIT_FROM_DRIVER")
|
|
field(SCAN, "I/O Intr")
|
|
field(FLNK, "$(INSTR)$(M):PushDLLM2Field")
|
|
}
|
|
record(ao, "$(INSTR)$(M):PushDLLM2Field") {
|
|
field(DOL, "$(INSTR)$(M):DLLM_RBV NPP")
|
|
field(OUT, "$(INSTR)$(M).DLLM")
|
|
field(OMSL, "closed_loop")
|
|
}
|
|
|
|
# This record pair reads the parameter library value for "motorVeloFromDriver_"
|
|
# and pushes it to the motor record field "VELO". This can be used to read the speed value
|
|
# from the hardware and correspondingly update the motor record from the driver.
|
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
|
# This record is coupled to the parameter library via motorVeloFromDriver_ -> MOTOR_VELO_FROM_DRIVER.
|
|
record(ai, "$(INSTR)$(M):VELO_RBV")
|
|
{
|
|
field(DTYP, "asynFloat64")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_VELO_FROM_DRIVER")
|
|
field(SCAN, "I/O Intr")
|
|
field(FLNK, "$(INSTR)$(M):PushVELO2Field")
|
|
}
|
|
record(ao, "$(INSTR)$(M):PushVELO2Field") {
|
|
field(DOL, "$(INSTR)$(M):VELO_RBV NPP")
|
|
field(OUT, "$(INSTR)$(M).VELO")
|
|
field(OMSL, "closed_loop")
|
|
}
|
|
|
|
# This record pair reads the parameter library value for "motorVbasFromDriver_"
|
|
# and pushes it to the motor record field "VBAS". This can be used to read the lower speed limit
|
|
# from the hardware and correspondingly update the motor record from the driver.
|
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
|
# This record is coupled to the parameter library via motorVbasFromDriver_ -> MOTOR_VBAS_FROM_DRIVER.
|
|
record(ai, "$(INSTR)$(M):VBAS_RBV")
|
|
{
|
|
field(DTYP, "asynFloat64")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_VBAS_FROM_DRIVER")
|
|
field(SCAN, "I/O Intr")
|
|
field(FLNK, "$(INSTR)$(M):PushVBAS2Field")
|
|
}
|
|
record(ao, "$(INSTR)$(M):PushVBAS2Field") {
|
|
field(DOL, "$(INSTR)$(M):VBAS_RBV NPP")
|
|
field(OUT, "$(INSTR)$(M).VBAS")
|
|
field(OMSL, "closed_loop")
|
|
}
|
|
|
|
# This record pair reads the parameter library value for "motorVmaxFromDriver_"
|
|
# and pushes it to the motor record field "VMAX". This can be used to read the upper speed limit
|
|
# from the hardware and correspondingly update the motor record from the driver.
|
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
|
# This record is coupled to the parameter library via motorVmaxFromDriver_ -> MOTOR_VMAX_FROM_DRIVER.
|
|
record(ai, "$(INSTR)$(M):VMAX_RBV")
|
|
{
|
|
field(DTYP, "asynFloat64")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_VMAX_FROM_DRIVER")
|
|
field(SCAN, "I/O Intr")
|
|
field(FLNK, "$(INSTR)$(M):PushVMAX2Field")
|
|
}
|
|
record(ao, "$(INSTR)$(M):PushVMAX2Field") {
|
|
field(DOL, "$(INSTR)$(M):VMAX_RBV NPP")
|
|
field(OUT, "$(INSTR)$(M).VMAX")
|
|
field(OMSL, "closed_loop")
|
|
}
|
|
|
|
# This record pair reads the parameter library value for "motorAcclFromDriver_"
|
|
# and pushes it to the motor record field "ACCL". This can be used to read the acceleration
|
|
# from the hardware and correspondingly update the motor record from the driver.
|
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
|
# This record is coupled to the parameter library via motorAcclFromDriver_ -> MOTOR_ACCL_FROM_DRIVER.
|
|
record(ai, "$(INSTR)$(M):ACCL_RBV")
|
|
{
|
|
field(DTYP, "asynFloat64")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_ACCL_FROM_DRIVER")
|
|
field(SCAN, "I/O Intr")
|
|
field(FLNK, "$(INSTR)$(M):PushACCL2Field")
|
|
}
|
|
record(ao, "$(INSTR)$(M):PushACCL2Field") {
|
|
field(DOL, "$(INSTR)$(M):ACCL_RBV NPP")
|
|
field(OUT, "$(INSTR)$(M).ACCL")
|
|
field(OMSL, "closed_loop")
|
|
}
|
|
|
|
# Read out the encoder type in human-readable form. The output numbers are ASCII
|
|
# codes and can be converted to chars in order to get the encoder type.
|
|
# EPICS prepends the ASCII code with 80
|
|
# The following encoder types are defined:
|
|
# - "Absolute encoder" (array 80 65 98 115 111 108 117 116 101 32 101 110 99 111 100 101 114)
|
|
# - "Incremental encoder" (array 80 73 110 99 114 101 109 101 110 116 97 108 32 101 110 99 111 100 101 114)
|
|
# This record is coupled to the parameter library via encoderType -> ENCODER_TYPE.
|
|
record(waveform, "$(INSTR)$(M):EncoderType") {
|
|
field(DTYP, "asynOctetRead")
|
|
field(INP, "@asyn($(CONTROLLER),$(AXIS),1) ENCODER_TYPE")
|
|
field(FTVL, "CHAR")
|
|
field(NELM, "80")
|
|
field(SCAN, "I/O Intr")
|
|
}
|