现代 C++ 的 PLCopen 运动控制库 —— 嵌入到你的控制器里,不替代你的控制器。
A modern C++ motion-control library implementing core PLCopen Part 1 building blocks and selected Part 2 concepts. Embed it in your controller, not replace your controller.
项目状态:当前工作集版本为
v0.6.0。项目现在具备 CI、自动化测试、Linux 构建、CMake 包导出、单轴与 homing 的 jerk-aware 规划、基础 IEC 61131-3 功能块、单轴管理/运动功能块、以及最小可用的 gear/cam 多轴同步功能块;在v1.0前 API 仍可能变化。详情见 ROADMAP.md;长期方向见 VISION.md。
plcopen 是一个 C++17 运动控制库,实现 PLCopen Motion Control Part 1 的核心功能块与状态机,并逐步补齐 Part 2 的选定能力。它被设计成可嵌入的库,不是完整的 PLC 运行时。
- 正在做工业机器人、自动化设备、定制控制器的 C++ 工程师
- 需要一个实现了 PLCopen 状态机 + 运动规划的库
- 希望把标准运动控制算法嵌入到自己的系统里,而不是部署一整套 PLC
- 需要完整的 PLC 编程 IDE(看 Beremiz)
- 需要 IEC 61131-3 编译器(ST / LD / FBD,看 MatIEC)
- 需要面向 Arduino / 树莓派的入门 PLC(看 OpenPLC)
- 需要生产就绪的商业 PLC 平台(看 CODESYS / TwinCAT)
| 项目 | 定位 | 不同点 |
|---|---|---|
| plcopen(本项目) | C++ PLCopen 运动控制库 | 现代 C++、可嵌入、运动为主 |
| CODESYS | 商业完整 PLC 平台 | 闭源、授权费高 |
| Beremiz | Python + IDE 全功能开源 PLC | 完整系统,不是可嵌入的库 |
| OpenPLC | Arduino/RPi 入门 PLC | 面向教学 / DIY |
| LinuxCNC | CNC 机床 G-code 控制器 | 不是通用 PLC,不含 PLCopen 功能块 |
| MatIEC | IEC 61131-3 编译器 | 只有编译器,不含运行时和运动控制 |
plcopen 想填补的空白是**"现代 C++ 的可嵌入 PLCopen 运动控制库"**——这块目前缺人做。
| 能力 | 说明 |
|---|---|
| 轴状态机 | PLCopen 标准的 8 状态机(Disabled、Standstill、DiscreteMotion 等) |
| 单轴管理/运动功能块 | MC_Power、MC_Reset、MC_ReadStatus、MC_ReadAxisError、MC_ReadActualPosition、MC_ReadCommandPosition、MC_ReadActualVelocity、MC_ReadCommandVelocity、MC_ReadParameter、MC_SetPosition、MC_SetOverride、MC_MoveAbsolute、MC_MoveRelative、MC_MoveAdditive、MC_MoveSuperimposed、MC_MoveVelocity、MC_Stop、MC_Halt、MC_Home、MC_TorqueControl |
| 基础 IEC 功能块 | R_TRIG、F_TRIG、SR、RS、TON、TOF、TP、CTU、CTD、CTUD |
| 多轴同步功能块 | MC_CamTableSelect、MC_CamIn / MC_CamOut、MC_GearIn / MC_GearOut |
| 运动规划 | 梯形 + 单轴 jerk-aware S 曲线 |
| Buffer mode | Aborting / Buffered 等缓冲切换 |
| 调度器 | 单线程周期调度(用户负责在 tick 里调用 runCycle()) |
| 示波器 demo | 可视化轴状态变化 |
| CMake 构建 | Windows + Visual Studio 2022 |
-
单轴功能块面补齐
MC_ReadParameter、MC_SetPosition、MC_SetOverride、MC_MoveSuperimposed、MC_TorqueControl -
公开多轴同步功能块补齐
MC_CamTableSelect、MC_CamIn / MC_CamOut、MC_GearIn / MC_GearOut -
新增最小
CamTable公共类型与多轴 Catch2 回归,真实验证主从同步与脱开 -
MC_SetOverride当前明确作用于新规划的运动命令;MC_MoveSuperimposed当前走单轴 additive 队列语义;MC_TorqueControl当前直接透传到伺服抽象 -
新增基础 IEC 61131-3 功能块首批实现:边沿检测、双稳态、定时器、计数器
-
定时器明确采用显式 scan-cycle 语义,由调用方配置周期时间,不依赖墙钟时间
-
新增
basic_fb_cycledemo 和独立 Catch2 回归,覆盖边沿、延时与计数边界 -
GitHub Actions CI(Windows + Linux)
-
Catch2 自动化测试覆盖轴状态机、轨迹规划器和单轴功能块
-
覆盖率基线 >50%,并纳入发布门槛
-
Linux 构建脚本
build.sh和BUILD_LINUX.md -
CMake
install(EXPORT)、find_package(plcopen)和FetchContent支持 -
独立
plcopen-examples消费者示例仓库 -
MC_Home补齐 direct、MODE5/6/7/8、非法参数和 buffer 交互回归测试 -
Buffer mode 覆盖
ABORTING与所有公开非ABORTING枚举的当前队列语义 -
单轴
AxisMove路径补齐非零jerk的 jerk-aware 轨迹规划与回归测试 -
MC_Home规划已真正接入mHomingJerk -
新增可选
docstarget,未安装 Doxygen 时优雅降级并给出提示 -
docs入口公开头文件已补齐 Doxygen 注释 -
新增概念级双轴
sync / gear / camdemo -
新增可选
pyplcopenPython 单轴仿真绑定与 smoke test -
pyplcopen::AxisSim已补move_velocity/halt/stop与加速度读取
完整清单见 ROADMAP.md。
以下能力属于长期愿景,当前不做:
- ST / IL / LD / FBD / SFC 编译器 & 编辑器
- 工业通信协议(Modbus / OPC UA / EtherNet/IP)
- IDE 和图形化调试器
- Web HMI
- SIL 安全认证、冗余、分布式 PLC
- RT-PREEMPT 实时调度
每项何时启动,见 VISION.md 的解锁条件表。
- Windows:Visual Studio 2022 + CMake 3.21+
- Linux:gcc 9+ 或 clang 10+ + CMake 3.21+(v0.2.0 起正式支持)
- C++17 编译器
git clone https://github.com/lusipad/plcopen.git
cd plcopen
# Windows(推荐使用 build.ps1,详见 BUILD_README.md)
.\build.ps1 -Test
# 跨平台通用命令
cmake -S . -B build
cmake --build build --config Releasecmake -S . -B build -DPLCOPEN_BUILD_DOCS=ON
cmake --build build --config Release --target docs如果本机未安装 Doxygen,docs target 会打印安装提示并优雅退出。
cmake -S . -B build -DPLCOPEN_BUILD_PYTHON_BINDINGS=ON
cmake --build build --config Release
ctest --test-dir build --build-config Release -R pyplcopen_smoke --output-on-failure#include "FbSingleAxis.h"
#include "Scheduler.h"
#include <thread>
#include <chrono>
using namespace plcopen;
int main() {
// 1. 建调度器和轴
Scheduler sched;
sched.setFrequency(100); // 100Hz 调度
Axis* axis = sched.newAxis(1, new Servo()); // 轴 ID = 1
// 2. 使能轴
FbPower power;
power.mAxis = axis;
power.mEnable = true;
power.mEnablePositive = true;
power.mEnableNegative = true;
// 3. 准备一次绝对运动:到位置 500,最大速度 400
FbMoveAbsolute move;
move.mAxis = axis;
move.mPosition = 500;
move.mVelocity = 400;
move.mAcceleration = 500;
move.mDeceleration = 500;
// 4. 周期性调用(这里用 sleep 模拟实时 tick)
while (!move.mDone) {
sched.runCycle();
power.call();
move.call();
if (power.mStatus && power.mValid && !move.mExecute)
move.mExecute = true; // 使能成功后触发运动
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
sched.release();
return 0;
}完整示例见 src/demo/:
basic_fb_cycle.cpp—— 基础 IEC 功能块的 scan-cycle 调用示例axis_move.cpp—— 点到点运动 + Buffer modeaxis_homing.cpp—— 回零示例(已覆盖核心路径)axis_move_oscilloscope.cpp—— 带状态示波器的演示axis_sync.cpp—— 概念级 1:1 双轴同步 demoaxis_gear.cpp—— 概念级固定齿轮比 follow demoaxis_cam.cpp—— 概念级离散 cam table follow demo
这些 demo 现在与仓库里的 MC_Cam* / MC_Gear* 最小实现保持一致,用于展示当前公开同步块的基础用法与边界。
图例:✅ 已实现 / 📋 未实现
| 功能块 | 描述 | 状态 |
|---|---|---|
| R_TRIG | 上升沿检测 | ✅ |
| F_TRIG | 下降沿检测 | ✅ |
| SR | 置位优先锁存器 | ✅ |
| RS | 复位优先锁存器 | ✅ |
| TON | 通电延时定时器 | ✅ |
| TOF | 断电延时定时器 | ✅ |
| TP | 脉冲定时器 | ✅ |
| CTU | 加计数器 | ✅ |
| CTD | 减计数器 | ✅ |
| CTUD | 双向计数器 | ✅ |
| 功能块 | 描述 | 状态 |
|---|---|---|
| MC_Power | 使能/禁用轴 | ✅ |
| MC_Reset | 清除轴错误 | ✅ |
| MC_ReadActualPosition | 读取实际位置 | ✅ |
| MC_ReadCommandPosition | 读取指令位置 | ✅ |
| MC_ReadActualVelocity | 读取实际速度 | ✅ |
| MC_ReadCommandVelocity | 读取指令速度 | ✅ |
| MC_ReadStatus | 读取状态 | ✅ |
| MC_ReadMotionState | 读取运动状态分类 | ✅ |
| MC_ReadAxisError | 读取轴错误 | ✅ |
| MC_ReadParameter | 读取已支持参数子集 | ✅ |
| MC_SetPosition | 重映射当前用户坐标位置 | ✅ |
| MC_SetOverride | 设置新规划运动的倍率 | ✅ |
| MC_EmergencyStop | 触发伺服急停 | ✅ |
| 功能块 | 描述 | 状态 |
|---|---|---|
| MC_MoveAbsolute | 绝对位置运动 | ✅ |
| MC_MoveRelative | 相对距离运动 | ✅ |
| MC_MoveAdditive | 叠加位置偏移 | ✅ |
| MC_MoveSuperimposed | 当前映射到 additive 队列语义 | ✅ |
| MC_MoveVelocity | 连续速度运动 | ✅ |
| MC_Stop | 停止运动 | ✅ |
| MC_Halt | 立即停止 | ✅ |
| MC_Home | 回零 | ✅ |
| MC_TorqueControl | 伺服扭矩设定透传 | ✅ |
| 功能块 | 描述 | 状态 |
|---|---|---|
| MC_CamTableSelect | 选择凸轮表 | ✅ |
| MC_CamIn / MC_CamOut | 凸轮同步 | ✅ |
| MC_GearIn / MC_GearOut | 齿轮同步 | ✅ |
┌──────────────────────────────────────────┐
│ 功能块层 (src/fb/) │
│ FbPower, FbMoveAbsolute, FbTon, ... │
└──────────────────────────────────────────┘
▼
┌──────────────────────────────────────────┐
│ 轴控制层 (src/motion/axis/) │
│ Axis, AxisBase, 状态机, AxisMove, ... │
└──────────────────────────────────────────┘
▼
┌──────────────────────────────────────────┐
│ 运动规划层 (src/motion/interpolation/) │
│ ProfilePlanner (梯形 + jerk-aware) │
└──────────────────────────────────────────┘
▼
┌──────────────────────────────────────────┐
│ 调度层 (src/motion/Scheduler.*) │
│ 单线程周期调度;轴由 runCycle 推进 │
│ 功能块由用户每周期显式 call() │
└──────────────────────────────────────────┘
▼
┌──────────────────────────────────────────┐
│ Servo 接口 (src/motion/Servo.*) │
│ 对接真实伺服或仿真(由使用者实现) │
└──────────────────────────────────────────┘
设计文档见 doc/design/design_doc.md。
- 当前实现中,所有非
ABORTING的 Buffer mode 枚举共享同一套“排队、不立即打断前一条命令”的语义;细粒度 blending 行为尚未分化实现。 - 基础 IEC 定时器按显式周期推进;调用方需要保证每 scan 调用一次,并通过
setCycleTime()提供周期时间。 MC_SetOverride当前作用于新规划的运动命令,不对已经运行中的 profile 做重规划。MC_MoveSuperimposed当前在单轴队列上按 additive 偏移语义实现,不是独立的并行叠加轨迹合成器。MC_TorqueControl当前把扭矩设定直接透传给伺服抽象;更深入的 torque-mode 闭环控制仍取决于具体伺服实现。MC_Gear* / MC_Cam*当前是单主单从的最小同步实现,不包含完整AxesGroup、多从轴协调或高级平滑脱开策略。MC_CamTableSelect当前负责表校验和句柄传递;MC_CamIn直接消费选定的CamTable句柄,不维护独立的控制器侧表仓库。mStartSync当前建模为同步建立成功时的一拍脉冲。pyplcopen当前只暴露单轴仿真 facade,不是完整 Python PLCopen SDK。
| 文档 | 说明 |
|---|---|
| README.md | 本文档:项目概览 |
| CHANGELOG.md | 版本变化记录 |
| VISION.md | 长期愿景(3-5 年方向) |
| ROADMAP.md | 近期路线(6-12 个月) |
| BUILD_README.md | 详细构建指南 |
| BUILD_LINUX.md | Ubuntu 22.04 构建说明 |
src/fb/FbBasic.h |
基础 IEC 功能块公开头文件 |
src/fb/FbMultiAxis.h |
多轴同步功能块公开头文件 |
| CLAUDE.md | AI 协作的行为规范 |
| doc/design/ | 当前代码的设计文档 |
| doc/reference/ | PLCopen 标准原文(PDF) |
| doc/vision/ | 愿景期探索性设计(非当前路线图) |
欢迎各种形式的贡献:
- Bug 修复、测试补充、文档改进:随时 PR
- 当前路线图里的 issue-driven 修复或文档/测试补充:先看 ROADMAP.md 当前状态,再发 issue / PR
- 不在路线图上的能力:先看 VISION.md 解锁条件,满足后开 issue 讨论,再动手
报告问题:GitHub Issues
本项目 fork 自 i5cnc(原仓库已停止维护)。我们保留了运动控制核心,按 PLCopen 标准重构和完善。
- IEC 61131-3 国际标准
- PLCOpen Motion Control 资料(本仓库
doc/reference/下有 Part 1&2 原文) - 设计模式:状态模式、观察者模式、工厂模式
- IEC 61131-3 国际标准
- PLCOpen 组织的技术规范
- i5cnc 原始项目
- 工业自动化开源社区