1、分布式EPICS设置
1) 操作界面:包括shell命令行方式(caget, caput, camonitor等)和图形界面方式(medm, edm, css等)。
2)输入输出控制器(IOC)
2、IOC
1) 数据库:数据流,基本上周期运行
2)sequencer:基本上按需的状态机
"硬"IOCs运行vxWorks并且直接连接了A/D, D/A, LLRF等硬件。
"软"IOCs运行在linux等上并且除了串口或网络设备外没有I/O硬件。
3、IOC数据库
1)'IOCcore'软件装载并且执行'记录(records)'-记录配置替代了编写自定义代码。
2)所有控制系统控制箱有:GUI工具; 网络协议;硬件驱动,但基本上没有一个相当的数据库。
4、示例:基本的温度控制
任务:
1)从设备读取温度
2)根据需要接通/断开开关
3)重复
一个温控数据库:
使用VisualDCT设计的由四个记录组成的数据库:
1)模拟输入记录(ai:$(TANK)TEMPERATURE)从设备读取温度值,并且把温度值写入到calcout($(TANK)CHECK)记录。
2)calcout($(TANK)CHECK)记录是通过通道访问从$(TANK)TEMPERATURE获取当前温度和通过数据库访问从模拟输入记录ai($(TANK)SETPOINT)获取了设定温度,并且把二者进行比较,并且把比较结果写入到二进制输出记录bo($(TANK)SWITCH)。
3)二进制输出记录bo($(TANK)SWITCH)根据写入的值是0或1,向设备发出断开或者闭合开关的指令。
以下是文本数据库:
1)$(TANK)TEMPERATURE:模拟输入记录ai用于读取设备的输入。
2)$(TANK)CHECK:calcout记录用于比较输入和设定值,并且在比较结果发生变化时,输出比较结果。
3)$(TANK)SWITCH:二进制输出记录bo,向设备输出向其写入的值。
4)$(TANK)SWITCH_RBV:二进制输入记录bi,用于读取设备的开关状态。
5)$(TANK)SETPOINT:模拟输入记录ai,提供给用户设置温度设定值。
record(ai, "$(TANK)TEMPERATURE") {field(DESC, "Read Temperature")field(SCAN, "I/O Intr")field(DTYP,"asynFloat64")field(INP,"@asyn($(PT1), 0,1000)FLOAT32_BE")field(PREC, "1")field(LINR, "NO CONVERSION")field(EGU, "Celsius")field(HOPR, "100")field(LOPR, "0")field(SMOO, "0.5")field(HIGH, "15")field(HSV, "MINOR")field(PINI, "NO")
}record(calcout, "$(TANK)CHECK") {field(DESC, "Control Heater")field(CALC, "A<B")field(INPA, "$(TANK)TEMPERATURE CP MS")field(OUT, "$(TANK)SWITCH PP")field(OOPT, "On Change")field(DOPT, "Use CALC")field(INPB, "$(TANK)SETPOINT")
}record(bo, "$(TANK)SWITCH") {field(DESC, "Heater Switch")field(SCAN, "Passive")field(DTYP,"asynUInt32Digital")field(OUT,"@asynMask($(PT2) 0 0x1)")field(OMSL, "supervisory")field(ZNAM, "Open")field(ONAM, "Closed")field(IVOA, "Set output to IVOV")field(IVOV, "0")
}record(bi, "$(TANK)SWITCH_RBV") {field(DESC, "Heater Switch Readback")field(SCAN, "I/O Intr")field(DTYP,"asynUInt32Digital")field(INP,"@asynMask($(PT3) 0 0x1)")field(ZNAM, "Open")field(ONAM, "Closed")
}record(ai, "$(TANK)SETPOINT") {field(DESC, "Temperature Setpoint")field(SCAN, "Passive")field(INP, "10")field(HOPR, "100")field(LOPR, "0")
}
使用modbus-slave软件模拟设备端:
1)温度定义如下:用两个字组成一个32位大端浮点数
2) 开关定义如下:用一个线圈位模拟一个开关
启动脚本设定如下:
#!../../bin/linux-aarch64/tank#- You may have to change tank to something else
#- everywhere it appears in this file< envPathscd "${TOP}"## Register all support components
dbLoadDatabase "dbd/tank.dbd"
tank_registerRecordDeviceDriver pdbbasedrvAsynIPPortConfigure("TANK","192.168.50.252:502",0,0,1)
#modbusInterposeConfig(const char *portName,
# modbusLinkType linkType,
# int timeoutMsec,
# int writeDelayMsec)
modbusInterposeConfig("TANK",0, 5000,0)# one float32 input read
drvModbusAsynConfigure("PT1", "TANK", 1, 4, 0, 2, 0, 500, "Tank")# one bit write
drvModbusAsynConfigure("PT2", "TANK", 1, 5, 0, 1, 0, 1000, "Tank")
# one bit read
drvModbusAsynConfigure("PT3", "TANK", 1, 1, 0, 1, 0, 500, "Tank")## Load record instances
dbLoadRecords("db/tank.db","TANK=TANK:, PT1=PT1,PT2=PT2,PT3=PT3")cd "${TOP}/iocBoot/${IOC}"
iocInit
运行这个IOC,并且查看IOC中加载的记录:
../../bin/linux-aarch64/tank st.cmd
#!../../bin/linux-aarch64/tank
< envPaths
...
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
## Start any sequence programs
epics> dbl
TANK:TEMPERATURE
TANK:SETPOINT
TANK:SWITCH_RBV
TANK:SWITCH
TANK:CHECK
CSS界面:
1) 当在modbus-slave中设置环境温度大于Set Point的温度时,开关会自动打开。
2)当在modbus-slave中设置环境温度小于Set Point的温度时,开关会自动闭合。
5、Database = Records + Fields + Links
1)IOC装载并且执行一个或多个数据库。
2)每个数据库有若干记录。
3)每个记录有以下字段:
- 名称(在整个网络上唯一)
- 类型(确定字段和它们的功能)
- 字段(属性,可以运行时被读取,绝大部分也能被写入)。
- 经常有与硬件连接的设备支持。
- 指向其他记录的链接。
6、记录是活动的
1)记录做事情的
- 从其他记录或者硬件获取数据
- 执行计算
- 检查值范围,产生警报
- 写入其他记录或硬件
记录做什么取决于记录类型,字段值,设备支持
2) 何时运行记录
记录周期性运行或者被事件或者其他记录触发运行。
除非一个记录被运行了,否则不发生操作。
7、第一个记录"first.db"
这是最简单的记录,它每秒产生一个随机数。
record(calc, $(P)Random)
{field(SCAN, "1 second")field(INPA, "10")field(CALC, "RNDM*A")
}
1)执行:softIoc -m P=FIRST: -d first.db
root@orangepi5:/usr/local/EPICS/program/softdb# softIoc -m P=FIRST: -d first.db
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
epics>
2) 在另一个终端中:camonitor FIRST:Random
(base) [blctrl@localhost EPICS]$ camonitor FIRST:Random
FIRST:Random 2024-05-01 03:34:42.839417 3.26696
FIRST:Random 2024-05-01 03:34:43.839276 0.0920119
FIRST:Random 2024-05-01 03:34:44.839298 2.97612
FIRST:Random 2024-05-01 03:34:45.839343 4.24582
^C
3) 尝试dbl,dbpr, dbpf命令:
epics> dbl
FIRST:Random
epics> dbpf FIRST:Random 10
DBF_DOUBLE: 10
epics> dbpr FIRST:Random
A : 10 AMSG: ASG : B : 0
C : 0 CALC: RNDM*A D : 0 DESC:
DISA: 0 DISV: 1 E : 0 F : 0
G : 0 H : 0 I : 0 J : 0
K : 0 L : 0 NAME: FIRST:Random NAMSG:
SEVR: NO_ALARM STAT: NO_ALARM TPRO: 0
VAL : 3.27107652399481
数据库可以分开,用以下方法在一个IOC中加载若干数据库文件:
first_a.db:
# first_a.db
record(ai, "$(P)Range")
{info(autosaveFields, "VAL")field(INP, "10")field(PINI, "YES")
}
first_b.db:
# first_b.db
record(calc, "$(P)Random")
{field(SCAN, "1 second")field(INPA, "$(P)Range")field(CALC, "RNDM*A")
}
#softIoc -m P=FIRST: -d first_a.db -d first_b.db
root@orangepi5:/usr/local/EPICS/program/softdb# softIoc -m P=FIRST: -d first_a.db -d first_b.db
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
epics> dbl
FIRST:Range
FIRST:Random
epics>
8、记录类型
1)ai/ao:模拟输入/输出:-读取/写入数值,映射成工程单位
2)bi/bo:二进制输入/输出:-读取/写入位,映射成字符串
3)calc:公式
4)mbbi/mbbo:多位二进制输入/输出:-读取/写入16位数值,映射位模式到字符串。
5)stringin/stringout:longin/longout, seq, compress, histogram, waveform, sub, ..
9、公共字段
1)设计时间
- -NAME:记录明,网上唯一。
- -DESC:描述。
- -SCAN:扫描机制。
- -PHAS:扫描阶段。
- -PINI:初始化时运行一次。
- -FLNK:转发链接。
2)运行时
- -TIME:时间戳。
- -SEVR,STAT:警报严重性,状态。
- -PACT:运行活动的。
- -UDF:未定义?从未运行?
- -PROC:强制运行。
3)还有
-TPRO:跟踪运行,设为1来调试记录运行。
10、记录扫描
1)SCAN字段
- 当被其它记录运行时:"Passive"(默认)
-周期地:".1 second", ".2 second", ".5 second", "1 second", "2 second", "5 second", "10 second"。
-事件触发:
- "Event":(EVNT字段选择事件)
- "I/O Intr":(如果设备支持允许这个)。
2)PHAS字段
对处于相同周期扫描地记录添加顺序。首先PHAS=0, 接着PHAS=1, ...
3)PINI字段
设置成"YES"使得记录启动时运行一次。对基本不再更改的"操作输入"记录有用,因此它们有一个初始值。
4)PROC字段
写入这个字段将运行一个记录。
11、数据库和IOC其它部分
1)记录扫描运行优先级高于通道访问或PV访问
在高CPU负载,PVs在记录仍然在运行时可能没有连接。
2)0.1秒扫描运行优先级高于10秒扫描。
3)PRIO字段为异步完成和事件扫描的记录选择优先级。
12、公有的输入/输出记录字段
- DYTP:设备类型。
- INP/OUT:如何读取/写入,格式取决于DTYP。
- RVAL:原始值(例如:16位整数)
- VAL:工程单位值(例如:64位float)
仅限输出:
- DOL:所需输出链接。输出记录读取这个链接获取VAL,接着写入OUT。
- OSML:输入模式选择,closed_loop, supervisory。
- IVOA:无效时,输出操作。
- DRVL,DRVH:驱动限制。
13、扩展"first.db"
一个从0到上限的渐变,通过一个单独的记录可以设置这个上限。
ramp.db:两个记录组成的数据库文件。
1)$(P)Limit是模拟输出记录,用它设置渐变的上限。使用输出。输入也有效,由于没有要读或要写的硬件,但仅输出有DRVH。
2)$(P)Ramp是calc记录,它每秒运行一次,如果计算结果小于上限,则其值每次加1,否则,其只被设为0。读取输入:A=我自己的当前值;B=$(P)Limit激烈的值。
record(ao, "$(P)Limit")
{field(DRVH, "100")field(DOL, "9")field(PINI, "YES")
}record(calc, "$(P)Ramp")
{field(SCAN, "1 second")field(INPA, "$(P)Ramp")field(INPB, "$(P)Limit")field(CALC, "A<B?A+1:0")
}
使用softIoc -m P=SECOND: -d ramp.db
root@orangepi5:/usr/local/EPICS/program/softdb# softIoc -m P=SECOND: -d ramp.db
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
epics> dbl
SECOND:Limit
SECOND:Ramp
从CSS软件中查看calc记录随时间的变化:
14、模拟记录字段
1)EGU:工程单位名称。
2)SMOO:平滑。
- -VAL:(1-SMOO) * new_value + SMOO*last_value
- -SMOO=0:VAL=new_value, 默认行为
- -SMOO=1:VAL=last_value, 失效行为
- -0<SMOO<1:VAL ‘平滑地’跟随最新地读数。
3)LINR:线性化(None, Slope, 断点表):-EGUL,EGUF,ESLO,EOFF:用于LINR的参数。
4)LOLO,LOW,HIGH,HIHI:警报限制:-LLSV,LSV,HSV,HHSV:相关联的警报严重性。
15、二进制记录字段
1) ZNAM, ONAM:对应"0", "1"的状态名称。
2)ZSV,OSV:警报严重性。
16、记录链接
1)输入或输出记录可以是
-其他记录的字段名称:“other”, “other.VAL”,"other.A"
- 如果其他记录是在相同IOC中,"数据库链接"
- 如果没有找到名称:"通道访问链接"
-硬件链接
- 具体取决于设备支持
- DTYP字段选择设备支持
- 格式示例:"field(OUT,"@asynMask($(PT2) 0 0x1)")"
2) 输入链接可以是
-常数数值:"0", "3.14", "1.6e-19"。
3) 一个记录的FLNK记录在当前记录结束后运行另一个记录。
17、数据库链接
1) 格式:"record.field {flags}"
-VAL是字段的默认。
2)Flags:
-PP:运行一个被动目标记录。
- INP,DOL:在读取前。
- OUT:在写入后。
-NPP:非运行被动(默认)。
-MS:最大化严重性
-NMS:非MS(默认)
-MSS:最大化严重性和状态。
-MSI:当severity=INVALID时。
3)示例:
field("INP", "other_rec.VAL PP MS")
18、通道访问链接
当被链接的记录不是在这个IOC中时,自动使用通道访问链接。
flags:
-PP:被忽略。不触发另一个IOC上运行。
-MS,MSI:(INVALID时)最大化严重性。
通道访问链接flags:
1)CA:强制CA链接,即使目标记录在相同IOC中,可以用于打破'锁集'。
2)CP:用于INP链接,对收到的CA monitor时运行。一般在链接的值变化时引起运行。具体取决于源的MDEL。
3)CPP:CP,但仅限SCAN=Passive。
19、转发链接(Forward links)
1) 触发运行,但不传递数据。
2)如果SCAN=Passive,目标记录被运行。
3)可以使用CA链接:
-必须使用
- FLNK=“other.PROC”(其他IOC)
- FLNK=“ohter.PROC CA”(相同IOC)
-即使SCAN!=Passive,总是触发运行。
20、运行链
1) 运行链1
以上记录都是每0.1秒执行一次,执行顺序由PHAS=0,1,2指定;Calculation_1通过INPA字段从Input_1获取输入,Output_1通常DOL从Calculation_1获取输入。
2)运行链2
Input_2记录每0.1秒运行一次,在其运行结束时,通过FLNK链接,使得Calculation_2运行,在Calculation_2运行期间,通过INPA从Input_2获取输入,并进行计算,在其运行结束时,通过FLNK链接,使得Output_2运行,在Calculation_2运行期间,通过DOL从Calculation_2获取输入。
3)运行链3
Output_3记录每0.1秒记录运行一次,在其运行期间,通过DOL从Calculation_3获取输入,由于其链接属性是PP,此时Calculation_3开始运行,其运行期间通过INPA从Input_3获取输入,由于其输入链接是PP,此时Input_3开始运行,其运行结束后,Calculation_3获取了输入值,并进行计算并得到结果,此时Calculation_3运行结束,Output_3开始运行,从Calculation_3获取了输入,并完成之后的运行。
21、变化率示例
计算一个输入的变化率:
Rate记录的类型是calc,它每1秒钟运行一次,当其运行时,首先通过INPA从Input记录获取输入,并且存入其A字段,然后通过INPB记录从Input记录获取输入,由于此输入链接是PP属性,此时会将运行权交给Input记录使得Input记录运行,当其运行结束时,将运行全交给Rate记录,INPB获取了Input新产生的值,并且将其放入字段B,然后根据CALC中指定的A-B进行计算,计算结果便是Input记录一秒间隔的变化值。
22、仿真模式
当在仿真模式时,AO记录不调用设备支持并且AI记录从AO记录获取其输入。
23、多扫描触发
慢周期扫描和快变化响应
每5秒钟以及在AO记录被更改时,AI记录被运行。即使正常扫描速率非常满,这也提供了对操作人员更改的立即响应。对电源设置的更改被代表一个本地/远程切换开关的BO记录禁止。
24、设备支持
1)记录(AI, AO,..)靠它们自己仅读写其它记录。
2)设备支持链接它们到硬件
3)硬件设备支持是EPICS ‘base’之外的。根据需要被添加到IOC中。
4)DTYP选择了一个设备支持模块。
5)INP/OUT提供细节。
25、同步与异步
1)”快“:在记录被运行时,同步设备支持读或写一个记录的VAL。
2)"慢“:当记录被运行时,异步支持开始读取或写入。记录保持在PACT=true状态,并且在数据已经被读/写时,设备支持触发运行结束。
3)无论记录是否正在运行,通道访问'get/put'读/写当前VAL。
4) 通道访问'get/put callback'在运行结束时将结束。
26、'软'设备支持
1)用于AI,AO,BI,BO,...的"软通道"
读/写这个VAL字段
2)用于AI,AO,BI,BO,...的"原始软通道"
读写RVAL字段,转成/或从VAL转换
3)用于AI,AO,BI,BO,...的”异步软通道“
执行一个get/put回调,等待结束。
27、锁集
1)由链接连接起来的记录组。
2)运行一个记录锁定了它的锁集。
- -防止由多个线程运行。
- 类似,但技术上与PACT分开
常能透明地避免问题,使用"CA"标记打破锁集。
28、记录锁定 VS PACT
取决于记录地设备支持,一个记录可以运行很长时间:
-运行置位PACT并且触发驱动程序获取数据。
-一段时间后,驱动程序再次运行这个记录,并且复位PACT。
当以下情况,在锁集中的记录被锁定:
1)运行开始,在其结束时,再次,但不在两个时段之间。
2)读取一个字段。
3)写一个字段。
29、警报
1)公共字段:
- SEVR:警报严重性。NONE,MINOR, MAJOR, INVALID
- STAT:警报状态。UDF, READ, WRITE, CALC, HIGH, STATE, ...
2) 二进制字段
-ZSV, OSV:对应'zero'和'one'状态的严重性。
3)模拟字段
- -LOLO, LOW, HIGH, HIHI:阈值
- -LLSV, LSV, HSV, HHSV:相关的严重性。
- HYST:回滞。
警报示例
当温度接近沸点时,产生警报:
record(ai, "$(P)TANK")
{field(DESC, "Water Temperature")field(SCAN, "xxx")field(INP, "xxx")field(EGU, "C")field(PREC, "1")field(HIGH, "90")field(HSV, "MINOR")field(HIHI, "100")field(HHSV, "MAJOR")
}
30、监视死区
模拟记录发送更新给CA客户端
-MDEL:用于大部分客户端的变化yu'zhi
-ADEL:用于存档的客户端。
31、记录小提示
1)对用户输入使用AO,模拟输出
-DRVL,DRVH可以限制值范围。
2)BO记录可以用作计时器:
-HIGH字段:当写VAL=1时,保持1 HIGH秒。
-对操作接口按钮有用:按钮西1,记录在HIGH=1后恢复为0。
3)MBBI,MBBO记录映射状态:
- 通过ZRVL/ZRST,ONVL/ONST,TWVL/TWST,...定义值和状态。
- 可以像BI/BO一样使用:ZRVL=0, ONVL=1, ZRST<=>ZNAM, ONST<=>ONAM
- 对于除了0,1外的值,ZRVL=0, ONVL=255
- 从位解码限位开关状态:
- ZRVL=0,ZRST=‘Moving’
- ONVL=1,ONST='At Left limit'
- TWVL=2,TWST='At Right Limt'
- THVL=3,THST='Broken', THSV=MAJOR
4) 对if-then-else逻辑使用CALCOUT
- INP*和CALC如CALC记录中的INP*和CALC。
- OOPT "On Change", "When Zero", "Transition to Zero"等。
- 输出可以使用CALC或者一个单独的OCAL。
5) SEQ, FANOUT, DFANOUT可以运行一个记录列表
- 只是运行或者写值。
- SEL可以从运行所有更改到运行选取的记录。
6)COMPRESS记录可以
- 在一个环形缓存中保持最新的N个值。
- 计算数组的平均,最大或最小。
7)ASUB记录可以调用C代码
- INAM,SNAM:initial()和sub()的名称。
- 很多INP*和VAL*字段。
8)EVENT记录可以提交数据库事件
-触发SCAN=Event并且EVNT=那个事件的记录。
32、Calcout记录详解
1)结合了calc记录和模拟输出功能。
- -INPA,INPB,..., INPL和CALC计算VAL。
- OUT指向要写VAL的位置。
2)OOPT确定了OUT是否/何时输出OUT。
-”Every time“, ”On Change“, ”When None-zero“, ”Transition to Zero“, ...
3)默认,VAL被输出,但也可以配置:
- -field(OCAL, "A/B+..."):计算另外的OVAL
- -field(DOPT, "Use OCAL"):选择输出OVAL而不是VAL到OUT。
4) 在一个记录内两个计算和一个"if"类型选择器。
record(calcout, “Corrector”)
{field(SCAN, “.1 second”)field(INPA, “Enable”)field(INPB, “Setpoint”)field(INPC, “Readback”)field(INPD, “17.54”)field(CALC, “A”)field(OOPT, “When Non-zero”)field(DOPT, “Use OCAL”)field(OCAL, “D*(B-C)”)field(OUT, ”SteeringMagnet PP”)
}
CALC确定我们是否应该做任何事情,OCAL用于实际计算,OVAL值用于实际输出到OUT。
33、EPICS base之外的'synApps'记录
1) MOTOR记录
用于控制电机的整个生态系统。
2)BUSY记录可以用于支持put-回调:
- 某些设置点记录FLNKs指向设置BUSY记录=1的逻辑。
- 当设备支持到达设置点,设置BUSY记录VAL=0
- 在设置达到设置点后,指向设置点的CA 'put-callback'将结束。
34、Motor记录详解
1)这个记录有超过100个字段。
2)基本控制
- VAL:电机需要的位置。支持put-calback
- RBV:回读值,实际电机位置
- DONE:结束移动电机了吗?
- HLS,LLS:电机在上限位或下限位吗?
- STOP:停止移动。
3) 分辨率:
-MRES,DIR,OFF,EGU:将电机脉冲数转成了"mm"或"degrees"工程单位。
-它时步进电机或伺服电机?我们有编码器吗,如果标定它。
4)移动
- VBAS, VMAX,ACCL,HVEL,JVEL, ... 速度,加速度
- HLM,LLM,移动范围的限制。
- BDST,BACC,RTRY,...齿隙补偿,重试。
5)其它:Homing, "Jog", "tweak", status
35、时间戳
1)TIME一般设置成记录上次被运行的时间。
2)TSE=-2:例如,设备支持已经设置TIME为从硬件获取的准确触发时间。
3)TSE=1...255:设置TIME为从定时系统获取的事件1..255的上次发生。
4)TSEL:允许从另一个记录获取时间戳。
36、线性转换
模拟记录转换RVAL<=>VAL
1) LINR=NO CONVERSION,VAL=RVAL
2) LINR=SLOPE:VAL=(RVAL)*ESLO+EOFF。
这假设设备支持填充整数RVAL字段。如果设备支持已经有了一个浮点值,它放置这个值到浮点VAL字段。需要进一步转换,则使用一个CALC记录。