IDS Peak comfortSDK, genericSDK, IPL, and AFL developer manuals are external documents. Please contact us if you need them.
When your system consists of multiple cameras, you might want to make them capture the images at the same time or in a defined time sequence.
1.If your requirements in terms or timing are not very high, you can use the software trigger mode and send the TriggerSoftware command to all cameras one by one. There will be a non-deterministic delay for each camera due to the different transmission times, but for some applications the timing is accurate enough.
2.Connect the same hardware trigger signal to all cameras.
3.Use one camera as master and trigger all other cameras with its output signal. Compared to hardware trigger, this solution needs no additional trigger source. Compared to software trigger, this solution has a deterministic trigger delay and all cameras start the exposure at the same time.
|
Note that the flash signal will not match precisely at very short exposure times, as almost all sensors have a jitter in the delay.
|
Fig. 91: Master-slave camera setup
|
Note on I/O pinning and circuits
For I/O pin assignment and circuit information for your camera model, refer to the technical manual of the respective camera family.
|
You might need additional hardware for your synchronization signal if:
•Using USB3 cameras
•Connecting many slave cameras to one master camera
•Using long cables
|
NOTICE! You should not mix opto-coupled and non-opto-coupled lines (LineFormat = LVTTL or TriState) without signal processing hardware (level and direction). This could damage your camera.
|
Configuration
Each camera, master and slave, is configured to start the image capture on a signal on the physical line, as explained in hardware trigger mode.
Camera
|
Line
|
Description
|
Master
|
Line 0
|
Hardware trigger signal input
|
Line 2
|
Connected to Line 2 of slave camera
|
Slave
|
Line 2
|
Connected to Line 2 of master camera
|
Master camera configuration
The master camera uses a timer to generate the signal for the physical line. The duration of the timer corresponds to the duration of the signal on that line.
// Timer duration defines the signal duration for the slave cameras (us)
TimerSelector = Timer0;
TimerDuration = 1000.0; // 1ms
TimerTriggerSource = ExposureTrigger;
The source for the output line is this "Timer0Active" signal (or "Timer1Active", if you use "Timer1"). Using inverted GPIOs instead of opto-coupled inputs and outputs keeps delays as small as possible.
// Configure the output line, preferrably a GPIO
LineSelector = Line2;
LineMode = Output;
LineSource = Timer0Active;
LineInverter = True;
Now the "ExposureStart" trigger can use exactly the same signal on the output line, that is also sent to the slave cameras to synchronize capture times.
// Configure ExposureStart Trigger
TriggerSelector = ExposureStart;
TriggerMode = On;
TriggerSource = Line0;
Now, the master camera's image acquisition can be started.
// Start Acquisition
AcquisitionStart();
Slave camera configuration
The slave cameras receive the synchronization signal on one of the input lines. Using GPIOs instead of opto-coupled in- and outputs keeps delays as small as possible.
// Configure the input line, preferrably a GPIO
LineSelector = Line2;
LineMode = Input;
Use the synchronization signal for triggering "ExposureStart".
// Configure ExposureStart Trigger
TriggerSelector = ExposureStart;
TriggerMode = On;
TriggerSource = Line2;
Now, the image acquisition on the slave cameras can be started.
// Start Acquisition
AcquisitionStart();
Fig. 92: Basic timing diagram for master slave mode
Trigger delay for timing corrections
You can use the TriggerDelay parameters to fine-tune the camera timing. Add the configuration to the parameters above.
Master Camera Configuration: Add the TriggerDelay to adjust possible delays due to signal transfer on the lines and through the digital I/Os.
// Configure ExposureStart Trigger
// ...
TriggerDelay = 30.0;
Slave camera configuration: Add the TriggerDelay to adjust slight timing differences between slave cameras, if necessary.
// Configure ExposureStart Trigger
// ...
TriggerDelay = 5.0;
Fig. 93: Timing diagram for master slave mode with timing adaptions using trigger delays
Hardware signal as master trigger
You can use a signal on an input line as master trigger signal instead of the software command.
Master camera configuration: Add the TriggerDelay to adjust possible delays due to signal transfer on the lines and through the digital I/Os.
// Configure ExposureStart Trigger
TriggerSelector = ExposureStart;
TriggerMode = On;
TriggerSource = Line3;
TriggerActivation = FallingEdge;
TriggerDelay = 30.0;
Then the timer configuration changes, too.
// Timer duration defines the signal duration for the slave cameras (us)
TimerSelector = Timer0;
TimerDuration = 1000.0;
TimerTriggerSource = Line3;
TimerTriggerActivation = FallingEdge;
Slave camera configuration: The configuration for slave cameras is the same. Add the TriggerDelay to adjust slight timing differences between slave cameras, if necessary.
// Configure ExposureStart Trigger
// ...
TriggerDelay = 5.0;
Fig. 94: Timing diagram for master slave mode triggered by a hardware signal
IDS peak: code examples
try
{
// Configuration of the master camera
// Get remote device nodemap
auto masterNodeMapRemoteDevice = masterDevice->RemoteDevice()->NodeMaps().at(0);
// Configure the timer on the master camera to generate the synchronization signal
// Timer duration defines the signal duration for the slave cameras (us)
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TimerSelector")->SetCurrentEntry("Timer0");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::FloatNode>("TimerDuration")->SetValue(1000.0);
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TimerTriggerSource")->SetCurrentEntry("Off");
// Configure the synchronization signal on an output line, preferrably a GPIO
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineSelector")->SetCurrentEntry("Line2");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineMode")->SetCurrentEntry("Output");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineSource")->SetCurrentEntry("Timer0Active");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::BooleanNode>("LineInverter")->SetValue(true);
// Configure ExposureStart Trigger
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSelector")->SetCurrentEntry("ExposureStart");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerMode")->SetCurrentEntry("On");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSource")->SetCurrentEntry("Line2");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerActivation")->SetCurrentEntry("FallingEdge");
// VARIATON: Add the TriggerDelay to adjust possible delays
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::FloatNode>("TriggerDelay")->SetValue(30.0);
// Configuration of the slave camera(s)
// Get remote device nodemap
auto slaveNodeMapRemoteDevice = slaveDevice->RemoteDevice()->NodeMaps().at(0);
// Configure the synchronization signal on an output line, preferrably a GPIO
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineSelector")->SetCurrentEntry("Line2");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineMode")->SetCurrentEntry("Input");
// Configure ExposureStart Trigger
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSelector")->SetCurrentEntry("ExposureStart");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerMode")->SetCurrentEntry("On");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSource")->SetCurrentEntry("Line2");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerActivation")->SetCurrentEntry("FallingEdge");
// VARIATON: Add the TriggerDelay to adjust possible delays
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::FloatNode>("TriggerDelay")->SetValue(5.0);
// Next step: start acquisition on all cameras
// ...
// If TimerSelector has been changed in the meantime, uncomment the following line
// masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TimerSelector")->SetCurrentEntry("Timer0");
// Trigger the acquisition of an image
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::CommandNode>("TimerReset")->Execute();
// Stop acquisition
// ...
}
catch (const std::exception& e)
{
std::string strError = e.what();
// ...
}
// ALTERNATIVE: Hardware signal as master trigger signal
try
{
// Configuration of the master camera
// Get remote device nodemap
auto masterNodeMapRemoteDevice = masterDevice->RemoteDevice()->NodeMaps().at(0);
// Configure the timer on the master camera to generate the synchronization signal
// Timer duration defines the signal duration for the slave cameras (us)
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TimerSelector")->SetCurrentEntry("Timer0");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::FloatNode>("TimerDuration")->SetValue(1000.0);
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TimerTriggerSource")->SetCurrentEntry("Line3");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TimerTriggerActivation")->SetCurrentEntry("FallingEdge");
// Configure the synchronization signal on an output line, preferrably a GPIO
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineSelector")->SetCurrentEntry("Line2");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineMode")->SetCurrentEntry("Output");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineSource")->SetCurrentEntry("Timer0Active");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::BooleanNode>("LineInverter")->SetValue(true);
// Configure ExposureStart Trigger
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSelector")->SetCurrentEntry("ExposureStart");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerMode")->SetCurrentEntry("On");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSource")->SetCurrentEntry("Line3");
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerActivation")->SetCurrentEntry("FallingEdge");
// VARIATON: Add the TriggerDelay to adjust possible delays
masterNodeMapRemoteDevice->FindNode<peak::core::nodes::FloatNode>("TriggerDelay")->SetValue(30.0);
// Configuration of the slave camera(s)
// Get remote device nodemap
auto slaveNodeMapRemoteDevice = slaveDevice->RemoteDevice()->NodeMaps().at(0);
// Configure the synchronization signal on an output line, preferrably a GPIO
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineSelector")->SetCurrentEntry("Line2");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("LineMode")->SetCurrentEntry("Input");
// Configure ExposureStart Trigger
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSelector")->SetCurrentEntry("ExposureStart");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerMode")->SetCurrentEntry("On");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerSource")->SetCurrentEntry("Line2");
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TriggerActivation")->SetCurrentEntry("FallingEdge");
// VARIATON: Add the TriggerDelay to adjust possible delays
slaveNodeMapRemoteDevice->FindNode<peak::core::nodes::FloatNode>("TriggerDelay")->SetValue(5.0);
// Next step: start acquisition on all cameras
// ...
// If TimerSelector has been changed in the meantime, uncomment the following line
// masterNodeMapRemoteDevice->FindNode<peak::core::nodes::EnumerationNode>("TimerSelector")->SetCurrentEntry("Timer0");
// Image Acquisition is triggered with each falling edge of the master signal (Line3 of master camera)
// Stop acquisition
// ...
}
catch (const std::exception& e)
{
std::string strError = e.what();
// ...
}
|