跳转到内容
STAGING SERVER
DEVELOPMENT SERVER

.NET 程序员指南#

本主题提供专属于 Basler blaze 相机的信息,并非旨在全面概述 pylon .NET API。

如果您是 pylon 的新用户,Basler 建议您先阅读 pylon .NET 程序员指南以熟悉 pylon .NET API。

.NET 编程示例#

要打开包含 blaze 相机编程示例的文件夹,请按下 Win 键,转到 Basler 文件夹,然后选择 blaze Samples。此时将打开一个文件资源管理器窗口。.NET 编程示例位于 DotNet 文件夹中。

如何构建示例#

信息

在构建示例之前,请将包含示例的文件夹复制到您具有读写权限的任意位置。

示例中提供了 Visual Studio 解决方案和项目文件。您可以使用 Visual Studio 2017 或更高版本打开解决方案并构建示例。

如何构建 .NET 应用程序#

若要使用 C# 或 Visual Basic .NET 操作 Basler blaze 相机,必须将 Basler.Pylon 和 Basler.Pylon.Blaze 程序集添加到项目的程序集引用列表中。

要添加程序集:

  1. 在 Visual Studio 解决方案资源管理器中右键单击您的项目,然后选择 添加 > 项目引用。
    此时将打开一个引用管理器窗口。
  2. 点击浏览按钮。
  3. 导航到 %Program Files%\Basler\pylon 8\Development\Assemblies\Basler.Pylon\x64 文件夹。
  4. 选择 Basler.Pylon.dll,然后点击添加按钮。
  5. 点击浏览按钮。
  6. 导航到 %Program Files%\Basler\pylon 8\Development\Assemblies\Basler.Pylon.Blaze\AnyCpu 文件夹。
  7. 选择 Basler.Pylon.Blaze.dll,然后点击添加按钮。

Basler.Pylon 程序集的处理器架构

无论您选择针对 32 位还是 64 位平台的程序集,都没有关系。由于这些程序集已安装在全局程序集缓存 (GAC) 中,因此 .NET 程序集加载器会自动选择与您的应用程序构建架构相匹配的程序集。

为避免在构建应用程序时出现关于潜在架构不匹配的警告,Basler 建议手动编辑 Visual Studio 项目文件以隐藏此类警告。操作步骤如下:

  1. 在“解决方案资源管理器”中,右键单击您的项目并选择 卸载项目。
  2. 再次右键单击该项目并选择 编辑项目。
    该项目的 XML 文件将在编辑器窗口中打开。
  3. 在 XML 文件中,导航至 Basler.Pylon 程序集被引用的位置,即搜索类似于以下内容的片段:

    <ItemGroup>
    ....
    <Reference Include="Basler.Pylon, Version=1.2.0.0, Culture=neutral,
        PublicKeyToken=e389355f398382ab, processorArchitecture=AMD64" />/
    
  4. 在 ItemGroup 元素上方,添加以下 XML 片段:

    <PropertyGroup>
    <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
    </PropertyGroup>
    

    添加元素后,您的项目文件应包含如下所示的片段:

    <PropertyGroup>
        <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
    </PropertyGroup>
    <ItemGroup>
    ....
    <Reference Include="Basler.Pylon">
        <HintPath>..\..\..\..\..\..\Program Files\Basler\pylon\Development\Assemblies\Basler.Pylon\x64\Basler.Pylon.dll</HintPath>
    </Reference>
    <Reference Include="Basler.Pylon.Blaze">
        <HintPath>..\..\..\..\..\..\Program Files\Basler\pylon\Development\Assemblies\Basler.Pylon.Blaze\AnyCpu\Basler.Pylon.Blaze.dll</HintPath>
    </Reference>
    ....
    </ItemGroup>
    
  5. 编辑完成后,右键单击项目并选择 重新加载项目来重新加载您的项目。
    如果系统提示,请确认关闭项目文件并保存未保存的更改。

打开和访问 blaze 相机#

pylon .NET API 为所有相机类型提供了一个单一的 Camera 类。可以使用重载构造函数来选择特定的相机设备。

创建并打开 blaze 相机对象需要三个步骤:

  1. 为要访问的相机创建一个相机对象。

  2. 注册应用默认配置的 blaze 专用参数配置。有关 blaze 配置事件处理程序类的更多详细信息,请参阅预定义相机参数配置部分。

  3. 调用 Open() 方法以建立与相机设备的连接。

以下示例说明了这三个步骤:

using Basler.Pylon;
using Basler.Pylon.Blaze;

// ...

var filter = new Dictionary<string, string> {
    { CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass }
};
using (var camera = new Camera(filter, CameraSelectionStrategy.FirstFound))
{
    // Set up the camera for continuously grabbing point clouds.
    camera.CameraOpened += BlazeConfigurations.AcquirePointCloudsContinuously;

    // Open the connection to the camera device.
    camera.Open();

    // Use the camera.

    // Close the connection.
    camera.Close();
}
Imports Basler.Pylon
Imports Basler.Pylon.Blaze

' ...

Dim filter = New Dictionary(Of String, String) From {
    {CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass}
}
Using camera = New Camera(filter, CameraSelectionStrategy.FirstFound)
    ' Set up the camera for continuously grabbing point clouds.
    AddHandler camera.CameraOpened,
        AddressOf BlazeConfigurations.AcquirePointCloudsContinuously

    ' Open the connection to the camera device.
    camera.Open()

    ' Use the camera.

    ' Close the connection.
    camera.Close()
End Using

为首个可用的 blaze 相机创建一个相机对象#

即: Camera 类提供了一个构造函数,允许您传递键值对列表,用于指定为您创建相机对象的相机设备的 Property。

要打开第一个可用的 blaze 相机,只需指定设备类型等于 blaze 设备类即可。

var filter = new Dictionary<string, string> {
    { CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass }
};
using (var camera = new Camera(filter, CameraSelectionStrategy.FirstFound))
{
}
Dim filter = New Dictionary(Of String, String) From {
    {CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass}
}
Using camera = New Camera(filter, CameraSelectionStrategy.FirstFound)

End Using

为特定的 blaze 相机创建一个相机对象#

如果您想打开特定的 blaze 相机(例如通过指定其序列号),除了将用于 blaze 相机的 pylon 设备类标识符传递给 CreateFirstDevice()之外,您还可以指定其他 Property。

以下代码片段说明了如何通过序列号打开 blaze 相机。

// Specify device class and serial number.
var filter = new Dictionary<string, string>
{
    { CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass },
    { CameraInfoKey.SerialNumber, "20399956" }
};
using (var camera = new Camera(filter, CameraSelectionStrategy.Unambiguous))
{
}
Dim filter = New Dictionary(Of String, String) From {
    {CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass},
    { CameraInfoKey.SerialNumber, "20399956" }
}
Using camera = New Camera(filter, CameraSelectionStrategy.FirstFoundUnambiguous)

End Using

要通过用户自定义名称打开 blaze 相机,请使用以下代码行:

// Specify device class and serial number.
var filter = new Dictionary<string, string>
{
    { CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass },
    { CameraInfoKey.UserDefinedName, "Top" }
};
using (var camera = new Camera(filter, CameraSelectionStrategy.Unambiguous))
{
}
Dim filter = New Dictionary(Of String, String) From {
    {CameraInfoKey.DeviceType, DeviceType.BaslerGenTlBlazeDeviceClass},
    { CameraInfoKey.UserDefinedName, "Top" }
}
Using camera = New Camera(filter, CameraSelectionStrategy.FirstFoundUnambiguous)

End Using

用户自定义名称

您可以使用以下参数为相机指定用户自定义名称: DeviceUserID 您可以在 blaze Viewer、pylon IP Configurator 或 pylon API 中执行此操作:

camera.Parameters[PLBlaze.DeviceUserID].SetValue("MyCamera");
camera.Parameters(PLBlaze.DeviceUserID).SetValue("MyCamera")

通过 IP 地址创建设备

目前,您无法通过指定 IP 地址来创建设备。

如果您想创建并打开具有特定 IP 地址的相机,必须首先枚举所有相机、遍历返回的列表,并在查询 IP 地址及其他网络相关信息之前打开每个相机。

如果未找到所需的 blaze 相机,请检查您是否使用了正确的属性值,并检查相机和网卡的 IP 配置设置。有关设置网络的更多信息,请参阅网络配置主题。

预定义的相机参数配置#

对于 blaze 相机,有 BlazeConfigurations 类。该类的方法可以添加到 CameraOpened 事件中。必须在通过调用 Open() 方法打开相机之前完成此操作。打开相机时,会自动调用配置方法并相应地更改相机配置。

示例:

// Set up the camera for continuously grabbing point clouds.
camera.CameraOpened += BlazeConfigurations.AcquirePointCloudsContinuously;
' Set up the camera for continuously grabbing point clouds.
AddHandler camera.CameraOpened,
AddressOf BlazeConfigurations.AcquirePointCloudsContinuously

即: BlazeConfigurations 提供以下配置方法:

  • AcquirePointCloudsContinuously
    连续采集数据。深度数据表示为点云。
  • AcquireDepthMapsContinuously
    连续采集数据。深度数据表示为深度图。

有关 pylon 配置事件处理程序的更多信息,请参阅 pylon .NET 程序员指南中的预定义相机参数配置一节。

解释深度数据#

处理测量结果主题提供了有关存储在 Range 数据组件中的深度数据格式的信息。

连接到相机#

创建相机对象并注册配置事件处理程序后,通过调用 CBlazeInstantCamera::Open() 方法来建立与相机的连接。

连接将保持活动状态,直到调用 CBlazeInstantCamera::Close() 方法。如果未显式调用, Camera 类的析构函数会自动调用 Close() 。为了显式控制相机对象的生命周期,Basler 建议如上方代码片段所示,在 using 语句内部使用相机对象。

如果相机未定期收到来自相机的心跳请求,它将关闭连接。如果应用程序崩溃或被调试器中断,则会出现心跳请求丢失的情况。有关更多详细信息,请参阅调试应用程序和控制 GigE Vision 心跳一节。

访问参数#

有关如何使用 pylon .NET API 访问相机参数的详细信息,请参阅 pylon .NET 程序员指南中的参数访问一节。

pylon .NET API 提供参数列表作为访问相机参数的便捷方法,并在 Visual Studio 的 IntelliSense 辅助下完成。

对于 blaze 相机,有 PLBlaze 参数列表。

以下代码片段演示了如何使用以下工具设置和获取 Property: PLBlaze 参数列表。

// Set the operating mode of the camera. The choice you make here
// affects the working range of the camera, i.e., the Minimum Working
// Range and Maximum Working Range parameters.
var oldOperatingMode = camera.Parameters[PLBlaze.OperatingMode].GetValue();
camera.Parameters[PLBlaze.OperatingMode].SetValue(PLBlaze.OperatingMode.LongRange);

// Exposure time of the camera. If the operating mode is changed, the
// exposure time is set to the recommended default value.
camera.Parameters[PLBlaze.ExposureTime].SetValue(750); // us

// Enable and configure image filtering.

// The spatial noise filter uses the values of neighboring pixels to
// filter out noise in an image.
camera.Parameters[PLBlaze.SpatialFilter].SetValue(true);

// The temporal noise filter uses the values of the same pixel at
// different points in time to filter out noise in an image.
camera.Parameters[PLBlaze.TemporalFilter].SetValue(true);
camera.Parameters[PLBlaze.TemporalFilterStrength].SetValue(220);

// The outlier removal removes pixels that differ significantly from
// their local environment.
camera.Parameters[PLBlaze.OutlierRemoval].SetValue(true);

// Some properties have restrictions.
// We use API functions that automatically perform value corrections.
// Alternatively, you can use GetInc() / GetMin() / GetMax() to make sure you
// set a valid value.
camera.Parameters[PLBlaze.ConfidenceThreshold].SetValue(
    321,
    IntegerValueCorrection.Nearest
);

// Not all functions are available in older cameras.
// Therefore, we must use "Try" functions that only perform the action
// when parameters are writable. Otherwise, we would get an exception.
camera.Parameters[PLBlaze.MultiCameraChannel].TrySetValue(1);

Console.WriteLine("Operating Mode           : {0}",
    camera.Parameters[PLBlaze.OperatingMode].GetValue());
Console.WriteLine("Exposure Time            : {0}",
    camera.Parameters[PLBlaze.ExposureTime].GetValue());
Console.WriteLine("Spatial Filter           : {0}",
    camera.Parameters[PLBlaze.SpatialFilter].GetValue());
Console.WriteLine("Temporal Filter          : {0}",
    camera.Parameters[PLBlaze.TemporalFilter].GetValue());
Console.WriteLine("Temporal Filter Strength : {0}",
    camera.Parameters[PLBlaze.TemporalFilterStrength].GetValue());
Console.WriteLine("Outlier Removal          : {0}",
    camera.Parameters[PLBlaze.OutlierRemoval].GetValue());
Console.WriteLine("Confidence Threshold     : {0}",
    camera.Parameters[PLBlaze.ConfidenceThreshold].GetValue());
if (camera.Parameters[PLBlaze.MultiCameraChannel].IsReadable)
{
    Console.WriteLine("Multi-Camera Channel     : {0}",
        camera.Parameters[PLBlaze.MultiCameraChannel].GetValue());
}

// Restore the old operating mode.
camera.Parameters[PLBlaze.OperatingMode].SetValue(oldOperatingMode);
' Set the operating mode of the camera. The choice you make here
' affects the working range of the camera, i.e., the Minimum Working
' Range and Maximum Working Range parameters.
Dim oldOperatingMode = camera.Parameters(PLBlaze.OperatingMode).GetValue()
camera.Parameters(PLBlaze.OperatingMode).SetValue(PLBlaze.OperatingMode.LongRange)

' Exposure time of the camera. If the operating mode is changed, the
' exposure time is set to the recommended default value
camera.Parameters(PLBlaze.ExposureTime).SetValue(750) ' us

' Enable and configure image filtering.

' The spatial noise filter uses the values of neighboring pixels to
' filter out noise in an image.
camera.Parameters(PLBlaze.SpatialFilter).SetValue(True)

' The temporal noise filter uses the values of the same pixel at
' different points in time to filter out noise in an image.
camera.Parameters(PLBlaze.TemporalFilter).SetValue(True)
camera.Parameters(PLBlaze.TemporalFilterStrength).SetValue(220)

' The outlier removal removes pixels that differ significantly from
' their local environment
camera.Parameters(PLBlaze.OutlierRemoval).SetValue(True)

' Some properties have restrictions.
' We use API functions that automatically perform value corrections.
' Alternatively, you can use GetInc() / GetMin() / GetMax() to make sure you set
' a valid value.
camera.Parameters(PLBlaze.ConfidenceThreshold).SetValue(
    321,
    IntegerValueCorrection.Nearest
)

' Not all functions are available in older cameras.
' Therefore, we must use "Try" functions that only perform the action
' when parameters are writable. Otherwise, we would get an exception.
camera.Parameters(PLBlaze.MultiCameraChannel).TrySetValue(1)

Console.WriteLine("Operating Mode           : {0}",
    camera.Parameters(PLBlaze.OperatingMode).GetValue())
Console.WriteLine("Exposure Time            : {0}",
    camera.Parameters(PLBlaze.ExposureTime).GetValue())
Console.WriteLine("Spatial Filter           : {0}",
    camera.Parameters(PLBlaze.SpatialFilter).GetValue())
Console.WriteLine("Temporal Filter          : {0}",
    camera.Parameters(PLBlaze.TemporalFilter).GetValue())
Console.WriteLine("Temporal Filter Strength : {0}",
    camera.Parameters(PLBlaze.TemporalFilterStrength).GetValue())
Console.WriteLine("Outlier Removal          : {0}",
    camera.Parameters(PLBlaze.OutlierRemoval).GetValue())
Console.WriteLine("Confidence Threshold     : {0}",
    camera.Parameters(PLBlaze.ConfidenceThreshold).GetValue())

If camera.Parameters(PLBlaze.MultiCameraChannel).IsReadable Then
    Console.WriteLine("Multi-Camera Channel     : {0}",
        camera.Parameters(PLBlaze.MultiCameraChannel).GetValue())
End If

' Restore the old operating mode.
camera.Parameters(PLBlaze.OperatingMode).SetValue(oldOperatingMode)

采集数据#

请参考 Grabbing Images 章节(位于 pylon .NET Programmer's Guide 中),了解如何使用 pylon .NET API 获取数据。

pylon 将抓取到的图像表示为名为 GrabResults 的数据结构。由 2D 相机获取的 GrabResult 包含单个灰度图或彩色图。

由 blaze 相机抓取的 GrabResult 包含多个组件。默认情况下,每个 GrabResult 存储强度图、置信度图以及深度信息。

根据为 Range 组件设置的 Pixel Format,深度数据可以表示为 2D 深度图或 3D 点云。

信息

无法让相机同时发送点云和深度图形式的深度信息。

Processing Measurement Results 主题解释了如何从深度图计算点云。

抓取循环#

pylon 支持用于设置抓取循环的不同方法,并提供了用于处理 Memory 缓冲区的不同策略。

有关更多详细信息,请参考 Grabbing Images 章节(位于 pylon .NET Programmer's Guide 中)。

以下代码示例说明了一个典型的抓取循环:

// Open the connection to the camera device.
camera.Open();

// The MaxNumBuffer parameter can be used to control the amount of buffers
// allocated for grabbing. The default value of this parameter is 10.
camera.Parameters[PLCameraInstance.MaxNumBuffer].SetValue(3);

// Start grabbing.
camera.StreamGrabber.Start();

// Grab a number of images.
for (int i = 0; i < 10; ++i)
{
  // Wait for an image and then retrieve it. A timeout of 1000 ms is used.
  IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(
      1000,
      TimeoutHandling.ThrowException
  );
  using (grabResult) // Make sure that the grab buffers are reused for
                     // grabbing as soon we run out of scope.
  {
    // Image grabbed successfully?
    if (grabResult.GrabSucceeded)
    {
      // Access the data.
      // ....
    }
    else
    {
      Console.WriteLine("Error: {0} {1}",
      grabResult.ErrorCode, grabResult.ErrorDescription);
    }
  }
}
// Stop grabbing.
camera.StreamGrabber.Stop();
' Open the connection to the camera device.
camera.Open()

' The MaxNumBuffer parameter can be used to control the amount of buffers
' allocated for grabbing. The default value of this parameter is 10.
camera.Parameters(PLCameraInstance.MaxNumBuffer).SetValue(3)

' Start grabbing.
camera.StreamGrabber.Start()

' Grab a number of images.
For i As Integer = 0 To 10 - 1
  ' Wait for an image and then retrieve it. A timeout of 1000 ms is used.
  Dim grabResult As IGrabResult = camera.StreamGrabber.RetrieveResult(
    1000,
    TimeoutHandling.ThrowException
  )

  Using grabResult
    ' Image grabbed successfully?
    If grabResult.GrabSucceeded Then
      ' Access the data.
      ' ....
    Else
      Console.WriteLine("Error: {0} {1}",
        grabResult.ErrorCode,
        grabResult.ErrorDescription)
    End If
  End Using
Next

' Stop grabbing.
camera.StreamGrabber.Stop()

访问组件#

要访问 GrabResult 的各个组件,您可以使用 IDataContainer 和 IDataComponent 类。一个容器可以容纳一个或多个组件。您可以使用该容器来查询组件数量并检索特定组件。容器中的每个组件都包含实际数据(例如深度值)以及元数据。

使用 IGrabResult::GetDataContainer() 方法来访问 GrabResult 的 IDataContainer.

有关 pylon 如何提供对包含多个组件的 GrabResults 的访问的更多信息,请参考 Multi-Component Grab Results 章节(位于 pylon .NET Programmer's Guide 中)。

示例:

IGrabResult grabResult = camera.StreamGrabber.RetrieveResult(
  1000,
  TimeoutHandling.ThrowException
);
using (grabResult)
{
  // Image grabbed successfully?
  if (grabResult.GrabSucceeded)
  {
    // Access the components.
    // The container and the components should always be used in combination
    // with using statements. This ensures that the underlying grab buffers
    // are reused for grabbing new data as soon as the variables go out
    // of scope. Omitting the using statements and relying on the garbage
    // collector instead will cause buffer underruns resulting in missed data.
    using (var container = grabResult.Container)
    using (var rangeComponent = container[0])
    using (var intensityComponent = container[1])
    using (var confidenceComponent = container[2])
    {
      var pointCloudData = rangeComponent.PixelData as float[];
      var intensityData = intensityComponent.PixelData as UInt16[];
      var confidenceData = confidenceComponent.PixelData as UInt16[];

      // Access the center pixel.
      var u = (uint)(rangeComponent.Width / 2);
      var v = (uint)(rangeComponent.Height / 2);
      var idx = v * rangeComponent.Width + u;
      var intensity = intensityData[idx];
      var confidence = confidenceData[idx];
      // There is a triple (x,y,z) of floats per pixel.
      var x = pointCloudData[3 * idx];
      var y = pointCloudData[3 * idx + 1];
      var z = pointCloudData[3 * idx + 2];

      if (confidence != 0) // Alternatively: if (z != 0)
      {
        // Valid depth data
        Console.WriteLine("x={0}, y={1}, z={2}, intensity={3}, confidence = {4}",
            x, y, z, intensity, confidence);
      }
      else
      {
        Console.WriteLine("No depth data available for pixel ({0},{1}), intensity={2}",
        u, v, intensity);
      }
  }
  else
  {
      Console.WriteLine("Error: {0} {1}",
        grabResult.ErrorCode, grabResult.ErrorDescription);
  }
}
Dim grabResult As IGrabResult =
  camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException)

Using grabResult
  ' Image grabbed successfully?
  If grabResult.GrabSucceeded Then
    ' Access the components.
    ' The container and the components should always be used in combination with
    ' using statements. This ensures that the underlying grab buffers are reused
    ' for grabbing new data as soon as the variables go out of scope.
    ' Omitting the using statements and relying on the garbage collector instead
    ' will cause buffer underruns resulting in missed data.
    Using container = grabResult.Container,
      rangeComponent = container(0),
      intensityComponent = container(1),
      confidenceComponent = container(2)

      Dim pointCloudData = TryCast(rangeComponent.PixelData, Single())
      Dim intensityData = TryCast(intensityComponent.PixelData, UInt16())
      Dim confidenceData = TryCast(confidenceComponent.PixelData, UInt16())

      ' Access the center pixel.
      Dim u = CUInt((rangeComponent.Width / 2))
      Dim v = CUInt((rangeComponent.Height / 2))
      Dim idx = v * rangeComponent.Width + u
      Dim intensity = intensityData(idx)
      Dim confidence = confidenceData(idx)
      Dim x = pointCloudData(3 * idx)
      Dim y = pointCloudData(3 * idx + 1)
      Dim z = pointCloudData(3 * idx + 2)

      If confidence <> 0 Then ' Alternatively: if (z != 0)
        ' Valid depth data
        Console.WriteLine("x={0}, y={1}, z={2}, intensity={3}, confidence = {4}",
          x, y, z, intensity, confidence)
      Else
        Console.WriteLine("No depth data available for pixel ({0},{1}), intensity={2}",
          u, v, intensity)
      End If
    End Using
  Else
    Console.WriteLine("Error: {0} {1}", grabResult.ErrorCode,
      grabResult.ErrorDescription)
  End If
End Using

解释深度数据#

处理测量结果主题提供了有关存储在 Range 数据组件中的深度数据格式的信息。

调试应用程序并控制 GigE Vision Heartbeat#

使用 pylon 7.0 或更低版本时的重新连接问题

如果应用程序在正确关闭与相机的连接之前终止或崩溃,相机将保持连接打开状态,直到心跳超时过期。在心跳超时过期之前,相机将拒绝任何进一步的连接尝试。重新启动应用程序或启动请求访问相机的另一个应用程序时,您将收到一条错误消息,指出设备当前正在使用中。

这通常发生在使用调试器停止应用程序或应用程序意外终止时。要再次打开相机,您必须等待超时结束,或者暂时断开相机与网络的连接。

为了解决此问题,当应用程序在调试器的控制下运行时,您可以通过将名为 GEV_HEARTBEAT_TIMEOUT 的环境变量设置为所需的超时时间(以毫秒为单位)来覆盖心跳超时的自动调整。或者,您可以使用 pylon API 在应用程序中设置心跳超时,如 DeviceRemovalCSharp 和 DeviceRemovalVB 示例程序中所示。