Engee documentation
Notebook

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).

In [ ]:
]add StateMachines

Let's create an automaton a1, which defines the logic of quadrocopter return to the base in case of low battery.

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

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.

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]:

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.

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]:

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.

image.png

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.

image.png

All that remains is to run the model in command mode and plot the graphs:

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]:

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.

Blocks used in example