嵌入式PLCOpen运行时环境,使用C11实现核心功能块(PID、一阶惯性),通过Python C扩展提供脚本化控制能力。
- 🎯 核心功能块: 位置式PID控制器、PIDA(带报警PID)、一阶惯性滤波器
- 🐍 Python脚本: 在Python中调用功能块,快速验证控制算法
- 🔄 热重载: 运行时自动检测脚本变更,无需重启
- 🔧 远程调试: 支持VSCode远程调试Python脚本
- 🏗️ 双平台: 支持ARM Cortex-M4和X86开发模拟
- Docker Desktop(推荐)
- 或本地环境:Python 3.11+,CMake 3.20+,GCC/Clang
# 克隆仓库
git clone https://github.com/hollysys-cn/plcopen-runtime-py.git
cd plcopen-runtime-py
# 启动开发环境
docker compose up --build
# 在另一个终端连接到容器
docker compose exec runtime bash# 安装Python依赖
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
# 构建C扩展
mkdir build && cd build
cmake .. -DBUILD_TESTS=ON
make -j$(nproc)
# 运行测试
ctest --output-on-failure
pytest tests/在 scripts/ 目录创建控制脚本:
# scripts/temperature_control.py
import plcopen
# 创建PID控制器
pid = plcopen.PID(kp=2.0, ki=0.5, kd=0.1, out_min=0, out_max=100)
def main():
"""主循环函数,由运行时按100ms周期调用"""
setpoint = 60.0 # 目标温度
pv = read_temperature() # 读取当前温度
output = pid.execute(setpoint=setpoint, pv=pv)
set_heater_power(output) # 设置加热器功率# 使用Docker
docker compose up
# 或本地运行
python -m runtime.mainplcopen-runtime-py/
├── src/ # C源代码
│ ├── fb/ # 功能块实现
│ ├── python/ # Python C扩展
│ └── common/ # 公共工具
├── include/ # C头文件
├── runtime/ # Python运行时模块
├── scripts/ # 用户脚本目录
├── tests/ # 测试代码
├── docker/ # Docker配置
└── specs/ # 规格说明文档
import plcopen
pid = plcopen.PID(
kp=1.0, # 比例增益
ki=0.1, # 积分增益
kd=0.05, # 微分增益
out_min=-100, # 输出下限
out_max=100, # 输出上限
dt=0.1 # 采样周期(秒)
)
output = pid.execute(setpoint=100.0, pv=80.0)
print(f"控制输出: {output}, 偏差: {pid.error}, 限幅: {pid.saturated}")基于IEC61131-3标准的工业级PID控制器,支持五种运行模式和四级过程值报警。
import plcopen
# 创建PIDA实例
pida = plcopen.PIDA(
kp=100.0, # 比例带(%)
ti=30.0, # 积分时间(秒)
td=5.0, # 微分时间(秒)
pvu=100.0, # PV量程上限
pvl=0.0, # PV量程下限
outu=100.0, # 输出上限(%)
outl=0.0, # 输出下限(%)
actopt=1, # 反作用(温度低时加热)
cyc=0.5, # 计算周期(秒)
)
# 设置自动模式
pida.sp = 60.0
pida.mode = plcopen.PIDA_MODE_AUTO
# 执行控制
output = pida.execute(pv=45.0)
print(f"输出: {output}, 偏差: {pida.error}")
# 检查报警状态
if pida.hhind:
print("高高限报警!")
if pida.ahind:
print("高限报警")
# 设定值爬坡
pida.start_ramp(target=70.0, rate=5.0) # 5%/秒爬到70%支持的模式:
PIDA_MODE_MANUAL- 手动模式PIDA_MODE_AUTO- 自动模式PIDA_MODE_CASCADE- 串级模式PIDA_MODE_MANUAL_TRACK- 手动跟踪PIDA_MODE_AUTO_TRACK- 自动跟踪
import plcopen
filter = plcopen.FirstOrder(
k=1.0, # 增益
t=0.5, # 时间常数(秒)
dt=0.1 # 采样周期(秒)
)
# 阶跃响应
for i in range(20):
output = filter.execute(100.0)
print(f"Step {i}: {output:.2f}")- 启动运行时(调试模式已启用)
- 在VSCode中按
F5附加调试器 - 在脚本中设置断点
- 脚本执行到断点处将暂停
详见 .vscode/launch.json 配置。
运行时会自动监控 scripts/ 目录:
- 修改脚本文件 → 自动重新加载(保留功能块状态)
- 添加新脚本 → 自动加载
- 删除脚本 → 自动卸载
# 脚本中的功能块状态会在重载时保留
pid = plcopen.PID(kp=2.0, ki=0.1)
def main():
# 重载后,pid 的积分器状态会恢复
return pid.execute(setpoint=100, pv=read_sensor())# 构建ARM交叉编译镜像
docker build -f docker/Dockerfile.arm -t plcopen-arm .
# 运行交叉编译
docker run --rm -v $(pwd):/app plcopen-arm \
cmake -B build-arm -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake基于 x86_64 平台测试结果:
| 指标 | 结果 |
|---|---|
| PID 执行时间 | ~100 ns |
| FirstOrder 执行时间 | ~50 ns |
| PID 实例内存 | ~120 bytes |
| FirstOrder 实例内存 | ~48 bytes |
详见 性能基准测试报告。
# C单元测试
cd build && ctest --output-on-failure
# Python测试
pytest tests/ -v# 检查Python代码
ruff check runtime/ tests/
mypy runtime/MIT License - 详见 LICENSE
欢迎提交Issue和Pull Request!