Table of Contents
- Physically connect the camera to the system
- Connect a camera device using the Baumer GAPI SDK for C
- Working with camera features
- Feature types
- Is the feature implemented and available?
- Is the feature available for reading or writing?
- Read and write feature values
- Handling features with a set increment
- When do changed feature settings become active?
- Execute ICommand features
- Using IEnumeration features
- Further feature attributes
- Images and buffers
This document is meant to describe the basics on how to operate a camera using the Baumer GAPI SDK for C.
Physically connect the camera to the system
Obviously, the first step to work with a camera is to physically connect it to the data interface and a power source.
U3V(USB) cameras
All Baumer U3V cameras need to be connected to a free USB3 port on your host system. The USB3 port delivers the necessary power for the camera and provides the data interface. For Windows to recognize the camera it is necessary to install the Baumer USB driver provided in the Baumer GAPI installer. On Linux systems the libusb package is used and no further driver is necessary, however the udev-rules need to be configured to raise the available memory for the USB-system.
When connecting several cameras to one host, it is necessary to think about the USB architecture of your host system. Typically, a host system has several USB3 controllers. Each controller provides the specified bandwidth for USB3, however if more than one device is connected to one controller they have to share the available bandwidth. So if you need the full USB3 bandwidth, you need to ensure each camera is connected to its own USB3 controller.
Troubleshooting tips:
- Use high-quality USB3 cables as a low quality cable can influence the maximum transfer rate of the camera. Low quality cable might also not be able to deliver the necessary power for the camera.
- Ensure, that the chosen USB-port does actually deliver the required power of your camera (see the data-sheet of your camera for details on power consumption).
- When using a USB-hub, ensure that it is specified for the required data speed and power consumption of your camera.
GigE(Ethernet) cameras
Baumer GigE cameras are connected through standard ethernet ports. Standard GigE cameras require a free Gigabit Ethernet port to achieve their full framerate. 10GigE cameras like the LXT-series will need a free 10 Gigabit Ethernet port. On Windows systems, the Baumer filter-driver provided with the Baumer GAPI installer can be installed to reduce the processor load caused by the data-transfer.
When connecting multiple cameras to a host system, it is important to think about the ethernet network topology. When working with switches, it needs to be ensured that the uplink can support the bandwidth requirements of multiple cameras.
Depending on your application, the cameras can be powered via PoE or via an external power supply. Please see the data-sheet of your camera for details.
Troubleshooting tips:
- Use high-quality Ethernet cables as a low quality cable can influence the maximum transfer rate of the camera. Low quality cable might also not be able to deliver the necessary power for the camera.
- Ensure, that the chosen power supply does actually deliver the required power of your camera (see the data-sheet of your camera for details on power consumption).
- When using a switch, ensure that it is specified for the required data speed.
Connect a camera device using the Baumer GAPI SDK for C
The Baumer GAPI SDK for C provides you with a unified interface to all system components of a camera system. It is based on the GenTL and the GenICam API's provided and maintained by the EMVA.
Setup of the project, required headers
For the setup of an example project, please see the Setup and Getting Started page.
The Baumer GAPI model of the camera system
The API has 6 main sets of functions to deal with the different components of the camera system: System, Interface, Device, DataStream, Buffer and Node.
The System
The System module provides access to a GenTL Producer and encapsulates a method of transport such as USB or Ethernet. Use the BGAPI2_UpdateSystemList()
function to search for available producers and BGAPI2_GetSystem()
to access a system specified by the index. Finally call BGAPI2_System_Open()
to open a system to work with it.
See the section System functions for details on each available function.
The Interface
Each (useful) System has one or more Interfaces. An Interface is a specific Ethernet or USB port where a GenICam camera is connected to. Use the BGAPI2_System_UpdateInterfaceList()
function to update the list of available interfaces for your system followed by a call to BGAPI2_System_GetInterface()
and BGAPI2_Interface_Open()
to open the interface specified by the index to work with it.
See the Interface functions for details on each available function.
The Device
Each Interface can have one or more Devices (typically a camera) connected to it. You can use the BGAPI2_Interface_UpdateDeviceList()
function to update the list of available Devices followed by a BGAPI2_Interface_GetDevice()
and BGAPI2_Device_Open()
to open a chosen Device to work with it.
See the Device functions for details on each available function.
The DataStream
Each Device (camera) can have one or more DataStreams where images can be retrieved. You can use the BGAPI2_Device_GetDataStream()
function to get a DataStream by index, followed by a BGAPI2_DataStream_Open()
to open the DataStream to work with it.
See the DataStream functions for details on each available function.
The Buffer
Buffers are required to queue retrieve images from the DataStream. Firstly create some Buffers using the BGAPI2_CreateBuffer()
function. Next you need to announce and queue Buffers to the DataStream using BGAPI2_DataStream_AnnounceBuffer()
and BGAPI2_DataStream_QueueBuffer()
. To retrieve an image the BGAPI2_DataStream_GetFilledBuffer()
is used.
See the Buffer functions for details on each available function.
Lifetime of objects
When using the Baumer GAPI SDK for C you have full responsibility for the memory management of your application. You need to ensure that objects which are created are closed once not required anymore.
The Baumer GAPI "objects" are structured hierarchically and each object has an update-list function. Those update functions create the child-objects of a certain type. To close/destroy those objects it is sufficient to call BGAPI2_System_Close()
and BGAPI2_ReleaseSystem()
on the parent System. If you choose to manually close the object you need to ensure, that you destroy them in the right order.
Objects created as children of objects through functions:
BGAPI2_UpdateSystemList()
- creates zero or more System objectsBGAPI2_System_UpdateInterfaceList()
- creates zero or more Interface objectsBGAPI2_Interface_UpdateDeviceList()
- creates zero or more Device objects
Some objects are created independent and you are attaching them to parent object such as providing Buffers to the DataStream. To close/destroy those objects you need to de-attach them and destroy them manually.
Objects which exists independently from parent objects:
BGAPI2_CreateBuffer()
- creates a Buffer objectBGAPI2_CreateDeviceEvent()
- creates an DeviceEvent objectBGAPI2_CreatePnPEvent()
- creates an PnPEvent object
Error handling
As typical for C, the Baumer GAPI SDK for C makes use of return codes to communicate success, failure and errors. The result codes are provided as constants starting with BGAPI2_RESULT_*
Example: Connect a camera
The following example shows how to connect a camera set the exposure time and retrieve one image into a buffer. We print the frame ID, which is a counter the camera will increment and send with each image as a way to check if the image was actually retrieved correctly from the camera.
Attention
For clarity, and to focus on actual functionality the examples provided make assumptions on the system without handling errors. This code is not suitable for production without error-handling! The SDK provides examples, those contain the full error-handling so that they can run on any system without crashes.
Working with camera features
Every camera project requires configuring at least some basic settings of the camera. GenICam compatible devices use the SFNC naming convention to standardize how features are named see here for details about the machine vision standards.
Using the Baumer GAPI SDK each feature is presented as a node. A node has functions to get and set feature values and read additional information about the feature such as name, type, min/max values, etc.
Additionally, there are functions to check availability and access status of features using the nodes.
Feature types
The GenICam describes 6 different feature types:
- IInteger, IFloat, IBool, IString — Those are simple features, the take a value which will have some influence on the camera.
- IEnumeration — Those features are used in two ways. Firstly, like in “PixelFormat” they can behave like an enum, the feature can only take a set amount of values. The second use case for IEnumeration features are “Selector features” here the feature is used to switch one or more other features. A good example is the “GainSelector” which selects which color-channel the “Gain” feature represents for reading or writing a value.
- ICommand — These are features which will execute something on the camera, good examples are the “AcquisitionStart” or the “TriggerSoftware” features.
Is the feature implemented and available?
The Standard Feature Naming Convention (SFNC) describes many features a camera can implement, however not all features are implemented on all cameras. That means, before you can access a feature, you need to check if the feature is available on a camera using the BGAPI2_Node_GetImplemented()
method.
Some features can change depending on other features set on the camera. So for example the availability of feature ExposureTime depends on the value of feature ExposureAuto. ExposureTime will only be available if the ExposureAuto is switched off. You can use the BGAPI2_Node_GetAvailable()
method to get the current status.
Is the feature available for reading or writing?
To check if a feature is readable or writable the methods BGAPI2_Node_IsReadable()
and BGAPI2_Node_IsWriteable()
are implemented. Some features will never be writable such as the device serial number or the model name. Other features might change their access status depending on the value of another feature. As an example, if the feature “ExposureAuto” is switched on, the feature “ExposureTime” will be set to read-only thereby ensuring nobody does interfere with the AutoExposure algorithm.
Read and write feature values
Once the feature is checked for availability and read/write-ability, reading and writing a value is trivial. There are getters and setters for different data types.
Handling features with a set increment
Features can have a minimum, maximum or increment for the allowed values set. This means it is not possible to set the full range of numbers but only a subset. A good example are the features to set a region or area of interest (ROI/AOI). The features “Width”, “Height”, “OffsetX” and “OffsetY” can typically only take values which are multiples of 2, 4, 8 or 16 and which have a maximum/minimum depending on the sensor of the camera. If an increment is set for a feature, you can check the increment using BGAPI2_Node_GetIntInc()
and BGAPI2_Node_GetDoubleInc()
functions.
Attention
Some features do not have an increment but are rounded inside of a camera so writing 2.2 to the Gain feature will result in a value like 2.1877 when read back from the camera.
When do changed feature settings become active?
If you change the value of a feature, this might not be honored by the next image you retrieve from the camera. This can be for two reasons. Firstly, the changed feature must be written to the camera before start of the exposure, otherwise the image will be taken using the old settings. Secondly, because there is a buffer queue on the host it might be that the next image you request is already in a buffer and therefore will also be taken with older settings.
This behavior can especially be observed when triggering very fast or in free running mode. If this is an issue, you can avoid this firstly by executing "AcquisitionAbort" after changing the feature, this will ensure the camera does not deliver any image taking with old settings. Secondly you need to remove all buffers which might hold data taken before a feature change.
Execute ICommand features
One special category are features which execute something on the camera. Examples are the software trigger or the acquisition start/stop features.
Using IEnumeration features
Another special case are enumeration features. They can be two different things, either a “selector feature” such as the “GainSelector” which is used to change other features on the camera, or an enumeration like the “PixelFormat” which can only be assigned a set number of values.
The example below shows, how to loop through the possible values of the PixelFormat feature. With the call BGAPI2_Node_IsReadable()
we check two things, firstly if the feature PixelFormat is not locked, that could be the case if the Acquisition is not stopped. Secondly we check if a value allowed, meaning that the camera implements the functionality behind it.
The next example shows how a selector feature is used to access a set of similar features. A camera can have more than one GPIO line, each of the lines has a set of attributes. To access them for one of the GPIO lines we set the LineSelector to this line and can than read or write the attributes of this line.
Further feature attributes
Each feature has a set of methods which should make it easy to use them for calculations or in a GUI. The available methods do depend on the type of the feature.
Images and buffers
Now that you have a camera connected and know how to change camera settings via the features, it is time to get some images. To get to your first image is straight forward. Please be aware, that the Baumer GAPI does not provide functionality to display or save images. Please use your preferred framework (like OpenCV) for those tasks.
How are images transferred to the application?
Firstly, there are two different modes a GenICam camera can be operated in. The camera can either be in “free-run” mode, where the camera will constantly supply images. Secondly, there is the trigger mode where you need to tell the camera to take an image either via software command feature “TriggerSoftware” or via a hardware trigger impulse where the source is set via the feature “TriggerSource”.
The transfer of the images from the camera is the most critical process. It needs to be reliable so no image gets lost. It also needs to be really quick, as a single camera can already deliver up to 10 GBits of data per second to the host. Furthermore, the mechanics of the image transfer needs some flexibility as the host operating system is not a real-time OS, which means, we don't know exactly when the application will be scheduled next for work. And finally, to be able to process the data at high speeds, it is necessary to enable parallel execution of image processing.
To deal with those issues, a buffer queue is implemented. In the beginning, all those buffers are empty. Calling BGAPI2_DataStream_GetFilledBuffer()
on an empty buffer queue will result in an empty image. For the camera to deliver an image to the host, an empty buffer must be lined up to receive an image. If no empty buffer is available, the camera will produce so called under-runs and will drop the image. Once the camera can deliver an image to a buffer, it will be placed in the queue of filled buffers. On calling BGAPI2_DataStream_GetFilledBuffer()
, one of the filled buffers is given to the user.
At this point, the buffer is delivered directly to you, to be used in your application without further copying (copying of large data blocks is slow!). The buffer is owned by you and is not available for the Baumer GAPI to store a new image. Therefore, you need to ensure that you always return buffers back to the buffer queue using the BGAPI2_DataStream_QueueBuffer()
function.
You need to setup the required buffers and provide them to the DataStream for usage. Depending on your application you might change the amount of buffers to use, especially if working with high frame-rates. The example below will fail with an NoImageBufferException
after 8 images as the example code never returns any buffer back to the Baumer GAPI.