Collision handling
Collision handling allows you to detect and handle collisions between:
- Robots and other objects in a cell,
- Different robots,
- The parts of each robot (base, all links, tool, other attachments).
This is an experimental feature. Expect changes in the future.
Execution behaviour
Collisions are checked for all move
functions when synchronizing the motion pointer to the program pointer.
All collected movements are planned offline and checked for collisions before being executed.
If a collision is detected, the movement is not executed and an error is returned.
Currently only sequential (not simultaneous) motions of multiple robots can be checked for collisions, as motion planning is done for each robot individually.
Safety zones on robot controller
If safety zones were defined on a robot controller, those zones will be respected for all collision handling automatically. Exception: Wandelbots NOVA is currently not able to detect safety zones set on a UR controller.
Safety zones on the robot controller are respected regardless of the collision scene defined by the user, e.g. if a safety zone is not part of a collision scene, it is still respected.
At each robot position both the safety zones and the user configured collision scene are checked and either of them can signal a collision.
This means that the collision_free_p2p()
function also avoids safety zone violations.
The safety zone check uses robot, tool and zone shapes defined by the controller.
Depending on the specific model the safety zones can be adjusted directly at the controllers teach panel.
Setup
To configure a collision scene, you'll use the Device Configuration API endpoint. First, we'll list all available devices in the cell, copy all existing devices and add a collision scene to them.
List all devices
- Go to Device Configuration > List All Devices and open
LIST /api/v1/cells/{cell}/devices
. - Send the API request to receive a similar response:
[
{
"type": "timer",
"identifier": "timer"
},
{
"type": "controller",
"identifier": "ur5_0",
"controller_model_name": "UniversalRobots::Controller",
"host": "ur5_0",
"plan": false
}
]
- Copy the response.
Create a collision scene
- Stay within Device Configuration and select Create Devices >
POST /api/v1/cells/{cell}/devices
. - Select "all" from the Examples dropdown.
At the bottom of the request body in line 52, you'll find the device typecollision_scene
.{ "type": "collision_scene", "identifier": "scene", "robot_configurations": { "robot": { "use_default_link_shapes": true } } }
- Replace the other listed devices of the example with the copied response.
[ { "type": "timer", "identifier": "timer" }, { "type": "controller", "identifier": "ur5_0", "controller_model_name": "UniversalRobots::Controller", "host": "ur5_0", "plan": false }, { "type": "collision_scene", "identifier": "scene", "robot_configurations": { "robot": { "use_default_link_shapes": true } } } ]
- Replace the
robot
value with the motion group id and the controller's name as displayed in the Robot Pad:<motion_group_id>@<controller_name>
.
In this case, we're using a UR which we namedur5_0
that has the motion group id0
, thus we're replacingrobot
with0@ur5_0
.[ { "type": "timer", "identifier": "timer" }, { "type": "controller", "identifier": "ur5_0", "controller_model_name": "UniversalRobots::Controller", "host": "ur5_0", "plan": false }, { "type": "collision_scene", "identifier": "scene", "robot_configurations": { "0@ur5_0": { "use_default_link_shapes": true } } } ]
- Send the API request.
The collision scene is created.
Verify collision scene
Ensure that the collision scene as well as all previously existing devices are present in the cell with GET /api/v1/cells/{cell}/devices
.
[
{
"type": "timer",
"identifier": "timer"
},
{
"type": "controller",
"identifier": "ur5_0",
"controller_model_name": "UniversalRobots::Controller",
"host": "ur5_0",
"plan": false
},
{
"type": "collision_scene",
"identifier": "scene",
"static_colliders": {},
"robot_configurations": {
"0@ur5_0": {
"use_default_link_shapes": true,
"link_attachements": {},
"tool": {}
}
}
}
]
You've successfully set up the collision scene for the controller.
Scene interaction
Wandelscript offers core functions to interact with the collision scene during the execution of a script.
There are four function groups available to interact with the collision scene: add
, remove
, get
, and set
.
Currently all function groups modify the environment of the cell not the robot itself.
To modify the robot's collision shape, adjust it before executing Wandelscript with Configurable Collision Scene via POST /api/v1/cells/{cell}/devices
.
To synchronize all previous commands, add sync
before the desired function.
Add collider
add_static_sphere(radius, center_pose, identifier)
adds a static sphere collider to the scene.
Returns: none
.
Argument | Description |
---|---|
radius | float, in mm |
center_pose | Pose, in mm and rad |
identifier | str, Optional, default: "sphere" |
Remove collider
remove_collider(collider_identifier)
removes collider from scene.
Returns: none
.
Argument | Description |
---|---|
collider_identifier | str |
Get collider pose
get_collider_pose(collider_identifier)
gets the pose of a collider.
Returns: pose
.
Argument | Description |
---|---|
collider_identifier | str |
Set collider pose
set_collider_pose(collider_identifier, pose)
sets the pose of a collider.
Returns: none
.
Argument | Description |
---|---|
collider_identifier | str |
pose | Pose |
Set tool colliders
set_tool_colliders(robot, tool_colliders)
sets tool colliders of a robot. Must be defined in flange frame.
Returns: none
.
Argument | Description |
---|---|
robot | robot identifier |
tool_colliders | str, JSON str to represent dict[str, Collider] |
Move collision-free
To move a robot collision-free, use the collision_free_p2p()
function:
Add a static sphere collider to the scene, set its pose, and remove it again. By removing the static sphere collider it cannot block the robot's movement. But adding it between two movements blocks the robot's later movement.
home = (139.9, -37.3, 319.8, -0.9, -2.5, -1.1)
velocity(200)
blending(inf)
target = (0, -600, 0, 0, 0, 0) :: home
add_static_sphere(100, (0, -300, 0, 0, 0, 0) :: home, "sphere")
set_collider_pose("sphere", (0, -300, 5000, 0, 0, 0) :: home)
remove_collider("sphere")
move via p2p() to home
move via p2p() to target
add_static_sphere(100, (0, -300, 0, 0, 0, 0) :: home, "sphere") # Blocking the robot's return movement. The robot moves to the set target and stops there.
move via p2p() to home
Now move the robot collision-free:
home = (139.9, -37.3, 319.8, -0.9, -2.5, -1.1)
velocity(200)
blending(inf)
add_static_sphere(100, (0, -300, 0, 0, 0, 0) :: home, "sphere")
target = (0, -600, 0, 0, 0, 0) :: home
move via collision_free_p2p() to target # Note: target can also be joints
move via collision_free_p2p() to home
Example
sphere_pose_default = get_collider_pose("sphere_default")
sphere_pose_set = assoc(sphere_pose_default, 2, 900)
set_collider_pose("sphere_default", sphere_pose_set)
sphere_pose_moved = get_collider_pose("sphere_default")
box_pose = (1000, 0, 0, 0, 0, 0)
add_static_box(10, 20, 30, box_pose, "added_box")
added_box_pose = get_collider_pose("added_box")
vertices = [
(0, 0, 1),
(1, 0, 1),
(0, 1, 0),
(0, 1, 1)
]
add_static_convex_hull(vertices, (0, 0, 1200, 0, 0, 0), "added_convex_hull")
added_convex_hull_pose = get_collider_pose("added_convex_hull")
add_static_collider_from_json('{"shape":{"type":"sphere", "radius":10}, "pose":{"position":[0, 1100, 0], "orientation":[0, 0, 0]}}', "added_sphere")
added_sphere_pose = get_collider_pose("added_sphere")
# hard to assert, but this also works:
# add_static_box(10, 20, 80, box_pose, "added_box_to_remove")
# remove_collider("added_box_to_remove")