diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..268ec69 --- /dev/null +++ b/.clangd @@ -0,0 +1,7 @@ +# 指定 compile_commands.json 所在目录(相对路径) +CompileFlags: + # 告诉 clangd:compile_commands.json 在 build 目录下 + CompilationDatabase: build + + + diff --git a/App/CMakeLists.txt b/App/CMakeLists.txt new file mode 100644 index 0000000..c324ff5 --- /dev/null +++ b/App/CMakeLists.txt @@ -0,0 +1,28 @@ +# CMake最低版本 +cmake_minimum_required(VERSION 3.21) + +# 工程名、版本号、工程描述 +project(MotionApp + VERSION 0.1 + DESCRIPTION "Test") + +# C/C++ 标准版本 +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 11) + +# 指定在当前目录或以下目录下通过命令(如 add_executable() )链接稍后创建的任何目标时要使用的库或标志 +LINK_LIBRARIES(m) + +# 工程源文件 +add_executable(${PROJECT_NAME} + ./Src/main.cpp) + +# 工程包含目录 +include_directories(./Inc) + +# 链接 moduleA,自动继承其 PUBLIC 的头文件路径和编译属性 +target_link_libraries(${PROJECT_NAME} + PRIVATE # 如果 moduleB 只是内部使用 moduleA,选 PRIVATE + MotionLib +) + diff --git a/App/Src/main.cpp b/App/Src/main.cpp index e856fc1..0a411b9 100644 --- a/App/Src/main.cpp +++ b/App/Src/main.cpp @@ -1,5 +1,8 @@ +#include "Axis.h" + int main() { + plcopen::Axis axis(); return 0; } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 71c1d1d..659ed1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,43 @@ -# CMake最低版本 -cmake_minimum_required(VERSION 3.21) +cmake_minimum_required(VERSION 3.22) -# 工程名、版本号、工程描述 -project(Motion - VERSION 0.1 - DESCRIPTION "Test") +project(Motion) -# C/C++ 标准版本 -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 11) +# 开启编译数据库导出(强制开启,不被缓存覆盖) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") -# 指定在当前目录或以下目录下通过命令(如 add_executable() )链接稍后创建的任何目标时要使用的库或标志 -LINK_LIBRARIES(m) +# 针对 GCC 编译器添加 UTF-8 编码选项 +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") # 仅对 GCC 生效 + # 添加 C++ 编译选项 + add_compile_options(-finput-charset=UTF-8) + add_compile_options(-fexec-charset=UTF-8) + + # 若需要支持 C 语言,补充 C 编译选项 + add_compile_options($<$:-finput-charset=UTF-8>) + add_compile_options($<$:-fexec-charset=UTF-8>) +endif() -# 工程源文件 -add_executable(${PROJECT_NAME} - ./App/Src/main.cpp) +if(WIN32) + # Windows平台特定的设置 + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/WIN32") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/WIN32") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/WIN32/static_lib") +elseif(APPLE) + # Apple平台特定的设置 + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/APPLE") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/APPLE") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/APPLE/static_lib") +elseif(UNIX) # 注意:Linux和macOS都满足UNIX为TRUE,所以通常先判断APPLE + # Linux或其他类Unix系统的设置 + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/UNIX") + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/UNIX") + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/build/$/UNIX/static_lib") +endif() -# 工程包含目录 -include_directories(./Inc) \ No newline at end of file + +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_subdirectory(${CMAKE_SOURCE_DIR}/MotionLib) +add_subdirectory(${CMAKE_SOURCE_DIR}/App) \ No newline at end of file diff --git a/MotionLib/CMakeLists.txt b/MotionLib/CMakeLists.txt new file mode 100644 index 0000000..495acc5 --- /dev/null +++ b/MotionLib/CMakeLists.txt @@ -0,0 +1,31 @@ +project(MotionLib + VERSION 0.0.1 # 版本 0.0.1 + LANGUAGES CXX # C++ + DESCRIPTION "运动控制库" # 描述 +) + +set(INC_DIRECTORES + ${CMAKE_CURRENT_SOURCE_DIR}/Inc +) + +set(LIB_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/Src/Axis.cpp +) + +set(LIB_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/Inc/Types.h + ${CMAKE_CURRENT_SOURCE_DIR}/Inc/Axis.h +) + +add_library(${PROJECT_NAME} SHARED + ${LIB_SOURCES} + ${LIB_HEADERS} +) + + +target_include_directories(${PROJECT_NAME} +PUBLIC + ${INC_DIRECTORES} +PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Src +) diff --git a/MotionLib/Inc/Axis.h b/MotionLib/Inc/Axis.h new file mode 100644 index 0000000..3f946bf --- /dev/null +++ b/MotionLib/Inc/Axis.h @@ -0,0 +1,63 @@ +/** + * @file Axis.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2026-07-02 + * + * @copyright Copyright (c) 2026 + * + */ +#include "Types.h" + +namespace plcopen { + /** + * \enum MotionCommandType + * \brief 内部运动指令类型(功能块 → 轴模型映射) + */ + enum class MotionCommandType { + None, /*!< 无活动指令 */ + PointToPoint, /*!< MC_MoveAbsolute / MC_MoveRelative */ + Velocity, /*!< MC_MoveVelocity */ + Stop, /*!< MC_Stop */ + Halt, /*!< MC_Halt */ + Home, /*!< MC_Home */ + }; + + +/** + * \struct MotionCommand + * \brief 当前活动运动指令的参数快照 + */ +struct MotionCommand { + MotionCommandType type = MotionCommandType::None; + REAL targetPosition = 0.0; + REAL targetVelocity = 0.0; + REAL maxVelocity = 0.0; + REAL acceleration = 0.0; + REAL deceleration = 0.0; + REAL homePosition = 0.0; + MC_AXIS_STATE resultingState = MC_AXIS_STATE::DiscreteMotion; +}; + +/** + * \class Axis + * \brief 单轴仿真对象,实现 PLCopen 轴状态机与运动学 + * \note 不要在功能块 cycle() 之外直接修改 Axis 内部状态。 + */ + +class Axis { +public: + /** + * \brief 构造轴 + * \param axisNo 轴编号 + * \param name 轴名称 + */ + explicit Axis(UINT axisNo = 1, std::string name = "Axis1"); +private: + AXIS_REF ref_; + MC_AXIS_STATE state_ = MC_AXIS_STATE::Disabled; + +}; + +} \ No newline at end of file diff --git a/MotionLib/Inc/Types.h b/MotionLib/Inc/Types.h new file mode 100644 index 0000000..c6a16b0 --- /dev/null +++ b/MotionLib/Inc/Types.h @@ -0,0 +1,121 @@ +/** + * @file types.h + * @author + * @brief + * @version 0.1 + * @date 2026-07-02 + * + * @copyright Copyright (c) 2026 + * + */ +#include +#include +namespace plcopen { + +class Axis; + +/** \typedef BOOL IEC 61131-3 BOOL 类型映射 */ +using BOOL = bool; +/** \typedef REAL IEC 61131-3 REAL 类型映射(双精度浮点) */ +using REAL = double; +/** \typedef WORD IEC 61131-3 WORD 类型映射(16 位无符号,常用于 ErrorID) */ +using WORD = std::uint16_t; +/** \typedef UINT IEC 61131-3 UINT 类型映射(32 位无符号) */ +using UINT = std::uint32_t; + +/** + * \enum MC_BUFFER_MODE + * \brief 运动指令缓冲与混合模式 (MC_BUFFER_MODE) + * + * 用于带 BufferMode 输入的功能块,决定新指令与当前运动的关系。 + */ +enum class MC_BUFFER_MODE : std::uint8_t { + mcAborting = 0, /*!< 默认:立即执行,中断当前运动并清空缓冲 */ + mcBuffered = 1, /*!< 等待前一指令 Done 后顺序执行,无混合 */ + mcBlendingLow = 2, /*!< 混合:在衔接点取两指令速度的较低值 */ + mcBlendingPrevious = 3, /*!< 混合:在衔接点保持前一指令速度 */ + mcBlendingNext = 4, /*!< 混合:在衔接点使用当前指令速度 */ + mcBlendingHigh = 5, /*!< 混合:在衔接点取两指令速度的较高值 */ +}; + +/** + * \enum MC_DIRECTION + * \brief 定位运动方向 (MC_DIRECTION) + */ +enum class MC_DIRECTION : std::uint8_t { + mcPositiveDirection = 0, /*!< 正向运动 */ + mcShortestWay = 1, /*!< 最短路径(线性轴默认策略) */ + mcNegativeDirection = 2, /*!< 负向运动 */ + mcCurrentDirection = 3, /*!< 保持当前运动方向 */ +}; + +/** + * \enum MC_SOURCE + * \brief 运动数据读取来源 (MC_SOURCE) + */ +enum class MC_SOURCE : std::uint8_t { + mcCommandedValue = 0, /*!< 指令值 */ + mcSetValue = 1, /*!< 设定值 */ + mcActualValue = 2, /*!< 实际值 */ +}; + +/** + * \enum MC_AXIS_STATE + * \brief 轴状态机状态 (PLCopen 状态图) + * + * \par 典型状态转换 + * - Disabled → Standstill:MC_Power.Enable = TRUE + * - Standstill → DiscreteMotion:MC_MoveAbsolute / MC_MoveRelative + * - Standstill → ContinuousMotion:MC_MoveVelocity + * - Standstill → Homing:MC_Home + * - 任意 → ErrorStop:轴错误或功率故障 + * - ErrorStop → Standstill:MC_Reset + * + * \note 同一时刻仅有一个状态位为 TRUE(由 MC_ReadStatus 反映)。 + */ +enum class MC_AXIS_STATE : std::uint8_t { + Disabled = 0, /*!< 初始/下电状态,功率未使能 */ + Standstill, /*!< 静止,功率已使能,可接受运动指令 */ + Homing, /*!< 回零进行中 (MC_Home) */ + DiscreteMotion, /*!< 离散运动(点到点),完成后自动停止 */ + ContinuousMotion, /*!< 连续运动(如 MC_MoveVelocity) */ + Stopping, /*!< MC_Stop 激活,减速中且拒绝新运动 */ + ErrorStop, /*!< 错误停止,需 MC_Reset 恢复 */ + SynchronizedMotion, /*!< 同步运动(Cam/Gear,本库预留) */ +}; + +/** + * \enum MC_ERROR_ID + * \brief 功能块与轴通用错误码 + */ +enum class MC_ERROR_ID : WORD { + mcNoError = 0, /*!< 无错误 */ + mcInvalidParameter = 1, /*!< 参数非法(如速度 ≤ 0) */ + mcInvalidState = 2, /*!< 当前状态不允许该操作 */ + mcActionNotAllowed = 3, /*!< 轴未上电或处于 Stopping/ErrorStop */ + mcAxisNotPowered = 4, /*!< 轴未使能 */ + mcAxisNotHomed = 5, /*!< 轴未完成回零 */ + mcCommandAborted = 6, /*!< 指令被中断 */ + mcStopActive = 7, /*!< MC_Stop 占用轴 */ + mcPowerFailure = 8, /*!< 功率级故障 */ + mcFollowingError = 9, /*!< 跟随误差超限 */ +}; + +/** + * \struct AXIS_REF + * \brief 轴引用 (VAR_IN_OUT),所有 MC 功能块的公共轴参数 + * + * \details + * 在 IEC 61131-3 程序中作为 VAR_IN_OUT 传递;本 C++ 实现中, + * `axis` 指针由 Axis 对象构造时自动绑定,应用层无需手动设置。 + */ +struct AXIS_REF { + UINT axisNo = 0; /*!< 轴编号(用户定义) */ + std::string axisName; /*!< 轴名称 */ + Axis* axis = nullptr; /*!< 内部绑定指针,指向仿真轴实例 */ +}; + +} + + + diff --git a/MotionLib/Src/Axis.cpp b/MotionLib/Src/Axis.cpp new file mode 100644 index 0000000..30f6275 --- /dev/null +++ b/MotionLib/Src/Axis.cpp @@ -0,0 +1,20 @@ +/** + * @file Axis.cpp + * @author + * @brief + * @version 0.1 + * @date 2026-07-02 + * + * @copyright Copyright (c) 2026 + * + */ +#include "Types.h" +#include "Axis.h" + +namespace plcopen { +Axis::Axis(UINT axisNo, std::string name) { + ref_.axisNo = axisNo; + ref_.axisName = std::move(name); + ref_.axis = this; +} +} \ No newline at end of file