跳到正文
PreciSim
concepts

设备抽象

虚拟设备和真实设备实现同一套接口——这是「先在虚拟机台上跑通」能成立的前提。

一句话

上层代码不知道自己在跟虚拟设备还是真实设备说话。

这不是为了好看。它决定了三件事能不能成立:

  1. 没有硬件的人能不能完整跑通流程;
  2. 流程在虚拟设备上验证过之后,到现场还需不需要重写;
  3. 能不能在 CI 里跑端到端测试。

接口长什么样

每类设备一个接口,只暴露业务真正需要的能力,不暴露厂商 SDK 的细节:

public interface ICamera : IDevice
{
    CameraInfo Info { get; }                       // 分辨率、像元尺寸
    Task<Frame> GrabAsync(CancellationToken ct);   // 抓一帧
    Task SetExposureAsync(double microseconds);
    Task SetGainAsync(double db);
}
 
public interface IAxis : IDevice
{
    AxisInfo Info { get; }                         // 行程、单位、正方向
    double Position { get; }                       // 当前位置(mm 或 deg)
    Task MoveAbsAsync(double target, MoveProfile p, CancellationToken ct);
    Task MoveRelAsync(double delta, MoveProfile p, CancellationToken ct);
    Task HomeAsync(CancellationToken ct);
    Task StopAsync();
}
 
public interface IDigitalIo : IDevice
{
    bool Read(int channel);
    Task WriteAsync(int channel, bool value);
    IObservable<IoChange> Changes { get; }         // 边沿事件
}

注意接口里没有的东西:没有 GetBaslerHandle(),没有 SendGCode(string), 没有任何「某一家厂商才有」的口子。一旦开了这种口子,上层就会开始依赖它,抽象就破了。

一台机器由配置拼出来

{
  "machine": "demo-2axis-vision",
  "devices": [
    { "id": "cam0", "type": "camera", "driver": "virtual",
      "params": { "width": 2448, "height": 2048, "pixelUm": 3.45 } },
    { "id": "axisX", "type": "axis", "driver": "virtual",
      "params": { "travelMm": 200, "backlashUm": 2.4, "repeatUm": 3 } },
    { "id": "axisY", "type": "axis", "driver": "virtual",
      "params": { "travelMm": 200, "backlashUm": 2.4, "repeatUm": 3 } }
  ]
}

"driver": "virtual" 换成 "driver": "basler" / "driver": "googoltech"上层一行都不用改。这就是全部的魔法。

虚拟设备多「虚」

虚拟设备不是返回假数据的空壳,它按物理模型算:

设备 模拟了什么
相机 投影成像、镜头畸变、景深与离焦、曝光/增益、读出噪声与散粒噪声、坏点
梯形/S 曲线加减速、反向间隙、螺距误差、重复定位误差、限位与急停
IO 气缸到位延时、光栅遮挡、按钮抖动
振镜 场畸变、跳转延时、标记延时

每一项都有开关和参数。教学时最有用的用法是把某一项调大,让新人一眼看清它的后果—— 比如把反向间隙从 2.4 µm 调到 50 µm,然后让他去做一次双向定位。

具体模型写在物理与模型说明里。

什么不该进设备层

  • 业务逻辑:「先吹气再拍照」属于工作流,不属于相机。
  • 标定结果:标定属于「这台机器的当前状态」,存在配置与标定库里,不在设备对象上。
  • 重试策略:设备只如实报错,重试/跳过/中止由工作流统一决定。

这三条守住了,换设备才真的只是换配置。

最后更新: 2026/9/21
这页有帮助吗?