Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH components #21

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Unreleased
**Added**

* Added `to_configuration` and `to_configuration_primitive` to `compas_rrc.ExternalAxes` and `compas_rrc.RobotJoints`
* Added Grasshopper components for RRC

**Changed**

Expand Down
5 changes: 4 additions & 1 deletion src/compas_rrc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,10 @@
StopWatch
)

__all_plugins__ = ['compas_rrc.__install']
__all_plugins__ = [
'compas_rrc.rhino.install',
'compas_rrc.ghpython.install'
]
__all__ = [
'__url__',
'__version__',
Expand Down
16 changes: 16 additions & 0 deletions src/compas_rrc/ghpython/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import absolute_import


def create_id(component, name):
return '{}_{}'.format(name, component.InstanceGuid)


def coerce_frame(plane):
import Rhino
from compas.geometry import Frame
if isinstance(plane, Rhino.Geometry.Plane):
return Frame(plane.Origin, plane.XAxis, plane.YAxis)
elif isinstance(plane, Frame):
return plane
else:
return Frame(*plane)
81 changes: 81 additions & 0 deletions src/compas_rrc/ghpython/components/CompasRrc_ExecuteBatch/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""
Execute a batch of instructions.
"""
from ghpythonlib.component import add_error
from ghpythonlib.component import add_warning
from ghpythonlib.componentbase import executingcomponent as component
from scriptcontext import sticky as st

import compas_rrc as rrc
from compas_rrc.ghpython import create_id


class CompasRrcExecuteBatch(component):
TIMEOUT = 60

def __init__(self):
super(CompasRrcExecuteBatch, self).__init__()
self.wait_for_completion = True

def RunScript(self, rrc_client, instructions, run):
if not rrc_client:
add_warning('rrc_client is not assigned. The component did not run.')
self.Message = ''
return (False, None)
gonzalocasas marked this conversation as resolved.
Show resolved Hide resolved

if len(instructions) == 0:
self.Message = 'No instructions'
return (False, None)
gonzalocasas marked this conversation as resolved.
Show resolved Hide resolved

run_key = create_id(self, 'run_status')
res_key = create_id(self, 'results')

# TODO: Add checks for rrc_client.ros.is_connected before attempting to execute
if run:
futures = []
for instruction in instructions[:-1]:
future = rrc_client.send(instruction)
if instruction.feedback_level > rrc.FeedbackLevel.NONE:
futures.append(future)

last_instruction = instructions[-1]

if not self.wait_for_completion:
future = rrc_client.send(last_instruction)
if last_instruction.feedback_level > rrc.FeedbackLevel.NONE:
futures.append(future)

# In the non-wait mode, the results are futures
results = futures
else:
feedback = rrc_client.send_and_wait(last_instruction, timeout=self.TIMEOUT)

# Since we wait for the last instruction, all previous ones
# must have completed as well, so we can collect their futures
results = [future.result(timeout=self.TIMEOUT) for future in futures]
results.append(feedback)

self.Message = 'Executed {} actions'.format(len(instructions))
st[run_key] = True
st[res_key] = results

done = st.get(run_key)
results = st.get(res_key)
return (done, results)
gonzalocasas marked this conversation as resolved.
Show resolved Hide resolved

def OnTextMenuClick(self, _sender, _args):
try:
self.wait_for_completion = not self.wait_for_completion
self.ExpireSolution(True)
except Exception as ex:
add_error(str(ex))

def AppendAdditionalMenuItems(self, items):
component.AppendAdditionalMenuItems(self, items)

try:
image = None
item = items.Items.Add('Wait for completion', image, self.OnTextMenuClick)
item.Checked = self.wait_for_completion
except Exception as ex:
add_error(str(ex))
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "Execute Batch",
"nickname": "Execute",
"category": "COMPAS RRC",
"subcategory": "Execute",
"description": "Execute a batch of instructions.",
"exposure": 2,

"ghpython": {
"isAdvancedMode": true,
"iconDisplay": 2,
"inputParameters": [
{
"name": "rrc_client",
"description": "The RRC client."
},
{
"name": "instructions",
"description": "List or tree of instructions to be executed as a batch",
"scriptParamAccess": "list"
},
{
"name": "run",
"description": "If True, executes the batch of instruction on the robot.",
"typeHintID": "bool"
}
],
"outputParameters": [
{
"name": "done",
"description": "Confirmation that the instructions have been executed on the robot."
},
{
"name": "results",
"description": "Feedback received from the batch of instructions, or future result objects if the option to wait for completion is deactivated."
}
]
}
}
11 changes: 11 additions & 0 deletions src/compas_rrc/ghpython/components/CompasRrc_GetFrame/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
Request the current frame of the robot.
"""
from ghpythonlib.componentbase import executingcomponent as component

import compas_rrc as rrc


class CompasRrcGetFrame(component):
def RunScript(self):
return rrc.GetFrame()
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

{
"name": "Get Frame",
"nickname": "Get Frame",
"category": "COMPAS RRC",
"subcategory": "Utility instructions",
"description": "Request the current frame of the robot.",
"exposure": 2,

"ghpython": {
"isAdvancedMode": true,
"iconDisplay": 2,
"inputParameters": [],
"outputParameters": [
{
"name": "ins",
"description": "Instruction instance."
beverlylytle marked this conversation as resolved.
Show resolved Hide resolved
}
]
}
}
50 changes: 50 additions & 0 deletions src/compas_rrc/ghpython/components/CompasRrc_MoveToFrame/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Move robot to the specified frame in cartesian space.
"""
from ghpythonlib.component import add_error
from ghpythonlib.component import add_warning
from ghpythonlib.componentbase import executingcomponent as component

import compas_rrc as rrc
from compas_rrc.ghpython import coerce_frame


class CompasRrcMoveToFrame(component):
def __init__(self):
super(CompasRrcMoveToFrame, self).__init__()
self.motion_type = rrc.Motion.JOINT

def RunScript(self, frame, speed, zone, feedback):
if not frame:
add_warning('Frame is not defined. The component did not run.')
return (None)
gonzalocasas marked this conversation as resolved.
Show resolved Hide resolved

if not speed or speed < 0.01:
add_warning('Speed must be greater or equal to 0.01 mm/s.')
return (None)
gonzalocasas marked this conversation as resolved.
Show resolved Hide resolved

if not zone:
zone = rrc.Zone.FINE

frame = coerce_frame(frame)
feedback = feedback or rrc.FeedbackLevel.NONE
instruction = rrc.MoveToFrame(frame, speed, zone, motion_type=self.motion_type, feedback_level=feedback)

return instruction

def OnTextMenuClick(self, _sender, _args):
try:
self.motion_type = rrc.Motion.JOINT if self.motion_type == rrc.Motion.LINEAR else rrc.Motion.LINEAR
self.ExpireSolution(True)
except Exception as ex:
add_error(str(ex))

def AppendAdditionalMenuItems(self, items):
component.AppendAdditionalMenuItems(self, items)

try:
image = None
item = items.Items.Add('Move in joint space', image, self.OnTextMenuClick)
item.Checked = self.motion_type == rrc.Motion.JOINT
except Exception as ex:
add_error(str(ex))
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

{
"name": "Move To Frame",
"nickname": "Move",
"category": "COMPAS RRC",
"subcategory": "Motion instructions",
"description": "Move robot to the specified frame in cartesian space.",
"exposure": 2,

"ghpython": {
"isAdvancedMode": true,
"iconDisplay": 2,
"inputParameters": [
{
"name": "frame",
"description": "Target frame."
},
{
"name": "speed",
"description": "Integer specifying TCP translational speed in mm/s.",
"typeHintID": "int"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not float?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not float... ABB RAPID is an inflexible friend sometimes... :P

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but

if not speed or speed < 0.01:
            add_warning('Speed must be greater or equal to 0.01 mm/s.')

},
{
"name": "zone",
"description": "Zone data, either an integer or Zone.FINE. Defaults to Zone.FINE.",
"typeHintID": "int"
},
{
"name": "feedback",
"description": "Feedback level. Defaults to DONE. Use together with Zone.FINE to ensure the motion planner has executed the instruction fully.",
"typeHintID": "int"
}
],
"outputParameters": [
{
"name": "ins",
"description": "Instruction instance."
}
]
}
}
17 changes: 17 additions & 0 deletions src/compas_rrc/ghpython/components/CompasRrc_PrintText/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"""
Print text on the flex pendant.
"""
from ghpythonlib.componentbase import executingcomponent as component

import compas_rrc as rrc


class CompasRrcPrintText(component):
def RunScript(self, text, feedback):
if not text:
return (None)
gonzalocasas marked this conversation as resolved.
Show resolved Hide resolved

feedback = feedback or rrc.FeedbackLevel.NONE
instruction = rrc.PrintText(text, feedback_level=feedback)

return instruction
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

{
"name": "Print Text",
"nickname": "Print",
"category": "COMPAS RRC",
"subcategory": "Utility instructions",
"description": "Print text on the flex pendant.",
"exposure": 2,

"ghpython": {
"isAdvancedMode": true,
"iconDisplay": 2,
"inputParameters": [
{
"name": "text",
"description": "Text to print on the flex pendant."
},
{
"name": "feedback",
"description": "Feedback level. Defaults to NONE.",
"typeHintID": "int"
}
],
"outputParameters": [
{
"name": "ins",
"description": "Instruction instance."
}
]
}
}
24 changes: 24 additions & 0 deletions src/compas_rrc/ghpython/components/CompasRrc_RrcClient/code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
Creates an RRC client instance.
"""
from ghpythonlib.component import add_warning
from ghpythonlib.componentbase import executingcomponent as component

import compas_rrc as rrc


class CompasRrcClient(component):
def RunScript(self, ros_client, namespace):
if not ros_client:
add_warning('ros_client is not assigned. The component did not run.')
self.Message = ''
return (None)
gonzalocasas marked this conversation as resolved.
Show resolved Hide resolved

kwargs = {}
if namespace:
kwargs['namespace'] = namespace

rrc_client = rrc.AbbClient(ros_client, **kwargs)
self.Message = 'RRC Client ready'

return rrc_client
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

{
"name": "RRC Client",
"nickname": "RRC",
"category": "COMPAS RRC",
"subcategory": "Connect",
"description": "Create an RRC client.",
"exposure": 2,

"ghpython": {
"isAdvancedMode": true,
"iconDisplay": 2,
"inputParameters": [
{
"name": "ros_client",
"description": "The ROS client."
},
{
"name": "namespace",
"description": "Namespace to allow multiple robots to be controlled through the same ROS instance. Optional. If not specified, it will use /rob1."
}
],
"outputParameters": [
{
"name": "rrc_client",
"description": "The RRC client."
}
]
}
}
Loading