2. 相机发现与设备枚举

在上一节完成 pylon SDK 的安装与运行环境确认之后,接下来要解决的是“程序怎么知道现场有哪些相机”。这一步在 pylon 中称为设备枚举(Device Enumeration)。它并不是简单地扫描网口,而是由 pylon 的传输层(Transport Layer,简称 TL)把不同物理接口上的相机统一抽象成可查询的设备对象。理解枚举机制,是后续打开相机、配置参数、处理多相机场景的前提。

一、Transport Layer:pylon 与相机之间的“接口适配层”

Basler 相机可能通过 GigE、USB3 Vision、Camera Link、CoaXPress 等不同物理接口接入主机。pylon 不希望上层应用为每种接口写一套发现逻辑,于是引入了 Transport Layer 概念。每个 TL 是一个动态库(Windows 下为 pylon_TL_xxx.dll,Linux 下为 libpylon_TL_xxx.so),负责该接口的发现、连接与数据流管理。常见的有:

  • pylon GigE TL:面向 GigE Vision 相机,通过 UDP 广播/单播发现设备,是工业现场最常用的 TL。
  • pylon USB TL:面向 USB3 Vision 相机,通过 USB 枚举获取设备。
  • pylon CL TL / CXP TL:分别面向 Camera Link 与 CoaXPress 采集卡。
  • pylon GenTL Producer:第三方厂商按 GenICam GenTL 标准提供的 TL,pylon 也能加载。

枚举时,pylon 会遍历当前已加载的所有 TL,让每个 TL 报告自己“看得见”的设备,再汇总成一份统一的设备列表。因此,如果某台相机没被列出,问题往往不在相机本身,而在于对应 TL 是否加载、网络是否可达、驱动是否正常。

pylon 设备枚举机制与 Transport Layer 结构 应用程序 / pylon API CTlFactory · EnumerateDevices 设备信息汇总列表 DeviceInfo(名称/序列号/IP/接口) GigE TL UDP 广播/单播发现 pylon_TL_gige USB TL USB3 Vision 枚举 pylon_TL_usb CL / CXP TL 采集卡接口枚举 pylon_TL_cl / cxp GenTL Producer 第三方 TL GenICam 标准 GigE 相机 192.168.1.10 USB3 相机 序列号 24001234 CL 相机 采集卡通道 0 第三方相机 GenTL 兼容

二、通过 IP 或序列号识别相机

枚举得到的每个设备都对应一个 CDeviceInfo 对象,它携带了识别相机所需的关键字段。最常用的两个是序列号(SerialNumber)和IP 地址(对于 GigE 相机)。

序列号是相机出厂时写入的全球唯一标识,不随网络配置变化,因此是最可靠的识别依据。在多相机系统中,推荐用序列号建立“物理相机—工位—程序实例”的映射关系。IP 地址则适合 GigE 相机,但要注意:相机 IP 可能被修改,也可能因 DHCP 变化,因此 IP 更适合作为连接参数,而不是长期身份标识。

pylon 提供两种典型用法:一是通过 CDeviceInfo 的 GetSerialNumber()、GetIpAddress() 等方法读取信息;二是用 CreateDevice(info) 直接按枚举到的信息创建设备对象。若已知序列号,也可以构造 CDeviceInfo 或使用 DeviceInfo 的查找接口定位特定相机。

在 GigE 场景中,如果相机与主机不在同一网段,pylon 的 GigE TL 可能仍能发现设备,但无法正常打开。此时需要先用 pylon IP Configurator 或 pylon-gige-configurator 调整网卡与相机 IP,使其处于同一子网。

三、多相机枚举与设备信息读取

多相机场景下,枚举结果是一个设备列表。工程上通常按以下顺序处理:

  1. 调用 CTlFactory::GetInstance().EnumerateDevices(list) 获取全部设备。
  2. 遍历列表,读取每台相机的 GetModelName()、GetSerialNumber()、GetUserDefinedName()、GetDeviceClass()、GetInterfaceID() 等字段。
  3. 根据序列号或用户自定义名称,把设备分配到对应的业务逻辑(如“上相机”“下相机”“侧相机”)。
  4. 对每台相机分别创建 CInstantCamera 实例,再执行打开、参数配置与取流。

需要特别注意的是:枚举只负责“发现”,不负责“占用”。同一台相机可以被多次枚举到,但同一时刻通常只能被一个进程以独占方式打开。如果打开失败并提示设备被占用,应先检查是否有其他程序(包括 pylon Viewer)正在使用该相机。

四、编写控制台程序列出所有可用 Basler 相机

下面给出一个最小可运行的控制台示例,使用 C++ 与 pylon C++ API。它完成三件事:初始化 pylon、枚举设备、打印设备信息。

#include <pylon/PylonIncludes.h>
#include <iostream>

using namespace Pylon;
using namespace GenApi;
using namespace std;

int main()
{
    // 1. 初始化 pylon 运行时
    PylonInitialize();

    try
    {
        // 2. 获取传输层工厂并枚举设备
        CTlFactory& tlFactory = CTlFactory::GetInstance();
        DeviceInfoList_t devices;
        tlFactory.EnumerateDevices(devices);

        cout << "发现设备数量: " << devices.size() << endl;

        // 3. 遍历并打印每台设备的信息
        for (size_t i = 0; i < devices.size(); ++i)
        {
            const CDeviceInfo& info = devices[i];
            cout << "----------------------------------------" << endl;
            cout << "索引        : " << i << endl;
            cout << "型号        : " << info.GetModelName() << endl;
            cout << "序列号      : " << info.GetSerialNumber() << endl;
            cout << "用户自定义名: " << info.GetUserDefinedName() << endl;
            cout << "设备类      : " << info.GetDeviceClass() << endl;
            cout << "接口 ID     : " << info.GetInterfaceID() << endl;

            // GigE 相机可读取 IP
            if (info.GetDeviceClass() == "BaslerGigE")
            {
                cout << "IP 地址     : " << info.GetIpAddress().c_str() << endl;
            }
        }
    }
    catch (const GenericException& e)
    {
        cerr << "pylon 异常: " << e.GetDescription() << endl;
    }

    // 4. 释放 pylon 运行时
    PylonTerminate();
    return 0;
}

编译时需链接 pylon 的库(如 pylonbase、pylonutility、GenApi 等),并确保运行时能找到对应 TL 动态库。运行后,控制台会输出类似下面的结果(以下为示例输出,实际内容取决于现场设备):

发现设备数量: 2
----------------------------------------
索引        : 0
型号        : acA1920-40gc
序列号      : 24001234
用户自定义名: TopCamera
设备类      : BaslerGigE
接口 ID     : 192.168.1.100
IP 地址     : 192.168.1.10
----------------------------------------
索引        : 1
型号        : acA1300-60gm
序列号      : 24005678
用户自定义名: SideCamera
设备类      : BaslerGigE
接口 ID     : 192.168.1.100
IP 地址     : 192.168.1.11

判断枚举是否成功,可以看三个信号:设备数量是否与现场一致、序列号是否与相机铭牌一致、GigE 相机的 IP 是否与预期网段一致。如果数量为 0,优先检查 TL 是否加载、网卡是否启用、防火墙是否拦截了 UDP 广播;如果数量正确但打开失败,则检查 IP 子网与设备占用情况。

不要用“枚举顺序”作为相机的唯一身份。不同主机、不同 TL 加载顺序下,枚举顺序可能变化。生产代码中应始终以序列号或用户自定义名作为绑定依据。

掌握设备枚举之后,下一步就可以基于枚举结果选择目标相机,进入打开设备与参数配置阶段。枚举本身不复杂,但它是整个采集链路的入口,把 TL、设备信息与多相机管理这三件事在这里理清,后续的取流与异常处理会顺畅很多。