Skip to content

Add support for webservices #22

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

Draft
wants to merge 61 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
aeeff94
First system interface instruction
fleischp Nov 22, 2021
c3990d3
Add support for custom instruction over webservices
fleischp Jan 10, 2022
69ec884
Typo
gonzalocasas Jan 20, 2022
c070ac2
Add more system instructions and rework internal return format
gonzalocasas Feb 17, 2022
0ae0d5a
key collisions?
gonzalocasas Feb 17, 2022
cccbcbe
fix ambiguity of keys based on sequence ids of two different counters…
gonzalocasas Feb 17, 2022
c521b9b
Merge branch 'main' into webservices
fleischp Apr 1, 2022
8baa32c
Add support for all types of signals
fleischp Sep 27, 2022
eb92d57
Start unifying normal and system instructions into one with interface…
fleischp Nov 11, 2022
d28cedd
Update readanalog/readdigital to new unified model
fleischp Nov 11, 2022
042981e
Add support for default interface and updated all IO instructions + s…
fleischp Nov 18, 2022
59b03b2
Migrate to `black` and `compas_invocations`
gonzalocasas Dec 16, 2022
f6a7775
blacken
gonzalocasas Dec 16, 2022
7cc4ae3
Ignore temp
gonzalocasas Dec 16, 2022
d14c21a
more blackening
gonzalocasas Dec 16, 2022
e72f503
missing updates for black migration
gonzalocasas Dec 16, 2022
f9709c9
Add RAPID lexer/parser
gonzalocasas Dec 16, 2022
261b9e1
Update doc generation to include changelog in markdown
gonzalocasas Dec 16, 2022
f17f201
Update build to use python 3.9
gonzalocasas Dec 16, 2022
728c6b4
Update python classifiers
gonzalocasas Dec 16, 2022
5ff446d
Comment out old code
gonzalocasas Dec 16, 2022
3052b5d
blacken it all
gonzalocasas Dec 16, 2022
3ee6298
one more blackened file
gonzalocasas Dec 16, 2022
389c3a2
blacken tests
gonzalocasas Dec 16, 2022
85bd474
Add GetVariable and ResetApp instructions
fleischp Dec 16, 2022
a721eea
Merge branch 'webservices' of https://github.com/compas-rrc/compas_rr…
fleischp Dec 16, 2022
873e951
blacken
gonzalocasas Dec 16, 2022
790cdc7
fix error raising
gonzalocasas Dec 16, 2022
9065bbc
typo
gonzalocasas Dec 23, 2022
83039f8
Update motion instructions to new base instruction
gonzalocasas Dec 23, 2022
6b1fde0
update printtext to baseinstruction
gonzalocasas Dec 23, 2022
ae155a7
update all utility instructions to base instruction and add docs
gonzalocasas Dec 23, 2022
0a17d36
update all watch instructions to base instruction
gonzalocasas Dec 23, 2022
c3f71c0
update CHANGELOG
gonzalocasas Dec 23, 2022
decd742
Update custom instruction to base instruction
gonzalocasas Dec 23, 2022
c0ca9bb
fix
gonzalocasas Dec 23, 2022
d0411bf
remove extra space in error string prefix
gonzalocasas Dec 23, 2022
52f5a9c
Add RAPID type parsing to GetVariable
gonzalocasas Dec 23, 2022
e7442d9
Added complex data type parser (draft) for ABB
gonzalocasas Dec 23, 2022
4d12396
Make PLY Python 2.7 compatible again
gonzalocasas Jan 6, 2023
bba3601
Add SetVariable instruction
gonzalocasas Jan 6, 2023
2326c3b
Move first-pass variable parsing to ROS side
gonzalocasas Jan 20, 2023
09bb727
Remove complex type parsing from client level
gonzalocasas Jan 20, 2023
f0e00c7
refactor complex type parsing
gonzalocasas Jan 20, 2023
259bdd2
Remove outdated code
gonzalocasas Jan 20, 2023
2f3b3c5
python 2.7
gonzalocasas Jan 25, 2023
3081ad2
fix: #23 proper exception handling when feedback parser fails
gonzalocasas Feb 17, 2023
534cb45
Add type namespace to client and add on_before_send/on_after_receive …
gonzalocasas Feb 17, 2023
760a7ba
Add debug flag to send/send_and_wait effectively replacing the need f…
gonzalocasas Feb 17, 2023
df4d5e1
Add suport to get raw_data from GetVariable instruction
gonzalocasas Feb 17, 2023
f30fcb3
added missing on_after_receive support on send_and_subscribe
gonzalocasas Feb 17, 2023
95a0198
Renamed all parse_feedback methods to on_after_receive
gonzalocasas Feb 17, 2023
54752fe
Add Get/Set Speed ratio instructions
gonzalocasas Feb 17, 2023
6b8deb2
Add GetControllerState, GetExecutionState, GetOperationMode instructions
gonzalocasas Feb 17, 2023
7af6f36
cleanup system instructions
gonzalocasas Feb 17, 2023
095e3d7
Add is_connected to AbbClient
gonzalocasas Mar 24, 2023
a2e4abe
Add sys interface to GetJoint
gonzalocasas May 12, 2023
f23094e
Small fixes to the client (human-readable printout)
gonzalocasas Mar 20, 2024
0e7da52
Draft of custom instruction for web services interface
gonzalocasas Mar 20, 2024
80b9788
Merge branch 'main' into webservices
gonzalocasas Aug 14, 2024
ccc7fd4
TODO list
gonzalocasas Oct 1, 2024
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,5 @@ ENV/
# autogenerated sphinx
docs/reference/generated/
docs/api/generated/

/temp/
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* Add `is_connected` property to `AbbClient`

### Changed

* Changed all instructions to inherit from `BaseInstruction` instead of `ROSMsg`.
* Changed `MoveGeneric` to require new interface arguments on the constructor.

### Removed


Expand Down
20 changes: 20 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# System Interface (WebService) support

- [x] Remove "abb" hard-coded selection in compas_rrc
- [x] Add option to print/see raw result of get/set variable instructions (ie. see the "list of list" output before converting to complex types)
- [x] Decide if we keep or remove raw_data from client-level (replacement of Debug())
- [x] Rename `parse_feedback` to `on_after_receive` across the board
- [ ] Add support for more system instructions:
- [x] Motor ON/OFF
- [x] Get Joints
- [ ] Get Frame/Robtarget/etc
- [ ] Test Alberto's use case from Grasshopper: PP To Main, Start, Stop, Send process code (eg. moving the robot) and in parallel we change some variables (num, speeddata, wobj) using the system interface.

- [ ] Add support for most RAPID types:
- [ ] [PF] Add decoder/encoders to compas_rrc.compas_types
- [ ] Add __str__ pretty prints for LoadData and other types with additional info
- [ ] Update documentation
- [ ] Releaseeeeee! 🚀
- [ ] Create new docker image (compsa-rrc)
- [ ] Create new docker image for moveit/dfab noetic
- [ ] Fix tests for RAPID lex parser (move to compas_rrc_ros)
4 changes: 4 additions & 0 deletions docs/api/instructions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ Utility

Noop
PrintText
GetVariable
ResetApp
StartApp
Stop
StopApp
WaitTime

Watch
Expand Down
65 changes: 65 additions & 0 deletions docs/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,68 @@ The following procedure is used to verify the protocol versions between ``Python
* ``RRC Server`` -> ``ROS Driver``
* Every feedback from the robot contains protocol version in the header.
* ROS Driver checks protocol version on first feedback after the connection, and raises an exception **if not the same**.

Software Architecture Layers
----------------------------

RRC is composed by three layers:

* User-level: the ``Python RRC Client``, a simple-to-use Python interface which can be used as a library on any python application and/or script.
* Middleware-level: the ``ROS Driver`` running as a ROS package which acts as intermediary between robot code and user code.
* Robot-level: the ``RRC Server`` running as an application on the robot controller and the system interface (eg. ``Robot Web Service`` in the case of ABB robots).

Interfaces
----------

There are two interfaces supported by RRC:

* ``System``: The system interface connects to system-level services on the robot.
* ``Application``: The application interface connects to the robot application via TCP using the RRC protocol specified above.

Data Parsing/Conversion
-----------------------

There are three different data type representations involved in the process of sending and receiving data:

* Python data types (eg. ``compas.geometry.Frame``)
* JSON/stringified representation of data types
* Robot data types (eg. ``tooldata`` for ABB RAPID)

Rules:

* ``Python RRC Client`` is the only layer that converts from/to high-level data types, such as ``compas.geometry.Frame``.
* ``ROS Driver`` only knows about Python built-in data types and the conversions required to/from the RRC protocol, which includes the conversion of Python built-in data types to Robot-native data types.
* ``RRC Server`` only knows about the RRC protocol and how to convert to native actions.
* ``ROS Driver`` does not have a dependency to COMPAS library.


Example Workflows
-----------------

* Move to Frame using Application interface:
* ``Python RRC Client`` input is ``MoveToFrame(frame)`` -> converts to strings/floats values according to the protocol -> converted to JSON for topic publishing ->
* ``ROS Driver`` input is topic message -> converts from strings/floats values to bytes of the wire protocol -> sends over TCP/IP
* ``RRC Server`` input is TCP/IP message -> converts to RAPID actions -> creates feedback and sends it over TCP/IP
* ``ROS Driver`` input is TCP/IP message -> convert to JSON for topic publishing ->
* ``Python RRC Client`` input is topic message -> convert to feedback string (``Done``)

* Get Frame using Application interface:
* ``Python RRC Client`` input is ``GetFrame()`` -> converts to strings/floats values according to the protocol -> converted to JSON for topic publishing ->
* ``ROS Driver`` input is topic message -> converts from strings/floats values to bytes of the wire protocol -> sends over TCP/IP
* ``RRC Server`` input is TCP/IP message -> converts to RAPID actions -> creates feedback and sends it over TCP/IP
* ``ROS Driver`` input is TCP/IP message -> converts to Python built-in data types -> convert to JSON for topic publishing
* ``Python RRC Client`` input is topic message -> converts from JSON to ``compas.geometry.Frame``.

* Get Variable using System interface:
* ``Python RRC Client`` input is ``GetVariable(name)`` -> converts to strings/floats values according to the protocol -> converted to JSON for topic publishing ->
* ``ROS Driver`` input is topic message -> converts from strings/floats values to REST JSON request -> sends request to system interface ``Robot Web Service``
* ``Robot Web Service`` input is REST JSON request -> returns REST JSON response
* ``ROS Driver`` input is REST JSON response -> parse RAPID string to Python built-in data types (using ``ply``) -> convert Python built-in data types (including complex dictionaries if needed) to JSON for topic publishing (``string_values[0]`` is the JSON string serialization of the variable value) ->
* ``Python RRC Client`` input is topic message -> loads variable value in JSON from ``string_values[0]`` and converts from Python built-in data types to COMPAS and other complex data types, eg. ``compas.geometry.Frame``.

* Set Variable using System interface:
* ``Python RRC Client`` input is ``SetVariable(name, value)`` -> converts to strings/floats values according to the protocol (``string_value[0]`` is variable name, ``string_value[1]`` is data representation of variable as JSON string) -> converted to JSON for topic publishing ->
* ``ROS Driver`` input is topic message -> converts from strings/floats values to REST JSON request including the conversion of ``string_value[1]`` JSON string to a Robot-native data type -> sends request to system interface ``Robot Web Service``
* ``Robot Web Service`` input is REST JSON request -> returns REST JSON response
* ``ROS Driver`` input is REST JSON response -> convert to JSON for topic publishing ->
* ``Python RRC Client`` input is topic message -> convert to feedback string (``Done``)
26 changes: 26 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[tool.black]
line-length = 120

[tool.pytest.ini_options]
minversion = "6.0"
testpaths = ["tests"]
python_files = [
"test_*.py",
"tests.py"
]
addopts = "-ra --strict --doctest-modules --doctest-glob=*.rst --tb=short"
doctest_optionflags= "NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ALLOW_UNICODE ALLOW_BYTES NUMBER"
filterwarnings = "ignore::DeprecationWarning"

[tool.isort]
line_length = 120
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
force_single_line = true
ensure_newline_before_comments = true
known_first_party = "compas_rrc"
default_section = "THIRDPARTY"
forced_separate = "test_compas_rrc"
skip = ["__init__.py"]
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ doc8
flake8
invoke>=0.14
isort
m2r2
pylint
pytest
sphinx_compas2_theme
Expand Down
35 changes: 9 additions & 26 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,12 @@
universal = 1

[flake8]
max-line-length = 180
exclude = */migrations/*

[tool:pytest]
testpaths = tests
norecursedirs =
migrations

python_files =
test_*.py
*_test.py
tests.py
addopts =
-ra
--strict
--doctest-modules
--doctest-glob=\*.rst
--tb=short

[isort]
force_single_line = True
line_length = 180
known_first_party = compas_rrc
default_section = THIRDPARTY
forced_separate = test_compas_rrc
skip = migrations
max-line-length = 120
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
E203,
# Only keep black line length check because flake8 forces it on comments as well
E501,

[pydocstyle]
convention = numpy
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ def read(*names, **kwargs):
author=about["__author__"],
author_email=about["__author_email__"],
url=about["__url__"],
long_description=re.compile("^.. start-badges.*^.. end-badges", re.M | re.S).sub(
"", read("README.rst")
),
long_description=re.compile("^.. start-badges.*^.. end-badges", re.M | re.S).sub("", read("README.rst")),
packages=find_packages("src"),
package_dir={"": "src"},
py_modules=[splitext(basename(path))[0] for path in glob("src/*.py")],
Expand Down
97 changes: 77 additions & 20 deletions src/compas_rrc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@
RobotJoints
ExternalAxes

# System instructions
# -------------------

# Besides the normal instructions, RRC can send and receive system-level instructions to the
# controller.

# .. autosummary::
# :toctree: generated/
# :nosignatures:

# GetControllerState
# GetExecutionState
# GetOperationMode
# GetSpeedRatio
# SetSpeedRatio

Debugging instructions
----------------------

Expand Down Expand Up @@ -108,67 +124,108 @@
SetDigital,
SetGroup,
)
from compas_rrc.motion import Motion, MoveToFrame, MoveToJoints, MoveToRobtarget, Zone
from compas_rrc.motion import (
Motion,
MoveToFrame,
MoveToJoints,
MoveToRobtarget,
Zone,
)
from compas_rrc.msg import PrintText
from compas_rrc.system import (
GetControllerState,
GetExecutionState,
GetOperationMode,
GetSpeedRatio,
SetSpeedRatio,
)
from compas_rrc.utility import (
Debug,
GetFrame,
GetJoints,
GetRobtarget,
GetVariable,
Noop,
ResetApp,
SetAcceleration,
SetMaxSpeed,
SetTool,
SetVariable,
SetWorkObject,
StartApp,
Stop,
StopApp,
WaitTime,
)
from compas_rrc.watch import ReadWatch, StartWatch, StopWatch
from compas_rrc.watch import (
ReadWatch,
StartWatch,
StopWatch,
)

__all_plugins__ = ["compas_rrc.__install"]
__all__ = [
# __version__
"__url__",
"__version__",
"__author__",
"__author_email__",
"__license__",
"__copyright__",
# client
"AbbClient",
"RosClient",
# common
"CLIENT_PROTOCOL_VERSION",
"FeedbackLevel",
"ExecutionLevel",
"InstructionException",
"TimeoutException",
"FutureResult",
"ExternalAxes",
"FeedbackLevel",
"FutureResult",
"InstructionException",
"RobotJoints",
"RosClient",
"AbbClient",
"SetDigital",
"SetAnalog",
"SetGroup",
"TimeoutException",
# custom
"CustomInstruction",
# io
"PulseDigital",
"ReadAnalog",
"ReadDigital",
"ReadGroup",
"Zone",
"SetAnalog",
"SetDigital",
"SetGroup",
# motion
"Motion",
"MoveToJoints",
"MoveToFrame",
"MoveToJoints",
"MoveToRobtarget",
"Zone",
# msg
"PrintText",
"CustomInstruction",
"Noop",
# system
"GetControllerState",
"GetExecutionState",
"GetOperationMode",
"GetSpeedRatio",
"SetSpeedRatio",
# utility
"Debug",
"GetFrame",
"GetJoints",
"GetRobtarget",
"GetVariable",
"Noop",
"ReadWatch",
"ResetApp",
"SetAcceleration",
"SetTool",
"SetMaxSpeed",
"Stop",
"WaitTime",
"SetTool",
"SetVariable",
"SetWorkObject",
"Debug",
"ReadWatch",
"StartApp",
"StartWatch",
"Stop",
"StopApp",
"StopWatch",
"WaitTime",
]
Loading
Loading