私はQtアプリケーションを使用して産業用カメラを制御しています。特に、特定の時間(たとえば、さまざまな照明設定が設定されている場合)にカメラをトリガーし、フレームが返されるまで待つ必要があります。最も単純なケースでは、次のコードがうまく機能します。
void AcquireFrame()
{
// Runs in the main GUI thread:
camera -> m_mutex.lock();
camera -> frameHasArrived = false;
camera -> m_mutex.unlock();
camera -> triggerImageAcquisition();
forever
{
camera -> m_mutex.lock()
bool isReady = camera -> frameHasArrived;
camera -> m_mutex.unlock()
if (isReady)
{
return;
}
else
{
Sleep(10);
}
}
}
void callback(camera *)
{
// Called by the camera driver from a separate OS thread - not a Qt thread -
// when a frame is ready:
camera -> m_mutex.lock();
camera -> frameHasArrived = true;
camera -> m_mutex.unlock();
}
...そしてほとんどの場合、これは完全にうまく機能します。ただし、これは現実の世界であるため、カメラがトリガーを受信できない場合や、コンピューターがフレームを正常に受信できない場合があり、上記のコードは無限ループに入ります。
当然のことですが、タイムアウトを設定することです。そのため、フレームが特定の時間内に受信されない場合は、画像の取得を再試行できます。改訂されたコードは次のようになります。
void AcquireFrame()
{
camera -> m_mutex.lock();
camera -> frameHasArrived = false;
camera -> m_mutex.unlock();
camera -> triggerImageAcquisition();
QTime timeout;
timeout.start();
forever
{
timeout.restart();
fetch: camera -> m_mutex.lock()
bool isReady = camera -> frameHasArrived;
camera -> m_mutex.unlock()
if (isReady)
{
return;
}
else if (timeout.elapsed() > CAM_TIMEOUT)
{
// Assume the first trigger failed, so try again:
camera -> triggerImageAcquisition();
continue;
}
else
{
Sleep(10);
goto fetch;
}
}
}
さて、問題は、この後者のバージョンでは、失敗率(「失敗したトリガー」の割合)がはるかに高く、少なくとも1桁高いことです。さらに、このコードも最終的には無限ループに陥ります。カメラを再トリガーしようとしても、フレームが戻ってくることはありません。後者の状況では、アプリケーションを強制終了してカメラをチェックすると、カメラが完全に機能し、次のトリガーを辛抱強く待っていることがわかります。したがって、カメラの問題ではないようです。実際、これはある種のシステムリソースの問題またはスレッドの競合であるため、Qtのイベントループではカメラのコールバックを適切なタイミングで呼び出すことができないという結論に達しました。
これは可能性がありますか、そして実際にこれを行うためのより良い方法はありますか?
6月6日の更新:
以下の方法を採用して以来、問題は発生していません(カメラオブジェクトに追加のメンバー、つまり「m_condition」と呼ばれるQWaitConditionを指定しました)。
void AcquireFrame()
{
bool frameReceived;
forever
{
camera -> triggerImageAcquisition();
camera -> m_mutex.lock();
frameReceived = camera -> m_condition.wait(&camera->m_mutex, CAM_TIMEOUT);
if (frameReceived)
{
// We received a frame from the camera, so can return:
camera -> m_mutex.unlock();
return;
}
// If we got to here, then the wait condition must have timed out. We need to
// unlock the mutex, go back to the beginning of the 'forever' loop and try
// again:
camera -> m_mutex.unlock();
}
}
void callback (camera *)
{
// Called by the camera driver from a separate OS thread -
// not a QThread - when a frame is ready:
camera -> m_condition.wakeOne();
}
これには、フレームを受信するかタイムアウトが発生するまでメインスレッドを一時停止する効果がありますが、Sleep()を削除し、Qtイベントループは全体を通して完全に制御されたままになります。古い方法がなぜこれほど多くの問題を引き起こしたのかはまだわかりませんが、システムリソースの制限があるのではないかと思いますが、この新しいアプローチはより軽量で、確かにうまく機能しているようです。