
简介面向TwinCAT 3自动化工程师的版本控制实战指南讲解如何利用集成在TwinCAT 3.1.4024中的AdsGitServer在不安装外部Git软件的前提下完成PLC程序的提交、拉取、版本比较与回退为协同开发提供统一环境。资源为1个PDF文件大小1.77MB内容出自Beckhoff华南区技术工程师之手基于实际测试整理含准备工作、操作步骤、常见问题等完整章节。已有369人学习下载适合需要提升PLC工程管理效率、实现多人协作的TwinCAT开发者。文档详细介绍了启用Multiuser、初始化Git Server、历史版本查看与恢复、从PLC上传源程序等方法并对Init创建失败、提交两个版本时的冲突处理等典型问题给出排查思路可直接对照操作减少踩坑。1. AdsGitServer 解决的是现场版本管理的最后一公里开发机上的 TwinCAT 3 工程放进 Git 管理已经不算新鲜事真正让人头疼的是产线运行时的设备PLC 程序、配方、HMI 画面散落在工控机的各个目录里谁改过、改了什么、能不能回滚很多时候全靠现场工程师的记忆。AdsGitServer 就是把 Git 仓库变成 ADS 服务的一种落地方式运行时的设备通过 ADS 协议连到服务端直接在 PLC 逻辑里提交版本、拉取历史、恢复快照不需要在工控机上装 Git 客户端更不需要开放乱七八糟的网络端口。这个方案适合设备集成商做售后运维也适合工厂 IT 把散落在多条产线上的版本收口到一个仓库统一审计。下面按一次完整部署路径展开从通信模型到配置、调用和常见故障照着走一遍能少踩一半坑。2. 先理解 AdsGitServer 的通信与仓库模型ADS 服务端把 Git 桥接给 PLC2.1 为什么是 ADS复用 TwinCAT 路由器不开放额外端口TwinCAT 3 内部所有设备之间的通信都走 ADS 协议而 ADS 请求统一由 TwinCAT Router 转发。Router 按“AMS NetId 端口号”寻址NetId 是设备的唯一标识形如192.168.0.11.1.1端口号则是设备上具体的服务入口。AdsGitServer 做的事情就是在这套寻址机制里注册一个自己的端口把 Git 操作封装成几条 ADS 命令写文件、提交、拉取、打标签、查状态。选择 ADS 而不是直接开 HTTP 服务原因是工程上的便利。工业现场工控机经常被 IT 安全策略限制端口HTTP、FTP 这类服务要过防火墙审批而 ADS 走的是 TwinCAT Router 自己维护的通道只要 Router 能通信AdsGitServer 就能被访问。这意味着 PLC、HMI、上位机天然都能调用它不需要为每个客户端单独装 Git 和配置认证。权限也可以收敛在 ADS 路由层对外根本不暴露任何 TCP 端口。2.2 仓库布局裸仓库、共享分支与文件暂存区AdsGitServer 服务端的仓库布局我一般建议“一个根目录、多仓库、每个设备一条分支”。RepositoryRoot下建子目录作为独立仓库一台设备一个仓库或者所有设备共用一个仓库而用子目录隔离。复用同一仓库便于做全厂审计但要注意分支隔离每台设备维护自己的分支发布时打 tag避免现场误推送到别人的分支。这里要区分裸仓库和带工作树的仓库。裸仓库只有 Git 内部对象没有检出文件适合纯归档场景不会产生文件锁冲突。但 AdsGitServer 经常需要“从仓库取某个文件返回给 PLC”所以常见做法是配置一个TempWorkDir作为临时检出目录读取文件时把指定版本检出到临时目录再通过 ADS 返回内容写入时先落临时目录再执行git add和git commit。这样的好处是正式仓库始终保持干净临时目录脏了无所谓重启后自动重建。2.3 一次提交请求的完整链路理解链路比记住命令更重要。一次提交在逻辑上经历五步PLC 里的功能块组装负载内容比如 XML 格式的参数、配方数据、版本号字符串。PLC 把负载通过AdsWrite发送到 AdsGitServer 的 ADS 端口命令字为 Commit。服务端将负载写入TempWorkDir中对应的相对路径。服务端调用 Git 命令完成add和commit提交信息可以带设备名和版本号。服务端返回状态码PLC 收到后更新本地的版本状态变量。这段链路里最容易出问题的不是 Git 本身而是第 2 步的寻址参数。AMS NetId 写错、端口号与服务端配置不一致、Router 路由缺失都会表现为超时或错误码。后面我会单独讲排查方法这里只需要建立整体认识AdsGitServer 是一个 ADS ServerPLC 是 ADS ClientGit 命令被完全封装在服务端内部。3. 部署与最小配置把 AdsGitServer 挂在工控机上并用路由连通3.1 工控机上的依赖检查与安装顺序AdsGitServer 依赖三样东西TwinCAT Router提供 ADS 路由能力、Git for Windows提供 Git 命令、以及运行环境按服务端实现可能是 .NET 运行时。安装顺序有讲究先装 Git 再装服务端因为服务端第一次启动时要探测 Git 可执行文件路径。装完后先验证依赖git --version sc query TcRTR | findstr STATE第一行确认 Git 可用输出类似git version 2.43.0.windows.1。第二行确认 TwinCAT Router 服务处于 RUNNING 状态服务名在不同版本里可能叫 TcRTR 或 TwinCAT System Service以现场实际服务名为准。如果 Router 没起来AdsGitServer 即使启动也注册不上 AMS 端口。3.2 配置文件逐项说明端口、仓库根目录与临时目录常见实现用一个 JSON 配置文件关键字段如下{ Server: { AdsPort: 29100, RepositoryRoot: D:\\GitRepos, TempWorkDir: C:\\AdsGitTemp }, Git: { GitExecutable: C:\\Program Files\\Git\\cmd\\git.exe, DefaultBranch: main }, Sync: { AutoPullOnRead: true, TimeoutSec: 30 } }参数说明字段取值建议说明AdsPort29100ADS 服务端口必须选未被占用的高位端口同一进程内唯一RepositoryRootD:\GitRepos仓库根目录建议单独一块 NTFS 卷便于配额和权限管理TempWorkDirC:\AdsGitTemp临时检出目录可被清理重启后自动重建GitExecutable实际安装路径服务端调用 Git 命令的可执行文件路径DefaultBranchmain新仓库初始分支名与团队规范保持一致AutoPullOnReadtrue读取前先执行git pull保证临时检出内容是最新的TimeoutSec30单次 Git 操作超时避免极端情况下命令挂死注意AdsPort不是 TwinCAT 系统端口而是 AdsGitServer 自己占用的端口端口范围不能落在系统保留范围内。我这里写 29100 是因为它避开了大部分默认服务具体值要查看工控机上现有服务占用情况后再定。3.3 让 TwinCAT Router 认识 AdsGitServer路由配置AdsGitServer 与 PLC 在同一台工控机上时NetId 就是本机地址路由天然可用。如果服务端放在独立服务器上必须加静态路由否则 PLC 根本寻不到目标 NetId。常见做法是通过 TwinCAT XAE 环境的路由设置界面在开发机上打开 TwinCAT 工程进入“Router”设置添加一台远程设备填写服务器电脑的名称和 AMS NetId。服务端电脑也需要反向加一条指向开发机/PLC 的路由否则 ADS 响应回不来。配置保存后会写入StaticRoutes.xml文件所以也可以直接编辑该文件再重启 Router 服务效果相同。检查路由是否生效最直接的方法是在开发机上用 TwinCAT 自带的 ADS 诊断功能读取远程设备状态。能读到就说明路由通了接下来才进入服务自检。3.4 启动自检确认服务注册成功服务启动后要确认它确实注册到了 AMS 网络上。常见做法是读一个版本号或服务状态符号AdsGitServer 如果暴露 ADS 符号可以直接在 TwinCAT 的在线监视里加变量读如果不暴露符号就发一条自定义的 Ping 命令成功时返回固定响应码。这里的关键是先用最简单的请求验证寻址通路不要一上来就提交真实文件。我这边常用的命令格式是这样netstat -ano | findstr 29100如果端口监听正常能看到对应 PID 的 LISTENING 记录说明服务进程起来了。但 ADS 是应用层协议不经过 TCP 监听端口所以这个检查只是辅助。真正有效的是从 PLC 侧发请求能收到成功码才是硬标准。4. 在 TwinCAT 3 工程里调用 AdsGitServer提交、回滚与自动比对4.1 PLC 端访问 ADS 服务调用接口的封装思路PLC 端使用 TwinCAT 3 的 Tc3_Ads 库核心函数就是AdsWrite和AdsRead。不要把裸调用散落在主程序里我会封装一个功能块FB_AdsGitClient输入是命令号、仓库名、相对文件路径、负载内容和版本标记输出是 Done、Error 和 ErrorID。FUNCTION_BLOCK FB_AdsGitClient VAR strNetId : T_AmsNetId : 192.168.0.11.1.1; nPort : WORD : 29100; nCmdCommit : WORD : 16#04D0; nCmdRead : WORD : 16#04D1; bBusy : BOOL; bDone : BOOL; hr : UDINT; nWritten : UDINT; nReceived : UDINT; sPayload : STRING; sResponse : STRING; END_VARstrNetId是 AdsGitServer 所在工控机的 AMS NetId必须和路由配置一致nPort就是 JSON 里的AdsPort字段。命令号需要查服务端接口说明这里16#04D0和16#04D1只是示例值真实值以你实际部署的版本为准。封装的好处是主程序只需要关心业务内容不需要每次处理 ADS 细节。4.2 最小提交把当前参数快照写入仓库假设要把一串参数写入仓库的params/目录下负载格式约定为“仓库名;相对路径;版本说明;内容”。提交在 PLC 侧只需一次AdsWriteIF bExecute AND NOT bBusy THEN sPayload : CONCAT( LineA_Packager;, params/recipe_20250530.xml;, v1.2.3 更换气缸参数;, sXmlContent); hr : AdsWrite( strNetId, nPort, nCmdCommit, 0, ADR(sPayload), LEN(sPayload), ADR(nWritten)); bBusy : TRUE; END_IF IF bBusy AND hr 0 THEN bBusy : FALSE; bDone : TRUE; END_IFsXmlContent是 PLC 里动态拼出来的 XML 参数LEN(sPayload)告诉 ADS 要传多少字节。注意AdsWrite的返回值和 ADS 错误码不一样hr 大于 0 通常表示请求已投递给服务端不代表 Git 操作成功。真正的提交结果还需要服务端把状态写回 PLC 的某个变量或者在下一拍用AdsRead查询。参数说明分隔符最好统一用分号因为文件路径里可能含空格内容里如果包含分号要转义或用长度前缀否则解析会错位。提交信息里带上版本号和时间后面回滚时看日志会非常方便。4.3 拉取与回滚恢复到指定版本回滚本质上是从仓库读回某个历史版本的文件内容。服务端执行的是git checkout tag -- file或直接读取某个 commit 中的文件然后通过 ADS 返回内容// 请求命令字 nCmdRead负载为“仓库名;标签;相对路径” sPayload : CONCAT(LineA_Packager;v1.2.3;params/recipe.xml); hr : AdsRead( strNetId, nPort, nCmdRead, 0, ADR(sResponse), SIZEOF(sResponse), ADR(nReceived)); IF hr 0 AND nReceived 0 THEN sRecipeXml : sResponse; // 写回 PLC 工作变量 END_IFAdsRead会把服务端返回的文件内容填到sResponse缓冲区nReceived是实际收到的字节数。读取前要确保AutoPullOnRead为 true否则服务端可能读到本地过期的检出文件。回滚后还要主动把内容重新下发到实际执行机构比如写回配方文件或更新工艺参数这一步取决于你的应用AdsGitServer 本身只管文件版本。4.4 启动时自动比对版本一个可落地的监控模式很多事故是“设备重启后跑的不是期望版本”。我习惯在 PLC 启动逻辑里加一段自动比对读当前仓库最新 tag和 PLC 里保存的sLocalVersion比较不一致就报警并禁止自动运行。// 启动后第一轮扫描 IF bInitDone THEN sPayload : CONCAT(LineA_Packager;HEAD;params/version.txt); hr : AdsRead(strNetId, nPort, nCmdRead, 0, ADR(sRemoteVersion), 32, ADR(nReceived)); IF hr 0 THEN IF sRemoteVersion sLocalVersion THEN diErrorCode : 16#1001; // 版本不一致需要人工确认 bPermissionRun : FALSE; ELSE bPermissionRun : TRUE; END_IF END_IF END_IF这样改的好处是版本信息从启动源头就被审计现场人员想绕过也难。version.txt的内容由提交方维护每次变更时同步更新比对才有意义。5. 避坑与排查AdsGitServer 落地时的高频故障与解决记录5.1 现象PLC 能 Ping 通工控机但 ADS 调用超时有一次现场报障网络通、IPC 也能访问但 PLC 里AdsWrite一直超时。查半天发现 PLC 配的 NetId 是开发机的地址而 AdsGitServer 实际跑在另一台工控机上。原因AMS NetId 是逻辑地址不等于 IP 地址。TwinCAT Router 里可以配置多个设备PLC 里写的 NetId 必须精确匹配服务端所在设备的 AMS 标识。解决在开发机路由列表里确认 AdsGitServer 所在设备显示的 NetId把 PLC 程序里的strNetId改成完全一致的字符串。这里提醒一句NetId 最后一段通常是端口标识不要想当然地省略。5.2 现象提交返回成功但仓库里看不到任何文件服务端返回了正常码可 Git 仓库空空的。这种情况多半是负载格式与服务端解析逻辑不匹配。原因常见实现把负载按固定分隔符拆成“仓库名、路径、说明、内容”如果内容里带了分隔符或 PLC 侧拼接时少了一个分号服务端会把整包内容当成文件名写进了一个莫名其妙的路径或者静默失败。解决先把负载字符串在服务端日志里打出来对照接口定义逐段检查。我在项目里直接改了分隔策略用“长度前缀 固定字段头”代替裸分号虽然调试麻烦一点但再没出过解析错位。5.3 现象提交中文路径或中文提交信息乱码Windows 简体中文环境下Git 默认把非 ASCII 路径做转义提交信息用的是系统本地编码仓库里看到的是\346\265\213这类八进制转义序列。原因Git for Windows 的默认配置是core.quotepathtrue而且提交信息编码没有显式指定 UTF-8。解决在服务端全局配置里固定两条git config --global core.quotepath false git config --global i18n.commitencoding utf-8服务端在组装 commit 命令时也要保证传给 Git 的字符串按 UTF-8 编码。这个坑通常不在 PLC 侧而在服务端调用 Git 命令行时的编码转换部署时直接写进安装脚本。5.4 现象TwinCAT 工程中间文件把仓库撑爆把整个 TwinCAT 工程目录直接提交后仓库膨胀得很快几十次提交就上 GB。原因.tmc、.compileinfo、.xti里很多可生成文件每次编译都会变化而且二进制化严重Git 无法有效压缩。解决在仓库根目录放.gitignore把生成物排除。我这边最少保留的是.plcproj、.tsproj、.xti源文件、POUs目录和符号导出文件其他一律过滤。对于配方和参数文件按“设备名/日期”分目录存放避免文件名冲突导致覆盖历史不可追溯。5.5 现象工控机重启后 AdsGitServer 连不上服务不在 Windows 服务列表里重启后没人拉起来PLC 侧所有 ADS 请求全部超时。原因AdsGitServer 常以控制台或计划任务方式运行没有配置自启动或者依赖了 TwinCAT Router 服务但启动顺序错误Router 还没就绪服务就开始注册端口。解决把服务进程注册为 Windows 服务或开机计划任务启动参数里加上“等待 TwinCAT Router 就绪”的延迟一般是 5 到 10 秒。我在现场的做法是写一个启动脚本先循环检测 Router 进程再启动 AdsGitServer比单纯加延迟可靠。6. 进阶用法把 AdsGitServer 变成产线的版本审计中枢AdsGitServer 的基本使用只是把自己从“改文件靠拷贝”升级成“改文件留痕”。真正值钱的是把 tag 规范和审计流程固化下来让每台设备都有可追溯的版本档案。我现在的习惯是给每台设备建立固定 tag 格式设备名_YYYYMMDD_版本号例如LineA_Packager_20250530_v1.2.3。每次现场变更无论大小提交后必须打 tagPLC 内部同步保存一个字符串变量sCurrentTag显示在 HMI 的维护页面操作工不用懂 Git 也能看到当前版本。验证这一整套是否可靠方法是定期对账。在服务器上执行git log --oneline --decorate --all --tags --dateshort对照产线各设备上报的版本字符串一眼能看出哪台设备落后、哪台设备没人管。更进一步可以让服务端在每次提交后自动生成一个摘要文件audit_export.txt内容包括提交人、时间、设备名、变更说明供质量和 IT 审计用。这样 AdsGitServer 就不再只是一个版本工具而是一个可以拿给客户证明“产线变更可控”的审计系统。我自己在这套方案上翻过车有次某工程师在现场改了配方没提交设备换料后重启工艺参数对不上排查了四个小时最后发现是人工改的直接磁盘文件。后来养成的习惯是“改完必须提交、提交必须打 tag、重启必须比对”三件事做齐才允许设备重新投入生产。再往后现场故障少了很多因为所有变更都有底账复现问题能直接从历史版本里找差异。这套方案越早铺越划算。一台设备的版本管理看起来很轻但十条产线、几十台设备同时运行时没有统一通道就是一团乱麻。希望帮到你至少让你在决定做版本管理时能少走一点我走过的弯路。本文还有配套的精品资源点击获取