Repository navigation
Documentation Style Guide
RTB uses reST-style docstrings rendered with Sphinx, not the NumPy docstring style.
This convention is shared across Peter's Python toolboxes (RTB, MVTB, SMTB, bdsim); see
the rvc-ecosystem repo's AGENTS.md (§5, Code Standards) for the canonical source.
- reST style:
:param name:,:returns:— not NumPy-style section headers (Parameters/Returns/Notesunderlined with dashes) - Section headings inside a docstring are rubrics:
.. rubric:: Examples(always plural, even for one example),.. rubric:: Notes,.. rubric:: References. Not an underlined title: that is NumPy style, and it only works because Sphinx'snapoleonextension reads it - Every docstring has a one-line summary, followed by a
:param:/:returns:block, followed by extended description and notes - Where appropriate, a docstring ends with
.. seealso::cross-links as its last line, the directive and not:seealso:.:seealso:looks right in the source, but Sphinx does not know it: it renders as one more labelled field after the parameters and returns ("Seealso: g()"), not as the "See also" box - Docstring references to classes and methods use the
:meth:and:class:roles, not plain text or Markdown-style backticks -
:type:/:rtype:are used only when shape information adds value beyond the signature's type hint (e.g.:type q: ndarray(6,n)) — the type hint itself covers everything else, so don't restate a plain type in:type:/:rtype:as a matter of habit - Math docstrings use
r"""..."""(a raw string) so LaTeX in:math:renders correctly - All public methods and functions are type-hinted, using modern syntax:
X | Y,X | None,list[X],dict[K, V]— notUnion,Optional,List,Dictfromtyping
r"""
One line description.
Longer paragraph description. Each section of the docstring should be
separated by a blank line.
:param name: description of the parameter
:type name: ndarray(6,n)
:param other: description of another parameter
:return: description of the return value
.. note::
An optional emphasised important note.
.. warning::
An optional warning about a gotcha or unsafe usage.
Extended discussion, background, or a worked mathematical explanation can go
here, after the parameter/return block.
.. rubric:: Examples
Prose describing what the example below shows.
.. runblock:: pycon
>>> import roboticstoolbox as rtb
>>> panda = rtb.models.Panda().ets()
>>> solver = rtb.IK_QP()
>>> Tep = panda.fkine([0, -0.3, 0, -2.2, 0, 2, 0.7854])
>>> solver.solve(panda, Tep)
.. versionadded:: 1.5.0
.. seealso:: :meth:`related_method` :class:`RelatedClass`
"""Real example, from roboticstoolbox/robot/IK.py's IK_NR class:
class IK_NR(IKSolver):
r"""
Newton-Raphson Numerical Inverse Kinematics Solver
A class which provides functionality to perform numerical inverse
kinematics (IK) using the Newton-Raphson method. See `step` method for
mathematical description.
.. note::
When using this class with redundant robots (>6 DoF), `pinv` must
be set to `True`
:param name: The name of the IK algorithm
:param ilimit: How many iterations are allowed within a search before
a new search is started
:param tol: Maximum allowed residual error E, where
:math:`E = \tfrac{1}{2} \vec{e}^\top \mat{W}_e \vec{e}` ...
"""The class docstring documents the constructor's parameters (via :param:), and lives
immediately below the class declaration. __init__ itself does not get its own
docstring — see IK_NR above: the docstring is on class IK_NR(IKSolver):, and
def __init__(self, name=..., ilimit=..., ...): has none.
Code examples that should actually execute (and show real, current output) use
.. runblock:: pycon, with a blank line and then the example indented, like any other
directive body:
.. runblock:: pycon
>>> import roboticstoolbox as rtb
>>> panda = rtb.models.Panda().ets()
>>> solver = rtb.IK_QP()
>>> Tep = panda.fkine([0, -0.3, 0, -2.2, 0, 2, 0.7854])
>>> solver.solve(panda, Tep)
Each runblock is a separate session: a second block needs its own imports, and does not see
the variables of the first.
An older layout, with the example on the next line, no blank line and no indent, also works but Sphinx reports "Explicit markup ends without a blank line" for each one, and it is the layout of the minority of the examples. Use the indented one.
A figure is a .. plot:: directive, with :include-source: to show the code that makes it
(this is the "pure code plus a figure" form):
.. plot::
:include-source:
import roboticstoolbox as rtb
puma = rtb.models.DH.Puma560()
puma.plot(puma.qr, block=False)
If the example would produce huge or non-deterministic output (hundreds of table rows,
a randomly-seeded result, anything that opens a window or a network connection — e.g.
Swift's browser-based visualizer), use a plain, static .. code-block:: pycon (or
.. code-block:: text for output) instead, with hand-written representative output.
Don't runblock something whose real captured output would be misleading or broken in
the built HTML — see docs/source/intro.rst's catalog() example and its Swift-plot
example for both cases in practice.
A new feature has .. versionadded:: X.Y.Z, and a change in behaviour has
.. versionchanged:: X.Y.Z with a sentence saying what changed, and a deprecation has
.. deprecated:: X.Y.Z, where X.Y.Z is the release that the change ships in: the next release after
the version in pyproject.toml. A notice that names a release that never exists stays wrong.
Class/module reference pages use plain automodule/autoclass directives.
A page documenting a whole module (several related classes), e.g. arm_superclass.rst:
.. automodule:: roboticstoolbox.robot.Robot
:members:
:undoc-members:
:show-inheritance:
:inherited-members:
:special-members: __getitem__A page documenting a single class, e.g. mobile-vehicle-bicycle.rst:
.. autoclass:: roboticstoolbox.mobile.Bicycle
:members:
:undoc-members:
:show-inheritance:
:inherited-members:
:special-members: __init__:special-members: is only needed to pull in a dunder method (like __init__ or
__getitem__) that Sphinx doesn't document by default.
These decisions were first written down in 2020, when the toolbox was being moved from MATLAB, and are what the code does now.
-
Optional arguments are Python keyword arguments,
Link(d=0.1, alpha=pi/2), not the MATLAB keyword-value pairs ('d', 0.1) or string options ('deg'). There is no compatibility layer for MATLAB-style arguments. -
A function that returns several things returns one object with named attributes, not a tuple to be unpacked by position and not a count of requested outputs as in MATLAB's
nargout.jtrajreturns aTrajectorywith.q,.qdand.qdd, and the inverse kinematics return anIKSolutionwith.q,.successand so on, sojtraj(q0, q1).qreads well. The oldernamedtupleform is still seen in places. -
Robot models are one class per robot under
roboticstoolbox/models/(DH,ETS,URDF), each providing its named configurations such asqzandqr, see Models. -
Examples are standalone scripts and notebooks in the
examplesanddocs/notebooksfolders, see Working with Jupyter.
- Frequently asked questions (FAQ)
- Documentation Style Guide
- Background
- Key concepts
- Introduction to robot and link classes
- Working with Jupyter
- Working from the command line
- What about Simulink?
- How to contribute
- Contributors
- Coding conventions