...
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 | ||
---|---|---|
|