Engee 文档
Notebook

模拟无人机飞越3D景观

所呈现的Julia代码实现了无人飞行器(UAV)在生成的3D景观上飞行的模拟。 该计划包括几个关键阶段。

  1. 地形生成使用三角函数和随机噪声创建逼真的地形。
  2. 基于高度、速度和障碍物检测限的无人机运动仿真。
  3. 2d和3D中的轨迹的可视化,以及基于检测到的障碍物的飞行动画。

该代码演示了Julia中数值方法、线性代数和交互式图形的使用,这使得它可用于自主导航、机器人和地形分析任务。

辅助图书馆

添加辅助对象和库。

LinearAlgebra连接线性代数运算(矩阵,向量,分解,规范等)的内置库。).

*plotlyjs()*激活PlotlyJS后端进行交互式可视化。

In [ ]:
using LinearAlgebra
plotlyjs()
Out[0]:
Plots.PlotlyJSBackend()

三维景观生成

**功能 generate_landscape**生成指定尺寸的3d地形(width_m×length_m)并将其渲染为交互式表面。

  1. 该函数创建一个坐标网格:x和y是从0到width_m和length_m的线性范围,增量为1米。
  2. 接下来,她填充高度(z)-使用正弦和余弦的组合来创建丘陵表面。
  3. 并且还添加了随机噪声(rand())以获得真实感。
  4. 此外,该函数确定无人机的随机起点和终点。 (绿色-开始,红色-结束)

关键参数
/参数/类型/值/描述|
|---------------|--------------------|-----------------------------------|
| width_m | Int /景观的宽度(米)。 |
| length_m | Int /景观的长度(米)。 |
| c=:terrain | Symbol /浮雕的彩色地图。 |
| start/finish| Vector{Float64} /坐标[x,y,z]。 |

In [ ]:
function generate_landscape(width_m, length_m)
    x = 0:1:width_m
    y = 0:1:length_m

    z = [10(sin(xi / 15) + cos(yi / 15)) + 5rand() + 10 for xi in x, yi in y]
    z = reverse(z, dims=(1, 2))

    random_yi_start = rand(1:length(y))
    random_yi_finish = rand(1:length(y))
    xi_start = 10
    xi_finish = length(x)-10
    start = [x[xi_start], y[random_yi_start], z[xi_start, random_yi_start]]
    finish = [x[xi_finish], y[random_yi_finish], z[xi_finish, random_yi_finish]]

    plt = surface(x, y, z', c=:terrain, xlabel="X (м)", ylabel="Y (м)", zlabel="Z (м)", title="3D ландшафт", legend=false)
    scatter!(plt, [start[1]], [start[2]], [start[3]+3], marker=(:circle), color=:green)
    scatter!(plt, [finish[1]], [finish[2]], [finish[3]+3], marker=(:circle), color=:red)

    display(plt)
    return x, y, z, start, finish
end

landscape = generate_landscape(100, 100);

无人机行为模拟

仿真中无人机行为的算法

1. 运动的基本逻辑

无人机正在从起点start)到终点线finish)沿着直线轨迹,观察限制:
-速度:无人机移动固定距离(speed)每步。
-高度:保持至少高度 min_height 高于地形而不是更高 max_height.
-边界修正:不会飞出景观(clamp).

2. 障碍物探测

无人机从预设距离扫描**视野(fov)**45°的空间(view_distance):
-检查视野中的点(12束)。
-如果障碍物的高度(obstacle_height)以碰撞威胁(obstacle_height + min_height > текущая высота),将其添加到列表中 visible_obstacles.

3. 避开障碍物
当检测到障碍物时,有以下选项。
-选项1(50%的机会):侧移(左/右 speed).
-选项2(50%几率):超过障碍物的最大高度+ min_height + 1.0.

4. 登船服务

到达终点线后
-平稳下降10步到终点浮雕的高度。

5. 可视化
-图1:2d轨迹(XY)与开始(绿色)和完成(红色)标记。
-图2:高度(Z)的逐步变化。

关键参数
/参数/值/描述|
|----------|----------|----------|
| min_height |-5米/地形以上的最低高度|
| max_height |5米|最大飞行高度|
| speed |1米/步/移动速度|
| fov_angle |45°/探测障碍物的视角|
| view_distance |10米|扫描范围|


In [ ]:
function simulate_drone(landscape, min_height, max_height, speed; fov_angle=45.0, view_distance=10.0)
    x, y, z, start, finish = landscape
    drone_path = [copy(start)]
    drone_heights = [start[3]]
    obstacles = [[]]

    current_pos = copy(start)
    for _ in 1:1000
        if norm(current_pos[1:2] .- finish[1:2]) < speed
            break
        end
        direction = normalize(finish[1:2] .- current_pos[1:2])
        next_pos = current_pos[1:2] .+ direction * speed
        next_pos[1] = clamp(next_pos[1], x[1], x[end])
        next_pos[2] = clamp(next_pos[2], y[1], y[end])

        xi = argmin(abs.(x .- next_pos[1]))
        yi = argmin(abs.(y .- next_pos[2]))
        terrain_height = z[xi, yi]
        new_z = clamp(max(terrain_height + min_height, current_pos[3]), -Inf, max_height)

        visible_obstacles = Tuple{Float64, Float64, Float64}[]
        for angle in range(-fov_angle/2, fov_angle/2, length=12)
            rad = deg2rad(angle)
            dir = [direction[1]*cos(rad) - direction[2]*sin(rad),
                   direction[1]*sin(rad) + direction[2]*cos(rad)]
            check_pos = next_pos .+ dir * view_distance
            xi_check = argmin(abs.(x .- check_pos[1]))
            yi_check = argmin(abs.(y .- check_pos[2]))

            if 1  xi_check  size(z, 1) && 1  yi_check  size(z, 2)
                obstacle_height = z[xi_check, yi_check]
                if obstacle_height + min_height > new_z
                    push!(visible_obstacles, (x[xi_check], y[yi_check], obstacle_height))
                end
            end
        end

        if !isempty(visible_obstacles)
            max_obstacle = maximum(obs[3] for obs in visible_obstacles)
            if max_obstacle + min_height > new_z
                if rand() < 0.5
                    next_pos[1] = clamp(next_pos[1] + rand([-1.0, 1.0]) * speed, x[1], x[end])
                else
                    new_z = max_obstacle + min_height + 1.0
                end
            end
        end

        current_pos = [next_pos[1], next_pos[2], new_z]
        push!(drone_path, copy(current_pos))
        push!(drone_heights, new_z)
        push!(obstacles, visible_obstacles)
    end

    xi_end = argmin(abs.(x .- finish[1]))
    yi_end = argmin(abs.(y .- finish[2]))
    final_ground = z[xi_end, yi_end]

    for _ in 1:10
        new_z = drone_path[end][3] - (drone_path[end][3] - final_ground) / 10
        push!(drone_path, [finish[1], finish[2], new_z])
        push!(drone_heights, new_z)
        push!(obstacles, [])
    end

    println("Время полёта дрона: $(length(drone_path)) шагов")
    return drone_path, drone_heights, obstacles, start, finish
end

speed = 1
drone_path, drone_heights, obstacles, start, finish = simulate_drone(landscape, -5, 5, speed)

path_x = [p[1] for p in drone_path]
path_y = [p[2] for p in drone_path]
path_z = [p[3] for p in drone_path]
t = 1:length(drone_path)

plt1 = plot(path_x, path_y, lw=2, c=:blue, xlabel="X (м)", ylabel="Y (м)", title="Путь дрона", legend=false)
scatter!(plt1, [path_x[1]], [path_y[1]], marker=:circle, markersize=8, color=:green)
scatter!(plt1, [path_x[end]], [path_y[end]], marker=:circle, markersize=8, color=:red)

plt2 = plot(t, path_z, lw=2, c=:purple, xlabel="Шаги", ylabel="Высота (м)", title="Высоты дрона", legend=false)
scatter!(plt2, [t[1]], [path_z[1]], marker=:circle, markersize=8, color=:green)
scatter!(plt2, [t[end]], [path_z[end]], marker=:circle, markersize=8, color=:red)

plot(plt1, plt2, layout=(1, 2), size=(1000, 400))
Время полёта дрона: 109 шагов
Out[0]:

3. 无人机飞行的可视化

无人机飞行可视化算法

1. 设置图形
-后端:使用中 gr() 供高性能渲染。
-帧速率:默认 fps=10 (它由参数调节)。

2. 数据准备
-景观:划分为坐标 x, y 和高度 z.
-优化:字典被创建 xidx, yidx 以在景观网格中快速搜索无人机坐标索引。

3. 基本图表
-3d表面(base_surface):
-配色方案 :terrain.
-开始(绿色)和完成标记(红色)。
-2D地图(base_2d):
-轮廓浮雕图(contour!)具有透明度 alpha=0.3.
-起点和终点。

4. 飞行动画

对于每个帧(i-路径的第1步):

  1. 3D可视化:
    -当前无人机位置(红点),
    -动态边框(xlims!, ylims!)专注于无人机周围的区域,
    -一个高度高于浮雕的标头和一个箭头(↑/↓),表示高度增加/减少。
  2. 2D可视化:
    -行进路径的逐步显示(蓝线),
    -当前位置(红点)。
  3. 障碍:
    -标有黄色十字架(:xcross)在3D和2D中,如果在当前步骤检测到。

5. 组装动画
-帧间隔生成 1/speed (但至少1步),
-生成的动画保存为指定的GIF fps.

关键参数
/参数/值/类型/描述|
|----------|--------------|----------|
| fps | 10 (默认)/动画帧速率(帧/秒)|
| speed | 1 (m/step)|无人机的速度影响动画的流畅度|
| layout | @layout([a{0.7w} b]) |3D和2D图形的尺寸比例(70%/30%)|

In [ ]:
gr()

function visualize_flight(landscape, drone_path, drone_heights, obstacles, speed, start, finish; fps=10)
    x, y, z = landscape

    xidx = Dict(px => argmin(abs.(x .- px)) for px in unique(p[1] for p in drone_path))
    yidx = Dict(py => argmin(abs.(y .- py)) for py in unique(p[2] for p in drone_path))

    base_surface = surface(x, y, z', c=:terrain, legend=false, aspect_ratio=:auto, axis=false)
    base_2d = plot(aspect_ratio=1, legend=false, axis=false)
    contour!(base_2d, x, y, z', c=:terrain, alpha=0.3)
    scatter!(base_surface, [start[1]], [start[2]], [start[3]], marker=:circle, markercolor=:green, label=false)
    scatter!(base_surface, [finish[1]], [finish[2]], [z[end, end]], marker=:circle, markercolor=:red, label=false)
    scatter!(base_2d, [start[1]], [start[2]], marker=:circle, markercolor=:green)
    scatter!(base_2d, [finish[1]], [finish[2]], marker=:circle, markercolor=:red)

    anim = @animate for i in 1:length(drone_path)
        plt1 = deepcopy(base_surface)
        plt2 = deepcopy(base_2d)

        px, py, pz = drone_path[i]
        scatter!(plt1, [px], [py], [pz], markersize=5, markercolor=:red, marker=:circle)
        xlims!(plt1, px - 10, px + 10)
        ylims!(plt1, py - 10, py + 10)

        xi, yi = xidx[px], yidx[py]
        height_above = pz - z[xi, yi]
        arrow = i == 1 ? "↑" : (height_above > (drone_path[i - 1][3] - z[xidx[drone_path[i - 1][1]], yidx[drone_path[i - 1][2]]]) ? "↑" : "↓")
        title!(plt1, "Высота дрона: $(floor(height_above)) м $arrow")

        if i > 1
            path = drone_path[1:i]
            plot!(plt2, [p[1] for p in path], [p[2] for p in path], linewidth=2, linecolor=:blue)
        end

        scatter!(plt2, [px], [py], markersize=5, markercolor=:red)

        if !isempty(obstacles[i])
            obs_x = [o[1] for o in obstacles[i]]
            obs_y = [o[2] for o in obstacles[i]]
            obs_z = [o[3] for o in obstacles[i]]
            scatter!(plt1, obs_x, obs_y, obs_z, markersize=3, markercolor=:yellow, marker=:xcross)
            scatter!(plt2, obs_x, obs_y, markersize=3, markercolor=:yellow, marker=:xcross)
        end

        plot(plt1, plt2, layout = @layout([a{0.7w} b]), size=(900, 300))
    end every max(1, round(Int, 1/speed))

    gif(anim, fps=fps)
end

visualize_flight(landscape, drone_path, drone_heights, obstacles, speed, start, finish; fps=5)
[ Info: Saved animation to /user/start/examples/codegen/tmp.gif
Out[0]:
No description has been provided for this image

结论

此代码是模拟无人机在随机地形上飞行的完整解决方案。 让我们列出它的主要特点。

  1. 参数的灵活性:可以调整速度,高度,视角和障碍物检测范围。
  2. 逼真的可视化:3D图形和动画用于直观地表示轨迹。
  3. 避障算法:无人机动态调整路线,避免碰撞。

该代码可以作为更复杂的模拟的基础,例如城市环境中的自主飞行或地形映射。 进一步的开发可以包括集成机器学习以优化路线或处理来自真实传感器的数据。