Tutorials

The purpose of this section is to demonstrate how to implement both a multi-part application as well as a multi-part / multi-robot application. In many cases we will simply explain the steps to follow but will not explain the details behind what was done. It is assumed that you understand how to create a new part, perform a part calibration and write a program for a one robot / one-part application.
Refer to the following section for further details.
Let’s Use the Part Feeding Option

Tutorial 1: 1 Robot, 1 Feeder, 2 Part Types

For this tutorial, there are two parts running on the same feeder at the same time. The parts are physically different. Part#1 and Part#2 are being used. There is a Fixed Downward camera over the feeder. The robot will pick and place two of Part#1 and then pick and place one of Part#2. This operation will be performed continuously in a loop.

Each part will be picked up with a different gripper (i.e., output bit). The quantity of parts and the pick order are important for this assembly application. The process of alternating between Part#1 and Part#2 will be accomplished using "PF_ActivePart". At first, we will write the code so that the robot motion is performed inside of the PF_Robot callback function. Then we will improve the robot throughput by performing the motion in a separate multitask and by parallel processing the feeder vibration.

  1. Create a new Epson RC+ project.

  2. Calibrate the Fixed Downward camera.

  3. From Vision Guide, create the Part Blob Sequence.
    The "Part Blob Sequence" is used for feedback during the Part Calibration and at runtime to make judgements about how to best feed the parts. The Part Blob Sequence detects individual parts or clumps of parts at runtime. The Part Blob Sequence generally contains a single Blob vision object. The Part Blob Sequence will need to have the camera calibration assigned to the Calibration property.
    The Blob object’s NumberToFind property should be set to "All". The ThresholdAuto property of the Blob should be set to False (default value).
    Place parts on the platform, open the Histogram window and adjust the Threshold High and Low until only the parts are detected. Set the Blob’s MinArea to roughly 0.9 times that of the part’s area. If the part has multiple sides, then set the MinArea so that the part can be found in any orientation. You can have separate Part Blob Sequences for each of the two parts (running on the feeder) but in general you can use the same Part Blob Sequence for all the parts.
    Make sure that the Part Blob Sequence can detect each Part that will be running on the feeder. The Blob object’s Search Window should fill as much of the platform area as possible. That said, it is critical that the Blob object only finds the Parts and not the feeder tray itself. If the Part Blob sequence finds any portion of the tray then the system will not function properly.

  4. From Vision Guide, create the Part Sequence for each of the two Parts that will be running on the feeder.
    Make sure that the Calibration property for each sequence is set. Typically, a Geometric object is used to locate the Front (and a second Geometric object is typically used to find the Back of the part if Flip is required). The vision object’s NumberToFind property is normally set to "All".

  5. Go to the [Tools] - [Part Feeding] dialog and add a new part. The "Part Wizard" will walk you through the process of adding a part.
    For more details about the Part Wizard, please refer to the following chapter.
    Let’s Use the Part Feeding Option

  6. Go to the [Calibration] page for the new Part and click on the [Calibrate] button to start the Calibration Wizard.
    Please refer to the following section for details on how to use the Calibration Wizard.
    Calibration & Test

  7. Go to the [Pick] page for Part#1 and click the [Teach] button.
    Jog the robot to the part pick height and teach the "Pick Z".

  8. Click the [Add] button in the [Part Feeding] dialog to add Part#2.
    Configure the part using the "Part Wizard".

  9. Go to the [Calibration] page and click the [Calibrate] button to start the Calibration Wizard.

  10. Go to the [Pick] page for Part#1 and click the [Teach] button.
    Jog the robot to the part pick height and teach the "Pick Z".

  11. Close the Part Feeding dialog.
    The Part Feeding template code (i.e., the Part Feeding callback functions) is automatically created.

  12. Teach robot points for "park" and "place" and label them respectively.

  13. Modify the template code as follows.

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

For the sample code shown above, the feeder will vibrate (if necessary) only after the robot has completed its motion to "place" and the PF_Robot function has finished. The code can be restructured such that the feeder vibration will occur in parallel with the robot motion.
The PF_Robot callback will be used to notify a motion task (function Main in this example) that parts are available to be picked up.
Memory IO (labeled "PartsToPick1" and "PartsToPick2") are used to signal when parts are available.
When the last available part is being placed (80% of the way through the motion for this example), the motion task signals the PF_Robot function to finish and return a value. The return values lets the system know that it is ok to acquire new images, vibrate, supply parts from a hopper etc… We will now modify our tutorial code so that the feeder action can occur in parallel with the robot motion.

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

Tutorial 2: 2 Robot, 1 Feeder, 2 Part Types

For this tutorial, there are two parts running on the same feeder at the same time. The parts are physically different. Part#1 and Part#2 are being used. There is a Fixed Downward camera over the feeder. Two robots will be sharing the same feeder. The robots will take turns picking from the feeder. Each robot will pick and place its own part. Robot#1 will pick up one of Part#1 and then Robot#2 will pick up one of Part#2.
The pick order matters for this application. The alternating pick order is accomplished with "PF_ActivePart". At first, we will write the code so that the robot motion is performed inside of the PF_Robot callback function. In this case, the robot motion will be sequential. In other words, only one robot will move at a time.
Then we will improve the robot throughput by performing motion in a separate multitasks. The revised tutorial will also include PF_AccessFeeder / PF_ReleaseFeeder. PF_AccessFeeder / PF_ReleaseFeeder are used to ensure that the robots will not collide when picking from the feeder.

  1. Create a new Epson RC+ project.
  2. Calibrate the Fixed Downward camera for Robot#1.
  3. Calibrate the Fixed Downward camera for Robot#2.
  4. From Vision Guide, create the Part Blob Sequence for Part#1. The Part Blob Sequence generally contains a single Blob vision object. The sequence will need to have the camera calibration that was performed for Robot#1 assigned to the Calibration property. The Blob object’s NumberToFind property should be set to "All".
    The ThresholdAuto property of the Blob should be set to False (default value). Place parts on the platform, open the Histogram window and adjust the Threshold High and Low until only the parts are detected. Set the Blob’s MinArea to roughly 0.9 times that of the part’s area.
    If the part has multiple sides, then set the MinArea so that the part can be found in any orientation. Make sure that the Part Blob Sequence can detect Part#1.
    The Blob object’s Search Window should fill as much of the platform area as possible. That said, it is critical that the Blob object only finds the Parts and not the feeder tray itself.
  5. From Vision Guide, create the Part Blob Sequence for Part#2. The Part Blob Sequence generally contains a single Blob vision object. The sequence will need to have the camera calibration that was performed for Robot#2 assigned to the Calibration property. The Blob object’s NumberToFind property should be set to "All".
    The ThresholdAuto property of the Blob should be set to False (default value).
    Place parts on the platform, open the Histogram window and adjust the Threshold High and Low until only the parts are detected.
    Set the Blob’s MinArea to roughly 0.9 times that of the part’s area.
    If the part has multiple sides, then set the MinArea so that the part can be found in any orientation. Make sure that the Part Blob Sequence can detect Part#2. The Blob object’s Search Window should fill as much of the platform area as possible.
    That said, it is critical that the Blob object only finds the Parts and not the feeder tray itself.
  6. From Vision Guide, create the Part Sequence which will be used to find Part#1.
    Make sure to set the Calibration property to the calibration that was performed for Robot#1.
    Typically, a Geometric object is used to locate the Front. (and a second Geometric object is used to find the Back of the part if Flip is required). The vision object’s NumberToFind property is normally set to "All".
  7. From Vision Guide, create the Part Sequence which will be used to find Part#2.
    Make sure to set the Calibration property to the calibration that was performed for Robot#2.
    Typically, a Geometric object is used to locate the Front. (and a second Geometric object is used to find the Back of the part if Flip is required). The vision object’s NumberToFind property is normally set to "All".
  8. Go to the [Tools] - [Part Feeding] dialog and Add a new part for Part#1. The "Part Wizard" will walk you through the process of adding a part. Make sure that you select Robot#1 on the first page of the Part Wizard.
    For more details about the Part Wizard, please refer to the following chapter.
    Let’s Use the Part Feeding Option
  9. Go to the [Calibration] page for the new Part#1 and click on the [Calibrate] button to start the Calibration Wizard.
    Please refer to the following section for details on how to use the Calibration Wizard.
    Calibration & Test
  10. Go to the [Pick] page for Part#1 and click the [Teach] button.
    Jog Robot#1 to the part pick height and teach the "Pick Z".
  11. Click the [Add] button in the [Part Feeding] dialog to add Part#2. Configure the part using the "Part Wizard".
    Make sure that you select Robot#2 on the first page of the Part Wizard.
  12. Go to the [Calibration] page and click the [Calibrate] button to start the Calibration Wizard.
  13. Go to the [Pick] page for Part#1 and click the [Teach] button. Jog Robot#2 to the part pick height and teach the "Pick Z".
  14. Close the Part Feeding dialog.
    The Part Feeding template code (i.e., the Part Feeding callback functions) is automatically created.
  15. Modify the template code as follows.

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

We will now modify the example code so that the robot motion will be performed in separate multitasks. When one robot is leaving the feeder, the other robot can begin moving toward the feeder. When robots share a feeder with parallel motion, it is critical that the PF_AccessFeeder and PF_ReleaseFeeder commands are used to prevent robot collisions.
In addition, the revised code will parallel process the feeder vibration and robot motion. In this tutorial, when each robot is 80% of the way to its place position, the robot has cleared the camera’s field of view and an image can be acquired.
Furthermore, when each robot is 80% of the way to its place position, it is safe for the other robot to begin moving toward the feeder. Of course, this is just an example. The actual percentage of motion depends on the speed and relative positioning of the robots in your specific situation. Each robot has a point labeled "park" and a point labeled "place". For this tutorial, Robot#1 picks from the feeder in a Righty arm orientation and Robot#2 picks from the feeder in a Lefty arm orientation.
Here is the revised template code.

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