我们在新能源行业设备开发中,收放卷是很经典常用的设备模块,不管是电芯电池卷绕机、叠片机、制片机等,都需要这个模块。那我们刚好利用上期介绍的让AI自动编写plc程序的两种方法中其一,即:VS code +cline + deepseek API 的方式来做本期的分享。
具体的方法在上一篇查看:DeepSeek大显神威,PLC编程也能如此高效有趣?
收放卷
我们这里以锂电池,特别是圆柱电池电芯为例,内部基本组成:正极片+负极片+双层隔膜。其他的组成部分还包含外壳、盖帽、电解液、PTC元件、垫圈以及安全阀等关键组件。
那生成这种电池的设备,这里以其中的卷绕工艺为核心的设备:
其中,正负极片和隔膜卷的收放是最典型的一个部分。上图红色圈内,就是正极片、负极片、上隔膜及下隔膜伺服放卷的位置。
Cline的使用步骤
当然,上述的收放卷是一个典型的结构,四个收放卷本质上是同一套代码,可以用面向对象的思维来架构,新建一个FB,再实例化四个功能块即可。
我们这里用AI来辅助实现收放卷,打开VS code,找到cline对话窗口:
提问之前,可以设置好API key,在右上角的设置栏,点击打开:
当然,AI的模型选择可以按照需求而定,这里我们以Deepseek为例进行演示:
设定好后,回到主窗口:
在最下方的Type a message输入您的需求,本例:两个伺服系统,一个收卷一个放卷,中间有摆杆控制,请给出最佳的解决方案。
需求输入完毕后,点击发送即可等待AI自动推理的过程,如果中文提问,一般也是中文回答,如果依然回答的英文,请在需求加上,以中文回答这个提示词即可。
根据任务描述,需要设计一个收卷和放卷系统,中间有摆杆控制。从环境信息中可以看到一些相关的ST(结构化文本)文件,包括dancer_control.st、pid_winder.st等,这些可能包含了现有的控制逻辑。
首先需要分析现有文件内容,了解当前系统实现。然后设计一个包含以下关键组件的解决方案:
最佳方案应该包括:
根据我们的需求,设计思路非常赞,基本包含:伺服的控制、摆杆位置检测和张力控制、系统协调控制。方案也很清晰,除了PID的调节,还考虑到了紧急停止及安全保护机制,这点非常不错。
代码
接下来,我们重点是让他生成代码,最开始还要询问我编程电脑上现用的dancer.st文件,但实际上没有,所以重新让他生成。
跟AI交流,就是简单直接,想要什么直接提,不像跟我们同事或者请教领导之类的,还要考虑措辞。
全新的收放卷的控制系统,给出了我们3大核心功能,模块化编程,思路清晰,不亚于我们工程师哈。
这里,它自动在桌面创建了一个文件,把所有代码放到winder_control.st里面,方便我们全部复制,用记事本的方式打开即可,亲测有效。
初始的自动plc代码,我们展示在下方(st语言实现的):
PROGRAM WinderControl
VAR
// 伺服控制变量
unwind_servo : SERVO_DRIVE;
rewind_servo : SERVO_DRIVE;
// 摆杆控制变量
dancer_pos : REAL; // 摆杆位置
dancer_setpoint : REAL := 0.5; // 摆杆设定位置
tension_PID : PID_CONTROLLER;
// 系统状态
system_state : (IDLE, RUNNING, FAULT);
emergency_stop : BOOL := FALSE;
// 运行参数
line_speed : REAL := 1.0; // 线速度 m/s
material_thickness : REAL := 0.001; // 材料厚度 m
END_VAR
// 初始化
IF FIRST_SCAN THEN
// 初始化PID参数
tension_PID.Kp := 1.0;
tension_PID.Ki := 0.1;
tension_PID.Kd := 0.01;
tension_PID.Ts := 0.01; // 采样时间10ms
system_state := IDLE;
END_IF
// 主控制逻辑
CASE system_state OF
IDLE:
// 待机状态处理
IF start_command THEN
system_state := RUNNING;
END_IF
RUNNING:
// 运行状态处理
RunControlLogic();
IF emergency_stop THEN
system_state := FAULT;
END_IF
FAULT:
// 故障处理
EmergencyStop();
IF reset_command THEN
system_state := IDLE;
END_IF
END_CASE
按照AI的自动生成逻辑,基本框架也是按照上述的3大核心部分来建立哈。本来想着还会自己自动完善,没想到停住了哈。没关系,再一次给命令,让他继续完善:
但是此处出现失败,应该是文件替换这块出错了,但是不影响哈,所以切换了write_to_file功能自动继续完善和生成:
PROGRAM WinderControl
VAR
// 伺服控制变量
unwind_servo : SERVO_DRIVE;
rewind_servo : SERVO_DRIVE;
unwind_speed : REAL := 0.0;
rewind_speed : REAL := 0.0;
speed_ratio : REAL := 1.0;
// 摆杆控制变量
dancer_pos : REAL; // 摆杆位置
dancer_setpoint : REAL := 0.5; // 摆杆设定位置
tension_PID : PID_CONTROLLER;
tension_error : REAL;
// 系统状态
system_state : (IDLE, RUNNING, FAULT) := IDLE;
emergency_stop : BOOL := FALSE;
start_command : BOOL := FALSE;
reset_command : BOOL := FALSE;
// 运行参数
line_speed : REAL := 1.0; // 线速度 m/s
material_thickness : REAL := 0.001; // 材料厚度 m
max_acceleration : REAL := 0.1; // 最大加速度 m/s²
// 安全参数
max_tension : REAL := 100.0; // 最大张力 N
min_tension : REAL := 10.0; // 最小张力 N
END_VAR
// 初始化
IF FIRST_SCAN THEN
// 初始化PID参数
tension_PID.Kp := 1.0;
tension_PID.Ki := 0.1;
tension_PID.Kd := 0.01;
tension_PID.Ts := 0.01; // 采样时间10ms
system_state := IDLE;
END_IF
// 主控制逻辑
CASE system_state OF
IDLE:
// 待机状态处理
IF start_command THEN
system_state := RUNNING;
END_IF
RUNNING:
// 运行状态处理
RunControlLogic();
// 安全检测
IF emergency_stop OR tension_error > max_tension OR tension_error < min_tension THEN
system_state := FAULT;
END_IF
FAULT:
// 故障处理
EmergencyStop();
IF reset_command THEN
system_state := IDLE;
END_IF
END_CASE
// 伺服控制逻辑
METHOD RunControlLogic : BOOL
VAR_INPUT
END_VAR
VAR
speed_cmd : REAL;
accel_time : REAL;
END_VAR
// 计算收放卷速度
speed_cmd := line_speed / (2 * 3.14159 * unwind_servo.radius);
unwind_speed := speed_cmd;
rewind_speed := speed_cmd * speed_ratio;
// 速度同步控制
IF ABS(unwind_speed - rewind_speed) > 0.01 THEN
speed_ratio := unwind_speed / rewind_speed;
END_IF
// 摆杆位置控制
tension_error := dancer_setpoint - dancer_pos;
tension_PID.PV := dancer_pos;
tension_PID.SP := dancer_setpoint;
tension_PID.CYCLE();
// 应用PID输出调整速度
unwind_speed := unwind_speed + tension_PID.CV;
rewind_speed := rewind_speed - tension_PID.CV;
// 限制速度范围
unwind_speed := LIMIT(unwind_speed, 0.0, 10.0);
rewind_speed := LIMIT(rewind_speed, 0.0, 10.0);
// 应用速度指令
unwind_servo.SetSpeed(unwind_speed);
rewind_servo.SetSpeed(rewind_speed);
RunControlLogic := TRUE;
END_METHOD
// 紧急停止处理
METHOD EmergencyStop : BOOL
VAR_INPUT
END_VAR
// 立即停止伺服
unwind_servo.Stop();
rewind_servo.Stop();
// 复位状态
emergency_stop := TRUE;
start_command := FALSE;
EmergencyStop := TRUE;
END_METHOD
相对比而言,较最开始的代码加了两个Method,熟悉st语言的朋友应该了解这种编程方式。
最终,任务完成后还会自动给出此次需求的总结陈词。先不论代码质量如何,单单就这个思路和框架值得我们参考。最后,把这个自动生成的代码供大家去品鉴:
PROGRAM WinderControl
VAR
// 伺服控制变量
unwind_servo : SERVO_DRIVE;
rewind_servo : SERVO_DRIVE;
unwind_speed : REAL := 0.0;
rewind_speed : REAL := 0.0;
speed_ratio : REAL := 1.0;
// 摆杆控制变量
dancer_pos : REAL; // 摆杆位置
dancer_pos_filtered : REAL := 0.5; // 滤波后摆杆位置
dancer_setpoint : REAL := 0.5; // 摆杆设定位置
tension_PID : PID_CONTROLLER;
tension_error : REAL;
tension_avg : REAL := 0.0; // 平均张力
tension_var : REAL := 0.0; // 张力方差
// 系统状态
system_state : (IDLE, RUNNING, FAULT) := IDLE;
emergency_stop : BOOL := FALSE;
start_command : BOOL := FALSE;
reset_command : BOOL := FALSE;
// 运行参数
line_speed : REAL := 1.0; // 线速度 m/s
material_thickness : REAL := 0.001; // 材料厚度 m
max_acceleration : REAL := 0.1; // 最大加速度 m/s²
// 安全参数
max_tension : REAL := 100.0; // 最大张力 N
min_tension : REAL := 10.0; // 最小张力 N
max_tension_var : REAL := 50.0; // 最大张力方差
material_break_threshold : REAL := 0.01; // 断料检测阈值
END_VAR
// 初始化
IF FIRST_SCAN THEN
// 初始化PID参数
tension_PID.Kp := 1.0;
tension_PID.Ki := 0.1;
tension_PID.Kd := 0.01;
tension_PID.Ts := 0.01; // 采样时间10ms
system_state := IDLE;
END_IF
// 主控制逻辑
CASE system_state OF
IDLE:
// 待机状态处理
IF start_command THEN
system_state := RUNNING;
END_IF
RUNNING:
// 运行状态处理
RunControlLogic();
// 安全检测
IF emergency_stop OR
tension_error > max_tension OR
tension_error < min_tension OR
tension_var > max_tension_var OR
ABS(dancer_pos_filtered - dancer_setpoint) > material_break_threshold THEN
system_state := FAULT;
END_IF
FAULT:
// 故障处理
EmergencyStop();
IF reset_command THEN
system_state := IDLE;
END_IF
END_CASE
// 伺服控制逻辑
METHOD RunControlLogic : BOOL
VAR_INPUT
END_VAR
VAR
speed_cmd : REAL;
accel_time : REAL;
END_VAR
// 计算收放卷速度
speed_cmd := line_speed / (2 * 3.14159 * unwind_servo.radius);
unwind_speed := speed_cmd;
rewind_speed := speed_cmd * speed_ratio;
// 速度同步控制
IF ABS(unwind_speed - rewind_speed) > 0.01 THEN
speed_ratio := unwind_speed / rewind_speed;
END_IF
// 摆杆位置滤波
dancer_pos_filtered := 0.8 * dancer_pos_filtered + 0.2 * dancer_pos;
// 摆杆位置控制
tension_error := dancer_setpoint - dancer_pos_filtered;
tension_PID.PV := dancer_pos_filtered;
tension_PID.SP := dancer_setpoint;
// 自适应PID参数
IF ABS(tension_error) > 0.1 THEN
tension_PID.Kp := 2.0;
tension_PID.Ki := 0.2;
ELSIF ABS(tension_error) > 0.05 THEN
tension_PID.Kp := 1.0;
tension_PID.Ki := 0.1;
ELSE
tension_PID.Kp := 0.5;
tension_PID.Ki := 0.05;
END_IF
tension_PID.CYCLE();
// 张力统计
tension_avg := 0.9 * tension_avg + 0.1 * tension_error;
tension_var := 0.9 * tension_var + 0.1 * (tension_error - tension_avg) * (tension_error - tension_avg);
// 应用PID输出调整速度
unwind_speed := unwind_speed + tension_PID.CV;
rewind_speed := rewind_speed - tension_PID.CV;
// 限制速度范围
unwind_speed := LIMIT(unwind_speed, 0.0, 10.0);
rewind_speed := LIMIT(rewind_speed, 0.0, 10.0);
// 应用速度指令
unwind_servo.SetSpeed(unwind_speed);
rewind_servo.SetSpeed(rewind_speed);
RunControlLogic := TRUE;
END_METHOD
// 紧急停止处理
METHOD EmergencyStop : BOOL
VAR_INPUT
END_VAR
// 立即停止伺服
unwind_servo.Stop();
rewind_servo.Stop();
// 复位状态
emergency_stop := TRUE;
start_command := FALSE;
EmergencyStop := TRUE;
END_METHOD
当然,这里的安全保护方面的代码,并没有完善,所以还可以继续提需求,直到让您满意为止。例如,断料检测这块,让他继续:
综合上述,我个人的体验感受: