在快速发展的物流与自主系统领域,优化无人机在三维空间中的飞行路径至关重要。无论是在城市环境中导航还是在复杂地形中穿行,确保高效、安全且节能的航线规划能够显著提升运营效率。本文将深入探讨一种创新方法,结合强化学习(Reinforcement Learning, RL)与遗传算法(Genetic Algorithms, GA),在自定义的3D环境中优化无人机飞行路径。我们将详细解析实现细节、RL与GA的协同作用,以及如何通过Plotly实现令人惊叹的3D可视化效果。
项目概述
本项目旨在通过结合强化学习(RL)与遗传算法(GA),在自定义的3D环境中优化无人机的飞行路径。具体来说:
- 环境定义(
low_altitude_env.py
):创建一个模拟无人机在3D网格中飞行的环境,考虑风速、风向、动态障碍物、电池容量等因素。 - 训练与优化(
dqn_ga.py
):使用PPO算法训练无人机的决策模型,并利用遗传算法进行多目标优化,平衡飞行时间、能耗与风险。 - 可视化展示(
main.py
):通过Plotly实现交互式3D可视化,直观展示无人机的飞行路径与环境中的动态障碍物。
这种模块化的设计不仅确保了代码的清晰与可维护性,还为后续的功能扩展提供了便利。
自定义3D环境:LowAltitudeLogisticsEnv
项目的核心是**LowAltitudeLogisticsEnv
**,一个基于OpenAI Gym构建的自定义环境。该环境模拟无人机在3D网格中的飞行,考虑多种环境因素和约束条件。
主要功能
- 状态表示:无人机的状态由12维向量表示,包括位置
(x, y, z)
、速度(vx, vy, vz)
、风向与风速(wind_dir, wind_speed)
、目标位置(goal_x, goal_y, goal_z)
以及剩余电量battery
。 - 动作空间:支持连续动作空间
[ax, ay, az]
(加速度)或离散动作空间(预定义的方向)。 - 动态障碍物:环境中障碍物根据自身速度向量动态移动,增加飞行路径规划的复杂性。
- 奖励机制:通过最小化时间、能耗与风险来奖励无人机,同时为到达目标给予额外奖励,为电量耗尽或高风险行为给予惩罚。
环境实现
以下是low_altitude_env.py
的完整实现:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文件: low_altitude_env.py
主要功能:
1. 定义升级版低空物流环境 LowAltitudeLogisticsEnv
2. 支持离散或连续动作(可通过 continuous_action 切换)
3. 模拟飞行高度限制、风向风速、动态障碍物、电量消耗等
"""
import gym
import numpy as np
import random
from gym import spaces
class LowAltitudeLogisticsEnv(gym.Env):
"""
升级版低空物流环境:
- 状态 (state): [x, y, z, vx, vy, vz, wind_dir, wind_speed, goal_x, goal_y, goal_z, battery]
- 动作 (action):
* 连续空间 [ax, ay, az] 在 [-1,1] 范围内(若 continuous_action=True)
* 或 8离散方向/动作(若 continuous_action=False)
- 动态障碍物:obstacle_list 中包含 (ox, oy, oz, ovx, ovy, ovz),每步更新位置
- 更多约束:如飞行高度限制 [0, max_alt]
"""
def __init__(self,
grid_size=10,
max_alt=10.0,
max_episode_steps=50,
alpha=1.0,
beta=0.1,
gamma=0.5,
obstacle_list=None,
battery_capacity=100.0,
continuous_action=False):
super(LowAltitudeLogisticsEnv, self).__init__()
self.grid_size = grid_size # x-y 范围
self.max_alt = max_alt # z 高度范围
self.max_episode_steps = max_episode_steps
self.alpha = alpha
self.beta = beta
self.gamma = gamma
self.battery_capacity = battery_capacity
self.continuous_action = continuous_action # 是否使用连续动作
# 初始化障碍物:每个障碍物为 (ox, oy, oz, ovx, ovy, ovz),静态障碍物的速度为0
if obstacle_list is None:
self.obstacle_list = [(grid_size/2, grid_size/2, 2.0, 0, 0, 0)]
else:
self.obstacle_list = obstacle_list
# 动作空间定义
if self.continuous_action:
# 连续动作空间: [ax, ay, az],范围 [-1, 1]
self.action_space = spaces.Box(low=-1.0, high=1.0, shape=(3,), dtype=np.float32)
else:
# 离散动作空间 (示例:8个方向)
self.action_space = spaces.Discrete(8)
# 状态空间定义
low_state = np.array([
0, 0, 0, # x, y, z
-5, -5, -5, # vx, vy, vz
-180, # wind_dir
0, # wind_speed
0, 0, 0, # goal_x, goal_y, goal_z
0 # battery
], dtype=np.float32)
high_state = np.array([
grid_size, grid_size, max_alt,
5, 5, 5,
180,
20,
grid_size, grid_size, max_alt,
battery_capacity
], dtype=np.float32)
self.observation_space = spaces.Box(low=low_state, high=high_state, dtype=np.float32)
self.steps = 0
self.state = None
self.reset()
def step(self, action):
"""
环境交互逻辑:
1. 根据动作更新 (vx, vy, vz)
2. 结合风速风向,计算新的 (x, y, z)
3. 判断与障碍物距离、计算风险
4. 计算奖励 + 检查 done
"""
x, y, z, vx, vy, vz, wind_dir, wind_speed, goal_x, goal_y, goal_z, battery = self.state
# 1) 动作处理
if self.continuous_action:
# action = [ax, ay, az]
ax, ay, az = action
new_vx = vx + ax * 0.1
new_vy = vy + ay * 0.1
new_vz = vz + az * 0.1
else:
# 离散动作(示例:8个方向)
directions = [
(1, 0, 0), # +x
(-1, 0, 0), # -x
(0, 1, 0), # +y
(0, -1, 0), # -y
(0, 0, 1), # +z
(0, 0, -1), # -z
(1, 1, 0), # x+y
(-1, 1, 0) # -x+y
]
dx, dy, dz = directions[action]
new_vx, new_vy, new_vz = dx, dy, dz
# 2) 风的影响
wind_rad = np.radians(wind_dir)
wind_fx = wind_speed * np.cos(wind_rad) * 0.1
wind_fy = wind_speed * np.sin(wind_rad) * 0.1
# wind_fz 可自行拓展,目前示例只考虑水平方向
# 3) 更新坐标
new_x = x + new_vx + wind_fx
new_y = y + new_vy + wind_fy
new_z = z + new_vz
# 4) 约束
new_x = np.clip(new_x, 0, self.grid_size)
new_y = np.clip(new_y, 0, self.grid_size)
new_z = np.clip(new_z, 0, self.max_alt)
# 5) 计算时间&能耗
move_dist = np.sqrt((new_x - x)**2 + (new_y - y)**2 + (new_z - z)**2)
time_cost = move_dist
energy_cost = move_dist * (1 + 0.1 * wind_speed)
new_battery = max(battery - energy_cost, 0)
# 6) 更新障碍物 (动态)
updated_obstacles = []
risk = 0.0
for obs in self.obstacle_list:
ox, oy, oz, ovx, ovy, ovz = obs
updated_ox = ox + ovx * 0.1
updated_oy = oy + ovy * 0.1
updated_oz