【问题标题】:Converting UML State Machine to SCL?将 UML 状态机转换为 SCL?
【发布时间】:2020-07-16 02:08:38
【问题描述】:

我想知道我是否可以使用状态机/图表对 PLC 进行编程。

在 Sparx EA 的帮助下,我们可以组成我们的状态机。有没有机会将此状态机转换为 SCL(结构化控制语言,用于 PLC 编程)?或者我们可以从 Sparx EA 中获取什么样的数据,作为 PLC 编程的输入?

或者也许你有更好的想法来实现这个想法。

【问题讨论】:

    标签: uml enterprise-architect state-machine plc


    【解决方案1】:

    当然。您需要一个可以读取状态机图并生成等效结构化文本的代码生成器工具。

    代码的形式非常简单。您可以为每个位定义一个 ST 布尔值(如果您可以像在 StateCharts 中那样具有实时并行状态)或一个包含状态编号的 ST 整数。

    每个状态的 ST 代码为:

       if (StateXXX) then
           <action in this state>
           if (somecondition)
              StateXXX=false;
              StateYYY=true;
           endif
       endif
    

    您需要为每个状态生成此代码。

    剩下的问题是您使用什么工具 来完成此任务? 可以说任何可以读取 UML 图的工具,通常可以从 UML 编辑器导出为 XML 文档;有了解析后的XML,你就可以编写代码爬过去,吐出上面的代码片段。

    如果您编写定义良好的模板片段,这可能会更容易。您可以使用临时模板(简单的文本字符串,其中包含必须填写内容的标记),也可以使用强制生成代码的结构和组合的工具,例如 Program Transformation System (PTS)

    PTS 接受一种语言的语法,将解析该语言的实例,并让您转换该语言,最后吐出修改后的语言实例。一个有用的特殊情况是,如果您愿意,可以将平凡的程序转换为复杂的真实程序。此外,一个好的 PTS 可以让你根据正式的代码模板编写模式和转换规则,至少强制模板的语法是有效的。这可确保您使用的作品始终具有一定的最小意义。 (相比之下,您可以在文本模板中编写任何您喜欢的垃圾)。当您编写大量此类模式时,这对于避免产生垃圾非常有帮助。

    对于这个特定的示例,对于(我公司的 PTS 称为 DMS,请参阅 bio),您可以为上述片段编写模式:

     pattern StateInstance(statenumber: natural, action: statements, exit_condition: expression, exit_state: natural): statement =
       " if (StateNumber=\statenumber) then
            \action
            if (\exit_condition) then
              StateNumber=\exit_state
            endif
          endif
        ";
    

    DMS 提供 API 来实例化此模式(以及其他模式,您通常会编写很多)并组合它们的结果(使用实例化模式作为其他模式的参数来实例化)以生成最终程序。您还可以添加转换规则来优化生成的代码。 (DMS 由语法定义驱动;它已经知道 40 多种语言,尤其是对 ST 和 XML 的强大定义。

    【讨论】:

    • 感谢您的回答。但是在构建 s7 代码时,我不能将整个代码放在一个文档中。所以在s7中,我们必须把它放在不同的模块中。这意味着我还必须自动化该过程以制作新模块并将一些代码复制到其中。有什么想法吗?
    • 这只是更多的转换。 PTS 应该能够从单个输入文档中生成多个源文件。模块结构本身只是另一种用部分代码填充的模式。您需要在 PTS 中使用一些额外的机制来决定整个生成代码的哪一部分放在哪个文件中。大多数 PTS 可以进行分析,但有时会很尴尬; DMS 对自定义分析器有很多支持。标准是什么?
    【解决方案2】:

    我从未真正编写过 S7,但基本上知道您在寻找什么。 EA 没有 SCL 的生成器,并且看到来自 Sparx 的可能性很低。所以有两种可能。

    首先(但我不喜欢)是深入研究代码生成过程中使用的 Sparx 宏语言的内容。如果您只需要对现有模板进行微调,那很好,但是编写一个全新的模板并不好玩(对我来说)。

    第二种方法是使用 API 进行代码生成。这相当容易(嗯,对我来说,因为我在大学学习编译器构造)。你要做的是获取状态机,遍历它并吐出相应的语言结构。这在很大程度上取决于您的技能,但我会在几天内创建一个粗略的原型。

    编辑这是一个示例 Perl(我知道它是一个 PITA,如果你一周左右不使用它,但你可能会破译它)脚本使用解析状态机EA 的 API:

    package Compiler;
    use strict;
    use Win32::OLE qw (in);
    
    sub new {
      my ($self, $rep) = @_;
      $self = {};
      $self->{nodes} = {};
      $self->{rep} = $rep;
      bless $self;
    }
    
    sub traverse {
      my ($self, $node) = @_;
      my $guid = $node->ElementGUID;
      return if defined($self->{nodes}->{$guid});
      my $nodeInfo = { 'name' => $node->Name, 'type'=> $node->Type, 'out' => ()};
      $self->{nodes}->{$guid} = $nodeInfo;
    
      for my $trans (in $node->Connectors) {
        my $target = $self->{rep}->GetElementByID($trans->SupplierID);
        next if $target->ElementGUID eq $guid;
    
        my @targetInfo = ($trans->TransitionGuard, $target->ElementGUID);
        push(@{$nodeInfo->{out}}, \@targetInfo);
        $self->traverse($target);
      }
    }
    
    1;
    

    还有一个像这样的简单主程序:

    use strict;
    no strict 'refs';
    use compiler;
    
    my $rep = $ENV{'REP'}; # get repository pointer "by magic"
    my $node = $rep->GetElementByGUID('{574C5E0C-E032-44c6-A6B0-783D35B9958B}'); # fixed addressing of InitialNode
    my $compiler = Compiler->new($rep); 
    $compiler->traverse($node); # read in all possible transitions/states
    my %states = %{$compiler->{nodes}}; # this hash holds all states and their transitions
    
    for my $key (keys %states) {
      my $state = $states{$key}; # loop through all found states
      print "$state->{type} $state->{name}\n"; # state name
      for my $out (@{$state->{out}}) {
        my ($guard, $guid) = @{$out};
        my $target = $compiler->{nodes}->{$guid};
        print "__$guard -> $target->{name}\n";
      }
    }
    

    现在假设你有一个这样的状态机:

    当你运行上面的程序时,它会打印出来

    状态节点
    状态节点
    __无条件 -> State1
    状态 State1
    __condition -> State2
    __exit ->
    状态 State2
    其他条件 -> State1

    第一个 StateNode 是未命名的出口,下一个是 InitialNode(您也可以从 API 获取该信息并使用它)。 State1 有两种可能的转换(退出和State2)。而State2 只转换为State1

    现在,通过命名状态列表,您可以为不同的状态创建一些枚举。此外,您还拥有所有转换的守卫,您可以将其转换为 if-cascades 或 switch-statements。

    当然,这不是一个完整的代码生成器,但您可以了解如何从这个脚手架制作一个。

    【讨论】:

    • 我是一名自动化专业的学生,​​第 3 学期。如果我能看到你的原型,那就太好了。 :)
    • 这里的答案肯定太长了。基本上,获取 StartNode,获取传出的转换,评估守卫并为您到达的所有状态创建状态。
    • 如果你真的想把你的原型发给我,我可以提供我的电子邮件地址。我看你对这个主题很了解,要多久才能出“代码翻译器”,能不能说一下程序员应该具备的资质?因为我想知道使用状态机而不是 SCL 是否正确。所以在和用户应该只做状态机,对市场和业务部门的人来说会更容易
    • 让我看看这些天我能不能破解一个脚手架。取决于我的可用时间。
    • 无论您使用哪个引擎来生成代码,状态机规范总是比 ST 代码更好,因为状态机使状态显而易见,并且ST代码最终掩盖了它。 (大多数工业控制器的替代方案是使用顺序功能图,它可以轻松地直接对状态机进行编码)。
    【解决方案3】:

    如果您使用的是 Siemens PLC-s,那么 S7 有一个名为 s7-graph 的可选软件包:http://w3.siemens.com/mcms/simatic-controller-software/en/step7/simatic-s7-graph/Pages/Default.aspx。您可以在那里实现状态机。但不知道它的任何导入选项。

    我将它用于一些被控制为状态机的设备。那个软件包不是免费的,我不记得它的价格了。我也不知道是否所有 S7 PLC 系列都支持它。我使用了 400 系列,它在那里工作。

    在将它用于任何项目之前,请让您当地的 Siemens 经销商让您试用一下。

    【讨论】:

      【解决方案4】:

      我在 EA 中编写了一个模板来实现从类图、状态机到 ST/SCL 代码的代码生成 PLCopen 代码(Twincat/Codesys 中的 IEC61131)。

      类图用于描述FB、DUT等程序的结构。 状态机用于描述plc程序的动态过程。 这样整个 oop plc 程序(带有接口,继承)将从 UML 模型中自动生成。

      https://www.youtube.com/watch?v=z071cZgMbZ8

      这里我创建了一个新的工具箱,专门用于 EA 中 plc 程序的建模

      https://www.youtube.com/watch?v=RfDxkq_hDvw&t=2s

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-18
        • 2019-03-09
        • 2023-03-27
        • 2021-12-08
        相关资源
        最近更新 更多