STM32 电机动态 PI 控制:从编码器反馈、增量式 PI 到 Matlab 参数拟合与 PWM 输出

发布时间:2026/8/25 22:55:42

STM32 电机动态 PI 控制:从编码器反馈、增量式 PI 到 Matlab 参数拟合与 PWM 输出
前言在 STM32 智能小车、移动机器人以及其他直流电机控制系统中最基础的电机控制方式是直接改变 PWM 占空比。例如PWM 5000;PWM 增大后电机得到的驱动力通常会增大转速也会随之提高。但是直接控制 PWM 存在一个明显问题PWM 决定的是给电机多大的驱动力并不能保证电机一定达到某个确定的速度。同一个 PWM在不同情况下可能得到不同的实际转速例如电池电量充足 → 1.2 m/s 电池电压下降 → 1.0 m/s 负载增加 → 0.8 m/s 地面摩擦增大 → 0.7 m/s因此如果希望机器人能够稳定地保持某个目标速度就需要加入编码器反馈并利用 PI 或 PID 控制器不断调整 PWM。本文介绍一种进一步改进的电机控制方法动态 PI 速度控制。它在普通 PI 控制的基础上让KP和KI随电机当前速度动态变化使控制器能够适应不同的速度区间。完整控制链路如下目标速度 ↓ 编码器测量实际速度 ↓ 计算速度误差 ↓ 根据当前速度动态计算 KP、KI ↓ 增量式 PI 计算 ↓ 得到 PWM 控制量 ↓ PWM 限幅 ↓ H 桥驱动电机 ↓ 电机速度发生变化 ↓ 编码器再次反馈 └────────────────→ 下一控制周期一、动态 PI 控制整体框架一个典型的四轮移动机器人通常有四个独立电机Motor A Motor B Motor C Motor D每个电机都拥有目标速度 Target 实际速度 Encoder PI 控制器 PWM 输出因此可以分别进行速度闭环控制MOTOR_A.Motor_Pwm Incremental_PI_A( MOTOR_A.Encoder, MOTOR_A.Target ); MOTOR_B.Motor_Pwm Incremental_PI_B( MOTOR_B.Encoder, MOTOR_B.Target ); MOTOR_C.Motor_Pwm Incremental_PI_C( MOTOR_C.Encoder, MOTOR_C.Target ); MOTOR_D.Motor_Pwm Incremental_PI_D( MOTOR_D.Encoder, MOTOR_D.Target );整体结构可以表示为机器人目标运动 ↓ 运动学逆解 ↓ ┌───────────┼───────────┐ ↓ ↓ ↓ ↓ A目标速度 B目标速度 C目标速度 D目标速度 ↓ ↓ ↓ ↓ PI PI PI PI ↓ ↓ ↓ ↓ PWM_A PWM_B PWM_C PWM_D ↓ ↓ ↓ ↓ 电机A 电机B 电机C 电机D ↑ ↑ ↑ ↑ 编码器A反馈 编码器B反馈 编码器C反馈 编码器D反馈从控制系统角度来看每个轮子实际上都是一个独立的速度闭环。二、动态 PI 核心代码以下以电机 A 为例int Incremental_PI_A(float Encoder, float Target) { /* 跨控制周期保存状态 */ static float Bias; static float Pwm; static float Last_bias; /* 1. 当前速度误差 */ Bias Target - Encoder; /* 2. 根据当前速度动态计算 PI 参数 */ Velocity_KP 218.0f 179.0f * (Encoder / 3.5f) 21.0f * (Encoder * Encoder) / (3.5f * 3.5f); Velocity_KI 218.0f 179.0f * (Encoder / 3.5f) 21.0f * (Encoder * Encoder) / (3.5f * 3.5f); /* 3. 增量式 PI */ Pwm Velocity_KP * (Bias - Last_bias) Velocity_KI * Bias; /* 4. PWM 限幅 */ if(Pwm 16700) Pwm 16700; if(Pwm -16700) Pwm -16700; /* 5. 保存当前误差 */ Last_bias Bias; return (int)Pwm; }这段程序可以拆成五个步骤目标速度与实际速度比较 ↓ 计算当前误差 ↓ 动态计算 KP、KI ↓ 增量式 PI 计算 PWM ↓ PWM 限幅并输出下面依次展开。步骤 1获取目标速度与实际速度PI 控制器首先需要知道两件事情Target表示希望电机达到的目标速度以及Encoder表示编码器测量得到的实际速度例如Target 1.5 m/s Encoder 1.2 m/s则当前速度误差为Bias Target - Encoder;即代入数据e(k)1.5-1.20.3因为误差为正说明实际速度 目标速度电机需要继续加速。反过来如果Target 1.5 m/s Encoder 1.8 m/s则e(k)1.5-1.8-0.3说明实际速度 目标速度控制器需要降低输出。因此Bias 0 → 电机偏慢 Bias 0 → 电机偏快 Bias ≈ 0 → 实际速度已经接近目标速度步骤 2增量式 PI 控制1. PI 控制中的 KP 和 KIPI 控制器包含两个核心参数KP比例增益 KI积分增益2. KP 的作用KP主要决定系统对当前误差变化的响应力度。可以简单理解为误差变化大 ↓ 控制器快速调整 误差变化小 ↓ 控制器小幅调整因此 KP 主要影响响应速度 控制灵敏度 动态跟随能力KP 太小响应比较慢KP 太大容易出现超调甚至振荡3. KI 的作用KI 主要用于消除长期存在的小误差。例如目标速度 1.0 m/s 实际速度 0.95 m/s虽然只差0.05 m/s但如果这种误差持续存在控制器就应该继续进行修正。积分作用会持续累积这个误差使 PWM 逐渐变化最终尽量实现实际速度 ≈ 目标速度所以KP 主要负责“快速响应” KI 主要负责“减小稳态误差”步骤 3增量式 PI 公式程序采用Pwm Velocity_KP * (Bias - Last_bias) Velocity_KI * Bias;对应数学表达式然后这里e(k) 当前误差 e(k-1) 上一次误差 KP 比例增益 KI 积分增益 ΔPWM 本控制周期需要增加或减少的 PWM1.为什么叫“增量式”因为控制器并不是每次重新计算一个全新的 PWM。它计算的是在上一次 PWM 基础上本次需要增加多少或者减少多少。例如当前PWM 5000控制器根据误差算出ΔPWM 300那么新 PWM 5000 300 5300下一周期继续测速。假设速度已经更接近目标值ΔPWM 80则PWM 5380如此不断迭代。因此它的过程为测量 ↓ 计算误差 ↓ 计算 PWM 增量 ↓ 修改 PWM ↓ 再次测量步骤 4根据当前速度动态计算 KP 和 KI示例程序使用程序实现Velocity_KP 218.0f 179.0f * (Encoder / 3.5f) 21.0f * (Encoder * Encoder) / (3.5f * 3.5f);其中v Encoder也就是当前编码器计算出来的实际速度。三、参数变化示例假设v1.5则得到约如果v3.0则得到约因此这个参数模型表现为速度较低 ↓ KP 较小 速度提高 ↓ KP 增大需要注意的是这只是当前参数模型的变化趋势并不意味着所有电机都必须按照“速度越高KP/KI 越大”的方式调节。最终关系应该由实验结果决定。步骤 5实验数据采集例如依次测试0.5 m/s 1.0 m/s 1.5 m/s 2.0 m/s 2.5 m/s 3.0 m/s 3.5 m/s在每个速度点调节KP KI同时观察1. 上升时间 2. 超调量 3. 稳态误差 4. 振荡情况 5. 达到目标速度后的稳定程度最终可以形成类似的数据车速 vm/sKPKI0.52402501.02702801.53003152.03253502.53553903.03904303.5420450这里的数据只是用来说明回归流程。不同电机的性能 减速比 机械结构 机器人重量 轮胎摩擦 电池状态都会影响最终 PI 参数因此不能直接照搬。四、Matlab 二次回归示例假设已经获取v [0.5 1.0 1.5 2.0 2.5 3.0 3.5]; KP_values [240 270 300 325 355 390 420]; KI_values [250 280 315 350 390 430 450];使用coeffs_KP polyfit(v, KP_values, 2); coeffs_KI polyfit(v, KI_values, 2);其中polyfit(x, y, 2)最后的2表示使用二次多项式进行回归。得到的结果形式coeffs_KP [a b c]对应同理五、Matlab 绘制拟合结果除了计算系数还可以画图观察拟合效果v [0.5 1.0 1.5 2.0 2.5 3.0 3.5]; KP_values [240 270 300 325 355 390 420]; % 二次拟合 p polyfit(v, KP_values, 2); % 生成连续速度 v_fit linspace(0.5, 3.5, 100); % 根据拟合公式计算KP KP_fit polyval(p, v_fit); % 绘制实验数据 scatter(v, KP_values, filled); hold on; % 绘制拟合曲线 plot(v_fit, KP_fit); xlabel(Velocity (m/s)); ylabel(KP); title(KP-Velocity Polynomial Fitting); grid on;最终可以看到实验采样点 二次拟合曲线如果拟合曲线能够较好地接近实验数据点就可以进一步将其写入 STM32。步骤 6将回归公式部署到 STM32Matlab 得到数学模型以后真正运行机器人时并不需要 Matlab。只需要把公式写进 STM32Velocity_KP 218.0f 179.0f * (Encoder / 3.5f) 21.0f * (Encoder * Encoder) / (3.5f * 3.5f);运行过程中编码器测得当前速度 ↓ 代入数学公式 ↓ 得到当前 KP、KI ↓ 执行 PI例如Encoder 1.5计算一套 PI 参数。下一周期Encoder 2.3马上计算另一套参数。所以这里并不是每隔一段时间重新人工调一次 PI而是MCU 在运行过程中实时自动计算 PI 参数步骤 7计算 PWM获得当前KP KI以后就可以进入增量式 PIPwm Velocity_KP * (Bias - Last_bias) Velocity_KI * Bias;完整数据关系目标速度 Target │ ↓ 计算误差 ↑ │ 实际速度 Encoder │ └────→计算 KP、KI ↓ 增量式 PI ↓ PWMPI 最终输出的并不是速度而是电机需要多大的控制量。在本系统中这个控制量最终就是 PWM。步骤 8PWM 限幅PI 本质上是不断累积调整 PWM。如果误差很大理论上可能出现PWM 20000 PWM 30000 ...但实际定时器和电机驱动器都有最大输出范围。因此需要if(Pwm 16700) Pwm 16700; if(Pwm -16700) Pwm -16700;最终控制-16700 ≤ PWM ≤ 16700PWM 的正负号可以表示电机方向而绝对值表示控制力度例如5000代表一个方向。-5000代表另外一个方向。而10000相较于5000代表更大的驱动输出。步骤 9通过 H 桥驱动电机PI 得到MOTOR_A.Motor_Pwm之后这仍然只是程序中的数字。需要通过Set_Pwm();真正写入定时器比较寄存器。例如Set_Pwm( MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm );对于双输入 H 桥一般需要把一个有符号 PWM 转换成两路控制信号。例如void Set_Motor_PWM(int motor_pwm) { if(motor_pwm 0) { MOTOR_PWM1 PWM_MAX; MOTOR_PWM2 PWM_MAX motor_pwm; } else { MOTOR_PWM2 PWM_MAX; MOTOR_PWM1 PWM_MAX - motor_pwm; } }例如motor_pwm 5000可能得到PWM1 11799 PWM2 16799而motor_pwm -5000得到PWM1 16799 PWM2 11799两路 H 桥控制信号的作用关系交换因此电机电流方向发生变化最终实现正反转。完整程序框架最终整个电机动态 PI 控制程序可以概括成void Motor_Control_Task(void) { /* 1. 获取电机目标速度 */ Drive_Motor(Vx, Vy, Vz); /* 2. 编码器测速 */ Get_Velocity_Form_Encoder(); /* 3. 动态PI控制 */ MOTOR_A.Motor_Pwm Incremental_PI_A( MOTOR_A.Encoder, MOTOR_A.Target ); MOTOR_B.Motor_Pwm Incremental_PI_B( MOTOR_B.Encoder, MOTOR_B.Target ); MOTOR_C.Motor_Pwm Incremental_PI_C( MOTOR_C.Encoder, MOTOR_C.Target ); MOTOR_D.Motor_Pwm Incremental_PI_D( MOTOR_D.Encoder, MOTOR_D.Target ); /* 4. PWM限幅 */ Limit_Pwm(16700); /* 5. 输出到H桥 */ Set_Pwm( MOTOR_A.Motor_Pwm, MOTOR_B.Motor_Pwm, MOTOR_C.Motor_Pwm, MOTOR_D.Motor_Pwm ); }对应流程Drive_Motor() 运动学逆解 ↓ 获得 Target ↓ Get_Velocity_Form_Encoder() ↓ 获得 Encoder ↓ Incremental_PI() ↓ 动态 KP / KI ↓ 计算 PWM ↓ Limit_Pwm() ↓ Set_Pwm() ↓ H桥 ↓ 电机 ↓ 编码器反馈总结动态 PI 控制的核心并不复杂。普通 PI 是固定 KP 固定 KI ↓ 根据速度误差计算 PWM动态 PI 则是在 PI 前面增加了一层参数调度当前速度 v ↓ 计算 KP(v) 计算 KI(v) ↓ 增量式 PI ↓ PWM整个电机闭环可以表示为目标速度 ↓ 编码器反馈实际速度 ↓ 计算速度误差 ↓ 根据当前速度动态计算 KP、KI ↓ 增量式 PI ↓ PWM 控制量 ↓ PWM 限幅 ↓ H 桥 ↓ 电机 ↓ 编码器再次反馈其中 Matlab 主要用于开发阶段真实实验 ↓ 不同速度下调试 KP、KI ↓ 采集 (v, KP, KI) ↓ Matlab 多项式回归 ↓ 得到 KP(v)、KI(v) ↓ 写入 STM32机器人真正运行以后并不需要 Matlab 实时参与。STM32 只需要读取当前速度 ↓ 代入已经得到的函数 ↓ 实时计算 KP、KI ↓ 完成 PI 控制这种方法本质上是一种计算量较小、实现简单的增益调度策略。相比单纯固定 PI它能够让控制器根据当前工作速度选择不同的增益因此在机器人运行速度范围较大、不同速度区间动态特性差异明显时具有一定的工程应用价值。Question1:为什么需要动态 PI普通 PI 一般采用固定参数KP 300; KI 250;无论电机0.5 m/s 1.5 m/s 3.0 m/s都使用同样的参数。但真实电机的控制特性并不是完全不变的。不同速度区间可能表现出不同特征。例如低速 机械摩擦、死区影响明显 中速 系统相对稳定 高速 惯性、反电动势、负载变化影响更加明显于是固定 PI 可能产生低速表现很好高速响应慢 或者 高速表现很好低速控制过于敏感动态 PI 的思路就是也就是说速度改变 ↓ PI 参数随之改变这种控制方法实际上可以看作一种简单的增益调度 Gain Scheduling。Question2这些 KP 和 KI 参数是怎么来的动态 PI 的关键并不是KP a b*v c*v*v;而是如何找到a b c这些系数。一个比较直观的工程方法是真实电机实验 ↓ 设置不同目标速度 ↓ 人工调整 KP、KI ↓ 寻找效果较好的参数 ↓ 记录 速度 v KP KI ↓ 将数据输入 Matlab ↓ 回归分析 ↓ 得到 KP(v)、KI(v)Question3为什么使用 Matlab完成实验以后得到的是一些离散数据v 0.5 → KP 240 v 1.0 → KP 270 v 1.5 → KP 300 ...但是机器人实际运行过程中速度并不一定正好等于这些实验点。例如v 1.37 m/s此时依然需要知道应该使用多少 KP。因此需要从离散实验点得到连续数学函数Matlab 在这里主要承担回归拟合与数据分析。Question4为什么使用二次多项式回归一次函数 → 简单但只能表达线性趋势 二次函数 → 可以描述一定非线性 高阶函数 → 表达能力更强但更容易过拟合二次多项式属于拟合能力与计算复杂度之间比较合适的折中方案。同时 STM32 计算K a b*v c*v*v;非常简单对 MCU 的实时计算负担也很小。

相关新闻

GEO优化实战:如何让品牌被DeepSeek、豆包、文心一言、千问、元宝等大模型优先引用

GEO优化实战:如何让品牌被DeepSeek、豆包、文心一言、千问、元宝等大模型优先引用

2026/8/25 22:55:42

在生成式AI席卷内容生态的今天,用户获取信息的入口正在从搜索引擎转向AI对话。越来越多的人在DeepSeek、豆包、文心一言、千问、元宝等平台上直接提问"哪个产品好""哪家企业靠谱"。谁能被大模型优先引用,谁就掌握了下一代的流量入口…

Seraphine:不碰内存的英雄联盟战绩查询工具,自动BP一站搞定

Seraphine:不碰内存的英雄联盟战绩查询工具,自动BP一站搞定

2026/8/25 22:45:42

Seraphine:不碰内存的英雄联盟战绩查询工具,自动BP一站搞定 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine Seraphine 是一款完全基于 League Client API 开发的英雄联盟战绩查询开源工…

CISA KEV八月新增漏洞盘点:被利用漏洞的应对优先级与Splunk事件分析

CISA KEV八月新增漏洞盘点:被利用漏洞的应对优先级与Splunk事件分析

2026/8/25 22:45:42

一、先给结论 CISA 的 Known Exploited Vulnerabilities(KEV,已知被利用漏洞目录)是安全运营的最高优先级输入——进了 KEV 意味着"有真实攻击者在利用",补丁优先级应高于任何普通 CVE。 2026年8月19-21日前后&#xff…

CVPR 2026|PhyFusion:基于物理感知和模态特定先验驱动的红外与可见光图像融合

CVPR 2026|PhyFusion:基于物理感知和模态特定先验驱动的红外与可见光图像融合

2026/8/25 23:45:44

PhyFusion:把红外辐射与可见光反射写进图像融合 1. 一句话总结 现有红外-可见光融合方法大多只匹配图像外观,容易削弱红外热目标并模糊可见光纹理。本文提出 PhyFusion,分别从红外辐射模型和可见光 Retinex 模型中提取物理先验,…

071、6D位姿估计基础与PPF:点对特征的刚体配准原理

071、6D位姿估计基础与PPF:点对特征的刚体配准原理

2026/8/25 23:45:44

071、6D位姿估计基础与PPF:点对特征的刚体配准原理 调试机器人抓取的时候,最烦的不是模型精度不够,而是你明明把点云喂进去了,位姿输出却在天上飞。上周调一个工业件抓取,CAD模型是标准STEP导出的,场景点云是RealSense拍的,PPF跑出来旋转矩阵行列式居然是负的——一看就…

G-Helper 上手指南:单文件管遍华硕笔记本的性能、电池与风扇

G-Helper 上手指南:单文件管遍华硕笔记本的性能、电池与风扇

2026/8/25 23:45:44

G-Helper 上手指南:单文件管遍华硕笔记本的性能、电池与风扇 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbo…

教育智能体框架:构建个性化学习与机构智能的统一多智能体系统

教育智能体框架:构建个性化学习与机构智能的统一多智能体系统

2026/8/25 23:45:44

1. 从“一刀切”到“千人千面”:教育智能体的必然之路如果你是一位教育从业者,或者是一位关注教育技术发展的开发者,最近一定被“Agentic AI”这个词刷屏了。它不再是科幻电影里的遥远概念,而是正在快速渗透到我们教学、管理和学习…

策略感知AI框架:从多模态数据到自闭症干预临床辅助

策略感知AI框架:从多模态数据到自闭症干预临床辅助

2026/8/25 23:45:44

1. 项目缘起:当AI遇见自闭症干预的临床现实自闭症谱系障碍的干预,是一个极其复杂且高度个性化的过程。作为一名长期关注AI在医疗健康领域应用的从业者,我见过太多“实验室里效果惊艳,临床落地一地鸡毛”的案例。核心痛点在于&…

基于SpringBoot的社区团购小程序的设计与实现源码+文档+讲解视频

基于SpringBoot的社区团购小程序的设计与实现源码+文档+讲解视频

2026/8/25 23:35:43

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

2026/8/24 19:53:32

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

2026/8/24 19:56:07

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

2026/8/24 21:16:09

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

三步把QQ空间历史说说导出到本地:GetQzonehistory 极简指南

三步把QQ空间历史说说导出到本地:GetQzonehistory 极简指南

2026/8/25 0:04:34

三步把QQ空间历史说说导出到本地:GetQzonehistory 极简指南 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory Meta Description:GetQzonehistory 是一个QQ空间历史说…

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

2026/8/25 0:04:35

【题目来源】 https://www.luogu.com.cn/problem/P7912 【题目描述】 小熊的水果店里摆放着一排 n 个水果。每个水果只可能是苹果或桔子,从左到右依次用正整数 1,2,…,n 编号。连续排在一起的同一种水果称为一个“块”。小熊要把这一排水果挑到若干个果篮里&#x…

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

2026/8/25 0:04:35

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG 【免费下载链接】transformers.js State-of-the-art Machine Learning for the web. Run 🤗 Transformers directly in your browser, with no need for a server! 项目地址: https:/…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/22 2:02:26

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/22 4:13:47

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/22 1:32:34

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…