如果定期调用状态机(在 MatLAB Simulink 或 PLC 程序中(,是否可以在相同的 plc 周期/simulink 步骤中在状态之间转换?
在Twincat 3(PLC(中,有一个选项"循环内部",如下面的链接所示: https://infosys.beckhoff.com/content/1033/tf1910_tc3_uml/63050395607969163.html
使用此类选项是否有任何限制? 系统是否仍然具有实时功能?
编辑为我无法写长评论:
1-在您的示例中,如果状态为循环中状态,并负责为电机生成设定点,直到达到所需的设定点(因此需要花费大量时间(。程序可能会"卡"在这种状态下,导致任务溢出,并违反实时约束。 建议的解决方案:使用变量"最大 DO 循环调用"控制此状态的最大调用次数:https://infosys.beckhoff.com/english.php?content=../content/1033/tf1910_tc3_uml/63050395607969163.html&id=,或者是否可以/更好地在单独的 PLC 任务中实现此任务?
2-对于没有周期内状态的状态图,程序将停止执行图表,保存状态,并在对当前活动状态进行一次评估后执行程序的其余部分。 如果图表中的所有状态都是周期中,则程序在哪里停止执行图表以执行程序的其余部分?
唯一的解决方案是让一些状态不是周期中,并确保它们足够快地到达,不会导致任务溢出?
是的,这是可能的。这完全取决于您如何定义状态机代码。Filippo的回答解释了如何使用循环内部选项。
另一种看待这个问题的方法是,在结构化文本中,状态机通常使用案例结构实现。
为了在单个循环中具有多个状态,您需要两个案例结构或运行相同的案例结构两次(例如,使用 For 或 While 循环(
例如,假设您希望在进入错误状态后立即对错误状态执行操作。您的第一个 Case 语句会将状态转换为"错误"。
在第二个 Case 语句中,您将检查"错误"状态并立即采取行动。
PLC具有实时功能,因此要回答您的最后一个问题,是的,无论您使用哪种编程语言,系统都是实时的。
使用 tf1910 扩展时,Beckhoff 运行时的代码将在后台生成,该代码将每 x 毫秒循环运行一次,具体取决于您的配置。
将 Cycle-Internal 操作转换为结构化语言可能如下所示:
假设您有一个软件组件Motor,它扩展了一个软件组件StateMachine。
状态机定义了不同的(原始(状态,如初始化、就绪、忙碌、空闲、错误等。
V Boot()
|
|
<Init>
|
|
| Start()
|
|
<Ready> -----------<--------------+-------------<-----------+
| | |
| | |
| Execute() | |
| | |
| | |
| | Reset() |
<Prepare> | |
| | |
| | |
| | |
Wait() | Fault() | |
<Waiting> ---<-------->--- <Busy> ----------->----------- <Error> |
EndWait() | |
| |
| |
| |
| Done() |
| |
| |
| |
<Idle> ---------------------->------------------------------+
因此,电机也继承了这些状态。
现在,如果Motor处于 Init 状态,调用 Start(( 方法会将状态从Init更改为Ready。
根据程序的体系结构,此更改可能会对程序流(这意味着在当前周期中(或下一个周期产生直接影响。
假设我们的状态机功能块将Cycle-Internal实现为布尔输入变量:bCycleInternal它的当前状态是一个 enumaration 变量:eStateMachine
假设,根据 eStateMachine 的值(因此状态机的当前状态(,StateMachine 调用一个特定的方法(例如,对于 InitInit((,对于 Ready Ready(( 等(。
当 bCycleInternal 为 true 并且 Start(( 方法将当前状态从 Init 更改为 Ready 时,在同一循环中直接在Init(( 之后调用Ready((。 否则,如果 bCycleInternal 为 false,则在使用 Start(( 方法将状态机的状态(或 eStateMachine 的值(从Init更改为 Ready 时,不会在下一个循环之前调用Ready((。