diff --git a/.github/workflows/notebook_to_html.yml b/.github/workflows/notebook_to_html.yml index 523f308..582e1b8 100644 --- a/.github/workflows/notebook_to_html.yml +++ b/.github/workflows/notebook_to_html.yml @@ -1,18 +1,17 @@ -# This is a basic workflow to help you get started with Actions - -name: Jupyter Book +name: MyST Book # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the "main" branch push: branches: [ "main" ] + pull_request: + branches: [ "main" ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: - # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" @@ -22,7 +21,7 @@ jobs: # To prevent github actions from eating up too many enterprise minutes timeout-minutes: 5 - + # https://github.com/actions/starter-workflows/blob/55eb18560f57898549b12afa6defe7cc79705d6a/pages/static.yml#L13 permissions: contents: read @@ -34,13 +33,13 @@ jobs: # Checks out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v4 - # Convert unstable/*.md → unstable/*.ipynb so the site provides "Download notebook" buttons + # Convert basic_lessons/*.md → basic_lessons/*.ipynb so the site provides "Download notebook" buttons # https://jupytext.readthedocs.io/ — supports md:myst format natively # Must run BEFORE build so myst/jupyter-book can pick up the generated notebooks - name: Generate downloadable notebooks run: | pip install jupytext - for f in unstable/lesson*_tutorial.md unstable/lesson*_exercise_answers.md; do + for f in basic_lessons/lesson*_tutorial.md basic_lessons/lesson*_exercise_answers.md; do [ -f "$f" ] || continue out="${f%.md}.ipynb" python -m jupytext --from md:myst --to notebook --output "$out" "$f" diff --git a/AGENTS.md b/AGENTS.md index 6bd7e01..d4657a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## Overview -**Open Executable Books in Robotics** is a collection of Jupyter notebooks teaching kinematic modelling and control of serial-link robotic manipulators. The project is licensed under [CC-BY-NC-SA 4.0](LICENSE) and hosted at . +**Open Executable Books in Robotics** is a collection of MyST text notebooks teaching kinematic modelling and control of serial-link robotic manipulators. The project is licensed under [CC-BY-NC-SA 4.0](LICENSE) and hosted at . --- @@ -10,108 +10,74 @@ | Path | Purpose | |------|---------| -| `basic_lessons/` | Canonical source: `.ipynb` notebooks (5 tutorials + 5 exercise answer keys) | -| `unstable/` | Work-in-progress text-only MyST notebooks (`.md` with `{code-cell}` directives) | +| `basic_lessons/` | Canonical source: MyST text notebooks (`.md` with `{code-cell}` directives) — 6 tutorials + 5 exercise answer keys | +| `basic_lessons/.gitignore` | Excludes generated `.ipynb` files (produced at build time) | | `other/` | Supplementary content (e.g. `dqrobotics.md`) | -| `convert_to_myst.py` | Script: converts `basic_lessons/*.ipynb` → `unstable/*.md` | -| `myst.yml` | MyST project config (root): LaTeX macros, TOC (including unstable section), site options | -| `unstable/myst.yml` | Standalone MyST project config for unstable-only builds (optional) | -| `build_html.sh` | Build script for `jupyter-book` (legacy pipeline) | +| `myst.yml` | MyST project config (root): LaTeX macros, TOC, site options | +| `build_html.sh` | Build script for `jupyter-book` | | `conf.py` | MyST parser extensions (`dollarmath`) | -| `_build/` | Build artifacts (excluded from git via `unstable/.gitignore`) | +| `_build/` | Build artifacts (excluded from git) | --- -## Modifying `.ipynb` Files +## Modifying MyST Text Notebooks -Jupyter notebooks are JSON files. Every cell's `source` field is a **list of strings**, where **each string must end with `\n`** (trailing newline). This is critical: +Lessons are [MyST text notebooks](https://mystmd.org/guide/notebooks-with-markdown) — plain Markdown files with `{code-cell}` directives. They are version-control friendly and human-readable. -### Correct format (renders properly in Jupyter): -```json -"source": [ - "# L1 A quick Python refresher\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "### Prerequisites\n", - "The user of this notebook is expected to have prior knowledge in\n" -] -``` - -### Broken format (renders as one concatenated line): -```json -"source": [ - "# L1 A quick Python refresher", - "", - "*License: CC-BY-NC-SA 4.0*", - "" -] -``` +### Structure -### When editing notebooks programmatically: -1. Load with `json.load()`, modify `cell['source']` entries. -2. **Every source line must end with `\n`** before writing back. -3. Save with `json.dump(nb, f, indent=1)` (single-space indent is standard). -4. Clear execution state on code cells to avoid stale output: - ```python - cell['outputs'] = [] - cell['execution_count'] = None - ``` - -### When editing notebooks manually: -- Use a notebook editor (Jupyter, VSCode, or nbconvert) rather than raw text edits. -- If editing raw JSON, always verify trailing `\n` on source lines. - -### Cell types: -| Type | Purpose | -|------|---------| -| `markdown` | Text, equations, images, headings | -| `code` | Python cells (numpy, math) | -| `raw` | Raw LaTeX macro definitions (`\providecommand`) | - -### LaTeX macros: -Custom macros (`\myvec`, `\mymatrix`, `\quat`, `\dual`) are defined in two places: -1. As **raw cells** in each notebook (for Jupyter/LaTeX rendering) -2. In **`myst.yml`** under `project.math` (for MyST rendering) +Each `.md` lesson file begins with YAML frontmatter declaring the kernel: +```yaml +--- +kernelspec: + name: python3 + display_name: 'Python 3' --- +``` -## Converting to MyST Text Notebooks +Code cells are delimited with `{code-cell}` directives: -Run the converter script to regenerate `unstable/*.md` from the canonical notebooks: +````markdown +````{code-cell} +import numpy as np +x = np.array([1, 2, 3]) +```` +```` -```bash -python3 convert_to_myst.py -``` +### Editing guidelines -This script: -- Copies images (`Lesson4.png`, `Lesson4.svg`) to `unstable/` -- Converts markdown cells as-is, code cells as ` ````{code-cell}```` directives -- Strips raw cells and LaTeX macro markdown cells (handled by `myst.yml`) -- Fixes `attachment:` image syntax → plain relative paths -- Handles both trailing-newline and no-trailing-newline source formats +- Edit `.md` files directly — they are plain text. +- Every lesson should follow the header format convention (see below). +- Keep code cells focused and self-contained. +- LaTeX equations use inline `$...$` or display `$$...$$` syntax with the `dollarmath` MyST extension enabled in `conf.py`. +- Custom macros (`\myvec`, `\mymatrix`, `\quat`, `\dual`) are defined in `myst.yml` under `project.math`. -### MyST Compatibility Notes +### `%%capture` magic -- **`%%capture` magic IS supported** in MyST text notebooks. MyST uses a Jupyter Server with an IPython kernel to execute code cells ([Execute Notebooks at Build Time](https://mystmd.org/guide/execute-notebooks)). The `%%capture` magic is a built-in IPython cell magic ([Built-in magic commands — IPython](https://ipython.readthedocs.io/en/stable/interactive/magics.html)) and works correctly during MyST execution. -- If output suppression is needed without `%%capture`, the MyST-native approach is to use cell tags like `remove-stdout` and `remove-stderr` on the `{code-cell}` directive. +**`%%capture` magic IS supported** in MyST text notebooks. MyST uses a Jupyter Server with an IPython kernel to execute code cells ([Execute Notebooks at Build Time](https://mystmd.org/guide/execute-notebooks)). The `%%capture` magic is a built-in IPython cell magic ([Built-in magic commands — IPython](https://ipython.readthedocs.io/en/stable/interactive/magics.html)) and works correctly during MyST execution. Use `%%capture` on `%pip install` cells to suppress output. ### Downloadable `.ipynb` from `.md` notebooks -The `unstable/` `.md` files are the canonical source. `.ipynb` files are generated at build time so visitors can download them: +The `basic_lessons/` `.md` files are the canonical source. `.ipynb` files are generated at build time so visitors can download them: -1. **CI pipeline** (`.github/workflows/notebook_to_html.yml`) runs `jupytext --from md:myst --to notebook` before the MyST build, converting each `unstable/*.md` → `unstable/*.ipynb`. -2. **`myst.yml` TOC** references the generated `.ipynb` for the unstable section — MyST renders these identically to the `.md` but provides native "Download notebook" buttons. -3. **`unstable/.gitignore`** excludes `*.ipynb` so only `.md` is tracked in git. +1. **CI pipeline** (`.github/workflows/notebook_to_html.yml`) runs `jupytext --from md:myst --to notebook` before the MyST build, converting each `basic_lessons/*.md` → `basic_lessons/*.ipynb`. +2. **`myst.yml` TOC** references the generated `.ipynb` for the lesson section — MyST renders these identically to the `.md` but provides native "Download notebook" buttons. +3. **`basic_lessons/.gitignore`** excludes `.ipynb` so only `.md` is tracked in git. To generate locally (e.g. for testing): ```bash pip install jupytext -for f in unstable/lesson*_tutorial.md unstable/lesson*_exercise_answers.md; do +for f in basic_lessons/lesson*_tutorial.md basic_lessons/lesson*_exercise_answers.md; do python -m jupytext --from md:myst --to notebook --output "${f%.md}.ipynb" "$f" done ``` +### Image references + +- Use relative paths: `![alt](Lesson4.png)` (relative to `basic_lessons/`) +- Images (`Lesson4.png`, `Lesson4.svg`) live alongside the lesson files in `basic_lessons/`. + --- ## Building & Testing @@ -132,41 +98,38 @@ pip install jupyter-book --pre ### Build Commands -**MyST build (root — includes all lessons + unstable):** +**jupyter-book build (CI pipeline):** ```bash -# Step 1: Generate .ipynb from .md (required for unstable section) +# Step 1: Generate .ipynb from .md (required for download buttons) pip install jupytext -for f in unstable/lesson*_tutorial.md unstable/lesson*_exercise_answers.md; do +for f in basic_lessons/lesson*_tutorial.md basic_lessons/lesson*_exercise_answers.md; do python -m jupytext --from md:myst --to notebook --output "${f%.md}.ipynb" "$f" done # Step 2: Build the site -myst build --html -``` -- `--execute` runs all code cells and caches results in `_build/execute/` -- `--html` produces HTML output in `_build/html/` -- Site format (JSON) goes to `_build/site/` - -**MyST build (unstable only — optional):** -```bash -cd unstable -myst build --execute --html -``` - -**Legacy jupyter-book build (root):** -```bash chmod +x build_html.sh ./build_html.sh ``` -- Requires `BASE_URL` env variable for correct link resolution +- Installs `jupyter-book --pre` (Jupyter Book 2.0 alpha) +- Sets `BASE_URL` for correct link resolution +- Runs `python -m jupyter book build --html --execute` - Outputs to `_build/html/` +**MyST build (local development):** +```bash +pip install mystmd jupyter-server ipykernel +myst build --html +``` +- `--execute` runs all code cells and caches results in `_build/execute/` +- `--html` produces HTML output in `_build/html/` + ### CI/CD -The GitHub Actions workflow (`.github/workflows/notebook_to_html.yml`) runs on pushes/PRs to `main`: -1. Runs `./build_html.sh` (jupyter-book pipeline) -2. Uploads `_build/html/` as Pages artifact -3. Deploys to GitHub Pages +The GitHub Actions workflow (`.github/workflows/notebook_to_html.yml`) runs on pushes to `main` and on pull requests: +1. Generates `.ipynb` from `.md` using jupytext +2. Runs `./build_html.sh` (jupyter-book pipeline) +3. Uploads `_build/html/` as Pages artifact +4. Deploys to GitHub Pages **Timeout:** 5 minutes. Keep cells fast to avoid CI failures. @@ -196,9 +159,8 @@ Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooks - `\dual{}` for dual numbers ### Image references: -- In `.ipynb`: `![alt](Lesson4.png)` (relative to `basic_lessons/`) -- In `.md` (unstable): same — images are copied to `unstable/` -- Avoid `attachment:` prefix in MyST notebooks +- Use relative paths: `![alt](Lesson4.png)` (relative to `basic_lessons/`) +- Images live alongside the lesson files in `basic_lessons/`. ### Language: - **UK English** spelling (e.g. *behaviour*, *modelling*, *summarised*) @@ -215,18 +177,19 @@ Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooks ### Files excluded from version control: - `venv/` — Python virtual environment -- `_build/` — Build artifacts (both root and `unstable/`) -- `unstable/.gitignore` already excludes `unstable/_build/` +- `_build/` — Build artifacts +- `basic_lessons/*.ipynb` — Generated at build time from `.md` files --- ## Adding a New Lesson -1. Create `basic_lessons/lesson_tutorial.ipynb` and `basic_lessons/lesson_exercise_answers.ipynb` -2. Follow the header format convention above -3. Add LaTeX macro raw cell (or markdown cell with `vscode` language metadata) -4. Update `myst.yml` → add new file to `project.toc` list -5. Run `python3 convert_to_myst.py` to regenerate `unstable/` -6. Update `myst.yml` → add new unstable `.md` file to the "Unstable" section in `project.toc` -7. Test: `myst build --html` from the repository root -8. Open PR with descriptive title and body \ No newline at end of file +1. Create `basic_lessons/lesson_tutorial.md` (and optionally `basic_lessons/lesson_exercise_answers.md`) +2. Add YAML frontmatter with kernelspec at the top of the file +3. Follow the header format convention above +4. Use `{code-cell}` directives for Python code blocks +5. Use `%%capture` on `%pip install` cells to suppress output +6. Update `myst.yml` — add new file(s) to `project.toc` list as `.ipynb` (generated at build time) +7. Update `basic_lessons/README.md` — add the new lesson to the contents table +8. Test: `./build_html.sh` from the repository root +9. Open PR with descriptive title and body diff --git a/basic_lessons/.gitignore b/basic_lessons/.gitignore new file mode 100644 index 0000000..0e3cc9d --- /dev/null +++ b/basic_lessons/.gitignore @@ -0,0 +1,2 @@ +# Generated .ipynb from .md (for downloadable notebooks) +*.ipynb \ No newline at end of file diff --git a/basic_lessons/README.md b/basic_lessons/README.md index 689c19a..5dc7aa4 100644 --- a/basic_lessons/README.md +++ b/basic_lessons/README.md @@ -1,11 +1,12 @@ # The Basics of Kinematic Modelling and Control of Serial-link Manipulators Using `numpy` -In this five-lesson tutorial, we start from the very basics of scalar and matricial operations in Python using `numpy`, +In this six-lesson tutorial, we start from the very basics of setting up your Python environment, +then cover scalar and matricial operations in Python using `numpy`, all the way until the basics of kinematic control. Until kinematic control, most is based on [@spong2020robot]. # Using this book -Each lesson is a [Jupyter notebook](https://jupyter-notebook.readthedocs.io/en/stable/notebook.html). Each lesson can be +Each lesson is a [MyST text notebook](https://mystmd.org/guide/notebooks-with-markdown). Each lesson can be opened and executed with popular IDEs, such as [VSCode](https://code.visualstudio.com) and [PyCharm](https://www.jetbrains.com/pycharm/). The reader is expected to follow it sequentially. @@ -14,8 +15,19 @@ The reader is expected to follow it sequentially. | Number | Title and Link | Content | |--------|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 1 | [](./lesson1_tutorial.ipynb) | Basic operations in Python and `numpy` | -| 2 | [](./lesson2_tutorial.ipynb) | Learn about elements and operations in $\mathbb{R}^n$, $SO(n)$, and $SE(n)$ with $n\in{\{2,3\}}$ related to positions, orientations, and poses, respectively. | -| 3 | [](./lesson3_tutorial.ipynb) | Learn about the composition of rigid body motion in series to obtain the forward kinematics model of a robotic manipulator, mapping their configuration space $\myvec{q}\in\mathbb{R}^n$ into their task space $\myvec{x}\in\mathbb{R}^m$. | -| 4 | [](./lesson4_tutorial.ipynb) | Learn about the first-order differential mapping $\dot{\myvec{x}}=\mymatrix{J}\dot{\myvec{q}}$ between joint space and task space velocities through the calculation of the Jacobian $\mymatrix{J}$. | -| 5 | [](./lesson5_tutorial.ipynb) | Employ the previous knowledge in all previous lessons to employ a Lyapunov-stable control law to move a manipulator in task space using configuration-space signals. | \ No newline at end of file +| 0 | [](./lesson0_tutorial.md) | Setting up the virtual environment and installing all required dependencies. | +| 1 | [](./lesson1_tutorial.md) | Basic operations in Python and `numpy` | +| 2 | [](./lesson2_tutorial.md) | Learn about elements and operations in $\mathbb{R}^n$, $SO(n)$, and $SE(n)$ with $n\in{\{2,3\}}$ related to positions, orientations, and poses, respectively. | +| 3 | [](./lesson3_tutorial.md) | Learn about the composition of rigid body motion in series to obtain the forward kinematics model of a robotic manipulator, mapping their configuration space $\myvec{q}\in\mathbb{R}^n$ into their task space $\myvec{x}\in\mathbb{R}^m$. | +| 4 | [](./lesson4_tutorial.md) | Learn about the first-order differential mapping $\dot{\myvec{x}}=\mymatrix{J}\dot{\myvec{q}}$ between joint space and task space velocities through the calculation of the Jacobian $\mymatrix{J}$. | +| 5 | [](./lesson5_tutorial.md) | Employ the previous knowledge in all previous lessons to employ a Lyapunov-stable control law to move a manipulator in task space using configuration-space signals. | + +### Exercise Answers + +| Lesson | Link | +|--------|------| +| L1 | [](./lesson1_exercise_answers.md) | +| L2 | [](./lesson2_exercise_answers.md) | +| L3 | [](./lesson3_exercise_answers.md) | +| L4 | [](./lesson4_exercise_answers.md) | +| L5 | [](./lesson5_exercise_answers.md) | \ No newline at end of file diff --git a/unstable/lesson0_tutorial.md b/basic_lessons/lesson0_tutorial.md similarity index 100% rename from unstable/lesson0_tutorial.md rename to basic_lessons/lesson0_tutorial.md diff --git a/basic_lessons/lesson1_exercise_answers.ipynb b/basic_lessons/lesson1_exercise_answers.ipynb deleted file mode 100644 index c4b024f..0000000 --- a/basic_lessons/lesson1_exercise_answers.ipynb +++ /dev/null @@ -1,157 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L1 Exercise Answers\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "### I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "### Latex Macros" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "vscode": { - "languageId": "latex" - } - }, - "source": [ - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "# Valid imports" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-28T15:43:12.703034Z", - "start_time": "2026-01-28T15:43:12.694818Z" - } - }, - "cell_type": "code", - "source": [ - "from math import pi, sin, cos\n", - "import numpy as np" - ], - "outputs": [], - "execution_count": 5 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercises\n", - "\n", - "## Exercise 1" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-28T15:43:12.729440Z", - "start_time": "2026-01-28T15:43:12.705744Z" - } - }, - "cell_type": "code", - "source": [ - "phi = pi/4.0\n", - "\n", - "e1 = sin(phi) + 4 * cos(phi / 5)\n", - "\n", - "# Printing the result is NOT a mandatory part of the answer.\n", - "print(f'e1 = {e1}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "e1 = 4.657860143567099\n" - ] - } - ], - "execution_count": 6 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "## Exercise 2" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-28T15:43:12.743890Z", - "start_time": "2026-01-28T15:43:12.731585Z" - } - }, - "cell_type": "code", - "source": [ - "A2 = np.array([[5, 2],\n", - " [3, 5]])\n", - "B2 = np.array([[5, 3],\n", - " [3, 8]])\n", - "\n", - "C2 = A2 + B2 + (A2 @ B2) - (B2 @ A2)\n", - "\n", - "# Printing the result is NOT a mandatory part of the answer.\n", - "print(f'C2 = {C2}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C2 = [[ 7 11]\n", - " [-3 16]]\n" - ] - } - ], - "execution_count": 7 - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson1_exercise_answers.md b/basic_lessons/lesson1_exercise_answers.md similarity index 95% rename from unstable/lesson1_exercise_answers.md rename to basic_lessons/lesson1_exercise_answers.md index c9860be..b641e49 100644 --- a/unstable/lesson1_exercise_answers.md +++ b/basic_lessons/lesson1_exercise_answers.md @@ -10,10 +10,9 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues -### Latex Macros # Valid imports diff --git a/basic_lessons/lesson1_tutorial.ipynb b/basic_lessons/lesson1_tutorial.ipynb deleted file mode 100644 index 26b1781..0000000 --- a/basic_lessons/lesson1_tutorial.ipynb +++ /dev/null @@ -1,1080 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L1 A quick Python refresher\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "### Prerequisites\n", - "The user of this notebook is expected to have prior knowledge in\n", - "- Basic Python [[Tutorial]](https://docs.python.org/3/tutorial/index.html)\n", - "- Numpy \n", - " - [[Tutorial: basics for beginners]](https://numpy.org/doc/stable/user/absolute_beginners.html)\n", - " - [[Tutorial: for MATLAB users]](https://numpy.org/doc/stable/user/numpy-for-matlab-users.html)\n", - "- Jupyter Notebook Basics [[Tutorial]](https://docs.jupyter.org/en/latest/)\n", - "\n", - "### I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "### Latex Macros\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "vscode": { - "languageId": "latex" - } - }, - "source": [ - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# A quick Python refresher\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Variable assignment \n", - "\n", - "Let\n", - "\n", - "$$a\\triangleq 10,b\\triangleq 5.$$\n", - "\n", - "We can replicate the above in Python with\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "a = 10\n", - "b = 5" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Output variables\n", - "Variables can be output using `print`. For example, for $a$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "10\n" - ] - } - ], - "source": [ - "print(a)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### Output text and variables using f-strings\n", - "To output $a$ and $b$ within a string, we can use `print` and f-strings as follows\n" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The value of a = 10 and b = 5.\n" - ] - } - ], - "source": [ - "print(f'The value of a = {a} and b = {b}.')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Basic Arithmetics\n", - "\n", - "Basic mathematical operations are trivially performed as follows.\n", - "\n", - "#### Sum\n", - "\n", - "$$c = a + b.$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=15\n" - ] - } - ], - "source": [ - "c = a + b\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Subtraction\n", - "$$c = a - b.$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=5\n" - ] - } - ], - "source": [ - "c = a - b\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Multiplication\n", - "$$c=ab$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=50\n" - ] - } - ], - "source": [ - "c = a * b\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Division\n", - "$$c = \\frac{a}{b}$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=2.0\n" - ] - } - ], - "source": [ - "c = a / b\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exponentiation\n", - "$$c = a^{b}$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=100000\n" - ] - } - ], - "source": [ - "c = a ** b\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Math functions\n", - "\n", - "For the following functions, we will need Python's built-in `math` module.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "from math import sqrt, exp, log, pi, sin, cos, tan" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Square root\n", - "\n", - "$$c = \\sqrt{a}$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "c = sqrt(a)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### n-th root\n", - "The nth root,\n", - "\n", - "$$c= \\sqrt[n]{a}, n \\in \\mathbb{N},$$\n", - "\n", - "does not seem to have a shorthand version in Python, but can be computed through simple properties such as\n", - "\n", - "$$c = \\sqrt[n]{a} = a^{\\frac{1}{n}} = e^{\\frac{ln(a)}{n}}.$$\n", - "\n", - "For example, suppose that\n", - "\n", - "$$n = 3.$$ \n", - "\n", - "Then,\n" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [], - "source": [ - "n=3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and we can calculate the n-th root like so\n" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=2.154434690031884\n" - ] - } - ], - "source": [ - "# n-th root using fractional exponent. Might be easier but most languages do not support a similar syntax\n", - "c = a ** (1/n)\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "or like so\n" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=2.154434690031884\n" - ] - } - ], - "source": [ - "c = exp(log(a)/n)\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and both should output the same value.\n", - "\n", - "### Trigonometric functions\n", - "\n", - "$$ \\phi = \\frac{\\pi}{4},$$\n", - "$$ s_{\\phi} = \\sin \\left( \\phi \\right),$$\n", - "$$ c_{\\phi} = \\cos \\left( \\phi \\right),$$\n", - "$$ t_{\\phi} = \\tan \\left( \\phi \\right).$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "phi=0.7853981633974483\n", - "s_phi=0.7071067811865475\n", - "c_phi=0.7071067811865476\n", - "t_phi=0.9999999999999999\n" - ] - } - ], - "source": [ - "phi = pi/4.0\n", - "s_phi = sin(phi)\n", - "c_phi = cos(phi)\n", - "t_phi = tan(phi)\n", - "\n", - "print(f'phi={phi}')\n", - "print(f's_phi={s_phi}')\n", - "print(f'c_phi={c_phi}')\n", - "print(f't_phi={t_phi}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Linear Algebra with Numpy\n", - "\n", - "### Installing the library\n", - "\n", - "Just in case `numpy` is not already installed, we can install it with the following command. Nothing will happen if the library is already installed.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture\n", - "%pip install numpy \n", - "%pip install numpy --break-system-packages" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Importing the library\n" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Instantiating vectors\n", - "A row vector can be instantiated from a list of lists. For instance, for \n", - "$$\\myvec{v} = \\left[\\begin{array}{ccc}\n", - " 1 & 2 \n", - " \\end{array}\\right],\n", - "$$ \n", - "we have\n" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "v=[[1 2]]\n" - ] - } - ], - "source": [ - "# Note the double [[]] to instanteate a vector with explicit row shape.\n", - "v = np.array([[1, 2]])\n", - "\n", - "print(f'v={v}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A column vector can be instantiated from a list of singleton *lists*. For instance, for \n", - "$$\\myvec{u} = \\left[\\begin{array}{ccc}\n", - " 1 \\\\\n", - " 2\n", - " \\end{array}\\right],$$ \n", - "we have\n" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "u=[[1]\n", - " [2]]\n" - ] - } - ], - "source": [ - "# Note that each row is defined by a single element within a [], while the whole vector is within an external []\n", - "u = np.array([[1],\n", - " [2]])\n", - "\n", - "print(f'u={u}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Dot product\n", - "\n", - "$$\\myvec{c} = <\\myvec{u},\\myvec{u}>$$ \n" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=5\n" - ] - } - ], - "source": [ - "c = np.vdot(u,u)\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Cross product\n", - "\n", - "Cross product is defined for vectors in $\\mathbb{R}^3$.\n", - "\n", - "For example, for \n", - "\n", - "$$\\myvec{u}_3 = \\left[\\begin{array}{ccc}\n", - " 1 \\\\\n", - " 2 \\\\\n", - " 3\n", - " \\end{array}\\right],$$ \n", - "\n", - "and\n", - "\n", - "$$\\myvec{v}_3 = \\left[\\begin{array}{ccc}\n", - " 4 \\\\\n", - " 5 \\\\\n", - " 6\n", - " \\end{array}\\right],$$ \n", - "\n", - "we can obtain the cross product\n", - "\n", - "$$\\myvec{c} = \\myvec{u}_3 \\times \\myvec{v}_3$$ \n" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=[[-3 6 -3]]\n" - ] - } - ], - "source": [ - "u3 = np.array([[1, 2, 3]])\n", - "v3 = np.array([[4, 5, 6]])\n", - "\n", - "c = np.cross(u3,v3)\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Euclidean norm\n", - "\n", - "$$\\myvec{c} = ||\\myvec{u}||$$ \n", - "\n", - "
\n", - "Note that the function is np.linalg.norm, as the norm calculation is within the module linalg.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=2.23606797749979\n" - ] - } - ], - "source": [ - "c = np.linalg.norm(u)\n", - "\n", - "print(f'c={c}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Instantiating matrices\n", - "For instance, suppose that we want to instantiate two real square matrices\n", - "$$\\mymatrix{A} = \\left[\\begin{array}{ccc}\n", - " 1 & 2 \\\\\n", - " 3 & 4 \n", - " \\end{array}\\right],\n", - "\\mymatrix{B} = \\left[\\begin{array}{ccc}\n", - " 5 & 6 \\\\\n", - " 7 & 8 \n", - " \\end{array}\\right] \n", - "$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "A=[[1 2]\n", - " [3 4]],\n", - "\n", - "B=[[5 6]\n", - " [7 8]]\n" - ] - } - ], - "source": [ - "A = np.array([[1, 2], \n", - " [3, 4]])\n", - "B = np.array([[5, 6], \n", - " [7, 8]])\n", - "\n", - "print(f'A={A},\\n\\nB={B}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Transpose\n", - "\n", - "$$\\mymatrix{C} = \\mymatrix{A}^T$$ \n" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C=[[1 3]\n", - " [2 4]]\n" - ] - } - ], - "source": [ - "C = A.T\n", - "\n", - "print(f'C={C}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Sum\n", - "\n", - "$$ \\mymatrix{C} = \\mymatrix{A} + \\mymatrix{B} $$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C=[[ 6 8]\n", - " [10 12]]\n" - ] - } - ], - "source": [ - "C = A + B\n", - "\n", - "print(f'C={C}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Subtraction\n", - "\n", - "$$ \\mymatrix{C} = \\mymatrix{A} - \\mymatrix{B} $$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C=[[-4 -4]\n", - " [-4 -4]]\n" - ] - } - ], - "source": [ - "C = A - B\n", - "\n", - "print(f'C={C}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Matrix multiplication\n", - "\n", - "For instance,\n", - "$$C = AB$$\n", - "is implemented with\n", - "\n", - "
\n", - "The matrix multiplication operator, @, is very unusual. Pay close attention.\n", - "Mistaking this can be a major source of bugs and confusion.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C=[[19 22]\n", - " [43 50]]\n" - ] - } - ], - "source": [ - "C = A @ B # Alternatively C = np.matmul(A,B), but that is too verbose\n", - "\n", - "print(f'C={C}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "which will naturally work for the vectors we defined. For example\n", - "$$\\myvec{c} = \\myvec{u}\\myvec{v} = \\left[\\begin{array}{ccc}\n", - " 1 & 2 \\\\\n", - " 2 & 4 \n", - " \\end{array}\\right],\n", - "$$\n", - "$$ \\myvec{d} = \\myvec{v}\\myvec{u} = 5.\n", - "$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=[[1 2]\n", - " [2 4]],\n", - "\n", - "d=[[5]]\n" - ] - } - ], - "source": [ - "c = u @ v \n", - "d = v @ u \n", - "\n", - "print(f'c={c},\\n\\nd={d}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and, of course, matrices and vectors\n", - "\n", - "$$ \\myvec{c} = \\myvec{A}\\myvec{u} $$\n", - "\n", - "
\n", - "We only use the \".\" sign to denote matrix multiplication when otherwise it would be difficult to read the equation.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c=[[ 5]\n", - " [11]],\n", - "\n" - ] - } - ], - "source": [ - "c = A @ u \n", - "\n", - "print(f'c={c},\\n')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Diagonal matrices\n", - "\n", - "Diagonal matrices get increasingly sparse with size, so it is important to have shorthand commands for creating them. For instance, suppose that we have the following diagonal matrix\n", - "\n", - "$$\\mymatrix{D} = \\left[\\begin{array}{ccc}\n", - " 1 & 0 & 0 \\\\\n", - " 0 & 2 & 0 \\\\\n", - " 0 & 0 & 3 \n", - " \\end{array}\\right] ,\n", - "$$\n", - "\n", - "this can be instantiated in `numpy` with\n" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "D=[[1 0 0]\n", - " [0 2 0]\n", - " [0 0 3]].\n" - ] - } - ], - "source": [ - "D = np.diag([1, 2, 3])\n", - "\n", - "print(f'D={D}.')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Identity matrix\n", - "\n", - "Among frequently used diagonal matrices, the identity matrix appears frequently. For instance, \n", - "\n", - "$$ \\mymatrix{I}_3 = \\left[\\begin{array}{ccc}\n", - " 1 & 0 & 0 \\\\\n", - " 0 & 1 & 0 \\\\\n", - " 0 & 0 & 1 \n", - " \\end{array}\\right],\n", - "$$ \n", - "\n", - "can be instantiated in `numpy` with\n" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I_3=[[1. 0. 0.]\n", - " [0. 1. 0.]\n", - " [0. 0. 1.]].\n" - ] - } - ], - "source": [ - "I_3 = np.eye(3)\n", - "\n", - "print(f'I_3={I_3}.')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Zero matrix\n", - "\n", - "Another frequently used matrix is the zero matrix. For instance,\n", - "\n", - "$$ \\mymatrix{O}_3 = \\left[\\begin{array}{ccc}\n", - " 0 & 0 & 0 \\\\\n", - " 0 & 0 & 0 \\\\\n", - " 0 & 0 & 0 \n", - " \\end{array}\\right],\n", - "$$ \n", - "\n", - "
\n", - "The np.zeros function takes a tuple to generate a properly sized matrix. Do not confuse it with np.eye that accepts a scalar.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "O_3=[[0. 0. 0.]\n", - " [0. 0. 0.]\n", - " [0. 0. 0.]].\n" - ] - } - ], - "source": [ - "O_3 = np.zeros((3,3))\n", - "\n", - "print(f'O_3={O_3}.')" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercises\n", - "\n", - "## Exercise 1\n", - "\n", - "For $\\phi = \\pi/4$, let\n", - "\n", - "$$ e_1 = \\sin(\\phi) + 4\\cos(\\frac{\\phi}{5}).$$\n", - "\n", - "Using the `math` module which is already imported, calculate the value of $e_1$ and store it in the variable `e1` shown in the cell below.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "e1 = None # Replace None with your solution to this exercise." - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Exercise 2\n", - "\n", - "Given\n", - "\n", - "$$\\mymatrix{A}_2 = \\left[\\begin{array}{ccc}\n", - " 5 & 2 \\\\\n", - " 3 & 5\n", - " \\end{array}\\right]$$\n", - "and\n", - "$$\n", - "\\mymatrix{B}_2 = \\left[\\begin{array}{ccc}\n", - " 5 & 3 \\\\\n", - " 3 & 8\n", - " \\end{array}\\right].$$\n", - "\n", - "Let\n", - "$$\\mymatrix{C}_2 = \\mymatrix{A}_2 + \\mymatrix{B}_2 + \\mymatrix{A}_2\\mymatrix{B}_2 - \\mymatrix{B}_2\\mymatrix{A}_2.$$\n", - "\n", - "Using the numpy module which is already imported, calculate the value of $\\mymatrix{C}_2$ and store it in the variable `C2` shown in the cell below.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "C2 = None # replace None with your solution to this exercise." - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson1_tutorial.md b/basic_lessons/lesson1_tutorial.md similarity index 99% rename from unstable/lesson1_tutorial.md rename to basic_lessons/lesson1_tutorial.md index e1fe3e7..48eb152 100644 --- a/unstable/lesson1_tutorial.md +++ b/basic_lessons/lesson1_tutorial.md @@ -10,7 +10,7 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### Prerequisites +## Prerequisites The user of this notebook is expected to have prior knowledge in - Basic Python [[Tutorial]](https://docs.python.org/3/tutorial/index.html) - Numpy @@ -18,13 +18,9 @@ The user of this notebook is expected to have prior knowledge in - [[Tutorial: for MATLAB users]](https://numpy.org/doc/stable/user/numpy-for-matlab-users.html) - Jupyter Notebook Basics [[Tutorial]](https://docs.jupyter.org/en/latest/) -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues -### Latex Macros - -# A quick Python refresher - ## Variable assignment Let @@ -183,6 +179,7 @@ print(f't_phi={t_phi}') Just in case `numpy` is not already installed, we can install it with the following command. Nothing will happen if the library is already installed. ````{code-cell} +%%capture %pip install numpy ```` diff --git a/basic_lessons/lesson2_exercise_answers.ipynb b/basic_lessons/lesson2_exercise_answers.ipynb deleted file mode 100644 index 14fc149..0000000 --- a/basic_lessons/lesson2_exercise_answers.ipynb +++ /dev/null @@ -1,334 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L2 Exercise Answers\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "### I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "### Latex Macros" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "vscode": { - "languageId": "latex" - } - }, - "source": [ - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "# Valid imports" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-29T22:31:23.725947Z", - "start_time": "2026-01-29T22:31:23.709145Z" - } - }, - "cell_type": "code", - "source": [ - "from math import pi, sin, cos\n", - "import numpy as np" - ], - "outputs": [], - "execution_count": 13 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercises\n", - "\n", - "## Exercise a" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-29T22:31:23.749857Z", - "start_time": "2026-01-29T22:31:23.733624Z" - } - }, - "cell_type": "code", - "source": [ - "θ_a = pi/4.0\n", - "\n", - "R_a = np.array([[cos(θ_a),-sin(θ_a)],\n", - " [sin(θ_a), cos(θ_a)]])\n", - "\n", - "# Printing the result is NOT a mandatory part of the answer.\n", - "print(f'R_a = {R_a}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "R_a = [[ 0.70710678 -0.70710678]\n", - " [ 0.70710678 0.70710678]]\n" - ] - } - ], - "execution_count": 14 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "## Exercise b" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-29T22:31:23.765717Z", - "start_time": "2026-01-29T22:31:23.750326Z" - } - }, - "cell_type": "code", - "source": [ - "θ_b1 = pi/12.0\n", - "θ_b2 = -pi/2.0\n", - "\n", - "R_b1 = np.array([[cos(θ_b1),-sin(θ_b1)],\n", - " [sin(θ_b1), cos(θ_b1)]])\n", - "\n", - "R_b2 = np.array([[cos(θ_b2),-sin(θ_b2)],\n", - " [sin(θ_b2), cos(θ_b2)]])\n", - "\n", - "R_b = R_b1 @ R_b2\n", - "\n", - "print(f'R_b = {R_b}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "R_b = [[ 0.25881905 0.96592583]\n", - " [-0.96592583 0.25881905]]\n" - ] - } - ], - "execution_count": 15 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "## Exercise c" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-29T22:31:23.779702Z", - "start_time": "2026-01-29T22:31:23.766189Z" - } - }, - "cell_type": "code", - "source": [ - "θ_c = pi/3.0\n", - "x_c = 2.0\n", - "y_c = 5.0\n", - "\n", - "H_c1 = np.array([[cos(θ_c),-sin(θ_c), 0],\n", - " [sin(θ_c), cos(θ_c), 0],\n", - " [0, 0, 1]])\n", - "\n", - "H_c2 = np.array([[1,0,x_c],\n", - " [0,1,y_c],\n", - " [0,0,1]])\n", - "\n", - "H_c = H_c1 @ H_c2\n", - "\n", - "print(f'H_c = {H_c}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H_c = [[ 0.5 -0.8660254 -3.33012702]\n", - " [ 0.8660254 0.5 4.23205081]\n", - " [ 0. 0. 1. ]]\n" - ] - } - ], - "execution_count": 16 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "## Exercise d" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-01-29T22:31:23.798367Z", - "start_time": "2026-01-29T22:31:23.780110Z" - } - }, - "cell_type": "code", - "source": [ - "θ_d = pi/3.0\n", - "x_d = 2.0\n", - "y_d = 5.0\n", - "\n", - "\n", - "H_d1 = np.array([[1,0,x_d],\n", - " [0,1,y_d],\n", - " [0,0,1]])\n", - "\n", - "H_d2 = np.array([[cos(θ_d),-sin(θ_d), 0],\n", - " [sin(θ_d), cos(θ_d), 0],\n", - " [0, 0, 1]])\n", - "\n", - "\n", - "H_d = H_d1 @ H_d2\n", - "\n", - "print(f'H_d = {H_d}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H_d = [[ 0.5 -0.8660254 2. ]\n", - " [ 0.8660254 0.5 5. ]\n", - " [ 0. 0. 1. ]]\n" - ] - } - ], - "execution_count": 17 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "`H_c` is *not* the same as `H_d`. This indicates that the order of operations matters. That is, sequential pose transformations are not commutative." - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Extra challenge 1\n", - "\n", - "$$R = \\left[\\begin{array}{cc}\n", - " \\cos\\left(\\sin(t) + 2\\cos(t)\\right) & -\\sin\\left(\\sin(t) + 2\\cos(t)\\right) \\\\\n", - " \\sin\\left(\\sin(t) + 2\\cos(t)\\right) & \\cos\\left(\\sin(t) + 2\\cos(t)\\right)\n", - " \\end{array}\\right].$$" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "t = 10.0\n", - "\n", - "θ = sin(t) + 2 * cos(t)\n", - "\n", - "R = np.array([[cos(θ),-sin(θ)],\n", - " [sin(θ), cos(θ)]])" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Extra challenge 2\n", - "\n", - "See DH parameters in lesson 3." - ] - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "θ = pi/10.0\n", - "d = 0.3\n", - "a = 0.5\n", - "α = -pi/2.0\n", - "\n", - "H1 = np.array(\n", - " [[cos(θ), -sin(θ), 0, 0],\n", - " [ sin(θ), cos(θ), 0, 0],\n", - " [ 0, 0, 1, 0],\n", - " [ 0, 0, 0, 1]]\n", - ")\n", - "\n", - "H2 = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, 1, 0, 0],\n", - " [0, 0, 1, d],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H3 = np.array(\n", - " [[1, 0, 0, a],\n", - " [0, 1, 0, 0],\n", - " [0, 0, 1, 0],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H4 = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, cos(α), -sin(α), 0],\n", - " [0, sin(α), cos(α), 0],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H = H1 @ H2 @ H3 @ H4" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson2_exercise_answers.md b/basic_lessons/lesson2_exercise_answers.md similarity index 98% rename from unstable/lesson2_exercise_answers.md rename to basic_lessons/lesson2_exercise_answers.md index a49ae1b..7c0def1 100644 --- a/unstable/lesson2_exercise_answers.md +++ b/basic_lessons/lesson2_exercise_answers.md @@ -10,10 +10,9 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues -### Latex Macros # Valid imports diff --git a/basic_lessons/lesson2_tutorial.ipynb b/basic_lessons/lesson2_tutorial.ipynb deleted file mode 100644 index 184096f..0000000 --- a/basic_lessons/lesson2_tutorial.ipynb +++ /dev/null @@ -1,912 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L2 Rigid Body Motion\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "## Prerequisites for the learner\n", - "The user of this notebook is expected to have prior knowledge in\n", - "- All the content and prerequisites of lesson 1.\n", - "\n", - "## I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "## Latex Macros\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "vscode": { - "languageId": "latex" - } - }, - "source": [ - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Installing prerequisites\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.847778Z", - "start_time": "2026-02-08T11:50:13.443851Z" - } - }, - "source": [ - "%%capture\n", - "%pip install numpy\n", - "%pip install numpy --break-system-packages" - ], - "outputs": [], - "execution_count": 11 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Imports\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.854506Z", - "start_time": "2026-02-08T11:50:16.848785Z" - } - }, - "source": [ - "import numpy as np\n", - "from math import pi, sin, cos" - ], - "outputs": [], - "execution_count": 12 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Rigid bodies\n", - "If the relative transformation between all points of a given object remain the same regardless of motion, it is a rigid body.\n", - "\n", - "In other words, the object has no flexibility and the motion of the entire body can be prescribed by its *position* and *orientation* with respect to a given *reference frame*.\n", - "\n", - "This tends to be the initial topic of robotics textbooks. That is because we can use this to derive the equations of motion for many classes of robots and objects from first principles.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Reference frames\n", - "\n", - "Positions/translations and orientations/rotations of objects are always defined with respect to a reference frame. Reference frames can be attached to rigid bodies or at fixed locations in space. Reference frames are usually defined in such way to make the mathematical derivations simpler.\n", - "\n", - "In this tutorial, the World (or neutral) reference frame has the following notation\n", - "\n", - "$$\\mathcal{F}.$$\n", - "\n", - "**Unless otherwise stated, a given position/orientation/pose is given with respect to the World frame**. When other frames are needed we usually rely on notations such as $$\\mathcal{F}',\\mathcal{F}''$$ when frames are sequential or $$\\mathcal{F}_a,\\mathcal{F}_b$$ when relationships are more complex.\n", - "\n", - "# 2D Position/translation\n", - "\n", - "Positions/translations in 2D can be uniquely defined as any $$\\myvec{p} \\in \\mathbb{R}^2.$$ Hence, if we would like to define \n", - "\n", - "$$\\myvec{p} = \\left[\\begin{array}{ccc}\n", - " x \\\\\n", - " y\n", - " \\end{array}\\right] =\\left[\\begin{array}{ccc}\n", - " 1 \\\\\n", - " 2\n", - " \\end{array}\\right],$$\n", - "\n", - "we can do so programmatically with the following piece of code.\n", - "\n", - "
\n", - "It is common for column and row vectors to not be distinguishable in Python with numpy. That is in general convenient but can cause problems when the dimension is important, so always pay close attention to what each function expects as input.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.862498Z", - "start_time": "2026-02-08T11:50:16.855005Z" - } - }, - "source": [ - "p = np.array([1.0, 2.0])\n", - "\n", - "print(f\"p={p}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "p=[1. 2.]\n" - ] - } - ], - "execution_count": 13 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Composition of translations\n", - "\n", - "Sequential translations, such as \n", - "\n", - "$$\\mathbb{R}^2 \\ni \\myvec{p}_i = \\left[\\begin{array}{ccc}\n", - " x_i \\\\\n", - " y_i\n", - " \\end{array}\\right],$$\n", - "\n", - "with $$i \\in \\mathbb{N}$$ can be composed with sequential additions\n", - "\n", - "$$\\myvec{p} = \\myvec{p}_{0} + \\myvec{p}_{1} + \\myvec{p}_{2} + \\myvec{p}_{3}.$$\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.876957Z", - "start_time": "2026-02-08T11:50:16.870498Z" - } - }, - "source": [ - "p0 = np.array([1.0, 2.0])\n", - "p1 = np.array([2.0, 3.0])\n", - "p2 = np.array([3.0, 4.0])\n", - "p3 = np.array([4.0, 5.0])\n", - "\n", - "p = p0 + p1 + p2 + p3\n", - "\n", - "print(f\"p={p}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "p=[10. 14.]\n" - ] - } - ], - "execution_count": 14 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Inverse translation\n", - "\n", - "The inverse translation can be obtained by subtractions and the element of no translation is the zero vector, that is, if we unwind all translations we're back to the origin of the reference frame\n", - "\n", - "$$\\myvec{p}' = \\myvec{p} - \\myvec{p}_{0} - \\myvec{p}_{1} - \\myvec{p}_{2} - \\myvec{p}_{3} = \\left[\\begin{array}{ccc}\n", - " 0 \\\\\n", - " 0\n", - " \\end{array}\\right].$$\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.892801Z", - "start_time": "2026-02-08T11:50:16.878736Z" - } - }, - "source": [ - "p0 = np.array([1.0, 2.0])\n", - "p1 = np.array([2.0, 3.0])\n", - "p2 = np.array([3.0, 4.0])\n", - "p3 = np.array([4.0, 5.0])\n", - "p = p0 + p1 + p2 + p3\n", - "\n", - "p_ = p - p0 - p1 - p2 - p3\n", - "\n", - "print(f\"p_={p_}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "p_=[0. 0.]\n" - ] - } - ], - "execution_count": 15 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2D orientation/rotation \n", - "\n", - "Orientations/rotations in 2D can be defined in many different ways. In this tutorial, we will address the special orthogonal group for two dimensions, i.e., SO(2). These rotations are defined, in this representation, as a matrix\n", - "\n", - "$$\\mymatrix{R} \\in \\mathbb{R}^{2 \\times 2}.$$\n", - "\n", - "The identity rotation means no rotation. For any frame $\\mathcal{F}_a$,\n", - "\n", - "$$\\mymatrix{R}^{a}_{a} = \\mymatrix{I}_2.$$\n", - "\n", - "An element of SO(2) is simply a matrix with the correct properties, therefore we can define one directly in `numpy`. For\n", - "\n", - "$$\\mymatrix{R}(\\theta) = \\left[\\begin{array}{ccc}\n", - " \\cos{\\theta} & -\\sin{\\theta} \\\\\n", - " \\sin{\\theta} & \\cos{\\theta} \n", - " \\end{array}\\right],$$\n", - "\n", - "when $\\theta = \\frac{\\pi}{2}$, we have the following equivalent piece of code.\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.908889Z", - "start_time": "2026-02-08T11:50:16.899514Z" - } - }, - "source": [ - "\u03b8 = pi/2\n", - "\n", - "R = np.array([[cos(\u03b8),-sin(\u03b8)],\n", - " [sin(\u03b8), cos(\u03b8)]])\n", - "\n", - "print(f\"R={R}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "R=[[ 6.123234e-17 -1.000000e+00]\n", - " [ 1.000000e+00 6.123234e-17]]\n" - ] - } - ], - "execution_count": 16 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2D poses (combined translation/orientation)\n", - "\n", - "2D poses can be represented using elements of SE(2). A translation followed by a rotation can be combined into a single $\\mymatrix{H}\\in\\mathbb{R}^{3 \\times 3}$ with the following structure\n", - "\n", - "$$\\mymatrix{H}(x,y,\\theta) =\n", - "\\left[\\begin{array}{ccc}\n", - " 1 & 0 & x \\\\\n", - " 0 & 1 & y \\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right]\n", - "\\left[\\begin{array}{ccc}\n", - " \\cos{\\theta} & -\\sin{\\theta} & 0 \\\\\n", - " \\sin{\\theta} & \\cos{\\theta} & 0 \\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right] =\n", - "\\left[\\begin{array}{ccc}\n", - " \\cos{\\theta} & -\\sin{\\theta} & x \\\\\n", - " \\sin{\\theta} & \\cos{\\theta} & y \\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "
\n", - "The translation and rotation order is extremely important. Check the exercises at the end of this lesson.\n", - "
\n", - "\n", - "For $\\theta = \\frac{\\pi}{2}$, $x = 0.1$, and $y = 0.2$, we have the following equivalent piece of code.\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.920073Z", - "start_time": "2026-02-08T11:50:16.914521Z" - } - }, - "source": [ - "\u03b8 = pi/2\n", - "x = 0.1\n", - "y = 0.2\n", - "\n", - "H = np.array([[cos(\u03b8),-sin(\u03b8), x],\n", - " [sin(\u03b8), cos(\u03b8), y],\n", - " [0, 0, 1]])\n", - "\n", - "\n", - "print(f\"H = {H}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H = [[ 6.123234e-17 -1.000000e+00 1.000000e-01]\n", - " [ 1.000000e+00 6.123234e-17 2.000000e-01]\n", - " [ 0.000000e+00 0.000000e+00 1.000000e+00]]\n" - ] - } - ], - "execution_count": 17 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3D Position/translation\n", - "\n", - "The 3D position/translations are a trivial extention of the 2D ones with one extra dimension.\n", - "\n", - "$$\\mathbb{R}^3 \\ni \\myvec{p}_i = \\left[\\begin{array}{ccc}\n", - " x_i \\\\\n", - " y_i \\\\\n", - " z_i\n", - " \\end{array}\\right].$$\n", - "\n", - "There is nothing surprising in terms of properties, so we will move on to SO(3).\n", - "\n", - "# 3D orientation/rotation \n", - "\n", - "For rotational matrices in 3D, we usually compose basic rotations. For rotations about the basis vectors, we have\n", - "\n", - "$$\\mymatrix{R}(z,\\theta) = \\left[\\begin{array}{ccc}\n", - " \\cos{\\theta} & -\\sin{\\theta} & 0 \\\\\n", - " \\sin{\\theta} & \\cos{\\theta} & 0 \\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right],$$\n", - "\n", - "$$\\mymatrix{R}(y,\\theta) = \\left[\\begin{array}{ccc}\n", - " \\cos{\\theta} & 0 & \\sin{\\theta} \\\\\n", - " 0 & 1 & 0 \\\\\n", - " -\\sin{\\theta} & 0 & \\cos{\\theta}\n", - "\\end{array}\\right],$$\n", - "\n", - "$$\\mymatrix{R}(x,\\theta) = \\left[\\begin{array}{ccc}\n", - " 1 & 0 & 0 \\\\\n", - " 0 & \\cos{\\theta} & -\\sin{\\theta} \\\\\n", - " 0 & \\sin{\\theta} & \\cos{\\theta}\n", - "\\end{array}\\right].$$\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.937129Z", - "start_time": "2026-02-08T11:50:16.924423Z" - } - }, - "source": [ - "Rz = np.array([[cos(\u03b8),-sin(\u03b8), 0],\n", - " [sin(\u03b8), cos(\u03b8), 0],\n", - " [0, 0, 1]])\n", - "\n", - "Ry = np.array([[ cos(\u03b8), 0, sin(\u03b8)],\n", - " [ 0, 1, 0],\n", - " [-sin(\u03b8), 0, cos(\u03b8)]])\n", - "\n", - "Rx = np.array([[1, 0, 0],\n", - " [0, cos(\u03b8), -sin(\u03b8)],\n", - " [0, sin(\u03b8), cos(\u03b8)]])\n", - "\n", - "# A rotation about z\n", - "print(f\"Rz={Rz}\")\n", - "\n", - "# A rotation about y\n", - "print(f\"Ry={Ry}\")\n", - "\n", - "# A rotation about x\n", - "print(f\"Rx={Rx}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Rz=[[ 6.123234e-17 -1.000000e+00 0.000000e+00]\n", - " [ 1.000000e+00 6.123234e-17 0.000000e+00]\n", - " [ 0.000000e+00 0.000000e+00 1.000000e+00]]\n", - "Ry=[[ 6.123234e-17 0.000000e+00 1.000000e+00]\n", - " [ 0.000000e+00 1.000000e+00 0.000000e+00]\n", - " [-1.000000e+00 0.000000e+00 6.123234e-17]]\n", - "Rx=[[ 1.000000e+00 0.000000e+00 0.000000e+00]\n", - " [ 0.000000e+00 6.123234e-17 -1.000000e+00]\n", - " [ 0.000000e+00 1.000000e+00 6.123234e-17]]\n" - ] - } - ], - "execution_count": 18 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Compositions of rotations in SO(3)\n", - "\n", - "Compositions in SO(3) follow the same rules as SO(2), where sequential rotations are represented by right multiplications. For instance,\n", - "\n", - "$$\\mymatrix{R}^0_c = \\mymatrix{R}^0_a\\mymatrix{R}^a_b\\mymatrix{R}^b_c.$$\n", - "\n", - "This can be represented by the following equivalent piece of code using sample angles.\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.959108Z", - "start_time": "2026-02-08T11:50:16.938508Z" - } - }, - "source": [ - "\u03b80_a = pi/4\n", - "R0_a = np.array([[cos(\u03b80_a),-sin(\u03b80_a), 0],\n", - " [sin(\u03b80_a), cos(\u03b80_a), 0],\n", - " [0, 0, 1]])\n", - "\n", - "\u03b8a_b = -pi/2\n", - "Ra_b = np.array([[ cos(\u03b8a_b), 0, sin(\u03b8a_b)],\n", - " [ 0, 1, 0],\n", - " [-sin(\u03b8a_b), 0, cos(\u03b8a_b)]])\n", - "\n", - "\u03b8b_c = pi/8\n", - "Rb_c = np.array([[1, 0, 0],\n", - " [0, cos(\u03b8b_c), -sin(\u03b8b_c)],\n", - " [0, sin(\u03b8b_c), cos(\u03b8b_c)]])\n", - "\n", - "R0_c = R0_a @ Ra_b @ Rb_c\n", - "print(f\"R0_c={R0_c}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "R0_c=[[ 4.32978028e-17 -9.23879533e-01 -3.82683432e-01]\n", - " [ 4.32978028e-17 3.82683432e-01 -9.23879533e-01]\n", - " [ 1.00000000e+00 2.34326020e-17 5.65713056e-17]]\n" - ] - } - ], - "execution_count": 19 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Inverse rotations in SO(3)\n", - "\n", - "Inverse operations in SO(3) are analogous to the inversions in SO(2), which are simply matrix transpositions.\n", - "\n", - "For example, we can recover $\\mymatrix{R}^0_a$ from $\\mymatrix{R}^0_c$ using inverse relative rotations as follows.\n", - "\n", - "$$\\begin{align}\n", - "\\mymatrix{R}^0_a &= \\mymatrix{R}^0_c \\mymatrix{R}^c_b \\mymatrix{R}^b_a \\\\\n", - "\\mymatrix{R}^0_a &= \\mymatrix{R}^0_c (\\mymatrix{R}^b_c)^T (\\mymatrix{R}^a_b)^T \\\\\n", - "\\end{align}$$\n", - "\n", - "In the example code below, we store this alternative calculation in `R0_a_` to compare it with `R0_a`.\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.979017Z", - "start_time": "2026-02-08T11:50:16.959692Z" - } - }, - "source": [ - "R0_a_ = R0_c @ Rb_c.T @ Ra_b.T\n", - "\n", - "if np.allclose(R0_a, R0_a_):\n", - " print('The results are pretty much the same!')\n", - "else:\n", - " print('The results are too different.')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The results are pretty much the same!\n" - ] - } - ], - "execution_count": 20 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3D poses\n", - "\n", - "In 3D, a translation followed by a rotation in the _current_ frame is represented with elements in SE(3). These elements are matrices $\\mymatrix{H}\\in\\mathbb{R}^{4 \\times 4}$ with the following structure\n", - "\n", - "$$\\mymatrix{H}(\\myvec{t},\\mymatrix{R}) =\n", - "\\left[\\begin{array}{ccc}\n", - " \\mymatrix{I} & \\myvec{t} \\\\\n", - " \\myvec{0} & 1\n", - " \\end{array}\\right]\n", - "\\left[\\begin{array}{ccc}\n", - " \\mymatrix{R} & \\myvec{0} \\\\\n", - " \\myvec{0} & 1\n", - " \\end{array}\\right] =\n", - "\\left[\\begin{array}{ccc}\n", - " \\mymatrix{R} & \\myvec{t} \\\\\n", - " \\myvec{0} & 1 \n", - " \\end{array}\\right].$$\n", - "\n", - "
\n", - "The translation and rotation order is extremely important.\n", - "
\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Sequential pose transformations\n", - "\n", - "We can also perform pose transformations using sequential right multiplications when they are with respect to the _current_ frame. Note also that we can verify the lack of commutativity on these transformations.\n", - "\n", - "For example, consider a translation in 3D along the _World_ frame, represented by the homogeneous transformation matrix below.\n", - "\n", - "$$\\mymatrix{H}^0_a = \\mymatrix{H}_a = \\left[\\begin{array}{ccc}\n", - " 1 & 0 & 0 & 1 \\\\\n", - " 0 & 1 & 0 & 2 \\\\\n", - " 0 & 0 & 1 & 3 \\\\\n", - " 0 & 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "Consider a rotation in 3D about the _current_ frame, represented by the homogeneous transformation matrix below.\n", - "\n", - "$$\\mymatrix{H}^a_b = \\left[\\begin{array}{ccc}\n", - " \\cos{\\theta_{ab}} & -\\sin{\\theta_{ab}} & 0 & 0 \\\\\n", - " \\sin{\\theta_{ab}} & \\cos{\\theta_{ab}} & 0 & 0 \\\\\n", - " 0 & 0 & 1 & 0 \\\\\n", - " 0 & 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "We can calculate their sequential combination as follows.\n", - "\n", - "$$\\mymatrix{H}^0_b = \\mymatrix{H}_b = \\mymatrix{H}_a\\mymatrix{H}^a_b$$\n", - "\n", - "We can compute this result with $\\theta_{ab} = \\frac{\\pi}{4}$ as shown in the piece of code below. We also show that\n", - "\n", - "$$\\mymatrix{H}_a\\mymatrix{H}^a_b \\neq \\mymatrix{H}^a_b\\mymatrix{H}_a,$$\n", - "\n", - "further reinforcing the importance of the order of operations.\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:16.991190Z", - "start_time": "2026-02-08T11:50:16.979684Z" - } - }, - "source": [ - "# An SE(3) translation\n", - "x = 1 # distance in metres\n", - "y = 2 # distance in metres\n", - "z = 3 # distance in metres\n", - "\n", - "H0_a = np.array([[1, 0, 0, x],\n", - " [0, 1, 0, y],\n", - " [0, 0, 1, z],\n", - " [0, 0, 0, 1]])\n", - "\n", - "# An SE(3) rotation\n", - "\u03b8ab = pi/4 # angle in radians\n", - "\n", - "Ha_b = np.array([[cos(\u03b8ab), -sin(\u03b8ab), 0, 0],\n", - " [sin(\u03b8ab), cos(\u03b8ab), 0, 0],\n", - " [0, 0, 1, 0],\n", - " [0, 0, 0, 1]])\n", - "\n", - "# H0_a then Ha_b\n", - "H0_b = H0_a @ Ha_b\n", - "\n", - "# Ha_b then Ha\n", - "H_wrong = Ha_b @ H0_a\n", - "\n", - "if np.isclose(H0_b,H_wrong).all():\n", - " print('The results are close!')\n", - "else:\n", - " print('The results are far, therefore the operation is not commutative')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The results are far, therefore the operation is not commutative\n" - ] - } - ], - "execution_count": 21 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Inverse transformations\n", - "\n", - "As you have learned in theory, the inverse transformation can be found as\n", - "\n", - "$$\\mymatrix{H^{-1}}(\\myvec{t},\\mymatrix{R}) = \\left[\\begin{array}{ccc}\n", - " \\mymatrix{R}^T & -\\mymatrix{R}^T\\myvec{t} \\\\\n", - " \\myvec{0} & 1 \n", - " \\end{array}\\right],$$\n", - "\n", - "so it is important to remember to _never_ invert the matrix with general matrix inversion algorithms. Using the matricial properties leads to a simpler, faster, and more accurate inversion. The only \"trick\" is to obtain the submatrix corresponding to the rotation matrix.\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "trusted": true, - "ExecuteTime": { - "end_time": "2026-02-08T11:50:17.004496Z", - "start_time": "2026-02-08T11:50:16.992720Z" - } - }, - "source": [ - "# Extract R from H", - "R0_b = H0_b[0:3,0:3] # The 3x3 Rotation matrix", - "t0_b = H0_b[0:3,3].reshape((3,1)) # The 3x1 translation vector at the fourth column. Reshape it into a column vector.", - "", - "A = R0_b.T", - "B = -R0_b.T @ t0_b", - "C = np.array([0,0,0])", - "D = np.array([1])", - "", - "# This is how you can use `np.block` to build a matrix like so", - "# | A B |", - "# | C D |", - "H0_b_inv = np.block([[A, B],", - " [C, D]])", - "", - "print(f\"H0_b_inv={H0_b_inv}\")", - "", - "print(f\"H0_b @ H0_b_inv = {H0_b @ H0_b_inv}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H0_b_inv=[[ 0.70710678 0.70710678 0. -2.12132034]\n", - " [-0.70710678 0.70710678 0. -0.70710678]\n", - " [ 0. 0. 1. -3. ]\n", - " [ 0. 0. 0. 1. ]]\n", - "H0_b @ H0_b_inv = [[1.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00]\n", - " [0.00000000e+00 1.00000000e+00 0.00000000e+00 2.22044605e-16]\n", - " [0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00]\n", - " [0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]\n" - ] - } - ], - "execution_count": 22 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercises\n", - "\n", - "Consider that the `numpy` and `math` modules are already imported as shown earlier in this lesson.\n", - "\n", - "## Exercise a\n", - "\n", - "For $\\theta_a = \\frac{\\pi}{4}$, calculate\n", - "\n", - "$$\\mymatrix{R}^0_{a} = \\mymatrix{R}_{a} = R(\\theta_a) \\in SO(2)$$\n", - "\n", - "and store it in the variable `R_a` shown in the cell below.\n" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-08T11:50:17.009164Z", - "start_time": "2026-02-08T11:50:17.004981Z" - } - }, - "cell_type": "code", - "source": [ - "\u03b8_a = pi/4.0 # As given in the exercise\n", - "\n", - "R_a = None # Replace None with your solution to this exercise." - ], - "outputs": [], - "execution_count": 23 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Exercise b\n", - "\n", - "Calculate the result of a rotation of $\\theta_{b1} = \\frac{\\pi}{12}$ followed by a rotation of $\\theta_{b2} = -\\frac{\\pi}{2}$, in the _current_ frame, using elements of SO(2).\n", - "\n", - "Store the result in the variable `R_b` shown in the cell below.\n" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-08T11:50:17.013166Z", - "start_time": "2026-02-08T11:50:17.009517Z" - } - }, - "cell_type": "code", - "source": [ - "\u03b8_b1 = pi/12.0 # As given in the exercise\n", - "\u03b8_b2 = -pi/2.0 # As given in the exercise\n", - "\n", - "R_b = None # Replace None with your solution to this exercise." - ], - "outputs": [], - "execution_count": 24 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Exercise c\n", - "\n", - "Consider the translation\n", - "\n", - "$$\\myvec{p}_c = \\left[\\begin{array}{ccc}\n", - " x_c \\\\\n", - " y_c\n", - " \\end{array}\\right],$$\n", - "\n", - "and the rotation\n", - "\n", - "$$R(\\theta_c) = \\left[\\begin{array}{ccc}\n", - " \\cos{\\theta_c} & -\\sin{\\theta_c} \\\\\n", - " \\sin{\\theta_c} & \\cos{\\theta_c}\n", - " \\end{array}\\right].$$\n", - "\n", - "Starting at the World frame, calculate the homogeneous transformation representing the rotation $R(\\theta_c)$, about the _World_ frame, followed by the translation $\\myvec{p}_c$, in the _current_ frame.\n", - "\n", - "Consider $\\theta_c = \\frac{\\pi}{3}$, $x_c = 2$, $y_c = 5$, and store the result in the variable `H_c` shown in the cell below.\n", - "\n" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-08T11:50:17.017113Z", - "start_time": "2026-02-08T11:50:17.013532Z" - } - }, - "cell_type": "code", - "source": [ - "\u03b8_c = pi/3.0 # As given in the exercise\n", - "x_c = 2.0 # As given in the exercise\n", - "y_c = 5.0 # As given in the exercise\n", - "\n", - "H_c = None # Replace None with your solution to this exercise." - ], - "outputs": [], - "execution_count": 25 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Exercise d\n", - "\n", - "Consider the same variables as in `Exercise c` by replacing the subscripts with `d`. Calculate, instead, the translation followed by the rotation. Store the result in the variable `H_d` shown in the cell below.\n", - "\n", - "Is `H_c` the same as `H_d`? What does that indicate?\n" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-08T11:50:17.020570Z", - "start_time": "2026-02-08T11:50:17.017417Z" - } - }, - "cell_type": "code", - "source": [ - "\u03b8_d = pi/3.0 # As given in the exercise\n", - "x_d = 2.0 # As given in the exercise\n", - "y_d = 5.0 # As given in the exercise\n", - "\n", - "H_d = None # Replace None with your solution to this exercise." - ], - "outputs": [], - "execution_count": 26 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Extra challenge(s)\n", - "1. Let a rotation represented by a SO(2) element have a time-varying angle of $\\theta(t) = \\sin(t) + 2\\cos(t)$.\n", - " - Write down its general form in SO(2) so that all four elements are clearly visible.\n", - " - Using this written down solution, compute the SO(2) representation at $t=10$.\n", - "2. Using SE(3) elements, calculate the final rigid body motion after four sequential transformations.\n", - " - The first transformation is a rotation of $\\theta=\\frac{\\pi}{10}$ about the $z$-axis of the _World_ frame.\n", - " - The second transformation is a translation of $d=0.3$ about the $z$-axis of the _current_ frame.\n", - " - The third transformation is a translation of $a=0.5$ about the $x$-axis of the _current_ frame.\n", - " - The fourth and last transformation is a rotation of $\\alpha=-\\frac{\\pi}{2}$ about the $x$-axis of the _current_ frame.\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/unstable/lesson2_tutorial.md b/basic_lessons/lesson2_tutorial.md similarity index 99% rename from unstable/lesson2_tutorial.md rename to basic_lessons/lesson2_tutorial.md index 90c4e83..cfdf0f4 100644 --- a/unstable/lesson2_tutorial.md +++ b/basic_lessons/lesson2_tutorial.md @@ -10,18 +10,18 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### Prerequisites for the learner +## Prerequisites for the learner The user of this notebook is expected to have prior knowledge in - All the content and prerequisites of lesson 1. -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues -### Latex Macros # Installing prerequisites ````{code-cell} +%%capture %pip install numpy ```` diff --git a/basic_lessons/lesson3_exercise_answers.ipynb b/basic_lessons/lesson3_exercise_answers.ipynb deleted file mode 100644 index 44aa719..0000000 --- a/basic_lessons/lesson3_exercise_answers.ipynb +++ /dev/null @@ -1,257 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L3 Exercise Answers\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "### I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "### Latex Macros" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "vscode": { - "languageId": "latex" - } - }, - "source": [ - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "# Valid imports" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-18T22:22:30.069623Z", - "start_time": "2026-02-18T22:22:30.051805Z" - } - }, - "cell_type": "code", - "source": [ - "from math import pi, sin, cos\n", - "import numpy as np" - ], - "outputs": [], - "execution_count": 1 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercises\n", - "\n", - "## Exercise a" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-18T22:22:30.088377Z", - "start_time": "2026-02-18T22:22:30.071120Z" - } - }, - "cell_type": "code", - "source": [ - "q_A0 = pi/4.0 # As given in the exercise\n", - "q_A1 = -0.1 # As given in the exercise\n", - "\n", - "H_A0_A0p = np.array(\n", - " [[cos(q_A0), -sin(q_A0), 0, 0],\n", - " [sin(q_A0), cos(q_A0), 0, 0],\n", - " [0, 0, 1, 0],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H_A0p_A0pp = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, 1, 0, 0],\n", - " [0, 0, 1, 0.5],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H_A0pp_A1 = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, cos(pi/2), -sin(pi/2), 0],\n", - " [0, sin(pi/2), cos(pi/2), 0],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H_A1_A2 = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, 1, 0, 0],\n", - " [0, 0, 1, q_A1],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "\n", - "H_A0_A2 = H_A0_A0p @ H_A0p_A0pp @ H_A0pp_A1 @ H_A1_A2\n", - "\n", - "# Printing the result is NOT a mandatory part of the answer.\n", - "print(f'H_A0_A2 = {H_A0_A2}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H_A0_A2 = [[ 7.07106781e-01 -4.32978028e-17 7.07106781e-01 -7.07106781e-02]\n", - " [ 7.07106781e-01 4.32978028e-17 -7.07106781e-01 7.07106781e-02]\n", - " [ 0.00000000e+00 1.00000000e+00 6.12323400e-17 5.00000000e-01]\n", - " [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]\n" - ] - } - ], - "execution_count": 2 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "## Exercise c" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-18T22:22:30.103393Z", - "start_time": "2026-02-18T22:22:30.089134Z" - } - }, - "cell_type": "code", - "source": [ - "# All rotations are the same\n", - "H_Rz = np.array(\n", - " [[cos(pi/5.0), -sin(pi/5.0), 0, 0],\n", - " [sin(pi/5.0), cos(pi/5.0), 0, 0],\n", - " [0, 0, 1, 0],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "# All translations are the same\n", - "H_Tx = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, 1, 0, 0],\n", - " [0, 0, 1, 0.25],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H_C0_C3 = H_Rz @ H_Tx @ H_Rz @ H_Tx @ H_Rz @ H_Tx\n", - "\n", - "# Printing the result is NOT a mandatory part of the answer.\n", - "print(f'H_C0_C3 = {H_C0_C3}')" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "H_C0_C3 = [[-0.30901699 -0.95105652 0. 0. ]\n", - " [ 0.95105652 -0.30901699 0. 0. ]\n", - " [ 0. 0. 1. 0.75 ]\n", - " [ 0. 0. 0. 1. ]]\n" - ] - } - ], - "execution_count": 3 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "# Challenge 1\n" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-18T22:22:30.115953Z", - "start_time": "2026-02-18T22:22:30.103902Z" - } - }, - "cell_type": "code", - "source": [ - "# Consider manipulator DoFs as the length of the following lists.\n", - "# Consider it as the configuration space of the RRR...RRR robot\n", - "q = [pi/2, pi/10, -pi/10, pi/2] # Increase length of q if you'd like to check\n", - "l = [1, 2, 3, 4] # l must be same size of q\n", - "\n", - "if len(q) != len(l):\n", - " raise Exception(\"q and l are not the same length\")\n", - "\n", - "def link_rotation(qi):\n", - " return np.array(\n", - " [[cos(qi), -sin(qi), 0],\n", - " [sin(qi), cos(qi), 0],\n", - " [0, 0, 1]])\n", - "\n", - "def link_translation(li):\n", - " return np.array(\n", - " [[1, 0, li],\n", - " [0, 1, 0],\n", - " [0, 0, 1]])\n", - "\n", - "H = np.eye(3)\n", - "for qi, li in zip(q, l):\n", - " H = H @ link_rotation(qi) @ link_translation(li)\n", - "\n", - "# Printing the result is NOT a mandatory part of the answer.\n", - "print(f\"Final answer is {H}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Final answer is [[-1.00000000e+00 -1.28674811e-16 -4.61803399e+00]\n", - " [ 1.02095262e-16 -1.00000000e+00 5.90211303e+00]\n", - " [ 0.00000000e+00 0.00000000e+00 1.00000000e+00]]\n" - ] - } - ], - "execution_count": 4 - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson3_exercise_answers.md b/basic_lessons/lesson3_exercise_answers.md similarity index 98% rename from unstable/lesson3_exercise_answers.md rename to basic_lessons/lesson3_exercise_answers.md index f742275..ab344a8 100644 --- a/unstable/lesson3_exercise_answers.md +++ b/basic_lessons/lesson3_exercise_answers.md @@ -10,10 +10,9 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues -### Latex Macros # Valid imports diff --git a/basic_lessons/lesson3_tutorial.ipynb b/basic_lessons/lesson3_tutorial.ipynb deleted file mode 100644 index 3086914..0000000 --- a/basic_lessons/lesson3_tutorial.ipynb +++ /dev/null @@ -1,437 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L3 Forward Kinematics\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "## Prerequisites for the learner\n", - "The user of this notebook is expected to have prior knowledge in\n", - "- All the content and prerequisites of lessons 1 and 2.\n", - "\n", - "## I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "#### Latex Macros\n", - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prerequisites\n" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "source": [ - "%%capture\n", - "%pip install numpy\n", - "%pip install numpy --break-system-packages" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Imports\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "imports" - ] - }, - "source": [ - "import numpy as np\n", - "from math import pi, sin, cos" - ], - "outputs": [], - "execution_count": null - }, - { - "attachments": { - "4A.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAswAAAJcCAYAAADtt/JZAAAMP2lDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnluSkEBoAQSkhN4EESkBpITQQu8INkISIJQYA0HFjiwquBZURMCGroooWAGxI3YWxd4XCwrKuliwK29SQNd95Xvn++be//5z5j9nzp1bBgC1ExyRKBtVByBHmCeOCfKjj09KppN6AAJGAiLQAiYcbq6IGRUVBqANnf9u725Ab2hX7aVa/+z/r6bB4+dyAUCiIE7l5XJzID4AAF7NFYnzACBKebPpeSIphg1oiWGCEC+W4nQ5rpbiVDneI/OJi2FB3AaAkgqHI04HQPUy5On53HSoodoPsaOQJxACoEaH2DsnZyoP4hSIraGPCGKpPiP1B530v2mmDmtyOOnDWD4XmSn5C3JF2ZyZ/2c5/rflZEuGYljCppIhDo6RzhnW7VbW1FApVoG4T5gaEQmxJsQfBDyZP8QoJUMSHC/3Rw24uSxYM6ADsSOP4x8KsQHEgcLsiDAFn5omCGRDDFcIOkOQx46DWBfixfzcgFiFzybx1BhFLLQxTcxiKvhzHLEsrjTWA0lWPFOh/zqDz1boY6oFGXGJEFMgNs8XJERArAqxQ25WbKjCZ1xBBitiyEcsiZHmbw5xDF8Y5CfXx/LTxIExCv+SnNyh+WKbMgTsCAXel5cRFyyvD9bG5cjyh3PBLvOFzPghHX7u+LChufD4/gHyuWM9fGF8rELngyjPL0Y+FqeIsqMU/rgpPztIyptC7JybH6sYiyfkwQUp18fTRHlRcfI88YJMTkiUPB98BQgDLOAP6EACWyqYCjKBoKOvqQ9eyXsCAQeIQTrgA3sFMzQiUdYjhMdYUAD+hIgPcofH+cl6+SAf8l+HWfnRHqTJevNlI7LAU4hzQCjIhtcS2SjhcLQE8AQygn9E58DGhflmwybt//f8EPudYUImTMFIhiLS1YY8iQFEf2IwMZBog+vj3rgnHgaPvrA54QzcfWge3/0JTwmdhEeE64Quwu0pgkLxT1mGgy6oH6ioReqPtcAtoaYL7od7QXWojOvg+sAed4ZxmLgPjOwCWZYib2lV6D9p/20GP9wNhR/ZkYySR5B9ydY/j1S1VXUZVpHW+sf6yHNNHa43a7jn5/isH6rPg+fQnz2xxdh+7Cx2EjuPHcGaAB07jjVj7dhRKR5eXU9kq2soWowsnyyoI/hHvKE7K61krmOdY6/jF3lfHn+G9B0NWFNFM8WC9Iw8OhN+Efh0tpDrMIru5OjkDID0+yJ/fb2Jln03EJ3279zCPwDwOj44OHj4OxdyHIC9bvDxP/Sds2bAT4cyAOcOcSXifDmHSw8E+JZQg0+aHjACZsAazscJuAJP4AsCQAiIBHEgCUyG2WfAdS4G08FssAAUg1KwAqwBlWAj2AJ2gN1gH2gCR8BJcAZcBJfBdXAXrp5u8AL0g3fgM4IgJISK0BA9xBixQOwQJ4SBeCMBSBgSgyQhKUg6IkQkyGxkIVKKlCGVyGakFtmLHEJOIueRTuQ28hDpRV4jn1AMVUG1UEPUEh2NMlAmGorGoZPQdHQaWoAWocvQCrQG3YU2oifRi+h1tAt9gQ5gAFPGdDATzB5jYCwsEkvG0jAxNhcrwcqxGqwea4H3+SrWhfVhH3EiTsPpuD1cwcF4PM7Fp+Fz8aV4Jb4Db8Tb8Kv4Q7wf/0agEgwIdgQPApswnpBOmE4oJpQTthEOEk7DZ6mb8I5IJOoQrYhu8FlMImYSZxGXEtcTG4gniJ3Ex8QBEomkR7IjeZEiSRxSHqmYtI60i3ScdIXUTfqgpKxkrOSkFKiUrCRUKlQqV9qpdEzpitIzpc9kdbIF2YMcSeaRZ5KXk7eSW8iXyN3kzxQNihXFixJHyaQsoFRQ6imnKfcob5SVlU2V3ZWjlQXK85UrlPcon1N+qPxRRVPFVoWlMlFForJMZbvKCZXbKm+oVKol1ZeaTM2jLqPWUk9RH1A/qNJUHVTZqjzVeapVqo2qV1RfqpHVLNSYapPVCtTK1farXVLrUyerW6qz1Dnqc9Wr1A+p31Qf0KBpjNGI1MjRWKqxU+O8Ro8mSdNSM0CTp1mkuUXzlOZjGkYzo7FoXNpC2lbaaVq3FlHLSoutlalVqrVbq0OrX1tT21k7QXuGdpX2Ue0uHUzHUoetk62zXGefzg2dTyMMRzBH8EcsGVE/4sqI97ojdX11+bolug2613U/6dH1AvSy9FbqNend18f1bfWj9afrb9A/rd83Umuk50juyJKR+0beMUANbA1iDGYZbDFoNxgwNDIMMhQZrjM8ZdhnpGPka5RptNromFGvMc3Y21hgvNr4uPFzujadSc+mV9Db6P0mBibBJhKTzSYdJp9NrUzjTQtNG0zvm1HMGGZpZqvNWs36zY3Nw81nm9eZ37EgWzAsMizWWpy1eG9pZZlouciyybLHSteKbVVgVWd1z5pq7WM9zbrG+poN0YZhk2Wz3uayLWrrYpthW2V7yQ61c7UT2K236xxFGOU+SjiqZtRNexV7pn2+fZ39QwcdhzCHQocmh5ejzUcnj145+uzob44ujtmOWx3vjtEcEzKmcEzLmNdOtk5cpyqna2OpYwPHzhvbPPaVs50z33mD8y0Xmku4yyKXVpevrm6uYtd61143c7cUt2q3mwwtRhRjKeOcO8Hdz32e+xH3jx6uHnke+zz+8rT3zPLc6dkzzmocf9zWcY+9TL04Xpu9urzp3inem7y7fEx8OD41Po98zXx5vtt8nzFtmJnMXcyXfo5+Yr+Dfu9ZHqw5rBP+mH+Qf4l/R4BmQHxAZcCDQNPA9MC6wP4gl6BZQSeCCcGhwSuDb7IN2Vx2Lbs/xC1kTkhbqEpobGhl6KMw2zBxWEs4Gh4Svir8XoRFhDCiKRJEsiNXRd6PsoqaFnU4mhgdFV0V/TRmTMzsmLOxtNgpsTtj38X5xS2PuxtvHS+Jb01QS5iYUJvwPtE/sSyxa/zo8XPGX0zSTxIkNSeTkhOStyUPTAiYsGZC90SXicUTb0yymjRj0vnJ+pOzJx+dojaFM2V/CiElMWVnyhdOJKeGM5DKTq1O7eeyuGu5L3i+vNW8Xr4Xv4z/LM0rrSytJ90rfVV6b4ZPRnlGn4AlqBS8ygzO3Jj5Pisya3vWYHZidkOOUk5KziGhpjBL2DbVaOqMqZ0iO1GxqGuax7Q10/rFoeJtuUjupNzmPC34I98usZb8InmY751flf9hesL0/TM0ZghntM+0nblk5rOCwILfZuGzuLNaZ5vMXjD74RzmnM1zkbmpc1vnmc0rmtc9P2j+jgWUBVkLfi90LCwrfLswcWFLkWHR/KLHvwT9UlesWiwuvrnIc9HGxfhiweKOJWOXrFvyrYRXcqHUsbS89MtS7tILv475teLXwWVpyzqWuy7fsIK4QrjixkqflTvKNMoKyh6vCl/VuJq+umT12zVT1pwvdy7fuJayVrK2qyKsonmd+boV675UZlRer/Kraqg2qF5S/X49b/2VDb4b6jcabizd+GmTYNOtzUGbG2ssa8q3ELfkb3m6NWHr2d8Yv9Vu099Wuu3rduH2rh0xO9pq3WprdxrsXF6H1knqendN3HV5t//u5nr7+s0NOg2le8AeyZ7ne1P23tgXuq91P2N//QGLA9UHaQdLGpHGmY39TRlNXc1JzZ2HQg61tni2HDzscHj7EZMjVUe1jy4/RjlWdGzweMHxgROiE30n008+bp3SevfU+FPX2qLbOk6Hnj53JvDMqbPMs8fPeZ07ct7j/KELjAtNF10vNra7tB/83eX3gx2uHY2X3C41X3a/3NI5rvPYFZ8rJ6/6Xz1zjX3t4vWI65034m/cujnxZtct3q2e29m3X93Jv/P57vx7hHsl99Xvlz8weFDzh80fDV2uXUcf+j9sfxT76O5j7uMXT3KffOkuekp9Wv7M+Fltj1PPkd7A3svPJzzvfiF68bmv+E+NP6tfWr888JfvX+394/u7X4lfDb5e+kbvzfa3zm9bB6IGHrzLeff5fckHvQ87PjI+nv2U+OnZ5+lfSF8qvtp8bfkW+u3eYM7goIgj5sh+BTDY0LQ0AF5vB4CaBAAN7s8oE+T7P5kh8j2rDIH/hOV7RJm5AlAP/9+j++DfzU0A9myF2y+orzYRgCgqAHHuAB07drgN7dVk+0qpEeE+YFPE19ScVPBvTL7n/CHvn89AquoMfj7/C9uSfGF2ps3uAAAAimVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAA5KGAAcAAAASAAAAeKACAAQAAAABAAACzKADAAQAAAABAAACXAAAAABBU0NJSQAAAFNjcmVlbnNob3RFngtOAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB1mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj42MDQ8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NzE2PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6VXNlckNvbW1lbnQ+U2NyZWVuc2hvdDwvZXhpZjpVc2VyQ29tbWVudD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CirkyR4AAAAcaURPVAAAAAIAAAAAAAABLgAAACgAAAEuAAABLgAARG0MkiyzAABAAElEQVR4AezdCdxN1f7H8d9NlKLHGJUMKbmouHIlURSFUKrbQCgpDW6SqcGYKURJpkiKW7pSukVRURRCNEjGQkpCxpLx32+92vv/nLPPc55zzrPPc/Y++7Nfr3vP3mtPa78Xr/u179pr/e34n4uwIIAAAggggAACCCCAQESBvxGYI7pQiAACCCCAAAIIIICAESAw8wcBAQQQQAABBBBAAIEoAgTmKDjsQgABBBBAAAEEEECAwMyfAQQQQAABBBBAAAEEoggQmKPgsAsBBBBAAAEEEEAAAQIzfwYQQAABBBBAAAEEEIgiQGCOgsMuBBBAAAEEEEAAAQQIzPwZQAABBBBAAAEEEEAgigCBOQoOuxBAAAEEEEAAAQQQIDDzZwABBBBAAAEEEEAAgSgCBOYoOOxCAAEEEEAAAQQQQIDAzJ8BBBBAAAEEEEAAAQSiCBCYo+CwCwEEEEAAAQQQQAABAjN/BhBAAAEEEEAAAQQQiCJAYI6Cwy4EEEAAAQQQQAABBAjM/BlAAAEEEEAAAQQQQCCKAIE5Cg67EEAAAQQQQAABBBAgMPNnAAEEEEAAAQQQQACBKAIE5ig47EIAAQQQQAABBBBAgMDMnwEEEEAAAQQQQAABBKIIEJij4LALAQQQQAABBBBAAAECM38GEEAAAQQQQAABBBCIIkBgjoLDLgQQQAABBBBAAAEECMz8GUAAAQQQQAABBBBAIIoAgTkKDrsQQAABBBBAAAEEECAw82cAAQQQQAABBBBAAIEoAgTmKDjsQgABBBBAAAEEEECAwMyfAQQQQAABBBBAAAEEoggQmKPgsAsBBBBAAAEEEEAAAQIzfwYQQAABBBBAAAEEEIgiQGCOgsMuBBBAAAEEEEAAAQQIzPwZQAABBBBAAAEEEEAgigCBOQoOuxBAAAEEEEAAAQQQIDDzZwABBBBAAAEEEEAAgSgCBOYoOOxCAAEEEEAAAQQQQIDAzJ8BBBBAAAEEEEAAAQSiCBCYo+CwCwEEEEAAAQQQQAABAjN/BhBAAAEEEEAAAQQQiCJAYI6Cwy4EEEAAAQQQQAABBAjM/BlAAAEEEEAAAQQQQCCKAIE5Ck52u3bv3i1bt26Vn376Sfbt2yeNGzeWk046KeJpe/fulc8++0yOHj0qF198sRQtWjTicRQigAACCCCAAAIIeEuAwBxne0yfPl3Wr18vW7Zskf3794ecfdNNN8m1114bUmZtDBw4UNasWWM2MzIypG/fvlK4cGFrN78IIIAAAggggAACHhUgMMfZMC+99JLo2+I9e/bI2rVrQ87Wt8ZPPfWU/O1vfwspP378uLRr1868XbZ2tG7dWq688kprk18EEEAAAQQQQAABjwoQmHPQMEuXLpXnnntONBBbS/fu3aVSpUrWpv2rx2mXDGu58cYbpWnTptYmvwgggAACCCCAAAIeFSAw57Bhxo0bJ59++ql9lSuuuELuuOMOe9ta0b7LU6dOlQ8++MAUdezY0fRltvbziwACCCCAAAIIIOBNAQJzDttl06ZN0qtXL/sqhQoVkqefftrRLcM6oHPnzrJz504ZMmSIlChRwirmFwEEEEAAAQQQQMCjAgRmFxrm0UcfNaNlWJfq06ePlCtXztq0f48dOyZ33323lCxZUvr372+Xs4IAAggggAACCCDgXQECswttM2PGDJk5c6Z9peuuu06uv/56e9taWblypYwYMUJuvvlmMwSdVc4vAggggAACCCCAgHcFCMwutM2GDRukX79+9pXOOecc6d27t71tregIGqtWrZLhw4eLdt1gQQABBBBAAAEEEPC+AIHZhTbSrhYPPPCAHDhwwFwtT548MnbsWMmXL5999R9++EEef/xxqV27trRv394uZwUBBBBAAAEEEEDA2wIEZpfaZ9SoUaLDzFlL+PBy+iHgF198ITqByRlnnGEdxi8CCCCAAAIIIICAxwUIzC410Pz582XSpEn21Vq0aCHNmzc32+vWrTMf+f3zn/+U+++/3z6GFQQQQAABBBBAAAHvCxCYXWqjbdu2ib5VtpZq1apJp06dzOaAAQPMdNpPPPGElCpVyjqEXwQQQAABBBBAAAEfCBCYXWykBx98UHbv3m2uqNNk68d9ixYtMv2ZL7/8crnzzjtdvFvil4o0dXfiV+NMBBBAAAEEEEAgvQUIzC627+jRo2XJkiX2FXVUDB1v+eDBg/Lkk09KRkaGvS+VKwTmVOpzbwQQQAABBBDwmwCB2cUWmzt3rkyZMsW+ok5e8t1338lNN90k1157rV2e6hUCc6pbgPsjgAACCCCAgJ8ECMwutlb4eMx66eLFi8ugQYMkb968Lt4pZ5ciMOfMj7MRQAABBBBAIFgCBGYX2/vw4cPSoUMHOXLkiH3Vbt26SeXKle1tL6wQmL3QCtQBAQQQQAABBPwiQGB2uaV0cpItW7aYq9arV0/atm3r8h1yfjkCc84NuQICCCCAAAIIBEeAwOxyWw8ePFhWr14tOkqGDieXP39+l++Q88sRmHNuyBUQQAABBBBAIDgCBGYX2/ro0aNmYpLff/9dunTpIhdccIGLV3fvUgRm9yy5EgIIIIAAAgikvwCB2cU2fvPNN+WNN94QL425HOnxCMyRVChDAAEEEEAAAQQiCxCYI7vEXardMIYMGSJnn322aD/mfPnyxX2N3DqBwJxb0twHAQQQQAABBNJBgMDsQivu2rVLevfuba7Up08f03/Zhcsm7RIE5qTRcmEEEEAAAQQQSEMBAnMOG/WPP/4wH/dt3bpVunfvLhUqVMjhFZN/OoE5+cbcAQEEEEAAAQTSR4DAHGNb7tmzR6ZOnSrr16+XihUrSsuWLc2Zw4cPN2V33HGHXHHFFTFeLbWHEZhT68/dEUAAAQQQQMBfAgTmGNtr5syZMmPGDPvoggULyrFjx+TAgQNy6623yjXXXGPv8/oKgdnrLUT9EEAAAQQQQMBLAgTmGFvj5Zdflvfffz/k6BNPPFHatGkjdevWDSn3+gaB2estRP0QQAABBBBAwEsCBOYYW2Pz5s3y5JNPyv79+80Z5cuXl9tvv13KlSsX4xW8cxiB2TttQU0QQAABBBBAwPsCBOY42ki7YPzwww9m9r7ixYvHcaa3DiUwe6s9qA0CCCCAAAIIeFuAwOzt9klK7QjMSWHloggggAACCCCQpgIE5jRt2GiPRWCOpsM+BBBAAAEEEEAgVIDAHOoRiC0CcyCamYdEAAEEEEAAAZcECMwuQfrpMgRmP7UWdUUAAQQQQACBVAsQmFPdAim4P4E5BejcEgEEEEAAAQR8K0Bg9m3TJV5xAnPidpyJAAIIIIAAAsETIDAHr82FwBzARueREUAAAQQQQCBhAQJzwnT+PZHA7N+2o+YIIIAAAgggkPsCBObcN0/5HQnMKW8CKoAAAggggAACPhIgMPuosdyqKoHZLUmugwACCCCAAAJBECAwB6GVw56RwBwGwiYCCCCAAAIIIBBFgMAcBSdddxGY07VleS4EEEAAAQQQSIYAgTkZqh6/JoHZ4w1E9RBAAAEEEEDAUwIEZk81R+5UhsCcO87cBQEEEEAAAQTSQ4DAnB7tGNdTEJjj4uJgBBBAAAEEEAi4AIE5gH8ACMwBbHQeGQEEEEAAAQQSFiAwJ0zn3xMJzP5tO2qOAAIIIIAAArkvQGDOffOU35HAnPImoAIIIIAAAggg4CMBArOPGsutqhKY3ZLkOggggAACCCAQBAECcxBaOewZCcxhIGwigAACCCCAAAJRBAjMUXDSdReBOV1bludCAAEEEEAAgWQIEJiToerxaxKYPd5AVC8pAseOHZN9+/bJ77//bv6j26eddpoUKlRI8ubNm5R7clEEEEAAgfQQIDCnRzvG9RQE5ri4ONinAsePH5dVq1bJ8uXL5fvvv5ctW7bI4cOHIz7NqaeeKsWLF5dy5crZ/ylVqpSccMIJEY8PL9QgvmzZMrn88stjPif8GmwjgAACCHhXgMDs3bZJWs0IzEmj5cIeENCg/NFHH8lbb70lO3fuTLhG+fLlk7Jly8o555xj/lO6dGkpUqSInHTSSeaaR44cMSF88eLFMm/ePDl06JA8+uijUqFChYTvyYkIIIAAAt4UIDB7s12SWisCc1J5uXgKBQ4cOCDPPvusrF692q7FWWedZd4aFy1aVIoVKyYnnnii7Nq1y4Tpn3/+WTZu3Gi6aNgnZLNyyimniL6R/vXXX0VDsy76Nrpt27Zy3nnnZXM2uxFAAAEE/ChAYPZjq+WwzgTmHAJyuicFjh49KkOHDrXDcpUqVaRRo0aiv9EW7cv8ww8/yLp168x/1q9fL7/88ku0U+x9+ra5WbNm5j558uSxy1lBAAEEEEgvAQJzerVnTE9DYI6JiYN8JjB58mT58MMPTa1vvvlmady4ccJPsGfPHtmwYYN88cUX5g20fhyob5T1g0H9SPD000+XCy+8UKpXry4nn3xywvfhRAQQQAABfwgQmP3RTq7WksDsKicX84DA/v375cEHHzRdJBo2bCgtW7aMqVbffPONvPHGG9K+fXsTgjOfpN02Bg8eLHv37pUxY8ZI+N+bzMeyjgACCCCQ3gIE5vRu34hPF/4//PqRFAsCfhbQN8v6hln7J2u41Q/2YllGjBgha9askVGjRplzrXP0Y0ENy9u3b5fWrVvLlVdeae3iFwEEEEAggAIE5iA2+t/+FvLUBOYQDjZ8KPDMM8/I559/LuXLl5devXrF9AQairt06SI1atSQ++67zz5nx44dJixrP+batWvL3Xffbe9jBQEEEEAgmAIE5gC2O2+YA9joaf7IAwcONG+Ka9asGRJ+oz32q6++KrNnzzbH63m6aEgeNGiQGUFDP+jTjwgzMjKiXYZ9CCCAAAIBECAwB6CRwx+RwBwuwrbfBbRLxdKlS6VMmTLSr1+/bB9n7dq1JhjrDH/6djp//vxy8OBB6dmzp+mGoRdo3ry5tGjRIttrcQACCCCAQPoLEJjTv40dT0hgdpBQ4HOBN99803y8p32Y+/fvL2eccUaWT6QjXWgw1rfJOnZyvXr1zLHPP/+8LFy40KzrDH/av1lHxGBBAAEEEECAwBzAPwME5gA2epo/svZH7t69u5n6Wt8y64x7kYZ70w/8JkyYYN4i67BwDz/8sJHRt9P6ltpadOzmrl27Wpv2r4btlStXSsmSJc1kKPYOVhBAAAEE0lqAwJzWzRv54QjMkV0o9beAjpmss/wdPnzYvBm+9tprzZTWOhufTkyiE5IsWrRI9CPXcuXKSadOncxxOuGJhu3Mk5V06NBBatWqFQLyySefmJE4/vjjD9FxmbUrh76JZkEAAQQQSH8BAnP6t7HjCQnMDhIK0kRAQ/O4ceNEp8iOtOhwc9dff71cc801dti1hqSzjtf+zCNHjgwZmu6zzz4zw9XprIC66DTbw4cPt07hFwEEEEAgzQUIzGnewJEej8AcSYWydBE4dOiQLFmyRL7//nsz2oV2zTjrrLOkVKlS5o1z5lEv9O2zDi2ns/hZizXdtXbz0CHm9D/btm0TKyxrP+l///vfctFFF1mn8IsAAgggkOYCBOY0b+BIj0dgjqRCWRAFPvroI3nhhRdifnTtu3zvvfdK2bJlYz6HAxFAAAEE/C9AYPZ/G8b9BATmuMk4Ic0Evv32W5kzZ46sWLHCfnOc3SMWL15cBgwYIPoGmgUBBBBAIFgCBOZgtbd5WgJzABudRzYfA+pHfxqUt2zZElFEPwbUrhYajgsXLmz6OesU2bow619EMgoRQACBQAgQmAPRzKEPSWAO9WArvQV0VIz58+fL66+/Lvv27Yv6sDqG89lnn20fs27dOjOusxY0aNBAWrVqZe9jBQEEEEAgOAIE5uC0tf2kBGabgpU0F9i+fbsZd1nHX9ZFP9irVq2a+dW3zZmXSpUqmeHlMpctWLDAnK9lOsycDjfn1qLD0+nHhDpudKyLnqNvx3WYPB3No3z58lKsWLFYT+c4BBBAAIEEBQjMCcL5+TQCs59bj7rHKqCjZDz11FOyd+9eE5AbNmwojRo1klNPPVV69OhhT4FtXa9z586OkS/0zfT7778v//znP01g1q4abi0vvviizJs3z0yYUrBgwaiX1dE8dDbDd955x9HnWruO6IyFVatWjXoNdiKAAAIIJC5AYE7czrdnEph923RUPJPArl27RD/e0zetOjNf3rx5M+0Vue+++8x4zBdffLHccsstpl+yHvD222/Lf//735BjK1euLN26dQspS+bG5s2bpXfv3ib8PvLII1KxYsUsb6cTq2hXkY0bN2Z5TJ48eeSuu+6SSy+9NMtj2IEAAgggkLgAgTlxO9+eSWD2bdNR8b8ENmzYIEOGDJGDBw+akhIlSkjfvn1NeLaQli9fLgUKFJDzzz/fKjKz+em02TpWs7VoNw0NpGeccYZVlPRf/ZBw9erV5j6tW7eWK6+8Mst7vvHGG+btsr7d1jfkp59+uuzevVu++uorM960daL+vVYT3c+CAAIIIOCuAIHZXU9fXI3A7ItmopJRBLSrxZdffhlyxAMPPCA1atQIKcu8oROPDBo0SNauXZu5WG688UZp2rRpSFkyN5YtW2am8LbuoWFZQ3OkRT9S1Cm8zzzzTHn88ccdQ9rpBC2jR4+2T9WuGfXq1bO3WUEAAQQQcEeAwOyOo6+uQmD2VXNR2QgC2t9YZ+LLvDz00ENR+/G+8sor8u6772Y+xfRN1q4b4X8nQg5ycUP7ImsXDP0Y0Vr+/ve/mz7V1nbm308++UQmTpxogr6+RY+0jBo1SpYuXWp26T8Y9B8OLAgggAAC7goQmN319MXVwsOBDrvFgoCfBLT/r37UZy364dvQoUMd/Zit/W+99ZYZVs7a1t8KFSpI165dJV++fJmLk7pu9Z/WkTp00hRdTjvttJA3zpkrMGbMGPPBYvv27TMXh6zrh4mTJk0yZeeee6707NkzZD8bCCCAAAI5FyAw59zQd1cgMPuuyahwmMC0adNk1qxZplQ/drvkkksihuUdO3aIHvvZZ5+FXEFHvbj77rsjnhNyoIsbe/bsMcPWaaht1qyZmTXQury+JY40UobWX2cWjLTPOlf7Mg8bNsxs1qxZ03zsaO3jFwEEEEDAHQECszuOvroKgdlXzUVlIwj8+OOPJnDu37/fjEXcpEkT0XGUdcQMDaY///yz6eOsXTAOHz5sX0H3t2jRwkxCEv73wD4oSSvatWLhwoXmA0N9I37vvffad8pupAz7wAgr2m1j/PjxZs+tt94q11xzTYSjKEIAAQQQyIkAgTknej49Nzwo0CXDpw0Z8Gpv2rRJRowYIb/++qstocOr6TBs4YuOvawTj+jHfYUKFQrfnfRt7T7Sp08f80FemzZtzP30Yz6r7tmNlBGtglOnTjXTfetoH+qhXTxYEEAAAQTcFSAwu+vpi6sRmH3RTFQyBgENxzrqhI4WoR/S6djM2idZh1YrWbKk+dURJnSc5tzsqxxe9QEDBpjZ+XTYN6t7hXaj0O4Uulx11VVy++23h5+W7baO/PHggw+ayVmuvvpque2227I9hwMQQAABBOIXIDDHb+b7MwjMvm9CHsBHAtbQbzp5io6jbC2ZR+2INlKGdXykX+uDP50ee+DAgY5h5yKdQxkCCCCAQPwCBOb4zXx/BoHZ903IA/hEQCdI0Wm4tauIjgGt3SasZcGCBTJhwgSzGW2kDOv48F+d8luvrX20dTKWcuXKhR/CNgIIIICASwIEZpcg/XQZArOfWou6+llg5syZMmPGDClSpIhccMEFIY+i40h//fXXdllWI2XYB2Ra0a4Yw4cPN+fruMs6/TcLAggggEDyBAjMybP17JUJzJ5tGiqWRgL6QV/37t3NW2X96DDSknkCk3hGypg8ebJ8+OGHpt+z9n9mQQABBBBIrgCBObm+nrw6gdmTzUKl0kxg3LhxsmjRIjM6RtmyZSM+XceOHc0He7pTR8+oX79+xOMyF+r40zq29A033GDGc868j3UEEEAAgeQIEJiT4+rpqxKYPd08VC4NBNavX2/GW9YJUnTq7awW/VBvzZo1ZncsI2XMmzdPXnzxRfPxoH5EyIIAAgggkDsCBObccfbUXQjMnmoOKpNmAjqueZ8/x1zesmWL+dCvRIkSWT7hCy+8IB999JHZn91IGYsXLxZ9a12nTh258847s7zmc889Z4658MILszyGHQgggAAC8QkQmOPzSoujCcxp0Yw8hEcFtG+x9jHWiVI6dOgQtZazZ8+WV1991Ryj/Zw17Ib//dSdK1eulJEjR5qP+3SGwEjHHDhwwEwX/t5778kzzzwjWfWbjlohdiKAAAIIRBQgMEdkSe/C8P+xZaa/9G5vni73BPQjvp49e8rBgwfloYcekqpVq0a9+dy5c2XKlCn2Mf3795ezzz7b3taV1atXy1NPPWWGjytevLgZoi7kgD83dNSMX375RfTvcixBPfx8thFAAAEEogsQmKP7pOVeAnNaNisPlWKBdevWyfjx482Mg1qVW2+9VWrXrm3P7Je5ekeOHJFt27aZLhabN2+2d+mMhHfccYfoRCS6bNiwQXR2QA3gsS7xjLYR6zU5DgEEEAi6AIE5gH8CCMwBbHQeOakCO3bskMGDBzvucfLJJ5uP/8J3TJw40bw5Di+3tjt16iSlSpWSMWPGmNBslWf3W7hwYXnssceyO4z9CCCAAAJxChCY4wRLh8MJzOnQijwDAggggAACCOSWAIE5t6Q9dB8Cs4cag6oggAACCCCAgOcFCMyebyL3K0hgdt+UKyKAAAIIIIBA+goQmNO3bbN8MgJzljTsQAABBBBAAAEEHAIEZgdJ+hcQmNO/jXlCBBBAAAEEEHBPgMDsnqVvrkRg9k1TUVEEEEAAAQQQ8IAAgdkDjZDbVSAw57Y490MAAQQQQAABPwsQmP3cegnWncCcIBynIYAAAggggEAgBQjMAWx2AnMAG51HRgABBBBAAIGEBQjMCdP590QCs3/bjpojgAACCCCAQO4LEJhz3zzldyQwp7wJqAACCCCAAAII+EiAwOyjxnKrqgRmtyS5DgIIIIAAAggEQYDAHIRWDntGAnMYCJsIIIAAAggggEAUAQJzFJx03UVgTteW5bkQQAABBBBAIBkCBOZkqHr8mgRmjzcQ1QuUwMMPPyznn3++1KlTRypWrCjhfz8DhcHDIoAAAh4VIDB7tGGSWa3w/0E+fvx4Mm/HtRFAIAuBzZs3S5kyZey9xYoVk8suu0yuu+46adOmjV3OCgIIIIBAagUIzKn1T8ndCcwpYeemCDgEpk6dKq1atXKUa1h+8cUXHeUUIIAAAgikRoDAnBr3lN6VwJxSfm6OgC3QoUMHGTdunL1trUyYMEHatWtnbfKLAAIIIJBiAQJzihsgFbcnMKdCnXsi4BSoUqWKrFq1yrFjzZo1UqFCBUc5BQgggAACqREgMKfGPaV3JTCnlJ+bI2AE9u3bJ4UKFZJjx46FiGjZrl27+PgvRIUNBBBAILUCBObU+qfk7gTmlLBzUwRCBN566y1p3rx5SJlutGjRQl5//XVHOQUIIIAAAqkTIDCnzj5ldyYwp4yeGyNgC3Tt2lWGDRtmb1srI0aMkE6dOlmb/CKAAAIIeECAwOyBRsjtKhCYc1uc+yHgFKhVq5YsXrzYsWPZsmVSvXp1RzkFCCCAAAKpEyAwp84+ZXcmMKeMnhsjYAQOHTokGRkZcvDgwRCRk08+Wfbu3St58+YNKWcDAQQQQCC1AgTm1Pqn5O4E5pSwc1MEbIF58+ZJ/fr17W1rpUGDBjJnzhxrk18EEEAAAY8IEJg90hC5WQ0Cc25qcy8EnAL9+vWT3r17O3Zoec+ePR3lFCCAAAIIpFaAwJxa/5TcncCcEnZuioAt0LBhQ5k7d669ba3om+crrrjC2uQXAQQQQMAjAgRmjzREblaDwJyb2twLgVCB48ePS5EiRWT37t0hO0444QRTVrBgwZByNhBAAAEEUi9AYE59G+R6DQjMuU7ODRGwBXQUjBo1atjb1soll1wiixYtsjb5RQABBBDwkACB2UONkVtVITDnljT3QcApoOMsd+7c2bFDx2UeMmSIo5wCBBBAAIHUCxCYU98GuV4DAnOuk3NDBGyBG264QWbMmGFvWys681/Tpk2tTX4RQAABBDwkQGD2UGPkVlUIzLklzX0QcAqUKlVKtm7d6tixbds2KVGihKOcAgQQQACB1AsQmFPfBrleAwJzrpNzQwSMwJo1a6RixYoOjcqVK8vXX3/tKKcAAQQQQMAbAgRmb7RDrtaCwJyr3NwMAVtgwoQJ0r59e3vbWunQoYOMGTPG2uQXAQQQQMBjAgRmjzVIblSHwJwbytwDAadA27ZtZfLkyY4dU6dOldtuu81RTgECCCCAgDcECMzeaIdcrQWBOVe5uRkCtkD58uVl48aN9ra1sn79etF9LAgggAAC3hQgMHuzXZJaKwJzUnm5OAIRBXbs2CHFixd37CtdurRs2rTJUU4BAggggIB3BAjM3mmLXKsJgTnXqLkRArbAtGnT5JZbbrG3rZWWLVvKlClTrE1+EUAAAQQ8KEBg9mCjJLtKBOZkC3N9BJwCHTt2lFGjRjl2jB07Vu655x5HOQUIIIAAAt4RIDB7py1yrSYE5lyj5kYI2AJVq1aVL774wt62VlatWiWVKlWyNvlFAAEEEPCgAIHZg42S7CoRmJMtzPURCBU4cOCAFCpUSI4cORKy47TTTpNff/1VTjjhhJByNhBAAAEEvCVAYPZWe+RKbQjMucLMTRCwBWbNmiVNmjSxt62VZs2aycyZM61NfhFAAAEEPCpAYPZowySzWgTmZOpybQScAo8++qgMGjTIsWPo0KHSpUsXRzkFCCCAAALeEiAwe6s9cqU2BOZcYeYmCNgCderUkYULF9rb1srixYulZs2a1ia/CCCAAAIeFSAwe7RhklktAnMydbk2AqEC2m85IyNDfvvtt5Ad+fLlk71798pJJ50UUs4GAggggID3BAjM3muTpNeIwJx0Ym6AgC2wYMECqVu3rr1trdSrV08+/PBDa5NfBBBAAAEPCxCYPdw4yaoagTlZslwXAaeA9l3WPszhS69evaRv377hxWwjgAACCHhQgMDswUZJdpUIzMkW5voI/L9A48aNZfbs2f9f8Nfa3Llz5aqrrnKUU4AAAggg4D0BArP32iTpNSIwJ52YGyBgCxQrVkx27txpb+uK/h3U8Ze1bzMLAggggID3BQjM3m8j12tIYHadlAsiEFFg5cqVUq1aNce+iy++WJYuXeoopwABBBBAwJsCBGZvtktSa0VgTiovF0fAFhg1apR07NjR3rZWHnroIRk+fLi1yS8CCCCAgMcFCMweb6BkVI/AnAxVromAU+Dmm2+W1157zbFjxowZcv311zvKKUAAAQQQ8KYAgdmb7ZLUWhGYk8rLxRGwBcqWLSubNm2yt62VrVu3yplnnmlt8osAAggg4HEBArPHGygZ1SMwJ0OVayIQKrBhwwY599xzQwv/3Dr//PPl22+/dZRTgAACCCDgXQECs3fbJmk1IzAnjZYLI2ALTJ48Wdq2bWtvWyt33XWXPP/889YmvwgggAACPhAgMPugkdyuIoHZbVGuh4BTQIPxxIkTHTs0SLdu3dpRTgECCCCAgHcFCMzebZuk1YzAnDRaLoyALaBdL9auXWtvWyvaVeOcc86xNvlFAAEEEPCBAIHZB43kdhUJzG6Lcj0EQgV0UpKiRYvK8ePHQ3YUL15ctm/fHlLGBgIIIICA9wUIzN5vI9drSGB2nZQLIhAioMPG3XDDDSFluqHDzL366quOcgoQQAABBLwtQGD2dvskpXYE5qSwclEEbAGdmOTpp5+2t60Vncjk/vvvtzb5RQABBBDwiQCB2ScN5WY1CcxuanItBJwCOvX18uXLHTt0quyLLrrIUU4BAggggIC3BQjM3m6fpNSOwJwUVi6KgBH4/fffJSMjQw4fPhwiUqBAAdm9e7fkyZMnpJwNBBBAAAHvCxCYvd9GrteQwOw6KRdEwBaYO3euNGzY0N62Vho3bizvvPOOtckvAggggICPBAjMPmost6pKYHZLkusg4BTo1auXPPHEE44dgwYNkh49ejjKKUAAAQQQ8L4Agdn7beR6DQnMrpNyQQRsgXr16sn8+fPtbWtlwYIFctlll1mb/CKAAAII+EiAwOyjxnKrqgRmtyS5DgKhAkePHpVChQrJ/v37Q3bkzZtX9uzZI/nz5w8pZwMBBBBAwB8CBGZ/tJOrtSQwu8rJxRCwBRYvXiy1atWyt62VOnXqyMcff2xt8osAAggg4DMBArPPGsyN6hKY3VDkGgg4BYYOHSrdunVz7Hj00UdlwIABjnIKEEAAAQT8IUBg9kc7uVpLArOrnFwMAVugWbNm8r///c/etlZmzZoljRo1sjb5RQABBBDwmQCB2WcN5kZ1CcxuKHINBJwCJUqUkO3bt4fs0L9vO3bskCJFioSUs4EAAggg4B8BArN/2sq1mhKYXaPkQgjYAqtWrZIqVarY29ZK1apVZcWKFdYmvwgggAACPhQgMPuw0XJaZQJzTgU5HwGnwNixY+Xee+917OjYsaOMHDnSUU4BAggggIB/BAjM/mkr12pKYHaNkgshYAu0bNlS/vOf/9jb1sq0adPkX//6l7XJLwIIIICADwUIzD5stJxWmcCcU0HOR8ApcO6558qGDRscOzZt2iSlS5d2lFOAAAIIIOAfAQKzf9rKtZoSmF2j5EIIGIHNmzdLmTJlHBrly5eX9evXO8opQAABBBDwlwCB2V/t5UptCcyuMHIRBGyBqVOnSqtWrexta6Vt27YyadIka5NfBBBAAAGfChCYfdpwOak2gTknepyLgFOgQ4cOMm7cOMeOCRMmSLt27RzlFCCAAAII+EuAwOyv9nKltgRmVxi5CAK2QOXKleWbb76xt62VNWvWSIUKFaxNfhFAAAEEfCpAYPZpw+Wk2gTmnOhxLgKhAnv27DGTkhw7dixkh05UohOWhP99CzmIDQQQQAABXwgQmH3RTO5WMvx/wI8fP+7uDbgaAgESeOutt6R58+aOJ77hhhtk+vTpjnIKEEAAAQT8J0Bg9l+b5bjGBOYcE3IBBGyBrl27yrBhw+xta2XEiBHSqVMna5NfBBBAAAEfCxCYfdx4iVadwJyoHOch4BS45JJLZMmSJY4dy5Ytk+rVqzvKKUAAAQQQ8J8Agdl/bZbjGhOYc0zIBRAwAn/88YdkZGSI/mZe8ufPL9q3OW/evJmLWUcAAQQQ8KkAgdmnDZeTahOYc6LHuQj8v8C8efOkfv36/1/w11rDhg3lvffec5RTgAACCCDgTwECsz/bLUe1JjDniI+TEbAF+vXrJ71797a3rRUt79mzp7XJLwIIIICAzwUIzD5vwESqT2BORI1zEHAKNGjQQN5//33HDn3zfMUVVzjKKUAAAQQQ8KcAgdmf7ZajWhOYc8QXuJN12MFNmzbJzz//LNu2bZOffvpJvvvuO7Ot+3T653r16gXORcdd1rGWta9y5iVPnjyye/duKVCgQOZi1hFAAAEEfCxAYPZx4yVadQJzonLBPG/v3r3SsWPHLB9+0KBBcuaZZ2a5P1136CgYNWrUcDxerVq15NNPP3WUU4AAAggg4F8BArN/2y7hmhOYE6YL5In6FllD8/bt22XOnDny2Wef2Q6FChWSZ555xt4O0oqOs9y5c2fHI+u4zEOGDHGUU4AAAggg4F8BArN/2y7hmhOYE6YL/Ikalp977jnb4dJLL5V77rnH3g7SSosWLeSNN95wPLLO/Ne0aVNHOQUIIIAAAv4VIDD7t+0SrjmBOWG6wJ84efJk+fDDD22Hu+66S+rUqWNvB2lFu6Fof+7wRd/EFy9ePLyYbQQQQAABHwsQmH3ceIlWncCcqBznde/e3Xz4Z0kMHz5cihYtam0G5nfNmjVSsWJFx/NWqVJFvvrqK0c5BQgggAAC/hYgMPu7/RKqPYE5IbbAn7Rr1y556KGHbIcSJUoEtq/uhAkTpH379raFtdKhQwcZM2aMtckvAggggECaCBCY06Qh43kMAnM8WhxrCSxcuFCef/55a9MMJadDygVxadOmjbz00kuOR586darcdtttjnIKEEAAAQT8LUBg9nf7JVR7AnNCbIE/afz48fLJJ5/YDg888EDEYdXsA9J4pXz58rJx40bHE2pZuXLlHOUUIIAAAgj4W4DA7O/2S6j2BOaE2AJ/UqdOneTXX381Dvpn6Nlnn5WCBQsGzkU/6tPuKOFLmTJl5Pvvvw8vZhsBBBBAIA0ECMxp0IjxPgKBOV4xjtfRIHr06GFDlC5dWp544gl7O0gr06ZNk1tuucXxyC1btpQpU6Y4yilAAAEEEPC/AIHZ/20Y9xMQmOMmC/wJH3zwQUif3WuuuUZuvfXWQLpoV5TMY1FbCGPHjg3smNSWAb8IIIBAugoQmNO1ZaM8F4E5Cg67IgqMHDlSli9fbu/TGe4uuugieztIK1WrVpUvvvjC8cirVq2SSpUqOcopQAABBBDwvwCB2f9tGPcTEJjjJgv0CTo19v333y8HDhwwDieeeKKMHj1aTjrppMC57N+/X3Q68KNHj4Y8u5bt3LlTTjjhhJByNhBAAAEE0kOAwJwe7RjXUxCY4+IK/MHfffed9OnTx3aoUKGCPPbYY/Z2kFZmzZolTZo0cTxys2bNZObMmY5yChBAAAEE0kOAwJwe7RjXUxCY4+IK/MEaEvVDN2u57rrr5Prrr7c2A/X7yCOPyODBgx3PPHToUOnSpYujnAIEEEAAgfQQIDCnRzvG9RQE5ri4An+whsGvv/7adnj00Ufl/PPPt7eDtFKnTh3RCVzCl8WLF0vNmjXDi9lGAAEEEEgTAQJzmjRkPI9BYI5HK9jHHjlyRO677z75448/DIT2W9b+y9qPOWjL4cOHJSMjQ37//feQR1eTvXv3Sr58+ULK2UAAAQQQSB8BAnP6tGXMT0Jgjpkq8Ad+++23MmjQINvhggsuCGzXgwULFkjdunVtC2ulXr168uGHH1qbSfvVwK6Tpuzbt09KlixpPj5M2s24MAIIIIBAiACBOYQjGBsE5mC0sxtPOWPGjJCP2W6++WZp3Lhx3JfWN9U6S2Dx4sXjPldPOHTokBnKrUaNGgmd78ZJAwcOjPixY69evaRv375u3CLiNZYtWyZvvvmm/PDDD6IjlliLjszRqlWrwE5PbjnwiwACCOSGAIE5N5Q9dg8Cs8caxMPV6d+/v6xbt86uoQbDsmXL2tuxrkyfPl3+97//yYgRI6RIkSKxnib6VnX+/Pny9ttvy+7du2Xy5Mkxn+v2gfoPhdmzZzsuO3fuXLnqqqsc5Tkt0IA8ceJE2bhxo7mUjv98ySWXmO05c+bYl0/0HzH2BVhBAAEEEMhWgMCcLVH6HUBgTr82TcYTHTx40PRftsYcLlCggIwaNUrC//xkd+8dO3aYabU1/OpIEtqtI7tF30h/9NFHJmTrm2lrSVVg1je7RYsWNW/Jrbror467rPU77bTTMhfneP37778X/dhSx33W5V//+lfIcHZDhgwRnShFF+1D/dRTT0nBggXNNv+FAAIIIOC+AIHZfVPPXzE88GT+v3k9X3kqmGsCOpvd8OHD7ftpdwidFjreRUP20qVLzWk6nbZOqx1t2bVrlwwYMMC8idYw+ssvv9iHpyowr1y5UqpVq2bXw1q5+OKL7WezynL6q2+Uhw0bZk8U07RpU7nxxhtDLqtv3SdNmmSXNW/eXFq0aGFvs4IAAggg4K4AgdldT19cjcDsi2ZKeSVfeeUVeffdd+16tGnTRurXr29vx7IS/tHg5ZdfLnfeeWfUU3VEDp1VULtuaFjOPL5xqgLzs88+K//+978d9X7ooYdC/lHhOCDOgvXr15uwbI3EoW/jH374Ycdb/TVr1oj2qbaWIH+MaRnwiwACCCRTgMCcTF2PXpvA7NGG8Vi1evbsKZs3b7Zr9eSTT5rRGbTg5ZdfNiFOPzrLatH/56J3796yadMm+5Bzzz1X9LqxLto1o127dvbhqQrM2k/4tddes+threhHkW5N4qJD0+nEKFY3jJNPPtmEYu0KEr5ou2R2PPPMM0NGMwk/nm0EEEAAgZwJEJhz5ufLswnMvmy2XK20Dl3WsWNHe1QGfdurH+zpot0rtJvFTTfdJNdee22W9dI+yC+88IJUqlRJvvnmG3Nc/vz5ZezYsVmeE77DK4G5dOnSsmXLlvDqyU8//WT/I8KxM84CHd96yZIl9lnRuq+Ev7nXfszjx4+3z2UFAQQQQMBdAQKzu56+uBqB2RfNlNJKap9dKyBrRS699FK555575Mcff5R+/fpJqVKlRGf804/eIi3apaBbt25SrFgxuf3220OGXYtnpAwvBOYNGzaIvhkPX3S2Qw2ubizLly+XkSNH2pfSIeO0H3PevHntsswrOtScdhOxFv2HyJgxYxxdN6z9/CKAAAII5EyAwJwzP1+eTWD2ZbPlaqV1qLQpU6bY92zUqJFUqVJFnn/+eTPUmw4vF21M5VdffdUMwfb444+Lvp3VsG19XNq1a1dzLfviUVa8EJhffPFFueOOOxy1vOuuu4yHY0ecBdpfW//xocPmWcttt90mV199tbXp+J03b55ovazllFNOMYHZ2uYXAQQQQMBdAQKzu56+uBqB2RfNlNJKfv755/LMM8846qD/17++OY70xtU6+OeffzYBsHr16mZYOi3XkKyz1OmSXRg0B/31X14IzBqMdTzk8EX7U7du3Tq8OO5tvfbHH39sn6dD1OkwcdGm2tYxrXVsa2vRmf+0jzkLAggggEByBAjMyXH19FUJzJ5uHk9UTkeq0D7M+mst+mGZjnBx3nnnWUURf59++mn5+uuvZfDgwaZLhh6kZStWrDDHxzJShnVhLwRm7Xqxdu1aq0r2rw7/Vq5cOXs7kZU9e/aIjrRhjXWt17jllltE3+hHW8aNGyeffvqpfYjWUd9SsyCAAAIIJEeAwJwcV09flcDs6ebxTOW0q4B+hKbTUmtY1i4ZWfVZtiqtk2nopBr6MaB+FGgt1kx/uh3PSBmpDsw7d+40XU+s7iTW85QoUUK2bdtmbSb8O2vWLJk2bZp9vr7B1zf72ic52qJv+fVNvrUkOka2dT6/CCCAAALRBQjM0X3Sci+BOS2bNeUPdezYMTPUmY6woaFZh0WzlkWLFtmjY8TT3zbVgfn11193TBqiz6TDzGk/7ZwuOoycfkhpLZdddpm0b9/e2oz4q77hE8g0aNBAog3xF/FCFCKAAAIIxCxAYI6ZKn0OJDCnT1t66Uk++OADeemll8yEIzVr1gypms7el3nINO2iUbhw4ZBjIm2kOjBrdwmta/iiw+rdf//94cVxbevoGzriSOZF3xxXrlw5c5FjPXwEEz3gvvvuk3Bzx4kUIIAAAggkLEBgTpjOvycSmP3bdl6tuXbf0LCnfZ61W0GkxZqQQ/fFOlJGqgOzTn2tQ76FLzpt+IUXXhheHNe2jnKho11kXs4666xsu72oo04Zbi3691mHpNOPBVkQQAABBJIjQGBOjqunr0pg9nTz+LJyU6dOlTlz5kj37t3NRCWRHqJz586ifYJ1iXWkjFQG5t9++00yMjJE65B5KViwoAmsefLkyVwc17p+5KfdKvQeOV3OPvts6d+/f04vw/kIIIAAAlEECMxRcNJ1F4E5XVs2Nc+lfXB1vOWKFSuat8xZ1UL7NetHgbrEOlJGKgOz/gMg0ljIjRs3lnfeeSerx4ypPHxqaz2pRYsWUq9evajn6xv8Ll26hBxzzTXXiM4KyIIAAgggkDwBAnPybD17ZQKzZ5vGlxWzgnCfPn2iDrP28ssvy/vvv2+eMdaRMlIZmHv16iVPPPGEo00GDRokPXr0cJTHU7BgwQKZMGFCyCn6lljfFkdbwmf402O1Ln//+9+jncY+BBBAAIEcChCYcwjox9MJzH5sNW/WeenSpaIfwF100UWiXS6iLZlnD9QRNMaOHZvtVM6HDx8WnTjEWnSykNxa9G3v/PnzHbdbuHCh1K5d21EeT4HOoqge1qJTYUeaKMbab/2qtZpbi05RPmDAAGuTXwQQQACBJAkQmJME6+XLEpi93Dr+qZtOuqFdMfbu3Wumvr700kujVj78rapOr122bNmo5/z0008hb3PHjx+f5UeFUS8U5059s60hVj9mzLzo7Hv63JmHzMu8P9Z1/Ugv88eEtWrVkg4dOkQ9XT/269Spk5ma3DqwXbt2UrduXWsz6q8+y5o1a6Rq1arZflgY6UK//PKLaBtef/312f5DJ9L5lCGAAAJ+FiAw+7n1Eqw7gTlBOE6zBTTIjhkzRjZt2mTKdAxg7Zec1XTOOqqDHq+BzVp0lAkNiaeeeqpVFPKrE4PoMHVWv2fd2aRJE2nevHnSQ7OOGx3pHwB16tQJmcY6pMJxbOgsiKtXr7bP0Jn9dIa/aMsbb7whb775pn2IjooxfPhwyZs3r10WbeWFF16Qjz76yMzAeMYZZ0Q7NGTfjh07RKfi1jfr+g+JSZMmJRS4Qy7KBgIIIOAzAQKzzxrMjeoSmN1QDO419A2rTsMcPvudBrdI3Qo0qGnf20iL/lnUj9jCp5jW6+/evTvSKebtZsmSJc0kKREPcKFw6NChET9g1Hq50QVC+0db/9jQ6upEKPoxYVaLfuynXV4yD82nHwnqPx5iWfRe2sdcJ5fRKc91uLzsFh07W4Pyxx9/HDJSCIE5Ozn2I4BAOgoQmNOxVbN5JgJzNkDsDrxAs2bNTFgMh5g9e7boqBQ5XcKnttZ+2vr2Oqvl3XfflVdeecXeffrpp5vgntUbffvAv1YGDhxov92PJWjrP4q0y4z2Tdc3zF9++aV9SQKzTcEKAggESIDAHKDGth6VwGxJ8ItAZIHixYuboJh5r/690XGkY5mhMPN5kdZ19I3169fbu7RrivZjjrRoNwh9C595spJo412HX8P6MNMq1xkBdWbA7Bb9fxD0mcOn4iYwZyfHfgQQSEcBAnM6tmo2z0RgzgaI3YEW+Prrr+WCCy5wGOjHcitWrHCUJ1IwevTokKnC27RpI/Xr1494qfC+y5dddpm0b98+4rHhhTrKyCOPPCL6wZ61xDvRiQbntm3bWqfTh9mWYAUBBIIkQGAOUmv/9awE5gA2Oo8cs4AOd3fvvfc6jte+vzq6hRvLtGnTZNasWfalrrvuOjP6hF3w18oPP/wgvXv3tvsQn3nmmWZkkqw+lAw/X/sgT58+3XyQqR/86XLiiSfK888/H/OHewTmcFW2EUAgiAIE5gC2OoE5gI3OI8cs0LJlS/nPf/7jOP61116Tm266yVGeSIF2x8g8KUrlypUdHxlqV4h+/frJ9u3bzS2KFCliPnTU31gW/WhS+0rrDIw6E2DmyVZ0lI5YR8ogMMeizTEIIJDuAgTmdG/hCM9HYI6AQhECfwnoiB3ff/+9w2PLli2iE4W4tehoG2vXrjWX04/3nnzySbHCsIZdHXFk48aNZr+Wd+3aVfQNc6yLvkXW4fH0PiVKlDDdOLQ/tC6xjpShxxKYVYEFAQSCLkBgDuCfAAJzABudR45JQIdfKxthMpXy5cuHfKQX08WyOei7776TYcOG2UPFnX/++XLttdeKjnGtXSn0DbMu+pGe9nGOtRuGnqNBW99OX3nllXL77bdrkenKoaFfl1hGyjAH/vlfBGZLgl8EEAiyAIE5gK1PYA5go/PIMQlMnTpVdBKW8EU/etPRIdxetLuF9pnW8KxjJFuL9jP+xz/+YfoeV6lSxSqO6VcDbv/+/U3wHjJkiBQoUMCcp/fRN866XHLJJRH7aZudYf9FYA4DYRMBBAIpQGAOYLMTmAPY6DxyTAI6vNu4ceMcx06cOFHuvPNOR7lbBb///rsJzUePHpWiRYtKsWLFspw1Mbt7aijWcHzbbbfJ1VdfbR/+9ttvy3//+1+zHc9IGQRmm5AVBBAIsACBOYCNT2AOYKPzyDEJ6Md333zzjeNYndK7QoUKjnKvFRw6dEh0jGbtE62TleTJk8euog6J9/TTT5ttnZVx/PjxMY2UQWC2CVlBAIEACxCYA9j4BOYANjqPnK2AfminH9dpQMy86NvezOMYZ97ntXVrzGYNzOEB/8CBA+YttlXnWEfKIDBbYvwigECQBQjMAWx9AnMAG51HzlbgrbfekubNmzuOu+GGG8xYxo4dHivYtWuXebt82mmnic5UGGnRUTm024cusY6UQWCOJEkZAggETYDAHLQW//N5CcwBbHQeOVsBHbZNR60IX7Qbw4MPPhhe7Llt7be8ePFiMzpG6dKlI9ZPZ/378ccfzT79h0CzZs0iHpe5kMCcWYN1BBAIqgCBOYAtT2AOYKPzyNkK6MgRS5YscRy3bNkyqV69uqPcSwX65ljHW85u9Asd2/nzzz83Vc/uWOv5CMyWBL8IIBBkAQJzAFufwBzARueRowocPHhQMjIyRD+ay7zo2Mfat1mHefPqosPR6fTZW7dulUGDBplJSrKqq85W+M4775jdsY6UQWDOSpNyBBAIkgCBOUit/dezEpgD2Og8clSBefPmSf369R3HNGzYUN577z1HuZcK5s6dK1OmTMn27bLW+eOPPxYdIk8XHUFDu3HoB4LRFp0dsF27dvYhOh71CSecYG+zggACCARBgMAchFYOe0YCcxgIm4EX0Fnx9C1t+PLEE0+YGfLCy72yrf2Rtd76ZjyWj/jmz58fMgGL9tvObmIUnSY8s83IkSPN23ivGFAPBBBAIDcECMy5oeyxexCYPdYgVCflAg0aNJD333/fUQ9983zFFVc4ylNdoN0wtC/yyy+/bLqMaH30DXndunWlXLlyjurt2bNHNm/eLK+88orpumEdUKpUKTOzoU79Hf6mWYfS06nCZ8yYEXJOtWrVzBTeOsFK4cKFrUvxiwACCKS1AIE5rZs38sMRmCO7UBpMAR1mTYPfvn37QgC037IGzVNOOSWk3Asbv/32m+ib3khLjx49HMUzZ86U1atXO8qtAp0VMHxkDb2+3ierJX/+/L4YPSSr+lOOAAIIxCNAYI5HK02OJTCnSUPyGK4I6CgYNWrUcFyrVq1a8umnnzrKKUAAAQQQCJ4AgTl4bc44zAFscx45a4ERI0ZI586dHQd069ZNnnzySUc5BQgggAACwRMgMAevzQnMAWxzHjlrgRYtWohOKR2+6Mx/TZs2DS8O2dZ+vhs3bpSaNWuGlLOBAAIIIJBeAgTm9GrPmJ6GLhkxMXFQQATOOOMM2bZtW8jT6t+R7du3S7FixULKdUM/hHvzzTfNx3CffPKJPPzww7yJdihRgAACCKSXAIE5vdozpqchMMfExEEBEFizZo1UrFjR8aQ61NpXX31ll69atcq8hdY30dZMedZOHZe4bdu21ia/CCCAAAJpKEBgTsNGze6RCMzZCbE/KAITJkyQ9u3bOx733nvvFe3b3LdvX5k+fbqsW7fOcYxVsGjRIjNpiLXNLwIIIIBA+gkQmNOvTbN9IgJztkQcEBCBNm3ayEsvveR42qlTp4oOtbZw4UIzTrF2w8hqufTSS83watoX2stTaD/++OPSqFEjqV27dlaPQjkCCCCAQBYCBOYsYNK5mMCczq3Ls8UjcM4558h3333nOEVntytTpowp17GYO3ToIK+++qrjuMwFZ599tgwcOFBatmzp+LA283GpWNd+1sOHD5eCBQvK7NmzCc2paATuiQACvhYgMPu6+RKrPIE5MTfOSi8B/dBPP/gLXzQoa2AOX/RN9AMPPBAywcnll18ut9xyi4waNUq0n7MuOqbz+PHjpWrVquGXSMl2r169RKf4thYNzXPnzmVkDwuEXwQQQCAGAQJzJQiWfwAABC1JREFUDEjpdgiBOd1alOdJRGDatGkm7Iaf26pVKzPldHi5busQctpVY8mSJWa39nUePXq0HD9+XKZMmSKPPPKImUZap5nWt806vnP437dI101mmX6keNVVV8mvv/5qbqMfOeqU3yVLlkzmbbk2AgggkFYCBOa0as7YHib8f8D1f+xZEAiagL4tfu655xyPPXbsWLnnnnsc5VbBkSNHzMeAGoiffvpp6dixo7XLTCXdvXt388ZZCxs3bmy6cuhb3VQuVmguUaIEYTmVDcG9EUDAtwIEZt82XeIVJzAnbseZ6SNw0UUXyZdfful4IO1aUalSJUd5eMGCBQvk1FNPlX/84x/hu2TWrFlmqDmd2ETv884778hZZ53lOC5ZBfoGPHwylZUrV5q3yrxZTpY610UAgXQWIDCnc+tm8WwE5ixgKA6MwN69e6Vw4cJy7NixkGfWsp07d7rSjUK7bzRp0kS+/fZb0Q8CNWBbHxKG3NTlDf3AT4fE037Ud911l8tX53IIIIBAMAUIzAFsdwJzABudRw4R0DfAGmbDl+bNm5tZ/MLLE93WfsM6vbbOCHjeeeeZ0KzdIpK1WKNh6PX17zmhOVnSXBcBBIImQGAOWov/+bwE5gA2Oo8cIqAf5w0ePDikTDeGDh0qXbp0cZTnpEDfZtevX1+WL19uumfom+Zk9GneunWrGZljx44ddnW1a8mKFStEP0JkQQABBBBIXIDAnLidb88kMPu26ai4SwKXXXaZeesbfrnFixc7+v6GH5PItobYunXryurVq804zTqiRjIW7ZN95ZVXit6P0TCSIcw1EUAgqAIE5gC2PIE5gI3OI9sChw4dkoyMDDl48KBdpiv58+eX3bt3J+1trE6vrR8I7t+/XyZPniytW7cOub9bGxqadQSQ1157jaHj3ELlOgggEHgBAnMA/wgQmAPY6DyyLaBdIvRtb/ii3SY++OCD8GJXtzUot23bVgoUKCDffPON+RgwJzfQ7iM6W+F9992Xk8twLgIIIIBANgIE5myA0nE3gTkdW5VnilVAx09+7LHHHIfrjHh9+/Z1lLtdcNNNN8n06dPNG2YN0Iku1gd++vdZZxokNCcqyXkIIIBA9gIE5uyN0u4IAnPaNSkPFIdAo0aN5N1333WcodNF64x4yV502m3tX6xdQ/RDwGrVqsV9Sw32ffr0sc/Tv9Mvv/yy6R9tF7KCAAIIIOCaAIHZNUr/XIjA7J+2oqbuCui4y0WLFjV9lTNfOU+ePGbq6GSMXpH5PtZ6t27dzIgcOrTd22+/bRXH/KvdOerVqyfbt2835/CBX8x0HIgAAggkJEBgTojN3ycRmP3dftQ+cQGd7S7SG90aNWrIZ599lviF4zxz165dZuY/fcu8YcMGKVu2bJxXENMHWkNzkSJFmO46bj1OQAABBOIT+D8AAAD//3RKedsAAEAASURBVO2dCdxV0/rHnz+NRGWoDClTCZmJSEmozMMNl5B5limKUBo0IJWUSjKWIZJkiszXVBlK0kSKkITm4n9/696973nP8L7nvGfc+3zX5/O291577bXX+j7Hx++s86zn+b+//12MUlQE/u///q/EfPkIlMDBRYgJDBo0yK6++uqYGV577bV2zz33xNRns+Lcc8+1Rx55xDp37my9evUq81Vvv/22HX744SXaffXVV1azZk2rU6dOiXouIAABCEAgswT+D8GcWaBB6A3BHAQrMcZsEGjXrp09/fTTMV2PGzfOTj755Jj6bFZ88MEH1rRpU9tmm21s0aJFFv3fZeS7r7/+eifo7733XuvYsWPkLc4hAAEIQCAHBBDMOYBcaK+I/h8zK8yFZiHGky0C22+/vROn0f3/+OOPVrt27ejqrF/Xq1fPvvvuO5s+fbrtvffecd/niWXvJqLZI8ERAhCAQO4IIJhzx7pg3oRgLhhTMJAcEpg7d67tsssuMW/cbbfdTK4N+SgXXnihjRw50vr162c33HBDzBCWLFli++67r/3www/+vUaNGtnUqVOtSpUqfh0nEIAABCCQXQII5uzyLcjeEcwFaRYGlWUCDz/8sHXo0CHmLRKtw4cPj6nPRcXYsWPtjDPOsNatW9ukSZPivnL27NnWokULJ5ol7t988018luOSohICEIBA9gggmLPHtmB7RjAXrGkYWBYJXHDBBfbQQw/FvGH06NF2zjnnxNTnomLevHm28847W61atUyryYmKRPNll11mjz/+OGI5ESTqIQABCGSRAII5i3ALtWsEc6FahnFlk0DDhg1NwjO6SLTuuOOO0dU5ud6wYYNVrVrV1q1bZ7/++quLeCHXDAnoTp065WQMvAQCEIAABMomgGAum1HoWiCYQ2dSJlQGgZ9//tmJ0OhmilCxePHi6OqcXsvN4uuvv7bPPvvMtNrthbfr06cPojmnluBlEIAABBITQDAnZhPaOwjm0JqWiSUg8Oyzz9ppp50Wc/f000+3MWPGxNTnsqJ58+amGMvnn39+jMuIfKvlY02BAAQgAIH8EkAw55d/Xt6OYM4Ldl6aRwKKXXzffffFjGDw4MF2xRVXxNTnsqJVq1Y2efJkGzZsmN155532/fffu9ezwS+XVuBdEIAABEongGAunU8o7yKYQ2lWJlUKgQMOOMA+/fTTmBZyg9hrr71i6nNZ0aZNG3v55Zdt/Pjxtscee7iIGNWqVSMaRi6NwLsgAAEIlEEAwVwGoDDeRjCH0arMKRGBFStWWI0aNWz9+vUlmlSvXt1ttNtoo41K1Ofy4vXXX7e77rrLrTBLNB9zzDGmTYibbLIJ0TByaQjeBQEIQKAMAgjmMgCF8TaCOYxWZU6JCLz66qtOiEbfb9u2rU2cODG6OmfXXga/rbfe2rQp8aOPPrIDDzwwZ+/nRRCAAAQgkDwBBHPyrELTEsEcGlMykSQIdO3a1Xr06BHTsnfv3nbzzTfH1OeiwhPLke9atGiRbbvttpFVnEMAAhCAQIEQQDAXiCFyOQwEcy5p8658EzjiiCNsypQpMcN499137dBDD42pz3bF0qVLTT7VCxYs8F9Vs2ZN++6770y+yxQIQAACECg8AgjmwrNJ1keEYM46Yl5QIASUEET+yytXriwxosqVK9vy5ctNx3yUb7/91m3uk2gmGkY+LMA7IQABCKRGAMGcGq9QtEYwh8KMTCIJAh988IE1bdo0pmWzZs1c7OOYGzmskGi+9NJLbdSoUWzwyyF3XgUBCECgPAQQzOWhFvBnEMwBNyDDT5pA37597aabbopp36VLF+vZs2dMfbYq5LOsyBeKs0yBAAQgAIHgEUAwB89maY8YwZw2QjoICIETTjjBJkyYEDPaSZMmWevWrWPqs1ERucHv1ltvRTRnAzJ9QgACEMgyAQRzlgEXYvcI5kK0CmPKNIG///7bFLJNm+wii+Iu//rrr6Y4zNkuirHcuXPnEq9RxsGrr766RB0XEIAABCBQ2AQQzIVtn6yMDsGcFawxnf71118mP1Vt7NJx2bJltmrVKvcnMSfBpugI2pQmYbfjjjva9ttvb+VJpKGkHBUqVIgZQzFXfPnll9a4ceMYBPvss49NmzYtpj4bFUpz3aJFC5s7d67rng1+2aBMnxCAAASyTwDBnH3GBfcGBHN2TfLbb7+5zG3vvPOOE8mpvK1SpUpWr149J5532mkn01/t2rUTdqFQZEqprBTPiiss4U35D4EHHnjALr/88hgcV111lQ0cODCmPlsVnmiuWLEi6a6zBZl+IQABCGSZAII5y4ALsXsEc/asoni/Y8eOLRHGTLy1mrzVVlu51WO5CEhUb9iwIamBKDavVp632GILtyKtzWM//PCDW7mWGNOKdMuWLa1du3Z5C5OW1ERy3Oiss86yJ554IuatTz31lP3jH/+Iqc9UhbIHHnvssSW6k530C0CdOnVK1HMBAQhAAALBIIBgDoadMjpKBHNGcfqdPf/88/bcc8+564033tiaNGliRx99tNWtWzfGXULuGj/99JN98803NmfOHHdcvHixyVUjlaLV6A4dOrgV6VSeK4a2YqMV+OiSzYx63ga/Tp06WZ8+faJfzTUEIAABCASUAII5oIZLZ9gI5nToxX9W8X6HDh3qbu6xxx524YUXuhXh+K3j1yq5hnxdJaD1J7H3xx9/xIhorSjLF1bxhZWprjw+z/FHEJ5a+YzXr18/ZkI777yzYxtzIwMVnlj2ukI0eyQ4QgACEAg+AQRz8G2Y8gwQzCkjK/WBtWvXuqgH2tAnkaaoCFWqVCn1Gd385Zdf7Ouvv3ZpkqMzzmml+aGHHnIRHrSCrA2Da9ascS4Z8lOObl/my4qswWOPPWbt27ePmfV5553nEoXE3EizQlkD9YuC7OkVfan58MMPbfPNN/eqOEIAAhCAQEAJIJgDarh0ho1gTode7LMSRUOGDHErvffee6+LehHbKrZGgvj999+3+++/v4QAlrvGiBEj7L333nMiLN7GtdjeqIkkoAx6w4YNi6xy5yNHjrTzzz8/pj4TFfIrP+KII5xoJhpGJojSBwQgAIHCIYBgLhxb5GwkCObMoh40aJB98sknLrpF9+7dk+pcq9HXXHONNWzY0PRTvlcklh988EGTi4d8n7t27VpCTHvtOJZOQG4xM2fOjGk0e/Zs23XXXWPqM1Uh0XzZZZc59xw2+GWKKv1AAAIQyD8BBHP+bZDzESCYM4tcolb+xlpd1E/+yZTJkyfbI4884jbsKU6visSy/KC1Yi0b3XHHHc7Fw93kn6QJKCmJIpJEb6CsVauWLVmyJOl+ymqoLzqKdDJgwICymnIfAhCAAAQCTgDBHHADlmf4CObyUEv8jITt/Pnz7aCDDrIrrrgiccP/3pG/q1Ika0Ofsr55Gefk1iGxrHLIIYeY3AooqRNQXOqTTjop5sFTTz3VnnnmmZj68lREbvDTLwWI5vJQ5BkIQAACwSGAYA6OrTI2UgRzxlC6jjyhq814/fr1c6vDid6gVc977rnHPv/8c2vevLnvT+utOHvP9erVy7bbbjvvkmMKBG688Ubr379/zBMStRK36Rb1rXdEFqXAvummmyKrOIcABCAAgRARQDCHyJjJTgXBnCyp5Np5m/7U+rTTTrPjjz8+7oOKpjFmzBiXBVDiukePHi6ahuIv33777ab7KkqRrVXreEWCO9p+8doVc93BBx/sr9RHcvj0009tv/32i6wq17niZ8v9xvORZoNfuTDyEAQgAIFAEUAwB8pcmRlstOCK9vXMzFuKpxf5Hsu1Yvr06aaEJcrydtxxx/mb9SSEtdns0UcftR9//NG1ufnmm61BgwYOklJaz5o1ywd29tln21FHHeVf60Qibdy4cSbRt//+++OuUYLO/y60mVIuLuvWrftf5b/PlC1R2RVln0wUTzTL9m+++SYZ/DIBlT4gAAEIFDABBHMBGydbQ0MwZ57s+vXrTdEyJJpVFCe5du3abtVY4krCSkWrxwprtsMOO7jrL7/80rlxuIt//6P0yXId2GyzzbwqF69ZLhpKqa2iuL56FyWWwBtvvGFHHnlkzA1lXHzllVdi6pOt0JeVk08+ucTqvmdXomEkS5F2EIAABIJLAMEcXNuVe+QI5nKjK/VBieZ3333XpkyZYgsXLjRdi7XcL+SPvOeee1rLli1LZObr1q2bzZs3z+933333tQsuuMCJZAlkJTeRf7PEmVe0oU3ijRJLQGH95N4SXe6880630TK6Pplrb4OfwsUpZnb0fz/J9EEbCEAAAhAINgEEc7DtV67RR/8PH5eMcmEs9SExVTSMTTbZxCpVqhS37RdffBF3c1rcxv+uVArstm3bmqI9kA47PiW5srz++usxN/UlRpssUy2eWPaeQzR7JDhCAAIQKC4CCObisrebLYI5v0aXe8a0adNciDNt+EumbLrppi79tjaYUeITUEzkGjVq2J9//lmiQcWKFd2Xl6pVq5aoL+tC/Rx66KEuoonXVvyVVEbvoUAAAhCAQPEQQDAXj639mSKYfRQ5PVm5cqW9/fbbbgX0559/jvvumjVrOhcOHVWIyxwXU9zKjz/+2MXCjr6pmNZKQV6eIpcY+UQrDCDRMMpDkGcgAAEIhIMAgjkcdkxpFgjmlHCl3XjZsmX2wgsv2HvvvWdr1qxJ2J9+/t9rr738+4qs0bNnT3eN37KPJeHJvffea9ddd13M/U6dOlmfPn1i6hNVRIfuk2i+/PLLbeDAgUTDSASNeghAAAIhJ4BgDrmB400PwRyPSubrJLwUcuypp54yhTtTkXuAwp5JhEWWbbfd1hQJI9I2b731lj300EOuWZs2beyMM86IfCTv53KByFSYtkxM5pRTTrHnnnsupqsJEya4MH8xN+JU6EuLfM+HDx9ewhZxmlIFAQhAAAJFRADBXETG9qYaKcpUx6Y/j0zmjoq9PHjwYPvss89cp4qUodBmTZs2dfVfffVViZedd955LhlGZKWEnlI5KzydomLItSBTRa4h77zzjnXp0iVlYSi/6+eff97mzJnjshZmakzp9iNOkdFE1J8+6/pyssUWW5TZfeQGP0UqQTSXiYwGEIAABIqGAIK5aEz9v4kimP/HIp2z6J/uvb608qpUyXKp0EYzZf475phjXIxlxWmW60BkkZhW8hKtPkeW77//3oWmq1+/fmR12ufazCY3hRUrVtjdd99tW221VVJ9KunK+PHj7V//+peLKy0/a8WMLoSixC+NGjWKGYpC+SkaSVlFiWc6duxYopnC0yXKuFiiIRcQgAAEIBB6Agjm0Js4doII5lgmqdT88ccfNnLkSFPSESUYad26tRPEXh8SzP369XMrwwoBp0QjKlp17ty5c4w7xrXXXmv77LOP93jWj8o46IVei/abjvfy33//3caOHeuEsmJLe6WQBPOIESPsoosu8obmHxUGbsiQIf51ohP5mbdq1cqmTp3qmrDBLxEp6iEAAQgUJwEEcxHaHcGcntEffPBBt4EvshetEMsPubTyxBNPxGSbU6KS6JXN0vpI996iRYtcAg8v86D8ouUfXVrRM1otP+CAA9xq7bBhw1zzQhLM5557rj3yyCMx0xDzM888M6Y+XoUnmhXNhHTX8QhRBwEIQKB4CSCYi9D2COb0jH7NNdfYb7/9VqITiV6J30RFK5f62T+yyOdWP/srxnKuila+tTLulWbNmtmFF17oXZZ5lFvGTTfd5NoVkmDeaaedbP78+THj/+6776xu3box9aoYM2aMtWvXrkQSGIlm/RIg21AgAAEIQAACHgEEs0eiiI4I5vSMfemll/pRL9RThQoVbNCgQS6rX7ye586d61w0vEgZaqMMgF27di1zVTpef+Wt8/ynlSXQW2GW0IyXSjrROxQ/+oYbbnC38yGYlS78jTfesE8//dQJZLnHyAXm1VdfjRlyvXr1bMGCBTH1qvA2+LVv394efvjhEqI57gNUQgACEIBAURNAMBeh+RHM6RldG+WUyEJljz32cD7MkfGTI3vXyrKiLehnfq9IaCpe8A477OBVZf0o3+NbbrnFRUQ57rjjnA+2XqpNiQ888EDSkTLyJZiV2lrcX375ZbcRMhlg//jHP1xIv+i2nlj26hHNHgmOEIAABCCQiACCORGZENcjmNMz7uTJk52/bKVKlaxDhw4u3Fs0U/n9yn820v1Bb91ll13siiuuSCrMWXqjLPm0hOaTTz7p0msrKsZtt93mN7jnnntsyy239K9LO8m1YF64cKFLGvLiiy+WNqy497SKr7ldcskl/n2t8h9xxBF+BkXd0AY/JZVJJvSc3xEnEIAA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x1y7dm3/OtmTuXPn2i+//GJNmjRJ9hHX/sMPP7QlS5a4kHZbb721aYV7hx12SLqPfDVELOeLPO+FAAQgAIFiIoBgLiZr/3euhSaYly9fbtdcc439/fffboRbbrml3XPPPSlbRvGbb7rpJid677///qSenzBhgo0bN87++usvlyBFMZ9nzZrlxtKmTRs744wzkuonH40Qy/mgzjshAAEIQKAYCSCYi9DqhSaYtbo7ZMgQ3xLNmjWzCy+80L9O9uS5556z559/3jUfOHCgVa9evdRH5QIiVxAVxXtW3GeV+fPnW48ePWz9+vXWtm1bO/300119If2DWC4kazAWCEAAAhAIOwEEc9gtHGd+hSaYH3roIXvrrbf8kV5yySXWtGlT/zqZk19//dVfXVZ7rTTvvvvuCR/9+OOPXRQONYgn0CPF9/nnn2/NmzdP2FeubyCWc02c90EAAhCAQLETQDAX4Seg0ATzDTfcYD///LNvifvuu89q1KjhruWPvMUWW9hGG23k3493MnToUPvggw/8W2effbYdddRR/nX0Sbdu3WzevHmuOp6/tNw7LrvsMrfKvN1221mvXr2iu8jLNWI5L9h5KQQgAAEIFDkBBHMRfgAKSTBLKEswe2Xbbbe13r17u0uJ5a5du7psfyeeeKLXJOb4zTffOBeKyBstW7a0c889N7LKP1+0aJF16dLFXdesWdMGDBjg34s86dmzp82ePdtVde7c2XbbbbfI2zk/RyznHDkvhAAEIAABCDgCCOYi/CAUkmCWK4ZcMrzSqlUra9++vUtgIuH8ww8/mISrt+LstfOO2iiojIBLly61ffbZx3ftaNiwoS+KvbbeccyYMTZp0iR3efDBB7uVZO9e5PGZZ54xbQpUKa1d5DPZOkcsZ4ss/UIAAhCAAATKJoBgLptR6FoUkmB+5JFHbPLkyT7jyy+/3A466CAbNWqUE7/K/qfrROXdd9+14cOHm/yMNa+RI0e6psoUmChSRuTKcbt27ezYY4+N232kn3PkynfcxlmsRCxnES5dQwACEIAABJIggGBOAlLYmhSSYFb6awlTrxx55JHOn/nzzz+30twq1H7NmjXWqVMn23zzzd0qs3yStdrslUSRMiJ9pjt06GAtWrTwHilxnDlzpvXp08fVVa5c2R588MES93NxgVjOBWXeAQEIQAACECidAIK5dD6hvFtIgvmll16ysWPHxnA+5JBDTNEyosca2dBzmfAiYqxevdouvfRSP56zVx/5jM4Vsm7dunWuurQVbIWXu+OOO1w7/aPQd5tuuql/ne0TxHK2CdM/BCAAAQhAIDkCCObkOIWqVbQI9RKG5GOS2vSnTXfff/+9e71Wi08++WS36ltaZAw9p414e+65p3Xs2NEfuuIpa7Oginyh5RMdWf7880+TSPbKjTfe6PrwriOPyvynFWyv3HnnnTnL/odY9qhzhAAEIAABCOSfAII5/zbI+QgKSTB7k9fmPrk9KIRcMkWuHNOmTXMbAuvUqeM/IqE5ffp0dx3PpeP333+3q666ym9fWvSL6AgeCkVXv359/9lsnSCWs0WWfiEAAQhAAALlI4BgLh+3QD9ViII5FaBKXa0IGsccc4z985//LPHoU089ZRMnTnR18SJlaDVdGwSVCltFq9P77ruvO4/+Z/HixW4V26uPF6/Zu5epI2I5UyTpBwIQgAAEIJA5AgjmzLEMTE9BFswSvLfffrt9++23brNftE/xH3/8YXK7UEkUKePqq6+25cuXuzYXX3yxHXrooe48+p/o+M7a9KdV8GwVxHK2yNIvBCAAAQhAID0CCOb0+AXy6SAL5ilTpriQc3vttZcTzNEGWLFihXPV8OoHDRoU0+7WW2+1hQsXuialZQT87LPP7J577nHtqlatasommK2CWM4WWfqFAAQgAAEIpE8AwZw+w8D1EFTBvGrVKrcJb5NNNnEuGfE2BUowK5azV26++WZr1KiRd+mOitX89ttvu3PFYFYs5njFE+e6t9NOO7mV7Xjt0q1DLKdLkOchAAEIQAAC2SWAYM4u34LsPaiC+cknn7SXX37ZCeImTZokZHvllVeaXDNU4kXKUIznu+++293fZZddXPptdxH1z7Bhw+z99993tfKVls90pgtiOdNE6Q8CEIAABCCQeQII5swzLfgegyiYtQFPrhR169Z1sZGj5xAJPTKTX7xIGRs2bHCRMrQaXaFCBRdfOZ5vsjYELlu2zLSSLWGbKD135LtTOUcsp0KLthCAAAQgAIH8EUAw54993t4cLTbzGYc5GQga31133WWKjlHaJj2vr0iXi0SuFI8//ri9+uqr7hElSGnatKn3uDtGbvjbe++97brrritxP90LxHK6BHkeAhCAAAQgkDsCCObcsS6YNwVNMHvZALXS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n37a+TlLTB933HG2++67+/fSPVFMaCUD6d27d1JdSSRPmDDBuZPoXEUZCRX14x//+IeLApJURzSCAAQgAAEIQAACEMgbgZwLZmXdq1q1aomYyZq9/JMlipWwRP7Ip59+uou/rHtvvPGGjR49Wqd+UYxgJTKJjqihcHOKjLH55pv7bTNxsmTJEuvSpYspFNvgwYNN8aJLK1pNlrD+9ttvTWM9/vjjXbbBN9980yVr0fMKj7f99tuX1g33IAABCEAAAhCAAATyTCBnglnuFEousmjRIudeccwxx5Rwl5AQffDBB61evXqme14aa606d+7cuURMZa3S3n777Va/fv2c4RswYIBNmzbNvU/j2W233RK+W24lWilXhkFlKOzVq5dzK9EDCpsnIf311187Ua++tGmRAgEIQAACEIAABCBQmARyJpglIJUwI7Io854y8JVWJLLlBhFZch39YsaMGS5roDeGc845x4488kjvMuYoH+zx48e7+vbt21urVq1KtNGXBwllZTrcd999rWPHjiXucwEBCEAAAhCAAAQgUDgEciaYL774YpfyOnLqcnFo2LBhZFWJ81deecWeeOKJEnXya1ZsZW8FusTNLFxI1N56661uZdzrXmJZojle0Qry9ddfb0uXLnW377vvPn91ObK9+ly4cKHzadaXia222iryNucQgAAEIAABCBQRAWUn/uqrr9x+LWUtVi4JuXPqV/XooghiWsxbu3atHXLIIbbrrrtGN+E6wwRyJpgvvPBCW7dunT98uSpo9TiR8P3444/tgQceMGWj84p8m+W3nGn/ZK//eMfJkyfbI4884kTvb7/95prIHUMrxPGKVtElgFWUYto7j2772GOP2WuvveaqtTlRmwApEIAABCAAAQgUDwEtyr399tv20UcfObGs68ii/Vxt27b1q6SjRo0aZe+9955fV7FiRbv//vvd/i2/kpOME8iZYO7bt6/7NqQZNG/e3I4++ui4G94kkCUkn3rqqRJiWb7N1113XdzV2oxT+W+H+rbXqVMn52PctGlTe/jhh90dCfZBgwbFfe1DDz3kJ05p1qyZ6YtCvKIvBNo8qFKnTh3r06dPvGbUQQACEIAABCAQUgJaIb788sttxx13dHu45syZY/Pnz/dnqz1OXmQu/YItYSz9EF0S/Zod3Y7r8hPImWCeMmWK+1akFeV27drZEUcc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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Forward Kinematics Model (FKM)The forward kinematics model of a rigid serial-link manipulator is obtained through a sequence of transformations.The only real challenge in obtaining the FKM is understanding from a diagram, or a real robot, what transformations represent the robot and in what order they happen.Anyway, we can start with an example. As always, remember that angles are in radians and lengths are in meters.![Lesson4.png](Lesson4.png)Consider the 2-DoF planar robot shown in the figure. It is classed as an RR robot, because the two joints are revolute.Let $q_0\\triangleq q_0(t) \\in \\mathbb{R}$ and $q_1\\triangleq q_1(t) \\in \\mathbb{R}$ compose its configuration space. In addition, let $l_{0} \\in \\mathbb{R}$ and $l_{1} \\in \\mathbb{R}$ be the geometric parameters, which are quantities that cannot be controlled.The configuration space is what is used in practice to control the robot. You as the system designer will send configuration space values $q_0$ and $q_1$, or other signals related to those, to command the robot. You will make it move to perform a relevant task and hopefully earn your next month's salary. The parameters $l_{0}$ and $l_{1}$ are constant in time and represent time-invariant geometrical aspects of the robot, such as link lengths, that you cannot control.As a representative task for robotic manipulators, let us use the configuration space and geometric parameters to calculate the pose of the frame of the tip of the robot. This is represented mathematically as follows.$$\\mymatrix{H}^{0}_{2}( q_0, l_{0},q_1,l_{1}) \\in SE(2).$$The equation for the end-effector (tip) pose is what is called the forward kinematics model (FKM). We need this frequently when using a robotic manipulator because the end effector is likely to be its most useful part. For instance, it could be a gripper that is used to pick and place objects. To pick or place an object, the robot needs to move somewhere.The first step towards moving somewhere is knowing where you are. Thence, the first step towards controlling a robotic manipulator's end effector pose in any meaningful way is to obtain its FKM.## Understanding the problemThe FKM is a mathematical description of the robot. Before we attempt any programming, we have to mathematically describe the sequential transformations that represent the robot being modelled.As shown in the figure, there are four transformations for this robot, taking us from the base, $\\mathcal{F}_0$, to the end-effector, $\\mathcal{F}_2$. The sequence can be summarised as follows.1. A rotation of $q_0$ about the current frame, from $\\mathcal{F}_0$ to $\\mathcal{F}_{0'}$.2. A translation of $l_0$ along the $x$-axis of the current frame, from $\\mathcal{F}_{0'}$ to $\\mathcal{F}_{1}$.3. A rotation of $q_1$ about the current frame, from $\\mathcal{F}_{1}$ to $\\mathcal{F}_{1'}$.4. A translation of $l_1$ along the $x$-axis of the current frame, from $\\mathcal{F}_{1'}$ to $\\mathcal{F}_{2}$.### 1. From $\\mathcal{F}_0$ to $\\mathcal{F}_{0'}$We start with the rotation that can be described by the following homogeneous transformation matrix.$$\\myvec H_{0'}^{0}\\left(q_0\\right)\t=\\begin{bmatrix} \\cos(q_0) & -\\sin(q_0) & 0\\\\\\sin(q_0) & \\cos(q_0) & 0\\\\0 & 0 & 1\\end{bmatrix}.$$Programmatically, supposing that $q_0 = \\frac{\\pi}{4}$, we arrive at the following piece of code.\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "tags": [] - }, - "source": [ - "H_0_0p = np.array(\n", - " [[cos(pi/4), -sin(pi/4), 0],\n", - " [sin(pi/4), cos(pi/4), 0],\n", - " [0, 0, 1]]\n", - ")\n", - "\n", - "print(f\"The first transformation is\\n\\n H_0_0p = \\n{H_0_0p}\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2. From $\\mathcal{F}_{0'}$ to $\\mathcal{F}_{1}$\n", - "\n", - "The second step is a translation that can be described by the following homogeneous transformation matrix.\n", - "\n", - "$$\\myvec H_{1}^{0'}\\left(l_0\\right)\t=\n", - "\\begin{bmatrix}\n", - "1 & 0 & l_0 \\\\\n", - "0 & 1 & 0 \\\\\n", - "0 & 0 & 1\n", - "\\end{bmatrix}.$$\n", - "\n", - "Programmatically, supposing that $l_0 = 0.3$, we arrive at the following piece of code.\n" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "source": [ - "H_0p_1 = np.array(\n", - " [[1, 0, 0.3],\n", - " [0, 1, 0],\n", - " [0, 0, 1]]\n", - ")\n", - "\n", - "print(f\"The second transformation is\\n\\n H_0p_1 = \\n{H_0p_1}\")" - ], - "outputs": [], - "execution_count": null - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3. From $\\mathcal{F}_{1}$ to $\\mathcal{F}_{1'}$\n", - "\n", - "The third step is a rotation that can be described by the following homogeneous transformation matrix.\n", - "\n", - "$$\\myvec H_{1'}^{1}\\left(q_1\\right)\t=\n", - "\\begin{bmatrix} \\cos(q_1) & -\\sin(q_1) & 0\\\\\n", - "\\sin(q_1) & \\cos(q_1) & 0\\\\\n", - "0 & 0 & 1\n", - "\\end{bmatrix}.$$\n", - "\n", - "Programmatically, supposing that $q_1 = -\\frac{\\pi}{14}$, we arrive at the following piece of code.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "H_1_1p = np.array(\n", - " [[cos(-pi/14), -sin(-pi/14), 0],\n", - " [sin(-pi/14), cos(-pi/14), 0],\n", - " [0, 0, 1]]\n", - ")\n", - "\n", - "print(f\"The third transformation is\\n\\n H_1_1p = \\n{H_1_1p}\")" - ], - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "### 4. From $\\mathcal{F}_{1'}$ to $\\mathcal{F}_{2}$\n", - "\n", - "The last step is a translation that can be described by the following homogeneous transformation matrix.\n", - "\n", - "$$\\myvec H_{2}^{1'}\\left(l_1\\right)\t=\n", - "\\begin{bmatrix}\n", - "1 & 0 & l_1 \\\\\n", - "0 & 1 & 0 \\\\\n", - "0 & 0 & 1\n", - "\\end{bmatrix}.$$\n", - "\n", - "Programmatically, supposing that $l_1 = 0.95$, we arrive at the following piece of code.\n" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "source": [ - "H_1p_2 = np.array(\n", - " [[1, 0, 0.95],\n", - " [0, 1, 0],\n", - " [0, 0, 1]]\n", - ")\n", - "\n", - "print(f\"The second transformation is\\n\\n H_1p_2 = \\n{H_1p_2}\")" - ], - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Ok, so where's the FKM for the RR robot?\n", - "\n", - "As we summarised earlier, the planar RR robot used in this lesson is composed of four sequential transformations. We obtained each of them individually, therefore the final step for the FKM is to compose them in sequence.\n", - "\n", - "$$\\mymatrix{H}^{0}_{2}( q_0, l_{0},q_1,l_{1}) = \\myvec H_{0'}^{0}\\left(q_0\\right)\\myvec H_{1}^{0'}\\left(l_0\\right)\\myvec H_{1'}^{1}\\left(q_1\\right)\\myvec H_{2}^{1'}\\left(l_1\\right).$$\n", - "\n", - "The equation above is general and is the FKM for this robot.\n", - "\n", - "Programmatically, we will compute the FKM at a given configuration. Using the configuration and parameters defined previously, we arrive at the following piece of code.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "H_0_2 = H_0_0p @ H_0p_1 @ H_1_1p @ H_1p_2\n", - "\n", - "print(f\"The FKM for the RR robot at the specified configuration is\\n\\n H_0_2 = \\n{H_0_2}\")" - ], - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Denavit-Hartenberg (DH) Parameters\n", - "\n", - "Despite being the most mistyped concept in my career, DH parameters are ubiquitous and frequently used to describe commercial robots.\n", - "\n", - "The process can be divided into two major parts, with different levels of difficulty.\n", - "1. Obtaining the DH parameters for a given robot.\n", - "2. Using given DH parameters to obtain the robot's FKM.\n", - "\n", - "Obtaining the DH parameters of a robot usually requires some thought, in particular if the robot has many degrees-of-freedom. This is not the objective of this lesson, because that does not involve programming. It is a pen-and-paper exercise.\n", - "\n", - "After the DH parameters are obtained, calculating the FKM of the robot is trivial.\n", - "\n", - "## DH parameter table for an RR robot\n", - "\n", - "Let us start with a sample table, shown below.\n", - "\n", - "| Joint | $\\theta$ | $d$ | $a$ | $\\alpha$ |\n", - "|-------|----------|-----|---------|----------|\n", - "| 0 | $q_0(t)$ | 0 | $l_{0}$ | 0 |\n", - "| 1 | $q_1(t)$ | 0 | $l_{1}$ | 0 |\n", - "\n", - "Each joint transformation is represented by a row. The transformations of each row will be done in the following sequence.\n", - "\n", - "1. A rotation about the $z$-axis of the current frame, related to column $\\theta$.\n", - "2. A translation about the $z$-axis of the current frame, related to column $d$.\n", - "3. A translation about the $x$-axis of the current frame, related to column $a$.\n", - "4. A rotation about the $x$-axis of the current frame, related to column $\\alpha$.\n", - "\n", - "Note that the sequence of transformations in the table represent the same FKM of our RR robot derived previously. The only difference is that the result will be an element of SE(3).\n", - "\n", - "## DH parameter table for a PP robot\n", - "\n", - "Instead of working again on the RR robot, let's derive the FKM for a PP robot, composed of two prismatic joints. Let its configuration be composed of $q_{B0}(t)$ and $q_{B1}(t)$, with different subscripts to clarify that it is a different robot.\n", - "\n", - "Consider that the FKM is represented by the table below. Note that another benefit of a table is that there's no need to interpret a robot diagram.\n", - "\n", - "| Joint | $\\theta$ | $d$ | $a$ | $\\alpha$ |\n", - "|-------|----------|-------------|-----|-----------------|\n", - "| 0 | 0 | $q_{B0}(t)$ | 0 | $\\frac{\\pi}{2}$ |\n", - "| 1 | 0 | $q_{B1}(t)$ | 0 | 0 |\n", - "\n", - "Given that we can ignore any cells with zeros, this robot will be composed of three transformations.\n", - "1. A translation of $q_{B0}(t)$ along the $z$-axis of the current frame, from $\\mathcal{F}_{B0}$ to $\\mathcal{F}_{B0'}$.\n", - "2. A rotation of $\\frac{\\pi}{2}$ about the $x$-axis of the current frame, from $\\mathcal{F}_{B0'}$ to $\\mathcal{F}_{B1}$.\n", - "3. A translation of $q_{B1}(t)$ along the $z$-axis of the current frame, from $\\mathcal{F}_{B1}$ to $\\mathcal{F}_{B2}$.\n", - "\n", - "## FKM for the PP robot\n", - "\n", - "Using elements of SE(3), we obtain each of the three transformations, as follows.\n", - "\n", - "$$\\begin{align}\n", - "\\mymatrix{H}^{B0}_{B0'}(q_{B0})&=\\left[\\begin{array}{cccc}\n", - " 1 & 0 & 0 & 0 \\\\\n", - " 0 & 1 & 0 & 0 \\\\\n", - " 0 & 0 & 1 & q_{B0}(t) \\\\\n", - " 0 & 0 & 0 & 1\n", - "\\end{array}\\right], \\\\\n", - "\\mymatrix{H}^{B0'}_{B1}&=\\left[\\begin{array}{cccc}\n", - " 1 & 0 & 0 & 0\\\\\n", - " 0 & \\cos{\\frac{\\pi}{2}} & -\\sin{\\frac{\\pi}{2}} & 0\\\\\n", - " 0 & \\sin{\\frac{\\pi}{2}} & \\cos{\\frac{\\pi}{2}} & 0\\\\\n", - " 0 & 0 & 0 & 1\n", - "\\end{array}\\right], \\\\\n", - "\\mymatrix{H}^{B1}_{B2}(q_{B1})&=\\left[\\begin{array}{cccc}\n", - " 1 & 0 & 0 & 0 \\\\\n", - " 0 & 1 & 0 & 0 \\\\\n", - " 0 & 0 & 1 & q_{B1}(t) \\\\\n", - " 0 & 0 & 0 & 1\n", - "\\end{array}\\right].\n", - "\\end{align}$$\n", - "\n", - "Then, we sequentially compose them to obtain the FKM.\n", - "\n", - "$$\n", - "\\mymatrix{H}^{B0}_{B2}(q_{B0},q_{B1})=\\mymatrix{H}^{B0}_{B0'}(q_{B0})\\mymatrix{H}^{B0'}_{B1}\\mymatrix{H}^{B1}_{B2}(q_{B1}).$$\n", - "\n", - "Programmatically, suppose $q_{B0}=0.2$ and $q_{B1}=0.3$. We obtain the following piece of code.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "q_B0 = 0.2\n", - "q_B1 = 0.3\n", - "theta_B0 = pi/2.0\n", - "\n", - "H_B0_B0p = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, 1, 0, 0],\n", - " [0, 0, 1, q_B0],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H_B0p_B1 = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, cos(theta_B0), -sin(theta_B0), 0],\n", - " [0, sin(theta_B0), cos(theta_B0), 0],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "H_B1_B2 = np.array(\n", - " [[1, 0, 0, 0],\n", - " [0, 1, 0, 0],\n", - " [0, 0, 1, q_B1],\n", - " [0, 0, 0, 1]]\n", - ")\n", - "\n", - "# FKM\n", - "H_B0_B2 = H_B0_B0p @ H_B0p_B1 @ H_B1_B2\n", - "\n", - "print(f\"The FKM for the PP robot at the specified configuration is\\n\\n H_B0_B2 = \\n{H_B0_B2}\")" - ], - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercises\n", - "\n", - "Consider that the `numpy` and `math` modules are already imported as shown earlier in this lesson.\n", - "\n", - "## Exercise a\n", - "\n", - "Consider a robotic manipulator that has the following DH-parameter table.\n", - "\n", - "| Joint | $\\theta$ | $d$ | $a$ | $\\alpha$ |\n", - "|-------|-------------|-------------|-----|-----------------|\n", - "| 0 | $q_{A0}(t)$ | 0.5 | 0 | $\\frac{\\pi}{2}$ |\n", - "| 1 | 0 | $q_{A1}(t)$ | 0 | 0 |\n", - "\n", - "Compute its FKM in SE(3) and store in `H_A0_A2` the result of the FKM given $q_{A0}(t) = \\frac{\\pi}{4}$ and $q_{A1}(t) = -0.1$.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "q_A0 = pi/4.0 # As given in the exercise\n", - "q_A1 = -0.1 # As given in the exercise\n", - "\n", - "H_A0_A2 = None # Replace None with your solution to this exercise." - ], - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "\n", - "## Exercise c\n", - "\n", - "Consider a robotic manipulator that has the following DH-parameter table.\n", - "\n", - "| Joint | $\\theta$ | $d$ | $a$ | $\\alpha$ |\n", - "|-------|-------------|----------|-----|----------|\n", - "| 0 | $q_{C0}(t)$ | $l_{C0}$ | 0 | 0 |\n", - "| 1 | $q_{C1}(t)$ | $l_{C1}$ | 0 | 0 |\n", - "| 2 | $q_{C2}(t)$ | $l_{C2}$ | 0 | 0 |\n", - "\n", - "Compute its FKM in SE(3) and store in `H_C0_C3` the result of the FKM given $q_{C0}(t)=q_{C1}(t)=q_{C2}(t) = \\frac{\\pi}{5}$ and $l_{C0} = l_{C1} = l_{C2} = 0.25$.\n" - ] - }, - { - "metadata": {}, - "cell_type": "code", - "source": "H_C0_C3 = None # Replace None with your solution to this exercise.", - "outputs": [], - "execution_count": null - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "\n", - "# Extra challenge(s)\n", - "1. What about if it was a planar revolute manipulator with `n` degrees-of-freedom?\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson3_tutorial.md b/basic_lessons/lesson3_tutorial.md similarity index 99% rename from unstable/lesson3_tutorial.md rename to basic_lessons/lesson3_tutorial.md index 43c4067..5c833c5 100644 --- a/unstable/lesson3_tutorial.md +++ b/basic_lessons/lesson3_tutorial.md @@ -10,16 +10,17 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### Prerequisites for the learner +## Prerequisites for the learner The user of this notebook is expected to have prior knowledge in - All the content and prerequisites of lessons 1 and 2. -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues -## Prerequisites +## Package installation ````{code-cell} +%%capture %pip install numpy ```` diff --git a/basic_lessons/lesson4_exercise_answers.ipynb b/basic_lessons/lesson4_exercise_answers.ipynb deleted file mode 100644 index 08980de..0000000 --- a/basic_lessons/lesson4_exercise_answers.ipynb +++ /dev/null @@ -1,362 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L4 Exercise Answers\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "### I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "### Latex Macros" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "vscode": { - "languageId": "latex" - } - }, - "source": [ - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": "# Valid imports" - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-23T16:34:43.746333Z", - "start_time": "2026-02-23T16:34:43.733628Z" - } - }, - "cell_type": "code", - "source": [ - "from math import pi, sin, cos\n", - "import numpy as np" - ], - "outputs": [], - "execution_count": 5 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercises\n", - "\n", - "## Exercise a\n", - "\n", - "First, we calculate FKM by hand. You'll notice that it is given by the equation below.\n", - "$$\\mymatrix{H}^{0}_{3} = \\left[\\begin{array}{ccc}\n", - " c_{012} & -s_{012} & l_{0}c_0 + l_{1}c_{01} + l_{2}c_{012}\\\\\n", - " s_{012} & c_{012} & l_{0}s_0 + l_{1}s_{01} + l_{2}s_{012}\\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "We don't need to compute it explicitly, we just need the task-space values.\n", - "\n", - "$$\\begin{align}\n", - "p_{x}&=l_{0}c_0 + l_{1}c_{01} + l_{2}c_{012} \\\\\n", - "p_{y}&=l_{0}s_0 + l_{1}s_{01} + l_{2}s_{012} \\\\\n", - "\\phi&=q_0 + q_1 + q_2.\\\\\n", - "\\end{align}$$\n", - "\n", - "Then, take the derivative to find the Jacobian.\n", - "\n", - "$$\\mymatrix{J} = \\left[\\begin{array}{ccc}\n", - " -l_{0}s_0 - l_{1}s_{01} - l_{2}s_{012} & - l_{1}s_{01} - l_{2}s_{012} & - l_{2}s_{012} \\\\\n", - " l_{0}c_0 + l_{1}c_{01} + l_{2}c_{012} & l_{1}c_{01} + l_{2}c_{012} & l_{2}c_{012}\\\\\n", - " 1 & 1 & 1\n", - " \\end{array}\\right].$$\n", - "\n" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-23T16:34:43.761410Z", - "start_time": "2026-02-23T16:34:43.748057Z" - } - }, - "cell_type": "code", - "source": [ - "q_0 = pi/4.0\n", - "q_1 = -pi/8.0\n", - "q_2 = pi/12.0\n", - "\n", - "l_0 = 1\n", - "l_1 = 1\n", - "l_2 = 1\n", - "\n", - "c0 = cos(q_0)\n", - "c01 = cos(q_0 + q_1)\n", - "c012 = cos(q_0 + q_1 + q_2)\n", - "\n", - "s0 = sin(q_0)\n", - "s01 = sin(q_0 + q_1)\n", - "s012 = sin(q_0 + q_1 + q_2)\n", - "\n", - "# Task space\n", - "p_x = l_0 * c0 + l_1 * c01 + l_2 * c012\n", - "p_y = l_0 * s0 + l_1 * s01 + l_2 * s012\n", - "phi = q_0 + q_1 + q_2\n", - "\n", - "# Jacobian\n", - "J_1_1 = - l_0 * s0 - l_1 * s01 - l_2 * s012\n", - "J_1_2 = - l_1 * s01 - l_2 * s012\n", - "J_1_3 = - l_2 * s012\n", - "\n", - "J_2_1 = l_0 * c0 + l_1 * c01 + l_2 * c012\n", - "J_2_2 = l_1 * c01 + l_2 * c012\n", - "J_2_3 = l_2 * c012\n", - "\n", - "J_3_1 = 1\n", - "J_3_2 = 1\n", - "J_3_3 = 1\n", - "\n", - "J = np.array(\n", - " [[J_1_1, J_1_2, J_1_3],\n", - " [J_2_1, J_2_2, J_2_3],\n", - " [J_3_1, J_3_2, J_3_3]]\n", - ")\n", - "\n", - "print(f\"The analytical Jacobian at q_0={q_0}, q_1={q_1}, and q_2={q_2} is \\n J={J}\")\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The analytical Jacobian at q_0=0.7853981633974483, q_1=-0.39269908169872414, and q_2=0.2617993877991494 is \n", - " J=[[-1.69855164 -0.99144486 -0.60876143]\n", - " [ 2.42433965 1.71723287 0.79335334]\n", - " [ 1. 1. 1. ]]\n" - ] - } - ], - "execution_count": 6 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Exercise b\n", - "\n", - "Suppose that we have a `PP` robot defined by the following transformations:\n", - "- a translation of $q_0$ along the $x-$axis of the base frame.\n", - "- a rotation of 90 degrees with respect to the current frame.\n", - "- a translation of $q_1$ along the $x-$axis of the current frame.\n", - "\n", - "\n", - "First, we calculate FKM by hand. You'll notice that it is given by the equation below.\n", - "$$\\mymatrix{H}^{0}_{3} = \\left[\\begin{array}{ccc}\n", - " 0 & -1 & q_0\\\\\n", - " 1 & 0 & q_1\\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "We don't need to compute it explicitly, we just need the task-space values.\n", - "\n", - "$$\\begin{align}\n", - "p_{x}&= q_0 \\\\\n", - "p_{y}&= q_1 \\\\\n", - "\\phi&= \\frac{\\pi}{2}.\\\\\n", - "\\end{align}$$\n", - "\n", - "Then, take the derivative to find the Jacobian.\n", - "\n", - "$$\\mymatrix{J} = \\left[\\begin{array}{cc}\n", - " 1 & 0\\\\\n", - " 0 & 1\\\\\n", - " 0 & 0\n", - " \\end{array}\\right].$$" - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-23T16:34:43.773438Z", - "start_time": "2026-02-23T16:34:43.762078Z" - } - }, - "cell_type": "code", - "source": [ - "# Jacobian is trivial so we don't need to compute each term separately.\n", - "# As you can see, in this example, it the Jacobian always has the same value.\n", - "J = np.array(\n", - " [[1, 0],\n", - " [0, 1],\n", - " [0, 0]]\n", - ")\n", - "print(f\"The analytical Jacobian is always\\n J={J}\")\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The analytical Jacobian is always\n", - " J=[[1 0 0]\n", - " [0 1 0]\n", - " [0 0 0]]\n" - ] - } - ], - "execution_count": 7 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Challenge 1\n", - "\n", - "To solve this challenge, we notice the patterns in the computation. You can change to the same link values of exercise a to test that this is correct." - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-23T16:34:43.790768Z", - "start_time": "2026-02-23T16:34:43.779260Z" - } - }, - "cell_type": "code", - "source": [ - "# Consider manipulator DoFs as the length of the following lists.\n", - "# Consider it as the configuration space of the RRR...RRR robot\n", - "q = [pi/4.0, -pi/8.0, pi/12.0, -pi/3.0] # Increase length of q if you'd like to check\n", - "l = [1, 1, 1, 1] # l must be same size of q\n", - "\n", - "if len(q) != len(l):\n", - " raise Exception(\"q and l are not the same length\")\n", - "\n", - "def c_n(q, n_frame):\n", - " \"\"\"\n", - " Get cos(q_0 + q_1 + ... + q_n).\n", - " \"\"\"\n", - " q_sum = 0\n", - " c_result = 0\n", - " for i in range(n_frame+1):\n", - " qi = q[i]\n", - " q_sum += qi # First will be q_0, then q_0 + q_1, then...\n", - " c_result = cos(q_sum) # First will be cos(q_0), then cos(q_0 + q_1), then...\n", - " return c_result\n", - "\n", - "def s_n(q, n_frame):\n", - " \"\"\"\n", - " Get sin(q_0 + q_1 + ... + q_n).\n", - " \"\"\"\n", - " q_sum = 0\n", - " s_result = 0\n", - " for i in range(n_frame+1):\n", - " qi = q[i]\n", - " q_sum += qi # First will be q_0, then q_0 + q_1, then...\n", - " s_result = sin(q_sum) # First will be sin(q_0), then sin(q_0 + q_1), then...\n", - " return s_result\n", - "\n", - "def px_n(q, l, n_frame):\n", - " \"\"\"\n", - " Get l_0*cos(q_0) + l_1*cos(q_0 + q_1) + ... + l_n*cos(q_0 + q_1 + ... + q_n).\n", - " \"\"\"\n", - " px = 0\n", - " for i in range(n_frame + 1):\n", - " li = l[i]\n", - " px += li * c_n(q, i)\n", - " return px\n", - "\n", - "def py_n(q, l, n_frame):\n", - " \"\"\"\n", - " Get l_0*sin(q_0) + l_1*sin(q_0 + q_1) + ... + l_n*sin(q_0 + q_1 + ... + q_n).\n", - " \"\"\"\n", - " py = 0\n", - " for i in range(n_frame + 1):\n", - " li = l[i]\n", - " py += li * s_n(q, i)\n", - " return py\n", - "\n", - "\n", - "def j_n(q, l, n_frame):\n", - " \"\"\"\n", - " Construct the n-th column of the Jacobian matrix.\n", - " \"\"\"\n", - " N = len(q)\n", - "\n", - " pnx = px_n(q, l, n_frame-1) # starts at 0\n", - " pny = py_n(q, l, n_frame-1) # starts at 0\n", - " pNx = px_n(q, l, N-1)\n", - " pNy = py_n(q, l, N-1)\n", - "\n", - " px = pNx - pnx\n", - " py = pNy - pny\n", - "\n", - " jn = np.array(\n", - " [[-py],\n", - " [px],\n", - " [1]]\n", - " )\n", - " return jn\n", - "\n", - "# Jacobian\n", - "J = j_n(q, l, 0)\n", - "for i in range(1,len(q)):\n", - " J = np.hstack((J, j_n(q, l, i))) # We stack the columns horizontally\n", - "print(J)\n" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[-1.31586821 -0.60876143 -0.226078 0.38268343]\n", - " [ 3.34821919 2.64111241 1.71723287 0.92387953]\n", - " [ 1. 1. 1. 1. ]]\n" - ] - } - ], - "execution_count": 8 - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson4_exercise_answers.md b/basic_lessons/lesson4_exercise_answers.md similarity index 99% rename from unstable/lesson4_exercise_answers.md rename to basic_lessons/lesson4_exercise_answers.md index a14c164..555c5fb 100644 --- a/unstable/lesson4_exercise_answers.md +++ b/basic_lessons/lesson4_exercise_answers.md @@ -10,10 +10,9 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues -### Latex Macros # Valid imports diff --git a/basic_lessons/lesson4_tutorial.ipynb b/basic_lessons/lesson4_tutorial.ipynb deleted file mode 100644 index 396ede0..0000000 --- a/basic_lessons/lesson4_tutorial.ipynb +++ /dev/null @@ -1,326 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L4 Differential Kinematics\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "## Prerequisites for the learner\n", - "The user of this notebook is expected to have prior knowledge in\n", - "- All the content and prerequisites of lessons 1, 2, and 3.\n", - "\n", - "## I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "#### Latex Macros\n", - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Package installation\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T13:56:28.237129Z", - "start_time": "2026-02-20T13:56:24.918563Z" - } - }, - "source": [ - "%%capture\n", - "%pip install numpy\n", - "%pip install numpy --break-system-packages" - ], - "outputs": [], - "execution_count": 1 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Imports\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "imports" - ], - "ExecuteTime": { - "end_time": "2026-02-20T13:56:28.242812Z", - "start_time": "2026-02-20T13:56:28.237681Z" - } - }, - "source": [ - "import numpy as np\n", - "from math import pi, sin, cos" - ], - "outputs": [], - "execution_count": 2 - }, - { - "attachments": { - "Lesson4.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Differential Kinematics Model (DFKM)\n", - "\n", - "As we have seen in the previous lesson, the FKM relates configuration-space position with task-space position. For a manipulator, inserting a valid set of joint configurations into the FKM leads to the task-space values of the end-effector.\n", - "\n", - "We also managed to systematise the process to find the FKM, using DH parameters. That way, the FKM of any serial-link manipulator with any number of degrees-of-freedom can be defined with a table. From the table we can derive the analytical FKM and compute it efficiently.\n", - "\n", - "Although the FKM is, then, straightforward to compute, the _inverse_ FKM does not have a general closed form for manipulators with any number of degrees-of-freedom. Naturally, there are ways to invert the FKM iteratively using its first-order derivative. This is where the differential kinematics model (DFKM) comes into play.\n", - "\n", - "The DFKM is the process of finding Jacobians, because the FKM is a vector-valued function. It was once said that\n", - "\n", - " \"Robotics is the art of finding Jacobians.\"\n", - " Bruno Siciliano @ Rosenbrock Lecture Series 2024\n", - "\n", - "The importance of Jacobians for robotics cannot be overstated. In conclusion, the DFKM is a central process of robotics.\n", - "\n", - "Despite all the fancy words, it's a rather simple process for simple manipulators. Let's start with our usual toy example.\n", - "\n", - "![Lesson4.png](attachment:Lesson4.png)\n", - "\n", - "For the 2-DoF planar robot shown in the figure, let us use the FKM obtained in the previous lesson. It is given as\n", - "\n", - "$$\\mymatrix{H}^{0}_{2}( q_0, l_{0},q_1,l_{1}) \\in SE(2).$$\n", - "\n", - "Also remember that the configuration space of this manipulator is\n", - "\n", - "$$\\myvec{q} = \\left[\\begin{array}{c}\n", - " q_0 \\\\\n", - " q_1\n", - " \\end{array}\\right].$$\n", - "\n", - "The DFKM is the process of calculating a Jacobian relevant for a given task. Therefore, herein we obtain the Jacobian $\\mymatrix{J}\\left(\\myvec{q}\\right)$ such that\n", - "\n", - "$$\\dot{\\myvec{x}}=\\mymatrix{J}\\left(\\myvec{q}\\right) \\dot{\\myvec{q}}$$\n", - "\n", - "where \n", - "\n", - "$$\\myvec{x} = \\left[\\begin{array}{c}\n", - " p_{x} \\\\\n", - " p_{y} \\\\\n", - " \\phi\n", - " \\end{array}\\right],$$\n", - "\n", - "in which $p_{x}$, $p_{y}$, and $\\phi$ are, respectively, the $x$-axis position, the $y$-axis position, and the rotation angle of $\\mathcal{F}_{2}$. Notice that $\\dot{l}_{0}=\\dot{l}_{1}=0$, because, as we defined in the previous lesson, they do not vary in time.\n", - "\n", - "As defined above, the Jacobian $\\mymatrix{J}\\left(\\myvec{q}\\right)$ is a function of the configuration-space values. Therefore, when computing it, we need to know at what $\\myvec{q}$.\n", - "\n", - "As a second part of this toy example, let us calculate what is the end-effector velocity given a configuration-space velocity. Mathematically, let us calculate $\\dot{\\myvec{x}}$ when\n", - "\n", - "$$\\dot{\\myvec{q}} = \\left[\\begin{array}{c}\n", - " 5 \\\\\n", - " 10\n", - " \\end{array}\\right].$$\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Step 1: Calculate the forward kinematics by hand\n", - "\n", - "It is not possible to calculate the Jacobian without the FKM. \n", - "\n", - "We saw how to do that in the previous lesson, so here is the answer for this robot.\n", - "\n", - "$$\\mymatrix{H}^{0}_{2} = \\left[\\begin{array}{ccc}\n", - " \\cos{(q_0 + q_1)} & -\\sin{(q_0 + q_1)} & l_{0}\\cos{q_0} + l_{1}\\cos{(q_0 + q_1)}\\\\\n", - " \\sin{(q_0 + q_1)} & \\cos{(q_0 + q_1)} & l_{0}\\sin{q_0} + l_{1}\\sin{(q_0 + q_1)}\\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "This means that, from inspection,\n", - "\n", - "$$\\begin{align}\n", - "p_{x}&=l_{0}\\cos{q_0} + l_{1}\\cos{(q_0 + q_1)} \\\\\n", - "p_{y}&=l_{0}\\sin{q_0} + l_{1}\\sin{(q_0 + q_1)} \\\\\n", - "\\phi&=q_0 + q_1 .\\\\\n", - "\\end{align}$$\n", - " \n", - "\n", - "## Step 2: Calculate the differential kinematics by hand\n", - "\n", - "We first calculate the Jacobian by hand, because programmatically there's nothing for us to do yet.\n", - "\n", - "The analytical Jacobian is given by\n", - "\n", - "$$ \\mymatrix{J} = \\left[\\begin{array}{ccc}\n", - " \\frac{\\partial p_{x}}{\\partial q_0} & \\frac{\\partial p_{x}}{\\partial q_1} \\\\\n", - " \\frac{\\partial p_{y}}{\\partial q_0} & \\frac{\\partial p_{y}}{\\partial q_1} \\\\\n", - " \\frac{\\partial \\phi}{\\partial q_0} & \\frac{\\partial \\phi}{\\partial q_1} \n", - " \\end{array}\\right].$$\n", - "\n", - "As we did in class, we find each element by calculating the partial derivative of the respective task-space value with respect to the configuration-space value\n", - "\n", - "$$\\begin{align}\n", - "\\frac{\\partial p_{x}}{\\partial q_0} &= -l_{0}\\sin{q_0} - l_{1}\\sin{(q_0 + q_1)} \\\\\n", - "\\frac{\\partial p_{x}}{\\partial q_1} &= -l_{1}\\sin{(q_0 + q_1)} \\\\\n", - "\\frac{\\partial p_{y}}{\\partial q_0} &= l_{0}\\cos{q_0} + l_{1}\\cos{(q_0 + q_1)} \\\\\n", - "\\frac{\\partial p_{y}}{\\partial q_1} &= l_{1}\\cos{(q_0 + q_1)} \\\\\n", - "\\frac{\\partial \\phi}{\\partial q_0} &= 1 \\\\\n", - "\\frac{\\partial \\phi}{\\partial q_1} &= 1 \n", - "\\end{align}$$\n", - " \n", - "resulting in\n", - "\n", - "$$\\mymatrix{J} = \\left[\\begin{array}{ccc}\n", - " -l_{0}\\sin{q_0} - l_{1}\\sin{(q_0 + q_1)} & -l_{1}\\sin{(q_0 + q_1)} \\\\\n", - " l_{0}\\cos{q_0} + l_{1}\\cos{(q_0 + q_1)} & l_{1}\\cos{(q_0 + q_1)} \\\\\n", - " 1 & 1 \n", - " \\end{array}\\right].$$\n", - "\n", - "## Step 3: Computing the Jacobian\n", - "\n", - "We're now equipped to solve the first question by doing the following\n" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T13:56:28.249591Z", - "start_time": "2026-02-20T13:56:28.243380Z" - } - }, - "source": [ - "# Sample values, the particular values do not matter\n", - "q_0 = pi / 4\n", - "q_1 = pi / 3\n", - "l_0 = 0.2\n", - "l_1 = 0.1\n", - "\n", - "# To possibly make it easier for you to read\n", - "J_1_1 = -l_0 * sin(q_0) - l_1 * sin(q_0 + q_1)\n", - "J_1_2 = -l_1 * sin(q_0 + q_1)\n", - "J_2_1 = l_0 * cos(q_0) + l_1 * cos(q_0 + q_1)\n", - "J_2_2 = l_1 * cos(q_0 + q_1)\n", - "J_3_1 = 1\n", - "J_3_2 = 1\n", - "\n", - "J = np.array(\n", - " [[J_1_1, J_1_2],\n", - " [J_2_1, J_2_2],\n", - " [J_3_1, J_3_2]]\n", - ")\n", - "\n", - "print(f\"The analytical Jacobian at {q_0} and {q_1} is {J}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The analytical Jacobian at 0.7853981633974483 and 1.0471975511965976 is [[-0.23801394 -0.09659258]\n", - " [ 0.11553945 -0.0258819 ]\n", - " [ 1. 1. ]]\n" - ] - } - ], - "execution_count": 3 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the correct definition of the Jacobian as above, we can calculate the second question as \n" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-02-20T13:56:28.254889Z", - "start_time": "2026-02-20T13:56:28.250577Z" - } - }, - "source": [ - "q_dot = np.array(\n", - " [[5],\n", - " [10]]\n", - ")\n", - "\n", - "x_dot = J @ q_dot\n", - "\n", - "print(f\"In these conditions, x_dot = {x_dot}\")" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "In these conditions, x_dot = [[-2.15599552]\n", - " [ 0.31887821]\n", - " [15. ]]\n" - ] - } - ], - "execution_count": 4 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Suggested exercises\n", - "\n", - "1. What about if the robot had 3 degrees-of-freedom, that is RRR?\n", - "2. What if the robot has one or more prismatic joints?\n", - "3. **Challenge.** What about if the robot had $n$ revolute degrees-of-freedom? Would it be much more complicated to solve?\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson4_tutorial.md b/basic_lessons/lesson4_tutorial.md similarity index 99% rename from unstable/lesson4_tutorial.md rename to basic_lessons/lesson4_tutorial.md index cb91d09..82d397c 100644 --- a/unstable/lesson4_tutorial.md +++ b/basic_lessons/lesson4_tutorial.md @@ -10,16 +10,17 @@ kernelspec: *Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* -### Prerequisites for the learner +## Prerequisites for the learner The user of this notebook is expected to have prior knowledge in - All the content and prerequisites of lessons 1, 2, and 3. -### I found an issue +## I found an issue Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues ## Package installation ````{code-cell} +%%capture %pip install numpy ```` diff --git a/basic_lessons/lesson5_exercise_answers.ipynb b/basic_lessons/lesson5_exercise_answers.ipynb deleted file mode 100644 index a6ee936..0000000 --- a/basic_lessons/lesson5_exercise_answers.ipynb +++ /dev/null @@ -1,355 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L5 Exercise Answers\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "## I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "#### Latex Macros\n", - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Package installation" - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-03-03T22:12:28.425945Z", - "start_time": "2026-03-03T22:12:27.299027Z" - } - }, - "source": [ - "%%capture\n", - "%pip install numpy matplotlib\n", - "%pip install numpy matplotlib --break-system-packages" - ], - "outputs": [], - "execution_count": 10 - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Imports" - ] - }, - { - "cell_type": "code", - "metadata": { - "tags": [ - "imports" - ], - "ExecuteTime": { - "end_time": "2026-03-03T22:12:28.434109Z", - "start_time": "2026-03-03T22:12:28.428282Z" - } - }, - "source": [ - "%matplotlib inline\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from math import pi, sin, cos" - ], - "outputs": [], - "execution_count": 11 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Definition(s)\n", - "\n", - "The function(s) defined below are valid for all solutions." - ] - }, - { - "cell_type": "code", - "metadata": { - "ExecuteTime": { - "end_time": "2026-03-03T22:12:28.440394Z", - "start_time": "2026-03-03T22:12:28.434535Z" - } - }, - "source": [ - "def damped_pseudo_inverse(A: np.array, damping: float = 0.01):\n", - " \"\"\"Calculates the damped pseudo inverse of A\"\"\"\n", - " if damping == 0:\n", - " raise Exception(f\"Damping is {damping} but should be different from zero\")\n", - " \n", - " return A.T @ np.linalg.inv(A @ A.T + (damping ** 2) * np.eye(A.shape[0]))" - ], - "outputs": [], - "execution_count": 12 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## `PP` Robot\n", - "\n", - "Suppose that we have a `PP` robot defined by the following transformations:\n", - "- a translation of $q_0$ along the $x-$axis of the base frame.\n", - "- a rotation of 90 degrees with respect to the current frame.\n", - "- a translation of $q_1$ along the $x-$axis of the current frame.\n", - "\n", - "For FKM and Jacobian calculation, see lesson 4.\n", - "\n", - "For the control parameters, see lesson 5." - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-03-03T22:12:28.622657Z", - "start_time": "2026-03-03T22:12:28.440896Z" - } - }, - "cell_type": "code", - "source": [ - "def get_error(x, xd):\n", - " return x - xd\n", - "\n", - "def planar_robot_pp_fkm(q: np.array) -> np.array:\n", - " q_0 = q[0]\n", - " q_1 = q[1]\n", - " return np.array([q_0,\n", - " q_1,\n", - " pi/2.0])\n", - "\n", - "def planar_robot_pp_jacobian(q):\n", - " # We can leave the parameter `q` for compatibility, but it's not used for this robot.\n", - " return np.array(\n", - " [[1, 0],\n", - " [0, 1],\n", - " [0, 0]]\n", - " )\n", - "\n", - "eta = 1 # Control gain\n", - "T = 0.001 # Sampling time\n", - "# A desired task-space value\n", - "xd = np.array([2.0,\n", - " 2.0,\n", - " pi/10])\n", - "print(f\"xd = {xd}\")\n", - "\n", - "# Lists to store the value of each control iteration\n", - "x_tilde_norm_list = []\n", - "t_list = []\n", - "u_norm_list = []\n", - "\n", - "# Starting conditions\n", - "t = 0\n", - "q_0 = 0.0\n", - "q_1 = 0.0\n", - "q = np.array([q_0,\n", - " q_1])\n", - "\n", - "# Control for 10 seconds\n", - "while t < 10:\n", - " x = planar_robot_pp_fkm(q)\n", - " x_tilde = get_error(x, xd)\n", - " J = planar_robot_pp_jacobian(q)\n", - " J_inv = damped_pseudo_inverse(J)\n", - " u = -eta * J_inv @ x_tilde\n", - "\n", - " ## Store values\n", - " x_tilde_norm_list.append(np.linalg.norm(x_tilde))\n", - " t_list.append(t)\n", - " u_norm_list.append(np.linalg.norm(u))\n", - "\n", - " ## Variable updated for the next loop\n", - " q = q + u * T\n", - " t = t + T\n", - "\n", - "plt.plot(t_list,x_tilde_norm_list, label=f\"$\\\\eta$={eta}\")\n", - "\n", - "plt.title('(PP) Error exponential decay visualization')\n", - "plt.xlabel(\"Time [s]\")\n", - "plt.ylabel(\"$||\\\\tilde{ \\\\bf{x} } (t) ||$\")\n", - "plt.show()" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "xd = [2. 2. 0.31415927]\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHHCAYAAABeLEexAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAATWhJREFUeJzt3Qd8FGX6wPEnISS0hBIggdCb9CJNVPrhgaKAqCDnCSJ3op56igUsp+iJ/vVUlEMsIIeoeKIColIVBaQpSO8dkhAgCSSQkJBk/p/nhd1LQhI2IZvZ8vv6eZ3d2Xdm35ndMM++bQJExBIAAAA/Fmh3AQAAAOxGQAQAAPweAREAAPB7BEQAAMDvERABAAC/R0AEAAD8HgERAADwewREAADA7xEQAQAAv0dABLd74oknZMeOHRIQEOC291i9erX83//9n9v2D+9mWZY8//zzhd6ue/fuZltdFoW+p27vD4YPH26OtW7duh5XjmXLlplU0ux6XxQNARHcKjQ0VJ566ikTrGS/MOhjR8rMzJTo6GhZtGjRJReeAwcO5MgbFxcny5cvl4EDB+bIp/t/8MEHJSIiwqVyZd9n7jRlypRiOnqUpH79+hUp6AGuRLNmzcz3zu5AEFcuqBj2AeRr5MiREhQUJLNmzbrktcWLF8vHH39sao7q168vDzzwgPz4449y0003ycKFC535fv/9d3njjTfM45o1a8p9990nc+bMkdGjR8v7779v1s+bN0+SkpLMPly9KDreP7fdu3dfwRHDLjfeeKP87W9/k/Hjx1/yWpkyZSQjI8OWcvmLmTNnyueffy5paWniaW644Qa37bt58+bywgsvyE8//SSHDh0qsfdF8SMgglvdc8898s033+T5j6QGHp9++qnzuQY5W7Zskb///e85AiKtPcqeT4OYvXv3yqOPPuoMiLRm58svv5S7777b5YAo9/u7qmzZspKamnrJ+lKlSklgYKCcP39eiqpcuXKSkpJS5O2RN0+8SPuarKwsjz3PV/I36Y3vi6KhyQxuU69ePWnTpo0sXbrUpfxbt26VEydOmNqigmizmfZJyp1vyZIl5j3btm0rxUXb/zVIu/rqq+Xnn3+Ws2fPyoQJE0z1uAZhY8aMkUceecQEaHox0F+LqmfPnqZp78yZM5KYmChz586Vpk2b5tm/RKvcNTBLSEiQlStXFlieihUryltvvSWHDx+Wc+fOyZ49e+TJJ5/M0T9La9mOHz8u1apVc64rXbq0bN682ZRTg67s73/VVVfJf//7Xzl9+rScPHlSJk6cKCEhIZcEe88++6zZXt9XmzJffvllCQ4OzpFP18+fP1+uu+46Wbt2rQkc9+3bJ3/+85+LdCzZz/Nf/vIX5/uvW7dOOnTo4Mw3ffp0Uzuksjd/5teHqE6dOjJ58mTZuXOnCUD1uL/44osravbQY9Zy6TFrOf/617/mm/dPf/qT/Pbbb+a94+PjTQ1qrVq1LsnXqVMn+e6778x3Q79LmzZtkocfftj5eqtWrcyx6znW942NjZVp06ZJlSpVnHl69Ohhjj93M7O68847zWvXXHNNnuVs3769eV1/aOSmtR/6mtbo5td3R7fXHzf6d63Hun//flO+y/XRcnzuus/CHKurfXlyN8VnT46yuPId0fLpDzGlNUS595FXHyL9u5w6daocO3bMHMfGjRsvOb+ufu9RvKghgttce+21ZrlhwwaX8leqVEkqV65s/vgLok1wtWvXNheS7NavX++8MOk/MpejzSjh4eGXrNemt+y/7DTPggULTHPAJ598YgKy7DVgup8PPvjABER64erdu7fJr//4a1W61ig99NBD8ssvv5jAKne1+uzZs00w8PTTTxfY8Vz3o0FZVFSUqRnTQELP8SuvvCI1atQwNWaOZkoNft577z0ZPHiwWafNSC1atDAXx9w1UPqP/MGDB2XcuHHmwqgBnn4O2S9G+g/4iBEjTFm1+bJz586mvBrM3XrrrTn216hRI3OR0IvVjBkzTHn+85//mM9n+/bthToWh2HDhpn+aJpXLxQaOH399dfSoEED0xSm67U5VS/Sd91112U+eZGOHTua99PP9OjRoyaQvv/++81FTYPavGoAC9KyZUvTBKsXfv3M9Tuq5zz7d8VBz9tLL71kzrueV71A6vdDA+h27dqZwFT94Q9/kG+//dZc+N9++21zAdXz3b9/f3nnnXdMnj59+phzoIGCvq6fsQZiunQEOXpMen41CNPAPDtdp39va9asyfO49DPTAOSOO+64pHl5yJAh5vuuff/yosflOCevvvqqnDp1ypzn3N8XV7lyrK7SWugKFSrkWKffOf0x5fh3xZXviH5m+tno34z+QNAfasqxzE3/rdDt9W/k3//+twnMbr/9dvN3ov/+OT5X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AjyVNndpHyNNAICisTw1qQEDBric/84777TOnDlj9e7du8B8FStWtE6dOmWNHDky3zzBwcFWaGioM9WsWdOURx/bfV5IJBKJRCKJS0mv265cv32mhmjIkCEydepUuf322+WHH34oMO/p06dl9+7d0qhRo3zzpKenmwQAAHzfpY3vXmjo0KEyffp0ufPOO+X77793aSRbw4YNJTY2tkTKBwAAPJvHBUQarLRp08YkVb9+ffO4du3a5vmECRNkxowZzvwaBH388ccyZswY01coIiLCJJ1vwOH11183w/Pr1q0rXbp0McP5dajwrFmzbDhCAADgiSxPSt27d7fyMn36dPO6LpctW+bMr48Lyq9p1qxZVnR0tHXu3DnryJEj5nmDBg3c0gZJIpFIJBJJPCa5ev32uJmqPRUzVQMA4LvXb49rMgMAAChpBEQAAMDvERABAAC/R0AEAAD8HgERAADwewREAADA7xEQAQAAv0dABAAA/J7P3Ny1JCd4AgAAvnXdJiAq5AmNjo62uygAAKAI1/GCZqrm1h2FULNmzWK/bYd+QBpkRUVFcUsQN+I8lxzOdcngPJcMzrNvnGfdf0xMTIF5qCEqhMudzCuhXwD+2NyP81xyONclg/NcMjjP3n2eXdknnaoBAIDfIyACAAB+j4DIZmlpafLCCy+YJdyH81xyONclg/NcMjjP/nOe6VQNAAD8HjVEAADA7xEQAQAAv0dABAAA/B4BEQAA8HsERDZ74IEH5MCBA5Kamipr1qyRjh072l0knzJ27FhZt26dJCUlSVxcnMyZM0eaNGlid7F83lNPPSWWZclbb71ld1F8csb8mTNnysmTJyUlJUU2b94s7du3t7tYPiUwMFBefPFF2b9/vznHe/fulWeffdbuYvmErl27yjfffGNmpdZ/IwYMGHBJnvHjx5uJkPXcL1myRBo1alRi5dNRZiQb0h133GGdO3fOGjFihNWsWTPr/ffftxISEqxq1arZXjZfSQsWLLCGDx9uNW/e3GrdurX17bffWgcPHrTKlStne9l8NXXo0MHav3+/tXHjRuutt96yvTy+lCpVqmQdOHDA+uijj6yOHTta9erVs/r06WM1aNDA9rL5Uho3bpx14sQJ68Ybb7Tq1q1rDR482EpKSrIeeugh28vm7alv377WSy+9ZA0cONBSAwYMyPH6k08+aSUmJlq3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" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 13 - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## `RP` Robot\n", - "\n", - "Suppose that we have a `RP` robot defined by the following transformations:\n", - "- a rotation of $q_0$ of the base frame.\n", - "- a translation of $q_1$ along the $x-$axis of the current frame.\n", - "\n", - "For FKM and Jacobian calculation process, see lesson 4.\n", - "\n", - "For the control parameters, see lesson 5." - ] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2026-03-03T22:12:28.827190Z", - "start_time": "2026-03-03T22:12:28.623257Z" - } - }, - "cell_type": "code", - "source": [ - "def get_error(x, xd):\n", - " return x - xd\n", - "\n", - "def planar_robot_rp_fkm(q: np.array) -> np.array:\n", - " q_0 = q[0]\n", - " q_1 = q[1]\n", - " return np.array([q_1*cos(q_0),\n", - " q_1*sin(q_0),\n", - " q_0])\n", - "\n", - "def planar_robot_rp_jacobian(q):\n", - " q_0 = q[0]\n", - " q_1 = q[1]\n", - " return np.array(\n", - " [[-q_1*sin(q_0), cos(q_0)],\n", - " [ q_1*cos(q_0), sin(q_0)],\n", - " [ 1, 0]]\n", - " )\n", - "\n", - "eta = 1 # Control gain\n", - "T = 0.001 # Sampling time\n", - "# A desired task-space value\n", - "xd = np.array([2.0,\n", - " 2.0,\n", - " pi/10])\n", - "print(f\"xd = {xd}\")\n", - "\n", - "# Lists to store the value of each control iteration\n", - "x_tilde_norm_list = []\n", - "t_list = []\n", - "u_norm_list = []\n", - "\n", - "# Starting conditions\n", - "t = 0\n", - "q_0 = 0.0\n", - "q_1 = 0.0\n", - "q = np.array([q_0,\n", - " q_1])\n", - "\n", - "# Control for 10 seconds\n", - "while t < 10:\n", - " x = planar_robot_rp_fkm(q)\n", - " x_tilde = get_error(x, xd)\n", - " J = planar_robot_rp_jacobian(q)\n", - " J_inv = damped_pseudo_inverse(J)\n", - " u = -eta * J_inv @ x_tilde\n", - "\n", - " ## Store values\n", - " x_tilde_norm_list.append(np.linalg.norm(x_tilde))\n", - " t_list.append(t)\n", - " u_norm_list.append(np.linalg.norm(u))\n", - "\n", - " ## Variable updated for the next loop\n", - " q = q + u * T\n", - " t = t + T\n", - "\n", - "plt.plot(t_list,x_tilde_norm_list, label=f\"$\\\\eta$={eta}\")\n", - "\n", - "plt.title('(PP) Error exponential decay visualization')\n", - "plt.xlabel(\"Time [s]\")\n", - "plt.ylabel(\"$||\\\\tilde{ \\\\bf{x} } (t) ||$\")\n", - "plt.show()" - ], - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "xd = [2. 2. 0.31415927]\n" - ] - }, - { - "data": { - "text/plain": [ - "
" - ], - "image/png": "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" - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - } - ], - "execution_count": 14 - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson5_exercise_answers.md b/basic_lessons/lesson5_exercise_answers.md similarity index 94% rename from unstable/lesson5_exercise_answers.md rename to basic_lessons/lesson5_exercise_answers.md index 5930229..f2160be 100644 --- a/unstable/lesson5_exercise_answers.md +++ b/basic_lessons/lesson5_exercise_answers.md @@ -4,9 +4,19 @@ kernelspec: display_name: 'Python 3' --- +# L5 Exercise Answers + +*License: CC-BY-NC-SA 4.0* + +*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* + +## I found an issue +Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues + # Package installation ````{code-cell} +%%capture %pip install numpy matplotlib ```` diff --git a/basic_lessons/lesson5_tutorial.ipynb b/basic_lessons/lesson5_tutorial.ipynb deleted file mode 100644 index 87e9181..0000000 --- a/basic_lessons/lesson5_tutorial.ipynb +++ /dev/null @@ -1,900 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# L5 Kinematic Control\n", - "\n", - "*License: CC-BY-NC-SA 4.0*\n", - "\n", - "*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*\n", - "\n", - "## Prerequisites for the learner\n", - "The user of this notebook is expected to have prior knowledge in\n", - "- All the content and prerequisites of lessons 1, 2, 3, and 4.\n", - "\n", - "## I found an issue\n", - "Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues\n", - "\n", - "#### Latex Macros\n", - "$\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n", - "$\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}$\n" - ] - }, - { - "cell_type": "raw", - "metadata": { - "vscode": { - "languageId": "raw" - } - }, - "source": [ - "\\providecommand{\\myvec}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}\n", - "\\providecommand{\\mymatrix}[1]{{\\mathbf{\\boldsymbol{{#1}}}}}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Package installation\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture\n", - "%pip install numpy matplotlib\n", - "%pip install numpy matplotlib --break-system-packages" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Imports\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "tags": [ - "imports" - ] - }, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from math import pi, sin, cos" - ] - }, - { - "attachments": { - "Lesson4.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 2 DoF planar robot (RR)\n", - "\n", - "![Lesson4.png](attachment:Lesson4.png)\n", - "\n", - "For the 2-DoF planar robot shown in the figure, let $q_0\\triangleq q_0(t)$, $q_1\\triangleq q_1(t)$, $l_{0}$, $l_{1} \\in \\mathbb{R}$ be the parameters to calculate\n", - "\n", - "$$\\mymatrix{H}^{0}_{2}( q_0, l_{0},q_1,l_{1}) \\in SE(2),$$\n", - "\n", - "that is, the forward kinematics model of the 2 DoF planar manipulator with configuration space given by \n", - "\n", - "$$\\myvec{q} = \\left[\\begin{array}{ccc}\n", - " q_0 \\\\\n", - " q_1\n", - " \\end{array}\\right].$$\n", - "\n", - "and given the analytical Jacobian below\n", - "\n", - "$$\\dot{\\myvec{x}}=\\mymatrix{J} \\dot{\\myvec{q}}$$\n", - "\n", - "where \n", - "\n", - "$$\\myvec{x} = \\left[\\begin{array}{ccc}\n", - " p_{x} \\\\\n", - " p_{y} \\\\\n", - " \\phi_{z}\n", - " \\end{array}\\right],$$\n", - "\n", - "in which $p_{x}$, $p_{y}$, and $\\phi_{z}$ are, respectively, the $x$-axis position, the $y$-axis position, and the $z$-axis angle of $\\mathcal{F}_{2}$. Notice that $\\dot{l}_{0}=\\dot{l}_{1}=0$. \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Consider the forward kinematics model calculated as in the past lesson\n", - "\n", - "$$ \\mymatrix{H}^{0}_{2} = \\left[\\begin{array}{ccc}\n", - " \\cos{(q_0 + q_1)} & -\\sin{(q_0 + q_1)} & l_{0}\\cos{q_0} + l_{1}\\cos{(q_0 + q_1)}\\\\\n", - " \\sin{(q_0 + q_1)} & \\cos{(q_0 + q_1)} & l_{0}\\sin{q_0} + l_{1}\\sin{(q_0 + q_1)}\\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "This means that, from inspection,\n", - "\n", - "$$\\begin{align}\n", - "p_{x} & = l_{0}\\cos{q_0} + l_{1}\\cos{(q_0 + q_1)} \\\\\n", - "p_{y} & = l_{0}\\sin{q_0} + l_{1}\\sin{(q_0 + q_1)} \\\\\n", - "\\phi_{z} & = q_0 + q_1.\n", - "\\end{align}$$\n", - "\n", - "With those, we can obtain the task space values with a function called `planar_robot_fkm` so that it can be easily reused\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "def planar_robot_fkm(q):\n", - " \"\"\"\n", - " q: The configuration space values in radians.\n", - " returns the x, this, the current task space value where x = [p_x p_y phi_z]^T.\n", - " \"\"\"\n", - " l_0 = 0.2 # The robot parameters. They don't change in time, so they are constant here.\n", - " l_1 = 0.1\n", - "\n", - " q_0 = q[0] # Just to make it more readable.\n", - " q_1 = q[1] \n", - "\n", - " p_x = l_0 * cos(q_0) + l_1 * cos(q_0 + q_1)\n", - " p_y = l_0 * sin(q_0) + l_1 * sin(q_0 + q_1)\n", - " phi_z = q_0 + q_1\n", - "\n", - " return np.array([p_x,\n", - " p_y,\n", - " phi_z])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### Consider the analytical Jacobian\n", - "\n", - "We first calculate the Jacobian by hand, because programmatically there's nothing for you to do yet. As we did in the previous tutorial, here is the Jacobian\n", - "\n", - "$$ \\mymatrix{J} = \\left[\\begin{array}{ccc}\n", - " -l_{0}\\sin{q_0} - l_{1}\\sin{(q_0 + q_1)} & -l_{1}\\sin{(q_0 + q_1)} \\\\\n", - " l_{0}\\cos{q_0} + l_{1}\\cos{(q_0 + q_1)} & l_{1}\\cos{(q_0 + q_1)} \\\\\n", - " 1 & 1 \n", - " \\end{array}\\right].$$\n", - "\n", - "We transform this Jacobian calculation into the function `planar_robot_jacobian` shown below\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def planar_robot_jacobian(q): \n", - " \"\"\"\n", - " q: The configuration space values in radians.\n", - " returns the 3x2 Jacobian mapping [q_0 q_1]^T to [px py phi_z]^T.\n", - " \"\"\"\n", - " l_0 = 0.2 # The robot parameters. They don't change in time, so they are constant here.\n", - " l_1 = 0.1\n", - "\n", - " q_0 = q[0] # Just to make it more readable.\n", - " q_1 = q[1] \n", - "\n", - " J_1_1 = -l_0 * sin(q_0) - l_1 * sin(q_0 + q_1)\n", - " J_1_2 = -l_1 * sin(q_0 + q_1)\n", - " J_2_1 = l_0 * cos(q_0) + l_1 * cos(q_0 + q_1)\n", - " J_2_2 = l_1 * cos(q_0 + q_1)\n", - " J_3_1 = 1\n", - " J_3_2 = 1\n", - "\n", - " return np.array(\n", - " [[J_1_1, J_1_2],\n", - " [J_2_1, J_2_2],\n", - " [J_3_1, J_3_2]]\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Kinematic Control\n", - "\n", - "### 1. Define an error function\n", - "\n", - "We usually use\n", - "\n", - "$$\\tilde{\\myvec{x}}= \\myvec{x} - \\myvec{x}_d$$\n", - "\n", - "that can be implemented as the function `get_error` below\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "def get_error(x, xd):\n", - " \"\"\"In this case, we use the difference as the error.\n", - " x: current task-space vector.\n", - " xd: desired task-space vector.\n", - " \"\"\"\n", - " return x - xd" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2. Define the control loop\n", - "\n", - "We resort to the following control law\n", - "\n", - "$$\\myvec{u} = -\\eta \\mymatrix{J}^{+}\\tilde{\\myvec{x}}$$\n", - "\n", - "that can be easily implemented. Notice that we can resort to `np.linalg.pinv()` to perform the pseudo inversion. According to its [documentation](https://numpy.org/doc/2.2/reference/generated/numpy.linalg.pinv.html), it implements the Moore-Penrose pseudo-inversion based on the Singular Value Decomposition of all \"large\" singular values.\n", - "\n", - "\n", - "\n", - "For the control loop itself, we use all previous functions. The idea here is to show that the norm of the error decreases with the control action. The desired task space vector will not always be achievable. Nonetheless, we can show, as below, that the control action reduces the task-space error, $\\tilde{\\myvec{x}}$.\n", - "\n", - "Let $\\eta=0.5$ be the controller gain, $T=0.001$ be the sampling time, and $\\myvec{x}_d=\\left[\\begin{array}{ccc} 0.1 & 0.1 & \\frac{\\pi}{10} \\end{array}\\right]^T$. In addition, let the manipulator start at $t=0$ with $q_0=q_1=0$.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "xd = [0.1 0.1 0.31415927]\n" - ] - } - ], - "source": [ - "eta = 0.5 # Controller proportional gain\n", - "T = 0.001 # Sampling time\n", - "# Define initial values for the joint positions\n", - "q_0 = 0.0\n", - "q_1 = 0.0\n", - "q = np.array([q_0,\n", - " q_1])\n", - "\n", - "# A desired task-space value, defined by the problem at hand\n", - "xd = np.array([0.1,\n", - " 0.1,\n", - " pi/10])\n", - "print(f\"xd = {xd}\")\n", - "\n", - "# Define a stop criteria, in this case let's control for 10 seconds\n", - "t = 0 # Current time\n", - "\n", - "# Lists to store the value of each control iteration\n", - "x_tilde_norm_list = []\n", - "t_list = []\n", - "\n", - "while t < 10:\n", - " # Calculate task-space value, x\n", - " x = planar_robot_fkm(q)\n", - " # Calculate task-space error, x_tilde\n", - " x_tilde = get_error(x, xd)\n", - " # Get the Jacobian\n", - " J = planar_robot_jacobian(q)\n", - " # Invert the Jacobian, for example, with numpy's implementation of it\n", - " J_inv = np.linalg.pinv(J)\n", - " # Calculate the control action\n", - " u = -eta * J_inv @ x_tilde\n", - " \n", - " ## Store values in the list so that we can print them later\n", - " x_tilde_norm_list.append(np.linalg.norm(x_tilde))\n", - " t_list.append(t)\n", - "\n", - " ## Variable updated for the next loop\n", - " q = q + u * T # Update law using the sampling time\n", - " t = t + T " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Optional: Print the data\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To help visualise the behaviour of the controller, you can optionally plot the data. These data show that with the defined parameters the qualitative behaviour is very close to exponential decay. However the error does not converge to zero, meaning that the manipulator did not reach its target. Indeed, this is usually the case when the target is outside the reach of the manipulator or all task-space desired values cannot be simultaneously satisfied.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(t_list,x_tilde_norm_list)\n", - "plt.title('(RR) Error exponential decay visualization (Moore-Penrose)')\n", - "plt.xlabel(\"Time [s]\")\n", - "plt.ylabel(\"$||\\\\tilde{ \\\\bf{x} } (t) ||$\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Alternative Jacobian Inversion Strategies\n", - "\n", - "The SVD-based Moore-Penrose pseudo-inverse is a common strategy for matrix inversion. It is important to notice, however, that this is not the only one. In addition, it is not always the best choice for robot control.\n", - "\n", - "Another common strategy is the so-called damped pseudo-inverse, described below. It is usually the easiest choice to embed robustness to singularities in the controller.\n", - "\n", - "$$\\mymatrix{J}^{\\dagger}=\\mymatrix{J}^T\\left(\\mymatrix{J}\\mymatrix{J}^T + \\lambda^2\\mymatrix{I}\\right)^{-1},$$\n", - "\n", - "defined in the function `damped_pseudo_inverse()` below in which we call $\\lambda$ as the variable `damping`\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "def damped_pseudo_inverse(A: np.array, damping: float = 0.01):\n", - " \"\"\"Calculates the damped pseudo inverse of A\"\"\"\n", - " if damping == 0:\n", - " raise Exception(f\"Damping is {damping} but should be different from zero\")\n", - " \n", - " return A.T @ np.linalg.inv(A @ A.T + (damping ** 2) * np.eye(A.shape[0]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "with that, our controller becomes, changing only the inversion strategy,\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "xd = [0.1 0.1 0.31415927]\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "eta = 0.5 # Controller proportional gain\n", - "T = 0.001 # Sampling time\n", - "# Define initial values for the joint positions\n", - "q_0 = 0.0\n", - "q_1 = 0.0\n", - "q = np.array([q_0,\n", - " q_1])\n", - "\n", - "# A desired task-space value, defined by the problem at hand\n", - "xd = np.array([0.1,\n", - " 0.1,\n", - " pi/10])\n", - "print(f\"xd = {xd}\")\n", - "\n", - "# Define a stop criteria, in this case let's control for 10 seconds\n", - "t = 0 # Current time\n", - "\n", - "# Lists to store the value of each control iteration\n", - "x_tilde_norm_list = []\n", - "t_list = []\n", - "\n", - "while t < 10:\n", - " # Calculate task-space value, x\n", - " x = planar_robot_fkm(q)\n", - " # Calculate task-space error, x_tilde\n", - " x_tilde = get_error(x, xd)\n", - " # Get the Jacobian\n", - " J = planar_robot_jacobian(q)\n", - " # Invert the Jacobian using the damped pseudo-inverse\n", - " J_inv = damped_pseudo_inverse(J)\n", - " # Calculate the control action\n", - " u = -eta * J_inv @ x_tilde\n", - " \n", - " ## Store values in the list so that we can print them later\n", - " x_tilde_norm_list.append(np.linalg.norm(x_tilde))\n", - " t_list.append(t)\n", - "\n", - " ## Variable updated for the next loop\n", - " q = q + u * T # Update law using the sampling time\n", - " t = t + T \n", - "\n", - "# (Optional) plot the data\n", - "plt.plot(t_list,x_tilde_norm_list)\n", - "plt.title('(RR) Error exponential decay visualization (damped pseudo-inverse)')\n", - "plt.xlabel(\"Time [s]\")\n", - "plt.ylabel(\"$||\\\\tilde{ \\\\bf{x} } (t) ||$\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Convergence rate of discrete-time systems\n", - "\n", - "Although we usually attempt to find $\\myvec{u}$ such that, the error $\\tilde{\\myvec{x}}$ converges exponentially. This means that, in the right conditions, we will have a convergence \n", - "\n", - "$$\\tilde{\\myvec{x}}(t)=\\tilde{\\myvec{x}}(0)e^{-\\eta t}$$\n", - "\n", - "in continuous time, hence the convergence depends only on $\\eta$.\n", - "\n", - "However, given that our implementation is in discrete time, the convergence is affected by our sampling time, $T$. In practice, we set $T$ as the fastest sampling time that can be achieved by the hardware, e.g. the robot controller. In many cases, this is about 1 millisecond in practice.\n", - "\n", - "The effect on the convergence for different $\\eta$ can be seen, computationally, below\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "xd = [0.1 0.1 0.31415927]\n" - ] - }, - { - "data": { - "image/png": "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EkIIIUSNJ4FIZ4sWLSIsLAw3Nze6d+/Ojh079C6pWpkzZw5du3bF29ubwMBAhg4dytGjR/Uuq9p7/fXXURSFqVOn6l1KtXPu3DkefPBBateujbu7O23btmXXrl16l1WtWCwWXn75ZRo1aoS7uztNmjTh1Vdfve5aWOL6Nm/ezJAhQwgJCUFRFNasWVPocVVVmTFjBnXr1sXd3Z3w8HCOHTtWKbVJINLRypUriYyMZObMmezZs4f27dsTERFBfHy83qVVG5s2beLJJ59k27ZtrF+/ntzcXAYOHEh6errepVVbO3fu5L333qNdu3Z6l1LtJCUl0atXL1xcXFi7di2HDh3i3//+N35+fnqXVq288cYbLF68mIULF3L48GHeeOMN5s6dyzvvvKN3aVVeeno67du3Z9GiRcU+PnfuXBYsWMCSJUvYvn07np6eREREkJWVVfHFqUI33bp1U5988kn79xaLRQ0JCVHnzJmjY1XVW3x8vAqomzZt0ruUauny5ctqs2bN1PXr16t9+/ZVn376ab1LqlamTZum9u7dW+8yqr077rhDffjhhwvtu+eee9QHHnhAp4qqJ0BdvXq1/Xur1aoGBwerb775pn1fcnKy6urqqn7++ecVXo+0EOkkJyeH3bt3Ex4ebt9nMBgIDw9n69atOlZWvaWkpADg7++vcyXV05NPPskdd9xR6OdalJ9vv/2WLl26MGLECAIDA+nYsSNLly7Vu6xqp2fPnkRFRfHXX38BsG/fPrZs2cLgwYN1rqx6i4mJITY2ttDnh6+vL927d6+U34uyuKtOEhISsFgsBAUFFdofFBTEkSNHdKqqerNarUydOpVevXrRpk0bvcupdr744gv27NnDzp079S6l2vr7779ZvHgxkZGR/N///R87d+5kypQpmM1mxo4dq3d51caLL75IamoqLVq0wGg0YrFYeO2113jggQf0Lq1ai42NBSj296LtsYokgUjUGE8++SQHDx5ky5YtepdS7Zw5c4ann36a9evX4+bmpnc51ZbVaqVLly7Mnj0bgI4dO3Lw4EGWLFkigagcffnll3z66ad89tlntG7dmujoaKZOnUpISIi8z9WY3DLTSUBAAEajkbi4uEL74+LiCA4O1qmq6mvy5Ml8//33bNiwgfr16+tdTrWze/du4uPj6dSpEyaTCZPJxKZNm1iwYAEmkwmLxaJ3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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "etas = [0.01, 0.1, 1, 10] # Different gains to iterate over the same control goals\n", - "T = 0.001 # Sampling time\n", - "# A desired task-space value, defined by the problem at hand\n", - "xd = np.array([0.1,\n", - " 0.1,\n", - " pi/10])\n", - "print(f\"xd = {xd}\")\n", - "\n", - "# Lists to store the value of each control iteration\n", - "x_tilde_norm_list = []\n", - "t_list = []\n", - "u_norm_list = []\n", - "\n", - "# Run the controller again for each gain\n", - "for i in range(0, len(etas)):\n", - " # Define a stop criteria, in this case let's control for 10 seconds\n", - " t = 0 # Current time\n", - " eta = etas[i]\n", - " # Define initial values for the joint positions\n", - " q_0 = 0.0\n", - " q_1 = 0.0\n", - " q = np.array([q_0,\n", - " q_1])\n", - " \n", - " x_tilde_norm_list.append([])\n", - " t_list.append([])\n", - " u_norm_list.append([])\n", - "\n", - " while t < 10:\n", - " # Calculate task-space value, x\n", - " x = planar_robot_fkm(q)\n", - " # Calculate task-space error, x_tilde\n", - " x_tilde = get_error(x, xd)\n", - " # Get the Jacobian\n", - " J = planar_robot_jacobian(q)\n", - " # Invert the Jacobian using the damped pseudo-inverse\n", - " J_inv = damped_pseudo_inverse(J)\n", - " # Calculate the control action\n", - " u = -eta * J_inv @ x_tilde\n", - " \n", - " ## Store values in the list so that we can print them later\n", - " x_tilde_norm_list[i].append(np.linalg.norm(x_tilde))\n", - " t_list[i].append(t)\n", - " u_norm_list[i].append(np.linalg.norm(u))\n", - "\n", - " ## Variable updated for the next loop\n", - " q = q + u * T # Update law using the sampling time\n", - " t = t + T \n", - "\n", - "\n", - " plt.plot(t_list[i],x_tilde_norm_list[i], label=f\"$\\\\eta$={eta}\")\n", - "\n", - "plt.title('(RR) Error exponential decay visualization for multiple $\\\\eta$')\n", - "plt.legend(loc=\"upper right\")\n", - "plt.xlabel(\"Time [s]\")\n", - "plt.ylabel(\"$||\\\\tilde{ \\\\bf{x} } (t) ||$\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Alright, then why don't we just choose the largest $\\eta \\approx \\infty$?\n", - "\n", - "Engineering is the art of trade-off. Whenever we have a large $\\eta$, that means the configuration-space velocities will comparatively be higher.\n", - "\n", - "Using our example, we can see that the control signal norm is heavily affected by $\\eta$. Therefore, for feasibility, it is important to keep the $\\eta$ so that the system can handle it. In fact, gains that are too high are one of the major risks that can break robots or hurt people when real hardware is used without the proper safeguards.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHJCAYAAABjZPjUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAA9hAAAPYQGoP6dpAABb3klEQVR4nO3deXhTZd4+8Ptkb7qE7gttoQgiUCk7ggqo1QLKyMwruLOoKAoi0984iqOAqK3gK6KCLM4g4zgorws4oyOIdWEQVLYiiKAgUKB0g7Zp0zbNcn5/tAkNTUvSJjmn6f25rnMlOTnL96S0uXnOc54jiKIogoiIiChIKaQugIiIiMifGHaIiIgoqDHsEBERUVBj2CEiIqKgxrBDREREQY1hh4iIiIIaww4REREFNYYdIiIiCmoMO0RERBTUGHaIiIgoqDHsEBERUVBj2KGAWLJkCa644grY7Xa/72vVqlVITU2F2Wz2+746gnXr1kEQBJw4cUIW2/EVudXjb7t27cLIkSMRGhoKQRCQn58f8BoWLlwIQRBc5rn7ObRUqxyOgTonhh3yO6PRiMWLF+OJJ56AQtHwT87xB9IxqVQqdO3aFdOmTcOZM2eabcOb5adNm4b6+nqsXr3aqzqPHTuGhx56CD169IBOp0NERASuvvpqvPrqq6itrW37B3AJO3bswMKFC1FRUeG3fVDHZrFYMGnSJJw/fx6vvPIK/vGPf6Bbt25Sl+VWS7V2pGMA+HsZbFRSF0DBb+3atbBarbjzzjubvbdo0SKkpaWhrq4O3333HdatW4ft27fj4MGD0Ol0bVpep9Nh6tSpWLp0KR599NFm/xN159NPP8WkSZOg1WoxZcoUpKeno76+Htu3b8fjjz+On376CWvWrGn/h+HGjh078Oyzz2LatGno0qWLX/bhC/feey/uuOMOaLVaqUvpdI4dO4aTJ0/izTffxAMPPCB1OS4u/nfRUq2HDx+W7TG401F+L8kzDDvkd2+99RZ+97vfuQ0v48aNw5AhQwAADzzwAGJiYrB48WL861//wuTJk9u8/OTJk7FkyRJ89dVXuP7661ut7/jx47jjjjvQrVs3fPnll0hMTHS+N2vWLBw9ehSffvppm47dH0wmE0JDQwO+X6VSCaVSGfD9dhT+/LmUlJQAgE+/dH1V78X/LlqqVc7HQMGPp7HIr44fP44ff/wRmZmZHi1/7bXXAmj432F7lh88eDCioqLw8ccfX3IbS5YsQXV1Nf72t7+5BB2Hnj174rHHHnO+3rdvH8aNG4eIiAiEhYXhhhtuwHfffddsPUf/hqNHjzr/d2gwGDB9+nTU1NQ4l3n88ccBAGlpac7TdI7+D45tHDp0CHfddRciIyNxzTXXeF2LJ6qqqjB37lx0794dWq0WcXFxuPHGG7F3714ALfeR+frrrzFkyBDodDpcdtllWL16dbO+HZ58Fg4nT57EI488gt69eyMkJATR0dGYNGlSm/vmeLNvwLPPtLWfi+O9X375Bffccw8MBgNiY2PxzDPPQBRFnDp1CrfeeisiIiKQkJCAl19+udX6p02bhtGjRwMAJk2aBEEQMGbMGJ/V25Lt27dj6NChLj9Xd5r+u2ip1ksdw5kzZ3DfffchPj4eWq0W/fr1w9q1a706Bm+2cal/C5f6vWzJ3//+dwiCgH379mHOnDlISEhASEgIJkyYgPLy8lbXJf9iyw751Y4dOwAAgwYN8mh5xx+TyMjIdi8/aNAgfPvtt5fcxr///W/06NEDI0eOvOSyP/30E6699lpERETgz3/+M9RqNVavXo0xY8bgm2++wfDhw5utM3nyZKSlpSE3Nxd79+7FX//6V8TFxWHx4sX4wx/+gF9++QXvvvsuXnnlFcTExAAAYmNjXbYxadIk9OrVCzk5ORBFsc21tGbmzJn44IMPMHv2bPTt2xfnzp3D9u3b8fPPP7f489u3bx/Gjh2LxMREPPvss7DZbFi0aFGz+j35LBx27dqFHTt24I477kBycjJOnDiBlStXYsyYMTh06BD0er1Xx+XNvr39TN39XBxuv/129OnTBy+++CI+/fRTPP/884iKisLq1atx/fXXY/HixfjnP/+JP/3pTxg6dChGjRrltu6HHnoIXbt2RU5ODubMmYOhQ4ciPj7e5/U2deDAAdx0002IjY3FwoULYbVasWDBAud+W9JSrWFhYS0eQ3FxMa666ioIgoDZs2cjNjYWn332Ge6//34YjUbMnTv3ksfg7TYu9W/B09/Li/34449QKBSYMWMGrrzySixcuBBff/01NmzYgNdeew0LFixodX3yI5HIj55++mkRgFhVVeUy/6233hIBiF988YVYWloqnjp1Svzggw/E2NhYUavViqdOnWrX8qIoig8++KAYEhLSan2V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UpcW1Hjpuf/8+9//FtPT00WtViteccUV4po1a6QuKegYjUbxscceE1NTU0WdTif26NFD/Mtf/iKazWapS+vQvvrqK7d/j6dOnSqKYsPl588884wYHx8varVa8YYbbhCPHDkSsPoEUeSwkURERBS82GeHiIiIghrDDhEREQU1hh0iIiIKagw7REREFNQYdoiIiCioMewQERFRUGPYISIioqDGsENEsjNt2rTAjazaxLp16yAIAgRBwNy5cz1aZ9q0ac51Nm3a5Nf6iKhteLsIIgooQRBafX/BggV49dVXIdV4pxEREThy5AhCQ0M9Wv7VV1/Fiy++iMTERD9XRkRtxbBDRAF19uxZ5/MNGzZg/vz5LjfADAsLQ1hYmBSlAWgIY97cidlgMMBgMPixIiJqL57GIqKASkhIcE4Gg8EZLhxTWFhYs9NYY8aMwaOPPoq5c+ciMjIS8fHxePPNN5032A0PD0fPnj3x2Wefuezr4MGDGDduHMLCwhAfH497770XZWVlXtf8xhtvoFevXtDpdIiPj8dtt93W3o+BiAKIYYeIOoS///3viImJwQ8//IBHH30UDz/8MCZNmoSRI0di7969uOmmm3DvvfeipqYGAFBRUYHrr78eAwcOxO7du7F582YUFxdj8uTJXu139+7dmDNnDhYtWoQjR45g8+bNGDVqlD8OkYj8hKexiKhDyMjIwNNPPw0AmDdvHl588UXExMRgxowZAID58+dj5cqV+PHHH3HVVVdh+fLlGDhwIHJycpzbWLt2LVJSUvDLL7/g8ssv92i/BQUFCA0NxS233ILw8HB069YNAwcO9P0BEpHfsGWHiDqE/v37O58rlUpER0fjyiuvdM6Lj48HAJSUlAAA9u/fj6+++srZBygsLAxXXHEFAODYsWMe7/fGG29Et27d0KNHD9x777345z//6Ww9IqKOgWGHiDoEtVrt8loQBJd5jqu87HY7AKC6uhoTJkxAfn6+y/Trr796dRoqPDwce/fuxbvvvovExETMnz8fGRkZqKioaP9BEVFA8DQWEQWlQYMG4cMPP0T37t2hUrXvT51KpUJmZiYyMzOxYMECdOnSBV9++SX+8Ic/+KhaIvIntuwQUVCaNWsWzp8/jzvvvBO7du3CsWPHsGXLFkyfPh02m83j7XzyySd47bXXkJ+fj5MnT+Ltt9+G3W5H7969/Vg9EfkSww4RBaWkpCR8++23sNlsuOmmm3DllVdi7ty56NKlCxQKz//0denSBR999BGuv/569OnTB6tWrcK7776Lfv36+bF6IvIlQZRqmFIiIplZt24d5s6d26b+OIIgYOPGjZLc5oKIWseWHSKiJiorKxEWFoYnnnjCo+Vnzpwp6YjPRHRpbNkhImpUVVWF4uJiAA2nr2JiYi65TklJCYxGIwAgMTHR43tqEVHgMOwQERFRUONpLCIiIgpqDDtEREQU1Bh2iIiIKKgx7BAREVFQY9ghIiKioMawQ0REREGNYYeIiIiCGsMOERERBTWGHSIiIgpq/x/E421B6aRXpgAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Run the controller again for each gain\n", - "for i in range(0, len(etas)):\n", - " eta=etas[i]\n", - " plt.plot(t_list[i],u_norm_list[i], label=f\"$\\\\eta$={eta}\")\n", - "\n", - "plt.title('(RR) Control signal norm for different $\\\\eta$')\n", - "plt.legend(loc=\"upper right\")\n", - "plt.xlabel(\"Time [s]\")\n", - "plt.ylabel(\"$||u (t) ||$\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 3 DoF Planar Robot (PRR)\n", - "\n", - "As you noticed from the previous discussion, what is important for any new robot after you understand these concepts are\n", - "- Defining a task space, $\\myvec{x}$, that correctly represents the task (and manipulator if applicable).\n", - "- Obtaining the Forward Kinematics Model (FKM) $f(\\myvec{q})=\\myvec{x}$ that maps the configuration space, $\\myvec{q}$, to the task space.\n", - "- Obtaining the analytical Jacobian so that the kinematic control can be applied.\n", - "- The kinematic control itself, aside from dimensions, does not need to change in general.\n", - "\n", - "For instance, we can even solve with no diagram as long as this information is given. Consider a PRR manipulator with configuration space\n", - "\n", - "$$\\mathbb{R}^3 \\ni \\myvec{q}_C \\triangleq \\left[\\begin{array}{ccc}\n", - " q_0 \\\\\n", - " q_1 \\\\\n", - " q_2\n", - " \\end{array}\\right].$$\n", - "\n", - "\n", - "And link lengths $l_{0}, l_{1}, l_{2}\\in \\mathbb{R}$.\n", - "\n", - "## Task Space & Forward Kinematics Model (FKM)\n", - "\n", - "Let \n", - "\n", - "$$\\begin{align*}\n", - "s_1 & \\triangleq \\sin{q_1} \\\\\n", - "s_{12} & \\triangleq \\sin{(q_1 + q_2)} \\\\\n", - "c_1 & \\triangleq \\cos{q_1} \\\\\n", - "c_{12} & \\triangleq \\cos{(q_1 + q_2)}.\n", - "\\end{align*}$$\n", - "\n", - "The forward kinematics of this manipulator is therefore given by\n", - "\n", - "$$ SE(2) \\ni \\mymatrix{H}^{0}_{3}(q_0,q_1,q_2) = \\left[\\begin{array}{ccc}\n", - " c_{12} & -s_{12} & (l_0 + q_0) + l_{1}c_{1} + l_{2}c_{12}\\\\\n", - " s_{12} & c_{12} & l_{1}s_{1} + l_{2}s_{12}\\\\\n", - " 0 & 0 & 1\n", - " \\end{array}\\right].$$\n", - "\n", - "Because this robot is planar, the following task space is necessary and sufficient to fully describe the reachable space\n", - "\n", - "$$\\myvec{x} = \\left[\\begin{array}{ccc}\n", - " p_{x} \\\\\n", - " p_{y} \\\\\n", - " \\phi_{z}\n", - " \\end{array}\\right].$$\n", - "\n", - "The values can be obtained from inspection of $\\mymatrix{H}^{0}_{3}(q_0,q_1,q_2)$,\n", - "\n", - "$$\\begin{align*}\n", - "p_{x} & = (l_0 + q_0) + l_{1}c_{1} + l_{2}c_{12} \\\\\n", - "p_{y} & = l_{1}s_{1} + l_{2}s_{12} \\\\\n", - "\\phi_{z} & = q_1 + q_2,\n", - "\\end{align*}$$\n", - "\n", - "which means that the FKM, $\\myvec{x}=f(\\myvec{q})$, in this case is equivalent to\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "def planar_robot_prr_fkm(q: np.array) -> np.array:\n", - " \"\"\"\n", - " q: The configuration space values in radians.\n", - " returns the x, this, the current task space value where x = [p_x p_y phi_z]^T.\n", - " \"\"\"\n", - " l_0 = 0.2 # The robot parameters. They don't change in time, so they are constant here.\n", - " l_1 = 0.1\n", - " l_2 = 0.3\n", - "\n", - " q_0 = q[0] # Just to make it more readable.\n", - " q_1 = q[1] \n", - " q_2 = q[2] \n", - "\n", - " s1 = sin(q_1)\n", - " c1 = cos(q_1)\n", - " s12 = sin(q_1 + q_2)\n", - " c12 = cos(q_1 + q_2)\n", - "\n", - " p_x = (l_0 + q_0) + l_1*c1 + l_2*c12\n", - " p_y = l_1*s1 + l_2*s12\n", - " phi_z = q_1 + q_2\n", - "\n", - " return np.array([p_x,\n", - " p_y,\n", - " phi_z])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "## Analytical Jacobian\n", - "\n", - "The analytical Jacobian is\n", - "\n", - "$$ \\mymatrix{J}_C(q_0,q_1,q_2) = \\left[\\begin{array}{ccc}\n", - " 1 & - l_{1}s_{1} - l_{2}s_{12} & -l_{2}s_{12}\\\\\n", - " 0 & l_{1}c_{1} + l_{2}c_{12} & l_{2}c_{12}\\\\\n", - " 0 & 1 & 1 \n", - " \\end{array}\\right].$$\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "def planar_robot_prr_jacobian(q): \n", - " \"\"\"\n", - " q: The configuration space values in radians.\n", - " returns the 3x3 Jacobian mapping [q_0 q_1 q_2]^T to [px py phi_z]^T.\n", - " \"\"\"\n", - " l_0 = 0.2 # The robot parameters. They don't change in time, so they are constant here.\n", - " l_1 = 0.1\n", - " l_2 = 0.3\n", - "\n", - " q_0 = q[0] # Just to make it more readable.\n", - " q_1 = q[1] \n", - " q_2 = q[2] \n", - "\n", - " s1 = sin(q_1)\n", - " c1 = cos(q_1)\n", - " s12 = sin(q_1 + q_2)\n", - " c12 = cos(q_1 + q_2)\n", - "\n", - " J_1_1 = 1\n", - " J_2_1 = 0\n", - " J_3_1 = 0\n", - "\n", - " J_1_2 = -l_1*s1 - l_2*s12\n", - " J_2_2 = l_1*c1 + l_2*c12\n", - " J_3_2 = 1\n", - "\n", - " J_1_3 = -l_2*s12\n", - " J_2_3 = l_2*c12\n", - " J_3_3 = 1\n", - "\n", - " return np.array(\n", - " [[J_1_1, J_1_2, J_1_3],\n", - " [J_2_1, J_2_2, J_2_3],\n", - " [J_3_1, J_3_2, J_3_3]]\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Kinematic Control\n", - "\n", - "With this, a similar control as before, but changing the FKM and Jacobian can be easily achieved. We change only \n", - "1. The configuration space in lines 20 to 25.\n", - "2. `planar_robot_prr_fkm` in line 33\n", - "3. `planar_robot_prr_jacobian` in line 37. \n", - "\n", - "
\n", - "The rest of the control loop is unchanged! This is one of the advantages of kinematic control.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "xd = [0.1 0.1 0.31415927]\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHJCAYAAABjZPjUAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAA9hAAAPYQGoP6dpAACIZElEQVR4nO3dd3xT5f7A8c9JundL6YJC2ZuyK0tAEFwoIgJelKX4Q0DEXhW5XsF1wXURFQTFCzhQURRUVFQQVGSPMmTvMtoy29Ld5Pz+OE1ooYWkNDlp+n2/XkfJyRnfpG367fN8n+dRVFVVEUIIIYRwUwa9AxBCCCGEcCRJdoQQQgjh1iTZEUIIIYRbk2RHCCGEEG5Nkh0hhBBCuDVJdoQQQgjh1iTZEUIIIYRbk2RHCCGEEG5Nkh0hhBBCuDVJdoQQQgjh1iTZEUIIIYRbk2SnnF5//XUaN26M2WzWOxSrOXPmUKtWLfLy8vQORbioBQsWoCgKR48edeq5AC+88AKKopTr3MrmRt8rR8WhV1x6vx+bNm2iU6dO+Pv7oygKSUlJusRR0ex5X/X82XcFkuyUQ0ZGBq+99hoTJ07EYNDeQss3g2Xz8fGhYcOGjBs3jtTUVOu5Vx7n4eFBjRo1GD58OCdPnrzqXvYcP3z4cPLz83n//fdteh1XXvvKbf369TfwLgm9rF27lhdeeIGLFy/qHYqoYlzxe6+goID777+f8+fP89Zbb/HJJ59Qu3ZtvcNyGFf8GrgCD70DqIzmzZtHYWEhDzzwwFXPvfTSS9SpU4fc3FzWrFnD7Nmz+fHHH9m1axd+fn6lHrd+/XoWLFjAmjVr2LVrFz4+Pte8blnH+/j4MGzYMKZPn87jjz9u81/RlmtfqX79+ra+JcKFrF27lhdffJHhw4cTEhJS4rmHHnqIwYMH4+3trU9wVYSrvs+Ojqus7z09349Dhw5x7Ngx5s6dyyOPPOL0+zubK34NXIEkO+Uwf/587r777lKTkttvv5127doB8Mgjj1CtWjWmT5/Ot99+WyI5uvK48PBwXnvtNb777jsGDhx43euWdfzAgQN5/fXXWbVqFbfccotNr6f4tW2VlZWFv7+/3c9VxPVF+RmNRoxGo95huD1XfZ/1ikvP9yMtLQ3gqsT/RlTGzydX/Z50FunGstORI0fYsWMHvXr1sul4S8Jx5MiRax7XtWtXQPsrxBZlHd+2bVvCwsL49ttvbbqOLSy1Frt37+Yf//gHoaGhdOnS5brPAWzbto3bb7+doKAgAgIC6Nmz51XdY9e7RmlOnjzJyJEjiYyMxNvbm2bNmjFv3rwSx+Tk5NC4cWMaN25MTk6Odf/58+eJjo6mU6dOmEwm6/337t3LwIEDCQoKolq1ajzxxBPk5uZedW97XtPBgwetf2EFBwczYsQIsrOzy/V6bLnmCy+8wNNPPw1AnTp1rF2S16rZOHbsGGPGjKFRo0b4+vpSrVo17r///hvqn1+zZg3t27fHx8eHevXqldm1asvrthz38MMPExMTg7e3N3Xq1OGxxx4jPz/frtexatUqFEVhyZIlV93js88+Q1EU1q1bV2qsixcvRlEUfv/996uee//991EUhV27dgFXv8+ZmZlMmDCBuLg4vL29iYiI4NZbb2Xr1q3WawwfPpy4uLirrl1arVN5v2ZXxnX06NFrdmXbc79rfe+VVfPhiJ+l4oYPH063bt0AuP/++1EUhe7du5fr/rZ+PlmO379/Pw8++CDBwcFUr16d559/HlVVSU5O5p577iEoKIioqCj++9//XhWzrd8HpR1jz9fA3s++K9n681uajz76CEVR2LZtG+PHjycqKgpfX1/69u3LhQsXbLqGPaRlx05r164FoE2bNjYdb0lGqlWrds3jLN+AoaGhNl33Wse3adOGv/76y6brAKSnp3P27NkS+xRFuSrm+++/nwYNGjB16lRUVb3uc3///Tddu3YlKCiIZ555Bk9PT95//326d+/O77//TkJCgs3XLy41NZWbbroJRVEYN24c1atX56effuLhhx8mIyODCRMmAODr68tHH31E586dee6555g+fToAY8eOJT09nQULFpT4S2fgwIHExcUxbdo01q9fzzvvvMOFCxf4+OOPrcfY+5oGDhxInTp1mDZtGlu3buXDDz8kIiKC1157ze7XY8s1+/fvz/79+/n888956623CA8PB6B69eplvp+bNm1i7dq1DB48mJo1a3L06FFmz55N9+7d2b17d4nuV1vs3LmT3r17U716dV544QUKCwuZMmUKkZGRJY6z9XWfOnWKDh06cPHiRR599FEaN27MyZMnWbx4MdnZ2Xh5edn8Orp3705sbCwLFy7k3nvvLRHPwoULqVevHh07diz1dd15550EBATw5ZdfWn+BWixatIhmzZrRvHnzUs8dPXo0ixcvZty4cTRt2pRz586xZs0a9uzZY/NnSXEV9TWrXr06n3zySYl9BQUFPPnkk9b31db72fu954ifpSv93//9HzVq1GDq1KmMHz+e9u3bW78PHfX5ZDFo0CCaNGnCq6++yg8//MArr7xCWFgY77//PrfccguvvfYaCxcu5KmnnqJ9+/bcfPPN173m9ZTn5x9s++y7kr2fW1fasWMHBoOBUaNG0aJFC1544QVWr17NokWLeOedd5gyZYrdr/+aVGGXf//73yqgZmZmltg/f/58FVBXrFihnjlzRk1OTla/+OILtVq1aqqvr6964sSJMo9bvHixWr16ddXb21tNTk6+7nWvdbyqquqjjz6q+vr6Xve1WK5d2ubt7W09bsqUKSqgPvDAA1dd41rP9evXT/Xy8lIPHTpk3Xfq1Ck1MDBQvfnmm226RmkefvhhNTo6Wj179myJ/YMHD1aDg4PV7OzsEvsnTZqkGgwG9Y8//lC/+uorFVBnzJhx1f3vvvvuEueNGTNGBdTt27eX+zWNHDmyxDXvvfdetVq1auV6PbZe84033lAB9ciRI+qVLF/z4s9d+X6pqqquW7dOBdSPP/74mueWpl+/fqqPj4967Ngx677du3erRqNRLf6RY+vrHjp0qGowGNRNmzZddS+z2Wz365g0aZLq7e2tXrx40bovLS1N9fDwUKdMmXLN1/bAAw+oERERamFhoXXf6dOnVYPBoL700kvWfVe+V8HBwerYsWOvee1hw4aptWvXvmq/5eteXHm/ZrZ8DceMGaMajUb1t99+s/t+ZX3vlXZfR/wslWbVqlUqoH711Vcl9jvq88ly/KOPPmrdV1hYqNasWVNVFEV99dVXrfsvXLig+vr6qsOGDbPus+f7oLT31Z6vga2ffaWda+/n8JVuvfVWFVAXLVpUYn90dLR6xx13XPPc8pBuLDudO3cODw8PAgICSn2+V69eVK9endjYWAYPHkxAQABLliyhRo0aZR43YMAA/P39+e6776hZs+Z1r3u940NDQ8nJybluE6/FrFmz+PXXX0tsP/3001XHjR49usxrXPmcyWTil19+oV+/ftStW9e6Pzo6mn/84x+sWbOGjIwMm69voaoqX3/9NX379kVVVc6ePWvd+vTpQ3p6eomuAdCaaps1a8awYcMYM2YM3bp1Y/z48Vdde+zYsSUeP/744wD8+OOPFfaaunbtyrlz56zHlef1XO+a9vL19bX+u6CggHPnzlG/fn1CQkKuuvf1mEwmfv75Z/r160etWrWs+5s0aUKfPn2sj2193WazmaVLl9K3b99S68qKN+vb+jqGDh1KXl4eixcvtu5btGgRhYWFPPjgg9d8fYMGDSItLY3Vq1db9y1evBiz2cygQYPKPC8kJIQNGzZw6tSpa17fVhX5NSvu448/5r333uP111+nR48eDrufI36WnH3/6yleDG00GmnXrh2qqvLwww9b94eEhNCoUSMOHz5s92uoSNf77LtSeT63rrRjxw66d+9+VY1qtWrV7G5NtoV0Y1WwWbNm0bBhQzw8PIiMjKRRo0bW4emlHZeens68efP4448/rlklb8/xalETq62jsTp06GBTgXJpI7bKeu7MmTNkZ2fTqFGjq45t0qQJZrOZ5ORkmjVrZtP1i1/34sWLfPDBB3zwwQelHmMpSLTw8vJi3rx51hqS+fPnl/reNGjQoMTjevXqYTAYrF2G5XlNxX/hw+VuxwsXLhAUFFSu13O9a9orJyeHadOmMX/+fE6ePFmiiT49Pd2ua505c4acnJyr3kuARo0aWT88bX3dZ86cISMjo8zuofK8jsaNG9O+fXsWLlxo/cWzcOFCbrrppuuOQLztttsIDg5m0aJF9OzZE9ASpVatWtGwYcMyz3v99dcZNmwYsbGxtG3bljvuuIOhQ4eW+EVrj4r8mlkkJSUxevRoHnjgARITEx16P0f8LDn6/rZ8PhV3ZbzBwcH4+PhYu5aK7z937pxd165o1/vsu1J5PreuPD81NZWJEyde9dzJkydtHlxjD0l27FStWjUKCwvJzMwkMDDwqudtTRyKH9evXz+6dOnCP/7xD/bt21dqq5E9x1+4cAE/P78Sf41VhGtdryLuZcs1LJM4PvjggwwbNqzUY1q2bHnVvp9//hmA3NxcDhw4YNMHV0VMgFfW6AfLL4vyvJ7rXdNejz/+OPPnz2fChAl07NiR4OBgFEVh8ODBDps009bXbc9rsud1DB06lCeeeIITJ06Ql5fH+vXrmTlz5nXv4e3tTb9+/ViyZAnvvfceqamp/PXXX0ydOvWa5w0cOJCuXbuyZMkSfvnlF9544w1ee+01vvnmG26//Xag7O83k8l0Q6/VFhcuXOC+++6jYcOGfPjhhw6/X3lU9Pe9vez9jCstXltegz3fB45yvc++8n4OW+zYsQO4uvb15MmTXLhwgRYtWtgTrk0k2bFT48aNAW101bW+mPYwGo1MmzaNHj16MHPmTJ599tkbOv7IkSM0adKkQmIrr+rVq+Pn58e+ffuuem7v3r0YDAZiY2PLdd3AwEBMJpPNI+J27NjBSy+9xIgRI0hKSuKRRx5h586dBAcHlzjuyiTo4MGDmM1m68gIR7ym8rye67E3SVu8eDHDhg0rMSokNze3XJOSVa9eHV9fXw4cOHDVc8XfN1tft9lsJigoyDrK6VrseR2DBw8mMTGRzz//nJycHDw9Pa/ZDVXcoEGD+Oijj1i5ciV79uxBVVWbzo2OjmbMmDGMGTOGtLQ02rRpw3/+8x9rshMaGlpqrMeOHbuh13o9ZrOZIUOGcPHiRVasWFFqF4Kt97P1e89Rnw+20vv+12LP90FpyvNH2vU++650o59blmTnyt+hO3fuLHV/RZCaHTtZRmps3ry5Qq/bvXt3OnTowIwZM2wa8net47du3UqnTp0qND57GY1GevfuzbfffluiKTQ1NZXPPvuMLl26lKvLxWg0ct999/H111+X+gvwzJkzJR4XFBQwfPhwYmJiePvtt1mwYAGpqak8+eSTV507a9asEo/fffddAOsvI0e8Jntfjy0s83/Y+ovPaDRe9dfxu+++W66/JI1GI3369GHp0qUcP37cun/Pnj3W1jXLcba8boPBQL9+/fj+++9L/ZkrHrc9ryM8PJzbb7+dTz/9lIULF3Lbbbdd1b1Qll69ehEWFsaiRYtYtGgRHTp0uGZLoclkuqqrJyIigpiYmBJLu9SrV4/09HTrLwKA06dPlzpMviK/Zi+++CI///wzn3/+eZmvw9b72fq956jPB1vpff9rsef7oDT2/vzD9T/7rnSjn1s7d+6kZs2aV40m3rFjB4qilOg+rCjSsmOnunXr0rx5c1asWMHIkSMr9NpPP/00999/PwsWLLCpGK6047ds2cL58+e55557bL7vTz/9xN69e6/a36lTp3LXFAC88sor/Prrr3Tp0oUxY8bg4eHB+++/T15eHq+//nq5r/vqq6+yatUqEhISGDVqFE2bNuX8+fNs3bqVFStWcP78+RIxJCUlsXLlSgIDA2nZsiWTJ0/m3//+NwMGDOCOO+6wHnvkyBHuvvtubrvtNtatW8enn37KP/7xD+Lj4x36mux5PbZo27YtAM899xyDBw/G09OTvn37ljkJ2l133cUnn3xCcHAwTZs2Zd26daxYseK60yWU5cUXX2T58uV07dqVMWPGUFhYyLvvvkuzZs1KfIDb+rqnTp3KL7/8Qrdu3Xj00Udp0qQJp0+f5quvvmLNmjXWyeLsfR1Dhw5lwIABALz88ss2vz5PT0/69+/PF198QVZWFm+++eY1j8/MzKRmzZoMGDCA+Ph4AgICWLFiBZs2bSrRUjJ48GAmTpzIvffey/jx48nOzmb27Nk0bNjwqmLPivqa7dy5k5dffpmbb76ZtLQ0Pv300xLPWwq2bb1fWd97pXHU54Ot9L5/Wez5PiiNPV8DC1s++650I59bO3bsKLX1ZufOndStW9cxEzZW+PiuKmD69OlqQEBAiaF1lqF5pQ2PLe5ax5lMJrVevXpqvXr1rENb7T1+4sSJaq1atUoMyb1eLGVt8+fPV1X18vDEM2fOXHWNaz2nqqq6detWtU+fPmpAQIDq5+en9ujRQ127dq1d1yhNamqqOnbsWDU2Nlb19PRUo6Ki1J49e6offPCB9ZgtW7aoHh4e6uOPP17i3MLCQrV9+/ZqTEyMeuHCBev9d+/erQ4YMEANDAxUQ0ND1XHjxqk5OTkV+prKGvpry+ux55ovv/yyWqNGDdVgMFx36PGFCxfUESNGqOHh4WpAQIDap08fde/evWrt2rVLDIm1dei5qqrq77//rrZt21b18vJS69atq86ZM6fUobO2vG5VVdVjx46pQ4cOtU65ULduXXXs2LFqXl6e3a/DIi8vTw0NDVWDg4NL/Tpfy6+//qoCqqIopU7/UPy9ysvLU59++mk1Pj5eDQwMVP39/dX4+Hj1vffeu+q8X375RW3evLnq5eWlNmrUSP30009Lfd/K+zW78rFlWHZZW3ne29K+98r63nHEz9KVyhp6fqP3L0tZxw8bNkz19/e/6vhu3bqpzZo1K7HP1u+Dst4DW78Gtn723cjn1pVMJpPq6+urPvvss1c9Fx8fr/br16/Mc2+EJDvlcPHiRTUsLEz98MMP9Q6lhNzcXDUqKqrEHDLi+sqTbInKr6CgQK1evfpV87cIUVW40mdfQUGB6uXlpU6ePNkh15eanXIIDg7mmWee4Y033nDaSARbzJ8/H09PT7vngxCiKlq6dClnzpxh6NCheociRJW3b98+8vPzHTISC6RAudwmTpxordp3FaNHj+b48eNVdlVbIWyxYcMG5s6dS2JiIq1bt75q6QchhPNZRmJJsiOEEBVg9uzZPPbYY0RERFxz7R8hhPPs3LkTHx+f607sWV6KqjppRiYhhBBCCB1Iy44QQggh3JokO0IIIYRwazKpINp06adOnSIwMLBC1kMSQgghhOOpqkpmZiYxMTHXHDAkyQ5w6tQp3dZBEUIIIcSNSU5OpmbNmmU+L8kOWFcvT05O1m09FCGEEELYJyMjg9jYWOvv8bJIssPlVWKDgoIk2RFCCCEqmeuVoEiBshBCCCHcmiQ7QgghhHBrkuwIIYQQwq1JzY4QQghxBZPJREFBgd5hVHmenp4YjcYbvo4kO0IIIUQRVVVJSUnh4sWLeociioSEhBAVFXVD8+BJsiOEEEIUsSQ6ERER+Pn5yUSzOlJVlezsbNLS0gCIjo4u97Uk2RFCCCHQuq4siU61atX0DkcAvr6+AKSlpREREVHuLi0pUBZCCCHAWqPj5+encySiOMvX40ZqqCTZEUIIIYqRrivXUhFfD5dMdmbNmkVcXBw+Pj4kJCSwcePGax5/8eJFxo4dS3R0NN7e3jRs2JAff/zRSdEKIYQQwpW5XM3OokWLSExMZM6cOSQkJDBjxgz69OnDvn37iIiIuOr4/Px8br31ViIiIli8eDE1atTg2LFjhISEOD94IYQQQrgcl0t2pk+fzqhRoxgxYgQAc+bM4YcffmDevHk8++yzVx0/b948zp8/z9q1a/H09AQgLi7OmSELIYQQwoW5VDdWfn4+W7ZsoVevXtZ9BoOBXr16sW7dulLP+e677+jYsSNjx44lMjKS5s2bM3XqVEwmU5n3ycvLIyMjo8TmCCeOHiPp+7c5nnwIVVUdcg8hhBDCEewtKbHlnD/++IO+ffsSExODoigsXbrUQdGX5FItO2fPnsVkMhEZGVlif2RkJHv37i31nMOHD/Pbb78xZMgQfvzxRw4ePMiYMWMoKChgypQppZ4zbdo0XnzxxQqP/0p/PnMvrXbksKrtJ/w37t/4+AUQ4udJiJ8XoX6ehPp5Wf99eb/lsRchfp54Gl0qHxVCCFEF2FtSYus5WVlZxMfHM3LkSPr37++016OoLtTkcOrUKWrUqMHatWvp2LGjdf8zzzzD77//zoYNG646p2HDhuTm5nLkyBHr+Pvp06fzxhtvcPr06VLvk5eXR15envVxRkYGsbGxpKenExQUVDEvRlVZ/MBNNEvKYHf7AlrU8WJcwXj2q7F2XSbA24MQa2LkaU2GgkskTJb9XgT7eRLk4yGjCYQQwk6W3yV16tTBx8dH73Ds1rx5cwYPHsyJEydYtGgR3t7ePPvss0yYMMHuayUkJNC+fXtmzpwJgNlsJjY2lscff7zUkpLynKMoCkuWLKFfv37XjOVaX5eMjAyCg4Ov+/vbpVp2wsPDMRqNpKamltifmppKVFRUqedER0dftXZGkyZNSElJIT8/Hy8vr6vO8fb2xtvbu2KDv5KiEF2zGSStI9PgSUPDSZb7TeZwu+fZG9OfCzmFXMzK50J2ARdz8rmYXcCF7Mv/T88pQFXhUl4hl/IKOXEhx+ZbGw0KIb6exZIkS0JUeuuRJWHy8bzx9UeEEMJdqKpKTkHZJRGO5OtptOuP1ry8PPbt28fHH3/Miy++yFNPPcXs2bOZOHEio0aN4u2332bq1KnXvMbu3bupVauWtaRk0qRJ1ueuV1JSnnOcyaWSHS8vL9q2bcvKlSutmZ7ZbGblypWMGzeu1HM6d+7MZ599htlsxmDQunz2799PdHR0qYmOMwX4alnmJe8gqNcEw6GV1N/wb+o33Qx93wbfkDLPNZlVMnMLuGBNgvK5kHU5EbqQXZQoFe2/WPQ4p8CEyaxyLiufc1n5QJbN8fp6GktNgiz/DymWJFlalYJ8PTEapBVJCOF+cgpMNJ38sy733v1SH/y8bP8VvWvXLgoLC3nnnXe47bbbABg+fDjTp08nOzub0aNHM3DgwGteIyYmBihfSUl5znEml0p2ABITExk2bBjt2rWjQ4cOzJgxg6ysLOvorKFDh1KjRg2mTZsGwGOPPcbMmTN54oknePzxxzlw4ABTp05l/Pjxer4MAAJ9Q8gDsvOyKHjgczw3vA8rX4TdS+HUVhgwH2q2K/Vco0EpSjq8qIO/zffMLTBdToaKJUHW1qOsYkmSNXEqwGTW/oLJSTdxKj3X5vspCgT5eF6VBJXWmhTi50movxchvp74edn3V4sQQoiybd++naioKPr06WPdd+bMGby8vAgLC8NoNBIWFqZjhPpyuWRn0KBBnDlzhsmTJ5OSkkKrVq1Yvny5NVs8fvy4tQUHIDY2lp9//pknn3ySli1bUqNGDZ544gkmTpyo10uw8vcJIg8wmM2kZKcR23k81O4Mi0fAxWMwrw/c8jx0Gg+GiilE9vE04uNpJDLI9v5mVVXJzCvkYpalxagoCSqRGJVsVbqYVUBmXiGqCuk5BaTnFMC5bJvv6WU0XLP16MrkSAq2hRDO5utpZPdLfa5/oIPubY+kpCTatWtX4o/IpKQkmjdvjtFoZOrUqTZ3Y5WnpKQ85ziTyyU7AOPGjSuz22r16tVX7evYsSPr1693cFT2M3hob6/BDMczjxMbFAs128LoP+H7J+DvJbBiChz5He59HwJKr3B3NEVRCPLxJMjHk1rVbF8TpsBk5mJRMnSxKDmy1BwVbz3Sjrlck5RvMpNvMpOWmUdaZt71b1RMoLcHIf6ehPiWLNgOKaUOKdTPixB/TwK9pWBbCGE/RVHs6krS0/bt27n55ptL7EtKSqJVq1YAdnVjlaekpDznOFPl+CpWVgYtMzcWJTud6azt9wnWurDq9oCfJsKh32B2Z+j/AdTroWPA9vE0Gqge6E31QNuLvVVVJTvfVEoSVKz16KqEqYCMXK1gOzOvkMy8QpK5sYLt0KJWo2DfKxImf+1xsK8UbAshKo/t27dfVb6xbds2Hn30UQDCwsLs6sa6XkkJwMyZM1myZAkrV660+ZxLly5x8OBB6+MjR46QlJREWFgYtWrVKtdrt4UkOw6keFxOdpIzk694UoG2wyC2A3w1As7sgU/uhS5PQo9/gdFTh4gdT1EU/L098Pf2oGao7eeZzCoZVxZmW1qVrhjJVnx/RRVsh/oXtRr5luxyC/H1JNTfk+CilqYQX088pKtNCOFER48eJT093dqKA9rorL1799K6detyXfN6JSWgFSUfOnTIrnM2b95Mjx6X/6hPTEwEYNiwYSxYsKBcsdrCpebZ0Yut4/TtdXbuXM78dzqrWirs+b+evNvz3dIPzM+Gn/8FW+Zrj2t2gPs+hNDaFRZLVZVbYCqWBJXemnRlq9LFHK1gu7wCvT0ILlZ3FOxb+r8tXW4hvtp+SZKE0Fdln2enuC1bttC+fXvS09MJDAzUO5wb4nbz7LgbxXi5Zueqlp3ivPyg7wyo2w2+Gw8nNsKcLnDndGh5v3OCdVM+nkaigo1EBdv+wWU2FxVsX6Nr7WJRUpRebF9GbiFwuavNnrmRAAJ9Lk8gGexbrA7J9/IkklrCdLnbLcjHQ5IkIcRVtm3bRt26dSt9olNRJNlxoCu7scyqGYNyjV9Mze6FmNbw9Sgt4fnmETj4K9zxJvhUXIuTuDaDQSG4qLWldjXbzys0mcnIvZwkpVsni9SSootFw/wvFh/Vll1ApiVJyi0kM7eQ5PP2JUlBPh6XW4n8vKz1ScX/bZld29INJ/MjCeHeihcnC0l2HKtoVmcPs0K+OZ+07DSi/K8zBC80Dkb8BH++Cb+/BjsWwfH10H8u1EpwfMyi3DyMBsL8vQjzt28yy0KTmfQcraXo4hUtR6X/+/LQf4CM3EIycgs5ft6+eIN8PKxD+4OLtSJdTpyKJ0za84E+kiQJURlYlmwQGkl2HEgpSnb8DT5APsmZyddPdgCMHtD9WW201jePaHPyzL8duj0DXZ/Snhduw8NooFqAN9UC7FvCpMBkLiraLtmKVCIpKqpRKv7vS1ckScfsuGfxSSSDrQXbWjIUXPzflpqlopalIB9PDJIkCSF0Ir81Hcma7PhiSXbaR7W3/fxaCTB6DfzwFOz8ElZPg0OrtCHqUrxc5XneQJKUXrylqNiEkdbi7ZwCa53SxWxt0shLNzCJpKKg1SH5lizMLv7v4lMBaPu8CPTxkCRJCHHDJNlxIEuBsp9B+2V0POO4/RfxCYb75kKDW+GHf0Ly+qLi5f9Cy2tPECVEaTyNBsIDvAm3M0nKLzQXJTqWouzrtyJdzM4nK9+EqmLdZ0+SZLAkSaUmSFd3t1lqkwK9JUkSQlwmyY4DWQqUfZWiZCezHMmORcuB2pw83zwKyRvgm1Fw4Fe4800tIRLCwbw87J9EErQk6WKOZUTb5Rm3S61HKvZ8dr4Js0rRiLgCu+5pULAmQMW71MqaEiDEV2bbFsKdSbLjSEXdWD6KVrB6IvPEjV0vNA6G/3i5eHnnl1pLT/8PpXhZuCwvDwMRgT5EBNo3b0leock675G1q62o5cjSspSeU7TgbbFpAHIKtCTpfFY+57Py7bqnsdhIvGDLqDbfyzVJIdbh/yUnkpR5koRwbZLsOJClG8tH0WZDPp55HFVVb+wvxxLFy6OKipdvg5ufgZufluJl4Ta8PYxEBBmJsGNRW9AmkszIsa0VqXitkmW27fIkSXB5MsnLSdLl4f7FHxd/PsRPliURwhnkN6MjFf2l56UaUVDIKsjiQt4FwnxsX5+kTJbi5R+fhh1fwO+vwsEVWvFytXo3fn0hKikfTyM+nuVPkkpMAVBUqG2pQ7IUZxevTcq8wckkvT0Ml5Ohoq624nMllUieiv5tqUuSLjchbCPJjgNZWnYUVSXSP5KUrBSOZxyvmGQHtIkG+7+vFS8vS4STm7Xi5d6vQLuR2hAYIYRNypskWSaTtI5wsyRI1lal4klS8QRKW5Ykr9BMakYeqRl5dt3X0uVmqUUqPtqteJdbiRYl6XITVZQkOw5kKVCm0ERsYCwpWSkkZybTKqJVxd6oxQCodRMsfQyO/AE/JMK+n+CemRBow7w+QohyKzmZpL/N56mqyqW8wjJbjIpPD3Dl87kF5grpciuzRalEF9zl5Em63ERlJcmOIxUVKKsmE7UCa7EpZdO118i6EcE14aFvYcMcWPGCtszEex3hrregWT/H3FMIUW6KohDoo81KHWvnubkFJmvyc3WLUfG124qed0SXW7Hi7NK63KyF3NLlJlyAJDsOZOnGwlRIbKD2cXZDw8+vx2CAjmOg3i1a8XLKDvhqGOwbDHe8LkPUhXATli63yHJ2uVmTozK63K56voK73Iq3GJXW5WZ5Xha61desWbN44403SElJIT4+nnfffZcOHTqUefwff/zBG2+8wZYtWzh9+jRLliyhX79+zgv4GiTZcSCl6IdULTRRK6gWUM6JBe0V0RgeWakNT18zXStgProG+r2nrawuhKiSyrt+25VdbhevaDEqMSP3FS1KFd7ldmWL0hUJkqVFSbrcbsyiRYtITExkzpw5JCQkMGPGDPr06cO+ffuIiIgo9ZysrCzi4+MZOXIk/fv3d3LE1ybJjiMVteyoJhNxQXEAHM04euPDz23h4QU9n4cGvWHJ/8GFI/Dx3XDTWOg5GTzt+4tQCFF1VVSX29UtRiUTpOLJU0V3uRUv0L7cxeZVYr+fUZvtu7Jq3rw5gwcP5sSJEyxatAhvb2+effZZJkyYYPe1pk+fzqhRoxgxYgQAc+bM4YcffmDevHk8++yzpZ5z++23c/vtt9/IS3AYSXYcyFqgbNIKlBUUMvMzK274uS0sQ9R/+TdsmQ/rZ8GhldoQ9eh458QghKiyKqzLrSgZKj7RZGkj3NJvoMutRqCRF3pEYErLxNMrHyPgYc7FaFCKNq1LzqgUbdb9BowGBYNCxf0h6+ln14javLw89u3bx8cff8yLL77IU089xezZs5k4cSKjRo3i7bffZurUqde8xu7du6lVqxb5+fls2bKFSZMmWZ8zGAz06tWLdevWlfsl6UmSHUcqVqDs4+FDtH80p7JOcSzjmPOSHQDvAOg7AxrdDt+OgzN7Ye4t0H0SdJ4gExEKIVxORXa5WSaPTM8p0OZSKtbNlp5TSHrR8xZms0p+oRmlIJsWHzWp6Jdmm3+dAi/bR/ft2rWLwsJC3nnnHW677TYAhg8fzvTp08nOzmb06NEMHHjt9RRjYmIAOHv2LCaTicjIyBLPR0ZGsnfvXjtfiGuQ33IOpHhYurG05tjaQbU5lXWKo+lHaR3R2vkBNewDY9bDsidgz/fw28uwfzn0mw3hDZwfjxBCVLAb6XLLuJTN8WNHia3mj4eXN6Zch4Rok2PnsjF4X2498jAUb0kq2bKkKArbt28nKiqKPn36WK9x5swZvLy8CAsLw2g0EhbmxD+yXYwkOw6kGC/PswNasrPu9DqOZhzVLyj/ajDwE9j+Bfz0DJzYpE1E2HMyJDymjegSQogqyMtD647y9jTi4+0BXsFaC8t1qKqKqkKhWcWkqpjMxTZVxWx9DIVmM2ZV1Y41a8+VViakFnqAybaCbqNBYdXajTRp0YojZ7OsSdAf6zbRuGkz0nMLmfHmVKa/8do1r2PpxgoPD8doNJKamlri+dTUVKKiKufcbZLsOJLhcjcWQFxwHADHMo7pFZFGUaDVAxDXBb57HA6vgp//BXuWaRMRynITQgihfVba0JWkFG32dbhpVPVyQlRoviJRsiRPpstJVKH58rHmompqk1llz66dtEnoxKW8Quu1t2zbRt1GzThxIYdb+z9Ih1vuvCJuBYOlDsmgkOcVzPHz2RgNCi1btWbZT79w86134GFQUFBZsXIlY8aMxWxWMRgq17xJkuw4UPECZcA6Ikv3ZMciJBYeWgJbFmgFzMfXaq08vV6E9o9IK48QQjiYoih4KAoY7E+WzMVakQ7u/ZsnnhhPbJjf5X27d/HA0BEE+XjiH1mdiOrh1qRJLWXYWU6hSk6h1po0eORjPJ84hrjGLWjeqg2f/m82mZcu0en2+9h1Kh2DovDFgrmsXL6MT79ehtGgkJudxfFjhzEWFVbv3neA6hs2EV6tGnG1a+Nh1FrO9CDJjgMpxpItO7WDagPaXDsmswmjwQXmgVAUaDdCm4jw27Fw9E/46WnY8x3cMwtCa+sdoRBCiFIYFAWDUeFk8lHS09Pp1KEdoX5aypSXl8fBA/u4pUsCceElW6cs3W4ms0rhld1uRduQBx4gN/Mis6dP40xaKk2ateD9T78mvHoEKlqide7cWY4fPUxWvtaatGnDRh4Z2Nd6n+eefQaAuwc8wMtvvUdMiC/hAd7OeXOuoKilpXdVTEZGBsHBwaSnpxMUFFRh1y1ITeVgt+7g6UmTnTswmU20X9ieAnMBy+9bTo2AGhV2rwphNsPm/8Gvk6EgG7wCoPfL0HaELCoqhHB7ubm5HDlyhDp16uDjU7nnItuyZQvt27cnPT2dwMDACrtu8W4305Vdb2UkTpYtJtTXmozZ41pfF1t/f0vLjgNdLlDWsl6jwUitwFocSj/E0fSjrpfsGAzQYRTU7wlLx2rdWsuehN3fwd3vat1eQgghXN62bduoW7duhSY6ULLbzV56tq1IUYYjWZIdVUU1m4HLXVm6jsi6nrC6MPwH6DMNPHy0AubZnWDrJ1Tq6UWFEKKKSEpKolWrVnqHUYKei8FKsuNA1pYdsLbuuMyIrOuxLCo6+i+o2QHyMuC7cbDwfsi4/lBMIYQQ+pk5cyaLFy/WOwyXIcmOAxVPdiwtOy43Iut6wuvDyOVw68tg9IaDv8Ksm6SVRwghRKUhyY4jeVwuiVILS47IqjTJDmjzBXUeD6P/hBptIS9da+X55F64UIlehxBCiCpJkh0HKtGNVWzJCIBTl06RW6jjXOTlUb0RjPwFbn3pci3Pex1hwwfaSC4hhBDCBUmy40jFu7GK5toJ8wkj0DMQFZXkzGS9Iis/owd0fkKr5anVCQqytHl5FtwBZw/qHZ0QQghxFUl2HEhRFOssxGpRgbKiKJWnSPlawutrI7bueFObj+f4Om3E1poZ1lYsIYQQwhVIsuNg1q6sopYdqCTDz21hmZdnzDptBmZTHqyYAh/2hJRdekcnhBBCAJLsOF5RkbJqulzTUimLlK8lpBY8+A3c8x74BMPpJPigG6yaCoW2rdorhBBCOIokOw52uWXncteOZfj50fSjzg/IURQFWg+BsRuh8V1gLoTfX4P3b4YTW/SOTgghRBUmyY6DXbkYKLhRN1ZpAqNg0Kdw/wLwC4cze+B/vbRV1fOz9Y5OCCFEFSTJjqNZkp3CYi07wXEoKFzMu8j53PN6ReY4igLN7tVaeVoMBNUMa9/VCpgPrdI7OiGEEFWMJDsOVlqBsq+HLzEBMQAcvnhYj7Ccw78a3DcX/vElBMbAhSPwST9Y8hhkndM7OiGEEGX4448/6Nu3LzExMSiKwtKlS/UO6YZIsuNopRQoA9QJrgPA4XQ3TnYsGvaBsRugw6OAAts/g1ntYfsiWXJCCCFcUFZWFvHx8cyaNUvvUCqEJDsOVlqBMkDd4LoAHEk/4uyQ9OETBHe8AQ//ChFNIfscLHkUPu0P56vIeyCEEA7UvHlzXnnlFUaPHk1oaChRUVHMmDGjXNe6/fbbeeWVV7j33nsrNkidSLLjYKUVKMPlZKdKtOwUF9se/u8P6DlZW1j00G/akhN/vS2TEQohXIqqqmQXZOuyqXa2eufl5bFv3z4+/vhjunXrxqZNmxgyZAgTJ04kKyuLqVOnEhAQcM3t+PHjDnon9edx/UPEDbF0YxVe0bITUkWTHQCjJ3T9JzTtB8smwJE/4NfJsPMr6PsO1Gijd4RCCEFOYQ4JnyXocu8N/9iAn6efzcfv2rWLwsJC3nnnHW677TYAhg8fzvTp08nOzmb06NEMHDjwmteIiYm5oZhdmUu27MyaNYu4uDh8fHxISEhg48aNZR67YMECFEUpsfn4+Dgx2mtTipaLoIyWnZSsFLILquiQ7Gr1YOh30G82+IZCyk5t9uXlkyDvkt7RCSFEpbF9+3aioqLo06ePdd+ZM2fw8vIiLCyMsLAw6tevf83Nw8N92z9c7pUtWrSIxMRE5syZQ0JCAjNmzKBPnz7s27ePiIiIUs8JCgpi37591seKojgr3OuztuyUTHaCvYMJ8wnjfO55jqQfoVl4Mz2i05+iQKt/QP1b4ed/wc4vYf17sOd7uHM6NOytd4RCiCrK18OXDf/YoNu97ZGUlES7du1K/P5LSkqiefPmGI1Gpk6dytSpU695jd27d1OrVq1yxevqXC7ZmT59OqNGjWLEiBEAzJkzhx9++IF58+bx7LPPlnqOoihERUU5M0ybWQuUzaarnqsbXJfzuec5nH646iY7FgHVtWHq8YNg2ZNw8Th8dj806w+3vQqBkXpHKISoYhRFsasrSU/bt2/n5ptvLrEvKSmJVq1aAUg3lt4BFJefn8+WLVvo1auXdZ/BYKBXr16sW7euzPMuXbpE7dq1iY2N5Z577uHvv/++5n3y8vLIyMgosTlKWQXKUIWLlK+lfi8Ysx46jQfFCH9/AzPbwca5pSaMQgghtGTHkthYbNu2zbrP3m6sS5cukZSURFJSEgBHjhwhKSmp0hYxu1Syc/bsWUwmE5GRJf+Kj4yMJCUlpdRzGjVqxLx58/j222/59NNPMZvNdOrUiRMnTpR5n2nTphEcHGzdYmNjK/R1lFBGgTIUK1J254kFy8PLH3q/DI+ugpg2kJcBPz6l1fOc3Kp3dEII4VKOHj1Kenp6iWQnLy+PvXv30rp163Jdc/PmzbRu3dp6fmJiIq1bt2by5MkVEbLTuVSyUx4dO3Zk6NChtGrVim7duvHNN99QvXp13n///TLPmTRpEunp6dYtOTnZYfGVNoOyRZWaWLA8ouPhkRVwx5vgHQyntsHcW+DHpyE3Xe/ohBDCJcTFxaGqKvXq1bPu27VrFyaTifj4+HJds3v37qiqetW2YMGCCorauVwq2QkPD8doNJKamlpif2pqqs01OZ6enrRu3ZqDBw+WeYy3tzdBQUElNocxam/xlQXKcLkbKzkzmQJTgeNiqMwMRugwCsZt0tbZQoWNH8DM9rBzsczALIQQpdi2bRt169YlMDBQ71BcgkslO15eXrRt25aVK1da95nNZlauXEnHjh1tuobJZGLnzp1ER0c7Kky7KMaiPtBS6k0i/SLx9/THpJo4nlk5+0GdJjBSK2Ae+i1Uqw+XUuHrh7W1ts6WndgKIURVVLw4WbhYsgNav+DcuXP56KOP2LNnD4899hhZWVnW0VlDhw5l0qRJ1uNfeuklfvnlFw4fPszWrVt58MEHOXbsGI888oheL6EEa4FyKS07iqJQJ0i6suxStzs8thZ6/FubgfnwapjdEVZNhYJcvaMTQgiXMHPmTBYvXqx3GC7D5YaeDxo0iDNnzjB58mRSUlJo1aoVy5cvtxYtHz9+HIPhco524cIFRo0aRUpKCqGhobRt25a1a9fStGlTvV5CSdaFQEtfCqFuSF12ndulFSnXdmZglZiHN3R7Glrcp9XvHFwBv7+mzcB8x5tQv6feEQohhHAhLpfsAIwbN45x48aV+tzq1atLPH7rrbd46623nBBV+VyrQBmkSPmGhNWFIYth97ew/Fk4f1hbWLTZvdBnGgS5RlemEEIIfblcN5bbuUaBMlTB1c8rmqJAs34wdiPcNAYUA/y9RCtgXjsTpPBbCCGqPEl2HMxSoFxmN1axZMesmp0Wl9vxCYLbpsGjv0ONdpCfCb88B3O6aguNCiGEqLIk2XGwy91YpScyNQNr4mnwJNeUy6lLp5wYmZuKbgkP/wp3vwt+1eDMHvioL3w1AtJP6h2dEEIIHUiy42geZS8XAeBh8LDW7Ry6eMhpYbk1gwHaDIVxm6H9qKKurW+0rq01b0Fhvt4RCiGEcCJJdhzMOs9OGd1YAPVD6gNw4OIBZ4RUdfiFwZ1val1bsQlQkAUrXtCGqh9ced3ThRBCuAdJdhxM8Sh7nh2LBqENADh4USbHc4joljDyZ+g3B/wj4NxBbdTWoge11dWFEEK4NUl2HM1g6ca6fsvOwQuS7DiMokCrB+DxzUWjtoyw53uY2QF+f0MmJBRCCDcmyY6DXW+eHbic7BxOP0yBWYZKO5RPsDZqa/SfULsLFObAqlfgvZtg/896RyeEEMIBJNlxMMWzaOh5QdktOzEBMfh6+FJgLiA5w3ErsItiIpvB8GVw3/8gMBouHIHPBsJng+CcFIoLIaq2P/74g759+xITE4OiKCxdurTU42bNmkVcXBw+Pj4kJCSwceNG5wZqI0l2HM2yXERh2cmOQTFIkbIeFAVaDNBWVO80HgwesH85zEqAXydDbobeEQohhC6ysrKIj49n1qxZZR6zaNEiEhMTmTJlClu3biU+Pp4+ffqQlpbmxEhtI8mOgykengCohdfunpIiZR15B0Lvl+GxdVCvJ5gL4K+34d22sPUTMMtkj0II19e8eXNeeeUVRo8eTWhoKFFRUcyYMaNc17r99tt55ZVXuPfee8s8Zvr06YwaNYoRI0bQtGlT5syZg5+fH/PmzSvnK3AcSXYczDIa61o1OyBFyi6hekN48Gv4x5cQVg+y0uC7cTC3Bxxfr3d0QggnU1UVc3a2LpuqqnbFmpeXx759+/j444/p1q0bmzZtYsiQIUycOJGsrCymTp1KQEDANbfjx20fnZqfn8+WLVvo1auXdZ/BYKBXr16sW7fOrtidwSUXAnUnisf1a3agWLIjLTv6UhRo2Afq9oCN78Pvr8PpJJjXB5oPgFtfhOCaekcphHACNSeHfW3a6nLvRlu3oPj52Xz8rl27KCws5J133uG2224DYPjw4UyfPp3s7GxGjx7NwIEDr3mNmJgYm+939uxZTCYTkZGRJfZHRkayd+9em6/jLJLsOJoNNTtwuRvreOZxcgtz8fHwcXho4ho8vKDT49ByMPz2Mmz9GHYthr0/QJcntee8bP8gEkIIR9q+fTtRUVH06dPHuu/MmTN4eXkRFhaG0WgkLCxMxwj1JcmOg12u2bl2slPNpxoh3iFczLvIkfQjNKnWxBnhiesJqA53vwPtH4afnoXja2H1VC356f0SNOuvtQYJIdyO4utLo61bdLu3PZKSkmjXrh1Ksc+jpKQkmjdvjtFoZOrUqUydOvWa19i9eze1atWy6X7h4eEYjUZSU1NL7E9NTSUqKsqu2J1Bkh0Hs3ZjXadAWVEU6ofUZ3PqZg5ePCjJjquJjocRP8LfS7SRWunJsHgkbJwLt70KMa30jlAIUcEURbGrK0lP27dv5+abby6xLykpiVatWgFUeDeWl5cXbdu2ZeXKlfTr1w8As9nMypUrGTdunF2xO4MkOw5mmWeH69TsANZkR4afuyhFgeb9odHtsPZd+HM6HF8HH3SHNg/BLc9DQITeUQohqqDt27czfvz4Evu2bdvGo48+CkBYWJhd3ViXLl3i4MHLNaRHjhwhKSmJsLAwa+tPYmIiw4YNo127dnTo0IEZM2aQlZXFiBEjKuAVVSxJdhzNeO1Vz4uzDj+XEVmuzdMXuj0Drf6hLSy686uimp5voMsE6DhOO0YIIZzg6NGjpKenW1txQBudtXfvXlq3bl2ua27evJkePXpYHycmJgIwbNgwFixYAMCgQYM4c+YMkydPJiUlhVatWrF8+fKripZdgSQ7DmZrzQ7IiKxKJ7gm3PchtB8FP0+Ck1vgt1dg83zoOQVa3A8Gmd1BCOFYcXFxVw1V37VrFyaTifj4+HJds3v37jYNfx83bpxLdltdST6JHczWmh2AeiH1ADiddZpL+ZccGpeoQLUS4OEV2tITwbGQcRKWPAof3gJH/9I7OiFEFbRt2zbq1q1LYGCg3qG4BEl2HMyemp1g72Ai/LSaD2ndqWQMhstLT/ScAl6BcGobLLgDvhgi620JIZyqeHGykGTH4RQb59mxaBCi1e3sv7DfYTEJB/L0ha6JMH4btBsJigH2LoNZHbSh69nn9Y5QCFEFzJw5k8WLF+sdhsuQZMfR7Ex2GoY1BCTZqfQCqsNdb2nrbTXoDeZC2DAb3mkF62ZBYb7eEQohRJUhyY6DKcaiZMdkW7LTOLQxAHvPu95026IcIhrDkK/goSUQ0Qxy0+Hnf2ktPbu/BTvXvxFCCGE/SXYczJ6aHYBGYY0ArWXHrMpq226j3i0w+k+4+10IiIQLR+DLoTD/djihzwytQghRVUiy42D21uzUDqqNl8GLnMIcTmSecGRowtkMRmgzFB7fCjc/Ax6+2qSEH96iJT5SxCyES7B3xXHhWBXx9ZBkx9HsTHY8DB7UD9Xm25GuLDflHQC3PAePb4FWQwBF69Ka1QGWJcKlNL0jFKJK8vTU5kXLzs7WORJRnOXrYfn6lIdMKuhg9kwqaNE4rDG7z+1m34V99I7r7ajQhN6Ca0C/96DjWG0m5gO/wOb/wfYvtFXVO40Db5kjQwhnMRqNhISEkJam/cHh5+dXYmFN4VyqqpKdnU1aWhohISEYi1YkKA9JdhzMUrNjT7LTMLRoRNZ5GZFVJUQ204qYj/ypLTJ6aiv8/qqW+HSbCG2Hg7H8f9EIIWxnWbHbkvAI/YWEhNzwSuqS7DiYYslE7Uh2GoVqRcp7L0g3VpVSpyuM+g12L4WVL8H5w/DjU7D+Peg5GZr20xYjFUI4jKIoREdHExERQUHB9We+F47l6el5Qy06FpLsOJi9BcpweURWSlYK6XnpBHsHOyQ24YIUBZrdC43vgi0L4PfXtKTnq+FQoy30elFLioQQDmU0Givkl6xwDVKg7GjlqNkJ9AqkRkANQCYXrLKMntBhlDYTc7dnwdNfW2j0o7tg4f2Q+rfeEQohRKUhyY6DWefZMZnsGj5nqduREVlVnHcg9JikJT3tHwGDh1bIPLszLHkMLh7XO0IhhHB5kuw4mKUbCwA7+n8bh2kzKe87v6+iQxKVUWAk3PlfGLsRmt4DqLD9M3inDfz4jAxXF0KIa5Bkx8GKJzt21e2EXp5JWQiravVg4MfwyEqoczOYC2Dj+/B2vFbUnHNR7wiFEMLlSLLjaMWTHZPJ5tMsC4IevHiQArOMCBBXqNkOhn0PQ7/VCpcLsuHP/8LbLeHP6ZCfpXeEQgjhMiTZcbDytuzUCKiBv6c/BeYCjqQfcURowh3U7a618gxaCNWbaAuNrnwR3mkNG+fK6upCCIEkOw6nGAxg0N5m1Y6aHYNisHZlSd2OuCZFgSZ3wWN/wb3vQ0htuJSqzdEzsy0kfQ5m21sVhRDC3Uiy4wTW1h07Wnbg8ogsSXaETQxGiB8M4zZrxcwBUdporaWjYXYn2PM9yAKHQogqSJIdJyjPxIIATao1AWDP+T0VHpNwYx5e2jD18du0SQh9QuDMXlj0IMztAYd+k6RHCFGlSLLjDJ72TywI0LRaUwD2nNtTIUvciyrGyw+6TIAntsPNT2sTE57aBp/cCx/1hWNr9Y5QCCGcQpIdJ7Csj2VvslMvpB5eBi8yCzJJzkx2RGiiKvANgVv+rSU9N40Boxcc/RPm3w4f3wPJG/WOUAghHEqSHScob82Op8HTWrez+/zuig5LVDUB1eG2aVr3VruRYPCEw6vhf7fCp/fBiS16RyiEEA4hyY4TlLdmBy7X7ew+J8mOqCDBNeGut+DxLdBmKChGOLgCPrwFPhsEp5L0jlAIISqUJDvO4Fn+ZMdStyPJjqhwobXh7nfh8c3QaggoBti/HD7oBl8MgZSdekcohBAVwiWTnVmzZhEXF4ePjw8JCQls3GhbTcEXX3yBoij069fPsQHaSbGsfF5Q/mRHipSFw4TVhX7vwdhN0HIQoMDeZTCnC3w5FNJkNKAQonJzuWRn0aJFJCYmMmXKFLZu3Up8fDx9+vQhLe3aCx0ePXqUp556iq5duzopUttd7sayf9mHBiEN8DR4kpGfwYlLJyo6NCEuC68P/T+AsRug+X2AAru/hfc6wuKRcEbWaRNCVE4ul+xMnz6dUaNGMWLECJo2bcqcOXPw8/Nj3rx5ZZ5jMpkYMmQIL774InXr1nVitLaxjMbCjrWxLDyNnjQIbQBIV5ZwkuqNYMA8eGzt5RXWd30N7yXAN4/C2YN6RyiEEHZxqWQnPz+fLVu20KtXL+s+g8FAr169WLduXZnnvfTSS0RERPDwww87I0z73UDNDpTsyhLCaSKbaiusj14Dje8C1Qw7FsGs9vD1KDgjM3sLISoHj+sf4jxnz57FZDIRGRlZYn9kZCR79+4t9Zw1a9bwv//9j6SkJJvvk5eXR15envVxRkZGueK11Y3U7IAUKQudRbWAwQu1CQlXv6oVMe/8EnZ+Bc36aRMWRjbTO0ohhCiTS7Xs2CszM5OHHnqIuXPnEh4ebvN506ZNIzg42LrFxsY6MMobq9mBYsnO+d1SpCz0E9Ma/rEIHv1da+lBhb+XaOtuLXoQTu/QO0IhhCiVSyU74eHhGI1GUlNTS+xPTU0lKirqquMPHTrE0aNH6du3Lx4eHnh4ePDxxx/z3Xff4eHhwaFDh0q9z6RJk0hPT7duycmOnZ24vJMKWjQIaYCHwYP0vHROZZ2qwMiEKIeYVlpLz+i/oGk/QNEWGX2/K3z+AJzcqnOAQghRkkslO15eXrRt25aVK1da95nNZlauXEnHjh2vOr5x48bs3LmTpKQk63b33XfTo0cPkpKSymyx8fb2JigoqMTmSDcyqSCAl9GLBiFSpCxcTFRzGPgRjFkPLe7X5unZ96O22OinA2QZCiGEy3CpZAcgMTGRuXPn8tFHH7Fnzx4ee+wxsrKyGDFiBABDhw5l0qRJAPj4+NC8efMSW0hICIGBgTRv3hwvLy89X8pl1mTH/tFYFlK3I1xWRGO470MYuxHiHyiakflXbRmKj/vJgqNCCN25VIEywKBBgzhz5gyTJ08mJSWFVq1asXz5cmvR8vHjxzEYXC5Hu6YbrdkBLdn5+sDXkuwI1xXeAO6dA92egT+nw/bP4fAqbYvrqu2P6wqKonekQogqRlGl4pWMjAyCg4NJT093SJfWyX8+RcYPPxA56VnChg0r1zX+Pvs3g38YTLB3MH8O+hNFfmEIV3fhGPw1A7Z+AuaiRD82Abr+Exr0lqRHCHHDbP39XbmaSCqpG63ZAWgY2hAvgxfpeekkZzq2oFqIChFaW1tw9Ikk6PAoGL0heQN8NhDmdIWdi8Fc/q5dIYSwlSQ7zmCZVLCc8+yANpNy42qNAdhxVob4ikokuCbc8QZM2AGdxoNXAKTuhK8fhpntYMtHUJh3/esIIUQ5SbLjBBXRsgPQMrwlADvPyGrUohIKjILeL8OTu6DHc+AbCucPw/fj4e14WDcL8i7pHaUQwg1JsuMEirEo2THdWLLTPLw5ALvO7rrhmITQjW+oVqw8YRf0mQqBMZB5Gn7+F8xoDqtfg+zzekcphHAjkuw4wY1OKmhhadnZc34P+ab8Gw1LCH15B0DHsVpNT993IKwu5FyA1VNhRgv45d+QmaJ3lEIINyDJjhMoFVCzA1AzsCYh3iEUmAvYd14WYRRuwsMb2g6DcZu11dYjm0P+JVj7LsxoCcuehPNH9I5SCFGJSbLjDJ6WhUDLP88OgKIo1q6snWelbke4GYMRmt+nrbL+j68g9iYw5cHmefBuW/j6EUiR73shhP0k2XECxZLs3GA3FhQrUpZkR7grRYGGveHhn2HET1C/F6gmbZX1OV3gk3vh0CqQKcKEEDZyuRmU3ZFSQS07AC2qtwAk2RFVRO1O2nYqCda+o62yfug3bYtqCZ2f0BYjNcpHmRCibNKy4wQVmew0r6Z1Yx3LOEZ6XvoNX0+ISiGmlVbPM34bdPg/8PSDlB3aXD3vtoYN70N+lt5RCiFclCQ7TlCRyU6ITwi1AmsBMgRdVEGhcXDH6/Dk39pcPX7V4OJx+OkZeKsZ/PYfuHRG7yiFEC5Gkh0nqMhkBy53ZclMyqLK8gvT5up58m+4czqE1tGGrf/xujZXz7In4dwhvaMUQrgISXacQPH0AkAtqJi5cVqEF9XtyEzKoqrz9IX2D8PjW2DgxxDTBgpzL4/gWvQQnNiid5RCCJ1JsuMEFd6yU5Ts7Dq7C1m0Xgi0YetN74FRv8HwH6BBH0CFPd/Bh7fA/Dtg309gNusdqRBCBzKEwQkqOtlpHNYYT4MnF/IukJyZTK2gWhVyXSEqPUWBuC7alrZHm5hwx5dw7C9tC6sHNz0Grf4BXv56RyuEcBJp2XGCik52vIxeNK3WFICkM0kVck0h3E5EE+j3nrbaeucnwCcYzh+CH5+C6U1hxQuQcUrvKIUQTiDJjhNYk538ikl2AFpHtAZgW9q2CrumEG4pKAZufQme3A23v6GtwZV7Eda8pa3B9fUoOCU/R0K4M0l2nOByy07FLd7ZqnorAJLSkirsmkK4Ne8ASHhUW4Nr8GdQuwuYC2Hnl/BBd62uZ88yMJv0jlQIUcGkZscJFK+K7cYCiI+IB+DgxYNk5GcQ5BVUYdcWwq0ZjND4Tm07lQTr34NdX1+u6wmtU1TXM0RLkIQQlZ607DhBRdfsAIT7hlsnF9yetr3CritElRLTCvp/ABN2QpcnwScELhwpmqSwKfzyPKSf0DtKIcQNkmTHCRyR7AC0imgFSN2OEDcsKAZ6vQCJu+GON7VRW7np2npcM1rC4pGQvEkWHxWikpJkxwksyQ4VWKAMl5MdGZElRAXx8ocOo7S6nge+gLiu2orru76G//WCuT1g+xdQmKd3pEIIO0iy4wSKl2UG5YpNdlpX10Zk7Tq7iwJzxV5biCrNYIBGt8PwZfB/f0CrB8HorY3aWvJ/l9fhyjitd6RCCBtIsuMEjurGqhtSl0CvQHIKc9h/fn+FXlsIUSQ6HvrN0rq4bnkeAmMg68zldbgWj4TkjdLFJYQLk2THCYonOxW5vINBMViHoEvdjhAO5h8ONz+lTVJ4/wKo1VEbur7ra/jfrVoXV9Ln0sUlhAuSZMcJrDU7AIWFFXptKVIWwsmMntDsXhi5/OourqWjpYtLCBckyY4TFE92Krxup2gm5aS0JFkUVAhnK97F1XNy6V1cxzdIF5cQOpNkxwkcmew0D2+Oh+JBWk4ap7PkL0khdOEfDl3/WayLq9PlLq55vbUZmrd+AvnZekcqRJUkyY4zGI3aasxUfLLj6+FL47DGAGxN21qh1xZC2MnaxfVTyS6u00nw3TiY3hiW/wvOHtQ7UiGqFEl2nEBRFIeNyAJoG9kWgM0pmyv82kKIcrJ2ce2BXi9CSG1tosL1s2BmW/j4HtjzPZgqto5PCHE1u9bGqlOnDkpRC4U9JkyYwPjx4+0+z50onp6o+fkOSXbaRbXjo90fsSV1S4VfWwhxg/yrQZcJ0OlxOLgSNv8P9v8Mh1drW2AMtBsBbYZCYJTOwQrhnuxKdhYsWFCum8TFxZXrPHdibdnJr7iVzy3aRLZBQeFoxlHOZJ+hul/1Cr+HEOIGGYzQsLe2XTgKWxbA1o8h8xSs+g/8/ho06QvtH4Hana1d30KIG2dXstOtWzdHxeH2HNmNFeQVRKOwRuw9v5ctqVu4rc5tFX4PIUQFCo3T1uLqPgl2fwub/gfJ6+HvJdpWvTG0exjiB4FPsN7RClHpSc2Okzgy2QFoF9kOgM2pUrcjRKXh4Q0tB8LDP8PoNdB2BHj6w5m98NPT8N8m8P0ESNmpd6RCVGqS7DiJs5KdTSmbHHJ9IYSDRbWAvjPgn3vg9je01p2CLNgyH+Z0gbk9YdunkJ+ld6RCVDpSoOwkipdjk502kW0AOJx+mHM556jmW80h9xFCOJhPMCQ8qq2+fuwv2DgX9i6Dk5u1bfkkrTWo7XAtQRJCXJcUKDuLg1t2Qn1CaRDagAMXDrAldQu943o75D5CCCdRFIjrom2X0iBpIWz5CC4cgU0faluNtlrS06w/eAfoHbEQLksKlJ3E4OkFOC7ZAa0r68CFA2xO3SzJjhDuJCACujwJnZ6Ao39oI7n2LIOTW7Rt+b+g5f1a4hMdr3e0QricG6rZKSgoIDk5mX379nH+/PmKisktXR567thkB6RIWQi3ZTBA3e7akhSJe+DWlyCsLuRnwuZ58P7N2tIUWxZAXqa+sQrhQuxOdjIzM5k9ezbdunUjKCiIuLg4mjRpQvXq1alduzajRo1i0yYpkr2So2t24PJMygcuHOBi7kWH3UcI4QICqkPnJ+DxrTDse2h+Hxi9tNXXv38C/ttYG8l1KknvSIXQnV3JzvTp04mLi2P+/Pn06tWLpUuXkpSUxP79+1m3bh1TpkyhsLCQ3r17c9ttt3HgwAFHxV35OLhmB6CabzXqBtcFYEuazKYsRJWgKFDnZhgwT2vt6f0KVKsP+Ze0kVwfdIP3u2lz+eRc1DtaIXRhV83Opk2b+OOPP2jWrFmpz3fo0IGRI0cyZ84c5s+fz59//kmDBg0qJNDKztFDzy3aRbbjcPphNqVsometng69lxDCxfiHa8tSdBynjeTaskCbtPB0EvyQBD//C5reA60fhNpdtG4xIaoAu5Kdzz//3KbjvL29GT16dLkCclfOSnY6RHfgy/1fsuH0BofeRwjhwoqP5LrtNdjxBWz9BM7sgR2LtC00TluVvdUDEFxT74iFcKhyp/WdOnUiIyOjImNxa05LdqI6oKBw8OJBzuacdei9hBCVgH816DgWxqyDR37TZmn2DtLW51r1CrzVHD69T1umojBP72iFcIhyJzvr168nNzf3qv0ZGRlMnDjxhoJyR85KdkJ9Qmkc1hiA9afXO/ReQohKRFGgZtuiWZr3wb3vQ1xXQIWDK+Cr4VpR80/PQsounYMVomLZnewMGDCAV199FUVRSEtLu+r5rKws3nzzzRsKatasWcTFxeHj40NCQgIbN24s89hvvvmGdu3aERISgr+/P61ateKTTz65ofs7wuVkp+JXPb/STTE3AbD+lCQ7QohSePlB/GAYvkwbzdX1KQiMgZzzsGE2zOlcVNT8oRQ1C7dgV80OQK1atVi2bBmqqhIfH0+1atWIj48nPj6eVq1asW/fPqKjo8sd0KJFi0hMTGTOnDkkJCQwY8YM+vTpw759+4iIiLjq+LCwMJ577jkaN26Ml5cXy5YtY8SIEURERNCnT59yx1HRFMukgg6cZ8fipuibmL9rPutPr0dV1XIt8SGEqCKq1YOez0OPf8Gh32DbJ7D3x2JFzc9Bk7u1oua4rlLULColRVVVtTwnenl58ddff3Hq1Cm2bdtGUlISO3fuxGw285///Id//OMf5QooISGB9u3bM3PmTADMZjOxsbE8/vjjPPvsszZdo02bNtx55528/PLLNh2fkZFBcHAw6enpBAUFlSvu60l9/Q3Oz5tH2MiRRD7ztEPuYZFbmEvnzzuTb87nu37fUSe4jkPvJ4RwM1lnYceXWuKTtvvy/uBYaDkI4h+A8Pr6xSdEEVt/f9vdsmORlZWFZ1HXzD333FPey5SQn5/Pli1bmDRpknWfwWCgV69erFu37rrnq6rKb7/9xr59+3jttdcqJKaK4qyaHQAfDx9aR7RmQ8oG1p9eL8mOEMI+/uHQcQzc9Bic2qqttr7za0hPhj/f1LaaHbSusOb9wTdU74iFuCa72iOPHz9u/bcl0bmWkydP2hXM2bNnMZlMREZGltgfGRlJSkpKmeelp6cTEBCAl5cXd955J++++y633nprmcfn5eWRkZFRYnO0y8tFOL5mB6RuRwhRARRFW2z0rrfgqX3axIUNeoNigBMb4YdEeLMRfDkM9v8MpkK9IxaiVHYlO+3bt+f//u//rrkcRHp6OnPnzqV58+Z8/fXXNxygLQIDA0lKSmLTpk385z//ITExkdWrV5d5/LRp0wgODrZusbGxDo9R8XL8QqDF3RStJTubUjZhMpucck8hhBvz9NWWpBjyFSTu1WZqjmgGpjzYvRQ+GwjTG2uLkqbs1DtaIUqwqxtr9+7d/Oc//+HWW2/Fx8eHtm3bEhMTg4+PDxcuXGD37t38/ffftGnThtdff5077rjDrmDCw8MxGo2kpqaW2J+amkpUVFSZ5xkMBurX1/qPW7VqxZ49e5g2bRrdu3cv9fhJkyaRmJhofZyRkeHwhMfgXZTs5DlnHosmYU0I9AokMz+T3ed206J6C6fcVwhRBQRGXp6pOWUHbP9Cq/HJOgPrZ2lbZAttwsIW92urtguhI7tadqpVq8b06dM5ffo0M2fOpEGDBpw9e9a6BtaQIUPYsmUL69atszvRAa3ouW3btqxcudK6z2w2s3LlSjp27GjzdcxmM3nXSCq8vb0JCgoqsTmatWXHSd1YRoORhKgEQObbEUI4iKJAdDzcNg3+uRce+EIbuWX0gtSd2vIU/20MCwdqkxYWXD03mxDOUK4CZV9fXwYMGMCAAQMqOh4SExMZNmwY7dq1o0OHDsyYMYOsrCxGjBgBwNChQ6lRowbTpk0DtC6pdu3aUa9ePfLy8vjxxx/55JNPmD17doXHdiMUL28AzPnOm6E0ITqBFcdXsO70Oka1HOW0+wohqiCjJzS6Xduyz8Our7UWn5Ob4cDP2uYTDE37QcuBUKuTDGMXTlPu0VirVq2iR48epT63YMEChg8fXq7rDho0iDNnzjB58mRSUlJo1aoVy5cvtxYtHz9+HEOxH5CsrCzGjBnDiRMn8PX1pXHjxnz66acMGjSoXPd3FMVbS3bUPOe07AB0iukEwLa0bWQVZOHv6e+0ewshqjC/MOgwStvO7Iftn2vrcWWchK0faVtQTWhxnzaUPbL0xaWFqCg2z7MzevRohgwZQteuXQHw8PDgySefZOrUqdaRWefOnWPUqFF8++23mEyVpyjWGfPsZPzyCyfHP4FvmzbEfbbQIfcozR3f3EFyZjJv93ibW2rd4rT7CiFECWaTthL7jkWw+zvIKzYKNqIZtLxfq++RRUmFHWz9/W1zG2K7du0YOnSo9bHZbGb69Ol06NCBv//+mx9//JEWLVqwdOlSm4alVzUGa8uOcxfa61KjCwBrTq5x6n2FEKIEgxHq3Az3zIKnDsDAj6HxXVp9T9rfsOIFeKsZzL8TtiyAnAt6RyzciM3JzoYNGxgyZIj18XfffUdUVBTbt2+nbdu29O3bl5SUFFq2bMmGDRscEmxlZu3GcmLNDpRMdso5WbYQQlQsTx9oeg8MXghP7Ye+b0Nt7bOKY2vg+yfgzYbwxRD4e6kUNosbZnPNztq1a/nhhx+sj++66y62bNlC69atSUtLQ1VVWrduzbp16/AqGnkkLrOMxjI7aTSWRfuo9ngZvDiddZrD6YepF1LPqfcXQohr8g2FtsO17WIy7FoMO77SWnv2LtM272Bo2hdaDIS4LlorkRB2sLll59VXX+W5556zPv7jjz/o1q0baWlp1oUmk5KS6NWrF4cOHar4SCs5y2gsZxYoA/h6+NI+qj0gXVlCCBcXEgtdnoQxa+GxtdB5AgTVgLx0bcmKj++Gt5pri5Oe3ALSWi1sVO6FQI1GI6qqUq9ePT799FOOHTvGY489xoULF/D39yczM7OiY3UYZxQo5x04wOG+d2MMDaXhurUOuUdZPt39Ka9teo2E6AQ+7P2hU+8thBA3xGyG42u1SQt3L4Xc9MvPhcZBs/7azM6RzbR5f0SVUuEFyldSVZVRo0aRlJREQkICAwcOZOfOnfTs2ZPs7OzyXtZtOXtSweI61+gMwNbUrWQXyNdGCFGJGAxa19Xd72iFzYMWasmNpx9cOAprpsOczjArAVa/BmcP6B2xcEHlnmdn6dKl3H333SX2xcTE8Ouvv/LOO+/ccGDuxlKg7OyaHYC4oDhqBNTg5KWTbDi9gR61Sp8fSQghXJqHNzS5S9vys2D/ctj1DRz4Fc7ug9VTtS2qpbYae7P+EFpb76iFCyh3N5Y7cUY3VuGFCxzoqE3y13j33yhOnjn0lfWvsGjfIgY2HMjzHZ936r2FEMKhctNh74/arM2HV4G52OrrNdtrLUFN+0FQtG4hCsdweDeWsI+h2Ag1PbqyutbQJoOUIehCCLfjE6wtOvrgYvjnfrhrhjanDwqc2ATLn4XpTWDBXbB5HmSd0zti4WR2dWPVqVPHOvLKHhMmTGD8+PF2n+dOlOLJTl4e+Pg49f6WIeinsk5x8OJBGoQ2cOr9hRDCKfyrQbsR2paZAru/1Vp8kjfA0T+17YenoG53ba6fxndp5wi3Zleys2DBgnLdJC4urlznuRUPD63QzmzGnJeHs2eJ8PP0IyE6gT9P/snq5NWS7Agh3F9gFCT8n7ZdTNZWXt/1NZxOgkMrtW3Zk1Cnq9bN1fguCKiud9TCAaRmB+fU7ADsbd0GNSeHeitW4FWzhsPuU5Yv933Jy+tfpmV4Sxbe6bz1uYQQwqWcO6QNY/97KaTsuLxfMUDtztCsHzTuC4GROgUobCU1Oy7o8vBz5y4ZYdE9tjsAO87u4GzOWV1iEEII3VWrB13/CaP/hPHboNcLENMaVHNRN9c/4b+NtHW6NnwAGaf1jljcIKnZcSKDlxdmnL8YqEWEXwTNqzVn17ldrE5ezYCGA3SJQwghXEZYXW3W5i5PavP27P5Oa/U5uUVbp+vYGvjpGah1k1bj0+RuCHZ+y7y4MVKz40SXFwN1/mgsi+6x3SXZEUKI0oTGQefx2nbxeFHi8y2c2AjH12nb8mehZgct8Wl6j7bEhXB5UrOD82p2Dt1xJ/mHD1Pr44/w79DBYfe5lv0X9nPfd/fhbfTmj0F/4Ofpp0scQghRaaSfgD3fazU+yetLPhfTRpvksHFfqN5Ql/CqMlt/f5d7BmVhP2vLjpMXAy2uQUgD62zK606vo2etnrrFIoQQlUJwTbjpMW3LOKUlPru/hWNr4dRWbVv5EoQ31EZ0NblLS4JkrS6XIQXKTmSZWFAt0C/ZURSFHrHachGrk1frFocQQlRKQTHaUPYRP8I/98Fdb0G9nmDwhLP7tbW65t6irc7+4zNw5A8wFV7/usKhpGXHiayjsXQqULboHtudT/d8yh8n/sBkNmE0OHvWHyGEcAOBkdBupLblXIQDv2itPgdXQMYJ2Pi+tvmGQaPbtVafej3A01fvyKscSXacyLoYqM7JTpvINgR6BXI+9zzbz2ynTWQbXeMRQohKzzcEWg7UtoIcOLQK9i6DfT9CznlIWqhtnv5Qvyc06QsNemvnCYeTZMeJXGE0FoCnwZOba97MD4d/YMXxFZLsCCFERfL0hcZ3aJupEI6vhT3LtOQn4yTs+U7bDJ7aGl5N7oJGd8okhg4kNTtOpHh5AvoWKFvcWvtWAH499qssDCqEEI5i9NASmjtehyf/hlG/QZdErZjZXHB5yYr/NoS5PeGPNyF1N8jncoWSlh0nMnhZWnb07cYC6BzTGT8PP1KyUth1dhctqrfQOyQhhHBvigI12mpbrylwZj/s/V5r9Tm1FU5u1rbfXoaQ2tDoDmh0m7aEhdFT7+grNWnZcSJX6cYC8PHwoVvNbgD8cuwXnaMRQogqqHpDbdmKR1dB4l64awY06ANGb7h4DDbMho/vgdfrweKRsHOxVggt7CbJjhNZRmPpXaBscWucdGUJIYRLCIqGdiNgyJcw8QgMWgitHgS/cMhL11Zr//pheKMefNQX1s+G80f0jrrSkG4sJ1K8LUPP9W/ZAehSowu+Hr6cvHSS3ed306xaM71DEkII4eWvFS03uQvMJm2drn0/wr6f4Mxebe6eI39oS1dENNWGtTe6Q5vI0CBtGKWRZMeJDC7UjQXg6+FL1xpd+eXYL/x69FdJdoQQwtUYjBDbQdt6vQDnDsH+5Vric2wtpO3Wtj//C/4R0LAPNLwN6nYH7wC9o3cZkgI6kXVSQRcoULawdGX9cuwX6coSQghXV60edBwLw5fB0weh/4fQrD94B0FWGmz7BBYNgdfraPU+697TEqQqTlp2nEgpGo1lznWdZOfmGjfjY/QhOTOZfRf20Tissd4hCSGEsIVfGLS8X9sK8+HYX1qrz/6f4cIROLxa236eBGH1tEkMG/bWRnd5eOsdvVNJsuNEio9lIVDXSXb8PP3oUqMLK46v4Jejv0iyI4QQlZGHl7YURb0ecNurcO6glvQc+EXr7jp/SBvdtWG2NotzvR7Q4FYtAQqK0Tt6h5Nkx4kMPtp6KObcHJ0jKalPXB9WHF/BT0d+4vHWj6PISr1CCFF5KQqEN9C2TuMgN0Nr4TnwMxz4FS6larM5712mHR/VQhvy3qA31Gyn1Qm5GUl2nMhgadnJydU5kpK6xXbDz8OPE5dOsP3MdlpFtNI7JCGEEBXFJwia3q1tZjOk7NBafPb/rI30StmpbX++qS1aWr+XVuhc7xatq8wNSLLjRIqlZceFurFAG5XVs1ZPvj/8PT8e+VGSHSGEcFcGA8S00rZuz0DWWW2V9v0/a0tX5JyHnV9qm2KAGu205Kd+T4hpXWlbfWQ0lhMZfH0AUHNcqxsL4I66dwDw89GfKTAX6ByNEEIIp/APh/jBcP98ePowDP8ROk/Q5u9RzXBiI6yeCh/21CY0XDwSti2EzBS9I7eLtOw4keKtJTuu1rIDcFP0TYT5hHE+9zzrT62na82ueockhBDCmYweENdZ2259EdJPwMGVWsvP4d8h54I2k/Our7XjI1toLT71e0LsTVqRtIuSZMeJXLllx8PgwW1xt/HZ3s/44cgPkuwIIURVF1wT2g7TNlOhtkjpwRXadioJUndq218zwCtAW9293i1at1dYHb2jL0GSHSdSfIpadnJdq0DZ4s66d/LZ3s/47fhvZBdk4+fpp3dIQgghXIHRA2rdpG23/Fur9Tm0Skt8Dq2ErDNFS1r8qB0fVq+o1acXxHXRlsDQkSQ7TmQoSnZUF012WoS3IDYwluTMZFYnr7bW8QghhBAl+IdfntDQbNZaeA6ugIO/QfJ6bV6fjYdg4wdg9IJaHeGmx7R1vHQgBcpOZGnZUQsKUAsLdY7maoqicEcdLcH54cgPOkcjhBCiUjAYIDoeuv4TRvwAzxyBwZ9Bu5EQUgtM+XDkd631RyfSsuNEBl9f67/NuXkYA1zv7b+z7p28v+N9/jr5F2dzzhLuG653SEIIISoTnyBofKe2qao2m/PBldqkhTqRlh0nUrwvr0Wi5rlmV1ad4Dq0rN4Sk2pi2aFleocjhBCiMrPM5nzTaAiM0i0MSXacSFGUy0XKLjaLcnH31r8XgKUHl8pK6EIIISo9SXaczFDUuqO62PpYxd0Wdxs+Rh8OpR9i59mdeocjhBBC3BBJdpxM8bUsBup6EwtaBHgFcGvtWwFYcnCJztEIIYQQN0aSHSe7PPzcdVt2APrV7wfA8iPLySl07ViFEEKIa3HJZGfWrFnExcXh4+NDQkICGzduLPPYuXPn0rVrV0JDQwkNDaVXr17XPF5vlycWdN2WHYB2Ue2oEVCDSwWXWHFshd7hCCGEEOXmcsnOokWLSExMZMqUKWzdupX4+Hj69OlDWlpaqcevXr2aBx54gFWrVrFu3TpiY2Pp3bs3J0+edHLktqksLTsGxcA99e8B4NuD3+ocjRBCCFF+LpfsTJ8+nVGjRjFixAiaNm3KnDlz8PPzY968eaUev3DhQsaMGUOrVq1o3LgxH374IWazmZUrVzo5ctsovq4/Gsvinnr3oKCwIWUDyZnJeocjhBBClItLJTv5+fls2bKFXr16WfcZDAZ69erFunXrbLpGdnY2BQUFhIWFOSrMG2IoWvncVefZKS4mIIaOMR0B+Hr/1zpHI4QQQpSPSyU7Z8+exWQyERkZWWJ/ZGQkKSkpNl1j4sSJxMTElEiYrpSXl0dGRkaJzVkqU8sOwMCGAwFtVFa+KV/naIQQQgj7uVSyc6NeffVVvvjiC5YsWYJPUW1MaaZNm0ZwcLB1i42NdVqMlpYds4vX7Fh0i+1GhF8E53PP8+uxX/UORwghhLCbSyU74eHhGI1GUlNTS+xPTU0lKura00y/+eabvPrqq/zyyy+0bNnymsdOmjSJ9PR065ac7Lx6FEvLjurio7EsPAweDGgwAIAv932pczRCCCGE/Vwq2fHy8qJt27YliostxcYdO3Ys87zXX3+dl19+meXLl9OuXbvr3sfb25ugoKASm7MYfCyTClaOlh2A/g36Y1SMbE3byv4L+/UORwghhLCLSyU7AImJicydO5ePPvqIPXv28Nhjj5GVlcWIESMAGDp0KJMmTbIe/9prr/H8888zb9484uLiSElJISUlhUuXLun1Eq5J8SlaLqKS1OwARPpH0iO2ByCtO0IIISofl0t2Bg0axJtvvsnkyZNp1aoVSUlJLF++3Fq0fPz4cU6fPm09fvbs2eTn5zNgwACio6Ot25tvvqnXS7gma8tOJRiNVdzARlqh8rLDy8guyNY5GiGEEMJ2HnoHUJpx48Yxbty4Up9bvXp1icdHjx51fEAVyGCp2alELTsACdEJxAXFcTTjKMsOL7MmP0IIIYSrc7mWHXdnXS4ip/LU7IA2o7IlwVm4ZyGqquockRBCCGEbSXaczODnD4A5u/J1BfWr3w8/Dz8Opx/mr1N/6R2OEEIIYRNJdpzM4OcHVM5kJ9ArkP4N+gPwye5PdI5GCCGEsI0kO05m8K+8LTsAQ5oMwaAYWHtqLQcvHNQ7HCGEEOK6JNlxssrcsgNQM7Amt8TeAsCnez7VORohhBDi+iTZcTKDf+VOdgAeavoQAN8f+p7zued1jkYIIYS4Nkl2nKyyt+wAtI5oTbNqzcg358skg0IIIVyeJDtOZkl2KChAza+cq4grimJt3fl87+fkFlauOYOEEEJULZLsOJk12QFMWVk6RnJjesf1Jto/mvO551l6cKne4QghhBBlkmTHyRQPDxTvovWxKnFXlqfBkxHNtfXK5u+aT4G5QOeIhBBCiNJJsqMDd6jbAbi3/r2E+YRxKusUPx35Se9whBBCiFJJsqMDd0l2fDx8GNp0KAAf7vwQs2rWOSIhhBDiapLs6MBdkh2AQY0GEegZyJH0I/x2/De9wxFCCCGuIsmODtwp2QnwCuCBJg8AMHfnXFkgVAghhMuRZEcHlX3JiCs92ORBfD182X1uN2tOrtE7HCGEEKIESXZ0YJ1FuRIPPS8u1CeUgQ0HAjAraZa07gghhHApkuzowNqNleUeLTsAI1uMxNfDl7/P/c2q5FV6hyOEEEJYSbKjA8WNanYswnzCGNJkCAAzk2bKyCwhhBAuQ5IdHbhTgXJxw5sNJ8AzgAMXDvDLsV/0DkcIIYQAJNnRhbsVKFsEewdb5915L+k9TGaTzhEJIYQQkuzowl1bdgAebPogQV5BHEk/wo9HftQ7HCGEEEKSHT1cLlB2j9FYxQV6BVrXzJq5bSZ5pjydIxJCCFHVSbKjA2s31qVLOkfiGEOaDCHCN4JTWaf4fM/neocjhBCiipNkRwfGoCAATJcydY7EMXw9fBnXehwAH+z4gIu5F/UNSAghRJUmyY4ODAEBAJgz3bNlB+DuenfTMLQhmQWZvL/jfb3DEUIIUYVJsqMDY2AgAOaMDJ0jcRyjwcg/2/0TgC/2fcHxjOM6RySEEKKqkmRHB4ZASzfWJbdeWqFTTCc6x3Sm0FzIjK0z9A5HCCFEFSXJjg6MgVo3FiYTak6OvsE4WGK7RAyKgV+P/cqmlE16hyOEEKIKkmRHB4qvLxiNAJgy3bNI2aJhaEPua3AfAFM3TKXAXKBzREIIIaoaSXZ0oCjK5bodN092AMa3Hk+wdzAHLx7ki71f6B2OEEKIKkaSHZ0YipIdU4b7JzshPiE80eYJQFtG4mzOWZ0jEkIIUZVIsqMTQ1HdjtlN59q5Uv/6/WlWrRmXCi4xffN0vcMRQghRhUiyoxOjZURWFejGAm0o+nMJz6Gg8P3h79maulXvkIQQQlQRkuzoxNqyU0WSHYAW1VvQv0F/AF5c9yL5pnydIxJCCFEVSLKjE2NAUc1OFUp2AJ5s+yTVfKpxOP0wH+z4QO9whBBCVAGS7OjEEGQZjeW+S0aUJtg7mEkJkwD4387/sf/Cfp0jEkII4e4k2dHJ5ZYd910yoiy9a/emR2wPCtVCXlj7AiazSe+QhBBCuDFJdnRiCKyaLTugzTP0XMJzBHgGsPPsThbuWah3SEIIIdyYJDs6MQZV3ZYdgEj/SBLbJQLw7rZ3OZp+VN+AhBBCuC1JdnRibdmpApMKluW+BveREJ1ArimXSX9OkqUkhBBCOIQkOzoxhoQAYLp4Udc49GRQDLzS+RUCvQLZdW4XH+74UO+QhBBCuCFJdnRiTXYuXNA3EJ1F+Ufx74R/A/D+jvfZcWaHzhEJIYRwN5Ls6MSa7GRkoJrN+gajszvq3sHtdW7HpJr415p/kV2QrXdIQggh3IgkOzrxKEp2MJsxZ1TNIuXinkt4jgi/CI5lHOPVja/qHY4QQgg3IsmOThQvLwz+/kDVrtuxCPYOZlqXaSgoLDm4hO8Pfa93SEIIIdyEJDs6snRlFVbxuh2LDtEdeCz+MQBeXv8yhy4e0jkiIYQQ7sAlk51Zs2YRFxeHj48PCQkJbNy4scxj//77b+677z7i4uJQFIUZM2Y4L9AbJCOyrvZoy0e5Kfomcgpz+Ofqf0r9jhBCiBvmcsnOokWLSExMZMqUKWzdupX4+Hj69OlDWlpaqcdnZ2dTt25dXn31VaKiopwc7Y0xhoYCYLqYrnMkrsNoMDKt6zTCfcM5lH6I/2z4D6qq6h2WEEKISszlkp3p06czatQoRowYQdOmTZkzZw5+fn7Mmzev1OPbt2/PG2+8weDBg/H29nZytDdGhp+XLtw3nNdvfh2DYuC7Q9/x+d7P9Q5JCCFEJeZSyU5+fj5btmyhV69e1n0Gg4FevXqxbt26CrtPXl4eGRkZJTY9SDdW2dpHtefJNk8C8Pqm19lweoPOEQkhhKisXCrZOXv2LCaTicjIyBL7IyMjSUlJqbD7TJs2jeDgYOsWGxtbYde2hyQ71zas2TDuqnsXJtXEP3//J8mZyXqHJIQQohJyqWTHWSZNmkR6erp1S07W55eoMTQEkG6ssiiKwpSOU2hWrRnpeemM/208WQVZeoclhBCiknGpZCc8PByj0UhqamqJ/ampqRVafOzt7U1QUFCJTQ/SsnN9Ph4+vN3jbcJ9wzl48SAT/5hIoblQ77CEEEJUIi6V7Hh5edG2bVtWrlxp3Wc2m1m5ciUdO3bUMTLH8AgLA6Dw/HmdI3Ftkf6RzOgxA2+jN7+f+F1GaAkhhLCLSyU7AImJicydO5ePPvqIPXv28Nhjj5GVlcWIESMAGDp0KJMmTbIen5+fT1JSEklJSeTn53Py5EmSkpI4ePCgXi/BZh7h4QAUnj2rcySuL756PK91fQ0FhcX7F/PhTlkhXQghhG1cLtkZNGgQb775JpMnT6ZVq1YkJSWxfPlya9Hy8ePHOX36tPX4U6dO0bp1a1q3bs3p06d58803ad26NY888oheL8FmHtWrA2BOT8ecn69zNK6vZ+2ePNvhWQDe2fYO3x36TueIhBBCVAaKKv0BZGRkEBwcTHp6ulPrd1RVZW/LeCgooP7KFXjWqOG0e1dm0zdPZ/7f8/FQPHjnlnfoWrOr3iEJIYTQga2/v12uZacqURRFurLKYULbCdxR5w4K1UKeXP2kzMEjhBDimiTZ0ZmlK0uSHdsZFAOvdHmF7rHdyTPl8fhvj7MtbZveYQkhhHBRkuzozNqyc+aMzpFULp4GT97s9iadYjqRU5jDmBVj+Pvs33qHJYQQwgVJsqOzy8mOtOzYy9vozYweM2gb2ZZLBZd49NdH2XV2l95hCSGEcDGS7OhMurFujK+HL7N6ziK+ejwZ+Rk88ssjbE3dqndYQgghXIgkOzrzqC7dWDfK39Of9299n3aR7cgqyGL0itGsO1VxC8cKIYSo3CTZ0ZnU7FQMf09/3uv1Hp1rdCanMIdxK8exOnm13mEJIYRwAZLs6MyjaLLEwgpc1b2q8vXw5Z0e79CzVk/yzflMWDWBr/d/rXdYQgghdCbJjs48Y2IArWVHZlG+cV5GL97o9gZ317sbk2rihXUv8O62d2UtLSGEqMIk2dGZMSwMxdsbkNadiuJp8OSVzq8wOn40AB/s+IDn1jxHgalA58iEEELoQZIdnSmKgmd0NAAFp05f52hhK0VRGNtqLC92ehGjYuT7w98zesVoLuRe0Ds0IYQQTibJjguwdGUVnDqlcyTup3+D/szsORM/Dz82pmxk8LLB7D2/V++whBBCOJEkOy7As4YkO47UpUYXFt6xkFqBtTiVdYqHfnyIn478pHdYQgghnESSHRdgbdk5LcmOo9QPrc9nd35G5xqdyTXl8swfz/DmpjeljkcIIaoASXZcgIe1ZkeSHUcK9g5m1i2zGNl8JAAf7f6IYcuHkZyZrHNkQgghHEmSHRdgbdk5KcmOoxkNRp5s+yQzus8g0CuQnWd3MvD7gSw/slzv0IQQQjiIJDsuwKt2HAAFJ0+iylw7TtGzdk8W911Mq+qtuFRwiaf/eJopa6dwKf+S3qEJIYSoYJLsuACPiOoY/PzAZCL/xAm9w6kyYgJimH/bfEa1GIWCwjcHvqH/d/1lXS0hhHAzkuy4AEVR8IqLAyD/yBF9g6liPAwejG8znv/1+R81AmpwOus0j/76KC+ve5msgiy9wxNCCFEBJNlxEV516gCS7OilfVR7vrn7GwY3GgzAl/u/pP+3/fk9+XedIxNCCHGjJNlxEZaWnbyjR3WNoyrz8/TjuZue48PeH1IjoAansk4x7rdxjP9tPKcuSfG4EEJUVpLsuIjLLTtH9Q1EkBCdwDd3f8OI5iPwUDxYlbyKe5bew4c7P5R5eYQQohKSZMdFeNWJAyD/4EFZodsF+Hn6kdg2ka/6fkXbyLbkmnJ5e+vb3L30bn4++rN8jYQQohKRZMdFeNevD0YjpvR0ClNT9Q5HFKkfWp/5feYztctUqvlU48SlEzz1+1M8+NODbEvbpnd4QgghbCDJjosweHvjXbcuALm79+gcjShOURT61uvLj/1/5LH4x/D18GXHmR0M/WkoT/z2BPvO79M7RCGEENcgyY4L8WnaBIDcvZLsuCI/Tz/GtBrDD/f+wH0N7sOgGPgt+TcGfD+AJ1c9KUmPEEK4KEl2XIh3Yy3ZydsjyY4rq+5XnRc6vcA3d3/DbXG3oaCw4vgKBnw/gCd+e4K/z/2td4hCCCGKkWTHhfg0KWrZ+Xu3zpEIW9QLqccb3d5gyT1LuD3udhQUfkv+jcHLBjPy55GsTl6NWTXrHaYQQlR5iirDSsjIyCA4OJj09HSCgoJ0i8OUmcn+DgmgqtT/43c8IyJ0i0XY7/DFw8zdOZflR5ZTqBYCEBcUx0NNH6Jvvb74evjqHKEQQrgXW39/S7KD6yQ7AIfv7U/enj3UeGs6QbffrmssonxSslL4bO9nLN63mMyCTAACPQO5q95dDGg4gIahDXWOUAgh3IOtv7+lG8vF+LVtC0D2ps06RyLKK8o/isS2ifx6/6882+FZagbUJLMgk8/3fs59393HkB+HsOTAErILsvUOVQghqgRp2cG1WnYylv/MyQkT8G7UiLrfLtU1FlExzKqZ9afXs3j/YlYdX2Xt4vLz8KNnrZ7cWfdOEqIT8DB46BypEEJULtKNZQdXSnYKz57lQJeuAFK344bO5pzl24Pf8vWBr0nOTLbur+ZTjdvq3Madde6keXhzFEXRMUohhKgcJNmxgyslOwBH7h9I7s6dRL38EqH33693OMIBVFVl+5ntLDu8jJ+P/szFvIvW56L8o7gl9hZuqXULbSLb4Gnw1C9QIYRwYZLs2MHVkp0z773H2XfeJeCWW4h9b5be4QgHKzAXsO7UOpYdXsbq5NXkFOZYnwvyCqJbzW70qNWDhOgEgrz0//4UQghXIcmOHVwt2cndu5cj/e5F8fGhwZo1GAP89Q5JOEluYS4bTm9g5fGVrE5ezYW8C9bnjIqRFuEt6BTTiU41OtGsWjOp8xFCVGmS7NjB1ZIdVVU5fMed5B85QvQrLxMyYIDeIQkdmMwmks4ksfL4StacXMOR9CMlng/0CiQhKoG2kW1pG9mWhqENMRqMOkUrhBDOJ8mOHVwt2QE4O3cuZ/47Hd82bYj7bKHe4QgXcOrSKdadWsdfp/5i/en1ZOZnlng+wDOA+Ih42kW2o01EG5pWa4qPh49O0QohhONJsmMHV0x2CtLSONjjFjCZqPPN1/g0bap3SMKFmMwmdp3bxcbTG9mStoWktCSyCrJKHOOheFA/tD7NqjWjeXhzmoc3p15IPSl4FkK4DUl27OCKyQ7AyaeeJmPZMgJvvZWa776jdzjChZnMJvZd2MfW1K1sTdvKltQtnM89f9Vx3kZvGoU1onFoYxqENrBuUvgshKiMJNmxg6smO3kHDnC4790AxH31Jb4tWugckagsVFUlJSuFXed28ffZv9l1bhe7z+62Ll9xpUi/SC3xCWlA/dD6xAXFUTuoNsHewU6OXAghbCfJjh1cNdkBODVxIunffod30ybU+fJLFA8ZfSPKx6yaOZ5xnL/P/c2BCwc4cPEABy4c4HTW6TLPCfEOoXZQ7au2mIAYaQ0SQuhOkh07uHKyU3j2LIfuuBNzRgbVRj1CxD//qXdIws1k5mdy8OJBDlw4wP4L+zmcfphjGcdIy0675nmBnoFEB0QT4x9DdEA0NQJqEO0fTUxADNH+0YT6hGJQZPk9IYTjSLJjB1dOdgAyfvqJk08mAhD14ouEDhqoc0SiKsguyOZ45nGOZhzleMZxjmUcs/67+IzPZfFQPKjmW40IvwjCfcOp7lud6n7VS/w/3DecEJ8QKZoWQpSLJDt2cPVkByDtv9M5N3cuAOHjHyf8//4PxShzqgh9ZBdkczrrNKcuneJ01mlOXjrJ6UunOZV1itOXTnMm5wwqtn+0BHoGEuITQqh3KCE+IYR4X/538X2BXoEEeQUR4BmAn6eftBwJUcVV6mRn1qxZvPHGG6SkpBAfH8+7775Lhw4dyjz+q6++4vnnn+fo0aM0aNCA1157jTvuuMPm+1WGZEdVVdLeeJPz8+YB4Nu6NRFPP41fm9Y6RybE1QrMBZzLOceZ7DOcyTnD2ZyzpGWncTbnLGdyzlj3n889j1k1l+seBsWAv6e/NfkJ9AokwCvA+jjAK4AAzwB8PXzx8/TT/u+h/b+0fTIhoxCVT6VNdhYtWsTQoUOZM2cOCQkJzJgxg6+++op9+/YRUcoK4GvXruXmm29m2rRp3HXXXXz22We89tprbN26lebNm9t0z8qQ7ICW8KQvWUrKK6+gZmcD4NOsGUF33YV/x5vwbtgQxSB/6YrKw2Q2kZmfyYW8C1zMu8iF3DL+n3eBi7kXuVRwiYz8DArNhRUei5fBy5oA+Xr44m30tm5eRq+r/u9j9LE+Lu0Yb6M3ngZPPAweeBo98VA88DBom2V/8cfF90mLlRC2qbTJTkJCAu3bt2fmzJkAmM1mYmNjefzxx3n22WevOn7QoEFkZWWxbNky676bbrqJVq1aMWfOHJvuWVmSHYuClBTOzprFxaXfQkGBdb/i64tXXBxecbXxqF4dj9BQjKFhGAICULy9MPj4oHh5Y/D2Ag9PFIMCBgMoCiiKligZDIBy1XOuwzVicam3pIpRVZU8cz7ZBdlcKrhEVkEWWQVZXCq4dHlfvvY415RLbmEuOYU52v9N2v9zC3PILcwj15SLSTXp/ZKuYlSMGBUjHgYPjAYjngZP7bGiPTYqRgwGAwbFgAEDRsWIoijaeYbL/zYoBowYUBSD9bFBMWAwFD1Ge2w931DsmGLXNSgKoKAoCgoKBsWAYn0MiuUxxZ5XsJ5jwKAdW3T+lf+3JHfWqygGULCeZ0B7bDnHcrxS9HmgFP1AWh9f9Y6WdVzJ/ZePvvJ4yxMlz7u8+9rXtR5f8n/FrnOD1y1NGU+VfcY1ninjA+9a9y/tudCIWIJCI8s8pzxs/f3tUuOY8/Pz2bJlC5MmTbLuMxgM9OrVi3Xr1pV6zrp160hMTCyxr0+fPixdurTM++Tl5ZGXl2d9nJGRcWOBO5lnVBTRL79M9cREMr5fxqU1f5KzeQvm7Gzy9uwhb88evUMUwmk8gZCizX24XgImHO/KlgeXaomoAAfG9KXX+Nd1ubdLJTtnz57FZDIRGVky84uMjGTv3r2lnpOSklLq8SkpKWXeZ9q0abz44os3HrDOPEJDCRv6EGFDH0ItLCQ/OZn8I0fJP34M07lzFJ4/j+n8Bcw5Oai5uZjz81Bz81Bzc1FNJlBVVNUMZhVUFcxm1KL/l3jsKlwlFleJQ7gdtdh/r3yizOeuOv/6x1mPUm0/tvQrV/zPQpmvwYV/7K4fmgsH70QGg34ph0slO84yadKkEq1BGRkZxMbG6hjRjVM8PPCuUwfvOnX0DkUIIYRwKS6V7ISHh2M0GklNTS2xPzU1laioqFLPiYqKsut4AG9vb7y9vW88YCGEEEK4PJcq+ffy8qJt27asXLnSus9sNrNy5Uo6duxY6jkdO3YscTzAr7/+WubxQgghhKhaXKplByAxMZFhw4bRrl07OnTowIwZM8jKymLEiBEADB06lBo1ajBt2jQAnnjiCbp168Z///tf7rzzTr744gs2b97MBx98oOfLEEIIIYSLcLlkZ9CgQZw5c4bJkyeTkpJCq1atWL58ubUI+fjx4xiKzSXTqVMnPvvsM/7973/zr3/9iwYNGrB06VKb59gRQgghhHtzuXl29FDZ5tkRQgghhO2/v12qZkcIIYQQoqJJsiOEEEIItybJjhBCCCHcmiQ7QgghhHBrkuwIIYQQwq1JsiOEEEIItybJjhBCCCHcmiQ7QgghhHBrkuwIIYQQwq253HIRerBMIp2RkaFzJEIIIYSwleX39vUWg5BkB8jMzAQgNjZW50iEEEIIYa/MzEyCg4PLfF7WxgLMZjOnTp0iMDAQRVEq7LoZGRnExsaSnJwsa245mLzXziHvs3PI++wc8j47hyPfZ1VVyczMJCYmpsQi4VeSlh3AYDBQs2ZNh10/KChIfpCcRN5r55D32TnkfXYOeZ+dw1Hv87VadCykQFkIIYQQbk2SHSGEEEK4NUl2HMjb25spU6bg7e2tdyhuT95r55D32TnkfXYOeZ+dwxXeZylQFkIIIYRbk5YdIYQQQrg1SXaEEEII4dYk2RFCCCGEW5NkRwghhBBuTZIdB5o1axZxcXH4+PiQkJDAxo0b9Q7JrUybNo327dsTGBhIREQE/fr1Y9++fXqH5fZeffVVFEVhwoQJeofilk6ePMmDDz5ItWrV8PX1pUWLFmzevFnvsNyKyWTi+eefp06dOvj6+lKvXj1efvnl666vJK7tjz/+oG/fvsTExKAoCkuXLi3xvKqqTJ48mejoaHx9fenVqxcHDhxwSmyS7DjIokWLSExMZMqUKWzdupX4+Hj69OlDWlqa3qG5jd9//52xY8eyfv16fv31VwoKCujduzdZWVl6h+a2Nm3axPvvv0/Lli31DsUtXbhwgc6dO+Pp6clPP/3E7t27+e9//0toaKjeobmV1157jdmzZzNz5kz27NnDa6+9xuuvv867776rd2iVWlZWFvHx8cyaNavU519//XXeeecd5syZw4YNG/D396dPnz7k5uY6PjhVOESHDh3UsWPHWh+bTCY1JiZGnTZtmo5Rube0tDQVUH///Xe9Q3FLmZmZaoMGDdRff/1V7datm/rEE0/oHZLbmThxotqlSxe9w3B7d955pzpy5MgS+/r3768OGTJEp4jcD6AuWbLE+thsNqtRUVHqG2+8Yd138eJF1dvbW/38888dHo+07DhAfn4+W7ZsoVevXtZ9BoOBXr16sW7dOh0jc2/p6ekAhIWF6RyJexo7dix33nlnie9rUbG+++472rVrx/33309ERAStW7dm7ty5eofldjp16sTKlSvZv38/ANu3b2fNmjXcfvvtOkfmvo4cOUJKSkqJz4/g4GASEhKc8ntRFgJ1gLNnz2IymYiMjCyxPzIykr179+oUlXszm81MmDCBzp0707x5c73DcTtffPEFW7duZdOmTXqH4tYOHz7M7NmzSUxM5F//+hebNm1i/PjxeHl5MWzYML3DcxvPPvssGRkZNG7cGKPRiMlk4j//+Q9DhgzROzS3lZKSAlDq70XLc44kyY5w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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "etas = [0.01, 0.1, 1, 10] # Different gains to iterate over the same control goals\n", - "T = 0.001 # Sampling time\n", - "# A desired task-space value, defined by the problem at hand\n", - "xd = np.array([0.1,\n", - " 0.1,\n", - " pi/10])\n", - "print(f\"xd = {xd}\")\n", - "\n", - "# Lists to store the value of each control iteration\n", - "x_tilde_norm_list = []\n", - "t_list = []\n", - "u_norm_list = []\n", - "\n", - "# Run the controller again for each gain\n", - "for i in range(0, len(etas)):\n", - " # Define a stop criteria, in this case let's control for 10 seconds\n", - " t = 0 # Current time\n", - " eta = etas[i]\n", - " # Define initial values for the joint positions\n", - " q_0 = 0.0\n", - " q_1 = 0.0\n", - " q_2 = 0.0\n", - " q = np.array([q_0,\n", - " q_1,\n", - " q_2])\n", - " \n", - " x_tilde_norm_list.append([])\n", - " t_list.append([])\n", - " u_norm_list.append([])\n", - "\n", - " while t < 10:\n", - " # Calculate task-space value, x\n", - " x = planar_robot_prr_fkm(q)\n", - " # Calculate task-space error, x_tilde\n", - " x_tilde = get_error(x, xd)\n", - " # Get the Jacobian\n", - " J = planar_robot_prr_jacobian(q)\n", - " # Invert the Jacobian using the damped pseudo-inverse\n", - " J_inv = damped_pseudo_inverse(J)\n", - " # Calculate the control action\n", - " u = -eta * J_inv @ x_tilde\n", - " \n", - " ## Store values in the list so that we can print them later\n", - " x_tilde_norm_list[i].append(np.linalg.norm(x_tilde))\n", - " t_list[i].append(t)\n", - " u_norm_list[i].append(np.linalg.norm(u))\n", - "\n", - " ## Variable updated for the next loop\n", - " q = q + u * T # Update law using the sampling time\n", - " t = t + T \n", - "\n", - "\n", - " plt.plot(t_list[i],x_tilde_norm_list[i], label=f\"$\\\\eta$={eta}\")\n", - "\n", - "plt.title('(PRR) Error exponential decay visualization for multiple $\\\\eta$')\n", - "plt.legend(loc=\"upper right\")\n", - "plt.xlabel(\"Time [s]\")\n", - "plt.ylabel(\"$||\\\\tilde{ \\\\bf{x} } (t) ||$\")\n", - "plt.show()" - ] - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "# Exercise\n", - "\n", - "Consider the `PRR` solution above as a solved exercise.\n", - "\n", - "# Suggested exercises\n", - "\n", - "Try to modify the code above to calculate the control action for a:\n", - "\n", - "1. `PP` robot\n", - "2. `RP` robot\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "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.12.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} \ No newline at end of file diff --git a/unstable/lesson5_tutorial.md b/basic_lessons/lesson5_tutorial.md similarity index 97% rename from unstable/lesson5_tutorial.md rename to basic_lessons/lesson5_tutorial.md index 77f3f4a..dd87a36 100644 --- a/unstable/lesson5_tutorial.md +++ b/basic_lessons/lesson5_tutorial.md @@ -4,9 +4,23 @@ kernelspec: display_name: 'Python 3' --- +# L5 Kinematic Control + +*License: CC-BY-NC-SA 4.0* + +*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)* + +## Prerequisites for the learner +The user of this notebook is expected to have prior knowledge in +- All the content and prerequisites of lessons 1, 2, 3, and 4. + +## I found an issue +Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues + # Package installation ````{code-cell} +%%capture %pip install numpy matplotlib ```` diff --git a/convert_to_myst.py b/convert_to_myst.py deleted file mode 100644 index e1f3777..0000000 --- a/convert_to_myst.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python3 -"""Convert Jupyter notebooks (.ipynb) to MyST text notebooks (.md). - -Each code cell becomes a ````{code-cell}```` directive. -Markdown cells are preserved as-is. -Raw cells and latex macro cells are removed (handled by myst.yml). -""" - -import json -import re -import sys -from pathlib import Path - - -def _join_source(source): - """Join cell source lines, ensuring proper newlines between them. - - Handles both formats: - - ["line1\n", "line2\n"] (original ipynb format) - - ["line1", "line2"] (json.dump re-saved without trailing newlines) - """ - if isinstance(source, str): - return source - parts = list(source) - if not parts: - return "" - # Check if lines already have trailing newlines - if parts and parts[0].endswith("\n"): - return "".join(parts) - # No trailing newlines — join with \n and add one at the end - return "\n".join(parts) + "\n" - - -def notebook_to_myst(nb_path: Path, output_path: Path, title_prefix: str = ""): - """Convert a single notebook to a MyST text notebook.""" - with open(nb_path) as f: - nb = json.load(f) - - lines: list[str] = [] - - # Frontmatter - lines.append("---") - lines.append("kernelspec:") - lines.append(" name: python3") - lines.append(" display_name: 'Python 3'") - lines.append("---") - lines.append("") - - for cell in nb["cells"]: - cell_type = cell["cell_type"] - source = _join_source(cell["source"]) - - if not source.strip(): - continue - - # Skip raw cells - if cell_type == "raw": - continue - - # Skip latex macro definition cells - lower_src = source.lower().strip() - if "providecommand" in lower_src and ("myvec" in lower_src or "mymatrix" in lower_src): - continue - - if cell_type == "markdown": - # Fix ipynb attachment syntax: ![img](attachment:img.png) -> ![img](img.png) - fixed = re.sub( - r'!\[(.*?)\]\(attachment:(.*?)\)', - r'![\1](\2)', - source, - ) - lines.append(fixed.rstrip("\n")) - lines.append("") - - elif cell_type == "code": - code = source.rstrip("\n") - lines.append("````{code-cell}") - lines.append(code) - lines.append("````") - lines.append("") - - # Remove trailing blank lines but keep one - while len(lines) > 1 and not lines[-1].strip(): - lines.pop() - lines.append("") - - output_path.write_text("\n".join(lines), encoding="utf-8") - print(f" {nb_path} -> {output_path}") - - -def main(): - base = Path(__file__).parent - src_dir = base / "basic_lessons" - dst_dir = base / "unstable" - dst_dir.mkdir(exist_ok=True) - - # Copy images - for img in src_dir.glob("*.*"): - if img.suffix.lower() in (".png", ".svg"): - dst = dst_dir / img.name - dst.write_bytes(img.read_bytes()) - print(f" Copied {img.name}") - - # Convert tutorial notebooks - tutorials = [ - "lesson1_tutorial.ipynb", - "lesson2_tutorial.ipynb", - "lesson3_tutorial.ipynb", - "lesson4_tutorial.ipynb", - "lesson5_tutorial.ipynb", - ] - - exercise_answers = [ - "lesson1_exercise_answers.ipynb", - "lesson2_exercise_answers.ipynb", - "lesson3_exercise_answers.ipynb", - "lesson4_exercise_answers.ipynb", - "lesson5_exercise_answers.ipynb", - ] - - print("Converting tutorials...") - for nb in tutorials: - src = src_dir / nb - dst = dst_dir / nb.replace(".ipynb", ".md") - notebook_to_myst(src, dst) - - print("\nConverting exercise answers...") - for nb in exercise_answers: - src = src_dir / nb - dst = dst_dir / nb.replace(".ipynb", ".md") - notebook_to_myst(src, dst) - - print("\nDone.") - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/myst.yml b/myst.yml index c66bb04..ca841ee 100644 --- a/myst.yml +++ b/myst.yml @@ -32,6 +32,7 @@ project: toc: - file: README.md - file: basic_lessons/README.md + - file: basic_lessons/lesson0_tutorial.md - file: basic_lessons/lesson1_tutorial.ipynb - file: basic_lessons/lesson2_tutorial.ipynb - file: basic_lessons/lesson3_tutorial.ipynb @@ -46,20 +47,6 @@ project: - file: book.md - file: CHANGELOG.md - file: TODO.md - - title: "Unstable" - children: - - file: unstable/README.md - - file: unstable/lesson0_tutorial.ipynb - - file: unstable/lesson1_tutorial.ipynb - - file: unstable/lesson2_tutorial.ipynb - - file: unstable/lesson3_tutorial.ipynb - - file: unstable/lesson4_tutorial.ipynb - - file: unstable/lesson5_tutorial.ipynb - - file: unstable/lesson1_exercise_answers.ipynb - - file: unstable/lesson2_exercise_answers.ipynb - - file: unstable/lesson3_exercise_answers.ipynb - - file: unstable/lesson4_exercise_answers.ipynb - - file: unstable/lesson5_exercise_answers.ipynb site: template: book-theme diff --git a/unstable/.gitignore b/unstable/.gitignore deleted file mode 100644 index 0cdbc71..0000000 --- a/unstable/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# MyST build artifacts -_build/ - -# Generated .ipynb files (converted from .md at build time via jupytext) -*.ipynb \ No newline at end of file diff --git a/unstable/Lesson4.png b/unstable/Lesson4.png deleted file mode 100644 index 4ca25c7..0000000 Binary files a/unstable/Lesson4.png and /dev/null differ diff --git a/unstable/Lesson4.svg b/unstable/Lesson4.svg deleted file mode 100644 index b5df4c6..0000000 --- a/unstable/Lesson4.svg +++ /dev/null @@ -1,290 +0,0 @@ - - - - diff --git a/unstable/README.md b/unstable/README.md deleted file mode 100644 index 33f22cb..0000000 --- a/unstable/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# [WIP] The Basics of Kinematic Modeling and Control of Serial-link Manipulators Using `numpy` - -> **Warning:** These are text-based (MyST) notebooks under active development. The canonical `.ipynb` versions remain in [`basic_lessons/`](../basic_lessons/). - -This directory contains the same five-lesson tutorial as [`basic_lessons/`](../basic_lessons/) but converted to -[MyST text notebooks](https://mystmd.org/guide/notebooks-with-markdown). The content is identical; only the file format -has changed from `.ipynb` to `.md` with `{code-cell}` directives. - -## Contents - -| Number | Title and Link | Content | -|--------|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| 0 | [](./lesson0_tutorial.md) | Setting up the virtual environment and installing all required dependencies. | -| 1 | [](./lesson1_tutorial.md) | Basic operations in Python and `numpy` | -| 2 | [](./lesson2_tutorial.md) | Learn about elements and operations in $\mathbb{R}^n$, $SO(n)$, and $SE(n)$ with $n\in{\{2,3\}}$ related to positions, orientations, and poses, respectively. | -| 3 | [](./lesson3_tutorial.md) | Learn about the composition of rigid body motion in series to obtain the forward kinematics model of a robotic manipulator. | -| 4 | [](./lesson4_tutorial.md) | Learn about the first-order differential mapping $\dot{\myvec{x}}=\mymatrix{J}\dot{\myvec{q}}$ through the calculation of the Jacobian $\mymatrix{J}$. | -| 5 | [](./lesson5_tutorial.md) | Employ the previous knowledge in all previous lessons to employ a Lyapunov-stable control law to move a manipulator in task space using configuration-space signals. | - -### Exercise Answers - -| Lesson | Link | -|--------|------| -| L1 | [](./lesson1_exercise_answers.md) | -| L2 | [](./lesson2_exercise_answers.md) | -| L3 | [](./lesson3_exercise_answers.md) | -| L4 | [](./lesson4_exercise_answers.md) | -| L5 | [](./lesson5_exercise_answers.md) | \ No newline at end of file