"硬" IOCs运行vxWorks并且直接连接到A/D, D/A, LLRF...硬件。
"软"IOCs运行在Linux等上,并且除了串口或网络设备(Moxa到电机控制器...)外没有I/O硬件。
1) 'iocCore'软件装载并且执行'记录'--记录的配置替代了自定义编写代码。
2) 所有控制系统工具箱都有:
但很少有一个相当的数据库。
任务:
1) 读取温度
2) 根据需要闭合/打开开关
3) 重复
由三个记录组成:temp, check以及switch。
1) 模拟输入记录temp用于表示读取鱼缸温度,SCAN字段表示1秒种读取一次,DTYP和INP字段表示硬件读取接口和硬件读取需要的格式,PREC是精度小数点后1位,LINR表示用表格转换温度,EGU表示工程单位。LOPR和HOPR表示上下温度限制,SMOO是读取所用平滑参数,HIGH表示上阈值,HSV表示当读取的值超过了HIGH设定值时,将触发MAJOR严重性警报。
2) 计算输出记录check,INPA表示用通道访问过程被动的方式(即:temp记录运行结束时本记录开始运行)从temp记录VAL字段读取输入,将这个输入与10进行比较,如果新产生的结果与上次结果不同时,将此次的VAL字段输出到switch记录。
3) 二进制输出记录,DTYP和OUT字段决定了硬件类型和输出的格式,当check记录运行结束后,如果其VAL发生变化了,则VAL的值将输出到switch记录,switch根据得到的值是0或1,对加热开关进行控制。IVOA字段决定了,当switch得到一个无效输入时,采取的行动是把输出值设置为0,即断开加热开关。
记录周期地或者被事件或者其它记录触发而运行。
[blctrl@rockygu db]$ cat first.db
# 最简单地记录,它做某件事情并且产生变化地数值
record(calc, "$(USER):random")
{field(SCAN, "1 second")field(INPA, "10")field(CALC, "RNDM*A")
}
1) 执行 softIoc -m USER="TEST" -d first.db加载这个数据库:
[blctrl@rockygu db]$ softIoc -m USER="TEST" -d first.db
dbLoadDatabase("/EPICS/base-R7.0.4.1/bin/linux-x86_64/../../dbd/softIoc.dbd")
softIoc_registerRecordDeviceDriver(pdbbase)
dbLoadRecords("first.db", "USER=TEST")
iocInit()
Starting iocInit
############################################################################
## EPICS R7.0.4.1
## Rev. 2022-06-14T15:34+0800
############################################################################
iocRun: All initialization complete
epics>
2) 在另一个终端执行:camonitor TEST:random
[blctrl@rockygu ~]$ camonitor TEST:random
TEST:random 2023-03-19 23:10:08.702282 2.3917
TEST:random 2023-03-19 23:10:09.702263 8.34287
TEST:random 2023-03-19 23:10:10.702296 1.3489
^C
3) 在ioc环境中尝试dbl, dbpr, dbpr命令:
epics> dbl
TEST:random
epics> dbpr TEST:random
A : 10 ASG : B : 0 C : 0
CALC: RNDM*A D : 0 DESC: DISA: 0
DISP: 0 DISV: 1 E : 0 F : 0
G : 0 H : 0 I : 0 J : 0
K : 0 L : 0 NAME: TEST:random SEVR: NO_ALARM
STAT: NO_ALARM TPRO: 0 VAL : 6.53513389791714
epics> dbpf TEST:random VAL
DBF_DOUBLE: 0.425726710918
epics> dbpf TEST:random VAL
DBF_DOUBLE: 5.78789959564
1) ai/ao:模拟输入/输出。读取/写入数值,映射成工程单位
2)bi/bo:二进制输入/输出。读/写单个bit位,映射成字符串
3) calc:公式计算
4) mbbi/mbbo:多位二进制输入/输出。读/写16位数值,映射位模式为字符串
5) stringin/stringout, longin/longout, seq, compress, histogram, waveform, sub, ...
a) NAME:记录名,在网络上唯一。
b) DESC:描述。
c) SCAN:扫描机制。
d) PHAS:扫描阶段。
e) PINI:在初始化时运行一次。
f) FLNK:转发的链接。
a) TIME:时间戳。
b) SEVR, STAT:警报严重性,状态。
c) PACT:PROCESS活跃的。
d) UDF:未定义?从不被运行。
e) PROC:强制运行。
TPRO:跟踪运行,设置为1来调试记录运行。
a) 当由其它记录使其运行:Passive(默认)
b) 周期地:".1 second", ".2 second", ".5 second", "1 second", "2 second", "5 second", "10 second",
c) 遇到事件:
为在相同周期扫描上地记录添加顺序: 首先PHAS=0, 接着PHAS=1, ...
设置"Yes"强制在启动时运行记录一次。对"操作输入"记录是个好办法,其几乎从不更改,因而它们有一个初始值。
写入这个字段将运行一个记录。
1) 记录扫描运行的优先级高于通道访问或PV访问:在高CPU负载时,在记录仍然被运行时,PV可能未连接。
2) 0.1秒扫描运行的优先级高于10秒扫描。
3) PRIO字段为异步完成以及事件扫描的记录选择优先级。
你的里程会不不同:RTOS或普通的Linux?
1) DTYP:设备类型。
2) INP/OUT:如何读/写,格式依赖于DTYP。
3) RVAL:原始值(例如:16位整数)
4) VAL:工程单位值(例如:64位浮点数)
1) DOL:所需的输出链接。输出记录读取这个链接来获取VAL,接着写到OUT...
2) OMSL:如果Output Mode Select = closed_loop。
3) IVOA:无效输出时的操作。
4) DRVL, DRVH:驱动限制。
# 一个斜率从0到'limit', 限制可以通过一个单独记录被设置
# 使用模拟输出记录,输入也也有作用,由于没有进行读或写的硬件,但仅输出记录有DRVH...
record(ao, "$(S):limit")
{field(DRVH, "100")field(DOL, "10")field(PINI, "YES")
}# 读取输入:A=我自己当前的值,B等于limit记录的值
# 在自身值小于limit的值时,每次1秒运行一次,自身值增加1,自身值等于limit值时,
# 下次运行,自身值变为0
record(calc, "$(S):ramp")
{field(SCAN, "1 second")field(INPA, "$(S):ramp")field(INPB, "$(S):limit")field(CALC, "A
1) EGU:工程单位名称。
2) SMOO:平滑。
3) LINR:线性(无,斜率,断点表):EGUL,EGUF,ESLO,EOFF:用于LINR的参数。
4) LOLO, LOW, HIGH, HIHI:警报限制。LLSV, LSV,HSV,HHSV是对应相关联的警报严重性。
1) ZNAM,ONAM:对应"zero", "one"的状态名。
2) ZSV, OSV:警报严重性。
1) 输入或输出链接可能是:
a)其它记录的字段的名称:"other", "other.VAL", "other.A"
b) 硬件链接
2) 输入链接可能是:常量"0", "3.14", "-1.6e-19"
3) 一个记录的FLNK字段在当前记录结束后运行另一个记录。
1) 格式:”record.field {flags}“
VAL是用于field的默认。
2) 标记:
3) 示例:field(INP, "other_rec.VAL PP MS")
当链接的记录不在这个IOC中时,自动使用通道访问链接。
标记:
1) PP:忽略。不触发在其它IOC上的运行。
2) MS,MSI:最大化严重性(当无效时)
1) CA:即使目标在相同IOC中,强制为CA链接,可以用于打破’锁集‘
2) CP:对于INP链接,在接收的CA监视器上运行。一般在链接的值变化时引起运行。细节取决于源的MDEL。
3) CPP:CP,但仅在SCAN=Passive时。
1) 触发运行,但不传递数据
2) 如果目标记录SCAN=Passive, 运行目标记录。
3) 可以使用CA链接
1)
Input_1, Calculation_1和Output_1都是按从左到右顺序每0.1秒运行一次,一个时刻仅运行一个记录。运行顺序受控于记录的PHAS字段,从小到大运行。
2)
Input_2记录每0.1秒运行一次,在其获取数据并结束运行后,通过FLINK使得Calculation_2记录运行,运行过程中INPA从Input_2记录的VAL字段获取值,并且根据设置进行计算,在其运行结束后,通过FLNK使得Output_2记录运行,在运行过程中DOL从Calculation_2的VAL获取值,并进行转换,将结果输出。
3)
Output_3记录每0.1秒运行一次,在其运行中,它将从Calculation_3的VAL获取值,但由于这个记录SCAN=Passive并且链接属性时PP,则Calculation_3记录开始运行,然后INPA字段将从Input_3记录的VAL字段读取输入值,但由于SCAN=Passive并且输入链接是PP属性,则Input_3记录开始运行,获取一个输入值,并且放到了VAL字段,Input_3记录到此运行结束,运行返回到Calculation_3记录,此时INPA获取了输入值,进行内部计算,并把结果放入到VAL,此时Calculation_3记录运行结束,运行返回到了Output_3记录,从Calculation_3记录VAL获取了值,进行转换后输出。
4) Calulation_1记录不会被运行。Output_1记录每0.1秒运行一次,其DOL字段是输入链接,在其获取输入前,会使Calculation_2记录运行,同样INPA字段是输入链接,在其获取输入前,使Input_1记录运行。Input_1记录和Calculation_1记录INPA之间的链接是NPP,而Calculation_1记录SCAN=Passive,所有这个记录不会运行。
5)同一个锁集中Output_1和Calculation_2都是0.1秒运行一次,而这两个记录通过输入链接使得上游数据源记录都可以运行,所以Input_1记录每0.1秒能够运行两次。(假设整个记录链运行时间相较于扫描时间0.1秒可以忽略不计)。
6)当通过输入链接和链接PP属性,记录运行权转移到了Input_1记录时,当其运行结束时,通过FLNK使得Calculation_1记录运行,而Calculation_1记录的INPA记录通过PP链接读取Input_1记录的VAL时,会使Input_1记录再次运行,运行权将在Input_1和Calculation_1之间轮流,所以其余记录将不会再运行了。
计算一个输入的"变化率"
INPA获取获取前1秒的输入数据,因为它不请求ai记录Input运行。INPB获取当前数据,因为它请求ai记录Input运行,并且获取其运行后的数据。这两个值相减反映了压力读取的'变化率'(差别/秒)。
当在仿真模式中,AO记录不调用设备支持并且AI记录从AO记录获取它的输入。
具有快速变边响应的慢速周期扫描:AI记录每5秒种以及当AO记录被更改时得到运行。这提供了对操作变化的即刻响应,即使正常扫描速率非常慢。对电源设置的更改被BO记录继承,此记录代表本地/远程切换。
1)记录(AI, AO,..)靠其自身仅从其他记录读或写。
2) 设备支持连接它们到硬件。
3) 硬件设备支持是EPICS 'base'之外的。根据需要添加到IOC。
4) DTYP选择一个设备支持模块。
5) INP/OUT提供具体连接。
1) "快速",同步设备支持在记录被运行时读或写一个记录的值。
2) "慢速",异步设备支持在记录被运行时启动取读或写入。这个记录保持PACT=true状态,并且当完成了数据的读取或写入时,设备支持触发运行结束。
3) 通道访问'获取/写入'当前值,无论这个记录是否正在运行。
4) 当运行结束时,通道访问‘get/put回调’将结束。
EPICS base包含了DTYP=
1) "Soft Channel"用于AI, AO,BI,BO,...:读取/写入VAL字段。
2) “Raw Soft Channel”用于AI,AO,BI,BO, ...:读取/写入RVAL字段,转换成VAL,或者从VAL转换。
3) "Async Soft Channel"用于AI,AO,BI,BO:执行一个get/put回调,等待结束。
以下记录链的问题:Output_1记录0.1秒运行一次,其引起ai记录0.1秒运行一次,Output_2记录5秒运行一次,其通过Calculation_2触发Input_1记录运行时,发现Input_1记录正在运行,则其将直接读取其当前值。
1) 由链接连接起来的记录组。
2) 运行一个记录锁定其锁集:
趋于透明地避免问题:除非你非常不幸运,则使用"CA"标记了打破锁集
1) 取决于其设备支持,一个记录可以"运行"很长时间:运行设置PACT并且触发驱动获取数据。一段时间后,驱动再次运行,并且清除PACT。
2) 当以下情况时,在锁集中地记录被锁定:
SEVR:警报严重性:None,MINOR, MAJOR, INVALID
STAT: 警报状态:UDF, READ,WRITE, CALC, HIGH,STATE, ...
ZSV, OSV:对应"zero"和"one"状态的严重性。
a) LOLO, LOW, HIGH, HIHI:阈值
b) LLSV, LSV, HSV, HHSV:相关联阈值的严重性。
c) HYST:回滞
# 当温度接近沸点时产生警报
record(ai , $(USER):tank)
{
field(DESC, "Water Temperature")
field(SCAN, "1 second")
field(INP, "xxxx")
field(EGU, "C")
field(PREC "1")
field(HIGH, "90")
field(HSV, "MINOR")
field(HIHI, "100")
field(HHSV, "MAJOR")
}
模拟记录发送更新给CA客户端:
1) MDEL:对于大部分客户端变化阈值
2) ADEL:用于存档客户端
1) 使用AO,模拟量输出记录,用于用户输入:DRVL, DRVH可以限制输出的范围。
2)BO记录可以用于计时器:
3) MBBI, MBBO记录映射状态:
ZRVL=0 ZRST="Moving"
ONVL=1 ONST="At Left Limit"
TWVL=2 TWST="At Right Limit"
THVL=3` THST="Broken", THSV=MAJOR
4) 使用CALCOUT用于if-then-else逻辑:
5) SEQ, FANOUT, DFANOUT可以运行一个记录列表:
6) COMPRESS记录:
7) ASUB记录可以调用C代码:
8) EVENT记录可以提交数据库事件:触发SCAN=Event并且EVNT=那个事件的记录。
1) 组合了calc记录和模拟输出功能:
2) OOPT确定了是否/何时写OUT:
"Every Time", "On Change" , "When Non-zero", "Transition to Zero"
3) 默认,VAL被写,但也可以配置
在一个记录中两个计算以及一个'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 None-zero")field(DOPT, "Use OCAL")field(OCAL, "D*(B-c)")field(OUT, "SteeringMagnet PP")
}
CALC确定我们是否应该做任何事情,OCAL用于实际计算。
1)MOTOR记录:一个用于控制电机的整个生态系统。
2) BUSY记录可以用于支持put-callback:
CA 'put-callback'到设置点将在设备到达这个设定点后结束。
1) 具有100+字段的记录。
2)基本控制:
3) 分辨率:
4) 移动:
5) 更多:Homing, jog, tweak, status
一个Motor记录?
motor.VAL 设定点
motor.RBL 回读
motor.DONE 结束?
motor.HLS 在高限位
motor.MRES 每个单位的步数
记录的集合?
record(ao, "$(M)_Set")
record(ai, "$(M)_Pos")
record(bi, "$(M)_Done")
record(bi, "$(M)_AtHighLim")
record(ao, "$(M)_StepsPerUnit")
record(waveform, "$(M)_Profile")
一个伺服电机步使用每个单位步数。步进电机支持一个移动profile。
没有一般化共享的'电源', “相机”, “PID”..记录。首选方法是记录集合。
1) TIME一般被设置成这个记录上次被运行时的事件。
2) TSE=-2:设备支持已经设置了TIME,例如,设为从硬件获取的确切触发时间。
3) TSE=1...255:设置TIME为从计时系统获取的事件1..255的上次发生。
4) TSEL:允许从另一个记录获取时间戳。
模拟记录转成RVAL为VAL:
LINR=NO CONVERSION:VAL=RVAL
LINR=SLOPAE:VAL=(RVAL)*ESLO + EOFF
这认为设备支持填充(整数)RVAL字段。如果设备支持已经有一个浮点值,它放置到(double)VAL字段。其余转换,则使用CALC记录。
模拟记录可以设置LINR=typeKdegC:这在一个*.dbd文件中:
上一篇:使用Ajax方式发送请求
下一篇:vue编程方法