チュートリアル
このセクションでは、複数パーツアプリケーションと複数パーツ, 複数ロボットアプリケーションの両アプリケーションをどのように実装するかを具体的に説明します。多くのケースでは、手順を簡単に説明し、実行内容の詳細については説明しません。本項は、ユーザーが新しいパーツの作成方法, パーツキャリブレーションの実行方法, ロボット1台パーツ1種類のアプリケーションのプログラム記述方法を理解していることを前提としています。
詳細は以下を参照してください。
使ってみよう
チュートリアル1: ロボット1台, フィーダー1台, パーツ2種類
このチュートリアルでは、2種類のパーツが同じフィーダー上を同時に流れます。パーツは物理的に異なります。パーツ#1とパーツ#2を使用しています。フィーダーの上には下向き固定カメラがあります。ロボットがパーツ#1を2つピック&プレースし、次にパーツ#2を1つピック&プレースします。この操作をループで継続して実行します。
各パーツは、異なるハンド (出力ビット)を使ってピックされます。この組立アプリケーションではパーツの数とピックの順序が非常に重要です。パーツ#1とパーツ#2を切り替える処理は、PF_ActivePartを使用して行います。最初に、PF_Robotコールバック関数内でロボット動作を実行するようにコードを記述します。次に、個別のマルチタスクで動作を実行し、フィーダーの振動を並行処理して、ロボットのスループットを向上します。
Epson RC+の新規プロジェクトを作成します。
下向き固定カメラをキャリブレーションします。
Vision Guideから、Part Blobシーケンスを作成します。
“Part Blobシーケンス”は、パーツの最適な投入方法を決定するため、パーツキャリブレーション中や、実行時のフィードバックに使用します。Part Blobシーケンスは、実行時にそれぞれのパーツやパーツ群を検出します。通常、Part Blobシーケンスには単一のBlobビジョンオブジェクトが含まれます。Part Blobシーケンスには、Calibrationプロパティーに割りあてられたカメラキャリブレーションが必要です。
BlobオブジェクトのNumberToFindプロパティーは“All”に設定します。BlobのThresholdAutoプロパティーは“False” (デフォルト値)に設定します。
プラットフォームにパーツを配置し、[ヒストグラム]ウィンドウを開いて、パーツが検出されるまでThresholdHighとThresholdLowを調整します。BlobのMinAreaをパーツ領域のMinAreaのおよそ0.9倍に設定します。パーツに裏表がある場合、パーツがどの向きでも検出されるようにMinAreaを設定します。(フィーダー上の)2種類のパーツそれぞれに対して個別のPart Blobシーケンスを設定できますが、通常はすべてのパーツに対して同じPart Blobシーケンスを使用できます。
Part Blobシーケンスでこのフィーダー上を流れる各パーツを検出できることを確認します。Blobオブジェクトのサーチウィンドウは、可能な限り広範なプラットフォームエリアをカバーする必要があります。ただし、Blobオブジェクトはパーツのみを検出し、フィーダートレイ自体は検出しないことが重要です。Part Blobシーケンスでトレイの一部が検出された場合、システムは正しく動作しません。Vision Guideから、このフィーダーで動作する2種類のパーツそれぞれのパーツシーケンスを作成します。
各シーケンスに対してCalibrationプロパティーが設定されていることを確認します。一般的に、Geometricオブジェクトは、表を特定するために使用します (2つ目のGeometricオブジェクトは、フリップが必要な場合にパーツの裏を特定するために使用します)。ビジョンオブジェクトのNumberToFindプロパティーは、 “All”に設定します。[ツール] - [パーツフィーディング]を表示し、“パーツウィザード”に従い新しいパーツを追加します。
パーツウィザードの詳細は、以下を参照してください。
使ってみよう新しいパーツの[キャリブレーション] - [キャリブレーション]ボタンをクリックし “キャリブレーションウィザード”を開始します。
キャリブレーションウィザードの詳しい使い方は、以下を参照してください。
キャリブレーション&テストパーツ#1の[ピック] - [ティーチ]ボタンをクリックします。
ロボットをパーツのピック高さまでジョグし、“Pick Z”をティーチングします。[パーツフィーディング] - [追加]ボタンをクリックし、パーツ#2を追加します。
“パーツウィザード”を使用してパーツを設定します。[キャリブレーション] - [キャリブレーション]ボタンをクリックし、キャリブレーションウィザードを開始します。
パーツ#2の[ピック] - [ティーチ]ボタンをクリックします。
ロボットをパーツのピック高さまでジョグし、“Pick Z”をティーチングします。[パーツフィーディング]ダイアログを閉じます。
パーツフィードのテンプレートコード (パーツフィーディングのコールバック関数)が自動的に作成されます。ロボットに停止 (park)とプレース (place)のポイントをティーチングし、それぞれ“park”と“place”と名前をつけます。
テンプレートコードを、以下のように修正します。
Main.prg
Function Main
Robot 1
Motor On
Power High
Speed 50
Accel 50, 50
Jump Park
PF_Start 1, 2
Fend
PartFeeding.prg
Global Integer numPicked ' number of parts that have been picked
Function PF_Robot(PartID As Integer) As Integer
Integer numRequired, gripperOutput
Select PartID
Case 1
numRequired = 2 ' number of parts required
gripperOutput = 1
Case 2
numRequired = 1
gripperOutput = 2
Send
Do
If PF_QueLen(PartID) > 0 Then
P0 = PF_QueGet(PartID)
PF_QueRemove (PartID)
Jump P0
On gripperOutput
Wait 0.1
Jump Place
Off gripperOutput
Wait 0.1
numPicked = numPicked + 1
Else
' Not enough parts were picked
PF_ActivePart PartID ' No change in Active Part
PF_Robot = PF_CALLBACK_SUCCESS
Exit Function
EndIf
Loop Until numPicked = numRequired
numPicked = 0
' select the next Active Part
If PartID = 1 Then
PF_ActivePart 2
Else
PF_ActivePart 1
EndIf
PF_Robot = PF_CALLBACK_SUCCESS
Fend
上記のサンプルコードでは、ロボットが“プレース”動作を完了し、PF_Robot関数が終了するとフィーダーが必要に応じて振動します。このコードは、ロボットの動作と並行してフィーダーを振動させるように再構成できます。
パーツをピックできるようになったことをモーションタスクに通知するため、PF_Robotコールバック (例: Function Main)を使用します。
パーツが使用できるようになると、メモリーIO ( “PartsToPick1”, “PartsToPick2”と名前をつける)を使用して信号を送ります。
使用可能な最後のパーツがプレースされると (この例の動作が80%完了した状態)、モーションタスクはPF_Robot関数に信号を送って終了し、値を返します。この戻り値によって、システムは新しい画像の取得, 振動, ホッパーからのパーツの供給などが可能になったことを把握します。ここでは、フィーダーの動作とロボットの動作を並行して実行できるよう、チュートリアルコードを修正します。
Main.prg
Function Main
Integer numToPick1, numToPick2, numPicked
Motor On
Power High
Speed 50
Accel 50, 50
Jump Park
MemOff PartsToPick1
MemOff PartsToPick2
numToPick1 = 2
numToPick2 = 1
PF_Start 1, 2
Do
numPicked = 0
Do
Wait MemSw(PartsToPick1) = On
pick = PF_QueGet(1)
PF_QueRemove (1)
Jump pick
On gripper1
Wait 0.1
numPicked = numPicked + 1
If numPicked < numToPick1 And PF_QueLen(1) > 0 Then
Jump Place
Else
' Last part or no more parts available to pick
If numPicked = numToPick1 Then
' Select the next part
PF_ActivePart 2
EndIf
Jump Place ! D80; MemOff PartsToPick1 !
EndIf
Off gripper1
Wait 0.1
Loop Until numPicked = numToPick1
numPicked = 0
Do
Wait MemSw(PartsToPick2) = On
pick = PF_QueGet(2)
PF_QueRemove (2)
Jump pick
On gripper2
Wait 0.1
numPicked = numPicked + 1
If numPicked < numToPick2 And PF_QueLen(2) > 0 Then
Jump Place
Else
' Last part or no more parts available to pick
If numPicked = numToPick2 Then
' Select the next part
PF_ActivePart 1
EndIf
Jump Place ! D80; MemOff PartsToPick2 !
EndIf
Off gripper2
Wait 0.1
Loop Until numPicked = numToPick2
Loop
Fend
PartFeeding.prg
Function PF_Robot(PartID As Integer) As Integer
Select PartID
Case 1
MemOn PartsToPick1
Wait MemSw(PartsToPick1) = Off
Case 2
MemOn PartsToPick2
Wait MemSw(PartsToPick2) = Off
Send
PF_Robot = PF_CALLBACK_SUCCESS
Fend
チュートリアル2: ロボット2台, フィーダー1台, パーツ2種類
このチュートリアルでは、2種類のパーツが同じフィーダー上を同時に流れます。パーツは物理的に異なります。パーツ#1とパーツ#2を使用しています。フィーダーの上には下向き固定カメラがあります。2台のロボットで同一のフィーダーを共有します。2台のロボットは、交互にフィーダーからピックを行います。各ロボットがそれぞれのパーツをピック&プレースします。ロボット#1がパーツ#1を1つピックし、次にロボット#2がパーツ#2を1つピックします。
このアプリケーションではピックの順序が重要です。ピックの順序は、 “PF_ActivePart”で入れ替えることができます。最初に、PF_Robotコールバック関数内でロボット動作を実行するようにコードを記述します。このケースでは、ロボット動作は順番に行われます。一度に動くロボットは1台のみです。
次に、個別のマルチタスクで動作を実行して、ロボットのスループットを向上します。修正したチュートリアルにもPF_AccessFeeder / PF_ReleaseFeederが含まれます。PF_AccessFeeder / PF_ReleaseFeederは、フィーダーからピックするとき、ロボットの衝突を防ぐために使用します。
- Epson RC+の新規プロジェクトを作成します。
- ロボット#1用の下向き固定カメラをキャリブレーションします。
- ロボット#2用の下向き固定カメラをキャリブレーションします。
- Vision Guideから、パーツ#1のPart Blobシーケンスを作成します。通常、Part Blobシーケンスには単一のBlobビジョンオブジェクトが含まれます。シーケンスには、Calibrationプロパティーに割りあてられたロボット#1に対して実行したカメラキャリブレーションが必要です。BlobオブジェクトのNumberToFindプロパティーは“All”に設定します。
BlobのThresholdAutoプロパティーは“False” (デフォルト値)に設定します。プラットフォームにパーツを配置し、[ヒストグラム]ウィンドウを開いて、パーツが検出されるまでThresholdHighとThresholdLowを調整します。BlobのMinAreaをパーツ領域のMinAreaのおよそ0.9倍に設定します。
パーツに裏表がある場合、パーツがどの向きでも検出されるようにMinAreaを設定します。Part Blobシーケンスがパーツ#1を検出できることを確認します。
Blobオブジェクトのサーチウィンドウは、可能な限り広範なプラットフォームエリアをカバーする必要があります。ただし、Blobオブジェクトはパーツのみを検出し、フィーダートレイ自体は検出しないことが重要です。 - Vision Guideから、パーツ#2のPart Blobシーケンスを作成します。通常、Part Blobシーケンスには単一のBlobビジョンオブジェクトが含まれます。シーケンスには、Calibrationプロパティーに割りあてられたロボット#2に対して実行したカメラキャリブレーションが必要です。BlobオブジェクトのNumberToFindプロパティーは“All”に設定します。
BlobのThresholdAutoプロパティーは“False” (デフォルト値)に設定します。
プラットフォームにパーツを配置し、[ヒストグラム]ウィンドウを開いて、パーツが検出されるまでThresholdHighとThresholdLowを調整します。
BlobのMinAreaをパーツ領域のMinAreaのおよそ0.9倍に設定します。
パーツに裏表がある場合、パーツがどの向きでも検出されるようにMinAreaを設定します。Part Blobシーケンスがパーツ#2を検出できることを確認します。Blobオブジェクトのサーチウィンドウは、可能な限り広範なプラットフォームエリアをカバーする必要があります。
ただし、Blobオブジェクトはパーツのみを検出し、フィーダートレイ自体は検出しないことが重要です。 - Vision Guideから、パーツ#1の検出に使用するパーツシーケンスを作成します。
Calibrationプロパティーがロボット#1に対して実行したキャリブレーションに設定されていることを確認してください。
一般的に、Geometricオブジェクトは表を特定するために使用します。 (2つ目のGeometricオブジェクトは、フリップが必要な場合にパーツの裏を特定するために使用します。) ビジョンオブジェクトのNumberToFindプロパティーは、“All”に設定します。 - Vision Guideから、パーツ#2の検出に使用するパーツシーケンスを作成します。
Calibrationプロパティーがロボット#2に対して実行したキャリブレーションに設定されていることを確認してください。
一般的に、Geometricオブジェクトは表を特定するために使用します。 (2つ目のGeometricオブジェクトは、フリップが必要な場合にパーツの裏を特定するために使用します。) ビジョンオブジェクトのNumberToFindプロパティーは、“All”に設定します。 - [ツール] - [パーツフィーディング]を表示し、パーツ#1の新しいパーツを追加します。“パーツウィザード”に従いパーツを追加します。パーツウィザードの最初のページでロボット#1が選択されていることを確認します。
パーツウィザードの詳細は、以下を参照してください。
使ってみよう - 新しいパーツ#1の[キャリブレーション] - [キャリブレーション]ボタンをクリックして“キャリブレーションウィザード”を開始します。
キャリブレーションウィザードの詳しい使い方は、以下を参照してください。
キャリブレーション&テスト - パーツ#1の[ピック] - [ティーチ]ボタンをクリックします。
ロボット#1をパーツのピック高さまでジョグし、“Pick Z”をティーチングします。 - [パーツフィーディング] - [追加]ボタンをクリックし、パーツ#2を追加します。“パーツウィザード”を使用してパーツを設定します。
パーツウィザードの最初のページでロボット#2が選択されていることを確認します。 - [キャリブレーション] - [キャリブレーション]ボタンをクリックし、キャリブレーションウィザードを開始します。
- パーツ#2の[ピック] - [ティーチ]ボタンをクリックします。ロボット#2をパーツのピック高さまでジョグし、“Pick Z”をティーチングします。
- [パーツフィーディング]ダイアログを閉じます。
パーツフィードのテンプレートコード (Part Feedingのコールバック関数)が自動的に作成されます。 - テンプレートコードを以下のように修正します。
Main.prg
Function Main
Robot 1
Motor On
Power High
Speed 50
Accel 50, 50
Jump Park
Robot 2
Motor On
Power High
Speed 50
Accel 50, 50
Jump Park
PF_Start 1, 2
Fend
PartFeeding.prg
Function PF_Robot(PartID As Integer) As Integer
If PF_QueLen(PartID) > 0 Then
Select PartID
Case 1
Robot 1
P0 = PF_QueGet(1)
PF_QueRemove (1)
Jump P0 /R
On rbt1Gripper
Wait 0.25
Jump Place
Off rbt1Gripper
Wait 0.25
PF_ActivePart 2
Case 2
Robot 2
P0 = PF_QueGet(2)
PF_QueRemove (2)
Jump P0 /L
On rbt2Gripper
Wait 0.25
Jump Place
Off rbt2Gripper
Wait 0.25
PF_ActivePart 1
Send
EndIf
PF_Robot = PF_CALLBACK_SUCCESS
Fend
ここで、ロボット動作が別のマルチタスクで実行されるよう、サンプルコードを修正します。1台のロボットがフィーダーを離れると、別のロボットがフィーダーに向かって移動を開始できるようになります。複数のロボットが並列動作により1台のフィーダーを共有する場合、PF_AccessFeederコマンドとPF_ReleaseFeederコマンドを使用して、ロボットの衝突を防ぐことが重要です。
さらに、修正したコードではフィーダーの振動とロボット動作を並行処理します。このチュートリアルでは、各ロボットがそれぞれのプレース位置まで80%の地点に到達した時点でロボットがカメラの視野を消去し、画像が取得できます。
また、各ロボットがそれぞれのプレース位置まで80%の地点に到達した時点で、もう一方のロボットがフィーダーに向かって移動を開始しても安全です。実際の動作のパーセンテージは、特定の状況におけるロボットの速度と相対的な位置決めによって決まります。各ロボットは、“park”ポイントと、“place”ポイントを持ちます。このチュートリアルでは、ロボット#1が右手姿勢でフィーダーからピックし、ロボット#2は左手姿勢でフィーダーからピックします。
修正したテンプレートコードは、以下のとおりです。
Main.prg
Function Main
Robot 1
Motor On
Power High
Speed 50
Accel 50, 50
Jump Park
Robot 2
Motor On
Power High
Speed 50
Accel 50, 50
Jump Park
MemOff PartsToPick1
MemOff PartsToPick2
PF_Start 1, 2
Xqt Robot1PickPlace
Xqt Robot2PickPlace
Fend
Function Robot1PickPlace
Robot 1
Do
Wait MemSw(PartsToPick1) = On
PF_AccessFeeder 1
P0 = PF_QueGet(1)
PF_QueRemove (1)
Jump P0 /R
On rbt1Gripper
Wait 0.25
Jump Place ! D80; MemOff PartsToPick1; PF_ReleaseFeeder 1 !
Off rbt1Gripper
Wait 0.25
Loop
Fend
Function Robot2PickPlace
Robot 2
Do
Wait MemSw(PartsToPick2) = On
PF_AccessFeeder 1
P0 = PF_QueGet(2)
PF_QueRemove (2)
Jump P0 /L
On rbt2Gripper
Wait 0.25
Jump Place ! D80; MemOff PartsToPick2; PF_ReleaseFeeder 1 !
Off rbt2Gripper
Wait 0.25
Loop
Fend
PartFeeding.prg
Function PF_Robot(PartID As Integer) As Integer
Select PartID
Case 1
If PF_QueLen(1) > 0 Then
MemOn PartsToPick1
Wait MemSw(PartsToPick1) = Off
PF_ActivePart 2
Else
PF_ActivePart 1
EndIf
Case 2
If PF_QueLen(2) > 0 Then
MemOn PartsToPick2
Wait MemSw(PartsToPick2) = Off
PF_ActivePart 1
Else
PF_ActivePart 2
EndIf
Send
PF_Robot = PF_CALLBACK_SUCCESS
Fend