Skip to content
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
33 changes: 21 additions & 12 deletions docs/notebooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,30 @@ found by that line, not by its position) and is folded by default.
Then it installs the toolbox with its dependencies, from the wheel bundled with the
JupyterLite site if there is one, or else from PyPI.

## The standard first cell
## The first cell

Every notebook starts with the same markdown cell: the logo and title, the copyright
line, and a short description. It is generated from the notebook's own metadata by
`sync_bootstrap.py`, like the bootstrap cell, and the `<!-- RTB_HEADER` comment on its
first line marks it:
The first cell of a notebook is ordinary markdown, written by hand: the logo and title,
the copyright line and a description. The logo is an absolute GitHub URL, since Colab
fetches only the one `.ipynb` file and cannot see `figs/`. A notebook that was updated
for API drift says so there ("Modernised <date>").

```json
"metadata": {"rtb_header": {"title": "Robot dynamics",
"paragraphs": ["What this notebook shows."],
"modernised": "2026-10-19"}}
```
The second cell is the generated bootstrap cell, below.

## Editing a notebook

Edit it as you like, in VS Code or anywhere. Before you commit:

1. **Run `python docs/notebooks/clear_outputs.py`.** Notebooks are committed without
outputs (clearing them in VS Code is not enough on its own). The script also resets
the metadata an editor writes (the name and version of your Python environment, and
so on) to a canonical form, and writes the file as Jupyter does, so opening and
saving a notebook does not show up as a change.
2. That is all for an ordinary edit. `python docs/notebooks/sync_bootstrap.py` is only
needed after you change `_rtb_nb_bootstrap.py` or a notebook's `rtb_bootstrap`
metadata (it also adds cell ids, which VS Code would otherwise add whenever it
opens a notebook that has none).

`title` is required; `paragraphs`, `copyright` and `modernised` are optional.
`modernised` adds a note that the notebook was updated to address API drift.
`docs.yml` runs both scripts with `--check`, so CI tells you if you forgot.

## Outputs are not committed

Expand Down
83 changes: 34 additions & 49 deletions docs/notebooks/branched-robot.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
"cells": [
{
"cell_type": "markdown",
"id": "2aa1a0db",
"metadata": {},
"source": [
"<!-- RTB_HEADER -- generated from the notebook metadata (rtb_header) by sync_bootstrap.py, do not hand-edit -->\n",
"<table>\n",
" <tr>\n",
" <td><div align=\"left\"><font size=\"30\">Robotics Toolbox for Python</font></div></td>\n",
" <td><img src=\"figs/RobToolBox_RoundLogoB.png\" width=\"300\"></td>\n",
" <td><img src=\"https://github.com/petercorke/robotics-toolbox-python/raw/main/docs/notebooks/figs/RobToolBox_RoundLogoB.png?raw=1\" width=\"300\"></td>\n",
" </tr>\n",
"</table>\n",
"\n",
Expand All @@ -26,6 +26,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "a13e6155",
"metadata": {
"jupyter": {
"source_hidden": true
Expand Down Expand Up @@ -80,6 +81,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "9daa4a69",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -89,6 +91,7 @@
},
{
"cell_type": "markdown",
"id": "5a617374",
"metadata": {},
"source": [
"We will load a model for a simple Y-shaped planar robot. Check out the source code to see how the model was constructed using `Link` and `Robot` classes."
Expand All @@ -97,6 +100,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "d91fc922",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -106,6 +110,7 @@
},
{
"cell_type": "markdown",
"id": "ee1f4eb9",
"metadata": {},
"source": [
"From the displayed table we see that this robot has two end-effectors, indicated by the links shown in blue and prefixed with the @ symbol.\n",
Expand All @@ -116,6 +121,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "0f9b8925",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -124,6 +130,7 @@
},
{
"cell_type": "markdown",
"id": "9be2bf18",
"metadata": {},
"source": [
"which writes a file in the current folder. We then render it to SVG format and [load and display it](https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html?highlight=svg#IPython.display.SVG)"
Expand All @@ -132,6 +139,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "36593abb",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -141,6 +149,7 @@
},
{
"cell_type": "markdown",
"id": "ee7b73be",
"metadata": {},
"source": [
"The fixed base of the robot is shown as the dark grey node. Link reference frames are shown by circles and the edges are marked with the elementary transform sequences that define the relative poses of the link frames. End-effector nodes are marked by a blue double circle.\n",
Expand All @@ -152,6 +161,7 @@
},
{
"cell_type": "markdown",
"id": "11846548",
"metadata": {},
"source": [
"The forward kinematics is quite straightforward, but we must specify which end-effector we are interested in"
Expand All @@ -160,6 +170,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "fdcdda90",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -168,6 +179,7 @@
},
{
"cell_type": "markdown",
"id": "2fec3923",
"metadata": {},
"source": [
"which is exactly the same as the pose of the second branch"
Expand All @@ -176,6 +188,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "9506e063",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -184,6 +197,7 @@
},
{
"cell_type": "markdown",
"id": "a46a6bcd",
"metadata": {},
"source": [
"In a similar fashion we can also compute the Jacobian, in this case as a $6 \\times 4$ matrix"
Expand All @@ -192,6 +206,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "1ea285df",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -200,6 +215,7 @@
},
{
"cell_type": "markdown",
"id": "990a8207",
"metadata": {},
"source": [
"We can generate an ETS for the bottom-branch of the robot"
Expand All @@ -208,6 +224,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "fac103c3",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -217,6 +234,7 @@
},
{
"cell_type": "markdown",
"id": "ec1eafbd",
"metadata": {},
"source": [
"and we could easily turn this into an unbranched robot represented by an `Robot` instance"
Expand All @@ -225,6 +243,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "47dd0ff7",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -234,6 +253,7 @@
},
{
"cell_type": "markdown",
"id": "216c43d3",
"metadata": {},
"source": [
"This robot has 5 links but only 4 joint angles which are inherited from the original branched robot: `q0`, `q1`, `q4` and `q5`. Its `fkine` method accepts either a vector of the four joint angles, in order, or a vector of six elements indexed by the original joint numbers, in which case `q2` and `q3` are ignored.\n",
Expand All @@ -244,6 +264,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "5c4851ce",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -253,6 +274,7 @@
},
{
"cell_type": "markdown",
"id": "bfa5dd51",
"metadata": {},
"source": [
"which is expressed as an ETS. Note that it is not in minimal form and the terms in the middle `tx(-1) * tx(1)` cancel out. We can precompile the constants which will take care of this for us"
Expand All @@ -261,6 +283,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "8081cc08",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -269,6 +292,7 @@
},
{
"cell_type": "markdown",
"id": "fce34f81",
"metadata": {},
"source": [
"# Graph display variations\n",
Expand All @@ -279,6 +303,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "733672f5",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -289,6 +314,7 @@
},
{
"cell_type": "markdown",
"id": "fb39355d",
"metadata": {},
"source": [
"and the input to a link frame is a black dot if it is preceded by a revolute joint, and a black box if it preceded by a prismatic joint.\n",
Expand All @@ -299,6 +325,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "6f999740",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -309,6 +336,7 @@
},
{
"cell_type": "markdown",
"id": "173f9240",
"metadata": {},
"source": [
"## PR2 model\n",
Expand All @@ -319,6 +347,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "454a5ced",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -331,6 +360,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "644b4e65",
"metadata": {},
"outputs": [],
"source": []
Expand All @@ -343,54 +373,9 @@
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
},
"varInspector": {
"cols": {
"lenName": 16,
"lenType": 16,
"lenVar": 40
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
},
"rtb_header": {
"title": "A branched robot",
"paragraphs": [
"A robot with more than one end-effector: its forward kinematics and Jacobian for each branch, extracting the ETS of a branch, and drawing the robot as a graph. Drawing the graphs needs [Graphviz](https://graphviz.org) (the `dot` command) installed."
],
"modernised": "2026-10-19"
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 4
"nbformat_minor": 5
}
Loading
Loading