Skip to content

Commit 6ee46e2

Browse files
Merge main: fix %%capture, section headers, and downloadable notebooks
2 parents 9c7b07f + 2d7e3a9 commit 6ee46e2

14 files changed

Lines changed: 164 additions & 44 deletions

.github/workflows/notebook_to_html.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ jobs:
3333
# Checks out your repository under $GITHUB_WORKSPACE, so your job can access it
3434
- uses: actions/checkout@v4
3535

36+
# Convert basic_lessons/*.md → basic_lessons/*.ipynb so the site provides "Download notebook" buttons
37+
# https://jupytext.readthedocs.io/ — supports md:myst format natively
38+
# Must run BEFORE build so myst/jupyter-book can pick up the generated notebooks
39+
- name: Generate downloadable notebooks
40+
run: |
41+
pip install jupytext
42+
for f in basic_lessons/lesson*_tutorial.md basic_lessons/lesson*_exercise_answers.md; do
43+
[ -f "$f" ] || continue
44+
out="${f%.md}.ipynb"
45+
python -m jupytext --from md:myst --to notebook --output "$out" "$f"
46+
echo "Generated: $out"
47+
done
48+
3649
# Runs a set of commands using the runner's shell
3750
# https://mystmd.org/guide/deployment-github-pages#fn-except-custom-domains
3851
- name: Install dependencies and build page

AGENTS.md

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
| Path | Purpose |
1212
|------|---------|
1313
| `basic_lessons/` | Canonical source: MyST text notebooks (`.md` with `{code-cell}` directives) — 6 tutorials + 5 exercise answer keys |
14+
| `basic_lessons/.gitignore` | Excludes generated `.ipynb` files (produced at build time) |
1415
| `other/` | Supplementary content (e.g. `dqrobotics.md`) |
1516
| `myst.yml` | MyST project config (root): LaTeX macros, TOC, site options |
1617
| `build_html.sh` | Build script for `jupyter-book` |
@@ -52,6 +53,26 @@ x = np.array([1, 2, 3])
5253
- LaTeX equations use inline `$...$` or display `$$...$$` syntax with the `dollarmath` MyST extension enabled in `conf.py`.
5354
- Custom macros (`\myvec`, `\mymatrix`, `\quat`, `\dual`) are defined in `myst.yml` under `project.math`.
5455

56+
### `%%capture` magic
57+
58+
**`%%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.
59+
60+
### Downloadable `.ipynb` from `.md` notebooks
61+
62+
The `basic_lessons/` `.md` files are the canonical source. `.ipynb` files are generated at build time so visitors can download them:
63+
64+
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`.
65+
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.
66+
3. **`basic_lessons/.gitignore`** excludes `.ipynb` so only `.md` is tracked in git.
67+
68+
To generate locally (e.g. for testing):
69+
```bash
70+
pip install jupytext
71+
for f in basic_lessons/lesson*_tutorial.md basic_lessons/lesson*_exercise_answers.md; do
72+
python -m jupytext --from md:myst --to notebook --output "${f%.md}.ipynb" "$f"
73+
done
74+
```
75+
5576
### Image references
5677

5778
- Use relative paths: `![alt](Lesson4.png)` (relative to `basic_lessons/`)
@@ -69,7 +90,7 @@ python3 -m venv venv
6990
source venv/bin/activate
7091

7192
# For MyST text notebook builds:
72-
pip install mystmd jupyter-server ipykernel
93+
pip install mystmd jupyter-server ipykernel jupytext
7394

7495
# For legacy jupyter-book builds:
7596
pip install jupyter-book --pre
@@ -79,6 +100,13 @@ pip install jupyter-book --pre
79100

80101
**jupyter-book build (CI pipeline):**
81102
```bash
103+
# Step 1: Generate .ipynb from .md (required for download buttons)
104+
pip install jupytext
105+
for f in basic_lessons/lesson*_tutorial.md basic_lessons/lesson*_exercise_answers.md; do
106+
python -m jupytext --from md:myst --to notebook --output "${f%.md}.ipynb" "$f"
107+
done
108+
109+
# Step 2: Build the site
82110
chmod +x build_html.sh
83111
./build_html.sh
84112
```
@@ -98,9 +126,10 @@ myst build --html
98126
### CI/CD
99127

100128
The GitHub Actions workflow (`.github/workflows/notebook_to_html.yml`) runs on pushes to `main` and on pull requests:
101-
1. Runs `./build_html.sh` (jupyter-book pipeline)
102-
2. Uploads `_build/html/` as Pages artifact
103-
3. Deploys to GitHub Pages
129+
1. Generates `.ipynb` from `.md` using jupytext
130+
2. Runs `./build_html.sh` (jupyter-book pipeline)
131+
3. Uploads `_build/html/` as Pages artifact
132+
4. Deploys to GitHub Pages
104133

105134
**Timeout:** 5 minutes. Keep cells fast to avoid CI failures.
106135

@@ -149,6 +178,7 @@ Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooks
149178
### Files excluded from version control:
150179
- `venv/` — Python virtual environment
151180
- `_build/` — Build artifacts
181+
- `basic_lessons/*.ipynb` — Generated at build time from `.md` files
152182

153183
---
154184

@@ -158,7 +188,8 @@ Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooks
158188
2. Add YAML frontmatter with kernelspec at the top of the file
159189
3. Follow the header format convention above
160190
4. Use `{code-cell}` directives for Python code blocks
161-
5. Update `myst.yml` → add new file(s) to `project.toc` list
162-
6. Update `basic_lessons/README.md` → add the new lesson to the contents table
163-
7. Test: `./build_html.sh` from the repository root
164-
8. Open PR with descriptive title and body
191+
5. Use `%%capture` on `%pip install` cells to suppress output
192+
6. Update `myst.yml` — add new file(s) to `project.toc` list as `.ipynb` (generated at build time)
193+
7. Update `basic_lessons/README.md` — add the new lesson to the contents table
194+
8. Test: `./build_html.sh` from the repository root
195+
9. Open PR with descriptive title and body

basic_lessons/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Generated .ipynb from .md (for downloadable notebooks)
2+
*.ipynb

basic_lessons/lesson1_exercise_answers.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ kernelspec:
1010

1111
*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*
1212

13-
### I found an issue
13+
## I found an issue
1414
Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues
1515

16-
### Latex Macros
1716

1817
# Valid imports
1918

basic_lessons/lesson1_tutorial.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,17 @@ kernelspec:
1010

1111
*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*
1212

13-
### Prerequisites
13+
## Prerequisites
1414
The user of this notebook is expected to have prior knowledge in
1515
- Basic Python [[Tutorial]](https://docs.python.org/3/tutorial/index.html)
1616
- Numpy
1717
- [[Tutorial: basics for beginners]](https://numpy.org/doc/stable/user/absolute_beginners.html)
1818
- [[Tutorial: for MATLAB users]](https://numpy.org/doc/stable/user/numpy-for-matlab-users.html)
1919
- Jupyter Notebook Basics [[Tutorial]](https://docs.jupyter.org/en/latest/)
2020

21-
### I found an issue
21+
## I found an issue
2222
Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues
2323

24-
### Latex Macros
25-
26-
# A quick Python refresher
27-
2824
## Variable assignment
2925

3026
Let
@@ -183,8 +179,8 @@ print(f't_phi={t_phi}')
183179
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.
184180

185181
````{code-cell}
182+
%%capture
186183
%pip install numpy
187-
%pip install numpy --break-system-packages
188184
````
189185

190186
### Importing the library

basic_lessons/lesson2_exercise_answers.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ kernelspec:
1010

1111
*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*
1212

13-
### I found an issue
13+
## I found an issue
1414
Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues
1515

16-
### Latex Macros
1716

1817
# Valid imports
1918

basic_lessons/lesson2_tutorial.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@ The user of this notebook is expected to have prior knowledge in
1717
## I found an issue
1818
Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues
1919

20-
## Latex Macros
2120

2221
# Installing prerequisites
2322

2423
````{code-cell}
24+
%%capture
2525
%pip install numpy
26-
%pip install numpy --break-system-packages
2726
````
2827

2928
# Imports

basic_lessons/lesson3_exercise_answers.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ kernelspec:
1010

1111
*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*
1212

13-
### I found an issue
13+
## I found an issue
1414
Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues
1515

16-
### Latex Macros
1716

1817
# Valid imports
1918

basic_lessons/lesson3_tutorial.md

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,69 @@ kernelspec:
44
display_name: 'Python 3'
55
---
66

7-
# Prerequisites
7+
# L3 Forward Kinematics
8+
9+
*License: CC-BY-NC-SA 4.0*
10+
11+
*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*
12+
13+
## Prerequisites for the learner
14+
The user of this notebook is expected to have prior knowledge in
15+
- All the content and prerequisites of lessons 1 and 2.
16+
17+
## I found an issue
18+
Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues
19+
20+
## Package installation
821

922
````{code-cell}
23+
%%capture
1024
%pip install numpy
11-
%pip install numpy --break-system-packages
1225
````
1326

14-
# Imports
27+
## Imports
1528

1629
````{code-cell}
1730
import numpy as np
1831
from math import pi, sin, cos
1932
````
2033

21-
# 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) =\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.
34+
# Forward Kinematics Model (FKM)
35+
36+
The forward kinematics model of a rigid serial-link manipulator is obtained through a sequence of transformations.
37+
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.
38+
Anyway, we can start with an example. As always, remember that angles are in radians and lengths are in meters.
39+
40+
![Lesson4.png](Lesson4.png)
41+
42+
Consider the 2-DoF planar robot shown in the figure. It is classed as an RR robot, because the two joints are revolute.
43+
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.
44+
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.
45+
46+
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.
47+
48+
$$\mymatrix{H}^{0}_{2}( q_0, l_{0},q_1,l_{1}) \in SE(2).$$
49+
50+
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.
51+
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.
52+
53+
## Understanding the problem
54+
55+
The 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.
56+
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.
57+
58+
1. A rotation of $q_0$ about the current frame, from $\mathcal{F}_0$ to $\mathcal{F}_{0'}$.
59+
2. A translation of $l_0$ along the $x$-axis of the current frame, from $\mathcal{F}_{0'}$ to $\mathcal{F}_{1}$.
60+
3. A rotation of $q_1$ about the current frame, from $\mathcal{F}_{1}$ to $\mathcal{F}_{1'}$.
61+
4. A translation of $l_1$ along the $x$-axis of the current frame, from $\mathcal{F}_{1'}$ to $\mathcal{F}_{2}$.
62+
63+
### 1. From $\mathcal{F}_0$ to $\mathcal{F}_{0'}$
64+
65+
We start with the rotation that can be described by the following homogeneous transformation matrix.
66+
67+
$$\myvec H_{0'}^{0}\left(q_0\right) =\begin{bmatrix} \cos(q_0) & -\sin(q_0) & 0\\\sin(q_0) & \cos(q_0) & 0\\0 & 0 & 1\end{bmatrix}.$$
68+
69+
Programmatically, supposing that $q_0 = \frac{\pi}{4}$, we arrive at the following piece of code.
2270

2371
````{code-cell}
2472
H_0_0p = np.array(

basic_lessons/lesson4_exercise_answers.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ kernelspec:
1010

1111
*Author: Murilo M. Marinho (murilo.marinho@manchester.ac.uk)*
1212

13-
### I found an issue
13+
## I found an issue
1414
Thank you! Please report it at https://github.com/MarinhoLab/OpenExecutableBooksRobotics/issues
1515

16-
### Latex Macros
1716

1817
# Valid imports
1918

0 commit comments

Comments
 (0)