Two Robots One Part

Program Example 3.1

Example Type:
Robots & 1 Physical Part Type - Motion in PF_Robot callback - Picking in a specific order

Configuration

  • Number of Robots: 2
  • Number of Feeders: 1
  • Number of Parts Types on the Feeder: 1
  • Number of Placement Positions: 2
  • Camera Orientation: Fixed Downward Camera

Description
There are two robots and one feeder. There is only 1 physical part type. Because each robot has its own camera calibration, there are two logical Parts - Part 1 for Robot 1 and Part 2 for Robot 2.
The robots will take turns picking from the feeder. The pick order matters for this application. The alternating pick order is accomplished with "PF_ActivePart".
Robot motion is performed inside the PF_Robot callback.
This example does not have parallel processing of the feeder and robot motion. The code is simple but not efficient. Each robot has a point labeled "park" and a point labeled "place". The key concept of this example is the PF_Robot callback return value "PF_CALLBACKRESTARTACTIVEPART".
This return value allows multiple robots to use the same feeder without the potential of the part coordinates in both Part’s queues. The return value forces a new image to be acquired for only the PF_ActivePart and only the PF_ActivePart queue is loaded.

Sample 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
 
    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_RESTART_ACTIVEPART
 
Fend

Program Example 3.2

Example Type:
2 Robots & 1 Physical Part Type - motion in separate tasks - pick order does not matter - Picking in a specific order

Configuration

  • Number of Robots: 2
  • Number of Feeders: 1
  • Number of Parts Types on the Feeder: 1
  • Number of Placement Positions: 2
  • Camera Orientation: Fixed Downward Camera

Description
There are two robots and one feeder. There is only 1 physical part type. Because each robot has its own camera calibration, there are two logical Parts - Part 1 for Robot 1 and Part 2 for Robot 2. Pick order does not matter - first come, first served.
What makes this example different is that vision is acquired for each part every cycle. This may be helpful if you are concerned that surrounding parts may be disturbed during pick up.
The PF_Robot callback return value "PF_CALLBACK_RESTART" will force vision to re-run for all parts and all part queues will be reloaded.
This method is not efficient but "PF_CALLBACKRESTART" can be useful in certain circumstances.

Sample 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 PartsToPick
    PF_Start 1, 2
    Xqt Robot1PickPlace
    Xqt Robot2PickPlace
Fend
 
Function Robot1PickPlace
    Robot 1
 
    Do
        PF_AccessFeeder (1)
        Wait MemSw(PartsToPick) = On
        If PF_QueLen(1) > 0 Then
            P0 = PF_QueGet(1)
            PF_QueRemove (1)
            Jump P0 /R
            On 5
             Wait 0.5
            Jump Place ! D30; MemOff PartsToPick; PF_ReleaseFeeder 1 !
            Off 5
            Wait 0.25
        Else
            MemOff PartsToPick; PF_ReleaseFeeder 1
        EndIf
    Loop
Fend
 
Function Robot2PickPlace
    Robot 2
 
    Do
        PF_AccessFeeder (1)
        Wait MemSw(PartsToPick) = On
        If PF_QueLen(2) > 0 Then
            P0 = PF_QueGet(2)
            PF_QueRemove (2)
            Jump P0 /L
            On 2
            Wait 0.5
            Jump Place ! D30; MemOff PartsToPick; PF_ReleaseFeeder 1 !
            Off 2
            Wait 0.25
        Else
            MemOff PartsToPick; PF_ReleaseFeeder 1
        EndIf
    Loop
Fend

PartFeeding.prg

Function PF_Robot(PartID As Integer) As Integer
    MemOn PartsToPick
    Wait MemSw(PartsToPick) = Off
 
    PF_Robot = PF_CALLBACK_RESTART 'Force vision and vibration to refresh 
Fend

Program Example 3.3

Example Type:
2 Robots & 1 Physical Part Type - motion in separate tasks - First Come, First Served - Simulated process delay

Configuration

  • Number of Robots: 2
  • Number of Feeders: 1
  • Number of Parts Types on the Feeder: 1
  • Number of Placement Positions: 2
  • Camera Orientation: Fixed Downward Camera

Description
There are two robots and one feeder. There is only 1 physical part type. Because each robot has its own camera calibration, there are two logical Parts - Part 1 for Robot 1 and Part 2 for Robot 2. For this example, each robot has a variable process time (simulated by a random wait time).
Each robot is busy performing some other operation after picking up a part from the feeder.
Memory bits "Rbt1Complete" and "Rbt2Complete" are used to signal when the robot has finished picking a part from the feeder and is ready to pick up another part from the feeder. The PF_Robot callback will return the value "PF_CALLBACK_RESTART_ACTIVEPART" if the desired part (PF_ActivePart) is not the same as the current part (i.e., the other robot wants to pick up a part). This will prevent duplication of points in the robot queues.
A new image will be acquired for the PF_ActivePart and only the PF_ActivePart’s queue will be loaded. However, if the next part is the same as the current part (i.e., the same robot is going to pick from the feeder) then the PF_Robot callback return value will be "PF_CALLBACK_SUCCESS". PF_AccessFeeder and PF_ReleaseFeeder ensure that the robots will not collide when accessing the feeder.

Sample Code
Main.prg

Function Main
    Robot 1
    Motor On
    Power High
    Speed 50
    Accel 50, 50
    Jump Place
    Robot 2
    Motor On
    Power High
    Speed 50
    Accel 50, 50
    Jump Place
    MemOff PartsToPick1
    MemOff PartsToPick2

    PF_Start 1, 2
    Xqt Robot1PickPlace
    Xqt Robot2PickPlace
Fend

Function Robot1PickPlace
    Integer randomTime

    Robot 1
    MemOn Rbt1Complete

    Do
        Wait MemSw(PartsToPick1) = On
        PF_AccessFeeder (1)
        MemOff Rbt1Complete
        P0 = PF_QueGet(1)
        PF_QueRemove (1)
        Jump P0 /R
        On rbt1Gripper
        Wait 0.25
        Jump Place ! D30; MemOff PartsToPick1; PF_ReleaseFeeder 1 !
        Off rbt1Gripper
        Wait 0.25
        'Test long process time - robot is doing something else
        Randomize
        randomTime = Int(Rnd(9)) + 1
        Wait randomTime
        MemOn Rbt1Complete
    Loop
Fend

Function Robot2PickPlace
    Integer randomTime

    Robot 2
    MemOn Rbt2Complete

    Do
        Wait MemSw(PartsToPick2) = On
        PF_AccessFeeder (1)
        MemOff Rbt2Complete
        P0 = PF_QueGet(2)
        PF_QueRemove (2)
        Jump P0 /L
        On rbt2Gripper
        Wait 0.25
        Jump Place ! D30; MemOff PartsToPick2; PF_ReleaseFeeder 1 !
        Off rbt2Gripper
        Wait 0.25
        'Test long process time - robot is doing something else
        Randomize
        randomTime = Int(Rnd(9)) + 1
        Wait randomTime
        MemOn Rbt2Complete
    Loop
Fend

PartFeeding.prg

Function PF_Robot(PartID As Integer) As Integer
    Integer nextPart

    Select PartID
        Case 1
            MemOn PartsToPick1
            Wait MemSw(PartsToPick1) = Off
        Case 2
            MemOn PartsToPick2
            Wait MemSw(PartsToPick2) = Off
    Send

    Wait MemSw(Rbt1Complete) = On Or MemSw(Rbt2Complete) = On
    If MemSw(Rbt1Complete) = On Then
        nextPart = 1
    ElseIf MemSw(Rbt2Complete) = On Then
        nextPart = 2
    EndIf

    PF_ActivePart nextPart

    If nextPart = PartID Then
        'Same part so no need to re-acquire an image and reload the queue
        PF_Robot = PF_CALLBACK_SUCCESS
    Else
        'Restart from vision-
        'Acquire image and load queue for only the Active Part
        PF_Robot = PF_CALLBACK_RESTART_ACTIVEPART
    EndIf

Fend