
简介面向希望入门或进阶多智能体强化学习与卫星调度交叉方向的学习者尤其适合作为计算机、自动化、航天等相关专业学生的毕设选题、课程设计、大作业或工程实训项目。项目基于 Python 与 STK11 搭建核心流程包括通过任务类在实例化时随机生成经纬度等信息批量创建大规模算例并存入数据表读取任务后连接已打开的 STK 11 场景计算每个任务的可访问时段并保存结果最终形成从数据生成、访问计算到多智能体强化学习调度的完整实验链路。压缩包共 199 个文件约 68.14MB主要包含 Python 源码、CSV 数据、STK 场景文件、PyTorch 模型权重、PNG 图表和 Markdown 说明文档同时附带训练好的模型参数与实验结果图表目录结构清晰便于对照学习、复现实验和二次开发。目前已有 1105 人学习下载能够帮助读者深入理解卫星调度问题建模、STK 二次开发以及多智能体强化学习训练评估的关键流程。 卫星调度这事放在以前基本是运筹优化算法的主场流程固化、计算量大一旦任务动态插入或者卫星状态异常重新排一遍代价极高。我最近基于 Python 和 STK 11 搭了一套多智能体强化学习实验环境让每颗卫星作为独立智能体通过集中训练、分布式执行的方式自主学习调度策略跑了小规模对地观测场景效果比传统贪心基线有明显提升。这篇就把整个实验的建模思路、工具链配置、代码实现和踩坑记录完整放出来给同样在做航天调度、组合优化或者多智能体强化学习的同学一个可参考的工程模板。1. 项目概述1.1 核心需求解析做卫星调度实验第一步得搞明白自己在解决什么。就拿对地观测卫星来说星上载荷只有一个相机目标却有一堆每颗卫星飞过不同目标上空的时间窗口还不一样这就成了典型的时间窗口约束下的任务分配问题。但实际约束远不止时间窗口。还得考虑存储容量——拍完的照片不能马上传下来得攒着电能约束——姿态机动、成像、数传都要耗电卫星过阴影区没法充电还有侧摆角度限制不是你想拍哪个目标就能拍哪个的。传统方法比如遗传算法、模拟退火求解效果还行但环境一变就得重新算实时性很差。我搭这套实验的目的就是测试多智能体强化学习在这种动态场景下能不能做到快速、自主的调度决策。1.2 为什么选择多智能体强化学习这里有个很实际的考量如果你用集中式调度所有卫星的状态、任务信息都汇总到一个中心节点计算再分发指令。这在卫星数量少的时候可行但星群规模一大通信延迟、计算瓶颈全都出来了。多智能体强化学习的思路不同。每颗卫星就是一个智能体它只依赖自己的局部观测做决策但训练的时候可以共享全局信息来学习。这个特性太契合卫星调度了——实际场景中卫星跟地面站通信是间歇性的不可能每时每刻都跟中心节点同步但在地面训练阶段我们却有充足的计算资源和全局信息可以用。我选择独立 PPOIPPO作为基线算法再跟 QMIX 做对比。原因稍后细说先记住一个结论在多智能体场景里不要一上来就上最复杂的算法先把独立学习跑通作为 baseline再逐步引入集中训练分布式执行框架。1.3 STK 11 在项目中的角色STKSystems Tool Kit是航天领域做轨道动力学仿真的标准工具。我们这里要利用的是它的高保真轨道预报和可见性计算能力——卫星什么时候飞过目标上空、持续多久、太阳光照条件如何这些数据靠我们手写公式去算精度和效率都不行。STK 给出精确结果我们把它作为环境状态输入给智能体。整个实验的架构可以概括为STK 负责提供真实可靠的轨道和窗口数据Python 负责智能体训练和决策逻辑两者通过 STK 自带的 Python 接口通信。 STK 11 虽然对 Python 的支持不如新版本 STK 12 那样原生但通过 COM 接口或者 Connect 命令仍然能顺畅工作后面我会写清楚关键的连接方法。2. 技术选型与原理详解2.1 核心工具对比实验选型阶段我对比了几种工具组合方式。第一种是纯 Python 的轨道计算库比如 skyfield、poliastro。优点是完全免费、可控性强适合快速原型验证。缺点是轨道动力学模型相对简化J2 摄动、大气阻力这些高阶效应要么没有、要么需要自己实现对于卫星调度这种对时间窗口精度要求高的场景误差可能会影响结论。第二种就是 STK 方案。高精度轨道预报、可见窗口分析、场景可视化一应俱全而且是航天领域的标准工具实验结果更容易说服同行。缺点是需要许可证且跟 Python 交互需要额外配置。第三种方案比较取巧——先用 STK 把所有场景的可见窗口批量计算好导出 CSV 或 JSON 格式的数据文件训练时直接读取不实时调用 STK。 这也是我最后采用的方式兼顾了精度和训练效率。2.2 强化学习算法选型算法选型这块我重点看了三个方向。独立 PPOIPPO简单直接每个智能体各自维护一套策略网络和 critic 网络互相独立更新不交换任何梯度信息。分布式执行是天然的训练时也不需要额外的通信机制。缺点是在协同性强的任务里智能体之间无法相互协调可能陷入次优。QMIX 属于值分解方法有一个超网络把全局 Q 值与各智能体的个体 Q 值联系起来训练时用全局奖励更新执行时每个智能体只根据自己的局部 Q 值做 argmax 决策。这正好契合了卫星调度“集中训练、分布式执行”的理念。MADDPG 适用于连续动作空间。但卫星调度中的动作本质是离散的选择下一个观测目标强行连续化反而增加复杂度所以我在当前版本没有采用但在规划卫星姿态控制时会有用武之地。最终我的方案是IPPO 作为快速基线和 QMIX 作为主要对比算法。实验结果显示 QMIX 在任务完成率上比独立 PPO 高出七八个百分点关键是它学会了多颗卫星之间默契的任务分配而不是各自闷头抢目标。3. 环境搭建与数据准备3.1 STK 场景构建场景构建是第一步。我在 STK 11 中创建了一个名为leo_scheduling的场景时间跨度为 24 小时起点设为某天的 00:00:00UTCG。卫星方面我建了 6 颗太阳同步轨道卫星轨道高度 500 到 600 公里之间升交点赤经均布。这个设计参考了实际遥感星座的做法——多颗卫星在同一轨道面内均匀分布能有效缩短重访周期。每颗卫星上挂载一个传感器半视场角设为 30 度侧摆能力正负 35 度。目标方面在地球表面随机选择 40 个观测目标点集中在中低纬度地区。目标属性包括经纬度、优先级权重1 到 5 之间随机以及最短观测时长要求。建好场景后用 STK 的 Access 计算功能依次计算每颗卫星到每个目标的可访问窗口。这一步在 STK 界面里操作比较慢我直接用 Python 调用 STK 的连接接口自动完成具体代码在 3.2 节给出。3.2 Python 连接与窗口数据提取STK 11 的自动化接口支持多种方式我使用的是 Connect 命令接口。先启动 STK 桌面端然后 Python 端创建连接通过字符串命令与 STK 交互。核心代码思路如下import subprocess import time import numpy as np # 启动STK并创建场景首次需手动打开STK软件 # 假设STK已打开某个场景通过Connect建立TCP连接 import win32com.client stk win32com.client.Dispatch(STK11.Application) root stk.Personality2 scenario root.children.Item(leo_scheduling) # 获取卫星列表 satellites [] for i in range(1, 7): sat_name fLEO_SAT_{i} sat scenario.children.Item(sat_name) satellites.append(sat) # 获取目标列表 targets [] for j in range(1, 41): tgt_name fTGT_{j} tgt scenario.children.Item(tgt_name) targets.append(tgt) # 遍历每对卫星-目标提取访问窗口 access_windows {} for sat in satellites: for tgt in targets: access sat.GetAccessToObject(tgt) access.ComputeAccess() # 获取窗口数量 count access.DataProviders.Item(Access Data).Exec(scenario.StartTime, scenario.StopTime) ...这段代码的关键在于拿到每个卫星到每个目标的访问时间区间。导出的数据样例如下卫星名称目标名称窗口开始时间 (UTCG)窗口结束时间 (UTCG)访问持续时长 (秒)LEO_SAT_1TGT_501 May 2025 03:12:45.0001 May 2025 03:14:10.0085.0LEO_SAT_1TGT_1201 May 2025 04:02:33.0001 May 2025 04:04:02.0089.0...............实际项目里我建议写成 JSON 文件保留更多字段比如相对速度、太阳光照角等信息方便后续扩展状态空间。 我用的核心字段就是卫星编号、目标编号、窗口开始时间、窗口结束时间、目标优先级。3.3 数据预处理与时间片生成窗口数据是连续的但强化学习需要离散的时间步。我把整个任务周期切成固定长度的时间片。这里采用 60 秒为一个决策步长这意味着智能体每隔一分钟做一次决策。为什么是 60 秒因为卫星相对目标的访问窗口平均持续 80 秒左右如果决策步长设太长比如 300 秒可能会错过整个窗口设太短比如 10 秒决策次数暴增训练效率大大降低。经过实际测试60 秒是一个平衡点。每个决策步内环境状态包括当前时间、每颗卫星的位置由轨道预报得到、剩余存储、剩余电量、当前点亮的可见目标集合。可见目标集合就是通过访问窗口数据判断——如果当前时间在某个窗口内且该目标尚未被观测则该目标可见。时间片的生成完全依赖预计算的窗口表我在训练时不再调用 STK只做简单的数组索引和比较运算。这样一次训练迭代的环境交互耗时从分钟级降到了毫秒级。4. 多智能体强化学习建模实现4.1 状态空间设计状态空间的设计直接决定了智能体能学到什么程度。我在实验里把每颗卫星的状态分为三块第一块是自身资源状态包括剩余存储百分比0到100、剩余电量百分比0到100、当前位置在轨道中的相位角。存储和电量是连续的做了归一化处理。第二块是当前可见目标的状态。由于目标数量固定为40个我构建了一个长度为40的向量每个位置表示对应目标当前是否可见1或0。另外还附加各个目标的优先级向量长度40优先级是固定的属性。第三块是历史观测信息记录最近10个决策步内完成观测的目标编号。这块信息虽然简单但对避免重复观测非常有效。如果没有历史信息智能体很容易在多个连续时间步内反复选择同一个目标。整体的状态维度是200卫星自身状态 80目标可见性和优先级 10历史观测 290 维。 对单智能体来说这个维度不算高但6个智能体组合起来的联合状态空间就非常大这也是多智能体强化学习比单智能体困难的原因之一。4.2 动作空间与掩码机制动作空间是离散的智能体在每个决策步选择一个目标进行观测或者选择空闲。所以动作空间大小为 4140个目标 1个空闲动作。这里有个必须注意的问题如果某个目标当前并不可见选择它就是非法动作。我直接采用了动作掩码action masking机制——把非法动作的概率设为0让智能体只能从可见目标里选择。技术上实现很简单# 在策略网络的输出层之后应用掩码 logits policy_net(state) mask torch.tensor(get_mask(visible_targets), dtypetorch.bool) logits logits.masked_fill(~mask, float(-inf)) probs torch.softmax(logits, dim-1)这个掩码机制看起来简单但作用巨大。没有掩码的对照组实验里智能体在初期大量尝试非法动作奖励几乎为零探索效率极低。加了掩码之后收敛速度至少提升了一倍。4.3 奖励函数设计奖励函数是强化学习里最敏感的设计环节卫星调度场景中我设置了四部分奖励。观测奖励是最核心的正向激励。当卫星成功观测到一个目标时获得该目标优先级的分数作为奖励比如优先级为5的目标给5分。这一项直接驱动智能体去完成任务。时间惩罚是负向激励。为了鼓励快速决策、别拖延每执行一个非观测动作包括空闲施加一个小的负奖励比如-0.01。这样可以防止智能体什么都做拖到最后才行动。冲突惩罚处理多颗卫星同时观测同一个目标的情况。实际调度里一个目标只需要被观测一次多星重复观测浪费资源。每当两颗以上卫星在同一决策步指向同一目标涉及冲突的这些动作都扣掉2分。资源超限惩罚是硬约束。卫星存储超过95%或者电量低于20%时施加一个较大的负奖励比如-10。这强制智能体学会在保证资源安全的前提下安排观测任务。最终总奖励是四部分的加权和。权重系数我调了三轮最终确定观测奖励权重1.0时间惩罚权重0.5冲突惩罚权重1.5资源超限权重3.0。资源超限权重最大因为一旦违反约束造成的后果最严重。4.4 网络结构与环境交互网络结构我采用的是比较经典的 Actor-Critic 架构。Actor 网络和 Critic 网络都是三层全连接网络隐藏层维度分别为256和256激活函数用 ReLU。QMIX 中额外增加了一个混合网络接收全局状态作为输入输出权重来混合各智能体的Q值。环境交互的流程是每次环境重置后初始化卫星状态与时间片然后循环决策。每个步骤中环境根据当前时间更新每个目标的可见状态智能体根据状态输出动作环境执行动作并返回奖励和新状态。整个过程用 gymnasium 风格封装方便接入现有的强化学习框架。环境交互中计算量最大的部分是更新可见状态但好在所有窗口数据都是预计算并索引好的每次只是查表所以环境交互速度非常快。一个完整episode24小时每分钟一个决策步总共有 1440 步6个智能体并行交互只需要不到 0.1 秒。5. 实验设计与结果分析5.1 训练配置训练超参数如下表所示超参数数值说明学习率3e-4Adam优化器Batch size512每批次采样的transition数量经验回放池100000按时间顺序存储GAE lambda0.95优势估计折扣折扣因子 gamma0.99长期回报折现PPO clip范围0.2截断阈值每轮更新次数10PPO内循环迭代次数训练总步数2000000约1400个episode训练时间方面GTX 3090 显卡上跑完两百万步大约需要 8 小时。CPU 版大约要慢5倍但也不是完全不能接受赶时间的话可以先跑 CPU 验证逻辑。5.2 核心指标对比评估阶段用以下指标对比算法任务完成率观测成功目标数 / 总目标数、平均完成优先级加权分、资源约束违反率存储或电量超限的episode占比和平均单目标观测能耗。对比了三种方案贪心算法优先选择最早可见窗口内的最高优先级目标不考虑资源状态、IPPO 和 QMIX。实验结果如下算法任务完成率加权分约束违反率单目标能耗贪心基线62.5%168.315.0%高独立PPO74.2%201.78.2%中QMIX81.5%226.93.1%低从数据可以看出QMIX 在任务完成率和资源管理上都优于 IPPO 和贪心算法。有趣的是欺贪心算法有时也能达到较高的完成率但它的能耗和约束违反率显著更高。强化学习学到的策略在很大程度上学会了在资源紧张时主动放弃低优先级目标、选择合适的观测顺序让卫星群的整体收益最大化。5.3 行为分析训练完成后我把 QMIX 策略在场景里回放了一遍观察智能体的行为模式。最直观的发现是QMIX 学会了分工。具体来说在某个时间段内假设目标 A 和 B 几乎同时出现可见窗口且一颗卫星分别访问这两个目标的时间窗口有重叠。独立 PPO 的情况下两颗卫星争抢 AB 反而没人管。QMIX 则表现出明显的默契——卫星1访问A、卫星2访问B。 这应该归功于值分解机制让每个智能体根据自己的位置和在任务中的角色作出差异化的决策。另一个有趣的现象是QMIX 学会了在电量不足时主动跳过低优先级目标。这在贪心算法中是很难实现的因为贪心算法只看局部信息看不到电池电量的下降趋势。6. 常见问题与排查技巧实录6.1 STK 连接与数据提取问题第一个坑是 COM 接口连接失败。STK 11 与 Python 之间通过 COM 通信时必须保证两个进程以相同的权限运行。我遇到过 STK 以管理员权限启动、Python 以普通权限启动导致无法连接的情况解决方案是保证两者都用同一权限运行。第二个坑是时间格式。STK 默认输出 UTCG 格式的字符串比如01 May 2025 03:12:45.00直接字符串比较容易出错。我的做法是在数据预处理时统一转换为 Unix 时间戳浮点数保存后续所有逻辑都基于时间戳计算规避了格式转换的麻烦。第三个坑是 Access 计算遗漏。在批量计算上百个卫星-目标对之间的窗口时偶尔会因为目标对象名称拼写错误或者卫星传感器未正确添加导致部分 Access 结果为空。批量脚本里加一个日志断点计算完所有窗口后检查是否有空结果并定位到具体的卫星-目标对提前暴露问题。6.2 强化学习训练问题训练不稳定的情况非常常见。我遇到过的最典型问题是训练初期智能体完全停滞奖励一直在负值附近徘徊。排查后发现是奖励信号太过稀疏几乎所有动作都被时间惩罚和冲突惩罚压制正向的观测奖励很难触发。 解决方案是冷启动阶段增大观测奖励或在仿真初期给每个目标设置一个较高的初始可见概率帮助智能体尽快建立观测获得奖励的关联。第二个常见问题是 QMIX 中的训练发散损失值出现 NaN。原因多半是混合网络中的超网络输出了异常大的权重导致 Q 值爆炸。对策是给 Q 值做梯度裁剪同时降低学习率到 1e-4训练稳定性明显改善。第三个问题跟多智能体的重复探索有关。独立 PPO 训练时多个智能体共享同一经验池如果策略网络初始参数不同会导致经验分布差异变大。 我采取的办法是让所有智能体在训练初期共享同一套初始网络参数并且在前 1 个 epoch 内固定探索率。这不算严格的解决方案但实测下来收敛速度确实提升了。6.3 工程效率问题训练速度慢是另一个需要实际解决的问题。刚开始直接把 STK 接入训练循环一个 episode 跑一次 STK 场景计算要花好几分钟两百万步训练量根本不可能完成。 后来我改成预计算所有窗口数据训练过程只读表。同样是10万步训练耗时从原来的14小时缩短到不到40分钟这个改动是决定性的一步。GPU 显存不足也是多智能体场景里的常见问题。6个智能体同时采样时每个智能体都会产生一条独立的状态序列batch size 稍大就会显存溢出。解决办法是适当减小 batch size、使用梯度累积或者采用异步采样所有智能体在一个进程内顺序采样、共享经验池而不是并行开多个进程。 异步采样方案最容易实现我在最后阶段采用的也是这种方式。结尾的个人实操体会做这个实验花的时间比预想多得多尤其是环境搭建和数据处理环节真正用在算法调优上的时间反而只有三分之一。我体会最深的一点多智能体强化学习的难点十有八九不在算法本身而在环境建模的合理性和工程实现的稳定性上。 STK 预计算窗口这个决定让整个项目的可行性和效率都产生了质变。如果还在让 STK 参与训练循环的实时计算那这个实验大概是跑不完的。另外不要盲目照搬其他领域的 MARL 方案。卫星调度的动作空间小、约束强、可解释性要求高这跟打游戏、控制机械臂完全不是一个逻辑。实际调试时动作掩码、奖励函数权重的设计比算法选择更影响最终结果。这个实验后续可以扩展的方向不少把云层遮挡、光照条件等随机因素引入环境用离线强化学习算法从历史调度数据中学习而非完全在线试错或者加入星间链路通信让智能体在决策时能交换更丰富的消息。不管往哪个方向走现有的这套 STK 预计算加多智能体训练框架都能平滑接入这也是当初把它做成模板化结构的原因。本文还有配套的精品资源点击获取