Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • This position cannot be palletized (2002)

  • Unable to find a collision-free path (2011)

  • this pattern hasn’t been fully verified (2023)

  • controlling the external hardware failed (2005)

  • vacuum not detected (1016)

  • … (more to come)

Example

Control loop via OPC UA

A script code is provided to receive commands from OPC UA. The command sequence is the following:

  • set the requested command in the OPC UA variable “COMMAND”

  • set the command parameters (specific to each command)

  • increment the variable value “COMMAND_SEQNO” by one

  • wait until “COMMAND_RESULT_SEQNO” is updated to the same value as “COMMAND_SEQNO”

  • read command result from the variable “COMMAND_RESULT” (possible values: 1=OK, 0=not OK)

Currently the following commands are supported:

  • “NEW_ORDER”: create a new palletizing task (pattern name and number of boxes)

  • “TERMINATE_PALLET”: immediately terminate the current pallet

  • “DELETE_ORDERS”: remove all orders from the queue

  • “EXIT”: terminate the robot program

To create a new palletizing task (NEW_ORDER):

  • set the requested command “NEW_ORDER” in the OPC UA variable “COMMAND”

  • set the pallet manager instance (optionally) in the variable “INSTANCE” or leave it to 0

  • set the requested pattern in the variable “PATTERN” (4-digits integer format)

  • set the requested number of boxes in the variable “BOXES” or leave it to 0 for a full pallet

  • increment the variable value “COMMAND_SEQNO”

  • wait until “COMMAND_RESULT_SEQNO” is updated to the same value as “COMMAND_SEQNO”

  • read command result from the variable “COMMAND_RESULT” (1: OK, 0: not OK)

Sample code to control Pally via OPC UA.

Code Block

def find_pattern_by_nr(pattern_number):
  # convert number to string with zero padding
  local p_str = str_cat("0000", pattern_number)
  # make sure the string is not longer than 4 digits
  p_str = str_sub(p_str, str_len(p_str)-4, 4)
  local nr_patterns = palletmanager_daemon.init_pattern_cache()
  local pattern_nr = 0
  while (pattern_nr < nr_patterns):
    local file_name = palletmanager_daemon.get_file_name(pattern_nr)
    textmsg("Testing pattern name: ", file_name)
    if (str_len(file_name) >= 6):
      if (str_sub(file_name, 2, 4) == p_str):
        textmsg("Found pattern name: ", file_name)
        return file_name
      end
    end
    pattern_nr = pattern_nr + 1
  end
  return ""
end

def do_insert_order():
  local instance = opcua_server_read_byname("INSTANCE")
  local pattern = opcua_server_read_byname("PATTERN")
  local boxes = opcua_server_read_byname("BOXES")
  local pattern_name = find_pattern_by_nr(pattern)
  local result = 0
  if (pattern_name != ""):
    local nr_orders = palletmanager_daemon.get_nr_orders(instance)
    if (palletmanager_daemon.insert_order(instance, nr_orders, "SOME_ID", "My Order", pattern_name, [1, boxes])):
      textmsg(str_cat("Inserted order ", pattern_name), str_cat(" with boxes ", boxes))
      result = 1
    end
  end
  return result
end

def do_terminate_pallet():
  local result = 0
  local instance = opcua_server_read_byname( "INSTANCE")
  if (instance==0):
    rf_P1_terminate = True
    rf_P2_terminate = True
    result = 1
  end
  return result
end

def do_delete_orders():
  local instance = opcua_server_read_byname("INSTANCE")
  local result = 0
  if (palletmanager_daemon.clear_orders(instance)):
    result = 1
  end
  return result
end

thread OpcPallyThread():
  local command = ""
  local can_go = True
  while (can_go):
    local last_command_seqno = opcua_server_read_byname("COMMAND_SEQNO")
    local command_seqno = last_command_seqno
    while (command_seqno == last_command_seqno):
      sleep(1)
      command_seqno = opcua_server_read_byname("COMMAND_SEQNO")
    end
    last_command_seqno = command_seqno
    command = opcua_server_read_byname("COMMAND")
    local result = -999 # command not supported
    if (command == "NEW_ORDER"):
      result = do_insert_order()
    elif (command == "TERMINATE_PALLET"):
      result = do_terminate_pallet()
    elif (command == "DELETE_ORDERS"):
      result = do_delete_orders()
    elif (command == "EXIT"):
      can_go = False
      result = 1
    end
    opcua_server_write_byname("COMMAND_RESULT", result)
    opcua_server_write_byname("COMMAND_RESULT_SEQNO", command_seqno)
  end
  # received EXIT command, terminate program
  halt
end


opc_pally_thid = run OpcPallyThread()

Palletizing progress via OPC UA

A script code is provided that updates some OPC UA variables during palletizing.

  • The actual pattern name will be visible in the string variable “CURRENT_PATTERN”.

  • The number of boxes being picked (1 for single pick, 2 for double pick, etc) in the “CURRENT_PICK” variable.

  • The variable “CURRENT_BOXES” contains the number of boxes already on the pallet.

  • The remaining boxes are indicated in “REMAINING_BOXES”.

  • The variable “PALLET_NUMBER” contains 1 when palletizing on the right pallet, 2 for the left pallet.

Code Block
def update_progress_opc(pallet_nr, pattern_name, current_pick, current_boxes, remaining_boxes):
  opcua_server_write_byname("CURRENT_PALLET", pallet_nr)
  opcua_server_write_byname("CURRENT_PATTERN", pattern_name)
  opcua_server_write_byname("CURRENT_PICK", current_pick)
  opcua_server_write_byname("CURRENT_BOXES", current_boxes)
  opcua_server_write_byname("REMAINING_BOXES", remaining_boxes)
end

def update_progress(after_pallet=False):
  # OBS instance number is always 0 in single product mode
  # use instance 0 or 1 in Dual product mode
  local st = palletmanager_daemon.get_pallet_state(0)
  local current_pick = st[0]-st[1]-st[2]
  local current_boxes = st[1]
  local remaining_boxes = 0
  if (not after_pallet):
    remaining_boxes = st[0]-st[1]
  end
  update_progress_opc(PalletNr, ProductName, current_pick, current_boxes, remaining_boxes)
end

def BeforePalletAction():
  update_progress()
end

def AfterGrabAction():
  update_progress()
end

def AfterReleaseAction():
  update_progress()
end

def AfterPalletAction():
  update_progress(True)
end 

The script functions are called from Pally callbacks:

  • beforePallet: call the function BeforePalletAction()

  • afterGrab: call the function AfterGrabAction()

  • afterRelease: call the function AfterReleaseAction()

  • afterPallet : call the function AfterPalletAction()

Add more function calls if needed.

...

Error codes via OPC UA

A script code is provided to suppress app popups and redirect error codes into registers.

The error/warning code will be set in the OPC UA integer variable “STATE_CODE”. Optional parameter of the error/warning can be accessed in the “STATE_PARAM” integer variable. If an error/warning occurs, the boolean variable “STATE_FLAG” will be set to true.

Info

Please note: the sample program will not simulate user acknowledgement of errors.

Code Block
rf_out_state_error = [3, 64]
rf_out_state_warning = [3, 64]
rf_out_state_info = [3, 64]
rf_out_state_code = [5, 24]
rf_out_state_param = [5, 25]

# Cannot simulate robot inputs
# program will continue after 1 sec. anyway
rf_in_state_ack = [-1, -1]

thread PopupToOpcConverterThread():
  opcua_server_write_byname("STATE_FLAG", False)
  while (True):
    # wait until state out
    while (not read_output_boolean_register(64)):
      sleep(0.1)
    end
    opcua_server_write_byname("STATE_CODE", read_output_integer_register(24))
    opcua_server_write_byname("STATE_PARAM", read_output_integer_register(25))
    opcua_server_write_byname("STATE_FLAG", True)
    textmsg("waiting for user ACK")
    # user must acknowledge via OPC UA by clearing STATE FLAG value
    while (opcua_server_read_byname("STATE_FLAG")):
      sleep(0.1)
    end
    # send ACK back to Pally
    # TODO cannot simulate input ACK
    # write...register()
    while (read_output_boolean_register(64)):
      sleep(0.1)
    end
    # TODO cannot simulate input 
    # write...register()
    textmsg("continue after user ACK")
  end
end

popcthid = run PopupToOpcConverterThread()

Running the example

See headless Pally in action here:

...

Download the example

Download the complete example here:

View file
nameHeadless.zip