diff --git a/docs/notebooks/symbolic.ipynb b/docs/notebooks/symbolic.ipynb
index e9daa05b6..dbad257d6 100644
--- a/docs/notebooks/symbolic.ipynb
+++ b/docs/notebooks/symbolic.ipynb
@@ -1,5 +1,28 @@
{
"cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
+ "
\n",
+ " \n",
+ " Robotics Toolbox for Python | \n",
+ "  | \n",
+ "
\n",
+ "
\n",
+ "\n",
+ "\n",
+ "Symbolic computation
\n",
+ "\n",
+ "\n",
+ "(c) Peter Corke 2026\n",
+ "\n",
+ "Forward kinematics and inverse dynamics of a Puma 560 robot with symbolic joint variables, and generating code from the results. The dynamics section takes a few minutes to run in full.\n",
+ "\n",
+ "> **Modernised 2026-10-19** to address API drift: this notebook was written for an earlier release of the Toolbox, and has been updated so that it runs with the current one."
+ ]
+ },
{
"cell_type": "code",
"execution_count": null,
@@ -51,7 +74,7 @@
" print(f'Running {where} using RTB v{version}')\n",
" return colab\n",
"\n",
- "COLAB = await ensure_installed()\n"
+ "COLAB = await ensure_installed(extras=['ik'])\n"
]
},
{
@@ -560,7 +583,7 @@
"outputs": [],
"source": [
"g = sym.symbol('g')\n",
- "puma.gravity = [0, 0, g]"
+ "puma.gravity = [0, 0, -g]"
]
},
{
@@ -596,7 +619,7 @@
"source": [
"Now we compute the inverse dynamics as a function of symbolic joint coordinates, velocities, accelerations and gravity as well as a lot of numerical kinematic and dynamic parameters.\n",
"\n",
- "Note that this next step might take 10 minutes or more to execute (but the result will be impressive and worth the wait!)"
+ "This takes a second or so. The result is impressive: each torque is an expression with thousands of terms. Note that `gravity` is the acceleration due to gravity, so for the usual orientation of the Puma it is `[0, 0, -g]`."
]
},
{
@@ -629,69 +652,17 @@
]
},
{
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%time z = simplify(tau[4])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%time z = simplify(tau[3])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%time z = simplify(tau[2])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "%time z = simplify(tau[1])"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
+ "cell_type": "markdown",
"metadata": {},
- "outputs": [],
"source": [
- "%time z = simplify(tau[0])"
+ "SymPy's `simplify` can reduce these expressions a lot, but it takes longer the more terms there are. It took about a second for the last joint, 15 seconds for $\\tau_3$, 50 seconds for $\\tau_4$ and several minutes for $\\tau_2$, which we will not wait for."
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
- },
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "The result `tau` is not a NumPy array as it would be for the numeric case"
+ "The result `tau` is a NumPy array, as it is for the numeric case, but with `dtype=object` since each element is a SymPy expression"
]
},
{
@@ -707,7 +678,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "but it is the symbolic (SymPy) equivalent and it has the expected shape"
+ "and it has the expected shape"
]
},
{
@@ -781,7 +752,7 @@
"metadata": {},
"outputs": [],
"source": [
- "m = tau[0].coeff(qdd[0]).args\n",
+ "m = tau_0.coeff(qdd[0]).args\n",
"m"
]
},
@@ -800,7 +771,7 @@
"metadata": {},
"outputs": [],
"source": [
- "m = tau[0].coeff(qdd[1]).args\n",
+ "m = tau_0.coeff(qdd[1]).args\n",
"m"
]
},
@@ -819,7 +790,7 @@
"metadata": {},
"outputs": [],
"source": [
- "c = tau[0].coeff(qd[0]).args\n",
+ "c = tau_0.coeff(qd[0]).args\n",
"c"
]
},
@@ -837,7 +808,8 @@
"metadata": {},
"outputs": [],
"source": [
- "C = tau[0].coeff(qd[0]).coeff(qd[0]).args"
+ "C = tau_0.coeff(qd[0], 2).args\n",
+ "C"
]
},
{
@@ -850,11 +822,14 @@
]
},
{
- "cell_type": "markdown",
+ "cell_type": "code",
"metadata": {},
"source": [
- "c = tau[0].coeff(qd[0]).coeff(qd[1]).args"
- ]
+ "c = tau_0.coeff(qd[0]).coeff(qd[1]).args\n",
+ "c"
+ ],
+ "execution_count": null,
+ "outputs": []
},
{
"cell_type": "markdown",
@@ -944,7 +919,7 @@
"metadata": {},
"outputs": [],
"source": [
- "signif_terms = [t for t in tau_0.args if abs(t.args[0]) > 1e-6]\n",
+ "signif_terms = [t for t in tau_0.args if abs(t.args[0]) > 1e-2]\n",
"signif_terms"
]
},
@@ -1024,11 +999,9 @@
"outputs": [],
"source": [
"subsdict = {}\n",
- "sqdict = {}\n",
"for j in range(puma.n):\n",
" subsdict[qd[j]] = 0\n",
- " subsdict[qdd[j]] = 0}\n",
- " sqdict[]"
+ " subsdict[qdd[j]] = 0"
]
},
{
@@ -1037,7 +1010,7 @@
"metadata": {},
"outputs": [],
"source": [
- "tau_g = tau.subs(subsdict)\n",
+ "tau_g = [t.subs(subsdict) for t in tau]\n",
"tau_g"
]
},
@@ -1086,13 +1059,6 @@
"source": [
"t1.expand().subs(sqdict)"
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {
@@ -1154,6 +1120,18 @@
"_Feature"
],
"window_display": false
+ },
+ "rtb_header": {
+ "title": "Symbolic computation",
+ "paragraphs": [
+ "Forward kinematics and inverse dynamics of a Puma 560 robot with symbolic joint variables, and generating code from the results. The dynamics section takes a few minutes to run in full."
+ ],
+ "modernised": "2026-10-19"
+ },
+ "rtb_bootstrap": {
+ "extras": [
+ "ik"
+ ]
}
},
"nbformat": 4,