Engee documentation
Notebook

Returning the drone to reduce battery power

In this project, we will apply several methods for calculating agent systems using finite automata.

Why finite automata?

Finite automata allow you to create a debugging environment or test a decision-making algorithm at an abstract level. To avoid the cost of developing and maintaining a solution from scratch, we'll try a couple of other ways.:

  • modeling using the standard library StateMachines and
  • using the Engee graphical language.

The simplest example of a finite state machine

To begin with, let's build a simple deterministic finite automaton (DFSM).

In [ ]:
]add StateMachines

Let's create a vending machine a1, which sets the logic for returning the quadcopter to base when the battery is low.

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 output option is graphical. For this output, we will translate the arrays states and events in lowercase form, we will set a certain order for them 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 (Chart последовательности).

If another kind of interpretation is convenient, you can reverse the axes of the graph.

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

The programming task of a finite automaton is convenient for modeling large systems or for generated scenarios. The graphical formalism presented in Engee is also well suited for representing a small decision-making algorithm. Chart (Finite state machine).

image.png

We define a scenario in which the occurrence of events is modeled in blocks. Ступенчатая функция (Step), passed through the blocks Разность (Difference). So on the inputs of the finite state machine Логика возврата there will be no steps, but discrete pulses.

Annotation elements have been added under the blocks so that the entire test scenario can be seen at a glance at the model.

image.png

All that remains is to run the model in command control mode and build 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 a code from this diagram (however, since Cyrillic characters are not supported in C, 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 functions of a quadcopter - "return to base" when the battery is low. You can use this model as a test scenario for a more complex system to check the order and occurrence of certain conditions in a controlled environment.

Blocks used in example