Aborting a capture command waiting for a trigger

General Information

  • Product: C57-6-M
  • Serial Number: 244888
  • Ensenso SDK Version: 4.0.1502
  • Operating System: Windows
  • C++ Interface

Problem / Question

I am capturing images using the hardware trigger.(TriggerMode:FallingEdge)
However, there may be cases where I want to interrupt capture while waiting for a trigger.
Therefore, it is not used with the Capture command, which cannot be interrupted midway.
Is there any good way to achieve this?

Currently this is achieved in the following way:
I uses the Trigger command and the Retrieve command.
After executing the Trigger command,
I executes a Retrieve command with a short timeout set in a While loop,
and detects interrupted operations between the Retrieve commands.

Best regards,
K.N,

The way you are combining Trigger and Retrieve is pretty much how we suggest it in our Capturing Images with Hardware Trigger Guide. You can either poll the result (Timeout = 0) as it is done in the example or set a short timeout as you have done.

The problem that I see is: Since you are executing the retrieves with small timeouts, there is no way for you to break the Retrieve command if you detect an interrupt, because the command has already finished. In order for you to be able to cancel the current Trigger and Retrieve sequence, I would suggest you do something like this:

{
	NxLibCommand(cmdTrigger).execute();

	NxLibCommand retrieve(cmdRetrieve);

	// Use a long timeout here so that we can cancel the command
	retrieve.parameters()[itmTimeout] = 5000;

	// Do not wait until the command execution finished, instead we poll
	retrieve.execute(false);

	while (true) {

		if (retrieve.finished() && retrieve.result()[serial][itmRetrieved].asBool()) {
			// A new image has been received and copied into the raw image node
			break;
		}

		// Check for an interrupt
		if (interrupt) {
			// Cancel the current retrieve
			retrieve.cancel();

			// Wait until the command has finished
			while (true) {
				if (retrieve.finished()) {
					break;
				}
			}

			break;
		}
	}
}

Let me know if this works for you or if you have any further questions.

Kind Regards
Benny


Edit: The code block has been edited, because it re-executed the Retrieve command in the while-loop.

1 Like

Hi Benjamin

First, thanks a lot for your quick response!
I’m going to try it right away.

How should I write the sample code you provided in C (language) interface
(like a C examples(basic C API calls))
instead of C++ interface?

I’d especially like to know about
“retrieve.execute(false);”,
“retrieve.cancel();”,
and “retrieve.finished()”.

Thanks for your support and
With kind regards
K.N.

The C++ API just adds an additional layer of convenience classes and functions, but under the hood it uses C-API calls. Have a look at nxLibFunctions.h, which under Windows is installed by default under:
C:\Program Files\Ensenso\development\c\include\

execute():
You can see how this is done in the C++ interface. If you come across the term “slot”, please refer to the tree documentation of the default slot for more information.

cancel():
It is important here is that you run the Break command in the same execution slot in which the Retrieve command has been executed in (the C++ interface shows how this is done exactly).

finished():
A command execution is finished by definition, if the Command node of the execution slot is null again.

Kind Regards
Benny

1 Like

Hi Benjamin

Thanks a lot for your quick response!
I tried it.
But it didn’t work.

1.Even if the trigger is triggered (Projector LED is ON->OFF),
“retrieve.result()[serial][itmRetrieved].asBool()”
remains false and does not become true.

2.Sometimes, after connecting the camera,
an image may be acquired with the first trigger input,
but from the second time onwards,
retrieve remains false and does not change.

The presented code is also executed from the beginning
when capturing the second image.

   {
       NxLibCommand(cmdTrigger).execute();
       .....
                break;
	        }
        }
    }

What could be the problem?
I’d like some advice on what I should check.

Thanks for your support and
With kind regards
K.N.

Could you share your code and a log file for each of the two cases? You can either post the information here or, if it contains sensitive data you don’t want to share, send me a file share link via PN?

In another post a colleague of mine explained how to create a log file (see the expandable section).

1 Like

Prepare the sources and logs.
I’m trying to create a log file,
but I couldn’t find the link you provided.

Please tell me how to create a log file?

Sorry, my fault. The post I linked to is not publicly available.

We have a guide on exporting debug information. I also described it in this post using the Python API, but the principle should be the same.

1 Like

I have been able to obtain Logs of each phenomenon.
Could you please confirm that this is the intended data?
settings.json (240 Bytes)
Case1-20250314(All4timesTriggerSwPush-FailedtoRetrieve).zip (42.1 MB)
Case2_1-20250314(1timesRetrieveSuccessOutOf4timesTriggerSwPush).zip (57.1 MB)
Case2_2-20250314(2timesRetrieveSuccessOutOf4timesTriggerSwPush).zip (45.0 MB)

In every log, the hardware trigger switch was turned on four times,
and the projector LED lit up all four times.

Case1-20250314(All4timesTriggerSwPush-FailedtoRetrieve):
The hardware trigger switch was turned ON and the projector LED lit up,
but Retrieve was not completed, so this is a log of the hardware trigger switch
being pressed three more times.
The hardware trigger switch was pressed a total of four times,
and the projector LED lit up all four times.

Case2_1-20250314(1timesRetrieveSuccessOutOf4timesTriggerSwPush):
The hardware trigger switch was turned on four times,
and the first time an image was acquired by Retrieve.
The hardware trigger switch was pressed the second time,
but Retrieve was not completed,
so the hardware trigger switch was pressed a further two times.
The hardware trigger switch was pressed four times,
and the projector LED lit up all four times.

Case2_2-20250314(2timesRetrieveSuccessOutOf4timesTriggerSwPush):
The hardware trigger switch was turned on four times,
and the first two times images were acquired by Retrieve.
The hardware trigger switch was pressed the third time,
but Retrieve was not completed,
so the hardware trigger switch was pressed once more.
The hardware trigger switch was pressed four times,
and the projector LED lit up all four times.


As for the code, there is a lot of irrelevant code as it is,
so I have prepared an excerpt of the relevant parts.
Please check it together with the log,
and let me know if you have any questions.

smplcode.cpp (10.5 KB)


I would also like to ask the following questions:
Q1.
How can I confirm that the hardware trigger switch
has been electrically turned ON or OFF on NxProfiler after reading the log?
Q2.
Is it possible to check that the hardware trigger is on
and the projector LED is lit blue, but Retrieve has not been performed?
(I would like to check on NxProfiler that the projector LED is lit blue.)
Q3.
Does the “retrieve.result()[m_serial][itmRetrieved].asBool()” become true
when “Execution of command ‘Retrieve’ successful” occurs on Nxprofiler?
Or, when “Execution of command ‘Retrieve’ successful” occurs,
“retrieve.finished()” becomes true,
but the timing when “retrieve.result()[m_serial][itmRetrieved].asBool()”
becomes true is different?

Thanks for your support and
With kind regards
K.N.

Thank for providing the debug data.

I had a look at your log files and the source code. It looks like you are opening stereo and color camera separately. I think in order for them to operate as one combined camera, you would have to open them together in one Open command by providing both serials to the Cameras node of the command parameters as you have done with RenderPointMap (line 95+96).

After you ran Trigger, the PiezoCaptureThread starts the FlexView capture sequence and actually captures 3 image pairs (the first left image takes 2s, so I assume this is when you pressed the button and the hardware trigger worked).

The problem now is that the Retrieve command only retrieves the image of the color camera (m_serial_C), but you are checking whether the result for m_serial has been retrieved. In the image below I marked the arrival of the stereo and the color images. The first “Retrieve run” retrieves the color image while the following three timeout because no more color images are captured.

The C-Series has a special internal trigger mode compared to our other cameras. To me it looks like the hardware trigger is working, which then also triggers the image acquisition of the color camera after (and this is expected behavior) the FlexView Sequence has been captured. What I do not understand right now is why the Retrieve command does set the flags for the left and right camera. But I will clarify this with my colleagues.

For now I would suggest that you only open the stereo camera and keep the color camera closed. This way we can focus on getting the hardware trigger to work in combination with the Retrieve command and your interrupt mechanism. If this works as expected, we can also add the color camera and make sure that everything works together.

1 Like

I had a colleague have a look at your code and the problem is stemming from there. Or rather from the code snippet I provided above:

retrieve.execute(false);

// If the command had finished, we have overwritten the result
// by re-executing the command at this point. Hence the next if
// statement will never be entered.

if (retrieve.finished() && retrieve.result()[serial][itmRetrieved].asBool()) {
    // A new image has been received and copied into the raw image node
    break;
}

Please move setting the timeout and executing the retrieve command outside the while-true loop:

{
	NxLibCommand(cmdTrigger).execute();

	NxLibCommand retrieve(cmdRetrieve);
	
	// Use a long timeout here so that we can cancel the command
	retrieve.parameters()[itmTimeout] = 5000;

	// Do not wait until the command execution finished, instead we poll
	retrieve.execute(false);

	while (true) {

		if (retrieve.finished() && retrieve.result()[serial][itmRetrieved].asBool()) {
			// A new image has been received and copied into the raw image node
			break;
		}

		// Check for an interrupt
		if (interrupt) {
			// Cancel the current retrieve
			retrieve.cancel();

			// Wait until the command has finished
			while (true) {
				if (retrieve.finished()) {
					break;
				}
			}

			break;
		}
	}
}

Due to the repeated parameter setting and command execution, the buffers of the “Translator” thread did overflow and make it impossible to see in the NxProfiler what the Retrieve command actually returned.

The following, which I assumed in my last post, is not true. You can safely open the cameras separately for them to operate together. It only saves time to open them with one command.

I think in order for them to operate as one combined camera, you would have to open them together in one Open command by providing both serials to the Cameras node of the command parameters […]

I am sorry for the inconvenience.

Kind Regards
Benny

1 Like

Should I make the following changes?

{
	nxLibSetString(&error, "/Execute/Parameters/Cameras", m_serial);
	if (error)	IdsErrorDsp(error);
	nxLibSetString(&error, "/Execute/Command", "Open");
	if (error)	IdsErrorDsp(error);
	nxLibWaitForType(&error, "/Execute/Command", NxLibItemTypeNull, 1);
	if (error)	IdsErrorDsp(error);
}
{
	nxLibSetString(&error, "/Execute/Parameters/Cameras", m_serial_C);
	if (error)	IdsErrorDsp(error);
	nxLibSetString(&error, "/Execute/Command", "Open");
	if (error)	IdsErrorDsp(error);
	nxLibWaitForType(&error, "/Execute/Command", NxLibItemTypeNull, 1);
	if (error)	IdsErrorDsp(error);
}

Chenge to

{
	nxLibSetString(&error, "/Execute/Parameters/Cameras", m_serial);
	if (error)	IdsErrorDsp(error);
	nxLibSetString(&error, "/Execute/Command", "Open");
	if (error)	IdsErrorDsp(error);
	nxLibWaitForType(&error, "/Execute/Command", NxLibItemTypeNull, 1);
	if (error)	IdsErrorDsp(error);
}

Since we now know that the problem probably came from the repeated Retrieve execution, you can keep opening both the stereo and the color camera. The log files showed, that the color capture worked in combination with your hardware trigger.

1 Like

Hi Benjamin

Thanks a lot for your quick response!
I have tried the following modifications based on what you have advised.

  • Move the TimeOut setting and execute outside the while loop
  • Change the Retrieve command completion judgment condition to the following:

if((retrieve.finished())
&&(retrieve.result()[m_serial][itmRetrieved].asBool())
&&(retrieve.result()[m_serial_C][itmRetrieved].asBool()))

  • The color camera’s TriggerMode was set to “Software”,
    so it was changed to “internal”.
  • No changes to camera open processing

With the above changes, it mostly worked fine.
However, if I left the while loop running for about 20 minutes without inputting a trigger,
it was no longer possible to determine that the Retrieve command had been completed, even when the trigger switch was turned on.
(When the switch is on, the projector LED glows blue.)
(If the device is left unused for a short period of time, it will function normally.)

Specifically,
even when the trigger switch was turned ON,
“retrieve.finished()” became true,
but variables
retrieve.result()[m_serial][itmRetrieved].asBool()
and
retrieve.result()[m_serial_C][itmRetrieved].asBool()
remained false.

The main changes in the code:

cnt = 0;
NxLibCommand retrieve(cmdRetrieve);
retrieve.parameters()[itmTimeout] = 5000;

while (1) {
	if((retrieve.finished())
	 &&(retrieve.result()[m_serial][itmRetrieved].asBool())
	 &&(retrieve.result()[m_serial_C][itmRetrieved].asBool())) {
		break;
	}
	if (!pThread->m_Valid) { //cancel
		retrieve.cancel();

		while (true) {
			if (retrieve.finished()) {
				break;
			}
		}
		return(1);
	}
	else{
		if (cnt == 1) {			if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)・")); }
		else if (cnt == 2000) {	if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)・・")); }
		else if (cnt == 4000) { if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)・・・")); }
		else if (cnt == 6000) { if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)"));	cnt = 0; }
		cnt++;
	}
}

The following data was taken
after leaving it for 20 minutes and then starting the log and
turning the trigger switch ON.
tmp_NxTreeEdit20250315(NonRetrieveAfter20min).zip (12.1 MB)

Could you please give me some advice?
Thank you in advance.
K.N.

The issue occurred even after leaving it alone for five minutes, so I will upload the log that I had been collecting since before I left it alone.
tmp_NxTreeEdit20250315(NonRetrieveAfter5min-AllLog).zip (214.0 MB)

thank you.
K.N.

Thinking about it calmly,
it seems that the cause is the retrieve command timing out.

In actual usage, the trigger may turn ON every 10 seconds,
but after starting the system in the morning,
it may continue to wait for a trigger until the evening.

In this case, would it be better to extend the time for the retrieve command?
Or would it be better to check the timeout and issue the retrieve command again?

Could you please tell me how to check the timeout of the etrieve command,
like the code you previously provided?

thank you.
K.N.

As an experiment,
I made the following changes and turned on the trigger switch about 10 seconds
after issuing the Trigger command, but Retrieve was not successful.
(asBool() did not become true.)


		if (retrieve.finished()) {
			if ((retrieve.result()[m_serial][itmRetrieved].asBool())
			 && (retrieve.result()[m_serial_C][itmRetrieved].asBool())) {
				break;
			}
			else{
				if (retrieve.result()[itmErrorSymbol].asString() == "CaptureTimeout") {
					retrieve.parameters()[itmTimeout] = 5000;
					retrieve.execute(static_cast<bool>(false));
				}
			}
		}

The following Log was taken when the trigger switch was turned on three times
about 10 seconds after the Trigger command was issued.
(The projector LED lit up blue all three times.)
tmp_NxTreeEdit20250317(NonRetrieveAfter10min-Try3timesTrigON).zip (32.6 MB)

thank you.
K.N.

It looks like you are not executing the Retrieve command, at least I cannot find the corresponding line in the code snippet you posted above:

cnt = 0;
NxLibCommand retrieve(cmdRetrieve);
retrieve.parameters()[itmTimeout] = 5000;

// The call to retrieve.execute(false); is missing here

while (1) {
    // retrieve.finished() always return true at this point

    // ...
}

This would explain why retrieve.finished() returns true, because you only created the command slot, but never executed it, which leaves the command being finish.

Can you confirm that this is actually the case here?

1 Like

Sorry.
I only described the changes.
The overall picture is as follows.

cnt = 0;
NxLibCommand retrieve(cmdRetrieve);
retrieve.parameters()[itmTimeout] = 5000;

while (1) {
	if (retrieve.finished()) {
		if ((retrieve.result()[m_serial][itmRetrieved].asBool())
		 && (retrieve.result()[m_serial_C][itmRetrieved].asBool())) {
			break;
		}
		else{
			if (retrieve.result()[itmErrorSymbol].asString() == "CaptureTimeout") {
				retrieve.parameters()[itmTimeout] = 5000;
				retrieve.execute(static_cast<bool>(false));
			}
		}
	}
	if (!pThread->m_Valid) { //cancel
		retrieve.cancel();
		while (true) {
			if (retrieve.finished()) {
				break;
			}
		}
		return(1);
	}
	else{
		if (cnt == 1) {			if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)・")); }
		else if (cnt == 2000) {	if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)・・")); }
		else if (cnt == 4000) { if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)・・・")); }
		else if (cnt == 6000) { if (pThread->m_Valid)	pThread->UpdateStatus(_T("Wait Trig(Wait Retrieved fin)"));	cnt = 0; }
		cnt++;
	}
}

thank you.
K.N.

So you are not executing the Retrieve command. What happens in your code is the following:

  • The Retrieve command is set up, but not executed yet
  • The while-loop is entered
  • It is checked whether Retrieve finished, which it did not really, but since you never executed it, it is still in its initial state in which the Command subnode is still null, causing finished() to return true
  • There are no command results, because the command was not executed, which means that the else-branch is taken
  • There it is checked whether the Retrieve command ran into a “CaptureTimeout”
  • But there is no such error symbol in the command result, because the command was not executed, hence the retrieve.execute(static_cast<bool>(false)); line is never reached

You have to execute the Retrieve command once before entering the loop, as I wrote in my post above. Can you confirm that this solves the problem?

1 Like