Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 69 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/rvc3python.svg)
[![Downloads](https://static.pepy.tech/badge/rvc3python/month)](https://pepy.tech/projects/rvc3python)

> [!NOTE]
> **Actively maintained — August 2026.** Every chapter notebook, the CLI
> tools (`rvctool`, `bdsim_path`, `rvc3-model`), and the packaging have
> been re-verified against current RTB/MVTB/SMTB/bdsim releases and fixed
> where they'd drifted. See [`errata.md`](errata.md) for the full list of
> what changed and why.

<table style="border:0px">
<tr style="border:0px">
<td style="border:0px">
Expand Down Expand Up @@ -61,6 +68,12 @@ This is a quick, non-interactive check that prints package versions and exercise
real code path per toolbox (RTB, MVTB, spatialgeometry, spatialmath, bdsim, and Open3D
if installed), reporting PASS/FAIL for each rather than just "it imported".

> [!NOTE]
> `pip`/`conda install` gives you the importable support code only. Jupyter
> notebooks, figure-generation scripts, and example data live in this
> GitHub repo — see [Additional book resources](#additional-book-resources)
> below, or just `git clone` now.

### Python version

`rvc3python` requires **Python 3.10 or later**.
Expand Down Expand Up @@ -100,6 +113,26 @@ or
```shell
conda install rvc3python
```

## Additional book resources

<img src="https://github.com/petercorke/RVC3-python/raw/main/doc/frontcover.png" alt="Front cover 978-3-031-06468-5_5208" width="100">

This GitHub repo provides additional resources for readers including:
- Jupyter notebooks containing all code lines from each chapter, see
the [`notebooks`](notebooks) folder
- The code to produce every Python/Matplotlib (2D) figure in the book, see the [`figures`](figures) folder
- 3D points clouds from chapter 14, and the code to create them, see
the [`figures/pointclouds`](figures/pointclouds) folder.
- 3D figures from chapters 2-3, 7-9, and the code to create them, see the [`figures/3d`](figures/3d) folder.
- All example scripts, see the [`RVC3/examples`](RVC3/examples) folder.
- To run the visual odometry example in Sect. 14.8.3 you need to download two image sequence, each over 100MB, [see the instructions here](https://github.com/petercorke/machinevision-toolbox-python/blob/main/packages/mvtb-data/README.md#install-really-big-image-files).

To get that material you must clone the repo
```shell
git clone https://github.com/petercorke/RVC3-python.git
```

## Using the Toolboxes

The simplest way to get going is to use the command line tool
Expand Down Expand Up @@ -140,7 +173,7 @@ Results of assignments will be displayed, use trailing ; to suppress

Default numeric formatting: %.3g

>>>
RVC3 >>>
```

This provides an interactive Python
Expand All @@ -152,7 +185,7 @@ For example to load an ETS model of a Panda robot, solve a forward kinematics
and inverse kinematics problem, and an interactive graphical display is simply:

```python
>>> panda = models.ETS.Panda()
RVC3 >>> panda = models.ETS.Panda()
ERobot: Panda (by Franka Emika), 7 joints (RRRRRRR)
┌─────┬───────┬───────┬────────┬─────────────────────────────────────────────┐
│link │ link │ joint │ parent │ ETS: parent to link │
Expand All @@ -174,32 +207,32 @@ ERobot: Panda (by Franka Emika), 7 joints (RRRRRRR)
│ qz │ 0° │ 0° │ 0° │ 0° │ 0° │ 0° │ 0° │
└─────┴─────┴────────┴─────┴───────┴─────┴───────┴──────┘

>>> panda.fkine(panda.qz)
RVC3 >>> panda.fkine(panda.qz)
0.7071 0.7071 0 0.088
0.7071 -0.7071 0 0
0 0 -1 0.823
0 0 0 1
>>> panda.ikine_LM(SE3.Trans(0.4, 0.5, 0.2) * SE3.Ry(pi/2))
RVC3 >>> panda.ikine_LM(SE3.Trans(0.4, 0.5, 0.2) * SE3.Ry(pi/2))
IKSolution(q=array([ -1.849, -2.576, -2.914, 1.22, -1.587, 2.056, -1.013]), success=True, iterations=13, searches=1, residual=3.3549072615799585e-10, reason='Success')
>>> panda.teach(panda.qz)
RVC3 >>> panda.teach(panda.qz)
```
![](https://github.com/petercorke/RVC3-python/raw/main/doc/panda_noodle.png)

Computer vision is just as easy. For example, we can import an image, blur it
and display it alongside the original
```python
>>> mona = Image.Read("monalisa.png")
>>> Image.Hstack([mona, mona.smooth(sigma=5)]).disp()
RVC3 >>> mona = Image.Read("monalisa.png")
RVC3 >>> Image.Hstack([mona, mona.smooth(sigma=5)]).disp()
```
![](https://github.com/petercorke/machinevision-toolbox-python/raw/main/docs/figs/mona%2Bsmooth.png)

or load two images of the same scene, compute SIFT features and display putative
matches
```python
>>> sf1 = Image.Read("eiffel-1.png", mono=True).SIFT()
>>> sf2 = Image.Read("eiffel-2.png", mono=True).SIFT()
>>> matches = sf1.match(sf2)
>>> matches.subset(100).plot("w")
RVC3 >>> sf1 = Image.Read("eiffel-1.png", mono=True).SIFT()
RVC3 >>> sf2 = Image.Read("eiffel-2.png", mono=True).SIFT()
RVC3 >>> matches = sf1.match(sf2)
RVC3 >>> matches.subset(100).plot("w")
```
![](https://github.com/petercorke/machinevision-toolbox-python/raw/main/docs/figs/matching.png)

Expand All @@ -209,8 +242,10 @@ matches
package prefixes
- results are displayed by default like MATLAB does, and like MATLAB you need to
put a semicolon on the end of the line to prevent this
- the prompt is the standard Python REPL prompt `>>>` rather than the IPython
prompt, this can be overridden by a command-line switch
- the prompt is `RVC3 >>> ` by default, distinct from a plain Python or
IPython prompt so a transcript is recognisable at a glance; override it
with `--prompt`, or pass `--book` to match the book's printed transcripts
exactly (plain `>>> `, no `Out[N]:` labels, no ANSI matrix colouring)
- allows cutting and pasting in lines from the book, and prompt characters are
ignored

Expand Down Expand Up @@ -251,7 +286,7 @@ IKSolution(q=array([7.235e-08, -0.8335, 0.09396, 3.142, 0.8312, -3.142]
array([7.235e-08, -0.8335, 0.09396, 3.142, 0.8312, -3.142])
PyPlot3D backend, t = 0.05, scene:
robot: Text(0.0, 0.0, 'Puma 560')
>>>
RVC3 >>>
```
and you are dropped into an IPython session after the script has run.

Expand All @@ -273,7 +308,7 @@ Additional command line tools available (from the Robotics Toolbox) include:
- `twistdemo`, Swift visualization that lets you experiment with 3D twists. The screw axis is the blue rod and you can
position and orient it using the sliders, and adjust its pitch. Then apply a rotation
about the screw using the bottom slider.
# Block diagram models
## Block diagram models

<a href="https://github.com/petercorke/bdsim"><img
src="https://github.com/petercorke/bdsim/raw/main/docs/figs/bdsim_logo.png"
Expand All @@ -288,37 +323,22 @@ included. To simulate these models we use the Python package
- created graphically using `bdedit`, bdsim's graphical editor, and saved as
a `.bd` (JSON format) file.

The models are included in the `RVC3` package when it is installed and `rvctool`
adds them to the module search path. This means you can invoke them from
`rvctool` by
```python
>>> %run -m vloop_test
```

If you want to directly access the folder containing the models, the command
line tool
```shell
bdsim_path
```
will display the full path to where they have been installed in the Python
package tree.


# Additional book resources

<img src="https://github.com/petercorke/RVC3-python/raw/main/doc/frontcover.png" alt="Front cover 978-3-031-06468-5_5208" width="100">

This GitHub repo provides additional resources for readers including:
- Jupyter notebooks containing all code lines from each chapter, see
the [`notebooks`](notebooks) folder
- The code to produce every Python/Matplotlib (2D) figure in the book, see the [`figures`](figures) folder
- 3D points clouds from chapter 14, and the code to create them, see
the [`pointclouds`](../pointclouds) folder.
- 3D figures from chapters 2-3, 7-9, and the code to create them, see the [`3dfigures`](../3dfigures) folder.
- All example scripts, see the [`examples`](examples) folder.
- To run the visual odometry example in Sect. 14.8.3 you need to download two image sequence, each over 100MB, [see the instructions here](https://github.com/petercorke/machinevision-toolbox-python/blob/main/packages/mvtb-data/README.md#install-really-big-image-files).

To get that material you must clone the repo
```shell
git clone https://github.com/petercorke/RVC3-python.git
```
The models are included in the `RVC3` package when it is installed. There
are three ways to run one:

- From inside `rvctool` (or any Jupyter notebook), `%run -i` shares the
current namespace, which some models rely on:
```python
RVC3 >>> %run -i vloop_test
```
- From a bare shell, the `rvc3-model` command runs a model directly —
no `rvctool`/Jupyter session needed:
```shell
$ rvc3-model vloop_test
```
Run `rvc3-model` with no arguments to list every model by name.
- To find where the models are installed on disk (e.g. to open a `.py` or
`.bd` file directly in an editor), use `bdsim_path`:
```shell
$ bdsim_path
```
Empty file added RVC3/bin/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions RVC3/bin/bdsim_path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python3

import RVC3.models as models
from pathlib import Path

def main():
print(Path(models.__file__).parent)

if __name__ == "__main__":
main()
42 changes: 42 additions & 0 deletions RVC3/bin/rvc3_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
"""Run a bdsim model script (RVC3/models/<name>.py) directly from the shell.

Usage:
rvc3-model <name> [args...]

Adds RVC3/models to sys.path first, matching how rvctool's %run -i/%run -m
already handle these scripts (some import sibling files, e.g. `from vloop
import vloop, B`), then runs the named script as if it were __main__ so its
`if __name__ == "__main__":` block executes.
"""

import sys
import runpy
from pathlib import Path

import RVC3.models as models


def main() -> None:
models_dir = Path(models.__file__).parent

if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"):
print(__doc__)
print("Available models:")
for f in sorted(models_dir.glob("*.py")):
if f.stem != "__init__":
print(f" {f.stem}")
sys.exit(0)

name = sys.argv[1]
script = models_dir / f"{name}.py"
if not script.exists():
sys.exit(f"rvc3-model: no such model {name!r} (looked in {models_dir})")

sys.path.insert(0, str(models_dir))
sys.argv = [str(script)] + sys.argv[2:]
runpy.run_path(str(script), run_name="__main__")


if __name__ == "__main__":
main()
41 changes: 21 additions & 20 deletions RVC3/bin/rvctool.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def parse_arguments():
parser.add_argument(
"--confirmexit", "-x", default=False, action="store_true", help="confirm exit"
)
parser.add_argument("--prompt", "-p", default=None, help="input prompt")
parser.add_argument("--prompt", "-p", default="RVC3 >>> ", help="input prompt")
parser.add_argument(
"-r",
"--resultprefix",
Expand All @@ -136,17 +136,18 @@ def parse_arguments():
parser.add_argument(
"-a",
"--showassign",
default=False,
default=True,
action="store_true",
help="do not display the result of assignments",
help="display the result of assignments",
)
parser.add_argument(
"-n",
"--normal",
dest="book",
default=True,
action="store_false",
help="use normal ipython settings for prompts and display on assignment",
"--book",
default=False,
action=argparse.BooleanOptionalAction,
help=(
"match the book's printed transcripts exactly: plain '>>> ' prompt, "
"no Out[N]: labels, no ANSI matrix colouring"
),
)
parser.add_argument(
"-R",
Expand All @@ -166,14 +167,17 @@ def parse_arguments():
)
parser.add_argument(
"--ansi",
default=False,
action="store_true",
help="use ANSImatrix to display matrices",
default=True,
action=argparse.BooleanOptionalAction,
help=(
"use ANSImatrix to display matrices -- colour codes can be problematic "
"when copying/pasting terminal output, pass --no-ansi to disable"
),
)
parser.add_argument(
"-e",
"--examples",
default=False,
default=True,
action="store_true",
help="change working directory to shipped examples",
)
Expand Down Expand Up @@ -474,12 +478,10 @@ def main():
)

if args.book:
# set book options
# match the book's printed transcripts exactly
args.resultprefix = ""
args.prompt = ">>> "
args.showassign = True
args.ansi = False
args.examples = True

# setup defaults
np.set_printoptions(
Expand Down Expand Up @@ -546,10 +548,9 @@ def main():

class MyPrompt(Prompts):
def in_prompt_tokens(self, cli=None):
if args.prompt is None:
return super().in_prompt_tokens()
else:
return [(Token.Prompt, args.prompt)]
# args.prompt always has a real value now (default "RVC3 >>> "),
# so this is never falling back to IPython's native In[N]: prompt.
return [(Token.Prompt, args.prompt)]

def out_prompt_tokens(self, cli=None):
if args.resultprefix is None:
Expand Down
Empty file added RVC3/models/__init__.py
Empty file.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ dev = ["pre-commit", "nbstripout"]

rvctool = "RVC3.bin.rvctool:main"
bdsim_path = "RVC3.bin.bdsim_path:main"
rvc3-model = "RVC3.bin.rvc3_model:main"


[build-system]
Expand Down