Engee documentation
Notebook

Visualisation of the drone's instrument readings

This example implements algorithms for visualising flight data recorded from the drone's sensors.

The purpose of this demonstration is to show the different possibilities of data visualisation, including time-based data visualisation.

Let's start by reading the recorded data from a CSV file.

In [ ]:
using CSV

# Читаем данные из файла data.csv
df_read = CSV.read("$(@__DIR__)/data_drone.csv", DataFrame)

# Проверка первых строк
first(df_read, 5)
Out[0]:
5×3 DataFrame
RowВремяВысотаУгол
Int64Float64Float64
100.0-4.0
213.0-5.0
325.0-3.0
438.0-3.0
5410.0-3.0

As we can see, the table contains 3 fields, time counts, altitude values and the angle of inclination of the drone relative to the horizon.

In [ ]:
max_idx = 350;
t = df_read.Время[1:max_idx]
heights = df_read.Высота[1:max_idx]
angles = df_read.Угол[1:max_idx]

H = plot(t, heights, title="Высота")
A = plot(t, angles, title="Угол наклона")
plot(H, A, layout=(2, 1), legend=false)
Out[0]:

Based on the visualisation of the sensor values. we can see that the drone has been gradually gaining altitude and and changing pitch as it flew around some sort of an obstacle. We also see fluctuations in pitch relative to the horizon, which is most likely with the drone flying in windy conditions.

Next, let's declare static variables that do not need to be updated in the loop.

In [ ]:
max_y_h = maximum(heights)+10

# Уравнение единичной окружности
θ = range(0, 2π, length=100)
x_circle = cos.(θ)
y_circle = sin.(θ)
x = [-1, 1]

using Images
# Загрузка изображения дрона
drone_img = load("$(@__DIR__)/drone.jpg") 
Out[0]:
No description has been provided for this image

Now let's move on to the data visualisation loop itself. It can be conditionally divided into three parts.

  1. height display. For each moment of time, an altitude graph is plotted in the form of a red dot. The axis constraints are set to show the area around the current time ±10 seconds. The graph header shows the current altitude value and an up/down arrow depending on whether the altitude is increasing or decreasing.
  2. Pitch Graph. The pitch graph shows the angle of deflection of the drone relative to the horizon. The cosd and sind functions are used to plot the pitch line. The header contains the pitch angle value in degrees.
  3. Drone image rotation and visualisation, The drone image is rotated by a certain angle (pitch value + 90 degrees). The channelview function converts the image into a view convenient for further processing. A mask is used to remove black pixels.

In the end, all three graphics are collected into a single frame, which forms GIF frames.

In [ ]:
@gif for i in 1:length(t)
    ti = t[i]
    ai = angles[i]
    hi = heights[i]
    
    # Высота
    h_plt = scatter([ti], [hi], 
        markershape=:circle, markersize=15, markercolor=:red, framestyle=:box, 
        xlims = (ti-10, ti+10), ylims = (0, max_y_h), 
        legend=false, grid=false, 
        title="Высота: $hi m $((i == 1 || heights[i] > heights[i-1]) ? "↑" : "↓")")

    # Тангаж
    tang = plot([x_circle, (cosd(-ai) .* x)], [y_circle, (sind(-ai) .* x)], 
        linewidth=3, color=:black, framestyle=:none, 
        title="Отклонение: $(ai)°")
    
    # Дрон
    sx,sy = size(drone_img)  3;
    mini_drone = imresize( drone_img, sx, sy );
    rotated_array = channelview(Gray.(imrotate(mini_drone, π*(ai+90)/ 180, fillvalue=oneunit(eltype(mini_drone)), axes(mini_drone))));
    
    dron = plot(framestyle=:none, grid=false, title = "Время: $(t[i])sec")
    # Отображаем повернутое изображение дрона
    heatmap!(
        1:size(rotated_array, 2), 1:size(rotated_array, 1),
        permutedims(rotated_array, (2, 1)),
        colorbar=false, c=:grays
    )
    Tng_Dr = plot(dron, tang, layout = grid(2, 1, heights=[0.8, 0.2]))
    grup = plot(Tng_Dr, h_plt, layout= grid(1, 2, width = [0.75, 0.25]), legend=false)
end
[ Info: Saved animation to /user/start/examples/image_processing/dron/tmp.gif
Out[0]:
No description has been provided for this image

Conclusion

As we can observe based on the results of GIF, we get a fairly informative representation of the data over time. This approach can be used quite often, especially when describing the behaviour of a real physical object.