Files
sinqMotor/db/sinqMotor.db
2025-05-09 11:59:51 +02:00

327 lines
15 KiB
Plaintext
Executable File

# SPDX-License-Identifier: GPL-3.0-only
# 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. In this version of the record, we set RDBD to a
# very high value in order to suppress both retries and the NTM (new target
# monitor) logic from issuing stop commands during overshoots (see
# https://epics.anl.gov/bcda/synApps/motor/motorRecord.html#Fields_misc).
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(DHLM, "$(DHLM=0)")
field(DLLM, "$(DLLM=0)")
field(TWV,"1")
field(RTRY,"0")
field(RDBD, "$(RDBD=10e300)") # Suppress retries and overshoot stop commands
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")
}
# If the value of this PV is 0, the according axis is currently disconnected from the controller.
# Trying to give commands to a disconnected axis will result in an error message in the IOC shell
# This record is coupled to the parameter library via motorConnected_ -> MOTOR_CONNECTED.
record(longin, "$(INSTR)$(M):Connected")
{
field(DTYP, "asynInt32")
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_CONNECTED")
field(SCAN, "I/O Intr")
field(PINI, "NO")
field(VAL, "1")
}
# 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)")
}
# If this PV has a value other than 0, adaptive polling for this axis is enabled.
# The standard motor record behaviour is to poll all axis with the busy / move poll
# period if at least one of the axes is moving. Adaptive polling changes this so
# that only axes which were moving in the last poll are polled with the busy / move poll
# period and all other axes are polled with the idle poll period.
record(longout, "$(INSTR)$(M):AdaptivePolling") {
field(DTYP, "asynInt32")
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) ADAPTIVE_POLLING")
field(PINI, "YES")
field(VAL, "$(ADAPTPOLL=1)")
}
# 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")
field(PINI, "NO")
}
record(ao, "$(INSTR)$(M):PushDHLM2Field") {
field(DOL, "$(INSTR)$(M):DHLM_RBV NPP")
field(OUT, "$(INSTR)$(M).DHLM")
field(OMSL, "closed_loop")
field(PINI, "NO")
}
# 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")
field(PINI, "NO")
}
record(ao, "$(INSTR)$(M):PushDLLM2Field") {
field(DOL, "$(INSTR)$(M):DLLM_RBV NPP")
field(OUT, "$(INSTR)$(M).DLLM")
field(OMSL, "closed_loop")
field(PINI, "NO")
}
# 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")
}