Engee 文档
Notebook

返回无人机以减少电池电量

在这个项目中,我们将应用几种使用有限自动机计算代理系统的方法。

为什么是有限自动机?

有限自动机允许您在抽象级别创建调试环境或测试决策算法。 为了避免从头开始开发和维护解决方案的成本,我们将尝试其他几种方法。:

-使用标准库建模[StateMachines](https://juliapackages.com/p/statemachines )和
-使用Engee图形语言。

有限状态机的最简单例子

首先,让我们构建一个简单的确定性有限自动机(DFSM)。

In [ ]:
]add StateMachines

让我们创建一个自动售货机 a1,它设置了在电池电量不足时将四轴飞行器返回底座的逻辑。

In [ ]:
using StateMachines

a1 = Automaton([
    Transition("landed", "flying", :takeoff),         # Взлет по команде
    Transition("flying", "returning", :low_battery),  # Авто-возврат
    Transition("flying", "returning", :return_cmd),   # Возврат по команде
    Transition("returning", "landed", :returned),     # Посадка
], start="landed")

states = []
events = [ :idle, :takeoff, :low_battery, :returned ]

for event in events
    prev_state = a1.state
    StateMachines.exec!( a1, event )
    append!( states, [a1.state] )
    println( "Переход $(String(prev_state)) -> $(String(a1.state)) по событию: $(String(event))" )
end
Переход landed -> landed по событию: idle
Переход landed -> flying по событию: takeoff
Переход flying -> returning по событию: low_battery
Переход returning -> landed по событию: returned

另一个输出选项是图形。 对于此输出,我们将转换数组 statesevents 在小写形式中,我们将为它们设置一定的顺序,以便输出不是按字母顺序执行,而是按更合乎逻辑的顺序执行。

In [ ]:
]add CategoricalArrays Measures
In [ ]:
using CategoricalArrays, Measures
gr()

# Зададим порядок событий и состояний (в противном случае они выводятся в алфавитном порядке)
events_ordered = levels!( categorical(string.(events)), ["idle", "takeoff", "low_battery", "returned"])
states_ordered = levels!( categorical(string.(states)), ["landed", "flying", "returning"])

plot(
    plot( events_ordered, 1:length(events_ordered), title="События",
          st=:steppre, yflip=true, lw=repeat([ 12; 2 ], length(events_ordered))[1:end-1] ),
    plot( states_ordered, 1:length(states_ordered), title="Состояния",
          st=:steppre, yflip=true, yaxis=nothing, c=2,
          lw=repeat([ 12; 2 ], length(states_ordered))[1:end-1] ),
    legend=false, xmirror=true, top_margin=5mm, right_margin = [10mm 0mm],
)
plot!( size=(800,300) )
Out[0]:

我们已经建立了一个相当典型的图,它在UML中被称为 Sequence Diagram (图表последовательности).

如果另一种解释方便,则可以反转图形的轴。

In [ ]:
# Зададим порядок событий и состояний (в противном случае они выводятся в алфавитном порядке)
events_ordered = levels!( categorical(string.(events)), ["idle", "takeoff", "low_battery", "returned"])
states_ordered = levels!( categorical(string.(states)), ["landed", "flying", "returning"])

plot(
    plot( 1:length(events_ordered), events_ordered, title="События",
          st=:steppre, lw=repeat([ 2; 12 ], length(events_ordered))[1:end-1] ),
    plot( 1:length(states_ordered), states_ordered, title="Состояния",
          st=:steppre, c=2, lw=repeat([ 2; 12 ], length(states_ordered))[1:end-1] ),
    legend=false, xmirror=true, top_margin=5mm, right_margin = [10mm 0mm],
)
plot!( size=(800,300) )
Out[0]:

在Engee环境中使用图表组件

有限自动机的编程任务便于对大型系统或生成的场景进行建模。 Engee中呈现的图形形式主义也非常适合表示小型决策算法。 Chart (有限状态机)。

image.png

我们定义了一个场景,其中事件的发生以块为单位进行建模。 Ступенчатая функция (Step),穿过街区 Разность (Difference). 等有限状态机的输入 Логика возврата 不会有步骤,而是离散脉冲。

在块下添加了注释元素,以便在模型中一目了然地看到整个测试场景。

image.png

剩下的就是在命令控制模式下运行模型并构建图形。:

In [ ]:
model_name = "drone_rtb_state_machine";
model_name in [m.name for m in engee.get_all_models()] ? engee.open(model_name) : engee.load( "$(@__DIR__)/$(model_name).engee");
res = engee.run( model_name );

plot( res["Состояние"].time, res["Состояние"].value, label="Состояние",
      yticks=((1,2,3), ("На базе","Полет","Возвращение")), lw=3, size=(600,300) )
Out[0]:

您可以从此图生成代码(但是,由于C中不支持西里尔字符,因此最好为块选择一个名称 Chart,由拉丁字符组成)。

结论

我们创建了一个四轴飞行器最简单的功能之一的模型-当电池电量不足时"返回基地"。 您可以将此模型用作更复杂系统的测试场景,以检查受控环境中某些条件的顺序和发生情况。

示例中使用的块