PMSOptical SDK 以单个 Windows DLL 导出 44 个 C 函数,覆盖串口与以太网连接、绝对位置控制、状态回读、加密控制卡功能,以及一整套用于双电机镜头的平行 API 族。核心工作流是四次调用:打开 → 回零 → 运动 → 等待。串口取句柄用 PMSOptical_OpenComm("COM1", 9600),TCP 用 PMSOptical_OpenSocket("192.168.1.200", 4196)。
本文记录函数分族、推荐调用时序,以及首次集成时最容易踩到的四条约束——其中一条与设备安全直接相关:SDK 中不存在可用的软件急停。
| 项目 | 值 |
|---|---|
| 导出函数 | 44 个(单电机 24 个、双电机 20 个) |
| 平台 | Windows x64 / x86(DLL) |
| 连接方式 | 串口 9600 波特率,或 TCP 端口 4196 |
| 句柄类型 | PMSHANDLE(void*)——必须判空 |
| 核心时序 | Open → GoHome → MoveTo(pulse) → WaitForOpticalFinished → GetPos → Close |
| 等待接口默认超时 | 100000 ms(100 秒) |
| 未实现函数 | 8 个,其中含 Stop 与 Stop2 |
| 语言绑定 | C++ 原生;C# 走 P/Invoke;其他语言用 ctypes/cffi(无官方绑定) |
PMSOptical-SDK/
├── Doc/
│ ├── POMEAS electric lens development documents V4.4.7.pdf (英文)
│ ├── encrypted / non-encrypted development documents V4.4.7 (控制卡对比)
│ └── dual-motor control card operation manual V1.5
├── SDK/
│ ├── include/PMSOpticalDll.h 44 个导出函数
│ ├── x64/{Release,Debug}/PMSOpticalDll.dll + .lib
│ │ └── OP/*.txt 各型号脉冲表
│ └── x86/{Release,Debug}/ 同上,32 位
└── demo/
└── x64/PMSOpticalDemo.exe + .ini MFC 演示程序
DLL 必须与可执行文件同目录,或位于系统 PATH 上。
| 方式 | 函数 | 参数 |
|---|---|---|
| 串口 | PMSOptical_OpenComm(char* comname, int nBaud) | comname 如 "COM1";nBaud = 9600 |
| 以太网 | PMSOptical_OpenSocket(char* ip, int nPort) | ip 如 "192.168.1.200";nPort = 4196 |
| 查询状态 | PMSOptical_IsOpened(PMSHANDLE, bool&) | — |
| 关闭 | PMSOptical_Close(PMSHANDLE&) | 句柄按引用传入 |
走网络时,上位机与镜头控制卡必须在同一网段——前三段相同,例如均为 192.168.1.xxx。子网掩码自动获取。
#include "PMSOpticalDll.h"
PMSHANDLE h = PMSOptical_OpenComm("COM2", 9600); // 串口
// PMSHANDLE h = PMSOptical_OpenSocket("192.168.1.200", 4196); // 以太网
if (!h) { /* 连接失败 */ }
| # | 函数 | 用途 |
|---|---|---|
| 1 | PMSOptical_OpenSocket(char* ip, int nPort) | 经以太网打开,返回设备句柄 |
| 2 | PMSOptical_OpenComm(char* comname, int nBaud) | 经串口打开,返回设备句柄 |
| 3 | PMSOptical_IsOpened(PMSHANDLE, bool& bIsOpened) | 返回句柄是否已打开 |
| 4 | PMSOptical_Close(PMSHANDLE&) | 关闭句柄 |
第 3、4 个函数的结果与句柄都是按引用传递。这是有意为之:头文件说明签名如此设计是为了兼容 C# P/Invoke。
| # | 函数 | 用途 | 已实现 |
|---|---|---|---|
| 5 | GoHome(PMSHANDLE) | 回原点 | 是 |
| 6 | IsHomed(PMSHANDLE, bool&) | 返回回零是否完成 | 否——标注未实现 |
| 7 | MoveTo(PMSHANDLE, int nPulse) | 运动到绝对脉冲位置 | 是 |
| 8 | Stop(PMSHANDLE) | 立即停止 | 否——标注未实现 |
| 9 | JogStart(PMSHANDLE, int nJogSpeed) | 点动(速度可正可负) | 否——标注未实现 |
| 10 | JogStop(PMSHANDLE) | 停止点动 | 否——标注未实现 |
| 11 | GetPos(PMSHANDLE, int& nCurPulse) | 读取当前位置 | 是 |
| 12 | GetMaxPos(PMSHANDLE, int& nMaxPulse) | 读取最大脉冲(总行程) | 是 |
| 13 | GetStatus(PMSHANDLE, int& nStatus) | 读取运动状态:0 运动中、1 已停止、2 初始化失败 | 是 |
| 14 | WaitForOpticalFinished(PMSHANDLE, int nTimeOut = 100000) | 阻塞至变倍运动结束 | 是 |
| 15 | GetVer(PMSHANDLE, char* Ver) | 读取固件版本 | 是 |
WaitForOpticalFinished 内部封装了状态轮询逻辑——轮询状态查询并检查停止标识——默认超时 100000 ms。多数应用中应调用它,而不是自己写轮询循环。
仅当镜头装配加密控制卡时可用(脉冲表文件名中含 encrypt 即为加密卡)。
| # | 函数 | 用途 |
|---|---|---|
| 16 | EncryptCommStatus(PMSHANDLE, bool& IsConnected) | 加密板是否已连接 |
| 17 | EncryptReadTimes(PMSHANDLE, int& nTimes) | 读取变倍循环计数 |
| 18 | EncryptWriteTimes(PMSHANDLE, int nTimes) | 写入变倍循环计数 |
| 19 | EncryptAddTimes(PMSHANDLE) | 递增变倍循环计数 |
| 20 | EncryptReadFlashMaxPos(PMSHANDLE, int&) | 读取 Flash 中存储的最大脉冲 |
| 21 | EncryptWriteFlashMaxPos(PMSHANDLE, int) | 向 Flash 写入最大脉冲 |
| 22 | EncryptCheckHomeStatus(PMSHANDLE, bool& bHasStatus, bool& bNowStatus) | 回零与限位开关状态 |
| 23 | EncryptReadFlashLensInfo(PMSHANDLE, unsigned char buf[64]) | 读取镜头信息(固定 64 字节块) |
| 24 | EncryptWriteFlashLensInfo(PMSHANDLE, unsigned char buf[64]) | 写入镜头信息(仅限可打印 ASCII) |
加密卡的实际用途:在控制器 Flash 中保存变倍循环计数与一块 64 字节镜头身份信息。它支撑设备资产追踪、使用统计与正品识别——对设备集成商、租赁机队与售后运维有直接价值。
上述每个函数都有一个后缀为 2 的平行版本,并在参数末尾带一个 unsigned char u8lensnum = 0,用于选择电机 1 或电机 2。
| 单电机 | 双电机 | 用途 |
|---|---|---|
GoHome | GoHome2(h, u8lensnum) | 对指定电机回零 |
IsHomed | IsHomed2(h, bool&, u8lensnum) | 未实现 |
MoveTo | MoveTo2(h, nPulse, u8lensnum) | 指定电机运动到绝对位置 |
Stop | Stop2(h, u8lensnum) | 未实现 |
JogStart / JogStop | JogStart2 / JogStop2 | 未实现 |
GetPos | GetPos2(h, int&, u8lensnum) | 读取位置 |
GetMaxPos | GetMaxPos2(h, int&, u8lensnum) | 读取总行程 |
GetStatus | GetStatus2(h, int&, u8lensnum) | 读取状态 |
WaitForOpticalFinished | WaitForOpticalFinished2(h, nTimeOut, u8lensnum) | 等待完成 |
GetVer | GetVer2(h, char*, u8lensnum) | 读取固件版本 |
Encrypt*(9 个) | Encrypt*2(h, …, u8lensnum) | 加密卡全族 |
双电机镜头把变倍电机与独立的焦点微调电机配成一对——例如 12.5X 变倍镜头配 12 mm 电动焦点微调,或配 3 mm 微调轴的双电机 12.5X。
// 双电机:电机 0 = 变倍,电机 1 = 焦点微调
PMSOptical_GoHome2(h, 0);
PMSOptical_MoveTo2(h, 4600, 0); // 变倍到 1X(见对应型号脉冲表)
PMSOptical_WaitForOpticalFinished2(h, 100000, 0);
Open(串口或以太网)
|
GoHome() -> WaitForOpticalFinished(timeout)
|
GetMaxPos() -> 校验总行程,并确认链路存活
|
+-- MoveTo(pulse)
| -> WaitForOpticalFinished(timeout) (或轮询 GetStatus 直到返回 1)
| -> GetPos() -> 与目标比对(闭环)
+-- 切换到下一个倍率,重复
|
Close()
厂商参考流程图对轮询路径规定了三条规则:
控制卡驱动电机期间通信被挂起,状态查询可能完全读不到数据。用「超时 + 重试」处理,或直接调用 WaitForOpticalFinished。不要当作故障,也不要重启连接。
若请求脉冲等于当前脉冲,镜头不动,并返回成功。绝不要用「指令已发出」测试链路存活,请改用 GetMaxPos 或 GetPos。
上电时镜头自行回零,这段窗口内不接受任何指令。上位机应在打开连接、下发指令前至少等待 35 秒。忽略这一点,是「设备无响应」类误报的常见来源。
头文件中 Stop 与 Stop2 都标注为 unrealized,IsHomed、JogStart、JogStop 及其双电机对应版本同样如此——合计八个函数。不要围绕它们设计安全功能。完成判定请用 GetStatus 或 WaitForOpticalFinished;急停应通过硬件回路实现——切断电源或外部联锁信号。
| 需求 | 建议 |
|---|---|
| 仅需变倍控制 | 标准卡 |
| 使用计数、真伪核验、租赁计费 | 加密卡(EncryptReadTimes、EncryptReadFlashLensInfo) |
| 机队混装 | 注意两种卡使用不同的脉冲表——换卡即换表 |
官方 SDK 只提供 Windows DLL(x64 与 x86)。在其他平台上请直接实现串口协议——它就是五条纯 ASCII 指令、无平台依赖,任何带串口或 TCP 套接字的主机都能用。
可以,走 ctypes 或 cffi,因为导出的是 C 链接符号。官方没有 Python 绑定,封装需要你自己写。注意 PMSHANDLE 是 void*,bool& 参数必须用 ctypes.byref 传递。
技术上可以,但不要在同一条链路上混用。两者操作同一批硬件寄存器,混用——尤其在回零基准附近——会产生不一致状态。一个项目只选一种方式。
WaitForOpticalFinished 该设多长超时?默认 100000 ms。请设为你的硬件上最大变倍行程耗时的两倍以上。手册参考值为 10 秒以上。
不是,也不应如此描述。SDK 提供的是可编程光学控制接口——位置、状态与回读。它可以集成进 AI 视觉架构,由上层软件根据检测结果下发新的倍率指令;但 SDK 本身不含任何 AI 或图像分析能力。准确表述是:电动变倍光学可集成到 AI 控制的机器视觉流程中。
两处值得注意。GetVer2 把参数声明成了 u8lennum——拼写笔误,不影响调用,但建议在你自己的封装里规范化。另外上文提到的八个 unrealized 函数不可依赖。
MoveTo 的值从哪来
您将收到我们最新的动态资讯