Claude Code 接博途:从空工程到跑通仿真的全链路

一句话需求 → 它自己写 FB → 编译 0 错 0 警 → 下载进仿真器 → 三个场景全部对上。

分享
Claude Code 接博途:从空工程到跑通仿真的全链路

让 Claude Code 这类编码智能体改博途程序,链路上没有神秘环节——加 CPU、导 SCL、编译、下载、跑仿真,每一步要么给你确定的成功,要么给你确定的报错。我们从一台空设备跑到终点:编译 0 错 0 警、下载进仿真器、三个场景跑出稳定数值。全程 34 个工具、9 个步骤,提示词、产出的 SCL 和实测数字都贴在下面。

披露:本文的实测数据来自 2026-10-27 在一台 Windows 机器上的真实运行(博途 V19 / Openness 19.0 / S7-PLCSIM Advanced 6.0 / 网关 TiaLink 1.3.2.0)。


一、它能做什么

把博途里那些日常动作,变成智能体能直接执行的操作:看、改、组、验、存,一条链走完。

能力 具体动作
看 读工程树、块内容、变量表、UDT、交叉引用、HMI 画面、硬件组态
改 生成或改写 SCL、建块建表、写回工程,单块编译或整 PLC 编译
组 加 CPU、插模块、建子网、连 IO 系统、配 PN 设备名
验 下载到 S7-PLCSIM Advanced、读写变量、跑场景看结果
存 导出 SimaticML,做离线比对与版本归档

本版共 34 个工具,上面五类各有一组(另有 LAD 规范与目录一组,给"写梯形图"用)。

装在不同客户端里,用法都一样:说一句话,它自己选工具、自己排步骤。

二、接上:一份端点,五个客户端

网关是 HTTP 型 MCP,接哪个客户端都只改配置,不用改程序。

客户端 加法 备注
Claude Code claude mcp add --transport http tialink http://192.168.1.110:8080/mcp Claude Code 2.1.311 实测,--transport http 是必须的
pi 项目内 .pi/mcp.json 写 mcpServers.tialink.url 同一份配置换了个客户端
Cursor .cursor/mcp.json 的 mcpServers 工具数量多时注意客户端的工具上限
Claude Desktop claude_desktop_config.json 改完要完全重启
WorkBuddy / CodeBuddy 界面「连接器 → 自定义连接器 → 添加 MCP」 加完必须显式【启用】,否则工具不出现

Claude Code 配置方法如下:

claude mcp add --transport http tialink http://192.168.1.110:8080/mcp
claude mcp list          # 确认连上、看工具数

pi 的配置只要几行:

{
  "mcpServers": {
    "tialink": {
      "url": "http://192.168.1.110:8080/mcp",
      "timeout": 180
    }
  }
}

顺带一个实践提醒:timeout 别用默认值。加 CPU 我们实测 34 s(旧固件那台)、导入 SCL 11.8 s、下载 9.6 s,客户端的 60 s 默认超时会在这些"正常慢"的地方先炸,让人误以为是失败。

三、一个需求,从提示词到能跑的程序

看完整链路前,先看最要紧的三样东西:需求、提示词、产出。

需求(工程师原话,两台电机的顺序启动):

  • 一台启动按钮启动 1 号电机;1 号运行 3 秒后自动启动 2 号
  • 停止按钮(常闭)或任一电机故障 → 两台立即全停
  • 两台各有运行输出,定时用 IEC 定时器
  • 逻辑写成一个可复用的 FB,OB1 调用
  • 输入输出走 M 区:M0.0 启动、M0.1 停止(常闭)、M0.2 故障、M0.3 1 号、M0.4 2 号

提示词(实际下发的那段,原文照抄):

【需求】两台电机的顺序启动控制
- 一台启动按钮启动 1 号电机;1 号电机运行 3 秒后自动启动 2 号电机
- 停止按钮(常闭)或任一电机故障时,1 号、2 号电机立即全部停止
- 两台电机各有运行输出,定时用 IEC 定时器
- 逻辑写成一个可复用的 FB,OB1 里调用它
- 输入输出用 M 区:M0.0 = 启动按钮,M0.1 = 停止(常闭,1 表示允许),M0.2 = 故障,
  M0.3 = 1 号电机,M0.4 = 2 号电机

【要求】
1. 自己决定步骤和工具,把它们下发到 PLC_3 并编译通过(0 错误)
2. 编译通过后下载到 S7-PLCSIM Advanced,创建全新的实例名,运行后用场景验证
3. 不要保存工程
4. 最后贴出完整的 SCL 源码和实测数值

没有指定"先读工程、再建块"这类步骤,也没给 SCL 模板——步骤和工具是它自己选的。

产出(它写出来的 FB,接口 + 实现):

FUNCTION_BLOCK "FB_MotorSeq"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT
      Start : Bool;             // 启动按钮(M0.0)
      StopPermit : Bool;        // 停止按钮 常闭,1=允许运行(M0.1)
      Fault : Bool;             // 故障(M0.2)
      RunDelay : Time := T#3S;  // 2 号电机延时
   END_VAR
   VAR_OUTPUT
      Motor1 : Bool;            // 1 号电机运行(M0.3)
      Motor2 : Bool;            // 2 号电机运行(M0.4)
   END_VAR
   VAR
      statRun : Bool;           // 运行自锁
      statPermit : Bool;        // 允许运行
      rtStart : R_TRIG;         // 启动按钮上升沿
      tonRun2 : TON_TIME;       // IEC 延时定时器
   END_VAR
BEGIN
    // 允许运行:停止按钮常闭点闭合(1)且无故障
    #statPermit := #StopPermit AND NOT #Fault;

    // 启动上升沿置位自锁;停止/故障立即复位
    #rtStart(CLK := #Start);
    #statRun := (#rtStart.Q OR #statRun) AND #statPermit;

    // 1 号电机立即运行,2 号电机在 1 号运行 RunDelay 之后启动
    #Motor1 := #statRun;
    #tonRun2(IN := #Motor1,
             PT := #RunDelay);
    #Motor2 := #statRun AND #tonRun2.Q;
END_FUNCTION_BLOCK

OB1 里调用它,把它接到 M 区:

ORGANIZATION_BLOCK "Main"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
BEGIN
    "DB_MotorSeq"(Start := %M0.0,
                  StopPermit := %M0.1,
                  Fault := %M0.2,
                  RunDelay := T#3s,
                  Motor1 => %M0.3,
                  Motor2 => %M0.4);
END_ORGANIZATION_BLOCK

编译:state=Success, errorCount=0, warningCount=0,Main (OB1) 与 FB_MotorSeq (FB1) 都通过。

这段代码有两个地方值得看:启动用了上升沿 R_TRIG(否则按住按钮会一直置位),以及停止/故障走的是 #statPermit 这一条独立通路,不经过定时器。后者正是下面第三个场景要验的东西。

四、全链路实测:从空工程到跑起来的 9 步

同一台机器上的一次完整下发,从空设备到一个能跑的程序,每一步的实际耗时如下。

# 动作 实测耗时
1 探活:确认网关连上了博途、当前工程名、设备数、前置检查 < 1 s
2 从硬件目录里查 CPU 型号 6ES7 516-3AN02-0AB0 / V2.9 ~1 s
3 建 CPU(PLC_2,CPU 1516-3 PN/DP V2.9) 2.2 s
4 导入 FB(SCL 源码,导入后自动生成块) 11.8 s
5 导入单实例 DB + 调用它的 OB1 各 0.6 s
6 编译 1.4 s
7 建虚拟 PLC 并上电 ~6 s
8 下载到 S7-PLCSIM Advanced 9.6 s
9 运行、写变量、读变量 < 100 ms/次

第 4 步之后有个细节值得知道:导入不等于编译,块的"已编译"标记还是空的,这时候连导出都会被拒(Block is inconsistent (not compiled))。所以"导入 → 编译 → 再读"这个顺序不是建议,是硬约束。

第 8 步的返回很能说明这套东西的可信度——它把 TIA 的结果树完整摊开:

target device: PLC_2 6ES7 516-3AN02-0AB0 FW V2.9
removed PLC protection for the simulated PLC: master secret (WithoutPassword), access level (was NoAccess)
Success: PLC_2
  Success: Hardware configuration
    Success: Certificate configuration was loaded successfully.
    Success: Hardware configuration was loaded successfully.
    Success: Connection configuration was downloaded successfully.
    Success: Routing configuration was loaded successfully.
    Success: PLC_2 started.
  Success: 'DB_MotorCtrl' / 'FB_MotorCtrl' / 'Main' were loaded successfully.

如果只回一句 Success: PLC_2,你分不清它是真下去了,还是只是回了个成功。

五、三个场景:数值对不对得上

先看时序,再看数值:

M0.0 启动脉冲 → 1 号电机立即运行 → 3.12 s 后 2 号电机启动 → 停止或故障时两台在同一扫描周期内归零

编译通过只说明它能进 PLC。下面三个场景是在仿真器里跑出来的,同一套 M 区读写。

场景 操作 观测 结论
启动 M0.1=1(允许),M0.0 打一个脉冲 1 号电机立即 =1;3.12 s 后 2 号电机 =1;松开启动按钮后两台保持 延时设定 T#3s,误差来自 150 ms 轮询粒度
停止 两台运行中,M0.1 → 0 同一个采样点两台同时 =0;恢复 M0.1=1 后不自动重启 停止走的是立即断开通路,且不会自己恢复
故障 两台运行中,M0.2 → 1 13 ms 内(一次扫描)两台全停;故障复位后仍不自动重启 故障优先级高于一切,需人工重新启动

三个场景对应三件事:

  • 3.12 s 证明定时器接的是"1 号电机运行"这个条件,而不是"按下启动按钮"——差这一层,实际设备上就是"按钮一松 2 号就不来了"。
  • 同一个采样点全停证明停止通路没被定时器拖住。这类错误编译期查不出来,现场也未必复现,只有跑场景才看得见。
  • 13 ms + 不自动重启证明故障是独立的锁断条件,且不会自愈——这条在真实设备上决定"要不要人按复位"。

另一台设备上我们还跑过一次"启动延时 2 s"的类似逻辑:定时器设定 2 s、实测 2.16 s,断开 0.06 s 内归零。两次的偏差都在一个采集周期量级,说明延时和断开两条路径的行为是稳定的。

六、读完再信:Success 之外还核对了什么

下载成功后我们没有直接收工,而是把块导出成 SimaticML 做离线核对——因为"下载成功"只说明数据下去了,不说明下去的是你写的那份。

对象 导出体积 核对点
Main(OB1) 7,766 B 确实调用了 DB_MotorCtrl,实参是 %M0.0/0.1/0.2,输出 => %M0.3
FB_MotorCtrl(FB1) 15,978 B 定时器用的是 IEC TON,没有夹带别的 FB 实例
DB_MotorCtrl(DB1) 6,903 B 单实例、consistent: true

为什么用导出而不是"再读一遍块内容":导出是可归档、可 diff 的文本,改前改后一对比就知道谁动了什么,这也正好是验收清单里"改前归档"那条的落地方式。块的元数据里还有两个便宜信号:编程语言说明它到底是 SCL 还是 LAD,编译状态说明它编译过没有。

还有一个概念必须说清楚,网关自己的说明里写得很直白:Nothing is persisted until POST /save。导入、硬件写、删除、编译全部只在内存里,只有显式保存才落盘。这既是可回滚性(写坏了不 save 就等于没写),也是坑——如果你没 save 就以为改完了,关掉博途那一刻什么都没了。我们的做法是先不 save 跑完验证,通过了再一次 save。

七、上线前的验收清单

八条,按顺序过,一条不过就别往下走:

  1. 先只读。让它读项目树、块、交叉引用,确认它"看懂"了你的工程,再谈写。
  2. 写只开预览。网关支持预览模式,跑一周,把它预览出来的 diff 和人写的比。
  3. 必须带回读校验。写完导出 SimaticML 或读回 contentHash,不一致就当没写。
  4. 单项目、单会话、串行写。Openness 侧本来就是串行的,多个 Agent 并发写只会造出半成品。
  5. 编译当门禁。编译过不等于逻辑对,但编译不过一定不能提交——这条是唯一可以完全自动化的门禁。
  6. 改前先归档。VCI 或 Git 把块导成可比对的文本,出问题能一眼看出改了什么。
  7. 审计留痕。谁、什么时候、用什么模式、改了哪个对象。
  8. 别把下载/上线交给无人值守的 Agent。要下装到真机,人在回路、单步确认、有回滚预案。

再加一条红线:AI 生成的 SCL 必须人工复核,尤其急停、互锁、F 程序。工具能保证"写进去了",保证不了"写得对"。

八、版本与边界:先对号再动手

项目 实测结论
博途版本 V19 / V20(本次实测 V19 + Openness 19.0)
Openness 随博途安装,版本严格匹配;本机实测 Openness 19.0(2 个程序集)
仿真器 S7-PLCSIM Advanced 6.0,Softbus 模式;CPU 固件要够新(本文实测 V1.1 失败、V2.9 通过)
部署形态 网关必须与博途同机;智能体可在另一台机器,只要能访问网关的 HTTP 端口
工具规模 本版 34 个工具(读写块、硬件、网络、编译、导出、仿真、LAD 规范各一组)

关于"只能在同机"这条常见误解要澄清一下:MCP 网关必须和博途同机,但调用它的智能体不必。本文所有调用都是从另一台机器发 HTTP 请求过去的——本文所有调用都是从另一台机器发 HTTP 请求过去的。

再补一条容易被问到的日志行:成功下载的返回里有一句 removed PLC protection for the simulated PLC: master secret (WithoutPassword), access level (was NoAccess)。意思是网关在下载前会把仿真 PLC 的保护临时抹掉(否则块根本写不进去),而这句出现在日志里,总比它默默做掉、让你事后猜要强。

九、想自己跑一遍

要的东西只有两样:一台装了博途 V19 / V20 的 Windows 机器,和装在同一台机器上的 TiaLink。 装完它会在 http://localhost:8080/ 给出网关地址,客户端那边加上第二章那一条配置就通了。

安装方式与版本支持看产品页; 想让模型先读懂工程再动手,配套的 TIA-Context 负责把块、变量表、调用关系喂给它。

跑通之后最容易犯的错,是让它一次写太多。从一个小块、一个有测试用例的改动开始,比丢给它"帮我重构这个项目"稳得多——同一套工程的 WorkBuddy 版本里也是这个结论(AI 驱动的 PLC 程序开发)。


相关阅读:AI 改博途程序:TIA Openness MCP 的写保护与边界 | OPC UA MCP 上手实测:读数据、浏览节点、写设定值 | AI × 工业 / PLC 完全指南 | AI 编程 / Vibe Coding 完全指南

来源与版本:TiaLink 1.3.2.0(工具清单、前置检查项、下载结果树均由网关返回);S7-PLCSIM Advanced 6.0;Claude Code 2.1.311 的 claude mcp add --help 帮助文本;博途 V19。文中耗时与报错原话来自 2026-10-27 的运行记录。

本文由汇智网原创整理,转载请注明出处。AI 生成的 PLC 程序必须经人工复核后才能用于生产。