Baumer工业相机堡盟相机如何使用PnPEventHandler实现相机掉线自动重连(C++新)

简介: Baumer工业相机堡盟相机如何使用PnPEventHandler实现相机掉线自动重连(C++新)

项目场景:

Baumer工业相机堡盟相机传统开发包BGAPI SDK进行工业视觉软件整合时,常常需要将SDK中一些功能整合到图像处理软件中,方便项目的推进使用;


在项目的图像处理任务中,可能会因为一些硬件比如线缆网卡的原因导致出现偶尔掉线,而软件重启则可以重新连上,这时为了适用于自动化设备不停线的情况下,需要图像处理软件可以自动进行断线重新连接。


注意:本文是基于Baumer的BGAPI SDK的基础上使用C++语言来实现相机的掉线重新连接。


注意:该方法与上一篇自动重连机制有所不同,更加的便捷,更符合PnPEventHandler事件定义:


Baumer工业相机堡盟相机如何实现相机掉线重连(C++)_格林威的博客-CSDN博客


如何发现掉线


Baumer工业相机BGAPI SDK中在相机事件中存在一种PnpEvent事件可以监控相机是否掉线,从而能够及时发现相机的问题。


在BGAPI SDK的C++开发包里存在PnpEvent的事件例程,关键字为:013_PnPEventMode_Handler


下面为例程中PnPEvent事件核心代码,已经进行优化

// CALLBACK
void BGAPI2CALL PnPEventHandler(void * callbackOwner, BGAPI2::Events::PnPEvent * pPnPEvent) {
    if (NULL != pPnPEvent) {
        std::cout << std::endl;
        std::cout << std::endl;
        std::cout << " [callback of " << ((BGAPI2::Interface *)callbackOwner)->GetDisplayName() << "] ";
        std::cout << " EventID " << pPnPEvent->GetId() << " PnPType: "
            << ((pPnPEvent->GetPnPType() == 0) ? "removed" : "added  ")
            << " SerialNumber: " << pPnPEvent->GetSerialNumber() << std::endl;
        std::cout << std::endl;
    return;
}

相机掉线重连实现方法:

1、在相机初始化的过程中,在相机对应的网口中注册SDK中PnPEvent回调函数


代码如下所示:

//为相机对应数据流注册掉线触发事件
m_pInterface->RegisterPnPEvent(BGAPI2::Events::EVENTMODE_EVENT_HANDLER);        
m_pInterface->RegisterPnPEventHandler(this, (Events::PnPEventHandler) &PnPEventHandler);

2、在PnPEvent回调函数里进行相机掉线事件的分析并对应实现相机的再次查找


注意在回调里尽量不要处理太多任务,可以从回调里发出信息,在外部处理回调发出的任务信息。本例在回调里处理任务方便参考,请大家理解。


PnPEvent回调函数代码如下所示:

BOOL BGAPI2CALL PnPEventHandler(void * callBackOwner, BGAPI2::Events::PnPEvent * pPnPEvent)
{
  if (NULL != pPnPEvent)
  {
  const char* EventTypeStrC = ((pPnPEvent->GetPnPType() == 0)? "removed" : "added");
  CString EventTypeStr(EventTypeStrC);
  BaumerCameraDriver* pCamera = (BaumerCameraDriver*)callBackOwner;
  if(EventTypeStr == _T("removed"))
  {
    //AfxMessageBox(_T("相机离线"));  
    pCamera->ReleaseCamera(); //释放相机资源  
  }
  if(EventTypeStr == _T("added"))
  {
    //AfxMessageBox(_T("相机在线"));
    #pragma region//网口资源的初始化
    pCamera->systemList = SystemList::GetInstance();
    pCamera->systemList->Refresh();
    int sysindex = 0; int devcount = 0;
    for(SystemList::iterator sysIterator = pCamera->systemList->begin();sysIterator != pCamera->systemList->end();sysIterator++)
    {
    CString sysModel0 = A2W(sysIterator->second->GetModel()); //bgapi_gige
    if(sysModel0.Find(_T("gige"))!=-1)    //此例程只连接网口Gige相机
    {     
      pCamera->pSystem = sysIterator->second;
      break;
    }
    sysindex++;
    }
    pCamera->interfaceList = pCamera->pSystem->GetInterfaces();
    pCamera->interfaceList->Refresh(100);
    int infcount =pCamera-> interfaceList->size();     //可以找到多个interface网络接口(包含实际接口和虚拟接口)
    for(InterfaceList::iterator ifIterator = pDlg->interfaceList->begin(); ifIterator != pDlg->interfaceList->end();ifIterator++)
    {
    CString infType = A2W(ifIterator->second->GetTLType());
    CString infName = A2W(ifIterator->second->GetDisplayName());
    BGAPI2::Interface* m_pInterface0 = ifIterator->second;
    if(m_pInterface0->IsOpen())               //检查网口是否开启
    {
      BGAPI2::DeviceList* m_pDeviceList = m_pInterface0->GetDevices();
      m_pDeviceList->Refresh(100);  
      int devcount = m_pDeviceList->size();     //一般为1
      if(devcount>0)
      {
      bool devListRefresh_reqiured = false;
      BGAPI2::Device * m_pDevice = (*m_pDeviceList)[0];
      if(m_pDevice->IsOpen())
      {
        if(pPnPEvent->GetSerialNumber()==m_pDevice->GetSerialNumber())
        {
        m_pDevice->Close();
        devListRefresh_reqiured = true;
        }
      }
      if (devListRefresh_reqiured)
      {
        m_pDeviceList->Refresh(200);
      }
      }
    }
    }
    #pragma endregion
    //相机的再连接
    pCamera->RelinkCamera();
  }
  return TRUE;
  }
}


3、在PnPEvent掉线发生后需要释放对应的资源,防止内存泄漏;


代码如下所示:

void CGigeDemoDlg::ReleaseCamera()
{
  //m_pDatastreamList = CurDevice->GetDataStreams();//获取相机设备数据流序列
  int iDscount = m_pDatastreamList->size();//一般为1  
  if(iDscount>0)
  m_pDataStream = (*m_pDatastreamList)[0];
  try
  {    
  m_pDataStream->StopAcquisition();                   //停止采集相机数据流
  }
  catch (BGAPI2::Exceptions::IException& ex)
  {}  
  try
  {
  m_pBufferList = m_pDataStream->GetBufferList();//获取相机设备数据流的Buffer序列
  while (m_pBufferList->size() > 0)              //对Bufferlist里每个buffer对象进行释放删除
  {
    BGAPI2::Buffer* m_pBuffer = m_pBufferList->begin()->second;
    m_pBufferList->RevokeBuffer(m_pBuffer);    //对当前buffer对象进行释放
    delete m_pBuffer;                          //对当前buffer对象进行删除
  }
  }
  catch (BGAPI2::Exceptions::IException& ex)
  {}
  try
  {  
  m_pDataStream->Close();                        //关闭相机数据流    
  }
  catch (BGAPI2::Exceptions::IException& ex)
  {}
}


4、在对应相机进行一定程度的释放资源后,相机的PnPEventHandler回调函数事件是一直再运行中,若相机重新连接上后,该回调函数事件回同步得到触发,因此可以同步执行相机资源的初始化和相机的自动重连;

void CGigeDemoDlg::ReConnectCamera(BGAPI2::Interface* CurInterface)
{
  USES_CONVERSION;
  m_pDeviceList = m_pInterface->GetDevices();
  m_pDeviceList->Refresh(100);  
  int devcount = m_pDeviceList->size();
  m_pDevice = (*m_pDeviceList)[0];
  m_pDevice->Open();
  CString devName = A2W(m_pDevice->GetDisplayName());
  m_pDatastreamList = m_pDevice->GetDataStreams();
  m_pDatastreamList->Refresh();
  int iDscount = m_pDatastreamList->size(); 
  BGAPI2::DataStream *m_pDataStream0 = (*m_pDatastreamList)[0];  //这里的DataStream需要使用临时变量
  m_pDataStream0->Open();
  m_pBufferList = m_pDataStream0->GetBufferList();
  for(int i=0; i<4; i++)
  {
  m_pBuffer = new BGAPI2::Buffer();
  m_pBufferList->Add(m_pBuffer);
  }
  for (BGAPI2::BufferList::iterator bfIterator = m_pBufferList->begin();bfIterator != m_pBufferList->end();bfIterator++)
  {
  bfIterator->second->QueueBuffer();
  }
  int iQBuffer = m_pBufferList->GetQueuedCount();
  int x=0;
  m_pDataStream0->RegisterNewBufferEvent(BGAPI2::Events::EVENTMODE_EVENT_HANDLER);
  m_pDataStream0->RegisterNewBufferEventHandler(this,(Events::NewBufferEventHandler) &BufferHandler);
  String strTrgStatus;
  strTrgStatus = m_pDevice->GetRemoteNode("TriggerMode")->GetString();
  CString strTrgStatusC = A2W(strTrgStatus);
  m_pDataStream0->StartAcquisitionContinuous();
  AfxMessageBox(devName+_T("已连接"));
}

5、上述相机将会在回调函数中自动完成重连操作,然后重新点击采图可以发现相机已经恢复正常。


相机连接代码如下所示:

void CGigeDemoDlg::OnBnClickedBtnplay()
{
  // TODO: 在此添加控件通知处理程序代码
  USES_CONVERSION;
  if(m_pDevice != NULL)
  {
  try
  {
    m_pDevice->GetRemoteNode("TriggerMode")->SetString("Off"); //关闭触发模式,进入自由采集图片流模式
    m_pDevice->GetRemoteNode("AcquisitionStart")->Execute();
    #pragma region 线程显示帧率和网口数据通量(做参考)
    m_bRun0 = true;
    //AfxBeginThread(ShowFrame_hThread1, (void*)this);    
    #pragma endregion 
  }
  catch (BGAPI2::Exceptions::IException& ex)
  {
    CString str1;
    str1.Format(_T("ExceptionType:%s! ErrorDescription:%s in function:%s"),ex.GetType(),ex.GetErrorDescription(),ex.GetFunctionName());
    MessageBox(str1);
  }
  }
}

6、完成上面操作后,就可以及时对掉线相机进行断线重连操作,可以尝试重新连接,也可以检查对应相机状态,需要对应掉线事件操作什么,取决于开发者想要什么的功能实现。


结论要点

工业相机的重连机制依托于相机的PnPEvent事件触发,并且出现PnPEvent事件后可以触发一个间隔1-2s的线程,反复刷新对应网口interface的相机,找到相机后,然后线程终止,然后再触发一个重新连接的功能或者方法。


PnPEvent事件类型有移除和增加两种类型,可以针对两种类型做相应的自定义处理。


事件类型如下图所示:


1.png


并且在刷新工业相机List的过程中可以根据类的构成和习惯有所不同,比如锁定好接口,方便快速只刷新这个接口,从而适用于多相机的系统。


注意

工业相机的重连功能基本上是属于软件层面的重新连接,若是涉及到硬件层面的变更和重连则需要更为严格的对象设计和逻辑优化。


本文的重连则采用了上述的PnPEvent事件类型来进行判断。

目录
相关文章
|
数据采集 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
267 0
|
算法框架/工具 C++ Python
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
1529 0
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
248 0
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
11月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
438 12
|
9月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
233 0
|
9月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
372 0
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
220 16
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
12月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。