Kernel rig: contact sets stop a drive at the block, touching faces don't, and edit, list, enable and disable do as coded

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jyviko
2026-10-29 17:20:41 -04:00
committed by Irakli Kourtis
parent 4894419075
commit e7eb8a5d44
16 changed files with 1583 additions and 0 deletions
@@ -0,0 +1,21 @@
{
"sources": [],
"what": "contact.check with the arm driven into the block (contact off for the drive)",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Stop: box 50x10x10 from (-10,30,0), grounded; the arm's corner (40,5) turned \u03b8 reaches y = 40 sin \u03b8 + 5 cos \u03b8, which is 30 at \u03b8 = asin(30/\u221a1625) - atan(5/40) = 40.9676; at 60 the corner reaches y = 40 sin60 + 5 cos60 = 37.14 > 30: the pair overlaps; with the set enabled again contact.check lists it",
"body_count": 3,
"volume_mm3": 13000.0,
"results": [
{
"step": 17,
"json": {
"collisions": [
{
"a": "Arm:1",
"b": "Stop:1"
}
]
}
}
]
}
@@ -0,0 +1,179 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "solid.box",
"params": {
"length": 50,
"width": 10,
"height": 10,
"corner": [
-10,
30,
0
],
"operation": "new",
"body_name": "StopBox"
}
},
{
"command": "component.create",
"params": {
"name": "Stop",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"StopBox"
],
"component": "Stop"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Stop:1",
"grounded": true
}
},
{
"command": "joint.create",
"params": {
"type": "revolute",
"name": "Hinge",
"flip": true,
"a": {
"occurrence": "Base",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"b": {
"occurrence": "Arm",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"quiet": true
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Arm",
"Stop"
],
"name": "Stop set"
}
},
{
"command": "contact.disable_all",
"params": {}
},
{
"command": "joint.drive",
"params": {
"joint": "Hinge",
"quiet": true,
"value": 60
}
},
{
"command": "contact.enable_sets",
"params": {}
},
{
"command": "contact.check",
"params": {}
}
]
}
@@ -0,0 +1,39 @@
{
"sources": [],
"what": "contact.check of two blocks touching face to face, then a drive in that set",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Arm stands on Base's top face (z = 0, a 10x10 patch): touching is not passing through, so contact.check lists nothing and a drive to 90 is not stopped",
"body_count": 2,
"volume_mm3": 8000.0,
"results": [
{
"step": 11,
"json": {
"collisions": []
}
},
{
"step": 12,
"json": {
"values": [
{
"value": 90.0
}
],
"stopped_by_contact": null
}
},
{
"step": 13,
"json": {
"total": {
"center_of_mass": [
0.0,
20.0,
5.0
]
}
}
}
]
}
@@ -0,0 +1,142 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "joint.create",
"params": {
"type": "revolute",
"name": "Hinge",
"flip": true,
"a": {
"occurrence": "Base",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"b": {
"occurrence": "Arm",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"quiet": true
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Base",
"Arm"
],
"name": "Face set"
}
},
{
"command": "contact.enable_sets",
"params": {}
},
{
"command": "contact.check",
"params": {}
},
{
"command": "joint.drive",
"params": {
"joint": "Hinge",
"value": 90,
"quiet": true
}
},
{
"command": "occurrence.properties",
"params": {
"occurrence": "Arm:1"
}
}
]
}
@@ -0,0 +1,38 @@
{
"sources": [],
"what": "contact.disable_all after a set was enabled, and a 90 degree drive",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Stop: box 50x10x10 from (-10,30,0), grounded; the arm's corner (40,5) turned \u03b8 reaches y = 40 sin \u03b8 + 5 cos \u03b8, which is 30 at \u03b8 = asin(30/\u221a1625) - atan(5/40) = 40.9676; contact off: the drive reaches 90, Arm at (0,20,5) inside the block",
"body_count": 3,
"volume_mm3": 13000.0,
"results": [
{
"step": 16,
"json": {
"enabled": false
}
},
{
"step": 17,
"json": {
"values": [
{
"value": 90.0
}
]
}
},
{
"step": 18,
"json": {
"total": {
"center_of_mass": [
0.0,
20.0,
5.0
]
}
}
}
]
}
@@ -0,0 +1,185 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "solid.box",
"params": {
"length": 50,
"width": 10,
"height": 10,
"corner": [
-10,
30,
0
],
"operation": "new",
"body_name": "StopBox"
}
},
{
"command": "component.create",
"params": {
"name": "Stop",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"StopBox"
],
"component": "Stop"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Stop:1",
"grounded": true
}
},
{
"command": "joint.create",
"params": {
"type": "revolute",
"name": "Hinge",
"flip": true,
"a": {
"occurrence": "Base",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"b": {
"occurrence": "Arm",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"quiet": true
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Arm",
"Stop"
],
"name": "Stop set"
}
},
{
"command": "contact.enable_sets",
"params": {}
},
{
"command": "contact.disable_all",
"params": {}
},
{
"command": "contact.list",
"params": {}
},
{
"command": "joint.drive",
"params": {
"joint": "Hinge",
"quiet": true,
"value": 90
}
},
{
"command": "occurrence.properties",
"params": {
"occurrence": "Arm:1"
}
}
]
}
@@ -0,0 +1,35 @@
{
"sources": [],
"what": "a contact set stops a 90 degree drive of the arm at the block",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Stop: box 50x10x10 from (-10,30,0), grounded; the arm's corner (40,5) turned \u03b8 reaches y = 40 sin \u03b8 + 5 cos \u03b8, which is 30 at \u03b8 = asin(30/\u221a1625) - atan(5/40) = 40.9676; the drive stops there, fraction \u03b8/90 = 0.45520",
"body_count": 3,
"volume_mm3": 13000.0,
"results": [
{
"step": 15,
"json": {
"values": [
{
"value": 40.966136
}
],
"stopped_by_contact": {
"fraction": 0.455179
}
}
},
{
"step": 16,
"json": {
"total": {
"center_of_mass": [
15.101944,
13.112257,
5.0
]
}
}
}
]
}
@@ -0,0 +1,177 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "solid.box",
"params": {
"length": 50,
"width": 10,
"height": 10,
"corner": [
-10,
30,
0
],
"operation": "new",
"body_name": "StopBox"
}
},
{
"command": "component.create",
"params": {
"name": "Stop",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"StopBox"
],
"component": "Stop"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Stop:1",
"grounded": true
}
},
{
"command": "joint.create",
"params": {
"type": "revolute",
"name": "Hinge",
"flip": true,
"a": {
"occurrence": "Base",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"b": {
"occurrence": "Arm",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"quiet": true
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Arm",
"Stop"
],
"name": "Stop set"
}
},
{
"command": "contact.enable_sets",
"params": {}
},
{
"command": "joint.drive",
"params": {
"joint": "Hinge",
"value": 90,
"quiet": true
}
},
{
"command": "occurrence.properties",
"params": {
"occurrence": "Arm:1"
}
}
]
}
@@ -0,0 +1,22 @@
{
"sources": [],
"what": "contact.edit renaming one set and deleting another",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Stop: box 50x10x10 from (-10,30,0), grounded; the arm's corner (40,5) turned \u03b8 reaches y = 40 sin \u03b8 + 5 cos \u03b8, which is 30 at \u03b8 = asin(30/\u221a1625) - atan(5/40) = 40.9676; two sets made (contact.create turns contact on), the first renamed 'Arm stop', the second deleted: one set left",
"body_count": 3,
"volume_mm3": 13000.0,
"results": [
{
"step": 16,
"json": {
"all": false,
"enabled": true,
"sets": [
{
"name": "Arm stop"
}
]
}
}
]
}
@@ -0,0 +1,152 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "solid.box",
"params": {
"length": 50,
"width": 10,
"height": 10,
"corner": [
-10,
30,
0
],
"operation": "new",
"body_name": "StopBox"
}
},
{
"command": "component.create",
"params": {
"name": "Stop",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"StopBox"
],
"component": "Stop"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Stop:1",
"grounded": true
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Arm",
"Stop"
],
"name": "Stop set"
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Base",
"Arm"
],
"name": "Face set"
}
},
{
"command": "contact.edit",
"params": {
"set": "Stop set",
"name": "Arm stop"
}
},
{
"command": "contact.edit",
"params": {
"set": "Face set",
"delete": true
}
},
{
"command": "contact.list",
"params": {}
}
]
}
@@ -0,0 +1,32 @@
{
"sources": [],
"what": "a suppressed contact set and a 90 degree drive into the block",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Stop: box 50x10x10 from (-10,30,0), grounded; the arm's corner (40,5) turned \u03b8 reaches y = 40 sin \u03b8 + 5 cos \u03b8, which is 30 at \u03b8 = asin(30/\u221a1625) - atan(5/40) = 40.9676; with its only set suppressed nothing stops the drive: 90, Arm at (0,20,5)",
"body_count": 3,
"volume_mm3": 13000.0,
"results": [
{
"step": 16,
"json": {
"values": [
{
"value": 90.0
}
]
}
},
{
"step": 17,
"json": {
"total": {
"center_of_mass": [
0.0,
20.0,
5.0
]
}
}
}
]
}
@@ -0,0 +1,184 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "solid.box",
"params": {
"length": 50,
"width": 10,
"height": 10,
"corner": [
-10,
30,
0
],
"operation": "new",
"body_name": "StopBox"
}
},
{
"command": "component.create",
"params": {
"name": "Stop",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"StopBox"
],
"component": "Stop"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Stop:1",
"grounded": true
}
},
{
"command": "joint.create",
"params": {
"type": "revolute",
"name": "Hinge",
"flip": true,
"a": {
"occurrence": "Base",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"b": {
"occurrence": "Arm",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"quiet": true
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Arm",
"Stop"
],
"name": "Stop set"
}
},
{
"command": "contact.enable_sets",
"params": {}
},
{
"command": "contact.edit",
"params": {
"set": "Stop set",
"suppressed": true
}
},
{
"command": "joint.drive",
"params": {
"joint": "Hinge",
"quiet": true,
"value": 90
}
},
{
"command": "occurrence.properties",
"params": {
"occurrence": "Arm:1"
}
}
]
}
@@ -0,0 +1,39 @@
{
"sources": [],
"what": "contact.enable_all and a 90 degree drive into the block",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Stop: box 50x10x10 from (-10,30,0), grounded; the arm's corner (40,5) turned \u03b8 reaches y = 40 sin \u03b8 + 5 cos \u03b8, which is 30 at \u03b8 = asin(30/\u221a1625) - atan(5/40) = 40.9676; every occurrence in one set: the block stops the arm at \u03b8 = 40.97 (Base, which Arm only touches, does not)",
"body_count": 3,
"volume_mm3": 13000.0,
"results": [
{
"step": 14,
"json": {
"all": true,
"enabled": true
}
},
{
"step": 15,
"json": {
"values": [
{
"value": 40.966136
}
]
}
},
{
"step": 16,
"json": {
"total": {
"center_of_mass": [
15.101944,
13.112257,
5.0
]
}
}
}
]
}
@@ -0,0 +1,171 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "solid.box",
"params": {
"length": 50,
"width": 10,
"height": 10,
"corner": [
-10,
30,
0
],
"operation": "new",
"body_name": "StopBox"
}
},
{
"command": "component.create",
"params": {
"name": "Stop",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"StopBox"
],
"component": "Stop"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Stop:1",
"grounded": true
}
},
{
"command": "joint.create",
"params": {
"type": "revolute",
"name": "Hinge",
"flip": true,
"a": {
"occurrence": "Base",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"b": {
"occurrence": "Arm",
"point": [
0,
0,
0
],
"z": [
0,
0,
1
]
},
"quiet": true
}
},
{
"command": "contact.enable_all",
"params": {}
},
{
"command": "contact.list",
"params": {}
},
{
"command": "joint.drive",
"params": {
"joint": "Hinge",
"quiet": true,
"value": 90
}
},
{
"command": "occurrence.properties",
"params": {
"occurrence": "Arm:1"
}
}
]
}
@@ -0,0 +1,25 @@
{
"sources": [],
"what": "contact.list after two sets and contact.enable_sets",
"source": "analytic",
"method": "Base: box 20x20x10 from (-10,-10,-10), grounded; Arm: box 40x10x10 from (0,-5,0), centre (20,0,5); Stop: box 50x10x10 from (-10,30,0), grounded; the arm's corner (40,5) turned \u03b8 reaches y = 40 sin \u03b8 + 5 cos \u03b8, which is 30 at \u03b8 = asin(30/\u221a1625) - atan(5/40) = 40.9676; both sets, in the order made, contact enabled for sets, not all",
"body_count": 3,
"volume_mm3": 13000.0,
"results": [
{
"step": 15,
"json": {
"all": false,
"enabled": true,
"sets": [
{
"name": "Stop set"
},
{
"name": "Face set"
}
]
}
}
]
}
@@ -0,0 +1,142 @@
{
"commands": [
{
"command": "solid.box",
"params": {
"length": 20,
"width": 20,
"height": 10,
"corner": [
-10,
-10,
-10
],
"operation": "new",
"body_name": "BaseBox"
}
},
{
"command": "solid.box",
"params": {
"length": 40,
"width": 10,
"height": 10,
"corner": [
0,
-5,
0
],
"operation": "new",
"body_name": "ArmBox"
}
},
{
"command": "component.create",
"params": {
"name": "Base",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"BaseBox"
],
"component": "Base"
}
},
{
"command": "component.create",
"params": {
"name": "Arm",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"ArmBox"
],
"component": "Arm"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Base:1",
"grounded": true
}
},
{
"command": "solid.box",
"params": {
"length": 50,
"width": 10,
"height": 10,
"corner": [
-10,
30,
0
],
"operation": "new",
"body_name": "StopBox"
}
},
{
"command": "component.create",
"params": {
"name": "Stop",
"parent": "root",
"activate": false
}
},
{
"command": "component.move_bodies",
"params": {
"bodies": [
"StopBox"
],
"component": "Stop"
}
},
{
"command": "occurrence.ground",
"params": {
"occurrence": "Stop:1",
"grounded": true
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Arm",
"Stop"
],
"name": "Stop set"
}
},
{
"command": "contact.create",
"params": {
"occurrences": [
"Base",
"Arm"
],
"name": "Face set"
}
},
{
"command": "contact.enable_sets",
"params": {}
},
{
"command": "contact.list",
"params": {}
}
]
}