Визуализация показаний приборов дрона
В данном примере реализованы алгоритмы визуализации
данных о полёте, записанных с датчиков дрона.
Цель данной демонстрации – показать различные возможности
отображения данных, включая их привязку ко времени.
Начнём с чтения записанных данных из файла CSV.
using CSV
# Читаем данные из файла data.csv
df_read = CSV.read("$(@__DIR__)/data_drone.csv", DataFrame)
# Проверка первых строк
first(df_read, 5)
Как мы можем видеть, таблица содержит 3 поля, временные отсчёты, значения высоты и угол наклона дрона относительно горизонта.
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)
Опираясь на визализацию значений датчиков, мы
видим, что дрон постипенно набирал высоту и
изменял угол наклона, облетая какое-то
препятствие. Также мы видим колебания отклонения
относительно горизонта, которые скорее всего связаны
с тем, что дрон летал в ветренную погоду.
Далее объявим статические переменные, которые не требуют обновления в цикле.
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")
Теперь перейдём к самому циклу визуализации данных. Его можно условно разделить на три части.
- Отображение высоты. Для каждого момента времени строится график высоты в виде красной точки.
Ограничения по осям устанавливаются так, чтобы показать область вокруг текущего времени ±10 секунд.
Заголовок графика показывает текущее значение высоты и стрелку вверх/вниз в зависимости от того, увеличивается высота или уменьшается. - График тангажа. График тангажа показывает угол отклонения дрона относительно горизонта.
Используются функции cosd и sind для построения линии угла наклона.
Заголовок содержит значение угла тангажа в градусах. - Поворот изображения дрона и визуализация, Изображение дрона поворачивается на определенный угол (значение тангажа + 90 градусов).
Функция channelview преобразует изображение в вид, удобный для дальнейшей обработки.
Используется маска для удаления черных пикселей.
В итоги все три графика собираются в единный кадр который и формирует кадры GIF.
@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
Вывод
Как мы можем наблюдать, опираясь на результаты GIF,
мы получаем достаточно информативное представление данных
во времени. Такой подход можно применять давольно
часто, особенно в случаях описания поведения реального физического объекта.