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
StateMachinesand - 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).
]add StateMachines
Let's create a vending machine a1, which sets the logic for returning the quadcopter to base when the battery is low.
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 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.
]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 (Chart последовательности).
If another kind of interpretation is convenient, you can reverse the axes of the graph.
# Зададим порядок событий и состояний (в противном случае они выводятся в алфавитном порядке)
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
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).
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.
All that remains is to run the model in command control mode and build 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 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.


