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", + " \n", + " \n", + " \n", + "
Robotics Toolbox for Python
\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,