首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Gemini3 炸裂全网,搞个PLC编程岂不是So easy!

Gemini3 炸裂全网,搞个PLC编程岂不是So easy!

作者头像
Hello工控
发布2025-12-23 15:05:12
发布2025-12-23 15:05:12
570
举报
文章被收录于专栏:Hello工控Hello工控

近日,全网都在说Gemini3 Pro这个模型多么厉害,作为关注工控和AI的公众号,自然不会错过这波体验。

从AI排行耪来看,目前已经冲到榜首:

各项评分数据也不错:

我们这里更加关心的是:Gemini 3 Pro的PLC编程能力如何?有没有比之前更优呢?

但是,在国内连Google都连不上,估计很多朋友都被这个难住了,当然我也不例外,大家如果有好的免费稳定资源欢迎留言区分享下。

加了翻墙的VPN,虽然可以登录,但是还是限制地区。

我翻了下面这个区域,看了是无法直接用了。

当然,看到提示也可以用Vertex AI来测试:

提示说不支持中文输入,好吧!我后面还是换成下面这种方式,即通过openrouter来测试下这款AI的编程能力:

要展示“专家级别”的 ST (Structured Text) 编程技能,关键不在于写出晦涩难懂的代码,而在于展示架构设计能力 (Architecture)抽象思维 (Abstraction)代码复用性 (Reusability) 以及对现代 IEC 61131-3 (OOP 扩展) 特性的熟练运用。

以下示例将展示如何在 CODESYS V3 或 Beckhoff TwinCAT 3 环境下,使用 面向对象编程 (OOP) 的方式构建一个通用的设备控制框架

相比于传统的“面条式代码”,这段代码展示了接口(Interface)、继承(Inheritance)、属性(Property)和方法(Method)的使用。


场景目标

构建一个通用的气缸/执行器控制系统。

  1. 定义标准: 所有执行器必须遵循统一的接口(无论它是气动的、液压的还是电驱的)。
  2. 基类封装: 封装通用的超时检测、状态机逻辑和错误处理。
  3. 具体实现: 这是一个具体的双电控气缸,只需编写少量的硬件映射代码。

1. 定义接口 (I_Actuator)

专家视角:使用接口实现“多态”。主程序不需要知道这是什么气缸,只需要知道它能 MoveWorkMoveHome

代码语言:javascript
复制
INTERFACE I_Actuator
(* 暴露给外部调用的公共方法和属性 *)
METHOD 
  MoveWork : BOOL
END_METHOD
METHOD
  MoveHome : BOOL
END_METHOD
METHOD 
  ResetError : BOOL
END_METHOD

PROPERTY ErrorID : UDINT END_PROPERTY
PROPERTY IsBusy : BOOL END_PROPERTY
PROPERTY IsAtWork : BOOL END_PROPERTY
PROPERTY IsAtHome : BOOL END_PROPERTY

2. 定义抽象基类 (FB_ActuatorBase)

专家视角:利用 ABSTRACTEXTENDS。这是最核心的部分,处理了定时器、状态切换、报错逻辑。子类无需重复编写这些通用逻辑。

代码语言:javascript
复制
FUNCTION_BLOCK ABSTRACT FB_ActuatorBase IMPLEMENTS I_Actuator
VAR
    (* 状态机枚举 *)
    _eState : (IDLE, MOVING_WORK, MOVING_HOME, ERROR) := IDLE;
    (* 内部变量,使用下划线前缀区分 *)
    _fbTimeoutTimer : TON;
    _tTimeoutLimit  : TIME := T#5S;
    _nErrorID       : UDINT := 0;
END_VAR
(* === 接口属性实现 (只读) === *)
PROPERTY ErrorID : UDINT
    GET
        ErrorID := _nErrorID;
    END_GET
END_PROPERTY
PROPERTY IsBusy : BOOL
    GET
        IsBusy := (_eState = MOVING_WORK) OR (_eState = MOVING_HOME);
    END_GET
END_PROPERTY
(* === 抽象方法 (强制子类必须实现具体的硬件读写) === *)
(* 子类用来设置物理输出 *)
METHOD PROTECTED ABSTRACT SetOutputs
    VAR_INPUT
        bWorkCmd : BOOL;
        bHomeCmd : BOOL;
    END_VAR
END_METHOD
(* 子类用来读取物理反馈 *)
METHOD PROTECTED ABSTRACT ReadInputs
END_METHOD
(* === 核心逻辑周期调用方法 === *)
METHOD PUBLIC Execute
    (* 读取子类映射的传感器状态 *)
    ReadInputs();
    (* 状态机逻辑 *)
    CASE _eState OF
        IDLE:
            _fbTimeoutTimer(IN := FALSE);
        MOVING_WORK:
            SetOutputs(TRUE, FALSE);
            _fbTimeoutTimer(IN := TRUE, PT := _tTimeoutLimit);
            (* 使用 THIS^ 访问通过接口/虚方法获取的状态 *)
            IF THIS^.IsAtWork THEN
                _eState := IDLE;
            ELSIF _fbTimeoutTimer.Q THEN
                _nErrorID := 101; 
            (* 例如: 动作超时 *)
                _eState := ERROR;
            END_IF
        MOVING_HOME:
            SetOutputs(FALSE, TRUE);
            _fbTimeoutTimer(IN := TRUE, PT := _tTimeoutLimit);
            IF THIS^.IsAtHome THEN
                _eState := IDLE;
            ELSIF _fbTimeoutTimer.Q THEN
                _nErrorID := 102;
                _eState := ERROR;
            END_IF
        ERROR:
            SetOutputs(FALSE, FALSE); (* 安全保护 *)
    END_CASE
END_METHOD
(* === 接口方法实现 === *)
METHOD MoveWork : BOOL
    IF _eState <> ERROR THEN
        _eState := MOVING_WORK;
        MoveWork := TRUE;
    END_IF
END_METHOD
METHOD MoveHome : BOOL
    IF _eState <> ERROR THEN
        _eState := MOVING_HOME;
        MoveHome := TRUE;
    END_IF
END_METHOD
METHOD ResetError : BOOL
    _nErrorID := 0;
    _eState := IDLE;
    ResetError := TRUE;
END_METHOD

3. 具体实现类 (FB_PneumaticCylinder)

专家视角:具体的业务逻辑非常干净。开发者只需关注 IO 映射,无需关心超时计时器怎么写,因为基类已经处理了。

代码语言:javascript
复制
FUNCTION_BLOCK FB_PneumaticCylinder EXTENDS FB_ActuatorBase
VAR_INPUT
    bSensorWork : BOOL; (* 物理输入 *)
    bSensorHome : BOOL;
END_VAR
VAR_OUTPUT
    bValveWork  : BOOL; (* 物理输出 *)
    bValveHome  : BOOL;
END_VAR
(* === 实现基类的抽象属性 === *)
PROPERTY IsAtWork : BOOL
    GET
        IsAtWork := bSensorWork;
    END_GET
END_PROPERTY
PROPERTY IsAtHome : BOOL
    GET
        IsAtHome := bSensorHome;
    END_GET
END_PROPERTY
(* === 实现基类的抽象方法 === *)
METHOD PROTECTED SetOutputs
    VAR_INPUT
        bWorkCmd : BOOL;
        bHomeCmd : BOOL;
    END_VAR
    (* 具体的硬件逻辑,例如这里是双电控 *)
    bValveWork := bWorkCmd;
    bValveHome := bHomeCmd;
END_METHOD
METHOD PROTECTED ReadInputs
    (* 如果需要复杂的滤波或防抖,在这里写 *)
    ;
END_METHOD

4. 主程序调用 (Main)

专家视角:主程序极度简洁。使用数组或接口列表可以轻松批量管理 100 个气缸。

代码语言:javascript
复制
PROGRAM MAIN
VAR
    (* 实例化具体的气缸 *)
    fbCylinderA : FB_PneumaticCylinder;
    (* 定义测试变量 *)
    bUserBtnExtend : BOOL;
    bUserBtnRetract : BOOL;
    bUserBtnReset   : BOOL;
    (* 接口指针,用于演示多态性 *)
    iMyActuator : I_Actuator; 
END_VAR
(* 1. 硬件 IO 映射 (模拟) *)
fbCylinderA.bSensorWork:= HwInputs.I0_0;
fbCylinderA.bSensorHome:= HwInputs.I0_1;
(* 2. 逻辑控制 - 通过接口操作,实现解耦 *)
iMyActuator := fbCylinderA; (* 将具体实例赋值给接口 *)
(* 此时,我们只通过 iMyActuator 操作,不关心具体是双电控还是单电控 *)
IF bUserBtnExtend THEN
    iMyActuator.MoveWork();
END_IF
IF bUserBtnRetract THEN
    iMyActuator.MoveHome();
END_IF
IF bUserBtnReset THEN
    iMyActuator.ResetError();
END_IF
(* 3. 周期性执行核心逻辑 *)
(* 注意:必须调用实例的 Execute 方法来驱动内部状态机 *)
fbCylinderA.Execute();
(* 4. 输出映射 *)
HwOutputs.Q0_0:= fbCylinderA.bValveWork;
HwOutputs.Q0_1:= fbCylinderA.bValveHome;

当然,最后还自己进行了自我阐述,证明自己专家级别的编程实力!


为什么这段代码展示了专家级技能?

  1. 解耦 (Decoupling): 主逻辑通过 I_Actuator 接口控制设备。如果未来你需要把气缸换成伺服电机推杆,只需新建一个 FB_ServoPusher 实现该接口,主程序的控制逻辑(按钮、状态流转)一行代码都不用改。
  2. 封装 (Encapsulation): _eState, _fbTimeoutTimer 等变量被隐藏在基类内部,外部无法随意修改,保证了系统的健壮性。只能通过 MoveWork() 等方法与其交互。
  3. 易维护性 (Maintainability): 如果你想修改所有气缸的超时时间逻辑,只需要修改 FB_ActuatorBase 一个地方,全厂所有气缸的逻辑都会自动更新。
  4. 代码整洁 (Clean Code): 没有大量的 IF..THEN..ELSE 嵌套,状态机清晰,逻辑分层明确(硬件层 -> 驱动层 -> 业务层)。

好了,至于代码到底如何,交给各位PLC的同仁们去评判吧。有任何想法欢迎留言讨论哦!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Hello工控 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景目标
  • 1. 定义接口 (I_Actuator)
  • 2. 定义抽象基类 (FB_ActuatorBase)
  • 3. 具体实现类 (FB_PneumaticCylinder)
  • 4. 主程序调用 (Main)
  • 当然,最后还自己进行了自我阐述,证明自己专家级别的编程实力!
  • 为什么这段代码展示了专家级技能?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档