BNS Lang:用数字键盘语言革新PLC梯形图编程
1. 项目概述当PLC编程遇上“数字键盘语言”如果你是一名工业自动化工程师或者接触过可编程逻辑控制器PLC的梯形图编程那么你一定对那种在集成开发环境IDE里用鼠标拖拽触点、线圈、分支线的操作模式又爱又恨。爱的是它的直观——电气原理图般的可视化逻辑恨的是它的繁琐——画一个简单的自锁电路可能都需要点击十几次鼠标版本管理更是噩梦总不能把整个项目文件夹的截图都塞进Git吧今天要聊的这个项目BNS Lang就是为了解决这个痛点而生的。它本质上是一个领域特定语言其核心设计哲学可以用一句话概括只用数字键盘和几个符号就能写出完整的PLC梯形图逻辑。是的你没看错它把梯形图编程从“图形化拖拽”变成了“文本化编写”。想象一下你不再需要打开臃肿的IDE而是在任何文本编辑器甚至是终端里敲下1 2 50就能生成一个“当X1和X2都导通时输出Y50”的经典与逻辑梯形图。这对于需要快速原型验证、批量生成逻辑、或者追求极致开发效率的团队来说无疑打开了一扇新的大门。这个项目更深层的价值在于它试图为工业自动化这个相对传统的领域引入现代软件开发的工具链和思维。版本控制Git、持续集成CI/CD、AI辅助编程通过Cursor/Claude Code这些在Web或应用开发中司空见惯的概念通过BNS Lang这个文本化的桥梁可以无缝地接入到PLC开发流程中。它不仅仅是一个编译器更是一个面向未来的PLC开发范式探索。2. 核心设计思路为何是“数字键盘DSL”2.1 从图形到文本的范式转换传统的PLC梯形图编程是高度图形化和交互式的。这种方式的优势在于与电气图纸一一对应易于电气工程师理解和排查。但其劣势也同样明显效率瓶颈复杂的逻辑意味着大量的鼠标操作定位、连线、设置参数速度远不如键盘输入。难以版本化梯形图文件通常是二进制或专有格式diff操作几乎不可能你无法清晰地知道两个版本之间具体修改了哪一行逻辑。不利于自动化你很难用一个脚本批量生成或修改成百上千个类似的逻辑段。BNS Lang的设计者敏锐地抓住了这些痛点并做出了一个关键决策不尝试去模拟或替代图形化IDE的交互而是彻底转向文本领域。文本是程序员最熟悉、工具链最完善的媒介。一旦逻辑被表达为文本所有现代软件工程的最佳实践——如代码审查、静态分析、自动生成——就都有了用武之地。2.2 语法设计的极简主义与实用性BNS Lang的语法设计是其精髓所在它严格遵循了“数字键盘友好”的原则。让我们拆解一下它的设计考量为什么用数字代表地址这是最直观的映射。在大多数PLC系统中输入输出点就是以数字地址来标识的如X1, Y50。直接使用数字减少了记忆成本输入速度也最快。项目预设的地址映射表0-99是X 100-199是Y作为触点等覆盖了大部分基础应用场景且允许按目标PLC进行配置兼顾了通用性与灵活性。为什么用空格和“”代表串联AND用“|”代表并联OR空格/“”在文本中表示“接着”、“然后”是最自然的。1 2读作“X1然后X2”在逻辑上就是“X1与X2”。加号“”是AND逻辑在数学表达式中的一种常见直观表示虽然严格意义上AND是乘法但在此上下文中“叠加”之意更易懂。“|”这个符号在正则表达式和许多编程语言中代表“或”选择它符合程序员的直觉。在键盘上它通常与反斜杠共享一个键输入也很方便。“”赋值或输出的经典符号用来驱动线圈再合适不过。“-”作为前缀表示“非”NC常闭触点例如-2代表NOT X2。负号表示“取反”非常形象。这种设计的结果是一个经验丰富的工程师在看到1 -2 | 110 10这行代码时能瞬间在脑中构建出对应的梯形图一个启动按钮X1、一个停止按钮常闭X2、一个自锁触点Y10作为常开触点地址映射为110并联最终输出到电机线圈Y10。这种“所见即所得”的文本逻辑映射是BNS Lang成功的关键。实操心得语法记忆技巧刚开始接触时可以这样联想把一行BNS代码想象成你在用键盘“画”梯级。你从左母线开始“敲”敲一个数字1就是放上一个X1的常开触点。敲一个空格就是向右移动一格准备放下一个触点串联。敲一个|就是画一条向下或向上的分支线并联开始。敲一个就是画到了右母线准备放置线圈。 多练习几次肌肉记忆就会形成输入速度会远超鼠标操作。2.3 架构设计清晰的编译流水线项目的架构非常清晰采用了经典的编译器设计模式词法分析器将输入的文本流如1 2 50拆分成一个个有意义的“单词”令牌如数字1、数字2、操作符、数字50。语法分析器根据BNS Lang的语法规则将这些令牌组织成一棵抽象语法树。这棵树定义了操作的优先级和结构例如它能理解|的优先级低于空格/以及括号()的成组作用。中间表示AST可以进一步转换为一种与具体PLC型号无关的中间表示方便后续处理。代码生成器这是后端根据目标PLC的类型将IR或AST翻译成对应的程序代码。目前主要支持IEC 61131-3标准的结构化文本这是一种高级的、类Pascal的PLC文本语言也是各大品牌PLC的通用标准之一。这种架构的优势是可扩展性强。要支持一个新的PLC品牌比如西门子S7理论上只需要开发一个新的代码生成器模块而不需要改动前端的词法、语法分析逻辑。项目路线图中规划对西门子、三菱的支持正是基于此架构的便利。3. 语法详解与实操指南理解了设计思路我们来深入看看BNS Lang的语法细节以及如何用它来表达常见的PLC控制逻辑。3.1 基础元件与操作符实战让我们结合实例把语法表中的每一个元素都“用”起来。基本逻辑电路与逻辑X1 AND X2 - Y50BNS: 1 2 50 梯形图: ──┤ X1 ├──┤ X2 ├──( Y50 )或逻辑X1 OR X2 - Y50BNS: 1 | 2 50 梯形图: ──┤ X1 ├──┬──( Y50 ) └──┤ X2 ├──┘非逻辑NOT X1 - Y50BNS: -1 50 梯形图: ──┤/X1 ├──( Y50 )组合逻辑与括号分组一个稍复杂的例子(X1 AND X2) OR (X3 AND X4) - Y50。在梯形图中这通常需要两个并联的支路每个支路串联两个触点。BNS: (1 2) | (3 4) 50或者利用空格即串联的规则可以更简洁地写为BNS: 1 2 | 3 4 50语法分析器会正确解析为两个串联组1 2和3 4进行并联。括号在逻辑非常复杂、优先级容易混淆时特别有用。自锁自保持电路这是电机控制中最经典的电路启动按钮X1 常开按下后电机Y10得电并通过自身的常开触点Y10实现自锁直到停止按钮X2 常闭被按下。BNS: 1 -2 | 110 10这里有一个关键细节110代表的是输出点Y10作为常开触点使用。根据地址映射表100-199是“输出作为触点”的地址范围。所以110对应的是Y10这个线圈的触点状态。线圈10驱动的是实际的Y10输出。这样就完美复现了自锁结构。置位与复位在PLC中SET置位和RESET复位是保持型输出常用于模式切换、报警锁定等场景。! 50表示对Y50进行置位操作锁存为ON。/ 50表示对Y50进行复位操作锁存为OFF。 例如一个报警复位电路报警条件X1触发后置位报警灯Y50复位按钮X2按下后复位它。BNS: 1 ! 50 BNS: 2 / 503.2 定时器与计数器的使用定时器和计数器是PLC编程的灵魂。BNS Lang对它们的支持非常直观。定时器假设我们需要一个延时接通定时器TON编号为T300定时时间为5秒5000毫秒。BNS: 300 5000这行代码会被编译为对应的结构化文本定时器功能块调用。在生成的ST代码中你可能会看到类似这样的结构TON_300(IN:SomeCondition, PT:T#5000MS); IF TON_300.Q THEN // 定时器到时的逻辑 END_IF;注意BNS代码300 5000本身只是声明了一个定时器资源和预设值。这个定时器何时开始计时IN端条件以及其输出触点Q用在何处需要在其他逻辑行中通过使用地址300代表T300的触点来体现。例如BNS: 1 300 // X1导通时启动定时器T300这里假设用于定时器启动具体语义需看编译器实现 BNS: 300 50 // T300到时输出Y50实际上在标准的BNS用法中300这个地址可以直接作为常开触点用在逻辑行里编译器会识别它是定时器触点并生成正确的ST代码。计数器计数器同理C5 100声明了一个计数器C5预设值为100。地址400-499用于计数器触点。例如一个上升沿计数器BNS: 1p 400 // X1的上升沿触发计数器C5假设p代表上升沿具体语法需确认 BNS: 400 50 // C5计数值达到100时其触点接通输出Y50 BNS: 2 / 400 // X2复位计数器C5注意事项定时器/计数器的细节不同品牌的PLC其定时器、计数器的编号范围、功能块调用方式可能有细微差别。BNS Lang的代码生成器需要为目标PLC做适配。例如LS Electric XGT和西门子S7-1200的定时器指令格式就不同。在编写涉及这些功能的BNS代码时务必查阅对应目标PLC的BNS映射文档了解地址范围的具体含义和特殊语法如上升沿p后缀是否支持。3.3 注释与代码组织良好的编程习惯离不开注释。BNS Lang使用#符号作为行注释的开始。# 这是一个注释 # 电机启动控制回路 1 -2 | 110 10 # X1启动X2停止Y10自锁使用---三个减号可以作为逻辑行之间的视觉分隔符让代码更清晰但它没有语法意义编译器会忽略。# 区域A输送带控制 1 2 50 --- # 区域B报警灯控制 3 | 4 51 ---4. 从安装到编译完整开发流程让我们抛开理论从头开始实际操作一遍看看如何用BNS Lang完成一个简单的项目。4.1 环境准备与安装BNS Lang是一个Node.js工具所以首先需要确保你的系统安装了Node.js环境建议版本14或以上。安装Node.js前往Node.js官网下载并安装适合你操作系统的版本。安装完成后在终端输入node -v和npm -v能显示版本号即表示成功。全局安装BNS Lang CLI打开终端或命令提示符执行以下命令。-g参数代表全局安装这样你可以在任何目录下使用bns命令。npm install -g bns-lang安装过程可能会持续一两分钟。完成后输入bns --help如果看到一列命令说明如compile,check,ladder恭喜你安装成功了。4.2 第一个BNS程序电机启停控制让我们创建一个最简单的电机启停控制程序。创建项目文件夹和文件mkdir my-first-bns cd my-first-bns touch motor_control.bns编辑BNS文件用你喜欢的文本编辑器VSCode, Sublime Text, Vim, 甚至记事本打开motor_control.bns输入以下内容# 电机启停控制程序 # X1: 启动按钮 (常开) # X2: 停止按钮 (常闭) # Y10: 电机接触器线圈 # M100: 内部继电器用于自锁逻辑可选这里直接用Y10触点 1 -2 | 110 10 # 主逻辑启动 OR 自锁且未被停止保存文件。语法检查在编译前可以先检查语法是否正确。bns check motor_control.bns如果文件没有语法错误命令行不会有输出静默成功。如果有错误比如拼写错误1 -2 | 11o 10o不是数字它会提示具体的错误行和原因。编译为结构化文本现在我们将它编译成标准的IEC 61131-3结构化文本这是最通用的格式。bns compile motor_control.bns -o motor_control.st打开生成的motor_control.st文件你会看到类似以下内容(* Generated by BNS Lang v2.0 *) (* 电机启停控制程序 *) PROGRAM MAIN VAR X1 AT %IX0.1 : BOOL; X2 AT %IX0.2 : BOOL; Y10 AT %QX1.10 : BOOL; END_VAR Y10 : ((X1 AND NOT X2) OR Y10); END_PROGRAM这段ST代码完全等价于我们编写的BNS逻辑可以直接导入到支持IEC 61131-3标准的PLC编程软件中如CODESYS、TwinCAT等或者经过简单适配后用于特定品牌PLC。查看梯形图如果你怀念图形化的视图BNS Lang甚至能生成ASCII艺术版的梯形图。bns ladder motor_control.bns输出会是──┤ X1 ├──┤/X2 ├──┬──( Y10 ) └──┤ Y10 ├──┘虽然简陋但逻辑关系一目了然非常适合在终端里快速预览或在纯文本文档中展示。4.3 进阶示例交通灯控制让我们尝试一个更复杂的例子——一个简单的两相位交通灯控制。假设相位A绿灯Y1亮10秒 - 黄灯Y2亮3秒 - 红灯Y3亮。相位B与相位A互补由相位A的红灯触发。使用定时器T110秒、T23秒。这个逻辑用BNS Lang可以这样编写traffic_light.bns# 交通灯控制 - 相位A # 启动条件系统启动或相位B完成这里简化用M0作为启动/循环标志 0 ! 1 # 置位启动标志M0假设M0地址为0 # 相位A绿灯 0 -3 1 # M0启动且A红灯未亮(Y3)则A绿灯亮(Y1)。同时启动10秒定时器。 1 300 10000 # Y1导通时启动定时器T30010秒 # 相位A黄灯 300 -301 2 # T300到时且T301未到时A黄灯亮(Y2)。启动3秒定时器。 300 301 3000 # T300到时启动定时器T3013秒 # 相位A红灯 301 3 # T301到时A红灯亮(Y3)。同时复位A绿灯、黄灯并触发切换到相位B。 301 / 1 301 / 2 301 ! 100 # 置位相位B启动标志M100 # 相位B逻辑与A对称地址不同 100 -103 4 # M100启动且B红灯未亮(Y6)则B绿灯亮(Y4) 4 302 10000 # 启动B绿灯定时器T302 302 -303 5 # B黄灯亮(Y5) 302 303 3000 # 启动B黄灯定时器 303 6 # B红灯亮(Y6)复位B绿灯黄灯并重新触发相位A 303 / 4 303 / 5 303 ! 0 # 重新置位相位A启动标志M0循环开始 303 / 100 # 复位相位B启动标志这个例子展示了如何使用定时器地址300,301等作为触点条件以及如何用内部继电器地址0,100作为程序步进的标志位。编译后你会得到一段相当长的结构化文本清晰地描述了整个状态转移过程。实操心得逻辑分段与注释对于复杂的顺序控制强烈建议使用注释和分隔符将逻辑分段如上例所示。每一段对应工艺的一个步骤或一个状态。在BNS文件中你可以自由地使用空行和注释来组织代码这对后期维护和团队协作至关重要。BNS Lang的文本特性使得这种良好的编程习惯能够被轻松践行。5. 与现代开发工具链的集成BNS Lang的真正威力在于它能无缝融入现代软件开发流程。5.1 版本控制与协作现在你的PLC程序就是一个纯文本的.bns文件。你可以把它放入Git仓库git init git add traffic_light.bns git commit -m “feat: 初始交通灯控制逻辑”当同事修改了逻辑你可以通过git diff清晰地看到哪一行被增加、删除或修改了就像对比任何其他源代码一样。这彻底改变了PLC程序的协作和审计方式。5.2 与AI编程助手深度集成Cursor/Claude Code这是BNS Lang最具前瞻性的特性。项目内置了对模型上下文协议的支持。这意味着你可以直接在Cursor或Claude Code这样的AI编程编辑器里用自然语言描述控制逻辑AI助手会调用BNS Lang的工具来生成、验证、甚至可视化代码。配置MCP服务器以Cursor为例确保你的项目根目录下有BNS Lang的源代码或已安装的模块。Cursor会自动读取项目中的.cursor/mcp.json配置文件。该文件已经指向了BNS Lang的MCP服务器脚本。重启CursorAI助手就获得了四个新工具bns_compile,bns_check,bns_ladder,bns_explain。工作流演示 你在Cursor的聊天框中输入“帮我写一个仓库卷帘门的控制程序。要求开门按钮X1按下门电机正转Y1启动直到上限位X3触发停止关门按钮X2按下电机反转Y2启动直到下限位X4触发停止。要有互锁防止同时正反转。”AI助手可能会这样响应并操作生成BNS代码它首先理解你的需求然后生成一段BNS代码。# 卷帘门控制 # X1: 开门按钮 X2: 关门按钮 # X3: 上限位 X4: 下限位 # Y1: 正转开 Y2: 反转关 # 互锁正转时禁止反转反之亦然 1 -3 -2 -4 1 # 开门按钮无上限位未反转无下限位 2 -4 -1 -3 2 # 关门按钮无下限位未正转无上限位 3 / 1 # 上限位停止正转 4 / 2 # 下限位停止反转调用bns_checkAI自动调用语法检查工具确保生成的代码没有错误。调用bns_ladderAI将生成的ASCII梯形图展示给你看让你确认逻辑是否符合预期。调用bns_compile最后AI输出编译好的结构化文本代码。整个对话和生成过程都在编辑器内完成你无需手动运行任何命令。这极大地降低了PLC编程的门槛也提升了资深工程师原型的效率。5.3 持续集成与自动化测试在团队环境中你可以在Git仓库中设置CI/CD流水线。例如使用GitHub Actions每当有新的提交或拉取请求时自动运行bns check对所有.bns文件进行语法检查。自动运行bns compile将BNS代码编译成目标PLC如LS XGT的程序文件。甚至可以集成PLC仿真器对生成的代码进行基础的逻辑仿真测试。这确保了代码库的质量实现了PLC程序的“左移”测试。6. 常见问题与排查技巧在实际使用BNS Lang的过程中你可能会遇到一些问题。以下是一些常见情况的排查思路。6.1 编译错误与排查错误信息示例可能原因解决方案SyntaxError: Unexpected token ‘a’ at line 1BNS代码中包含非法字符。BNS只允许数字、空格、、、-、、!、/、(、)、#。Error: Address 500 out of range for coil.线圈地址超出了配置的映射范围。例如默认输出线圈Y的地址范围是0-99使用了 500。检查地址映射表。如果是输出确保地址在0-99之间。如果需要使用更大的地址可能需要自定义地址映射配置。Parse Error: Unmatched parenthesis.括号没有成对出现。仔细检查代码中的每一个(是否都有对应的)。使用编辑器的括号高亮功能辅助检查。编译成功但ST逻辑不对BNS逻辑编写有误或运算符优先级理解有偏差。使用bns ladder命令生成ASCII梯形图直观检查逻辑是否符合预期。记住优先级-取反最高然后是空格/串联最后是6.2 逻辑功能异常排查如果BNS代码编译通过但下载到PLC后行为不符合预期排查思路和传统编程类似但有了文本工具某些环节更简单。复查BNS源码用bns ladder生成视图与人脑或设计图纸中的梯形图进行比对。文本的逐行对比比在图形界面中寻找差异更高效。检查地址映射确保BNS中使用的数字地址与实际PLC硬件上的输入输出点正确对应。1是否真的是你接线的那个启动按钮50是否连接到了正确的继电器这是最常见的错误来源。审查生成的ST代码编译后的结构化文本是高级语言有时比梯形图更容易阅读复杂逻辑。检查IF/THEN/ELSE或赋值语句是否准确反映了你的意图。利用版本控制如果之前是正常的现在出了问题直接使用git diff查看最近修改了哪些逻辑行能快速定位问题引入点。6.3 性能与规模考量Q: BNS Lang适合编写大型、复杂的PLC程序吗A: 对于纯粹的逻辑控制部分BNS Lang完全胜任。它的可读性和可维护性在大型项目中甚至更有优势。然而对于复杂的模拟量处理、PID调节、结构化数据或大量的函数块调用目前BNS Lang的语法可能显得局限。这些场景通常直接在结构化文本中编写会更灵活。BNS Lang的最佳定位是快速生成和维护梯形图逻辑主体复杂算法部分可以混合编程在ST中编写函数在BNS中调用其触点/线圈接口如果未来支持函数块的话。Q: 学习BNS Lang需要多久A: 对于有梯形图基础的工程师掌握基本语法可能在30分钟以内。核心就是记住那几张映射表。真正的熟练需要几个小时的实际编写以形成“文本-图形”的思维转换肌肉记忆。对于新手它可能比直接学梯形图更抽象一点但作为入门后的效率工具非常合适。7. 项目生态与未来展望BNS Lang目前已经实现了从概念到可用的跨越。其路线图展示了开发者对工业自动化工具链现代化的完整思考。短期目标完善对更多国产和主流PLC品牌如信捷、汇川、西门子、三菱的代码生成支持。这将极大扩展其适用性。中期目标开发离线逻辑仿真器bns sim。这将允许用户在将程序下载到实体PLC前在电脑上对BNS逻辑进行模拟和调试进一步缩短开发周期。长期愿景与更广泛的工业自动化平台集成。例如与PLAIDE等新兴的自动化工程平台结合实现从逻辑设计、仿真到部署的全链路文本化、自动化。我个人在实际使用中的体会是BNS Lang最大的价值不在于替代传统的图形化编程而是提供了一种互补和增强的选择。在需要快速迭代、批量处理、版本严格管控或与AI工具协同的场景下它的效率优势是压倒性的。它像是一把精准的“手术刀”在PLC编程这个庞大生态中切出了一个属于文本化、自动化工具的细分市场。对于拥抱变化的工程师和团队来说现在开始了解并尝试BNS Lang或许就是在为未来更高效率的自动化工程实践做准备。