From 934cea8947d0494749923f68fef7ada2b9376497 Mon Sep 17 00:00:00 2001 From: Peter Corke Date: Wed, 19 Aug 2026 08:59:58 +1000 Subject: [PATCH] docs+feat: getting-going -- fix README discoverability, rvctool defaults, bdsim model CLI access README: - Fix 3 broken links in "Additional book resources" (pointclouds, 3dfigures, examples all pointed at nonexistent top-level folders -- real paths are figures/pointclouds, figures/3d, RVC3/examples). - Move "Additional book resources" up to right after "Installing the package", so "pip install gets you the library, clone the repo for notebooks/figures" isn't buried as the very last section of a 325-line file. - Add a one-line pointer to that section right after the install instructions, and a top-of-file [!NOTE] banner flagging this pass of fixes, linking errata.md. - Rewrite "Block diagram models" to document all three ways to run a model (rvctool %run -i, the new rvc3-model command, bdsim_path to locate the install folder) instead of just one, and fix its own %run -m -> %run -i staleness. rvctool: replace the confusing -n/--normal (dest="book", inverted sense) with a direct --book/--no-book pair. Defaults changed so a plain `rvctool` now gives a nicer interactive experience by default (RVC3 >>> prompt, Out[N]: labels shown, ANSImatrix on, cwd to examples) rather than the old book-print-fidelity defaults; --book now narrowly means "match the printed page exactly" (plain '>>> ', no Out[N]:, no ANSI). Also fixes a real bug: book mode used to overwrite --prompt unconditionally even when explicitly passed, silently breaking the tool's own documented RVCTOOL_OPTIONS example. Removed the now-dead args.prompt is None branch in MyPrompt (prompt always has a real default now). New: RVC3/models/__init__.py, RVC3/bin/__init__.py -- both packages were implicit namespace packages (no __init__.py despite being explicitly listed in pyproject.toml's packages=[...]), which is why bdsim_path.py's own Path(models.__file__) crashed (namespace packages have __file__ = None). Restored bdsim_path.py from UNTRACKED/ (it had existed there, uncommitted, for years -- the pyproject.toml [project.scripts] entry pointing at it has never actually worked in any real install until now). New: rvc3-model command (RVC3/bin/rvc3_model.py) -- runs a named model from RVC3/models/ directly from a bare shell, no rvctool/Jupyter session needed. Adds the models directory to sys.path first so sibling imports some models use (e.g. `from vloop import vloop, B`) still resolve. Co-Authored-By: Claude Sonnet 5 --- README.md | 118 +++++++++++++++++++++++----------------- RVC3/bin/__init__.py | 0 RVC3/bin/bdsim_path.py | 10 ++++ RVC3/bin/rvc3_model.py | 42 ++++++++++++++ RVC3/bin/rvctool.py | 41 +++++++------- RVC3/models/__init__.py | 0 pyproject.toml | 1 + 7 files changed, 143 insertions(+), 69 deletions(-) create mode 100644 RVC3/bin/__init__.py create mode 100644 RVC3/bin/bdsim_path.py create mode 100644 RVC3/bin/rvc3_model.py create mode 100644 RVC3/models/__init__.py diff --git a/README.md b/README.md index 9353af2..1de21c6 100644 --- a/README.md +++ b/README.md @@ -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. +
@@ -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**. @@ -100,6 +113,26 @@ or ```shell conda install rvc3python ``` + +## Additional book resources + +Front cover 978-3-031-06468-5_5208 + +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 @@ -140,7 +173,7 @@ Results of assignments will be displayed, use trailing ; to suppress Default numeric formatting: %.3g ->>> +RVC3 >>> ``` This provides an interactive Python @@ -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 │ @@ -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) @@ -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 @@ -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. @@ -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 >> %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 - -Front cover 978-3-031-06468-5_5208 - -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 + ``` diff --git a/RVC3/bin/__init__.py b/RVC3/bin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/RVC3/bin/bdsim_path.py b/RVC3/bin/bdsim_path.py new file mode 100644 index 0000000..f59cff1 --- /dev/null +++ b/RVC3/bin/bdsim_path.py @@ -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() diff --git a/RVC3/bin/rvc3_model.py b/RVC3/bin/rvc3_model.py new file mode 100644 index 0000000..a79441f --- /dev/null +++ b/RVC3/bin/rvc3_model.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +"""Run a bdsim model script (RVC3/models/.py) directly from the shell. + +Usage: + rvc3-model [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() diff --git a/RVC3/bin/rvctool.py b/RVC3/bin/rvctool.py index 57b0197..7c4a403 100755 --- a/RVC3/bin/rvctool.py +++ b/RVC3/bin/rvctool.py @@ -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", @@ -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", @@ -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", ) @@ -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( @@ -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: diff --git a/RVC3/models/__init__.py b/RVC3/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml index eab80eb..b8ff3bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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]