Beckhoff#TF7000 Tc3_Vision Containerを詳しく見よう

みなさんこんにちは。Beckhoff TwinCAT3 TF7xxxの第2話です。今回はContainerのコンセプトについてもう少し深く説明します。ContainerはTc3_Visionの中の大事な部品なのでコンセプトをしっかり理解する必要があり、QRCodeやBarCode読み取るからObject Detectなどのアプリケーションまでも、絶対Containerを使いますので。

みなさんが最後までお付きいただけると嬉しいです。

前回の記事:

Beckhoff#TwinCAT3 TF7000 VisionでQRCode読み込んでみよう | (soup01.com)

Functions

Containerを説明する前に、まずVisionのFunctionsについてもう少し説明しますね。前回もある程度書いてますが、今回は復習しますね。関数は以下のFormatになります:

hr

Functionの実行結果が格納されます。

F_VN_

Visionの関数はF_VN_から始まります。

Parameter<..>

FunctionのParameterは必ずすべて入れてください。Parameterは以下の種類あります:

  • Input Parameter:ImagesやContainer
  • アルゴリズムの設定パラメタ
  • 戻り値


Expert Functions

Tc3_VisionにF_VN_xxx_Expのような名前の関数で(例えばF_VN_MaxImageとF_VN_MaxImageExp)、Expがついてる関数は必要のパラメタも多くなり、できることも多くなります。

Define the Container

まずcontainerを定義します。そのcontainerは増設できる、形はいつでも壊して作り直せるとの箱だと思ってください。が、増設するときの素材(いわゆる変数のタイプ)は同じにする必要があります。

LoginしMonitorしたら2つのContainerも16#0格納されていますね。

F_VN_CreateContainer

次は関数を使用しContainerを作ります。ここをみるとちょっと混乱する読者もいると思いますが、先のStepではあくまでもこのようContainerがありますよと定義するだけで中は空っぽです。このF_VN_CreateContainer関数を使用することで、Containerをどういう形になるかを作ります。

関数に渡してたパラメータ(nTypeGuidなど)はこのContainerを作るときの仕様だと思ってください。

LoginしMonitorしたらipContainerは16#0ではなく、16#xxxxxxxの値が格納されています。

その関数はどんなContainerで作られたのでしょうか。ContainerType_Vector_REALは実数タイプの変数ですね。そしてnElementNum=10なので、10個の実数だと。

なので、下図のようになります。

Function Block

VAR_INPUT

ipContainerITcVnContainer実数 Elementsが含まれてるContainer
nTypeGidGUIDContainerのElement Data Type
nElementNumULINTいくつElementsを設定する
hrPrevHRESULT前回実行結果

Return Value

F_VN_CreateContainerHRESULT実行結果

Code

//Create a Container
IF bcreateContiner THEN
hr:=F_VN_CreateContainer(
ipContainer:=ipContainer
,nTypeGuid:=ContainerType_Vector_REAL
,nElementNum:=10
,hrPrev:=hr
);
IF SUCCEEDED(hr) THEN
bcreateContiner:=FALSE;
END_IF
END_IF

Adding Element

この部分はContainer内のElement操作です。

F_VN_AppendToContainer_REAL

次は生成されたContainerに新しいElementを追加します。Containerの操作は配列と似てると思ってください。このF_VN_AppeendToContainer_REAL関数は新しいElementを1番最後に追加します。

Function Block

VAR_INPUT

fElementReference To REAL該当するElement現在値
ipContainerITcVnContainer実数 Elementsが含まれてるContainer
hrPrevHRESULT前回実行結果

Return Value

F_VN_AppendToContainer_REALHRESULT実行結果

F_VN_InsertIntoContainer_REAL

今度は同じくElementを追加するのですが、Indexを指定し特定の場所に插入します。F_VN_InsertIntoContainer_REAL関数を使用します。下記のようにIndex=0なら1番先頭に新しいElementを追加することになります。前も書いていますが、操作は配列とすごく似ています。

Function Block

VAR_INPUT

fElementReference To REALInsertするElement値
ipContainerITcVnContainer実数 Elementsが含まれてるContainer
nIndexULINT插入したいElementのIndex
hrPrevHRESULT前回実行結果

Return Value

F_VN_InsertIntoContainer_REALHRESULT実行結果

Code

IF bAddElement AND ipContainer <>0 THEN
hr := F_VN_AppendToContainer_REAL(1.23, ipContainer, hr);
hr := F_VN_AppendToContainer_REAL(2.23, ipContainer, hr);
hr := F_VN_InsertIntoContainer_REAL(FrealTest, ipContainer, 0, hr);
IF SUCCEEDED(hr) THEN
ii:=ii+1;
END_IF
bAddElement:=FALSE;
END_IF

Accessing Element

F_VN_GetAT_XXとF_VN_SetAt_XXという関数を使ってContainer内のElementを操作することができます。注意するのはContainerのIndexは0からStartで、XXはあなたのContainer含まれているData Tyoeにより変わりまので、このあたりはManualに参照してください。


F_VN_GetAt_REAL

Container内に指定するElementの現在値を取得したい場所はF_VN_GetAt_REAL関数を追加します。下図の例ではnIndex=5なら5番目のElementの現在値を取得できます。

Function Block

VAR_INPUT

ipContainerITcVnContainer実数 Elementsが含まれてるContainer
fElementReference To REAL該当するElement現在値
nIndexULINT取得したいElementのIndex
hrPrevHRESULT前回実行結果

Return Value

F_VN_GetAt_REALHRESULT実行結果

F_VN_SetAt_REAL

同じ考え方で指定のElementの値をセットすることもできます。下記の例だと3番目のElement現在値をfVarablesに変更します。

Function Block

VAR_INPUT

fElementReference To REAL該当するElementの与え値
ipContainerITcVnContainer実数 Elementsが含まれてるContainer
nIndexULINT書き込みしたいElementのIndex
hrPrevHRESULT前回実行結果

Return Value

F_VN_SetAt_REALHRESULT実行結果

Code

IF ipContainer <> 0 THEN
hr:=F_VN_GetAt_REAL(
ipContainer:=ipContainer
,fElement:=fElement
,nIndex:=myIndex
,hrPrev:=hr
);
END_IF

IF ipContainer <>0  AND bset3 THEN
hr:=F_VN_SetAt_REAL(
fElement:=fVarables
,ipContainer:=ipContainer
,nIndex:=3
,hrPrev:=hr
);
bSet3:=FALSE;
END_IF

Looping

先の説明では1LineのプログラムだけでContainerの指定Elementにアクセスすることができます(もちろんContainer Typeは一致とIndexは範囲内)。もしContainerのElementをすべてアクセスしたい場合、iteratorsを使ったほうがパフォーマンスがよいので。

今回はExample内で使われてる関数やInterfaceを説明します。

ITcVnForwardIterator

Offers an interface for a forward iterator.

Methods – TcQueryInterface

このMethodからIntefaceのQuery を取得することができます。このQueryを使用すればLoopingなどの機能も実装できるようになります。

HRESULT TcQueryInterface(RITCID iid, PPVOID pipItf )

VAR_INPUT

iidRITCIDInterface IID
pipItfPPVOIDinterface pointer

Return Value

実行に成功したらS_OK(0)や他の正の整数が戻ります。

HRESULT実行結果

Methods – CheckIfEnd

いまのiteratorが最後かどうかをCheckします。

F_VN_CheckIfIteratorIsAtEnd()に代用できます。

Methods – Increment

iteratorを足します。(つまり次の部品に回します)

F_VN_IncrementIterator()に代用できます。

ITcVnAccess_REAL

実数の変数にアクセスできるInterfaceです。

Methods – Get

現在値を取得します。

Methods – Set

新しい値を格納します。

Flow

こちらはLoopingのSample Flowです。

Program

//Get From Loop
IF bGet THEN
hr := F_VN_GetForwardIterator(ipContainer, ipIterator, hr);
index:=0;
IF SUCCEEDED(hr) AND ipIterator <> 0 THEN
hr := ipIterator.TcQueryInterface(IID_ITcVnAccess_REAL, ADR(ipAccess));
IF SUCCEEDED(hr) AND ipAccess<>0 THEN
WHILE  SUCCEEDED(hr) AND ipIterator.CheckIfEnd() <>S_OK  DO
hr:=ipAccess.Get(fValue:=fElement);
IF SUCCEEDED(hr) THEN
fElement:=fElement+1;
hr:=ipAccess.Set(fValue:=fElement);
END_IF
IF SUCCEEDED(hr) THEN
arrReal[index]:=fElement;
hr:=ipIterator.Increment();
index:=index+1;
END_IF
END_WHILE

END_IF
hr:=FW_SafeRelease(ADR(ipAccess));
END_IF
bGet:=FALSE;
hr:=FW_SafeRelease(adr(ipIterator));
bGet:=FALSE;
END_IF


+in Python

ここまで説明すると、かなり複雑に見えますが、Pythonで書くと単なる以下の3Linesですねー

elements=[4,1,2,4,5,7,8,1,2,66,224,4]
for element in elements:
#Do you stuff

Export Container as Array

次はContainerから配列を出力するときに使える関数です。

F_VN_ExportContainerSize

Containerの部品が占有しているメモリサイズを取得できます。

VAR_INPUT

ipContainerITcVnContainerBasic Elementが含まれているContainer
nBufferSizeULINTContainerからの出力先メモリサイズ
hrPrevHRESULT前回実行結果

Return Value

F_VN_SetAt_REALHRESULT実行結果

F_VN_ExportContainer

この関数はContainerをData bufferにExportすることができます。必ずBufferSizeの容量を確認してください。F_VN_ExportContainerSize()関数で必要なMemoryが取得できます。

VAR_INPUT

ipContainerITcVnContainerBasic Elementが含まれているContainer
pBufferPVOIDContainerからの出力先変数メモリアドレス
nBufferSizeULINTContainerからの出力先メモリサイズ
hrPrevHRESULT前回実行結果

Return Value

F_VN_SetAt_REALHRESULT実行結果

Code

//Export it
IF bExport THEN
nBufferSize:=0;
FOR i:=0 TO 99 DO
arrReal[i]:=0.0;
END_FOR
hr:=F_VN_ExportContainerSize(
ipContainer:=ipContainer
,nBufferSize:=nBufferSize
,hrPrev:=hr
);
hr:=F_VN_ExportContainer(
ipContainer:=ipContainer
,pBuffer:=ADR(arrReal)
,nBufferSize:=nBufferSize
,hrPrev:=hr
);

bExport:=FALSE;

END_IF

Container In Container

最後はContainerの中にさらにContainerを格納するプログラムです。ではいままで説明したContainerのコンセプトを見てみましょう。

一つのCotainerが配列のように、データ・タイプが固定で中に自由自在に部品を数を設定できます。

もしContainerの中にさらにContainerがあると、どうなるでしょうか。

下図のようなイメージです。

ContainerがContainerのままで中に配列が格納され、Data Typeは一致します。そしてContainerの中に5つのSub-Containerが入っています。

面白いのはここです。各SubContainerには更に配列が格納されてます。その配列には実数の部品が入っています。その下図は固定ではなく、Container0は6個あり、Container1は4個あるようなFlexibilityの構成ができます。

このような構造はどこで使えるの?と疑問を持ってる人がいるかもしれません。例えば画像内で複数のObjectを検出するとき、当然1つの画像に複数のObjectを検出するのは普通のことです。そのとき1つめのObject情報はContainer0番、2つめのObject情報はContainer1番、そしてObjectの種類によって格納する情報数も違いますよね。

そのために、Container In Containerはよく使われてると思います。

以下は今回Example CodeからContainer In ContainerのFlowになります。他の作り方もたくさんありますので、これはあくまで参考になります。

F_VN_AppendToContainer_ITcVnContainer

シングルのContainerを一番最後に插入します。ipElement とipContainerはSame TypeID必要です。

Function block

VAR_INPUT

ipElementITcVnContainer插入したいSignle Container
ipContainerITcVnContainer插入されたいContainer
hrPrevHRESULT前回実行結果

Return Value

F_VN_AppendToContainer_ITcVnContainerHRESULT実行結果

F_VN_ReserveContainerMemory

Containerのメモリを先に確保する関数です。

VAR_INPUT

ipContainerITcVnContainerメモリ予約するContainer
nElementULINTそのContainerにあるElementの数予定
hrPrevHRESULT前回実行結果

Return Value

F_VN_AppendToContainer_ITcVnContainerHRESULT実行結果


Code

IF bSubContainerExample THEN
hr := F_VN_CreateContainer(ipContainerBase, ContainerType_Vector_Vector_REAL, 0, hr);
hr := F_VN_ReserveContainerMemory(ipContainerBase, TO_ULINT(cNumberOfSubContainers), hr);
FOR i:=0 TO (cNumberOfSubContainers-1) DO
hr := F_VN_CreateContainer(ipHelper, ContainerType_Vector_REAL, TO_ULINT(aContainerStructure[i]), hr);
hr := F_VN_AppendToContainer_ITcVnContainer(ipHelper, ipContainerBase, hr);
END_FOR


bSubContainerExample:=FALSE;
END_IF


IF ipContainerBase <> 0 THEN
F_VN_GetNumberOfElements(
ipContainer:=ipContainerBase
,nNumberOfElements:=nNumberOfElementsInSubContainter
,hrPrev:=hr
);
hr := F_VN_GetForwardIterator(ipContainerBase,ipIterator,hr);
hr := ipIterator.GetContainer(ADR(ipSubContainer));
IF ipSubContainer <> 0 AND SUCCEEDED(hr) THEN
iOpeartionCounter[9]:=iOpeartionCounter[9]+1;

hr:=F_VN_GetForwardIterator(ipSubContainer,ipIteratorInSubContainer,hr);
IF SUCCEEDED(hr) AND ipIteratorInSubContainer <> 0 THEN
iOpeartionCounter[10]:=iOpeartionCounter[10]+1;
ipIteratorInSubContainer.GetValueSize((nBufferSize));
ipIteratorInSubContainer.TcQueryInterface(
iid:=IID_ITcVnAccess_REAL
,ADR(ipAccessSubContainer)
);
IF SUCCEEDED(hr) AND ipAccessSubContainer<>0 THEN
iOpeartionCounter[11]:=iOpeartionCounter[11]+1;
ipAccessSubContainer.Get(fValue:=fElement);
ipAccessSubContainer.Set(fValue:=2);
ipAccessSubContainer.Get(fValue:=fElement);
END_IF
END_IF
END_IF
END_IF


Sample Code Download

TwinCAT3/TwinCAT Project_Vision_Container.tnzip at main · soup01Threes/TwinCAT3 (github.com)


Summary

今回はF_VN_AppendToContainer_REAL()、F_VN_InsertIntoContainer_REAL()、F_VN_GetAt_REAL()、F_VN_StAt_REAL()でContainerに操作しましたが、もしContainerの部品はINTならF_VN_AppendToContainer_INT()がありますし、DINTならF_VN_AppendToContainer_DINT()の関数があります。

それは最初にいってた自由自在で、箱の形を自由に設定できるのと同じです。F_VN_AppendToContainer_REAL()を使用することで箱の入れ物も自由に組み立てることができます。そのあたりはManual調べてください。(使い終わったPointerを必ずリリースしてください。)

今回の例では実数のContainerベースで説明しましたが、F_VN_CreateContainer()関数でGuidを設定することにより違うData TypeのContainerを作成することができます。それはContainerの強みで、事前に”実数 Type”のContainer、”整数 Type”のContainerなどを定義しなくてもよく、一つのContainerを使い回すことができます。下図は設定できるGUIDです。

Footer_Basic

Please Support some devices for my blog

Amazon Gift List

Find ME

Twitter:@3threes2
Email:soup01threes*gmail.com (* to @)
YoutubeChannel:https://www.youtube.com/channel/UCQ3CHGAIXZAbeOC_9mjQiWQ

シェアする

  • このエントリーをはてなブックマークに追加

フォローする