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

Sphinx doc #95

Merged
merged 10 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 7 additions & 3 deletions .github/helpers/check_urls.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@ urls=$(grep -oP "(http|ftp|https):\/\/([a-zA-Z0-9_-]+(?:(?:\.[a-zA-Z0-9_-]+)+))(

fail_counter=0

FAILED_LINKS=()
for item in $urls; do
# echo $item
filename=$(echo "$item" | cut -d':' -f1)
url=$(echo "$item" | cut -d':' -f2-)
echo "Checking $url from file $filename"
echo -n "Checking $url from file $filename"
if ! curl --head --silent --fail "$url" 2>&1 > /dev/null; then
echo "Invalid link in file $filename: $url"
echo -e " \033[0;31mNOT FOUND\033[32m\n"
FAILED_LINKS+=("$url from file $filename")
((fail_counter=fail_counter+1))
else
echo "$url ok"
printf " \033[32mok\033[0m\n"
fi
done

echo "Failed files:"
printf '%s\n' "${FAILED_LINKS[@]}"
exit $fail_counter
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ jobs:
--exclude-dir=CMakeModules \
--exclude=tcp_socket.cpp \
--exclude-dir=debian \
--exclude=real_time.md \
--exclude=dataflow.graphml \
--exclude=start_ursim.sh

Expand Down
5 changes: 5 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
MD013:
line_length: 100
MD033:
allowed_elements: [img, a]
11 changes: 10 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,13 @@ repos:
- repo: https:/pre-commit/mirrors-clang-format
rev: 'v14.0.6'
hooks:
- id: clang-format
- id: clang-format
- repo: https:/DavidAnson/markdownlint-cli2
rev: v0.13.0
hooks:
- id: markdownlint-cli2
exclude: "include/ur_client_library/queue/LICENSE.md"
- repo: https:/sphinx-contrib/sphinx-lint
rev: v0.9.1
hooks:
- id: sphinx-lint
322 changes: 70 additions & 252 deletions README.md

Large diffs are not rendered by default.

142 changes: 142 additions & 0 deletions doc/architecture.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
Library architecture
====================

The image below shows a rough architecture overview that should help developers to use the different
modules present in this library. Note that this is an incomplete view on the classes involved.

.. image:: images/dataflow.svg
:width: 100%
:alt: Data flow


The core of this library is the ``UrDriver`` class which creates a
fully functioning robot interface. For details on how to use it, please see the
:ref:`example-driver` section.

The ``UrDriver``'s modules will be explained in the following.

RTDEClient
----------

The ``RTDEClient`` class serves as a standalone
`RTDE <https://www.universal-robots.com/articles/ur-articles/real-time-data-exchange-rtde-guide/>`_
client. To use the RTDE-Client, you'll have to initialize and start it separately:

.. code-block:: c++

rtde_interface::RTDEClient my_client(ROBOT_IP, notifier, OUTPUT_RECIPE, INPUT_RECIPE);
my_client.init();
my_client.start();
while (true)
{
std::unique_ptr<rtde_interface::DataPackage> data_pkg = my_client.getDataPackage(READ_TIMEOUT);
if (data_pkg)
{
std::cout << data_pkg->toString() << std::endl;
}
}

Upon construction, two recipe files have to be given, one for the RTDE inputs, one for the RTDE
outputs. Please refer to the `RTDE
guide <https://www.universal-robots.com/articles/ur-articles/real-time-data-exchange-rtde-guide/>`_
on which elements are available.

Inside the ``RTDEclient`` data is received in a separate thread, parsed by the ``RTDEParser`` and
added to a pipeline queue.

Right after calling ``my_client.start()``, it should be made sure to read the buffer from the
``RTDEClient`` by calling ``getDataPackage()`` frequently. The Client's queue can only contain 1
item at a time, so a ``Pipeline producer overflowed!`` error will be raised if the buffer isn't read
before the next package arrives.

For writing data to the RTDE interface, use the ``RTDEWriter`` member of the ``RTDEClient``. It can be
retrieved by calling ``getWriter()`` method. The ``RTDEWriter`` provides convenience methods to write
all data available at the RTDE interface. Make sure that the required keys are configured inside the
input recipe, as otherwise the send-methods will return ``false`` if the data field is not setup in
the recipe.

An example of a standalone RTDE-client can be found in the ``examples`` subfolder. To run it make
sure to

* have an instance of a robot controller / URSim running at the configured IP address (or adapt the
address to your needs)
* run it from the package's main folder, as for simplicity reasons it doesn't use any sophisticated
method to locate the required files.


RTDEWriter
^^^^^^^^^^

The ``RTDEWriter`` class provides an interface to write data to the RTDE interface. Data fields that
should be written have to be defined inside the ``INPUT_RECIPE`` as noted above.

The class offers specific methods for every RTDE input possible to write.

Data is sent asynchronously to the RTDE interface.

ReverseInterface
----------------

The ``ReverseInterface`` opens a TCP port on which a custom protocol is implemented between the
robot and the control PC. The port can be specified in the class constructor.

It's basic functionality is to send a vector of floating point data together with a mode. It is
meant to send joint positions or velocities together with a mode that tells the robot how to
interpret those values (e.g. ``SERVOJ``, ``SPEEDJ``). Therefore, this interface can be used to do
motion command streaming to the robot.

In order to use this class in an application together with a robot, make sure that a corresponding
URScript is running on the robot that can interpret the commands sent. See `this example
script <../resources/external_control.urscript>`_ for reference.

Also see the :ref:`ScriptSender` for a way to define the corresponding URScript on the
control PC and sending it to the robot upon request.

.. _ScriptSender:

ScriptSender
------------

The ``ScriptSender`` class opens a tcp socket on the remote PC whose single purpose it is to answer
with a URScript code snippet on a "*request_program*" request. The script code itself has to be
given to the class constructor.

Use this class in conjunction with the `External Control URCap
<https:/UniversalRobots/Universal_Robots_ExternalControl_URCap>`_ which will make the
corresponding request when starting a program on the robot that contains the **External Control**
program node. In order to work properly, make sure that the IP address and script sender port are
configured correctly on the robot.

Other public interface functions
--------------------------------

This section shall explain the public interface functions that haven't been covered above


check_calibration()
^^^^^^^^^^^^^^^^^^^

This function opens a connection to the primary interface where it will receive a calibration
information as the first message. The checksum from this calibration info is compared to the one
given to this function. Connection to the primary interface is dropped afterwards.

sendScript()
^^^^^^^^^^^^

This function sends given URScript code directly to the secondary interface. The
``sendRobotProgram()`` function is a special case that will send the script code given in the
``RTDEClient`` constructor.

DashboardClient
---------------

The ``DashboardClient`` wraps the calls on the `Dashboard server <https://www.universal-robots.com/articles/ur-articles/dashboard-server-e-series-port-29999/>`_
directly into C++ functions.

After connecting to the dashboard server by using the ``connect()`` function, dashboard calls can be
sent using the ``sendAndReceive()`` function. Answers from the dashboard server will be returned as
string from this function. If no answer is received, a ``UrException`` is thrown.

Note: In order to make this more useful developers are expected to wrap this bare interface into
something that checks the returned string for something that is expected. See the
`DashboardClientROS <https:/UniversalRobots/Universal_Robots_ROS_Driver/blob/master/ur_robot_driver/include/ur_robot_driver/dashboard_client_ros.h>`_ as an example.
184 changes: 184 additions & 0 deletions doc/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))

import os
import catkin_pkg.package

catkin_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
catkin_package = catkin_pkg.package.parse_package(
os.path.join(catkin_dir, catkin_pkg.package.PACKAGE_MANIFEST_FILENAME)
)

# -- Project information -----------------------------------------------------

project = "ur_client_library"
copyright = "2022, Felix Exner"
author = "Felix Exner"

# The short X.Y version
version = catkin_package.version
# The full version, including alpha/beta/rc tags
release = catkin_package.version


# -- General configuration ---------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []

# Add any paths that contain templates here, relative to this directory.
templates_path = [".templates"]

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = ".rst"

# The master toctree document.
master_doc = "index"

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None


# -- Options for HTML output -------------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "agogo"

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = [".static"]

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}


# -- Options for HTMLHelp output ---------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = "ur_client_librarydoc"


# -- Options for LaTeX output ------------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(
master_doc,
"ur_client_library.tex",
"ur\\_client\\_library Documentation",
"Felix Exner",
"manual",
)
]


# -- Options for manual page output ------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "ur_client_library", "ur_client_library Documentation", [author], 1)]


# -- Options for Texinfo output ----------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
"ur_client_library",
"ur_client_library Documentation",
author,
"ur_client_library",
"One line description of project.",
"Miscellaneous",
)
]


# -- Options for Epub output -------------------------------------------------

# Bibliographic Dublin Core info.
epub_title = project

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''

# A unique identification for the text.
#
# epub_uid = ''

# A list of files that should not be packed into the epub file.
epub_exclude_files = ["search.html"]
11 changes: 11 additions & 0 deletions doc/example.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.. _example-driver:

Example driver
==============
In the ``examples`` subfolder you will find a minimal example of a running driver. It starts an
instance of the ``UrDriver`` class and prints the RTDE values read from the controller. To run it make
sure to
* have an instance of a robot controller / URSim running at the configured IP address (or adapt the
address to your needs)
* run it from the package's main folder (the one where this README.md file is stored), as for
simplicity reasons it doesn't use any sophisticated method to locate the required files.
File renamed without changes.
File renamed without changes
Loading
Loading