Returning the drone when the battery charge decreases¶
In this project, we will apply several ways to compute agent systems using finite automata.
Why finite automata?¶
Finite automata allow you to create a debugging environment or test a decision algorithm at an abstract level. To avoid the cost of developing and maintaining a solution from scratch, we will try a couple of other ways:
- Modelling with the in-house library
StateMachines
and - using the Engee graphical language.
The simplest example of a finite automaton¶
First, let us construct a simple deterministic finite automaton (DFSM).
]add StateMachines
Let's create an automaton a1
, which defines the logic of quadrocopter return to the base in case of low battery.
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
Another variant of output is graphical. For this output we will translate the arrays states
and events
into a string form and give them a certain order, so that the output is performed not in alphabetical order, but in a more logical order.
]add CategoricalArrays Measures
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) )
We have built a fairly typical diagram, which in UML is called Sequence Diagram
(Sequence Diagram).
If another kind of interpretation is convenient, you can reverse the axes of the diagram.
# Зададим порядок событий и состояний (в противном случае они выводятся в алфавитном порядке)
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) )
Using the Chart component in the Engee environment¶
Programming a finite automaton is useful for modelling large systems or for generated scenarios. For the representation of a small decision-making algorithm, the graphical formalism represented in Engee by the Chart
(Finite Automaton) component is also well suited.
We define a scenario in which the occurrence of events is modelled by blocks Ступенчатая функция
(Step
) passed through blocks Разность
(Difference
). Thus, the inputs of the finite automaton Логика возврата
will receive discrete pulses instead of steps.
Annotation elements have been added under the blocks so that the whole testing scenario can be seen from the first glance at the model.
All that remains is to run the model in command mode and plot the graphs:
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) )
You can generate code from this diagram (at that, since C does not support Cyrillic characters, it is better to choose a name for the block Chart
, consisting of Latin characters).
Conclusion¶
We have created a model of one of the simplest quadrocopter functions - "return to base" when the battery level is low. We can use this model as a test scenario for a more complex system to check the sequence and occurrence of certain states in a controlled environment.