チュートリアル

このセクションでは、複数パーツアプリケーションと複数パーツ, 複数ロボットアプリケーションの両アプリケーションをどのように実装するかを具体的に説明します。多くのケースでは、手順を簡単に説明し、実行内容の詳細については説明しません。本項は、ユーザーが新しいパーツの作成方法, パーツキャリブレーションの実行方法, ロボット1台パーツ1種類のアプリケーションのプログラム記述方法を理解していることを前提としています。
詳細は以下を参照してください。
使ってみよう

チュートリアル1: ロボット1台, フィーダー1台, パーツ2種類

このチュートリアルでは、2種類のパーツが同じフィーダー上を同時に流れます。パーツは物理的に異なります。パーツ#1とパーツ#2を使用しています。フィーダーの上には下向き固定カメラがあります。ロボットがパーツ#1を2つピック&プレースし、次にパーツ#2を1つピック&プレースします。この操作をループで継続して実行します。

各パーツは、異なるハンド (出力ビット)を使ってピックされます。この組立アプリケーションではパーツの数とピックの順序が非常に重要です。パーツ#1とパーツ#2を切り替える処理は、PF_ActivePartを使用して行います。最初に、PF_Robotコールバック関数内でロボット動作を実行するようにコードを記述します。次に、個別のマルチタスクで動作を実行し、フィーダーの振動を並行処理して、ロボットのスループットを向上します。

  1. Epson RC+の新規プロジェクトを作成します。

  2. 下向き固定カメラをキャリブレーションします。

  3. 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シーケンスでトレイの一部が検出された場合、システムは正しく動作しません。

  4. Vision Guideから、このフィーダーで動作する2種類のパーツそれぞれのパーツシーケンスを作成します。
    各シーケンスに対してCalibrationプロパティーが設定されていることを確認します。一般的に、Geometricオブジェクトは、表を特定するために使用します (2つ目のGeometricオブジェクトは、フリップが必要な場合にパーツの裏を特定するために使用します)。ビジョンオブジェクトのNumberToFindプロパティーは、 “All”に設定します。

  5. [ツール] - [パーツフィーディング]を表示し、“パーツウィザード”に従い新しいパーツを追加します。
    パーツウィザードの詳細は、以下を参照してください。
    使ってみよう

  6. 新しいパーツの[キャリブレーション] - [キャリブレーション]ボタンをクリックし “キャリブレーションウィザード”を開始します。
    キャリブレーションウィザードの詳しい使い方は、以下を参照してください。
    キャリブレーション&テスト

  7. パーツ#1の[ピック] - [ティーチ]ボタンをクリックします。
    ロボットをパーツのピック高さまでジョグし、“Pick Z”をティーチングします。

  8. [パーツフィーディング] - [追加]ボタンをクリックし、パーツ#2を追加します。
    “パーツウィザード”を使用してパーツを設定します。

  9. [キャリブレーション] - [キャリブレーション]ボタンをクリックし、キャリブレーションウィザードを開始します。

  10. パーツ#2の[ピック] - [ティーチ]ボタンをクリックします。
    ロボットをパーツのピック高さまでジョグし、“Pick Z”をティーチングします。

  11. [パーツフィーディング]ダイアログを閉じます。
    パーツフィードのテンプレートコード (パーツフィーディングのコールバック関数)が自動的に作成されます。

  12. ロボットに停止 (park)とプレース (place)のポイントをティーチングし、それぞれ“park”と“place”と名前をつけます。

  13. テンプレートコードを、以下のように修正します。

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は、フィーダーからピックするとき、ロボットの衝突を防ぐために使用します。

  1. Epson RC+の新規プロジェクトを作成します。
  2. ロボット#1用の下向き固定カメラをキャリブレーションします。
  3. ロボット#2用の下向き固定カメラをキャリブレーションします。
  4. 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オブジェクトはパーツのみを検出し、フィーダートレイ自体は検出しないことが重要です。
  5. 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オブジェクトはパーツのみを検出し、フィーダートレイ自体は検出しないことが重要です。
  6. Vision Guideから、パーツ#1の検出に使用するパーツシーケンスを作成します。
    Calibrationプロパティーがロボット#1に対して実行したキャリブレーションに設定されていることを確認してください。
    一般的に、Geometricオブジェクトは表を特定するために使用します。 (2つ目のGeometricオブジェクトは、フリップが必要な場合にパーツの裏を特定するために使用します。) ビジョンオブジェクトのNumberToFindプロパティーは、“All”に設定します。
  7. Vision Guideから、パーツ#2の検出に使用するパーツシーケンスを作成します。
    Calibrationプロパティーがロボット#2に対して実行したキャリブレーションに設定されていることを確認してください。
    一般的に、Geometricオブジェクトは表を特定するために使用します。 (2つ目のGeometricオブジェクトは、フリップが必要な場合にパーツの裏を特定するために使用します。) ビジョンオブジェクトのNumberToFindプロパティーは、“All”に設定します。
  8. [ツール] - [パーツフィーディング]を表示し、パーツ#1の新しいパーツを追加します。“パーツウィザード”に従いパーツを追加します。パーツウィザードの最初のページでロボット#1が選択されていることを確認します。
    パーツウィザードの詳細は、以下を参照してください。
    使ってみよう
  9. 新しいパーツ#1の[キャリブレーション] - [キャリブレーション]ボタンをクリックして“キャリブレーションウィザード”を開始します。
    キャリブレーションウィザードの詳しい使い方は、以下を参照してください。
    キャリブレーション&テスト
  10. パーツ#1の[ピック] - [ティーチ]ボタンをクリックします。
    ロボット#1をパーツのピック高さまでジョグし、“Pick Z”をティーチングします。
  11. [パーツフィーディング] - [追加]ボタンをクリックし、パーツ#2を追加します。“パーツウィザード”を使用してパーツを設定します。
    パーツウィザードの最初のページでロボット#2が選択されていることを確認します。
  12. [キャリブレーション] - [キャリブレーション]ボタンをクリックし、キャリブレーションウィザードを開始します。
  13. パーツ#2の[ピック] - [ティーチ]ボタンをクリックします。ロボット#2をパーツのピック高さまでジョグし、“Pick Z”をティーチングします。
  14. [パーツフィーディング]ダイアログを閉じます。
    パーツフィードのテンプレートコード (Part Feedingのコールバック関数)が自動的に作成されます。
  15. テンプレートコードを以下のように修正します。

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