% 随机种子 rng(42); %% ================= 仿真参数 ================= sim.dt = 0.2; % s sim.T = 200; % 迭代步数 sim.Hp = 12; % 预测域 sim.Hc = 3; % 控制域 sim.state_dim = 6; % [x y z vx vy vz] sim.input_dim = 3; % [ax ay az] sim.vmax = 4.0; % m/s 速度上限 sim.umin = -2.0*ones(3,1); % m/s^2 sim.umax = 2.0*ones(3,1); % 软约束 & 求解器 sim.safety_margin = 0.6; % 安全裕度 sim.obs_stride = 2; % 避障约束步长(加速) sim.casadi.W_slack = 50.0; % slack 权重 sim.casadi.cache_version = 1; % 调整以强制重建模型 sim.casadi.ipopts = struct( ... 'print_time', false, ... 'ipopt', struct( ... 'print_level', 0, ... 'max_iter', 200, ... 'max_cpu_time', 0.2, ... % 单次求解 CPU 上限(秒) 'tol', 1e-3, ... 'constr_viol_tol', 1e-3, ... 'acceptable_tol', 5e-3, ... 'acceptable_obj_change_tol', 5e-3, ... 'warm_start_init_point', 'yes' ... ) ... ); % 事件触发参数(通信) sim.trigger.threshold = 0.6; % 误差范数阈值(相对尺度) sim.trigger.dwell = 3; % 最小驻留步 sim.trigger.near_obst_gain = 0.5; % 近障降低阈值系数 sim.trigger.stall_speed = 0.1; % 低速保护(m/s) % 代价权重(论文中可给出) sim.W_track = blkdiag(2.0*eye(3), 0.2*eye(3)); % 位置>速度 sim.W_u = 0.05*eye(3); sim.W_du = 0.05*eye(3); % 领航速度平滑,跟随偏置 sim.leader_speed = 2.5; % 目标点速度(m/s) %% =============== 路径 & 环境 =============== addpath_if_exist(cfg.casadi_path); % 工作空间(立方体) ws.min = [0 0 0]'; ws.max = [30 18 12]'; % 起点在 (min) 邻域,终点在 (max) 邻域(对角) N = 5; % 1 领航 + 4 跟随 [starts, goals, offsets] = make_diagonal_layout(ws, N); % 障碍(静态若干 + 1 个缓慢动态) [obst, obst_dyn] = make_obstacles(); %% =============== 参考轨迹(领航) =============== leader_traj = make_leader_reference(starts(:,1), goals(:,1), sim); %% =============== 初始化 =============== states = zeros(sim.state_dim, N, sim.T+1); inputs = zeros(sim.input_dim, N, sim.T); states(:, :, 1) = init_states(starts); % 事件触发状态 event.last_tx_k = -1e6*ones(1,N); event.savings_solves = 0; % 避免求解的次数 comms = zeros(1,N); % 通信次数 % 指标累计 metrics.Evel = zeros(1, sim.T); metrics.Eform= zeros(1, sim.T); metrics.Eu = zeros(1, sim.T); metrics.Esafe= zeros(1, sim.T); %% =============== 双场景对比 =============== S_sync = run_dmpc_scenario(states(:,:,1), leader_traj, offsets, obst, obst_dyn, sim, false); S_et = run_dmpc_scenario(states(:,:,1), leader_traj, offsets, obst, obst_dyn, sim, true ); %% =============== 作图/导出 =============== export_figures_and_tables(S_sync, S_et, ws, outdir); fprintf('[Savings] Solves: %.1f%% | Comms: %.1f%%\n', 100*S_et.savings_solves, 100*S_et.savings_comms); end %% ================== 核心:运行单场景 ================== function S = run_dmpc_scenario(states0, leader_traj, offsets, obst, obst_dyn, sim, use_event) import casadi.* N = size(states0,2); T = sim.T; % 结果缓存 states = zeros(sim.state_dim, N, T+1); inputs = zeros(sim.input_dim, N, T); flags = zeros(1,T); % 1: 使用了求解器,0: 复用了上一次输入 states(:,:,1) = states0; % 通信与事件 last_tx_k = -1e6*ones(1,N); comms = zeros(1,N); % 初值 u0 u_last = zeros(sim.input_dim, N); % 障碍缓冲(加速):提前计算每个 k 的 OC/RAD 序列 [OC_all, RAD_all] = precompute_obstacles_over_horizon(obst, obst_dyn, sim); for k=1:T % 近障检测用于事件阈值调节 near_obst = false(1,N); for i=1:N near_obst(i) = is_near_obstacle(states(1:3,i,k), obst, obst_dyn, sim); end for i=1:N % 构造参考(含编队偏置) ref_now = make_reference(leader_traj, offsets(:,i), k, sim); % 事件触发:决定是否重算优化或复用 u 上次 do_solve = true; % 默认要求解 if use_event err = states(:,i,k) - ref_now(:,1); eps = sim.trigger.threshold * (1 + 0.0*norm(ref_now(1:3,1))); %#ok<*NASGU> if near_obst(i); eps = eps * sim.trigger.near_obst_gain; end if k - last_tx_k(i) < sim.trigger.dwell do_solve = false; % 驻留期内不给发 elseif norm(err(1:3)) < eps && norm(states(4:6,i,k)) > sim.trigger.stall_speed do_solve = false; % 误差小且未停滞