From 9cad2d41f5fec991e3c9204e8fba0d514706a866 Mon Sep 17 00:00:00 2001
From: Anton Tetov <anton@tetov.se>
Date: Wed, 6 Apr 2022 17:33:16 +0200
Subject: [PATCH] docs, packaging & tooling

---
 .gitlab-ci.yml                 |   8 ++
 data/.gitkeep                  |   0
 log/.gitkeep                   |   0
 poetry.lock                    |  26 ++---
 pyproject.toml                 |  15 +--
 ur_py_ctl/__init__.py          |  13 +++
 ur_py_ctl/urscript_commands.py | 174 ++++++++++++++++++++++++++++-----
 7 files changed, 187 insertions(+), 49 deletions(-)
 create mode 100644 data/.gitkeep
 create mode 100644 log/.gitkeep

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ded34fb..74fe994 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -48,3 +48,11 @@ run-pre-commit:
 python3.9:
   <<: *test
   image: python:3.9
+
+python3.10:
+  <<: *test
+  image: python:3.10
+
+python3.11:
+  <<: *test
+  image: python:3.11
diff --git a/data/.gitkeep b/data/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/log/.gitkeep b/log/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/poetry.lock b/poetry.lock
index bda0ede..80a9a11 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -64,11 +64,11 @@ python-versions = ">=3.6.1"
 
 [[package]]
 name = "click"
-version = "8.0.4"
+version = "8.1.2"
 description = "Composable command line interface toolkit"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
 colorama = {version = "*", markers = "platform_system == \"Windows\""}
@@ -219,11 +219,11 @@ testing = ["pytest", "pytest-benchmark"]
 
 [[package]]
 name = "pre-commit"
-version = "2.17.0"
+version = "2.18.1"
 description = "A framework for managing and maintaining multi-language pre-commit hooks."
 category = "dev"
 optional = false
-python-versions = ">=3.6.1"
+python-versions = ">=3.7"
 
 [package.dependencies]
 cfgv = ">=2.0.0"
@@ -342,7 +342,7 @@ python-versions = ">=3.6"
 
 [[package]]
 name = "virtualenv"
-version = "20.13.4"
+version = "20.14.0"
 description = "Virtual Python Environment builder"
 category = "dev"
 optional = false
@@ -360,8 +360,8 @@ testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)",
 
 [metadata]
 lock-version = "1.1"
-python-versions = ">=3.9,<3.11"
-content-hash = "ab1f88cbf02688daeb723c77086aedf337fd9c15eac50157c4b0481537be2098"
+python-versions = ">=3.9,<3.12"
+content-hash = "abe8e0f79c0ea225ee0b4414ce6da0afa7360a1c61bf1050502ad5dbb084ef09"
 
 [metadata.files]
 "aspy.refactor-imports" = [
@@ -385,8 +385,8 @@ cfgv = [
     {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
 ]
 click = [
-    {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"},
-    {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"},
+    {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"},
+    {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"},
 ]
 colorama = [
     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
@@ -463,8 +463,8 @@ pluggy = [
     {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
 ]
 pre-commit = [
-    {file = "pre_commit-2.17.0-py2.py3-none-any.whl", hash = "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616"},
-    {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"},
+    {file = "pre_commit-2.18.1-py2.py3-none-any.whl", hash = "sha256:02226e69564ebca1a070bd1f046af866aa1c318dbc430027c50ab832ed2b73f2"},
+    {file = "pre_commit-2.18.1.tar.gz", hash = "sha256:5d445ee1fa8738d506881c5d84f83c62bb5be6b2838e32207433647e8e5ebe10"},
 ]
 py = [
     {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
@@ -542,6 +542,6 @@ typing-extensions = [
     {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"},
 ]
 virtualenv = [
-    {file = "virtualenv-20.13.4-py2.py3-none-any.whl", hash = "sha256:c3e01300fb8495bc00ed70741f5271fc95fed067eb7106297be73d30879af60c"},
-    {file = "virtualenv-20.13.4.tar.gz", hash = "sha256:ce8901d3bbf3b90393498187f2d56797a8a452fb2d0d7efc6fd837554d6f679c"},
+    {file = "virtualenv-20.14.0-py2.py3-none-any.whl", hash = "sha256:1e8588f35e8b42c6ec6841a13c5e88239de1e6e4e4cedfd3916b306dc826ec66"},
+    {file = "virtualenv-20.14.0.tar.gz", hash = "sha256:8e5b402037287126e81ccde9432b95a8be5b19d36584f64957060a3488c11ca8"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index 5a9b7d1..18858ae 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,19 +3,14 @@ requires = ["poetry-core>=1.0.0"]
 build-backend = "poetry.core.masonry.api"
 
 [tool.poetry]
-name = "py_ur_ctl"
+name = "ur_py_ctl"
 version = "0.1.0"
-description = "package for script execution on UR5 for selectica project"
-authors = [
-  "Tihomir Zilic <tihomir.zilic@control.lth.se>",
-  "Anton Tetov <anton.johansson@control.lth.se>",
-  "Jacek Malek <jacek.malec@cs.lth.se>",
-  "Anders Robertsson <anders.robertsson@control.lth.se>",
-]
-repository = "https://gitlab.control.lth.se/selectica/py_ur_ctl"
+description = "Python wrapper around URScript (for Universal Robotics robots)."
+authors = ["Anton Tetov <anton.johansson@control.lth.se>"]
+repository = "https://gitlab.control.lth.se/robotlab/ur_py_ctl"
 
 [tool.poetry.dependencies]
-python = ">=3.9,<3.11"
+python = ">=3.9,<3.12"
 
 [tool.poetry.dev-dependencies]
 flake8 = "^4.0.1"
diff --git a/ur_py_ctl/__init__.py b/ur_py_ctl/__init__.py
index 6c89e01..1ca033b 100644
--- a/ur_py_ctl/__init__.py
+++ b/ur_py_ctl/__init__.py
@@ -4,4 +4,17 @@ __version__ = "0.1.0"
 
 HERE = pathlib.Path(__file__).parent
 REPO_DIR = HERE.parent
+DATA_DIR = REPO_DIR / "data"
 LOG_DIR = REPO_DIR / "log"
+
+from .urscript_commands import Motion  # noqa: F401,E402
+from .urscript_commands import move_to_pose  # noqa: F401,E402
+from .urscript_commands import move_to_conf  # noqa: F401,E402
+from .urscript_commands import set_tcp  # noqa: F401,E402
+from .urscript_commands import set_DO  # noqa: F401,E402
+from .urscript_commands import read_DO  # noqa: F401,E402
+from .urscript_commands import set_AO  # noqa: F401,E402
+from .urscript_commands import read_AO  # noqa: F401,E402
+from .urscript_commands import sleep  # noqa: F401,E402
+from .urscript_commands import text_msg  # noqa: F401,E402
+from .urscript_commands import popup  # noqa: F401,E402
diff --git a/ur_py_ctl/urscript_commands.py b/ur_py_ctl/urscript_commands.py
index e4b6bb9..8801c66 100644
--- a/ur_py_ctl/urscript_commands.py
+++ b/ur_py_ctl/urscript_commands.py
@@ -1,3 +1,4 @@
+from collections.abc import Sequence
 from functools import wraps
 
 
@@ -9,11 +10,6 @@ def _add_whitespace(func):
     return wrapper
 
 
-class Motion(object):
-    LINEAR = 0
-    JOINT = 1
-
-
 def _get_func(func_name, urscript_args, urscript_kwargs=None):
     args = urscript_args
     if urscript_kwargs:
@@ -26,7 +22,12 @@ def _get_pose(x: float, y: float, z: float, ax: float, ay: float, az: float) ->
     return f"p[{x:.5f}, {y:.5f}, {z:.5f}, {ax:.5f}, {ay:.5f}, {az:.5f}]"
 
 
-def _get_conf(j1: float, j2: float, j3: float, j4: float, j5: float, j6: float):
+def _get_conf(joint_conf: Sequence[float]) -> str:
+    if len(joint_conf) != 6:
+        raise RuntimeError("Wrong amount of joint positions, should be 6.")
+
+    j1, j2, j3, j4, j5, j6 = joint_conf
+
     return f"[{j1:.5f}, {j2:.5f}, {j3:.5f}, {j4:.5f}, {j5:.5f}, {j6:.5f}]"
 
 
@@ -37,7 +38,8 @@ def _get_move_kwargs(**kwargs) -> str:
 
     for key in kwargs:
         if key in ok_keywords:
-            urscript_kwargs.append(f"{key}={kwargs[key]:.5f]}")
+            if kwargs[key]:
+                urscript_kwargs.append(f"{key}={kwargs[key]:.5f]}")
         else:
             raise RuntimeError(f"Keyword name {key} not recognized.")
 
@@ -47,8 +49,35 @@ def _get_move_kwargs(**kwargs) -> str:
         return " ,".join(kwargs)
 
 
+class Motion(object):
+    LINEAR = 0
+    JOINT = 1
+
+
 @_add_whitespace
 def set_tcp(x: float, y: float, z: float, rx: float, ry: float, rz: float) -> str:
+    """Create a set TCP function call
+
+    Arguments
+    ---------
+    x
+        X coordinate (m)
+    y
+        Y coordinate (m)
+    z
+        Z coordinate (m)
+    rx
+        X component of axis angle vector
+    ry
+        X component of axis angle vector
+    rz
+        X component of axis angle vector
+
+    Returns
+    -------
+    str
+        URScript function call
+    """
     return _get_func("set_tcp", _get_pose(x, y, z, rx, ry, rz))
 
 
@@ -66,6 +95,39 @@ def move_to_pose(
     t: float = None,
     r: float = None,
 ) -> str:
+    """Create a move to pose function call
+
+    Arguments
+    ---------
+    x
+        X coordinate (m)
+    y
+        Y coordinate (m)
+    z
+        Z coordinate (m)
+    rx
+        X component of axis angle vector
+    ry
+        X component of axis angle vector
+    rz
+        X component of axis angle vector
+    mode
+        Motion.LINEAR or Motion.JOINT. Defaults to Motion.JOINT
+    a
+        Tool acceleration (m/s²)
+    v
+        tool speed (m/s)
+    t
+        time (s)
+    r
+        blend radius (m)
+
+    Returns
+    -------
+    str
+        URScript function call
+
+    """
     func_name = "movel" if mode == Motion.LINEAR else "movej"
 
     pose = _get_pose(x, y, z, rx, ry, rz)
@@ -76,48 +138,108 @@ def move_to_pose(
 
 @_add_whitespace
 def move_to_conf(
-    j1: float,
-    j2: float,
-    j3: float,
-    j4: float,
-    j5: float,
-    j6: float,
+    joint_conf: Sequence[float],
     v: float = None,
     a: float = None,
     t: float = None,
     r: float = None,
 ) -> str:
-    conf = _get_conf(j1, j2, j3, j4, j5, j6)
+    """Create a move to configuration function call
+
+    Arguments
+    ---------
+    joint_conf
+        A list of joint positions (rad)
+    a
+        Joint acceleration of leading axis (rad/s²)
+    v
+        Joint speed of leading axis (rad/s)
+    t
+        time (s)
+    r
+        blend radius (m)
+
+    Returns
+    -------
+    str
+        URScript function call
+    """
+    conf = _get_conf(joint_conf)
     move_kwargs = _get_move_kwargs(v=v, a=a, t=t, r=r)
 
     return _get_func("movej", conf, move_kwargs)
 
 
 @_add_whitespace
-def textmsg(string: str) -> str:
+def text_msg(string: str) -> str:
+    """Create a log function call
+
+    Arguments
+    ---------
+    string
+        Message to print in log
+
+    Returns
+    -------
+    str
+        URScript function call
+    """
     return f'textmsg("{string}")'
 
 
+@_add_whitespace
+def popup(string: str) -> str:
+    """Construct a function call that opens a popup on the teach pendant.
+
+    Arguments
+    ---------
+    string
+        Message to print
+
+    Notes
+    -----
+    Popup arguments title, error & warning is not implemented in URScript.
+    """
+    return f'popup("{string}")'
+
+
 @_add_whitespace
 def set_DO(pin: int, state: bool) -> str:
-    """Construct a function call that sets the state of a digital out."""
+    """Construct a function call that sets the state of a digital out.
+
+    Arguments
+    ---------
+    pin
+        Pin number
+    state
+        True or False
+
+    Returns
+    -------
+    str
+        URScript function call
+    """
     # bool(state) should convert numeric representation to boolean value and
     # then into True or False as string.
     return _get_func("set_digital_out", f"{pin:d}, {bool(state)}")
 
 
 @_add_whitespace
-def sleep(seconds: int) -> str:
-    """Construct a function call that instructs the controller to sleep."""
-    return _get_func("sleep", str(seconds))
+def read_DO(pin: int) -> bool:
+    raise NotImplementedError()
 
 
 @_add_whitespace
-def popup(string: str) -> str:
-    """Construct a function call that opens a popup on the teach pendant.
+def set_AO(pin: int, value: float) -> str:
+    raise NotImplementedError()
 
-    Notes
-    -----
-    Popup arguments title, error & warning is not implemented in URScript.
-    """
-    return f'popup("{string}")'
+
+@_add_whitespace
+def read_AO(pin: int) -> float:
+    raise NotImplementedError()
+
+
+@_add_whitespace
+def sleep(seconds: int) -> str:
+    """Construct a function call that instructs the controller to sleep."""
+    return _get_func("sleep", str(seconds))
-- 
GitLab