用强化学习SAC算法帮我实现航向控制
好的,我将用中文为你详细解读如何使用 Soft Actor-Critic (SAC) 强化学习算法来实现船舶或无人机的航向控制(Heading Control)。这是一个非常经典的连续控制问题。
目标:让船舶(或无人机)的航向角 ψ(psi,单位:度或弧度)跟踪一个给定的参考航向角 ψ_ref。
状态空间(State):
ψ_error = ψ_ref - ψ(航向误差,范围:[-180°, 180°])r(偏航角速度 yaw rate,单位:°/s 或 rad/s)δ_prev(帮助抑制震荡)动作空间(Action):
δ(舵角或滚转角,连续值,范围:[-δ_max, δ_max],如 [-35°, 35°])奖励函数(Reward):
reward = -w1 * abs(psi_error) - w2 * abs(delta) - w3 * abs(r)
其中 w1, w2, w3 是权重系数(如 w1=1.0, w2=0.1, w3=0.01)。我们使用一个简化的 Nomoto 模型(一阶非线性船舶操纵模型):
class ShipEnv(gym.Env):
def __init__(self):
super().__init__()
# 状态空间:航向误差、偏航角速度、上一时刻舵角
self.observation_space = spaces.Box(low=-np.inf, high=np.inf, shape=(3,))
# 动作空间:舵角(连续)
self.action_space = spaces.Box(low=-np.radians(35), high=np.radians(35), shape=(1,))
# Nomoto模型参数
self.K = 0.1 # 增益
self.T = 10.0 # 时间常数
self.dt = 0.1 # 仿真步长
self.psi = 0.0 # 初始航向角
self.r = 0.0 # 初始偏航角速度
self.delta_prev = 0.0
def reset(self, psi_ref=0.0):
self.psi_ref = psi_ref
self.psi = 0.0
self.r = 0.0
self.delta_prev = 0.0
return np.array([self._normalize_angle(self.psi_ref - self.psi), self.r, self.delta_prev])
def step(self, delta):
# 执行舵角限制
delta = np.clip(delta, self.action_space.low[0], self.action_space.high[0])
# Nomoto模型更新
self.r += (self.K * delta - self.r) / self.T * self.dt
self.psi += self.r * self.dt
# 航向误差
psi_error = self._normalize_angle(self.psi_ref - self.psi)
# 奖励函数
reward = -abs(psi_error) - 0.1 * abs(delta) - 0.01 * abs(self.r)
# 下一状态
obs = np.array([psi_error, self.r, delta])
done = False # 可设置最大步数
self.delta_prev = delta
return obs, reward, done, {}
def _normalize_angle(self, angle):
# 将角度归一化到 [-pi, pi]
return (angle + np.pi) % (2 * np.pi) - np.pi
SAC 是一个 Actor-Critic 架构的 off-policy 算法,适合连续动作空间。我们使用 Stable-Baselines3 库(已集成 SAC)。
pip install stable-baselines3[extra] gym
from stable_baselines3 import SAC
from stable_baselines3.common.vec_env import DummyVecEnv
# 创建环境
env = DummyVecEnv([lambda: ShipEnv()])
# 创建 SAC 模型
model = SAC(
"MlpPolicy",
env,
verbose=1,
learning_rate=3e-4,
buffer_size=100000,
learning_starts=1000,
batch_size=256,
gamma=0.99,
tau=0.005,
train_freq=1,
gradient_steps=1,
policy_kwargs=dict(net_arch=[256, 256])
)
# 训练
model.learn(total_timesteps=100000)
# 保存模型
model.save("sac_heading_control")
import matplotlib.pyplot as plt
env = ShipEnv()
obs = env.reset(psi_ref=np.radians(30)) # 目标航向30°
model = SAC.load("sac_heading_control")
psi_history = []
delta_history = []
for _ in range(500):
action, _ = model.predict(obs, deterministic=True)
obs, reward, done, _ = env.step(action)
psi_history.append(np.degrees(env.psi))
delta_history.append(np.degrees(action[0]))
plt.subplot(2,1,1)
plt.plot(psi_history, label='实际航向')
plt.axhline(y=np.degrees(env.psi_ref), color='r', linestyle='--', label='目标航向')
plt.legend()
plt.subplot(2,1,2)
plt.plot(delta_history, label='舵角')
plt.legend()
plt.show()
状态扩展:
∫ψ_error dt 消除稳态偏差。奖励调参:
psi_error^2)。-w4*(delta - delta_prev)^2。仿真真实性:
SAC 非常适合解决航向控制的连续动作问题:
你可以根据实际需求调整模型复杂度,甚至迁移到 Gazebo、ROS 等仿真环境中进行更真实的测试。需要更复杂的模型或代码细节吗?