Beckhoff#TwinCAT TF7000を使用しBarCode読み込んでみよう

みなさんこんにちは。またTc3_Visionの記事を見てくださってありがとうございます。今回はTc3_visionを使用しBarCodeを読み込んでみます。WatchdogとContoursという新しいコンセプトが出てきますが難しくないので一緒に進みましょう。


Watchdogs

まずWatchdogから説明します。Watchdogは通信のタイムアウトなどでよく出てくる言葉ですが、この機能は画像処理でも大切な役割があります。これは関数は呼び出しましたが、処理時間が長すぎて本来の制御タスクが回さなくなるというリスクがあるからです。

では、どんな理由で処理時間が長くなるのでしょうか。

  1. カメラの照明が急激に変わった
  2. 望まないものが画像内で現れてる

特殊な関数F_VN_FindContours()などが使用するとき。例えば正常の照明では10個のObjectが検知できる予定ですが、急激に変わったら本来見えなくなるものが見えてしまっ

て検知できるものが急に100に変わったになるなど。

そのような状況のせいでMain Systemに影響されたくないので、Watchdog機能を使用します。

Activate

Plc project> SYSTEM>Task>実行Task.

Watchdog stackのCheckboxをいれてください。

Contours

次はContoursについて説明します。ContoursはFrameやOutlineの意味でObjectの周囲を明確認識できるように枠です。下図のように赤枠がBarcodeを示していますね。

このContoursは以下のものを示しています;

  • Shape
  • サイズ
  • Objectの位置

Fields of contours

もちろん画像内で1つ以上のContoursが存在するのも普通です。基本的にこのように2D配列式に格納します.

Function block

今回もExample内で使用するFunction/Function Blockのみ説明します。

FB_VN_WriteImage

このFunction blockはTwinCATの画像をFile Systemに保存します。

VAR_INPUT

ipImageReference To ITcVnImageFile Systemに保存する画像
sFilePathSTRING 保存先
bWrite BOOL 立ち上げ=保存
nTimeout TIME VISION_ADS_TIME OUTTimeout

VAR_OUTPUT

bBusyBOOL 1=実行中.
bErrorBOOL 1=エラーあり.
nErrorIdUDINTエラー情報

F_VN_StartRelWatchdog

Watchdogを起動します。Monitor時間は現在時間の相対時間になります。

VAR_INPUT

tStop DINT Stop time in us
hrPrevHRESULT前回の実行結果

Return Value

F_VN_StartRelWatchdogHRESULT実行時間

F_VN_StopWatchdog

Watchdogを停止し、Runtime情報を取得します。

VAR_INPUT

hrStartWatchdogHRESULTThe execute result of start watchdog function

VAR_OUTPUT

nFunctionsMonitoredULINT 関数がMonitorされた回数
bEnFractionProcerrorssed UDINT 実数の処理時間
tRest DINT 残り時間

Return Value

F_VN_StopWatchdogHRESULT実行結果


F_VN_PutTextExp

画像にテキストを入れる。

VAR_INPUT

sText STRING 入れたいテキスト
ipDestImageITcVnImageテキストを入れたい画像
nX UDINT x coordinate (bottom left)
nYUDINT y coordinate (bottom left)
eFontType ETcVnFontType 
fFontScale LREAL Scaling factor
aColor Reference To TcVnVector4_LREALText color
nThickness DINT Line thickness
eLineType ETcVnLineType 
bBottomLeftOrigin BOOL 1=画像の原点を左下に設定する
hrPrev HRESULT 前回の処理結果

Return Value

F_VN_PutTextExpHRESULT処理結果


ETcVnFontType

Offers font types.

Further information

ETcVnLineType

Offers line types

F_VN_DrawContours

この関数で画像にContoursを書きます。

  • Contourは関数に渡すContainerにより変わります。
  • この記事では、F_VN_ReadBarcodeExp()を使用しContourを検知します。

VAR_INPUT

ipContours ITcVnContainer Single contour (ContainerType_Vector_TcVnPoint2_DINT) multiple contours (ContainerType_Vector_Vector_TcVnPoint2_DINT)
nContourIndex DINT 書きたいContourのIndexマイナス値ならすべて書くようにします。
ipDestImage ITcVnImage  書き込みたい画像
eFontType ETcVnFontType 
aColor Reference To TcVnVector4_LREALText color
nThickness DINT Line thicknessマイナスならContourはFull-fitする
hrPrev HRESULT 前回の実行結果

Return Value

F_VN_DrawContoursHRESULT実行結果

F_VN_ReadBarcodeExp

この関数はF_VN_ReadBarCodeのExpertバージョンです。この関数を使ってBarcoeを検知し、Codeの位置などを返します。 

VAR_INPUT

ipSrcImageITcVnImageソース image Type:USINT elements, 1 channel・3 channel 3 channelの場合は内部の場合でGrayに変換します。
ipDecodedDataReference ToITcVnContainerDecodeされたデータ
ipContours ITcVnContainer Code位置などの情報含むContainer返します。Type:ContainerType_Vector_Vector_TcVnPoint2_DINT
eBarcodeType UDINT検索するBarCodeの種類
nCodeNumber DINT  検知するBarCodeの数いま1つだけSupportできます。
eSearchDirectionETcVnBarcodeSearchDirection Barcodeの検索方向
hrPrev HRESULT indicating the result of previous operation

Return Value

F_VN_ReadBarcodeExpHRESULTThe execute result

ETcVnBarcodeSearchDirection

TCVN_BSD_ANY最初は水平で、そのあとすんべて垂直方向。
TCVN_BSD_HORIZONTAL水平のみ
TCVN_BSD_VERTICAL垂直のみ

ETcVnBarcodeType

F_VN_ExportSubContainer_String

この関数を使用しContainer内のElementsを文字列として出力します。

ContainerType_Vector_String_SINTのみの2D Containersだけ有効です。

VAR_INPUT

ipContours ITcVnContainer Container ソース ContainerType_Vector_String_SINTのみ
nIndex ULINTContainer内のElements Index
sText STRING  Text 出力
nMaxLength ULINT 
hrPrev HRESULT 前回実行結果

Return Value

F_VN_ExportSubContainer_StringHRESULT実行結果

Implemention

前回の記事と同じく、RoboDKに関しては詳しく説明しませんのでProjectダウンロードしてみてください。

Configuration

こちらも前回と同じく、RoboDK 2DのCamera Simulation Interfaceを使用します。

そしてやり取りはTwinCAT TF6100 OPCUAを使います。


Flow

こちらはRoboDKとTwinCATのHandshake Flowです。


Barcode Reading Flow

こちらはBarCodeを読み込むためのFlowになります。

まずImagesを読み込む>BarCodeを検知>CodeをExport>テキストなどを描く>Imageを出力の流れです。

OPCUA Connections

下記のLinkでTwinCAT3のOPCUA TF6100を参考にしてください。

Beckhoff#Using TwinCAT TF6100 to startup OPCUA Server | (soup01.com)

Script to Create BarCode

こちらはランダムのBarCode生成プログラムです。

from robolink import *  # RoboDK API
from robodk import *  # Robot toolbox
from random import choice
import barcode

defCreateRandomBarCode(i):
    sequence = [i for i in range(9)]
    BarCodeList=[]
    for _ in range(i):
        st=”
        for _ in range(13):
            sel=choice(sequence)
            st1=str(sel)
            st+=st1
#print(st)
#print(type(st))
        BarCodeList.append(st)
    return BarCodeList


BarCodeList=CreateRandomBarCode(5)
print(BarCodeList)

BASE_PATH=r’C:\images\barcode_’
for i in range(1,5):
    print(BASE_PATH+str(i)+’.png’)

data = mbox(“Enter your bar code (EAN 13 digits)”, entry=’5701234567899′)
if data is None or data is False or type(data) is not str:
    # User cancelled
    quit()
if not data.isdecimal() or len(data) != 13:
    # Invalid input
    quit()


#img = barcode.EAN13(data, writer=barcode.writer.ImageWriter())

name = “EAN13_” + data.replace(‘.’, ”).replace(‘:’, ”).replace(‘/’, ”)

filename = None
if filename is None or filename == ”:
    import_install(“tempdir”)
    import tempfile
    tempdir = tempfile.gettempdir()
    filename = r’C:\images\barcode1.png’

for i in range(len(BarCodeList)):
    img = barcode.EAN13(BarCodeList[i], writer=barcode.writer.ImageWriter())
    filename=BASE_PATH+str(i)+’.png’
    img.save(filename)


#img.save(filename)

filename += ‘.png’  # barcode .save adds the .png
import os.path
if not os.path.exists(filename):
    quit(-1)

Program

こちらのプログラムを写真読み込み>BarCode検知とTE1800使って表示します。

VAR

VAR
//FB
FB_Images:FB_VN_ReadImage;
WriteImages:FB_VN_WriteImage;
R_TRIG1,R_TRIG2,R_TRIG5 :R_TRIG;
TON:TON;
hr,hr2:HRESULT:=S_OK;
index:ULINT;
//Pointers
ipImage:ITcVnImage;
ipDecodedData:ITcVnContainer;
stImageInfo_1:TcVnImageInfo;
ImageInfo:TcVnImageInfo;
//System Devices
read:BOOL;
readQR:BOOL;
binit:BOOL;
safetyInit:BOOL;
bwrite:BOOL;
b3,b4:BOOL;
i:INT;
//Image Information
width:UDINT;
height:UDINT;
sText:STRING;
// Watchdog
hrWD :   HRESULT;
tStop:   DINT := 50000;
tRest:   DINT;
sWatchDogTime:STRING;
// BarCode
readBarCode:BOOL;
ipCodeContourList:ITcVnContainer;
eBarcodeType              :   ETcVnBarcodeType := TCVN_BT_EAN13;
eBarcodeSearchDirection   :   ETcVnBarcodeSearchDirection := TCVN_BSD_ANY;
imagePath:STRING:=’C:\images\Images_read’;
imageMarkedPath:STRING:=’C:\images\Images_read_barcode’;
pathOrg,pathMarked:STRING;
// Color
aColorRed                 :   TcVnVector4_LREAL := [255, 0, 0];
//HMI
hmiIndex:INT;
hmis:ARRAY[1..4]OF DUT_VisionDisplay;
EmptyImageInfo:TcVnImageInfo;
END_VAR

Code

//init
IF binit THEN
IF ipImage <> 0 THEN
ipImage.TcRelease();
ipImage:=0;
END_IF
binit:=FALSE;

END_IF
//Safety Init
IF safetyInit THEN

FW_SafeRelease(ADR(ipImage));
FW_SafeRelease(ADR(ipDecodedData));
FW_SafeRelease(ADR(ipCodeContourList));
safetyInit:=FALSE;
read:=FALSE;
readQR:=FALSE;
hr:=0;
hr2:=0;
FOR i :=1 TO 4 DO
hmis[i].Code:=”;
hmis[i].Info:=EmptyImageInfo;
hmis[i].watchDog:=”;
hmis[i].urlMarked:=”;
hmis[i].urlOrg:=”;

END_FOR
i:=0;
END_IF

//HandShake with RoboDK
R_TRIG1
(CLK:=GVL_OPCUAServer.Node.Command2=1);

R_TRIG5(
CLK:=b4
OR GVL_OPCUAServer.Node.Command2 =41
);
IF R_TRIG5.Q THEN
i:=1;
b4:=TRUE;
END_IF
IF R_TRIG1.Q THEN
GVL_OPCUAServer.Node.Command1:=0;
END_IF

//BarCode Reading Program
IF b4 THEN
CASE i OF
//init the path,Release the pointer
//Trigger the Read Command
1..4:
pathOrg:=”;
pathMarked:=”;
pathOrg:=CONCAT(STR1:=imagePath,INT_TO_STRING(i));
pathOrg:=CONCAT(pathOrg,’.png’);
hmis[i].urlOrg:=pathOrg;
pathMarked:=CONCAT(STR1:=imageMarkedPath,INT_TO_STRING(i));
pathMarked:=CONCAT(pathMarked,’.png’);
hmis[i].urlMarked:=pathMarked;
i:=1+i*10;
FB_Images.bRead:=TRUE;
//Read the Image
11,21,31,41:
FB_Images(
sFilePath:=pathOrg
,ipDestImage:=ipImage
);
IF ipImage <> 0 THEN
i:=i+1;
FB_Images.bRead:=FALSE;
FB_Images(
sFilePath:=pathOrg
,ipDestImage:=ipImage
);
END_IF
//Take a 0.1s Delay
12,22,32,42:
TON(
IN:=TRUE
,PT:=T#0.1S
);
IF TON.Q THEN
TON(
IN:=FALSE
);
i:=i+1;
END_IF
//Get the Image Info Data and Transfer to HMI
13,23,33,43:
hmiIndex:=i/10;
IF hmiIndex >0 AND hmiIndex <=4 THEN
F_VN_GetImageInfo(
ipImage
,stImageInfo:=hmis[hmiIndex].Info
,hrPrev:=hr
);
i:=i+1;
END_IF
//Search the BarCode
14,24,34,44:
hrWD:=F_VN_StartRelWatchdog(tStop:=tStop,hrPrev:=hrWD);
hr:=F_VN_ReadBarcodeExp(
ipSrcImage:=ipImage
,ipDecodedData:=ipDecodedData
,ipContours:=ipCodeContourList
,eBarcodeType:=eBarcodeType
,nCodeNumber:=1
,eSearchDirection:=eBarcodeSearchDirection
,hrPrev:=hr2
);
hrWD := F_VN_StopWatchdog(hrWD, tRest => tRest);
IF SUCCEEDED(hr)  THEN
i:=i+1;
END_IF
//Image Drawing Operation
15,25,35,45:
//Export the String that Read from Image
hr := F_VN_ExportSubContainer_String(
ipContainer:=ipDecodedData
,nIndex:=0
,sText:=sText
,nMaxLength:=255
,hrPrev:=hr2
);
//Write the Code that you read to HMi
hmis[hmiIndex].Code:=sText;
//Put BarCode Values into Image
hr:=F_VN_PutTextExp(
sText:=sText
,ipDestImage:=ipImage
,nX:=20
,nY:=20
,eFontType:=ETcVnFontType.TCVN_FT_HERSHEY_PLAIN
,fFontScale:=1
,aColor:=aColorRed
,nThickness:=2
,eLineType:=TCVN_LT_4_CONNECTED
,bBottomLeftOrigin:=FALSE
,hrPrev:=hr2
);
//Draw Contours to mark out the barcode in the Image
hr:=F_VN_DrawContours(
ipContours:=ipCodeContourList
,nContourIndex:=0
,ipDestImage:=ipImage
,aColor:=aColorRed
,nThickness:=1
,hrPrev:=hr2

);
//Draw the WatchDog Time into Images
sWatchDogTime := CONCAT(CONCAT(‘Time: ‘, DINT_TO_STRING(tStop – tRest)), ‘us’);
//Put the Text
hr:=F_VN_PutTextExp(
sText:=sWatchDogTime
,ipDestImage:=ipImage
,nX:=20
,nY:=50
,eFontType:=ETcVnFontType.TCVN_FT_HERSHEY_SIMPLEX
,fFontScale:=0.5
,aColor:=aColorRed
,nThickness:=1
,eLineType:=TCVN_LT_4_CONNECTED
,bBottomLeftOrigin:=FALSE
,hrPrev:=hr2
);
//Write the Watchdog time value that you read to HMi
hmis[hmiIndex].watchDog:=sWatchDogTime;
//IF all process is OK, jumpt to next Step by +1
IF SUCCEEDED(hr) THEN
i:=i+1;
END_IF
//Write to image to file system
16,26,36,46:
IF ipImage <> 0 THEN
WriteImages(
ipImage:=ipImage
,sFilePath:=pathMarked
,bWrite:=TRUE
);

END_IF
//Release the pointer
IF (NOT WriteImages.bBusy AND NOT WriteImages.bError)
OR WriteImages.bError
THEN
bWrite:=FALSE;
WriteImages(
bWrite:=FALSE
,sFilePath:=pathMarked
);
FW_SafeRelease(ADR(ipImage));
FW_SafeRelease(ADR(ipDecodedData));
FW_SafeRelease(ADR(ipCodeContourList));
//Check the step again
//To Do list:any Clever way?
//if Step=46, all image are read and back to 0.
CASE i OF
16:
i:=2;
26:
i:=3;
36:
i:=4;
46:
i:=0;
b4:=FALSE;
//A ungly step, finding way to get the status from RoboDK that the Program is finished
GVL_OPCUAServer.Node.Command2:=0;
END_CASE

END_IF;
END_CASE
END_IF

Visualization

こちらのScreenで4枚の画像情報を表示させます。


Sample Code

TwinCAT3/TwinCAT Project_Vision_Part2_ReadBarCode.zip at main · soup01Threes/TwinCAT3 (github.com)

Result

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

シェアする

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

フォローする