一个用大语言模型辅助 PID 调参的实用工具。
💬 QQ 群:1082281492 - 欢迎加入交流讨论 📺 B站教程视频 - 详细视频教程手把手教你使用 📺 YouTube 教程视频
中文 | English
如果你是第一次接触这个项目,不要先折腾 Python。 最省事的用法是直接下载 Release 里的
llm-pid-tuner.exe。
如果你想看 最新功能、最新教程、最新 Simulink 配置说明,请直接参考 dev 分支文档:
如果你只想使用 当前稳定版 main,继续阅读本页即可。
- 系统结构图
- 先看你该怎么用
- 这个项目适合什么场景
- 它不是做什么的
- 3 分钟上手:Windows 打包版(推荐给小白)
- config.json 怎么填
- 推荐模型与接口填写方式
- 如何自定义提示词 (Prompt)
- MATLAB/Simulink 仿真模式
- 如果你还没有硬件,先跑仿真
- 进阶:源码方式运行
┌──────────────────────── 本地仿真模式 (Simulator) ────────────────────────┐
│ │
│ simulator.py ───────────── API(JSON) ─────────────> LLM / AI Tuner │
│ (热系统仿真) (生成 PID 建议) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
┌──────────────────────── 真实硬件模式 (Hardware) ─────────────────────────┐
│ │
│ MCU / firmware.cpp ── Serial(CSV) ──> tuner.py ── API ──> LLM │
│ (Arduino / ESP32) (上位机 / .exe) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
- 只想调硬件,不想配开发环境:走
exe路线,见下方“3 分钟上手”。 - 想先看看这个项目到底有没有用:运行
simulator.py做本地热系统仿真。 - 想接自己的 Arduino / ESP32 / 其他控制板:使用
firmware.cpp+tuner.py/llm-pid-tuner.exe。 - 想二次开发或看内部设计:看 PROJECT_DOC.md。
- 恒温控制:加热板、热端、恒温箱、水浴、烘箱
- 电机 / 执行器:需要 PID 闭环调节的对象
- 已经能跑,但参数不好:响应慢、超调大、抖动、稳态误差明显
- 没有成熟整定经验,希望让 LLM 先帮你缩小试错范围
- 它不是“一键保证完美控制”的魔法程序
- 它不是替代硬件保护的安全系统
- 它不是为了漂亮 benchmark 分数而设计的玩具
这个项目更在意的是:真实调参时少走弯路、少炸参数、调差了还能回退。
打开 Release 页面,并下载资产里的 llm-pid-tuner.exe。
你需要一个能通过串口持续上报控制数据的板子。
最简单的方式是直接参考仓库里的 firmware.cpp,它已经实现了这个项目默认使用的串口协议。
程序默认希望设备通过串口持续输出类似下面的 CSV 数据:
timestamp_ms,setpoint,input,pwm,error,p,i,d
如果你不想自己适配协议,最省事的办法就是直接从 firmware.cpp 开始。
双击运行 llm-pid-tuner.exe。
启动器会先让你选择模式:[1] 真实硬件调参,[2] 本地仿真 TUI(默认)。
如果你现在是准备接串口硬件,请先选 [1]。
第一次运行时,如果当前目录下没有 config.json,程序会自动生成一份默认配置。
打开 config.json,至少先把“硬件模式最小必填项”改掉:
{
"SERIAL_PORT": "AUTO",
"BAUD_RATE": 115200,
"LLM_API_KEY": "sk-your-key",
"LLM_API_BASE_URL": "https://api.openai.com/v1",
"LLM_MODEL_NAME": "gpt-4o",
"LLM_PROVIDER": "openai"
}如果你只是想先跑 simulator.py 看效果,没有接真实串口,也可以先不填 SERIAL_PORT,只把 LLM 相关字段填好。
如果你要用 MiniMax / DeepSeek / Ollama / LM Studio 这类 OpenAI 兼容接口,通常这样配就行:
{
"LLM_API_KEY": "你的 key",
"LLM_API_BASE_URL": "你的 /v1 地址",
"LLM_MODEL_NAME": "你的模型名",
"LLM_PROVIDER": "openai"
}比如 MiniMax 兼容接口可以是:
{
"LLM_API_BASE_URL": "http://你的地址/v1",
"LLM_MODEL_NAME": "MiniMax-M2.5",
"LLM_PROVIDER": "openai"
}如果你用的是 Claude 中转站 / OneAPI / New API 这类 OpenAI 兼容接口,现在也可以更明确地写成:
{
"LLM_API_BASE_URL": "https://你的中转站/v1",
"LLM_MODEL_NAME": "claude-3-7-sonnet",
"LLM_PROVIDER": "openai_claude"
}openai_claude 和 openai 都会走 OpenAI 兼容协议;前者只是专门给 Claude 中转站准备的显式选项。
如果你使用 Claude 原生接口,再把 LLM_PROVIDER 改成 anthropic。
保存 config.json 后重新运行程序。
- 如果
SERIAL_PORT填的是AUTO,程序会扫描串口并让你选择 - 如果你已经知道端口号,比如
COM5,也可以直接写死,省掉选择步骤
程序会持续:
- 读取串口数据
- 分析当前响应质量
- 请求 LLM 给出新的 PID 建议
- 必要时使用保底策略
- 如果后续结果变差,会回退到之前更稳的参数
- 当系统“已经够好”时,会尽量提前停止,避免过调
你最终需要做的事通常只有一件:把收敛后的 PID 参数写回你的固件。
第一次运行 tuner.py、simulator.py 或 llm-pid-tuner.exe 时,如果当前目录没有 config.json,程序会自动生成一份默认配置。
如果你喜欢先看模板,也可以直接参考仓库里的 config.example.json。
1. 真实硬件模式最小必填
{
"SERIAL_PORT": "AUTO",
"BAUD_RATE": 115200,
"LLM_API_KEY": "sk-your-key",
"LLM_API_BASE_URL": "https://api.openai.com/v1",
"LLM_MODEL_NAME": "gpt-4o",
"LLM_PROVIDER": "openai"
}2. 本地 Python 仿真最小必填
{
"LLM_API_KEY": "sk-your-key",
"LLM_API_BASE_URL": "https://api.openai.com/v1",
"LLM_MODEL_NAME": "gpt-4o",
"LLM_PROVIDER": "openai"
}3. Simulink 模式额外补这几项
{
"MATLAB_MODEL_PATH": "C:/models/my_pid_model.slx",
"MATLAB_PID_BLOCK_PATH": "my_pid_model/PID Controller",
"MATLAB_ROOT": "D:/Program Files/MATLAB/R2025b",
"MATLAB_OUTPUT_SIGNAL": "y_out",
"MATLAB_SIM_STEP_TIME": 15.0,
"MATLAB_SETPOINT": 200.0
}这 6 项是跑通单控制器模型的最小必填。
如果你的 Simulink 模型不是“单个标准 PID Controller 块 + 一个输出信号”这种最简单结构(例如主副环、分离式 P/I/D 增益块),程序也支持更复杂的兼容字段。
请直接查看完整的 MATLAB/Simulink 调参指南。 指南里详细说明了:
- 如何快速获取正确的 Simulink 块路径
- 如何配置双控制器与分离式增益块
MATLAB_ROOT什么时候可以不填- 常见环境报错(如
No module named matlab.engine)的解决方法
| 分类 | 什么时候需要 | 字段 | 说明 |
|---|---|---|---|
| 硬件串口 | 真实硬件调参 | SERIAL_PORT BAUD_RATE |
SERIAL_PORT 不确定先填 AUTO,BAUD_RATE 要和固件一致 |
| LLM 基础 | 所有模式都需要 | LLM_API_KEY LLM_API_BASE_URL LLM_MODEL_NAME LLM_PROVIDER |
这是最核心的一组配置,不填就无法调参 |
| 调参行为 | 想微调策略时再改 | BUFFER_SIZE MIN_ERROR_THRESHOLD MAX_TUNING_ROUNDS LLM_REQUEST_TIMEOUT LLM_DEBUG_OUTPUT PID_MAX_INCREASE_RATIO |
新手建议先保持默认,只有在采样不够、网络慢或需要排查日志时再动。PID_MAX_INCREASE_RATIO 用于限制单次参数调整的最大倍数(如 1.5 表示最多增加 50%),填 0.0 则使用默认限制。 |
| Simulink | 只在 MATLAB/Simulink 模式下需要 | MATLAB_MODEL_PATH MATLAB_PID_BLOCK_PATH MATLAB_ROOT MATLAB_OUTPUT_SIGNAL MATLAB_SIM_STEP_TIME MATLAB_SETPOINT,以及按需填写 MATLAB_CONTROL_SIGNAL MATLAB_SETPOINT_BLOCK MATLAB_PID_BLOCK_PATHS MATLAB_PID_BLOCK_PATH_2 MATLAB_P/I/D_BLOCK_PATH(_2) |
最小 6 项先跑通,复杂模型再逐步补充兼容字段 |
| 代理 | 只有需要代理时才填 | HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY |
留空就是不启用 |
程序也支持环境变量,并且环境变量优先级高于 config.json。
例如:
$env:LLM_API_KEY="sk-xxx"
$env:LLM_API_BASE_URL="http://127.0.0.1:11434/v1"
$env:LLM_MODEL_NAME="qwen2.5:7b"
$env:LLM_PROVIDER="openai"如果你是小白,优先用 config.json,更直观。
如果你需要走 VPN/代理,可以在 config.json 里新增以下字段:
{
"HTTP_PROXY": "http://127.0.0.1:7890",
"HTTPS_PROXY": "http://127.0.0.1:7890",
"ALL_PROXY": "http://127.0.0.1:7890",
"NO_PROXY": ""
}留空则不启用代理,对不需要代理的用户没有影响。
如果你希望将调参过程中的实时数据(时间戳、设定值、当前值、PWM、误差、PID参数等)保存下来,以便后续在 Excel 或 MATLAB 中分析,可以在 config.json 中配置 CSV_EXPORT_PATH 字段:
{
"CSV_EXPORT_PATH": "logs/tuning_data.csv"
}- 填入你希望保存的 CSV 文件路径(支持相对路径或绝对路径)。
- 每次运行调参时,程序会自动将数据追加到该文件中,并记录当前的
session_id和round(轮次),方便你区分不同次的调参记录。 - 留空(
"")则不导出 CSV。
| 方案 | LLM_API_BASE_URL 示例 |
LLM_PROVIDER |
说明 |
|---|---|---|---|
| OpenAI | https://api.openai.com/v1 |
openai |
最省心 |
| DeepSeek 兼容接口 | 对应服务商的 /v1 地址 |
openai |
常见且便宜 |
| MiniMax 兼容接口 | 对应服务商的 /v1 地址 |
openai |
推理能力适合调参 |
| Claude 中转站 / OneAPI / New API | 对应服务商的 /v1 地址 |
openai_claude |
Claude 模型走 OpenAI 兼容协议时用这个最直观 |
| Ollama | http://localhost:11434/v1 |
openai |
本地免费部署 |
| LM Studio | http://localhost:1234/v1 |
openai |
本地可视化较友好 |
| Anthropic Claude | https://api.anthropic.com |
anthropic |
原生接口用这个 |
这个项目现在做了更稳的解析和回退处理,对 OpenAI 兼容接口更友好。如果 SDK 路径不顺,它也会尽量走更直接的 HTTP 路径,减少“能调通 API 但程序不工作”的情况。
本项目提供了两种自定义提示词(调参策略)的方式,以适应不同的需求:
在每次启动调参(无论是仿真还是硬件模式)时,程序会首先进入预调参对话 (Pre-Tuning Conversation)。 在这里,你可以直接用自然语言输入你的偏好。例如:
- "我希望系统绝对稳定,不能有任何超调,哪怕响应慢一点也没关系。"
- "这是一个对响应速度要求极高的系统,允许 10% 以内的超调,请尽可能激进地调参。"
- "注意,这个电机的死区比较大,P 参数可以给大一点。"
程序会自动将你的自然语言偏好转化为结构化的 JSON 约束,并附加到 LLM 的系统提示词中,从而改变 LLM 的调参行为。
如果你希望永久改变 LLM 的核心调参逻辑或角色设定,你需要修改源码:
- 打开
llm/prompts.py文件。 - 找到
_BASE_SYSTEM_PROMPT变量,这里定义了 LLM 的核心角色、职责和调参原则。 - 找到
_MODE_NOTES变量,这里定义了不同模式(如hardware,simulink,python_sim)下的特定规则。 - 根据你的需求修改这些字符串内容即可。
如果你已经有 MATLAB/Simulink 仿真模型,可以直接让 LLM 对你的模型进行 PID 调参,无需真实硬件。
在 config.json 里至少填写下面这些字段,再运行 python simulator.py 或打包版启动器里的 Simulink 模式:
MATLAB_MODEL_PATH:Simulink.slx文件路径MATLAB_PID_BLOCK_PATH:模型里的 PID 模块完整路径MATLAB_OUTPUT_SIGNAL:To Workspace 输出变量名MATLAB_ROOT:MATLAB 安装根目录;打包版建议填写,源码运行如果当前 Python 已装好 MATLAB Engine 可以留空
详细配置步骤、模型准备方法和常见问题,见 MATLAB/Simulink 调参指南。
如果你只是想确认这个项目到底在干什么,先跑这个:
pip install -r requirements.txt
python simulator.pysimulator.py 会在本地模拟一个热系统,然后让 LLM 自动调参。
这条路线最适合先理解项目,而不是直接上真实硬件。
在调参循环开始前,程序现在会自动进行两个对新手非常友好的操作:
- 运行环境诊断(
doctor.py),检查配置、API 连接性、串口及代理设置。 - 进行简短的系统辨识(热启动),给出比默认值更合理的初始 PID 建议。
此外,交互模式下支持预调参对话(Pre-Tuning Dialog)。你可以用自然语言直接输入调参偏好或限制(例如:“超调不能超过 5%” 或 “响应可以慢点但绝不能震荡”),LLM 会自动提取为调参的硬性约束。
如果你只想手动运行环境检查而不启动仿真,可以使用:
python doctor.py如果你不想用 exe,也可以直接跑源码。
dev分支:当前最新开发代码,功能修复、TUI 改动、打包前验证都会先进入这里main分支:更偏稳定展示和正式 release,同步会慢一些,不保证是当前最新行为- 如果你想源码运行、跟进最近修复,或者准备提 PR,建议直接拉
dev
git clone -b dev https://github.com/KINGSTON-115/llm-pid-tuner.git
cd llm-pid-tunergit fetch origin
git checkout dev
git pull --ff-only origin devpip install -r requirements.txt如果你要跑 Simulink 源码模式,还需要让当前这个 Python 环境能导入 matlab.engine。不会配的话,直接看 MATLAB/Simulink 调参指南。
- 跑
python tuner.py:至少填好 LLM 配置和串口配置 - 跑
python simulator.py:至少填好 LLM 配置 - 跑 Simulink:再额外补
MATLAB_*相关字段
第一次运行时如果没有 config.json,程序会自动生成一份默认配置;你也可以直接从 config.example.json 开始改。
python simulator.py如果你想用旧式纯日志输出,而不是 TUI,或者需要强制切换显示语言:
python simulator.py --plain
python simulator.py --lang en # 强制使用英文界面,默认支持根据系统自动检测语言python tuner.py你可以先采一段阶跃响应数据,再用 system_id.py 给出一组初值建议:
python system_id.py --file sample_step.csv这适合想先拿到一组“不会太离谱”的初始参数,再交给 LLM 继续细调的用户。
| 文件 | 用途 |
|---|---|
launcher.py |
启动器,可选择硬件或仿真模式并支持语言切换 |
tuner.py |
真实硬件调参主程序,也是 exe 的核心入口 |
simulator.py |
本地热系统仿真,适合演示和验证策略 |
pid_safety.py |
参数保护、保底策略、最佳结果记录、回退逻辑 |
firmware.cpp |
单片机侧示例固件,负责串口上报与执行 PID |
system_id.py |
利用阶跃响应做系统辨识,给出初始 PID 建议 |
doctor.py |
环境诊断检查工具,快速排查配置与连接问题 |
benchmark.py |
固定随机种子的对比工具,更偏开发验证用途 |
config.json |
运行配置文件 |
docs/zh-CN/PROJECT_DOC.md |
面向开发者的内部说明文档 |
常见原因:
config.json还没填好- API Key 无效
- 串口打不开
- 当前目录没有写入权限,导致配置文件生成失败
建议直接在 PowerShell 里运行,这样错误信息不会消失:
.\llm-pid-tuner.exe检查下面几件事:
- 设备是否真的连上电脑
- 驱动是否安装正确
- 其他上位机是否已经占用了串口
BAUD_RATE是否和单片机一致
大概率是你的固件输出格式和项目默认协议不一致。
最稳妥的办法是先按 firmware.cpp 的格式对齐。
多数时候是这几类问题:
LLM_API_BASE_URL写错- 模型名写错
- 你用的是 OpenAI 兼容接口,但
LLM_PROVIDER填成了anthropic - 你用的是 Claude 中转站,但把它当成了 Anthropic 原生接口;这时应该用
openai_claude或openai - 服务端虽然可用,但返回 JSON 风格不稳定
现在的程序会:
- 给 PID 做基本护栏限制
- LLM 异常时启用保底建议
- 记录历史最佳稳定参数
- 后续结果明显变差时自动回退
也就是说,它的设计目标不是“每一轮都更激进”,而是优先把系统留在一个更稳、更可用的位置。
可以,但前提是你本地起了兼容 OpenAI 接口的模型服务,比如:
- Ollama
- LM Studio
然后把 LLM_API_BASE_URL 指向本地地址即可。
在真实硬件上调参时,请务必有人值守。
尤其是加热类系统,一定要有:
- 硬件级限温
- 传感器异常保护
- 继电器 / MOS 管失控保护
- 必要时的物理断电手段
这个项目能帮你减少调参痛苦,但不能替代硬件安全设计。
- 最新打包版请看 Release
- 打包方法见 Issue #11
- 当前打包使用 Python
3.8(见llm-pid-tuner.spec中matlabengineforpython3_8.pyd) - 历史测试环境包含
R2022b;文档里的R2025b只是示例路径版本,请替换成你本机实际安装的 MATLAB 版本 - 想看项目内部设计,请看 PROJECT_DOC.md
CC BY-NC-SA 4.0