Skip to Content
MaintainedWandelscriptAdvanced

Advanced Wandelscript examples

To inspire you when writing your own Wandelscript, we’ve published a set of example programs. These examples cover a wide range of automation tasks and involve robot movements, I/Os or other sensors, coordinate systems, and geometric operations.

A little selection of those examples can be found on this page, find the complete example collection  on GitHub.

Multi-robot

Pick and place using conveyors, sensors and OPC UA.

# defines the pick position of the box # 0 - 8 --> back to 0 TCP_Sucker = frame("WOS_Sucker") TCP_HookedHook = frame("WOS_HookedHook") TCP_ABB = frame("BASE/tool0") LEFT_SENSOR_IO = "digital_in[1]" RIGHT_SENSOR_IO = "digital_in[0]" RED_BUTTON_IO = "digital_in[2]" GREEN_BUTTON_IO = "digital_in[3]" prod = False debug = False run_no = 0 abb_home = (475.7, -94.4, 553.8, -0.027, -0.024, 1.176) ur_home = (191.6, -717.3, 433.2, 0, pi, 0) ur_pick_pose = (184, -1038, 150, 0, pi, 0) ur_drop_pose = (460, -832, 346, 0, pi, 0) abb_pick_pose = (484.1, 151.4, 446.6, 0.019, 0.006, 1.335) abb_drop_pose = (484.3, -388.3, 303, 0.017, 0.004, 1.335) def wait_for(key, value): while (read(controller, key) != value): pass def wait_for_left_sensor_touched(): wait_for(LEFT_SENSOR_IO, True) def wait_for_right_sensor_touched(): wait_for(RIGHT_SENSOR_IO, True) def move_conveyor_belt_to_the_left(): already_left = read(controller, LEFT_SENSOR_IO) if (already_left == False): wait_for(RIGHT_SENSOR_IO, True) write(controller, "digital_out[4]", True) write(controller, "digital_out[5]", True) write(controller, "digital_out[6]", False) sync def move_conveyor_belt_to_the_right(): already_right = read(controller, RIGHT_SENSOR_IO) if (already_right == False): wait_for(LEFT_SENSOR_IO, True) write(controller, "digital_out[4]", True) write(controller, "digital_out[5]", False) write(controller, "digital_out[6]", True) sync def abb_gripper(open): if open: write(controller, "digital_out[0]", True) write(controller, "digital_out[1]", False) write(controller, "digital_out[2]", True) else: write(controller, "digital_out[0]", True) write(controller, "digital_out[1]", True) write(controller, "digital_out[2]", False) def ur_gripper(on): if on: write(controller, "tool_out[1]", True) else: write(controller, "tool_out[1]", False) def is_red_button_pressed(): return read(controller, "digital_in[2]") == False def is_green_button_pressed(): return read(controller, "digital_in[3]") == False def is_any_sensor_touched(): return (is_left_sensor_touched() + is_right_sensor_touched()) == 1 # def is_object_in_drop_position(): # return read(controller, "digital_in[4]") == 1 def get_grid_pose(corner_pose, idx): grid_step = 63 grid_n = 3 dir_1 = (grid_step * modulo(idx, grid_n), 0, 0, 0, 0, 0) dir_2 = (0, grid_step * intdiv(idx, grid_n), 0, 0, 0, 0) pose_for_idx = corner_pose :: dir_1 :: dir_2 return pose_for_idx def move_ur_to_suck_object(idx): pick_pose = get_grid_pose(ur_pick_pose, idx) move TCP_Sucker via p2p() to pick_pose :: (0, 0, -100) ur_gripper(True) move TCP_Sucker via p2p() to pick_pose move TCP_Sucker via p2p() to pick_pose :: (0, 0, -100) def move_ur_to_unsuck_object(): move TCP_Sucker via p2p() to ur_drop_pose :: (0, 0, -150) ur_gripper(False) move TCP_Sucker via p2p() to ur_drop_pose wait(2000) move TCP_Sucker via p2p() to ur_drop_pose :: (0, 0, -150) move TCP_Sucker via p2p() to ur_home def move_ur_to_hook_object(): pick_pose = [211.3, -1036.5, 211.0, 0, pi, 0] # TODO: find pick position move TCP_HookedHook via p2p() to pick_pose :: (0, 0, -100) move TCP_HookedHook via p2p() to pick_pose move TCP_HookedHook via p2p() to pick_pose :: (0, 0, -100) def move_ur_to_unhook_object(): pick_pose = (0, 0, 100, 0, pi, 0) # TODO: find pick position move TCP_HookedHook via p2p() to pick_pose :: (0, 0, -100) move TCP_HookedHook via p2p() to pick_pose move TCP_HookedHook via p2p() to pick_pose :: (0, 0, -100) def move_ur_to_suck_hook(): hook_pick_pose = (451, -543.7, 107.6, 0, pi, 0) move TCP_Sucker via p2p() to hook_pick_pose :: (0, 0, -100) move TCP_Sucker via p2p() to hook_pick_pose ur_gripper(True) move TCP_Sucker via p2p() to hook_pick_pose :: (0, 0, -100) def move_ur_to_unsuck_hook(): hook_drop_pose = [451, -543.7, 107.6, 0, pi, 0] move TCP_Sucker via p2p() to hook_drop_pose :: (0, 0, -100) move TCP_Sucker via p2p() to hook_drop_pose ur_gripper(False) move TCP_Sucker via p2p() to hook_drop_pose :: (0, 0, -100) def move_abb_to_pick_object(): with velocity(300): do with robot_abb1200: move TCP_ABB via p2p() to abb_pick_pose :: (0, 0, 100, 0, 0, 0) move TCP_ABB via p2p() to abb_pick_pose abb_gripper(False) wait(1000) do with robot_abb1200: move TCP_ABB via p2p() to abb_pick_pose :: (0, 0, 100) def move_abb_to_drop_object(): with velocity(300): do with robot_abb1200: move TCP_ABB via p2p() to abb_drop_pose :: (0, 0, 100) move TCP_ABB via p2p() to abb_drop_pose :: (0, 0, 0, 0, 0, 0) move TCP_ABB via p2p() to abb_drop_pose :: (-200, 200, 0, 0, 0, 0) abb_gripper(True) wait(500) do with robot_abb1200: move TCP_ABB via p2p() to abb_drop_pose :: (-200, 200, 100) def reset_cell(): ur_gripper(False) abb_gripper(False) do with robot_ur10e: move TCP_Sucker via p2p() to ur_home #and do with robot_abb1200: # move via p2p() to abb_home # move_conveyor_belt_to_the_right() def skill_suck(idx): # skill_a picks the object with a vacuum gripper move_ur_to_suck_object(idx) move_conveyor_belt_to_the_right() move_ur_to_unsuck_object() move_conveyor_belt_to_the_left() # ABB movement wait_for_left_sensor_touched() move_abb_to_pick_object() sync #abb_gripper(False) move_abb_to_drop_object() sync #abb_gripper(True) def skill_hook(): # skill_b picks the object with the hook #move_ur_to_suck_hook() #move_ur_to_hook_object() #wait_for_io(controller, RIGHT_SENSOR_IO) #move_ur_to_unhook_object() #move_conveyor_belt_to_the_left() #move_ur_to_unsuck_hook() #wait_for_io(controller, LEFT_SENSOR_IO) #move_abb_to_pick_object() #move_abb_to_drop_object() print("hook") # ----------------------------------------- # TESTING # ----------------------------------------- velocity(300) # move to home do with robot: move TCP_Sucker via p2p() to ur_home move TCP_Sucker via p2p() to ur_home :: (0, 0, -136) and do with robot_abb1200: move TCP_ABB via p2p() to abb_home move TCP_ABB via p2p() to abb_home :: (0, 0, 100) # abb_pose = read(robot_abb1200, "pose") # print(abb_pose) # ----------------------------------------- # MAIN # ----------------------------------------- #abb_pose = read(robot_abb1200, "BASE/tool0") #print(abb_pose) #do with robot_abb1200: # move TCP_ABB via p2p() to abb_home # move TCP_ABB via p2p() to abb_home :: [0, 0, 100] # move TCP_ABB via p2p() to abb_home i = 0 while True: print(i) button_red_not_pressed = True button_green_not_pressed = True while True: button_red_not_pressed = read(controller, RED_BUTTON_IO) button_green_not_pressed = read(controller, GREEN_BUTTON_IO) if button_red_not_pressed == False: break if button_green_not_pressed == False: break # reset_cell() if button_red_not_pressed == False: i = 0 skill_suck(i) if button_green_not_pressed == False: skill_suck(i) i = i + 1 if i == 9: i = 0

Applications

Sanding 2 edges and 2 surfaces. Including camera and IOs.

# ### ----------------------------------------------------------- # ### Includes ------------------------- def set_motor(state, is_active): if is_active: set_io_map(get_aov_motor_ios(state, aov)) def set_compliance(state, is_active): if is_active: set_io_map(get_aov_compliance_ios(state, aov)) def align_approach(pose, align_to_origin, flip_axis, use_x_axis): if align_to_origin: return rotate_z_origin_direction(pose, flip_axis, use_x_axis) return rotate_z(pose, flip_axis, use_x_axis) def move_via_collision_free_p2p(tool, joints): convex_hulls = [ ] move tool via collision_free_p2p(convex_hulls) to joints def move_to_home_safely(flange_tcp_name, workspace_tcp_name, home, workspace_robot_mounting): # ### ----------------------------------------------------------- # ### Definitions ------------------------- pullout_mm = 100 lift_mm = 100 moving_velocity_slow = 20 moving_velocity = 50 # ### ----------------------------------------------------------- # ### Path ------------------------- flange = frame(check_tcp_name(flange_tcp_name)) workspace_tcp = frame(check_tcp_name(workspace_tcp_name)) workspace_tcp_pose = get_tcp_pose(robot, check_tcp_name(workspace_tcp_name)) velocity(moving_velocity) current = solve_point_forward(robot, read(robot, "joints"), check_tcp_name(workspace_tcp_name)) up_direction_pose = ~workspace_robot_mounting home_global = workspace_robot_mounting :: solve_point_forward(robot, home, check_tcp_name(flange_tcp_name)) current_global = workspace_robot_mounting :: current if home_global[2] - current_global[2] >= lift_mm: pullout = current :: (0, 0, -pullout_mm, 0, 0, 0) lift = up_direction_pose :: (0, 0, lift_mm, 0, 0, 0) :: ~up_direction_pose :: pullout velocity(moving_velocity_slow) move workspace_tcp via p2p() to current move workspace_tcp via line() to pullout velocity(moving_velocity) move workspace_tcp via line() to lift move_via_collision_free_p2p(workspace_tcp, home) def sand_surface(path, pressure, moving_velocity, sanding_velocity, is_hot_sanding, up_direction_pose, start_joints, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_surface): # ### ----------------------------------------------------------- # ### Definitions ------------------------- def align_pose(pose): return align_approach(pose, approach_align_to_origin, approach_flip_axis, approach_use_x_axis) ABOVE_HIGH = lift_above_surface ABOVE_CLOSE = 10 # ### ----------------------------------------------------------- # ### Path ------------------------- set_compliance(pressure, is_hot_sanding) velocity(moving_velocity) highest_polygon_pose = get_highest_point(path, up_direction_pose) move_via_collision_free_p2p(sanding_tool, start_joints) move sanding_tool via p2p() to align_pose(highest_polygon_pose :: (0, 0, -ABOVE_HIGH, 0, 0, 0) :: ~tcp_offset) move sanding_tool via line() to align_pose(highest_polygon_pose :: (0, 0, -ABOVE_CLOSE, 0, 0, 0) :: ~tcp_offset) move sanding_tool via line() to align_pose(path[0] :: (0, 0, -ABOVE_CLOSE, 0, 0, 0) :: ~tcp_offset) velocity(sanding_velocity) for i = 0..<len(path): if i == 1: set_motor(True, is_hot_sanding) move sanding_tool via line() to align_pose(path(i) :: ~tcp_offset) velocity(moving_velocity) move sanding_tool via line() to align_pose(path[-1] :: (0, 0, -ABOVE_CLOSE, 0, 0, 0) :: ~tcp_offset) set_motor(False, is_hot_sanding) move sanding_tool via line() to align_pose(highest_polygon_pose :: (0, 0, -ABOVE_CLOSE, 0, 0, 0) :: ~tcp_offset) move sanding_tool via line() to align_pose(highest_polygon_pose :: (0, 0, -ABOVE_HIGH, 0, 0, 0) :: ~tcp_offset) move_via_collision_free_p2p(sanding_tool, start_joints) def sand_edge(path, pressure, moving_velocity, sanding_velocity, is_hot_sanding, sanding_tool, start_joints, up_direction_pose, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_edge): # ### ----------------------------------------------------------- # ### Definitions ------------------------- def align_pose(pose): return align_approach(pose, approach_align_to_origin, approach_flip_axis, approach_use_x_axis) ABOVE_HIGH = lift_above_edge ABOVE_CLOSE = 10 # ### ----------------------------------------------------------- # ### Path ------------------------- edge_no_approach = slice_array(path, 2, -2) highest_pose = get_highest_point(edge_no_approach, up_direction_pose) set_compliance(pressure, is_hot_sanding) velocity(moving_velocity) move_via_collision_free_p2p(sanding_tool, start_joints) move sanding_tool via p2p() to align_pose(highest_pose :: (0, 0, -ABOVE_HIGH, 0, 0, 0)) move sanding_tool via line() to align_pose(highest_pose :: (0, 0, -ABOVE_CLOSE+1, 0, 0, 0)) move sanding_tool via line() to align_pose(edge_no_approach[0] :: (0, 0, -ABOVE_CLOSE, 0, 0, 0) :: ~tcp_offset) set_motor(True, is_hot_sanding) velocity(sanding_velocity) for i = 0..<len(edge_no_approach): move sanding_tool via line() to align_pose(edge_no_approach[i] :: ~tcp_offset) set_motor(False, is_hot_sanding) velocity(moving_velocity) move sanding_tool via line() to align_pose(edge_no_approach[-1] :: (0, 0, -ABOVE_CLOSE, 0, 0, 0) :: ~tcp_offset) move sanding_tool via line() to align_pose(highest_pose :: (0, 0, -ABOVE_CLOSE-1, 0, 0, 0)) # The -1 here is to prevent a wbr bug https://wandelbots.atlassian.net/browse/AA-1405 move sanding_tool via line() to align_pose(highest_pose :: (0, 0, -ABOVE_HIGH, 0, 0, 0)) move_via_collision_free_p2p(sanding_tool, start_joints) def sand_straight_edge(edge, target_radius, lane_number_range, lane_density_weight, level_distance, pressure, moving_velocity, sanding_velocity, is_hot_sanding, sanding_tool, start_joints, up_direction_pose, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_edge): # ### ----------------------------------------------------------- # ### Path ------------------------- meander = generate_edge_meander(edge[0], edge[1], target_radius, lane_number_range, lane_density_weight, level_distance) sand_edge(meander, pressure, moving_velocity, sanding_velocity, is_hot_sanding, sanding_tool, start_joints, up_direction_pose, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_edge) def sand_curved_edge(edge, target_radius, lane_number_range, lane_density_weight, level_distance, pressure, moving_velocity, sanding_velocity, is_hot_sanding, sanding_tool, start_joints, up_direction_pose, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_edge): # ### ----------------------------------------------------------- # ### Path ------------------------- meander = generate_curved_edge_meander(edge[0], edge[1], target_radius, lane_number_range, lane_density_weight, level_distance) sand_edge(meander, pressure, moving_velocity, sanding_velocity, is_hot_sanding, sanding_tool, start_joints, up_direction_pose, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_edge) def sand_planar_surface(poly, distance, margin, pressure, moving_velocity, sanding_velocity, is_hot_sanding, up_direction_pose, start_joints, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_surface): # ### ----------------------------------------------------------- # ### Path ------------------------- meander = generate_plane_meander(poly, distance, margin) sand_surface(meander, pressure, moving_velocity, sanding_velocity, is_hot_sanding, up_direction_pose, start_joints, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_surface) def sand_curved_surface(pcd, distance, margin, pressure, moving_velocity, sanding_velocity, is_hot_sanding, up_direction_pose, start_joints, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_surface): # ### ----------------------------------------------------------- # ### Path ------------------------- meander = generate_curved_surface_meander(pcd, distance, margin) sand_surface(meander, pressure, moving_velocity, sanding_velocity, is_hot_sanding, up_direction_pose, start_joints, tcp_offset, approach_align_to_origin, approach_flip_axis, approach_use_x_axis, lift_above_surface) # ### ----------------------------------------------------------- # ### Input parameters ------------------------- # General polygons = read(arguments, "polygons") edges = read(arguments, "edges") curved_edges = read(arguments, "curved_edges") curved_surfaces = read(arguments, "curved_surfaces") hot_sanding_on = True safety_offset_z = 0 # (mm) positive value goes away from the workpiece moving_velocity = 1000 workspace_robot_mounting = (0,0,0,0,0,0) workspace_tcp = "TOOL 5" home = [-0.08263993263244629,0.17805440723896027,0.4916095733642578,0.014160103164613247,-2.345040798187256,1.635414719581604] use_approach_optimization = False approach_align_to_origin = False approach_flip_axis = False approach_use_x_axis = False # ### ----------------------------------------------------------- # ### Definitions ------------------------- def align_pose(pose): return align_approach(pose, approach_align_to_origin, approach_flip_axis, approach_use_x_axis) # Safety features MOVING_OFFSET_HIGHEST = 150 # Path optimization features use_start_joint_search = False max_allowed_joint_deviations = [1, 1, 3, 3, 6, 6] apply_operation_sync = use_start_joint_search # ### ----------------------------------------------------------- # ### Configuration settings (developer can change) ------------- sanding_tool = frame(check_tcp_name(workspace_tcp)) tcp_pose = get_tcp_pose(robot, check_tcp_name(workspace_tcp)) tcp_correction_offset = (0, 0, 0, 0, 0, 0) # Normally set to zero (This gets applied to the points before the actual robot TCP is used) # Construct the via pose: up_direction_pose = ~workspace_robot_mounting highest_pose = get_highest_point(polygons + edges + curved_surfaces + curved_edges, up_direction_pose) above_workpiece = (highest_pose[0], highest_pose[1], highest_pose[2], 0, 0, 0) :: up_direction_pose :: (0, 0, MOVING_OFFSET_HIGHEST, 0, 0, 0) :: (0, 0, 0, pi, 0, 0) above_workpiece = align_pose(above_workpiece) # ### ----------------------------------------------------------- # ### Preparation (don't change) -------------------------------- safety_offset = (0, 0, safety_offset_z, 0, 0, 0) if hot_sanding_on: tcp_offset = tcp_correction_offset else: # This variable is kind of a 'local/relative' tcp, in relation to the actual used TCP of the robot tcp_offset = tcp_correction_offset :: safety_offset # ### ----------------------------------------------------------- # ### Skill starts --------------------------------- above_workpiece_joints = solve_point_inverse(robot, above_workpiece :: ~tcp_offset, check_tcp_name(workspace_tcp), home) blending(10) velocity(moving_velocity) move_via_collision_free_p2p(sanding_tool, home) move_via_collision_free_p2p(sanding_tool, above_workpiece_joints) sand_straight_edge(edges[0], 4, [5,17], 0.2, 100, 0.5, moving_velocity, 100, hot_sanding_on, sanding_tool, above_workpiece_joints, up_direction_pose, tcp_offset, False, False, False, 100) if apply_operation_sync: sync sand_straight_edge(edges[1], 4, [5,17], 0.2, 100, 0.5, moving_velocity, 100, hot_sanding_on, sanding_tool, above_workpiece_joints, up_direction_pose, tcp_offset, False, False, False, 100) if apply_operation_sync: sync sand_planar_surface(polygons[0], 80, 0, 2, moving_velocity, 100, hot_sanding_on, up_direction_pose, above_workpiece_joints, tcp_offset, False, False, False, 100) if apply_operation_sync: sync sand_planar_surface(polygons[1], 80, 0, 2, moving_velocity, 100, hot_sanding_on, up_direction_pose, above_workpiece_joints, tcp_offset, False, False, False, 100) if apply_operation_sync: sync # ### ----------------------------------------------------------- move_via_collision_free_p2p(sanding_tool, home) # Motions are not resolved at this point motion = motion_trajectory_to_json_string(robot)

Control flow

Loop

Loop with any robot brand.

# Robot Agnostic C1_HOME_J = [1.3950, 0.6053, 0.3194, 0.0089, 0.6564, 1.3092] C1_PICK_APPROACH_ROTATED = (-62.1, 421.9, 434.9, -2.223, -2.22, 0) C1_PICK_1 = (-44.9, 412.9, 118.8, 0, -3.1, 0) C1_PICK_2 = (-231, 383.2, 119.1, 0, -3.1001, 0.0002) C1_PICK_3 = (-265.7, 567.5, 118.8, -0.0001, -3.1079, 0.0113) C1_PICK_4 = (-81.1, 595.1, 118.8, -0.0003, -3.1019, 0.0062) # Piece 1 C1_SCANNER_APPROACH = (237.3, 478.1, 457.8, -2.225, -2.222, 0) C1_SCANNER = (352.9, 478.1, 457.8, -2.224, -2.221, 0) C1_SCANNER_LEAVE = (353.6, 319.0, 457.7, -2.226, -2.223, 0) # Piece 2 C1_SCANNER_APPROACH_2 = (237.3, 478.1, 457.8, 0, -3.1, 0) C1_SCANNER_2 = (352.9, 478.1, 457.8, 0, -3.1, 0) C1_SCANNER_LEAVE_2 = (353.6, 319.0, 457.7, 0, -3.1, 0) C1_PLACE_APPROACH = (484.3, 15.3, 200.9, -3.148, 0, 0) C1_PLACE_1 = (452.2, -12.1, 132, 3.1, 0.0, 0.0) C1_PLACE_2 = (635, 5, 132, 3.1367, 0, -0.0054) def cell1_abb_open_gripper(): write(cell1_abb, True, "Local/SC_1/SC1CBCOK") write(cell1_abb, False, "Local/SC_1/SC1CBCPREWARN") def cell2_abb_close_gripper(): write(cell1_abb, False, "Local/SC_1/SC1CBCOK") write(cell1_abb, True, "Local/SC_1/SC1CBCPREWARN") # ---------------- programm ------------ ' velocity(300) cell1_abb_open_gripper() do with cell1_abb_0: move via joint_p2p() to C1_HOME_J move via p2p() to C1_PICK_2 :: (0, 0, -50, 0, 0, 0) move via line() to C1_PICK_2 cell2_abb_close_gripper() wait(1000) do with cell1_abb_0: move via line() to C1_PICK_2 :: (0, 0, -50, 0, 0, 0) move via line() to C1_SCANNER_APPROACH_2 move via line() to C1_SCANNER_2 with velocity(50) wait(2000) do with cell1_abb_0: move via line() to C1_SCANNER_APPROACH_2 with velocity(50) move via line() to C1_PLACE_2 :: (0, 0, -50, 0, 0, 0) move via line() to C1_PLACE_2 with velocity(50) cell1_abb_open_gripper() wait(1000) velocity(300) do with cell1_abb_0: move via line() to C1_PLACE_APPROACH move via joint_p2p() to C1_HOME_J # Bringe back wait(2000) do with cell1_abb_0: move via p2p() to C1_PLACE_2 :: (0, 0, -50, 0, 0, 0) move via p2p() to C1_PLACE_2 :: (0, 0, 12.8, 0, 0, 0) with velocity(50) cell2_abb_close_gripper() wait(500) do with cell1_abb_0: move via p2p() to C1_PLACE_2 :: (0, 0, -50, 0, 0, 0) move via joint_p2p() to C1_HOME_J move via p2p() to C1_PICK_2 :: (0, 0, -50, 0, 0, 0) move via p2p() to C1_PICK_2 :: (0, 0, -5, 0, 0, 0) cell1_abb_open_gripper() wait(500) do with cell1_abb_0: move via joint_p2p() to C1_HOME_J
Last updated on