External Script Usage Guide
About 2514 wordsAbout 8 min
As an extension point of the software, external scripts are called by Pickwiz. They can add business logic without modifying the core code, flexibly adapting to customized on-site requirements such as compensating Robot arm installation errors, unit conversion, obstacle avoidance strategy adjustment, and protocol adaptation, and do not involve network communication functions. When the system reaches the corresponding stage (such as after calculating the Picking Pose or before preparing to send data to the Robot arm), it will automatically call these functions in the external script.
At present, external scripts can be added in four places:
When PickWiz receives a message from the Robot
When PickWiz processes received placeholder information
When PickWiz processes sent placeholder information
Before PickWiz sends a message to the Robot
MC/Snap7/Modbus do not have the concept of messages, so there is no mechanism for processing external script instructions in the first and fourth places

1. Create a Python File
Create a python file in the directory C:\Users\dex\.dexforce\kuawei_data\robot_hooks, as shown below.
Right-click in the directory C:\Users\dex\.dexforce\kuawei_data\robot_hooks and create a new text document 
Change the extension of the newly created text document to .py, and click "Yes" to change the extension 
Copy the following code into the newly created Python file.
from typing import List
from PickLight.log.logger import logger_pipe
class AttrHooks(object): # Create an AttrHooks class containing multiple hook functions; the system will automatically recognize and call them
# All hook functions follow the same parameter format:
#@staticmethod
#def received_messages_hook(data: str, context) -> str
# When PickWiz receives a command from the Robot: received_messages_hook
# Before PickWiz sends a command to the Robot: messages_hook
# When PickWiz processes placeholder information: placeholder_hook
# data: the raw data to be processed; the type depends on the scenario. context: context information, including additional information such as Robot configuration and task configuration id
# context: Robot context information, including additional information such as Robot configuration and task configuration id. You can use context.get_available_context() inside the hook function to obtain the context information available to the current functioncontext: context information, including additional information such as Robot configuration and task configuration id. You can obtain the current available context configuration through context.get_available_context(). The currently available context information is as follows.
Robot configuration: robot_config
Reserved decimal places: decimals
Robot degrees of freedom: dof_type
Rotation expression: rotation_type
Length unit: translation_unit
Angle unit: euler_angle_unit
Task configuration id: config_ids
Task id: task
Calibration id: calibration
Robot id: robot
Vision Parameter id: vision_param
ROI id: roi
Product id: product
Gripper id: end_effector
Scene Object id: scene_object (when the collision detection plugin is selected)
roi
2d ROI information: roi2d
3d ROI information: roi3d
2. PickWiz Receives Robot Commands
When PickWiz receives a command sent by the Robot, you can add the pre_receive_messages_hook function to the AttrHooks class in the newly created Python file to process the received Robot message.
❗At present, the external script function is only registered and takes effect at two specific moments, "refresh configuration" and "send detection result". Therefore, if you modify the
pre_receive_messages_hookfunction, you need to manually switch the configuration or trigger a detection once for the modified function to take effect; otherwise, the system will still use the old function.
Example: When PickWiz receives a short command code sent by the Robot (such as the short messages like "210" and "211" in the example), the pre_receive_messages_hook function in the external script is used for parsing and processing, directly replacing the short command code with a complete command that the Robot can recognize and execute with full Parameters (for example, replacing "210" with "d,0,0,0,0,0,0,1"), thereby avoiding the Robot being unable to respond or executing incorrectly due to incomplete short command information, and quickly adapting to the command interaction requirements of on-site Robots.
@staticmethod
def pre_receive_messages_hook(data: str, context) -> str: # When PickWiz receives a command sent by the Robot, adjust the received Robot fields based on the different fields sent by the Robot
logger_pipe.info("available context: %s", context.get_available_context())
logger_pipe.info("received messages: %s", data)
if data == "210":
data = "d,0,0,0,0,0,0,1"# When "210" is received, replace it with the full command "d,0,0,0,0,0,0,1"
elif data == "211":
data = "d,0,0,0,0,0,0,2"# When "211" is received, replace it with "d,0,0,0,0,0,0,2"
return dataExample: Fix a task configuration (for example, the ROI ID in a fixed task configuration). When PickWiz receives a Robot command, it first checks whether the ROI ID in the current context is 1. If it is not 1, it automatically changes the command content to "d,0,0,0,0,0,0,1", thereby fixing the ROI ID to 1 and avoiding errors in picking, detection, and other tasks caused by on-site ROI configuration confusion.
@staticmethod
def pre_receive_messages_hook(data: str, context) -> str: # When PickWiz receives a command sent by the Robot, check whether the ROI id is 1; if not, switch the ROI to 1 through the placeholder ${roi_id}
logger_pipe.info("available context: %s", context.get_available_context())
logger_pipe.info("raw messages: %s", data)
if context["config_ids"]["roi"] != 1:
data = "d,0,0,0,0,0,0,1"
logger_pipe.info("modified messages: %s", data)
return data3. Modify Received Placeholder Information
Placeholders can be used in various configurations and messages in the system for dynamic replacement with actual values. In commands received by PickWiz, the meaning, default value, and data type of each placeholder are shown in the table below.
| Placeholder | Meaning | Data Type |
|---|---|---|
| p | Robot 6d pose | 6-digit floating point |
| j | Robot joint pose | 6-digit floating point |
| ps | Workpiece size | 1-3 digit floating point |
| p_tol | Workpiece size tolerance | 1-3 digit floating point |
| pid | Workpiece ID | short integer |
| wid | Task ID | short integer |
| calib_id | Calibration configuration ID | short integer |
| ee_id | Tool ID | short integer |
| roi_id | ROI ID | short integer |
| vp_id | Vision Parameter ID | short integer |
| so_id | Scene Object ID | short integer |
| co | Photo calculation type | short integer |
| max_merge_num | Maximum number of combinations per row | short integer |
| max_merge_lines | Maximum number of combination rows | short integer |
To modify placeholder information, you can add the placeholder_hook function to the AttrHooks class in the newly created Python file.
Example: Fix a task configuration (for example, the ROI ID in a fixed task configuration). When PickWiz receives a command sent by the Robot, it forcibly fixes the ROI ID to 1, avoiding errors in picking, detection, and other tasks caused by on-site ROI configuration confusion.
@staticmethod
def roi_id_hook(data: str, context) -> str: # When PickWiz receives a command sent by the Robot, forcibly switch the ROI id to 1
logger_pipe.info("raw pid: %s", data)
data = 1
logger_pipe.info("modified pid: %s", data)
return data4. Modify Sent Placeholder Information
Placeholders can be used in various configurations and messages in the system for dynamic replacement with actual values. In commands sent by PickWiz to the Robot, the meaning, default value, and data type of each placeholder are shown in the table below.
| Placeholder | Meaning | Default Value | Data Type |
|---|---|---|---|
| s | Detection result signal | 1 | short integer |
| vn | Valid instance quantity | 1 | short integer |
| ln | Remaining instance quantity | 1 | short integer |
| rn | Returned instance quantity | 1 | short integer |
| tn | Total detected instances | 1 | short integer |
| pre_pick | Picking Waypoint | 2,j1,j2,j3,j4,j5,j6,j1,j2,j3,j4,j5,j6 | floating point |
| post_pick | Retreat waypoint | 2,j1,j2,j3,j4,j5,j6,j1,j2,j3,j4,j5,j6 | floating point |
| pose_index | Pick Point index | 1 | short integer |
| grasp_pose | Picking Pose | 0,0,0,0,0,0 | floating point |
| grasp_pid | Picked workpiece ID | 1 | short integer |
| length | Workpiece length (along the image x direction) | 0.2 | floating point |
| width | Workpiece width (along the image y direction) | 0.2 | floating point |
| height | Workpiece height | 0.1 | floating point |
| rect_length | Workpiece length (along the image x direction) | 0.1 | floating point |
| rect_width | Workpiece width (along the image y direction) | 0.1 | floating point |
| direction | Workpiece orientation (0: horizontal along x, 1: vertical along y) | 1 | short integer |
| left_top | Top-left vertex | x,y,z | floating point |
| right_top | Top-right vertex | x,y,z | floating point |
| left_bottom | Bottom-left vertex | x,y,z | floating point |
| right_bottom | Bottom-right vertex | x,y,z | floating point |
| entity | Returned instance type (0: workpiece, 1: pallet) | 0 | short integer |
| category_id | Workpiece category | 0 | short integer |
| aux_info | Additional information | ... | floating point |
| radius | Circular surface radius | 0.2 | floating point |
| pmf_height | Cylinder height | 0.2 | floating point |
| sr | Automatic calibration sampling result | 1 | short integer |
| cp | Next sampling pose for automatic calibration | 0,0,0,0,0,0 | floating point |
| so_size_id | (Collision Detection) container size ID | 1 | short integer |
| so_size | (Collision Detection) container size (length, width, height, long-side thickness, short-side thickness, bottom thickness) | 0.1,0.1,0.1,0.1,0.1,0.1 | floating point |
| so_pose | (Collision Detection) container pose | 0,0,0,0,0,0 | floating point |
To modify placeholder information, you can add the placeholder_hook function to the AttrHooks class in the newly created Python file.
Example: Adjust the detection result signal
@staticmethod
def s_hook(data: List[int], context) -> List[int]: # Adjust the detection result signal; when the returned signal is not success (100), set all others to error (-1)
logger_pipe.info("raw signal: %s", data)
if data and data[0] != 100:
data[0] = -1
logger_pipe.info("modified signal: %s", data)
return dataExample: Adjust the picking height
@staticmethod
def grasp_pose_hook(data: List[float], context) -> List[float]: # Adjust the picking height by increasing the Z coordinate of all Pick Points by 0.01. Suitable for compensating Robot arm installation errors or fine-tuning Pick Points according to workpiece height.
logger_pipe.info("raw poses: %s", data)
# Increase the Z coordinate value
if data and len(data) >= 6:
modified_data = data.copy()
pose_size = 6 # Each pose consists of 6 values
poses_count = len(data) // pose_size
for i in range(poses_count):
z_index = i * pose_size + 2 # The Z coordinate is in the 3rd position (index 2)
if z_index < len(modified_data):
modified_data[z_index] += 0.01 # Increase the Z coordinate by 0.01
logger_pipe.info("modified poses: %s", modified_data)
return modified_data
return data5. Before PickWiz Sends Commands to the Robot
Before PickWiz sends commands to the Robot, if you need to process messages, you can add the pre_send_messages_hook function to the AttrHooks class in the newly created Python file.
When the Robot is not configured with the "split message" function, the
datalist usually has only 1 element, which is the complete command message to be sent, so the function only needs to process this one element.When the Robot is configured with the "split message" function (that is, one complete command is split into multiple sub-messages and sent), the
datalist contains all split sub-messages, with each sub-message as an element in the list. The function needs to process all sub-message elements in the list separately to ensure that each sub-message meets the sending requirements.
Example: Before PickWiz sends a command to the Robot, adjust the content of the first placeholder in the command string. This function first reads the original command list data to be sent (the default list length is 1 and contains only one complete command), and then determines and modifies the content of the first placeholder in the command string according to on-site requirements (for example, when the signal corresponding to the first placeholder is not the success value 100, it is forcibly changed to -1), ensuring that the content of the first placeholder in the command received by the Robot meets the task requirements and avoiding Robot execution errors caused by abnormal original placeholder data.
@staticmethod
def pre_send_messages_hook(data: List[str], context) -> List[str]:# When the first placeholder is ${s}, adjust the returned signal; when the returned signal is not success (100), set all others to error (-1)
logger_pipe.info("raw messages: %s", data[0])
result = data[0]
if result and result.split(",")[0] != "100":
data[0] = "-1" + result[result.find(","):]
logger_pipe.info("modified messages: %s", data[0])
return data