Backends

A backend is what draws a robot, and animates it. The Toolbox talks to a backend through a small, standard interface, so the same program can show a robot in a Matplotlib window, in a notebook or in a web browser, and a new backend can be added without changing the Toolbox. A backend could equally be a simulator or a physical robot, since all the Toolbox asks of it is to display the objects it is given, and to do something when time advances.

Name

Class

Display

Needs

Teach pendant

"pyplot"

PyPlot

3D, in a Matplotlib window or a notebook

nothing extra

yes

"pyplot2"

PyPlot2

2D, for planar robots, in Matplotlib

nothing extra

yes

"swift"

Swift, from the Swift package

3D, in a web browser, with meshes

the swift extra, see Installation

yes

“Teach pendant” in this context means a set of joint configuration sliders that allow you to control the configuration of the displayed robot using the robot’s teach() method.

Using a backend

Most of the time you don’t use a backend directly: robot.plot(q) makes one, adds the robot to it and steps it. Name the backend to choose one, or set the default for a robot or for all robots.

robot.plot(q, backend="swift")            # use this backend, this time
robot.default_backend = "swift"           # the default for this robot
rtb.Robot.set_default_backend("swift")    # the default for all robots

With no explicit choice the robot’s own default is used, then the default for all robots. If there is none, the Toolbox picks one: "pyplot" for a DH robot, "pyplot2" for a planar robot, and for any other robot "swift" if it has geometry to show and "pyplot" if not. If Swift is not installed it falls back to "pyplot". Swift cannot yet draw a DH robot.

roboticstoolbox.backends.load_backend makes a backend from its name. To use one directly, which is what robot.plot does for you:

import roboticstoolbox as rtb
from roboticstoolbox.backends import load_backend

robot = rtb.models.DH.Panda()
backend = load_backend("pyplot")      # make a backend
backend.launch()                      # start it with an empty scene
backend.add(robot)                    # add the robot to the scene
robot.q = robot.qr                    # set the configuration
backend.step()                        # update the display
backend.hold()                        # keep the window open

What a backend does

The backend holds a scene: the robots and other objects that it has been asked to display. It does not own them. The user’s robot object stays the source of truth, and the backend draws it, so that after robot.q = ... and step() the display agrees with the robot.

  • Starting and stopping. launch starts the display with an empty scene, which has to be done before anything is added, close shuts it down, reset returns to the state after launch, and restart closes and relaunches.

  • The scene. add(obj) puts an object in the scene and returns an identifier, and remove(id) takes it out. The object must be of a class that the backend knows how to draw, such as a robot, or an ellipsoid if the backend supports them.

  • Time. step(dt) advances the scene by dt seconds, which makes each robot act according to its control type (position, velocity, acceleration or torque) and updates the display.

  • Waiting. hold keeps the backend running after the script has finished, for as long as the window is open.

  • Optional features, which a backend declares with two flags: supports_teach is true if it can show the interactive teach pendant of teach(), and supports_ellipse is true if it can draw the ellipsoids made by plot_ellipse().

The contract

This is written down as the Connector protocol. A backend is any object that has these methods and flags, and does not have to inherit from it: Swift does not, since it does not depend on the Toolbox. The PyPlot backends inherit from it, which supplies the default values of the flags and makes a missing method an error when the backend is made. The arguments differ from one backend to another, so the methods are declared with *args, **kwargs, and the details are in each backend.

launch

Launch the external program with an empty or specific scene

close

Gracefully close the external program

reset

Reset the external program to the state defined by launch()

restart

Close and relaunch the external program to the state defined by launch()

add

Add an object to the external environment

remove

Remove an object from the external environment, given its id

step

Trigger the external program to make a time step

hold

Keep the backend open, that is stop the program from closing once the main script has finished.

class Connector(*args, **kwargs)[source]

What RTB needs of a graphical backend

A backend is any object that has these methods and flags: it does not have to inherit from this class. Swift does not, since it does not depend on RTB. The PyPlot backends inherit from it explicitly, which supplies the default values of the flags and of _add_teach_panel(), and makes a missing method an error at construction.

The methods take different arguments in different backends, so they are declared with *args, **kwargs; see the backend for the details.

supports_teach: bool = True

True if the backend supports the interactive teach pendant.

supports_ellipse: bool = False

True if the backend can render EllipsePlot objects.

abstractmethod launch(*args, **kwargs)[source]

Launch the external program with an empty or specific scene

Return type:

Any

abstractmethod step(*args, **kwargs)[source]

Trigger the external program to make a time step

step(dt) goes through each robot in the scene and makes them act based on their control type (position, velocity, acceleration, or torque). Upon acting, the other three of the four control types will be updated in the internal state of the robot object. The control type is defined by the robot object, and not all robot objects support all control types.

Return type:

Any

abstractmethod reset(*args, **kwargs)[source]

Reset the external program to the state defined by launch()

Return type:

Any

abstractmethod restart(*args, **kwargs)[source]

Close and relaunch the external program to the state defined by launch()

Return type:

Any

abstractmethod close(*args, **kwargs)[source]

Gracefully close the external program

Return type:

Any

abstractmethod add(*args, **kwargs)[source]

Add an object to the external environment

id = add(object): the object must be of a class the backend knows. It is added to the list of objects which will act upon step().

Return type:

Any

abstractmethod remove(*args, **kwargs)[source]

Remove an object from the external environment, given its id

Return type:

Any

abstractmethod hold(*args, **kwargs)[source]

Keep the backend open, that is stop the program from closing once the main script has finished. This method may need to keep an event loop running for the backend to stay responsive.

Return type:

Any

The backends

PyPlot and PyPlot2

Both use Matplotlib, which is a common and highly portable graphics library for Python but has relatively limited 3D capability. PyPlot draws robots in 3D axes and is the default. PyPlot2 is its two-dimensional counterpart for planar robots. In a notebook they work with the inline and ipympl backends of Matplotlib.

class PyPlot[source]

Bases: Connector

Graphical backend using matplotlib

matplotlib is a common and highly portable graphics library for Python, but has relatively limited 3D capability.

Example:

1import roboticstoolbox as rtb
2
3robot = rtb.models.DH.Panda()  # create a robot
4
5pyplot = rtb.backends.PyPlot()  # create a PyPlot backend
6pyplot.add(robot)              # add the robot to the backend
7robot.q = robot.qz             # set the robot configuration
8pyplot.step()                  # update the backend and graphical view

Note

PyPlot is the default backend, and robot.plot(q) effectively performs lines 7-8 above.

supports_ellipse: bool = True

True if the backend can render EllipsePlot objects.

ax: Any
fig: Any
timer: Any
limits: ndarray | Sequence[float] | None
launch(name: str | None = None, fig: Any = None, ax: Any = None, limits: ndarray | Sequence[float] | None = None, view: str | None = None, **kwargs: Any) → None[source]

Launch a graphical interface

`env = launch()` creates a blank 3D matplotlib figure and returns a reference to the backend.

Parameters:

view (str | None) – "xy", "xz" or "yz" to start with a flat, axis-aligned view of that plane, see plane_view(), or None for the usual three-dimensional view. The view is not locked, the plot can be rotated as usual.

Raises:

ValueError – if view is not one of those

Return type:

None

Optional keyword arguments

ax

Existing Matplotlib 3D axes to render into.

render_mode

One of 'window', 'notebook-widget', or 'notebook-inline'. If omitted it is chosen from the environment, see _resolve_render_mode().

animation

True if frames will be stepped through in a single running cell. In a notebook with the ipympl backend this selects the inline mode, since an ipympl figure cannot update while the cell is running.

inline_every_n

Push one inline frame every N simulation steps (inline mode only).

inline_format

Inline frame format: 'svg' (default) or 'png'.

inline_dpi

DPI for PNG inline frames only. Ignored for SVG.

step(dt: float = 0.05) → None[source]

Update the graphical scene

Parameters:

dt (float) – time step in seconds, defaults to 50 (0.05 s)

Raises:

ValueError – if dt is not greater than zero in a window, where the plot pauses for dt

Return type:

None

env.step(args) triggers an update of the 3D scene in the matplotlib window referenced by env.

Note

  • Each robot in the scene is updated based on their control type (position, velocity, acceleration, or torque).

  • Upon acting, the other three of the four control types will be updated in the internal state of the robot object.

  • The control type is defined by the robot object, and not all robot objects support all control types.

  • In a window the execution is blocked for the specified interval, which must be greater than zero: Matplotlib’s pause(0) does not return, since a timeout of zero means to wait until the event loop is stopped. In a notebook there is no pause and dt of zero is fine.

Changed in version 1.5.0: In a window, dt of zero or less raises ValueError, it used to wait for ever.

reset() → None[source]

Reset the graphical scene

env.reset() triggers a reset of the 3D scene in the matplotlib window referenced by env. It is restored to the original state defined by launch().

Return type:

None

restart() → None[source]

Restart the graphics display

env.restart() triggers a restart of the matplotlib view referenced by env. It is closed and relaunched to the original state defined by launch().

Return type:

None

close() → None[source]

env.close() gracefully closes the matplotlib window referenced by env.

Return type:

None

add(ob: Any, readonly: bool = False, display: bool = True, jointaxes: bool = True, jointlabels: bool = False, eeframe: bool = True, shadow: bool = True, name: bool = True, options: Any = None, q: ndarray | Sequence[float] | None = None, color: Any = None) → Any[source]

Add a robot to the graphical scene

Parameters:
  • ob (Any) – The object to add to the plot (robot or ellipse)

  • readonly (bool) – Do not update the state of the object (i.e. display not simulate), defaults to False

  • display (bool) – Display the object, defaults to True

  • jointaxes (bool) – Show the joint axes of the robot with arrows, defaults to True

  • eeframe (bool) – Show the end-effector frame of the robot, defaults to True

  • shadow (bool) – Display a shadow of the robot on the x-y gound plane, defaults to True

  • name (bool) – Display the name of the robot, defaults to True

  • options (Any) – colors and line widths, a dict of dicts that is merged over the defaults, for example {"robot": {"color": "r", "linewidth": 3}}

  • q (ndarray | Sequence[float] | None) – the joint coordinates to draw, by default those of the robot

  • color (Any) – the color of the robot’s line, shorthand for options["robot"]["color"] which it overrides

Return type:

Any

Returns:

for a robot, its RobotPlot handle, for anything else an integer id

handle = env.add(robot) adds the robot to the graphical

environment.

The handle is the drawing of the robot in this scene, and its q is the pose that it draws. If q is given the drawing is pinned to that pose, and the same robot can be added again in another pose, each drawn where it was put; handle.q = q moves only that drawing. If q is not given the drawing follows robot.q, as it has always done.

Changed in version 1.5.0: Added q and color, and a robot now returns its plot handle, not an integer id, which nothing could use.

Note

  • robot must be of an appropriate class.

  • Adds the robot object to a list of robots which will be updated when the step() method is called.

remove(id: int) → None[source]

Remove a robot or shape from the graphical scene

Parameters:
  • id (int) – The id of the robot to remove. Can be either the DHLink or GraphicalRobot

  • fig_num (int, optional) – The canvas index to delete the robot from, defaults to the initial one

Raises:
  • ValueError – Figure number must be between 0 and total number of canvases

  • TypeError – Input must be a DHLink or GraphicalRobot

Return type:

None

env.remove(robot) removes the robot from the graphical

environment.

hold() → None[source]

hold() keeps the plot open i.e. stops the plot from closing once the main script has finished.

Return type:

None

getframe() → Any[source]
Return type:

Any

supports_teach: bool = True

True if the backend supports the interactive teach pendant.

class PyPlot2[source]

Bases: Connector

supports_ellipse: bool = True

True if the backend can render EllipsePlot objects.

launch(name: Any = None, limits: Any = None, **kwargs: Any) → None[source]

env = launch() launches a blank 2D matplotlib figure

Optional keyword arguments

render_mode

One of 'window', 'notebook-widget', or 'notebook-inline'. If omitted it is chosen from the environment.

animation

True if frames will be stepped through in a single running cell, which selects the inline mode for the ipympl backend.

inline_every_n

Push one inline frame every N simulation steps (inline mode only).

inline_format

Inline frame format: 'svg' (default) or 'png'.

inline_dpi

DPI for PNG inline frames only. Ignored for SVG.

Return type:

None

step(dt: float = 0.05) → None[source]

state = step(args) triggers the external program to make a time step of defined time updating the state of the environment as defined by the robot’s actions.

The will go through each robot in the list and make them act based on their control type (position, velocity, acceleration, or torque). Upon acting, the other three of the four control types will be updated in the internal state of the robot object. The control type is defined by the robot object, and not all robot objects support all control types.

Parameters:

dt (float) – time step in seconds, which must be greater than zero in a window, where the plot pauses for dt; in a notebook there is no pause

Raises:

ValueError – if dt is not greater than zero in a window: Matplotlib’s pause(0) does not return, since a timeout of zero means to wait until the event loop is stopped

Return type:

None

reset() → None[source]

state = reset() triggers the external program to reset to the original state defined by launch

Return type:

None

restart() → None[source]

state = restart() triggers the external program to close and relaunch to thestate defined by launch

Return type:

None

close() → None[source]

close() closes the plot

Return type:

None

add(ob: Any, readonly: bool = False, display: bool = True, eeframe: bool = True, name: bool = False, q: Any = None, **kwargs: Any) → Any[source]

handle = add(robot) adds the robot to the external environment. robot must be of an appropriate class. This adds a robot object to a list of robots which will act upon the step() method being called.

If q is given the drawing of the robot is pinned to that pose, and the same robot can be added again in another pose; the handle that is returned is the drawing, and handle.q = q moves only that drawing. Otherwise it follows robot.q. An ellipse has no handle.

Return type:

Any

remove() → None[source]

id = remove(robot) removes the robot to the external environment.

Return type:

None

hold() → None[source]

hold() keeps the plot open i.e. stops the plot from closing once the main script has finished.

Return type:

None

supports_teach: bool = True

True if the backend supports the interactive teach pendant.

Swift

Swift is a separate package which supports the backend contract, and is installed by the swift extra. It shows the robot in a web browser, with its meshes, and the teach pendant as a panel of sliders. It does not draw ellipsoids.

Swift is a web page served by the Python process, and plot() works out how to show it:

  • In a script it opens a browser window. browser="chrome", "firefox" or "safari" on macOS, "google-chrome" or "chromium" on Linux, or a command line with %s for any other browser, chooses the browser; the names are those of Python’s webbrowser module, which depend on the operating system, and webbrowser.get(name) tells you whether one works on your machine. The default is the system’s browser. See swift.Swift.Swift.launch().

  • In a notebook it is shown in a frame of the cell, so the same robot.plot(q) works whichever you use. notebook=True asks for this explicitly, and notebook=False for a window even in a notebook. The browser that shows the notebook must be on the machine running the kernel, since the frame points at localhost. browser="notebook", the old way, is deprecated.

  • A trajectory is animated in real time, one step to each dt. Swift draws at most 60 frames per second and skips a step that comes sooner, so realtime=False would show only the first frame of a trajectory.

Changed in version 1.5.0: In a notebook Swift is shown in the cell and not in a browser window, and a trajectory is animated. notebook= is new.