电池电量减少时返还无人机¶
在本项目中,我们将采用几种方法来使用有限自动机计算代理系统。
为什么要使用有限自动机?¶
有限自动机允许你创建一个调试环境,或在抽象层面上测试决策算法。为了避免从头开始开发和维护解决方案的成本,我们将尝试其他几种方法:
- 使用内部库
StateMachines
建模,以及使用 Engee 图形语言。 - 使用 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
另一种输出方式是图形输出。对于这种输出,我们将把数组states
和events
转换为字符串形式,并赋予它们一定的顺序,这样输出就不会按字母顺序进行,而是按更合理的顺序进行。
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
(有限自动机)组件所代表的图形形式主义也非常适合。
我们定义了一个场景,在这个场景中,事件的发生是通过块Ступенчатая функция
(Step
) 通过块Разность
(Difference
) 来模拟的。因此,有限自动机Логика возврата
的输入将接收离散脉冲,而不是步长。
在块下添加了注释元素,这样,整个测试场景就可以从模型的第一眼看到。
剩下的工作就是在命令模式下运行模型并绘制图表:
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
)。
结论¶
我们创建了一个最简单的四旋翼飞行器功能模型--电池电量不足时 "返回基地"。我们可以使用该模型作为更复杂系统的测试场景,在受控环境中检查某些状态的顺序和发生情况。