Humanoid Path Planner Documentation
A motion planning toolkit for kinematic chains evolving among obstacles — from industrial robot arms to full humanoids.
Introduction
HPP is a C++ Software Developement Kit implementing path planning for kinematic chains in environments cluttered with obstacles. Collision checking is performed by a modified version of the Flexible Collision Library developed at University of North Carolina. Robots can be loaded from URDF model. It is a collection of software packages handled by cmake and pkg-config.
Why HPP?
HPP is not a toy planner: it is built to handle the kind of complex, contact-rich motion planning problems found in real robotics applications.
- Built for complex kinematic chains — from single manipulator arms to full humanoids and multi-robot systems.
- Manipulation planning out of the box — hpp-manipulation handles grasping, regrasping, and multi-contact scenarios, not just collision-free transit paths.
- Fast, reliable collision checking — powered by a modified Flexible Collision Library (coal) under hpp-pinocchio.
- Python-first workflow — define scenes, robots, and planning problems from simple Python scripts via hpp-python, with the heavy algorithmic lifting handled in C++.
- Flexible visualization — watch your robot plan and move in a web browser with viser, or plug into your existing ROS/ROS2 setup with rviz2 or gazebo.
- Battle-tested on real industrial use cases — surface treatment, welding, and assembly tasks, as shown below.
Applications
HPP is already used to plan motions for real industrial robotic tasks — here are a few examples in action.
Surface treatment
Planning a tool path to sweep and abrade the surface of a cylinder, while avoiding self-collisions and obstacles in the workspace.
Welding
Planning collision-free trajectories for a welding tool around complex parts.
Assembly / construction
Planning manipulation sequences to assemble a structure piece by piece, combining grasping, regrasping, and placement.
Overview of the architecture
flowchart TB
HPPY["hpp-python"]
subgraph HPP_STACK["HPP stack"]
direction TB
HM["hpp-manipulation"]
HC["hpp-core"]
HCONS["hpp-constraints"]
HPIN["hpp-pinocchio"]
HM --> HC
HC --> HCONS
HCONS --> HPIN
end
PIN["pinocchio"]
COAL["coal"]
HPIN --> PIN
HPIN --> COAL
HPPY --> HPP_STACK
subgraph HPP_VIZ["HPP Visualization"]
direction TB
VW["Viewer"]
GPV["Gepetto Viewer"]
GV["Graph Viewer"]
VW --> GPV
VW --> GV
end
HPPY --> |import| VW
classDef external fill:#C8E6C9,stroke:#2E7D32;
class PIN,COAL external
The software is composed of C++ libraries implementing the algorithms. Python bindings built on Boost.Python are provided to help users easily define and solve problems. Visualization of the scene can be done in a web browser using viser, or using ROS/ROS2 with rviz2 or gazebo.
The algorithmic part, built on hpp-manipulation is embedded in several Python modules by hpp-python. From a Python script, users can define scenes containing robots and environments, they can also define and solve motion planning problems. Results of path planning requests as well as individual configurations can be displayed in a web browser via package hpp-gepetto-viewer.
Getting started
Package hpp_tutorial provides some examples of how to use this project. Lets start now ! Tutorial
Acknowledgement
Contributors
Thanks to all the contributors of the HPP project:
How to Contribute
Thanks for your interest in contributing to this project! Here are a few simple guidelines to follow.
Reporting a bug
- Check that a similar issue doesn’t already exist in the Issues section.
- Open a new issue describing:
- the expected behavior and the observed behavior,
- steps to reproduce the problem,
- your environment (OS, package version, compiler, Python version…).
Proposing a change (Pull Request)
- Fork the repository, then clone your fork.
- Create a dedicated branch from
devel:git checkout -b my-feature - Make your changes, keeping commits clear and atomic.
- Follow the existing code style of the file you’re modifying (C++ or Python).
- If you add a feature, add or update the corresponding tests.
- Make sure the project builds and the tests pass:
cmake -B build cmake --build build cmake --build build -t test - Push your branch and open a Pull Request against the upstream repository.
- Clearly describe what your PR does and why.
Pre-commit
This project uses prek (a faster, drop-in replacement for pre-commit) to automatically check code formatting and quality before each commit.
- Install
prek(one-time setup): follow the instructions at https://prek.j178.dev/installation/ - Enable the hooks in your local clone:
prek install
- From then on, checks run automatically on every
git commit. You can also run them manually on all files:
prek run --all-files
- If a hook modifies files (auto-formatting), stage those changes and commit again:
git add -u
git commit
The repository also uses pre-commit.ci, so the hooks will automatically be checked on your Pull Request as well.
Commit messages
- Use short, descriptive, imperative-mood messages (e.g.
Fix collision check in hpp-core). - One change = one commit whenever possible.
License
By contributing, you agree that your code will be distributed under the project’s license (see the LICENSE file of the relevant repository).
Questions
For any questions, open an issue or check the documentation at https://humanoid-path-planner.github.io/hpp-doc/
Installation
Choosing the Right Installation Method
| Method | Stable | Requires Compilation | Uses Nix | Recommended For |
|---|---|---|---|---|
| Stable - Binary | ✅ | No | ❌ | Most users |
| Stable - Source | ✅ | Yes | ❌ | Advanced users |
| Stable - Nix Environment (HPP Binary Packages) | ✅ | No | ✅ | Nix users |
| Development - Source | ❌ | Yes | ❌ | Contributors and testers |
| Development - Nix Environment (HPP Sources) | ❌ | Yes | ✅ | HPP developers |
| ROS - Source | ❌ | Yes | ❌ | ROS users |
Binary installation on Ubuntu 24.04 64 bit
To install HPP packages on Ubuntu 24.04 LTS 64 bit, follow these steps.
1. Install basic tools
sudo apt-get install git cmake curl doxygen lsb-release make wget
2. Install robotpkg
Install robotpkg by following the robotpkg installation website.
3. Install HPP
pyver=312
sudo apt-get install robotpkg-py${pyver}-hpp-manipulation-corba \
robotpkg-py${pyver}-qt5-hpp-gepetto-viewer
4. Install optional extra packages for demonstrations
Tutorials
sudo apt-get install robotpkg-py${pyver}-hpp-tutorial \
robotpkg-py${pyver}-qt5-hpp-practicals
GUI
sudo apt-get install robotpkg-py${pyver}-qt5-hpp-gui \
robotpkg-py${pyver}-qt5-hpp-plot
Robot descriptions
sudo apt-get install robotpkg-py${pyver}-hpp-environments \
robotpkg-romeo-description
5. Choose a directory for the documentation
Define the environment variable DEVEL_HPP_DIR with the full path to this directory.
- The documentation will be cloned into
DEVEL_HPP_DIR/install.
It is recommended to set DEVEL_HPP_DIR in your .bashrc for future use.
mkdir -p $DEVEL_HPP_DIR/src
6. Copy configuration files
wget -O $DEVEL_HPP_DIR/config.sh https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/stable/doc/config/ubuntu-24.04.sh
wget -O $DEVEL_HPP_DIR/src/Makefile https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/stable/makefiles/devel.mk
7. Configure the environment
Go to {DEVEL_HPP_DIR}
source config.sh
## 8. Build the documentation
Go to the source directory and install the documentation:
```bash
cd ${DEVEL_HPP_DIR}/src
make hpp-doc.install hpp-practicals.checkout hpp_tutorial.checkout
9. Documentation access
Open:
$DEVEL_HPP_DIR/install/share/doc/hpp-doc/index.html
in a web browser to access the documentation of most HPP packages.
Binary installation on Ubuntu 22.04 64 bit
To install HPP packages on Ubuntu 22.04 LTS 64 bit, follow these steps.
1. Install robotpkg
Install robotpkg by following the robotpkg installation website.
2. Install HPP
pyver=310
sudo apt-get install robotpkg-py<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">h</span><span class="mord mathnormal">pp</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">mani</span><span class="mord mathnormal">p</span><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">i</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">cor</span><span class="mord mathnormal">ba</span><span class="mspace"> </span><span class="mord mathnormal">ro</span><span class="mord mathnormal">b</span><span class="mord mathnormal">o</span><span class="mord mathnormal">tp</span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span>{pyver}-qt5-hpp-gepetto-viewer
3. Install optional extra packages for demonstrations
Tutorials
sudo apt-get install robotpkg-py${pyver}-hpp-tutorial
GUI
sudo apt-get install robotpkg-py${pyver}-qt5-hpp-gui \
robotpkg-py${pyver}-qt5-hpp-plot
Robot descriptions
sudo apt-get install robotpkg-py${pyver}-hpp-environments \
robotpkg-romeo-description
Documentation
sudo apt-get install robotpkg-hpp-doc
4. Setup environment variables
Add the following lines to your .bashrc file (adjust the Python version if necessary):
export PATH=/opt/openrobots/bin<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{PATH}
export LD_LIBRARY_PATH=/opt/openrobots/lib<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal">L</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">L</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.00773em;">BR</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.2222em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{LD_LIBRARY_PATH}
export PYTHONPATH=/opt/openrobots/lib/python3.10/site-packages<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mord mathnormal" style="margin-right:0.13889em;">ONP</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{PYTHONPATH}
export ROS_PACKAGE_PATH=/opt/openrobots/share<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.02778em;">RO</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord mathnormal">A</span><span class="mord mathnormal">G</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{ROS_PACKAGE_PATH}
export CMAKE_PREFIX_PATH=/opt/openrobots<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.10903em;">CM</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">REF</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{CMAKE_PREFIX_PATH}
export PKG_CONFIG_PATH=/opt/openrobots<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.07153em;">C</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">ONF</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord"><span class="mord mathnormal">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{PKG_CONFIG_PATH}
5. Documentation access
Open:
/opt/openrobots/share/doc/hpp-doc/index.html
in a web browser to access the documentation of most HPP packages.
Binary installation on Ubuntu 20.04 64 bit with ROS Noetic
To install HPP packages on Ubuntu 20.04 LTS 64 bit with ROS Noetic, follow these steps.
1. Install ROS Noetic
Install ROS Noetic by following steps 1.1 to 1.3 of the ROS installation website.
2. Install robotpkg
Install robotpkg by following the robotpkg installation website.
3. Install HPP
pyver=38
sudo apt-get install robotpkg-py<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal" style="margin-right:0.02778em;">er</span></span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">h</span><span class="mord mathnormal">pp</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">mani</span><span class="mord mathnormal">p</span><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mord mathnormal">i</span><span class="mord mathnormal">o</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">cor</span><span class="mord mathnormal">ba</span><span class="mspace"> </span><span class="mord mathnormal">ro</span><span class="mord mathnormal">b</span><span class="mord mathnormal">o</span><span class="mord mathnormal">tp</span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mspace" style="margin-right:0.2222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span>{pyver}-qt5-hpp-gepetto-viewer
4. Install optional extra packages for demonstrations
Tutorials
sudo apt-get install robotpkg-py${pyver}-hpp-tutorial
GUI
sudo apt-get install robotpkg-py${pyver}-qt5-hpp-gui \
robotpkg-py${pyver}-qt5-hpp-plot
Robot descriptions
sudo apt-get install ros-noetic-pr2-description \
robotpkg-py${pyver}-hpp-environments \
robotpkg-romeo-description
Documentation
sudo apt-get install robotpkg-hpp-doc
5. Setup environment variables
Add the following lines to your .bashrc file:
source /opt/ros/noetic/setup.bash
export PATH=/opt/openrobots/bin<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{PATH}
export LD_LIBRARY_PATH=/opt/openrobots/lib<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal">L</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">L</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.00773em;">BR</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.2222em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{LD_LIBRARY_PATH}
export PYTHONPATH=/opt/openrobots/lib/python2.7/site-packages<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7778em;vertical-align:-0.0833em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mord mathnormal" style="margin-right:0.13889em;">ONP</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{PYTHONPATH}
export ROS_PACKAGE_PATH=/opt/openrobots/share<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.02778em;">RO</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord mathnormal">A</span><span class="mord mathnormal">G</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{ROS_PACKAGE_PATH}
export CMAKE_PREFIX_PATH=/opt/openrobots<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.10903em;">CM</span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">REF</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.0785em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{CMAKE_PREFIX_PATH}
export PKG_CONFIG_PATH=/opt/openrobots<span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mclose">!</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.07153em;">C</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">ONF</span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord"><span class="mord mathnormal">G</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">A</span><span class="mord mathnormal" style="margin-right:0.13889em;">T</span><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mord">−</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span></span>{PKG_CONFIG_PATH}
6. Documentation access
Open:
/opt/openrobots/share/doc/hpp-doc/index.html
in a web browser to access the documentation of most HPP packages.
Source installation on Ubuntu 24.04 64 bit
To install HPP and its dependencies from source on Ubuntu 24.04 LTS 64 bit, follow these steps.
1. Install robotpkg
Install robotpkg by following the robotpkg installation website.
2. Install dependencies using apt-get
sudo apt-get update && sudo apt-get install \
assimp-utils cmake coinor-libipopt-dev coinor-libipopt1v5 cython3 doxygen \
git ffmpeg gcovr gfortran graphviz libassimp-dev libboost-all-dev \
libbullet-dev libccd-dev libcdd-dev libconsole-bridge-dev libeigen3-dev \
libglpk-dev libgraphviz-dev libgtest-dev liblapack-dev liblog4cxx-dev \
libltdl-dev liboctomap-dev libopencv-dev libpcl-dev libqt5svg5-dev \
libqt5xmlpatterns5-dev libtinyxml2-dev libtinyxml-dev libtool-bin \
liburdfdom-dev liburdfdom-headers-dev libyaml-cpp-dev llvm m4 \
oxygen-icon-theme pkg-config psmisc pyqt5-dev python3-defusedxml \
python3-dev python3-empy python3-gnupg python3-matplotlib python3-venv \
python3-netifaces python3-nose python3-numpy python3-paramiko \
python3-pydot python3-pyqt5 python3-scipy python3-setuptools \
python3-sip-dev python3-sphinx python3-yaml python3-pip python-is-python3 \
qtbase5-private-dev qtmultimedia5-dev texlive-latex-extra wget \
robotpkg-romeo-description robotpkg-py312-eigenpy robotpkg-py312-coal \
robotpkg-py312-pinocchio robotpkg-py312-proxsuite robotpkg-qt5-qgv
3. Choose a development directory
Choose a directory on your filesystem and define the environment variable DEVEL_HPP_DIR with its full path.
- The packages will be cloned into
DEVEL_HPP_DIR/install.
It is recommended to set DEVEL_HPP_DIR in your .bashrc file for future use.
mkdir -p $DEVEL_HPP_DIR/src
4. Copy configuration files
wget -O $DEVEL_HPP_DIR/config.sh https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/stable/doc/config/ubuntu-24.04.sh
wget -O $DEVEL_HPP_DIR/src/Makefile https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/stable/makefiles/stable.mk
5. Configure the environment
Go to DEVEL_HPP_DIR
source config.sh
## 6. Install Python dependencies
Create a Python virtual environment and install the required Python packages:
```bash
python -m venv <span class="katex"><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8333em;vertical-align:-0.15em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.13889em;">NST</span><span class="mord mathnormal">A</span><span class="mord mathnormal">L</span><span class="mord"><span class="mord mathnormal">L</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.13889em;">P</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3283em;"><span style="top:-2.55em;margin-left:-0.1389em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span></span></span></span>INSTALL_PIP_DIR/bin/pip install "numpy==1.26.4" trimesh pycollada viser
7. Build and install the packages
Go to the source directory and build the packages:
cd ${DEVEL_HPP_DIR}/src
make all
8. Documentation access
Open:
$DEVEL_HPP_DIR/install/share/doc/hpp-doc/index.html
in a web browser to access the documentation of most HPP packages.
Binary setup with Nix
To open a Nix development environment with all HPP packages already compiled, follow these steps.
1. Setup direnv (optional but recommended)
Install and configure direnv with nix-direnv.
This step is already done on LAAS computers.
2. Setup the Gepetto Nix binary cache (optional but recommended)
Configure the Gepetto Nix binary cache:
This step is already done on LAAS computers.
3. Activate the HPP binary Nix environment
In the current working directory, create the environment configuration:
echo "use flake github:gepetto/nix#hpp-bin" > .envrc
direnv allow
If you do not want to use nix-direnv, you can alternatively run:
nix develop github:gepetto/nix#hpp-bin
However, this command must be executed manually in each new shell.
Source installation on ubuntu-24.04 64 bit
To install all the packages on ubuntu 24.04 LTS 64 bit, you should do the following steps:
1. Install dependencies
install robotpkg: follow the robotpkg installation website.
2. Install by apt-get
sudo apt-get update && apt-get install \
assimp-utils cmake coinor-libipopt-dev coinor-libipopt1v5 cython3 doxygen \
git ffmpeg gcovr gfortran graphviz libassimp-dev libboost-all-dev \
libbullet-dev libccd-dev libcdd-dev libconsole-bridge-dev libeigen3-dev \
libglpk-dev libgraphviz-dev libgtest-dev liblapack-dev liblog4cxx-dev \
libltdl-dev liboctomap-dev libopencv-dev libpcl-dev libqt5svg5-dev \
libqt5xmlpatterns5-dev libtinyxml2-dev libtinyxml-dev libtool-bin \
liburdfdom-dev liburdfdom-headers-dev libyaml-cpp-dev llvm m4 \
oxygen-icon-theme pkg-config psmisc pyqt5-dev python3-defusedxml \
python3-dev python3-empy python3-gnupg python3-matplotlib python3-venv\
python3-netifaces python3-nose python3-numpy python3-paramiko \
python3-pydot python3-pyqt5 python3-scipy python3-setuptools \
python3-sip-dev python3-sphinx python3-yaml python3-pip python-is-python3 \
qtbase5-private-dev qtmultimedia5-dev texlive-latex-extra wget \
robotpkg-romeo-description robotpkg-py312-eigenpy robotpkg-py312-coal \
robotpkg-py312-pinocchio robotpkg-py312-proxsuite robotpkg-qt5-qgv
3. Choose a directory on your file system
- Define the environment variable
DEVEL_HPP_DIRwith the full path to this directory. - the packages will be cloned into
DEVEL_HPP_DIR/install.
It is recommanded to set variable DEVEL_HPP_DIR in your .bashrc for future use.
mkdir -p $DEVEL_HPP_DIR/src
4. Copy Config and Makefile
wget -O $DEVEL_HPP_DIR/config.sh https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/stable/doc/config/ubuntu-24.04.sh
wget -O $DEVEL_HPP_DIR/src/Makefile https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/stable/makefiles/devel.mk
5. cd into $DEVEL_HPP_DIR and type
cd $DEVEL_HPP_DIR
source config.sh
6. install some dependencies via pip
python -m venv $INSTALL_PIP_DIR
$INSTALL_PIP_DIR/bin/pip install "numpy==1.26.4" trimesh pycollada viser
7. cd into $DEVEL_HPP_DIR/src and type
cd ${DEVEL_HPP_DIR}/src
make all
8. Documentation acces
open $DEVEL_HPP_DIR/install/share/doc/hpp-doc/index.html in a web brower and you will have access to the documentation of most packages.
Source installation with Nix
To compile all HPP packages inside a Nix development environment, follow these steps.
1. Setup direnv (optional but recommended)
Install and configure direnv with nix-direnv.
This step is already done on LAAS computers.
2. Setup the Gepetto Nix binary cache (optional but recommended)
Configure the Gepetto Nix binary cache:
This step is already done on LAAS computers.
3. Choose a development directory
Choose a directory on your filesystem. This directory will be referred to as DEVEL_HPP_DIR.
- The packages will be cloned into
DEVEL_HPP_DIR/install.
Create the directory and enter it:
mkdir -p $DEVEL_HPP_DIR
cd $DEVEL_HPP_DIR
4. Activate the HPP Nix environment
Create the .envrc file:
echo "use flake github:gepetto/nix#hpp" > .envrc
direnv allow
If you do not want to use nix-direnv, you can alternatively run:
nix develop github:gepetto/nix#hpp
However, this command must be executed manually in each new shell.
The Nix environment will define the DEVEL_HPP_DIR environment variable to the current working directory.
5. Get the Makefile
Download the Makefile:
wget -O $DEVEL_HPP_DIR/src/Makefile https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/devel/makefiles/devel.mk
6. Compile all packages
Build all HPP packages:
cd $DEVEL_HPP_DIR/src
make all
ROS — Source
Source installation with ROS
To compile all the packages in a ROS workspace, you can follow these steps:
-
Choose, setup, and activate a ROS distribution: https://www.ros.org/blog/getting-started/
-
Choose a directory on your file system which we will call
DEVEL_HPP_DIR.- the packages will be cloned into
$DEVEL_HPP_DIR/src, - the packages will be installed in
$DEVEL_HPP_DIR/install.
Create that directory and enter inside
- the packages will be cloned into
-
Download our repos file to clone HPP packages with vcs2l:
```bash
mkdir -p $DEVEL_HPP_DIR/src
wget -O $DEVEL_HPP_DIR/hpp.repos https://raw.githubusercontent.com/humanoid-path-planner/hpp-doc/devel/ros/devel.repos
vcs import --input hpp.repos src
```
- Compile all packages with colcon:
```bash
colcon build
```
- Activate the install prefix of the workspace
```bash
source install/setup.bash
```
Tutorial for humanoid path planner platform.
This package provides some tutorials to learn how to use Humanoid Path Planner software. The various tutorials are:
- tutorial 1 How to install and run the software.
- tutorial 2 How to define and solve a simple pick and place problem.
- tutorial 3 How to use HPP in manufacturing.
- tutorial 4 How to control the trajectory of a tool.
- tutorial 5 How to optimize and time-parameterize paths.
- tutorial 6 How to use the rviz2 vizualization.
- tutorial 7 How to execute motions on a simulated robot.
- tutorial 8 Pick and place with gripper, introducing pre and post-actions.
- tutorial 9 A more efficient way to assign pre or post-actions.
Installing the software
This tutorial provides a quick procedure to install the software in docker. For general installation instructions, please visit the project page
Prerequisite
You need a machine running linux with docker installed. See https://docs.docker.com/engine/install/ubuntu for docker installation instructions.
Installing HPP in a docker image
We will build a minimal docker image containing HPP software from binary packages. Then we will run the image in a container that shares a directory with the host machine. Docker will create a user in the container. In order to avoid file ownership conflicts between this user and your account on your machine, we will make them use the same user id and group.
- Create an empty directory on your machine that will be shared by the container and
cdinto this directory. - Download the Dockerfile to build the docker image.
wget https://raw.githubusercontent.com/humanoid-path-planner/hpp_tutorial/refs/heads/devel/tutorial_1/Dockerfile
- Download a lightweight web browser
wget https://github.com/goastian/midori-desktop/releases/download/v11.6/midori_11.6-1_amd64.deb
- Build the docker image
docker build --build-arg DOCKER_USER=`id -u` --build-arg DOCKER_GROUP=`id -g` -t hpp:tuto -f Dockerfile .
- Create directory
src
mkdir src
- get configuration file and compilation file
wget https://raw.githubusercontent.com/humanoid-path-planner/hpp_tutorial/refs/heads/devel/tutorial_1/config.sh
wget -O src/Makefile https://raw.githubusercontent.com/humanoid-path-planner/hpp_tutorial/refs/heads/devel/tutorial_1/Makefile
- Get script that will run docker
wget https://raw.githubusercontent.com/humanoid-path-planner/hpp_tutorial/refs/heads/devel/tutorial_1/run_docker.sh
- Run the container
chmod 775 run_docker.sh
./run_docker.sh
- In the docker container, install a few things.
cd /home/user/devel/src
make all
Everything is now installed. You can now exit the container by typing CTRL-D and proceed to tutorial 2.
Note
The docker container shares the current directory in your host machine with /home/user/devel. As a consequence, if you restart it later, you do not need to redo the previous steps.
Solving a simple pick and place task with HPP
This tutorial will help you defining and solving a simple pick and place task with a franka robot.
Prerequisite
Having installed HPP by following the steps described in tutorial 1.
Resources
The main concepts and theory implemented in HPP software are described in the following paper: https://laas.hal.science/hal-02995125v2.
You can access the C++ online API documentation here
Starting the container and opening new terminals
To open again the container, in the same directory as in tutorial 1, simply run the command
./run_docker.sh
Then in another terminal, type
docker exec -it hpp bash
This will open another bash terminal in the container. You can do this as many times as you want to open new terminals in the container.
In the new terminal, open midori web browser:
midori
Building and displaying a robot
In the first terminal, go into directory hpp_tutorial/tutorial_2 and run the following python script
cd /home/user/devel/src/hpp_tutorial/tutorial_2
python -i init.py
You are now in an interactive python terminal. To display the robot that has been loaded by the script, type
v = Viewer(robot)
v.initViewer(open=False, loadModel=True)
v(q)
Then in midori address bar, type http://localhost:8080. You should see the panda robot.
You can have a quick look at the script to see the instructions used to define the robot.
Adding an obstacle to the scene
In the python terminal, copy-paste the following instructions
urdf_filename = "package://hpp_tutorial/urdf/ground.urdf"
srdf_filename = "package://hpp_tutorial/srdf/ground.srdf"
urdf.loadModel(robot, 0, "ground", "anchor", urdf_filename, srdf_filename, SE3.Identity())
v = Viewer(robot)
v.initViewer(open=False, loadModel=True)
v(q)
Adding an object to the scene
In the python terminal, copy-paste the following instructions
urdf_filename = "package://hpp_tutorial/urdf/box.urdf"
srdf_filename = "package://hpp_tutorial/srdf/box.srdf"
urdf.loadModel(robot, 0, "box", "freeflyer", urdf_filename, srdf_filename, SE3.Identity())
q = neutral(robot.model())
q[7:9] = [0.035, 0.035]
q[9:12] = [.4, -0.2, 0.025]
v = Viewer(robot)
v.initViewer(open=False, loadModel=True)
v(q)
Setting bounds to the object translation
Latter on, we will uniformly sample random configurations. To make it possible, we need to set bounds to the translation of the object.
robot.setJointBounds("box/root_joint", [-1.5, 1.5,
-1.5, 1.5,
-0.2, 1.5,
-float("Inf"), float("Inf"),
-float("Inf"), float("Inf"),
-float("Inf"), float("Inf"),
-float("Inf"), float("Inf")])
The first six values are the minimal and maximal values along x, y, z axes. The eight last values apply to the quaternion coefficients that need not being bounded.
Explaining the code
Let us have a quick look at the code in init.py.
robot = Device("tuto")
This line creates an empty robot implementing
- a
pinocchiomodel for the kinematic chain, - a
pinocchiogeometric model for collision, and - a
pinocchiogeometric model for visual display.
The following lines populate the kinematic chain with a panda robot:
urdf_filename = "package://example-robot-data/robots/panda_description/urdf/panda.urdf"
srdf_filename = "package://hpp_tutorial/srdf/panda.srdf"
urdf.loadModel(robot, 0, "panda", "anchor", urdf_filename, srdf_filename, SE3.Identity())
The arguments of the latter functions are the following:
robot: the kinematic chain to which the new robot will be appended,0: the index of the frame to which the new robot is appended (here the world frame),"anchor": the type of mobility of the new robotbase_link(here the robot is fixed to the environment),urdf_filename: URDF file that describes the new robot,srdf_filename: SRDF file that adds some information about the new robot, like collision pairs, and some information we will explain later on,SE3.Identity()pose of the new robot in the world frame.
The following lines of code retrieve the neutral configuration of the robot (all joint set to 0) and open the gripper of the panda.
# Get neutral configuration of robot
q = neutral(robot.model())
# Open the gripper
q[-2:] = [0.035, 0.035]
Note that adding the ground and a box use the same function. The box is added with “freeflyer” as the mobility type. Therefore, the box is part of the kinematic chain and neutral returns a vector of dimension 16 (9 for the panda, 7 for the box).
Explaining the SRDF files
SRDF follows the xml syntax. Some specific tags are parsed by HPP to add information to the robot and object models. Let us now have a look at the srdf files that are used above by function urdf.loadModel Note that all srdf files used above can be found in the srdf directory of the package.
In file panda.srdf,
<!-- gripper -->
<gripper name="gripper" clearance="0.05">
<position xyz="0 0 0" wxyz="1 0 0 0" />
<link name="panda_hand_tcp"/>
</gripper>
defines a gripper, that is a frame attached to link panda_hand_tcp. The relative pose of the frame with respect to the link is defined by tag position. Attribute xyz defines the translation, attribute wxyz defines the rotation as a unit quaternion with real part in first position.
Attribute clearance will be used later on to define pregrasp configurations.
In file box.srdf,
<handle name="handle" clearance="0.025" approaching_direction="0 0 1">
<position xyz="0 0 0" wxyz="0 0 1 0" />
<link name="base_link"/>
</handle>
defines a handle, that is a frame attached to link base_link. he relative pose of the frame with respect to the link is defined by tag position. Note that the z axis of the handle points downwards when the object is placed on a horizontal contact surface. Tag approaching_direction will be used by used later on by the constraint graph factory to generate pregrasp states.
<contact name="surface">
<link name="base_link"/>
<point>-0.025 -0.025 -0.025 -0.025 0.025 -0.025 0.025 0.025 -0.025 0.025 -0.025 -0.025
</point>
<shape> 4 0 1 2 3</shape>
</contact>
defines a contact surface used to define stable poses of the object. The surface is a plane polygon defined by the vertices (point tag). Here we define 1 polygon with 4 vertices in order 0 1 2 3 (shape tag).
Note that box.srdf also defines a contact surface. The box is in stable contact pose when the contact surfaces are coplanar with opposite normal and the center of the box surface is included in the polygonal surface of the ground.
A quick tour of the viewer
In the upper right corner of the viewer, there is the following window to control the view. We call this window the view controller.
Move the mouse to the icon representing three vertical sliders in the upper right corner, “Configuration and diagnostics” should pop up. Click on the icon and you will see the scene tree. Clicking again brings you back to the initial widget. Select tab “Display” in the upper part of the view controller and select “Show Visuals”, “Show Frames” and “Show Contact Surfaces”. Many frames are displayed, as well as the contact surfaces defined in the SRDF files.
Go again to the scene tree. In the tree, expand “pinocchio” then “frames”, then “panda”. By clicking on the eye in front of each node, you remove the corresponding frame from the view. Remove them all except “panda/gripper” and “box/handle”. You now see the gripper and handle frames that will define how the robot grasps the object as in the picture below.
Defining a manipulation problem
The manipulation problem is defined through a variable of type Problem and through the constraint graph that will be constructed by a factory. Let us define those variables.
from pyhpp.manipulation import (Graph, Problem, ManipulationPlanner)
from pyhpp.manipulation.constraint_graph_factory import ConstraintGraphFactory
problem = Problem(robot)
graph = Graph("robot", robot, problem)
factory = ConstraintGraphFactory(graph)
Later on the graph will solve numerical constraints. We need to set the error threshold and the maximal number of iterations.
graph.maxIterations(40)
graph.errorThreshold(1e-5)
Then, we need to define the set of grippers that will be used.
factory.setGrippers(["panda/gripper"])
We also define the list of objects and for each of them, the list of handles and the list of contact surfaces.
objects = ["box"]
handlesPerObject = [["box/handle"]]
contactsPerObject = [["box/surface"]]
factory.setObjects(objects, handlesPerObject, contactsPerObject)
Finally, we define the set of environment contact surfaces (surfaces on which objects may be placed).
factory.environmentContacts(["ground/surface"])
Then we ask the factory to generate the constraint graph corresponding to the manipulation problem.
factory.generate()
Before initializing the graph, we will add a constraint to all states and transitions in order to keep the gripper open all the time.
import numpy as np
from pyhpp.constraints import (ComparisonType, ComparisonTypes, LockedJoint)
cts = ComparisonTypes()
cts[:] = [ComparisonType.EqualToZero]
lockedFingers = list()
for i in range(2):
lj = LockedJoint(robot, f'panda/panda_finger_joint{i+1}', np.array([0.035]), cts)
lockedFingers.append(lj)
graph.addNumericalConstraintsToGraph(lockedFingers)
graph.initialize()
Displaying the constraint graph
In the python terminal, copy paste the following lines
v.setProblem(problem)
v.setGraph(graph)
In the view controller, click on the button “Show Graph Viewer”. The window below should appear.
This window displays the constraint graph.
If you click on show waypoints, you will see waypoint states as on the picture below. Those intermediate states ease manipulation planning by forcing the robot to approach the object from above and lift it above the ground before moving it. The distance of the gripper to the object in pregrasp state is the sum of the gripper and handle clearances defined in the SRDF files.
By clicking on a state, you can display the constraints of this state. By right clicking on a state, you can select “Generate random config” and figure out what the additional states are meant for. Note that this operation may fail if the numerical solver does not converge and that it does not care for collisions.
Back to the manipulation problem
To define a manipulation problem, we now simply need to set the initial and goal configurations. To do so, we move the robot in a collision-free configuration and change only the pose of the box between those configurations
q_init = np.array([ 0. , 0. , 0. , -0.5 , 0. , 0.5 , 0. , 0.035,
0.035, 0.4 , -0.2 , 0.0251, 0. , 0. , 0. , 1. ])
q_goal = np.array([ 0. , 0. , 0. , -0.5 , 0. , 0.5 , 0. , 0.035,
0.035, 0.4 , 0.2 , 0.0251, 0. , 0. , 0. , 1. ])
You can display these configurations with
v(q_init)
v(q_goal)
Solving the manipulation problem
To define and solve the problem,
from pyhpp.manipulation import ManipulationPlanner
problem.initConfig(q_init)
problem.addGoalConfig(q_goal)
problem.constraintGraph(graph)
manipulationPlanner = ManipulationPlanner(problem)
manipulationPlanner.maxIterations(500)
p = manipulationPlanner.solve()
Displaying the resulting path
You can display the resulting path in the graphical interface by first loading it
v.loadPath(p)
and then by clicking on “Play” in the view controller.
optimizing paths
Random sampling method usually compute paths that are far from being optimal. These paths can be post-processed to make them shorter.
from pyhpp.core import RandomShortcut
optimizer = RandomShortcut(problem)
p1 = optimizer.optimize(p)
How to use HPP in manufacturing.
Prerequisite
Having installed HPP by following the steps described in tutorial 1.
Introduction
In many manufacturing applications, we often need to bring a tool mounted on a robot end effector to a predefined pose with respect to a part. This tutorial shows how to use the same concepts as in tutorial 2 to perform a simplified drilling task.
Initializing the problem
In the docker container, cd into tutorial_3 directory. In a bash terminal, run
python -i init.py
to load the models and initialize the path planning problem. The script is similar to tutorial_2 example, except that
- the robot is a Stäubli TX2-90 holding a drill,
- the object is a vertical square plate,
- a function
display()creates and initializes the viewer client, - a handle is added to the object via python and not via the SRDF file.
The handle is created and added by the following lines
# Add a handle on the plate
R = np.array([[ 0, 0, 1],
[ 0, 1, 0],
[-1, 0, 0]])
T = np.array([0.02, 0, 0])
pose = SE3(rotation = R, translation = T)
robot.addHandle("plate/base_link", "plate/hole", pose, 0.1, 6*[True])
handle = robot.handles()["plate/hole"]
handle.approachingDirection = np.array([0, 0, 1])
the pose of the handle in the link frame is provided by an object of type SE3 from pinocchio module, initialized by a rotation matrix and a translation vector. Note that the link name and the handle names are prefixed by the name of the object that holds the handle: "plate/base_link", "plate/hole". Parameter 0.1 is the handle clearance.
The code above is equivalent to the following lines in an SRDF file:
<handle name="hole" clearance="0.1" approaching_direction="0 0 1">
<position xyz="0.02 0 0" rpy="0 1.5707963267948966 0" />
<link name="base_link"/>
</handle>
Creating waypoint configurations
To plan a drilling motion, we will proceed in several steps:
- generate a “pregrasp” (qpg) and a “grasp” (qg) configurations,
- plan motions between q_init and qpg, then plan a motion between qpg and qg.
For step 1, first copy paste the following code into the python terminal:
# Generate configuration in pregrasp reachable from q_init and in grasp reachable from pregrasp
transition = graph.getTransition("staubli/tooltip > plate/hole | f_01")
pv = transition.pathValidation()
res, qpg, err = graph.generateTargetConfig(transition, q_init, q_init) # -> failure
if not res:
print ("Failed to project q_init to pregrasp waypoint state")
The above code tries to project configuration q_init to the pregrasp waypoint state “staubli/tooltip > plate/hole | f_pregrasp”. Method graph.generateTargetConfig uses a solver containing the constraints of transition “staubli/tooltip > plate/hole | f_01” and of the target state “staubli/tooltip > plate/hole | f_pregrasp”. In this case the constraints are
- Locked joint “plate/root_joint”,
- staubli/tooltip pregrasps plate/hole.
The right hand side of the first one is initialized with q_init (second argument). This simply means that the part shoud be in the same pose as in q_init. The second one is a constraint of relative pose between the gripper and the handle: both frames should have the same orientation and the position of the center of the handle in the gripper frame is the product of the sum of gripper and handle clearances by the approaching direction vector. As state above, the solver is initialized with q_init (third argument). The output of the function is composed of
res:Trueif the solver succeeded,Falseotherwise,qpg: the result configuration or the last iteration of the solver in case of failure,err: the norm of the residual.
Note that projection fails, this does not mean that the constraints have no solution. Initializing the solver with another configuration may succeed.
Copy paste now the code below in the python terminal.
for i in range(1000):
transition = graph.getTransition("staubli/tooltip > plate/hole | f_01")
q = shooter.shoot()
res, qpg, err = graph.generateTargetConfig(transition, q_init, q)
if not res: continue
res, report = pv.validateConfiguration(qpg)
if not res: continue
transition = graph.getTransition("staubli/tooltip > plate/hole | f_12")
res, qg, err = graph.generateTargetConfig(transition, qpg, qpg)
if res: break
# Notice that qg is in collision
res, report = pv.validateConfiguration(qg)
print(report)
The code above tries to generate a pregrasp and a grasp configurations by initializing the pregrasp
solver with a random configuration and the grasp solver with the pregrasp configuration. The pregrasp configuration is tested for collision. If a projection fails or a collision occurs, the loop restart with another random configuration. Note that the grasp configuration is produced by initializing the solver (second call to graph.generateTargetConfig) with the pregrasp configuration. This is necessary to make sure that the latter is close to the former and that the robot does not need a long reconfiguration motion to reach grasp from pregrasp.
You can visualize qpg and qg in the graphical interface as follows.
v = display()
v(q_init)
v(qpg)
v(qg)
Using security margins
In the previous example, the grasp configuration is in collision since the tool is inside the part. We need to deactivate collision checking between the end-effector and the part on the second part of the motion (transition “staubli/tooltip > plate/hole | f_12”). For that, we will use a python class to handle security margins.
A security margin is a distance below which two objects are considered as colliding. By extension,
- a negative security margin means that penetration is allowed
- -Inf security margin means that the object are never considered as colliding.
Path and configurations are checked for collisions by PathValidation instances. Each transition of the constraint graph owns a PathValidation (hpp::core::ContinuousValidation) instance. Security margins can be defined between pairs of joints by a square matrix of size the number of joints. The value in a cell corresponds to the security margin between the joints corresponding to the row and column indices of the cell. the indices are those in the list returned by
robot.getJointNames()
The code below sets security margins between robots (as set of joints). Copy paste the code in the python terminal
# Defining security margins
from pyhpp.manipulation.security_margins import SecurityMargins
sm = SecurityMargins(problem,factory, ["staubli", "plate"], robot)
sm.setSecurityMarginBetween("staubli", "plate", 0.05)
sm.apply()
Then, if you type
M = graph.getSecurityMarginMatrixForTransition(transition)
print(np.array(M))
you should see
[[0. 0. 0. 0. 0. 0. 0. 0. ]
[0. 0. 0. 0. 0. 0. 0. 0.05]
[0. 0. 0. 0. 0. 0. 0. 0.05]
[0. 0. 0. 0. 0. 0. 0. 0.05]
[0. 0. 0. 0. 0. 0. 0. 0.05]
[0. 0. 0. 0. 0. 0. 0. 0.05]
[0. 0. 0. 0. 0. 0. 0. 0.05]
[0. 0.05 0.05 0.05 0.05 0.05 0.05 0. ]]
and notice that between each joint of the robot and the plate, the security margin is 0.05.
The following code deactivates collision checking between the robot end effector and the plate along a transition.
transition = graph.getTransition("staubli/tooltip > plate/hole | f_12")
graph.setSecurityMarginForTransition(transition, "staubli/joint_6", "plate/root_joint",
float("-inf"))
Copy paste this code and display again the security margin matrix.
After modifying the graph, we need to reinitialize it.
graph.initialize()
We can now generate collision free pregrasp and grasp configurations.
# Generate configuration in pregrasp reachable from q_init and in grasp reachable from pregrasp
# and test collision for both.
for i in range(1000):
# Project random configuration on pregrasp waypoint state
transition = graph.getTransition("staubli/tooltip > plate/hole | f_01")
q = shooter.shoot()
res, qpg, err = graph.generateTargetConfig(transition, q_init, q)
if not res: continue
# Check the configuration for collision
pv = transition.pathValidation()
res, report = pv.validateConfiguration(qpg)
if not res: continue
# Project pregrasp configuration on grasp state
transition = graph.getTransition("staubli/tooltip > plate/hole | f_12")
res, qg, err = graph.generateTargetConfig(transition, qpg, qpg)
if not res: continue
# Check the configuration for collision
pv = transition.pathValidation()
res, report = pv.validateConfiguration(qg)
if res: break
You can visualize qpg and qg in the graphical interface.
Planning motions between the waypoint configurations
We now need to plan a motion between q_init and qpg and between qpg and qg, keeping the relevant constraints satisfied. Here the only relevant constraint is that the part should not move. To do so, we will use the TransitionPlanner class. This class plans motions along a transition, keeping the constraints of the transition satisfied. The right hand side of the parameterizable constraints of the transition is initialized with the initial configuration. The code below shows how to use this class.
from pyhpp.manipulation import TransitionPlanner
planner = TransitionPlanner(problem)
planner.maxIterations(1000)
for i in range(10):
# Project random configuration on pregrasp waypoint state
transition = graph.getTransition("staubli/tooltip > plate/hole | f_01")
q = shooter.shoot()
res, qpg, err = graph.generateTargetConfig(transition, q_init, q)
if not res: continue
# Check the configuration for collision
pv = transition.pathValidation()
res, report = pv.validateConfiguration(qpg)
if not res: continue
# plan motion between q_init and qpg
planner.setTransition(transition)
try:
q_goal = np.zeros((robot.configSize(), 1))
q_goal[:,0] = qpg
p1 = planner.computePath(q_init, q_goal, True)
except Exception as exc:
print(f"path planning failed between q_init and qpg: {exc}")
continue
# Project pregrasp configuration on grasp state
transition = graph.getTransition("staubli/tooltip > plate/hole | f_12")
res, qg, err = graph.generateTargetConfig(transition, qpg, qpg)
if not res: continue
# Check the configuration for collision
pv = transition.pathValidation()
res, report = pv.validateConfiguration(qg)
if not res: continue
# plan motion between qpg and qg
planner.setTransition(transition)
try:
q_goal = np.zeros((robot.configSize(), 1))
q_goal[:,0] = qg
p2 = planner.computePath(qpg, q_goal, True)
except Exception as exc:
print(f"path planning failed between qpg and qg: {exc}")
continue
if p2:
p3 = p2.reverse()
break
You can now load paths p1, p2, p3 in the graphical interface and play them.
v.loadPath(p1)
v.loadPath(p2)
v.loadPath(p3)
The drilling path is a little bit naive since the tool trajectory is not a straight line but the result of an interpolation in joint space and the velocities of the robot and tool are not controlled.
Tutorial 4 shows how to better control a tool trajectory.
How to control the trajectory of a tool.
Prerequisite
Having completed tutorial 3
Initializing the problem
In the docker container, cd into tutorial_4 directory. In a bash terminal, run
python -i init.py
The script contains the code of tutorial_3 up to the computation of
a path to qpg. To plan a path between qpg and qg, we first generate a desired trajectory
of the tooltip.
from pyhpp.constraints import (ComparisonType, ComparisonTypes)
gripper = robot.grippers()["staubli/tooltip"]
trajConstraint = handle.createGrasp(gripper, "drilling")
cts = ComparisonTypes()
cts[:] = 6*[ComparisonType.Equality]
trajConstraint.comparisonType(cts)
init = trajConstraint.function()(qpg)
goal = np.array([0,0,0,0,0,0,1])
The code above create a relative pose contraint between the gripper (tooltip) and the handle.
The value of the constraint in SE(3) is the pose of the handle in the frame of the gripper.
init is the value of the function in qpg. As an element of SE(3), it is not a vector.
print(init.space())
As shown in the python terminal, it is an element of R^3^ x SO(3) (equivalent to SE(3)). We can access to the vector representation as follows:
print(init.vector())
As expected, this corresponds to the pose of the handle in the gripper frame in configuration qpg:
a translation of 10cm along z.
See documentation of class hpp::pinocchio::LiegroupSpace for more information.
from pyhpp.manipulation.steering_method import (Cartesian, makePiecewiseLinearTrajectory)
weights = 50*np.ones(6)
points = np.zeros(14).reshape((2,7))
points[0:] = init.vector()
points[1:] = goal
rhs = makePiecewiseLinearTrajectory(points, weights)
The above code creates a straight path in SE(3) from the initial pose of the gripper to the
handle. The duration of the path is tuned by a vector of weights as described in the
documentation of method
hpp::manipulation::steeringMethod::Cartesian::makePiecewiseLinearTrajectory.
cartesian = Cartesian(planner.innerProblem())
cartesian.trajectoryConstraint = trajConstraint
cartesian.setRightHandSide(rhs, True)
res, p2 = cartesian.planPath(qpg)
The trajectory constraint as well as the time-varying right hand side are passed to the
Cartesian steering method and a path is computed.
transition = graph.getTransition("staubli/tooltip > plate/hole | f_12")
pv = transition.pathValidation()
res, p3, report = pv.validate(p2, False)
The path is then tested for collision after setting the relevant security margins.
Tutorial 5 shows how to optimize and time-parameterize paths.
How to optimize and time-parameterize paths.
Prerequisite
Having completed tutorial 4
Initializing the problem
In the docker container, cd into tutorial_5 directory. In a bash terminal, run
python -i init.py
The script contains the code of tutorial 4 with an additional obstacle
placed between the robot and the plate. This forces the planner to find a non-straight path for p1
(the motion from q_init to the pregrasp configuration qpg).
The path p1 uses a dimensionless path parameter s ranging from 0 to p1.length(). This
parameter does not correspond to real time: the robot has no notion of velocity or acceleration
along this path.
Visualizing the raw path
A small helper in plot.py plots joint positions, velocities, and accelerations against the path
parameter. It returns the matplotlib figure so you can inspect it interactively or save it:
from plot import plotTraj
fig = plotTraj(p1, 0, 7, order=2)
fig.show()
The raw path p1 is collision-free but typically jagged, with abrupt direction changes. The
acceleration plot shows large spikes — this is what the rest of this tutorial smooths out.
Path optimization
Before time parameterization we smooth the path with SplineGradientBased_bezier3, which fits a
cubic-Bézier spline that minimizes integral squared acceleration while remaining collision-free:
from pyhpp.core import SplineGradientBased_bezier3
bezier = SplineGradientBased_bezier3(problem)
p2 = bezier.optimize(p1)
print(f"Smoothed path length: {p2.length():.3f} (was {p1.length():.3f})")
The resulting path is continuously differentiable (C1), a prerequisite for producing a smooth velocity profile in the next step.
Time parameterization
TOPPRA
TOPPRA (Time-Optimal Path Parameterization based on Reachability Analysis) computes the
time-optimal parameterization subject to velocity, acceleration, and torque constraints. Applied
directly to the raw path p1, TOPPRA produces endpoint velocity discontinuities and an
acceleration spike at the start. Applied after SplineGradientBased_bezier3, the smoothed
spline eliminates these and keeps accelerations bounded throughout. Note that the acceleration
bounds apply only on selected joints. Below, we select only the robot joints.
import numpy as np
from pyhpp_toppra import Toppra
toppra = Toppra(problem)
toppra.velocityScale = 0.5
toppra.effortScale = -1
toppra.N = 100
toppra.selectJoints([f"staubli/joint_{i}" for i in range(1,7)])
toppra.accelerationLimits = np.array(6 * [0.5])
p3 = toppra.optimize(p2)
print(f"TOPPRA duration: {p3.length():.3f} s")
Parameters:
velocityScale: scaling factor for velocity limits (1.0 = full velocity). Use a small value (e.g. 0.5) for slower, more visible motions.effortScale: scaling factor for torque limits. Set to a negative value to disable torque constraints. Note: torque constraints require mass and inertia data in the robot URDF. The Staubli model has no dynamics data, soeffortScalemust be set to-1(disabled).accelerationLimits: per-DOF acceleration cap. The vector size must match the problem’s velocity dimension, not the configuration size — here it is6(6-DOF Staubli arm).N: minimal number of discretization points along the path.interpolationMethod:"constant_acceleration"or"hermite".gridpointMethod:"param_space"or"time_space".
Compare the profiles after Bézier smoothing and after optimal time parameterization:
fig = plotTraj(p2, 0, 7, order=2)
fig.show()
fig = plotTraj(p3, 0, 7, order=2)
fig.show()
SimpleTimeParameterization (simpler alternative)
When hpp-toppra is not available, SimpleTimeParameterization computes a polynomial time
parameterization that maps real time t to the path parameter s, while respecting joint
velocity and acceleration limits. It is less optimal than TOPPRA but needs no extra dependency.
from pyhpp.core import SimpleTimeParameterization
stp = SimpleTimeParameterization(problem)
stp.order = 2
stp.safety = 0.95
stp.maxAcceleration = 0.5
p_stp = stp.optimize(p2)
print(f"STP duration: {p_stp.length():.3f} s")
Parameters:
order: polynomial continuity order.0= linear (C0),1= cubic (C1, zero velocity at endpoints),2= quintic (C2, zero velocity and acceleration at endpoints).safety: scaling factor for velocity limits (0.95 = use 95% of max velocity).maxAcceleration: maximum acceleration per DOF in rad/s². Only used whenorder >= 2. Set to a negative value to disable.
Visualization
You can visualize the path in the viewer:
v = display()
v.loadPath(p3)
How to use a rviz2 visualization
Prerequisite
Having completed tutorial 2.
Overview
This tutorial shows how to set up an RViz2 visualization for HPP using the RVizVisualizer
from pyhpp_rviz. Unlike the web-based viewer used in tutorials 2–5, this visualizer
communicates over ROS 2 topics and displays the robot, paths, and landmarks directly inside
RViz2.
Setting up the simulation
The base tutorial docker image does not include ROS 2 control packages. Build the extended image from the tutorial 6 directory on the host machine (not inside the container):
cd tutorial_6
docker build --build-arg DOCKER_USER=`id -u` --build-arg DOCKER_GROUP=`id -g` \
-t hpp-ros2:tuto .
Then start the container from the root shared directory:
cd ../../..
./src/hpp_tutorial/tutorial_6/run_docker.sh
Compiling the HPP RViz2 plugins
On your first make all from tutorial 1, the RViz2 plugin sources were notcompiled.
Build hpp-rviz:
cd src
make hpp-rviz.install
export the package path
export ROS_PACKAGE_PATH=/home/user/devel/src/:/opt/openrobots/share/:$ROS_PACKAGE_PATH
Initializing the viewer
In the docker container, cd into tutorial_6 directory and run:
python -i init.py
The script is identical to tutorial 2 up to the computation of path p
The only difference is that it uses RVizVisualizer instead of viser Viewer.
from pyhpp_rviz import RVizVisualizer as Viewer
v = Viewer()
v.initViewer(robot=robot)
Configuring RViz2
Open a second terminal in the container:
docker exec -it hpp bash
rviz2
In RViz2, set the Fixed Frame to world (in the Global Options panel).
Set the Frame Rate to 300
For each model loaded with urdf.loadModel, add a RobotModel display and set its
Description Topic to the topic published for that model (e.g. /panda/robot_description,
/ground/robot_description, /box/robot_description). The prefix matches the name
passed to urdf.loadModel.
Add a TF display to visualize all frame transforms published by the viewer.
Disable TF arrows and put Frame Time Out to 1e+07
There is a rviz config file on hpp_tutorial/launch/tuto6.rviz
rviz2 -d hpp_tutorial/launch/config.rviz
Call v(q_init) in the Python terminal to place all objects in their initial configuration.
The scene should now appear in RViz2.
Visualizing a configuration
v(q_init)
Use v(config) to display a configuration on rviz2 like is done with viser.
Visualizing a path
Add the Trajectory plugin (from the HPP RViz2 plugins) to RViz2. A control panel will appear at the bottom of the screen.
Load a path from the Python terminal:
v.loadPath(path)
The panel lets you slide through the path parameter to inspect any intermediate configuration.
To display the spatial trace of a frame along the path, use:
v.displayPath(path, target_frame="panda/gripper")
You can also trigger this from RViz2 by entering the frame name directly in the DisplayTrajectory panel.
Adding landmarks
Add the Landmark tool from the RViz2 toolbar (installed with the HPP RViz2 plugins). Add the Landmark display to visualize the landmarks in the scene.
Landmarks can be placed in three ways:
-
Interactively: select the Landmark tool in the toolbar, then click in the 3D view. Drag the landmark with the interact tool for moving it or Right-click a landmark marker and choose Edit position to adjust it numerically with the interact tool too
-
From a named frame (Python):
v.addLandmarkFromFrame("panda/gripper", "first landmark")This publishes the current pose of the given frame as a landmark.
-
From explicit coordinates (Python):
v.addLandmark(xyz=[0.8, 0.0, 1.0], quat_xyzw=[0.0, 0.0, 0.0, 1.0], "landmark")
Summary of viewer methods
| Method | Description |
|---|---|
v(q) | Display configuration q |
v.loadPath(p) | Register path p for trajectory control |
v.displayPath(p, target_frame=...) | Publish the spatial trace of a frame along p |
v.addLandmarkFromFrame(frame) | Publish current pose of frame as a landmark |
v.addLandmark(xyz, quat_xyzw) | Publish an explicit pose as a landmark |
v.setProblem(problem) | Register problem for graph viewer |
v.setGraph(graph) | Register constraint graph for graph viewer |
v.launch_graph_viewer() | Open the constraint graph viewer (React app) |
How to execute motions on a simulated robot.
Prerequisite
Having completed tutorial 6.
Overview
This tutorial plans a simple arm motion for the Franka FR3 robot and executes it
on a Gazebo simulation via ROS2. It introduces the hpp_exec package which
bridges HPP paths to ros2_control.
Terminal 1: Launching the simulation
Launch the Gazebo simulation with
a joint_trajectory_controller:
ros2 launch hpp_tutorial tutorial_6_launch.py
Wait until you see Configured and activated joint_trajectory_controller in the
output.
Terminal 2: Planning and executing
Open a second terminal:
docker exec -it hpp bash
Source the environments and run the tutorial script:
cd ~/devel/src/hpp_tutorial/tutorial_6
python -i init.py
The script loads the FR3 robot, plans a motion from the current robot configuration to a goal configuration using BiRRT, optimizes it with RandomShortcut, and applies time parameterization using SimpleTimeParameterization (as seen in tutorial 5).
You can visualize the planned path in the browser viewer:
v = display()
v.loadPath(p_timed)
Understanding the trajectory
After time parameterization, p_timed is a continuous function mapping time (in
seconds) to robot configurations. To send it to ros2_control, we need discrete
waypoints.
Check the trajectory duration:
print(f"Trajectory duration: {p_timed.length():.2f} seconds")
Sample a configuration at a specific time (e.g., t=1.0s):
q, success = p_timed(1.0)
print(f"Config at t=1.0s: {q}") # First 7 values are arm joints
The HPP configuration vector has 9 elements: 7 arm joints + 2 finger joints.
Extracting waypoints
To execute the trajectory, we sample it at regular intervals. Try extracting waypoints yourself:
import numpy as np
n_samples = 50
configs = []
times = []
for i in range(n_samples + 1):
t = (i / n_samples) * p_timed.length()
q, success = p_timed(t)
assert(success)
configs.append(np.array(q))
times.append(t)
print(f"Extracted {len(configs)} waypoints over {times[-1]:.2f} seconds")
Sending the trajectory
Now send the waypoints to Gazebo via ros2_control:
from hpp_exec import send_trajectory
send_trajectory(
configs, times,
joint_names=[f'fr3_joint{i}' for i in range(1, 8)],
joint_indices=list(range(7)),
)
joint_names: The ROS2 joint names expected by the controller.joint_indices: Which elements of the HPP config to send (indices 0-6 are the arm joints; we skip indices 7-8 which are the fingers).
You should see the robot move in Gazebo and Trajectory execution complete in
the terminal.
Experiment
Try different values of n_samples (e.g., 10, 100, 200) and observe how it
affects the smoothness of motion in Gazebo.
You can also play the reverse motion using
p_reversed = p_timed.reverse()
Pick and place with gripper, introducing pre and post-actions
Prerequisite
Having completed tutorial 7.
Overview
Tutorial 6 executed one arm trajectory with send_trajectory. This tutorial
adds the gripper: the robot must open the fingers before approaching the box,
close them before transport, then open them again at the goal.
The script plans a pick-and-place path with an HPP manipulation constraint
graph. We then use hpp_exec to expose the graph segments, attach the Gazebo
actions for this problem, and execute the segments.
For the full hpp_exec API, see the
hpp-exec documentation.
Setting up the simulation
Use the same Docker image as tutorial 6 (hpp-ros2:tuto). If you have not
built it yet, see the tutorial 6 instructions.
Terminal 1: Launching the simulation
Launch Gazebo with the FR3 and its gripper:
ros2 launch hpp_tutorial tutorial_7_launch.py
Wait until you see Configured and activated gripper_controller in the output.
Note: one gripper finger may appear loose in Gazebo. This is a simulation artefact with mimic joints. It does not affect the tutorial.
Terminal 2: Planning
Open a second terminal:
docker exec -it hpp bash
Run the tutorial script:
cd ~/devel/src/hpp_tutorial/tutorial_7
python -i init.py
The script loads the FR3, the ground, and a box. It solves a pick-and-place
problem that moves the box from (0.4, -0.2) to (0.4, 0.2), optimizes the
path, time-parameterizes it with SimpleTimeParameterization.
Note that between optimization and time parameterization, an object called EnforceTransitionSemantic is called. This steps labels each sub-path with the transition of the graph the sub-path belongs to. This step is necessary before executing the path in order to place pre-actions and post-actions at the right times.
You can visualize the planned path in the browser viewer:
v = display()
v.loadPath(p_timed)
Defining gripper actions
Create the actions that will be called during execution:
from hpp_exec import send_trajectory
def attach_box():
attach_pub.publish(Empty())
rclpy.spin_once(gazebo_node, timeout_sec=0.05)
time.sleep(0.2)
gazebo_node.get_logger().info("Published '/box/attach' on Gazebo topic")
return True
def detach_box():
detach_pub.publish(Empty())
rclpy.spin_once(gazebo_node, timeout_sec=0.05)
time.sleep(0.2)
gazebo_node.get_logger().info("Published '/box/detach' on Gazebo topic")
return True
def open_gripper():
return send_trajectory(
[np.array([0.0]), np.array([0.035])],
[0.0, 0.5],
joint_names=GRIPPER_JOINT_NAMES,
controller_topic="/gripper_controller/follow_joint_trajectory",
)
def close_gripper():
return send_trajectory(
[np.array([0.035]), np.array([0.0])],
[0.0, 0.5],
joint_names=GRIPPER_JOINT_NAMES,
controller_topic="/gripper_controller/follow_joint_trajectory",
)
def grasp_box():
return attach_box() and close_gripper()
def release_box():
return open_gripper() and detach_box()
open_gripper and close_gripper send a reference value for
fr3_finger_joint1 to open or close the gripper. They use send_trajectory,
as in tutorial_6. On the real robot, this would be performed by a ROS action
instead.
grasp_box and release_box call attach_box and detach_box respectively.
These functions tell Gazebo that the box is attached to or detached from the
end effector.
At this point the useful objects are:
p_timed: the time-parameterized HPP path.configs: sampled HPP configurations along the timed path.times: timestamps in seconds, returned bysegments_from_graph.segments: graph segments where you can add pre/post actions.graph: the HPP manipulation constraint graph.open_gripper,close_gripper,grasp_box, andrelease_box: Gazebo actions for the gripper and simulated box attachment.
Building execution segments
The planned path contains the approach, transport, and retreat motion in one
path. Ask hpp_exec to sample the timed path and expose the HPP graph
segments:
from hpp_exec import segments_by_transition, print_segments, segments_from_graph
configs, times, segments = segments_from_graph(p_timed, graph)
print_segments(segments)
The table shows the segment times, graph transition names, nominal states, observed states, and how many pre/post actions are attached.
Build a transition-name map and attach the actions to the movements used in this tutorial:
GRASP_TRANSITION = "fr3/gripper > box/handle | f_23"
RELEASE_TRANSITION = "fr3/gripper < box/handle | 0-0_21"
segments_by_name = segments_by_transition(segments)
segments[0].pre_actions.append(open_gripper)
for segment in segments_by_name[GRASP_TRANSITION]:
segment.pre_actions.append(grasp_box)
for segment in segments_by_name[RELEASE_TRANSITION]:
segment.pre_actions.append(release_box)
print_segments(segments)
segments_by_transition is a dictionary that stores the segments by the transition they belong to. This is very convenient to assign pre or post-actions to each segment.
Conceptually, execution has three phases:
| # | Phase | What the arm does | Action before phase |
|---|---|---|---|
| 0 | approach | move above the box, descend | open |
| 1 | transport | carry the box to the goal | attach and close |
| 2 | retreat | lift and return | open and detach |
Executing the segments
Send the arm segments to the arm controller and let the segment actions command the gripper controller:
from hpp_exec import execute_segments
close_gripper()
reset_box_pose()
execute_segments(
segments, configs, times,
joint_names=[f"fr3_joint{i}" for i in range(1, 8)],
joint_indices=list(range(7)),
)
You should see the fingers open, the arm descend, the fingers close on the box, the arm carry the box to the goal, the fingers open, and the arm retreat.
reset_box_pose() detaches the simulated box if needed and places it back at
the planned start pose before execution.
A more efficient way to assign pre or post-actions
Prerequisite
Having completed tutorial 8.
Overview
Tutorial 7 opens the gripper as a blocking pre-action before the approach
motion. This tutorial uses hpp_exec.BackgroundAction to start opening the
gripper in the background, let the arm begin travelling, then wait for the
opening action just before grasping the box.
The planning problem, Gazebo setup, and pick-and-place path are the same as in tutorial 7. Only the execution actions change.
For the full hpp_exec API, see the
hpp-exec documentation.
Setting up the simulation
Use the same Docker image as tutorial 6 (hpp-ros2:tuto). If you have not
built it yet, see the tutorial 6 instructions.
Terminal 1: Launching the simulation
Launch the same FR3 and gripper simulation as tutorial 7:
ros2 launch hpp_tutorial tutorial_7_launch.py
Wait until you see Configured and activated gripper_controller in the output.
Note: one gripper finger may appear loose in Gazebo. This is a simulation artefact with mimic joints. It does not affect the tutorial.
Terminal 2: Planning
Open a second terminal:
docker exec -it hpp bash
Run the tutorial script:
cd ~/devel/src/hpp_tutorial/tutorial_8
python -i init.py
The script loads the FR3, the ground, and a box. It solves the same
pick-and-place problem as tutorial 7, optimizes the path, enforces transition
semantics, and time-parameterizes it with SimpleTimeParameterization.
You can visualize the planned path in the browser viewer:
v = display()
v.loadPath(p_timed)
At this point the useful objects are:
p_timed: the time-parameterized HPP path.configs: sampled HPP configurations along the timed path.times: timestamps in seconds, returned bysegments_from_graph.segments: graph segments whosetransition_namevalues can be used as action dictionary keys.graph: the HPP manipulation constraint graph.open_gripper,close_gripper,grasp_box, andrelease_box: Gazebo actions for the gripper and simulated box attachment.
Building execution dictionaries
The planned path contains the approach, transport, and retreat motion in one
path. Ask hpp_exec to sample the timed path and expose the HPP graph
segments:
from hpp_exec import segments_by_transition, print_segments, segments_from_graph
configs, times, segments = segments_from_graph(p_timed, graph)
print_segments(segments)
This tutorial attaches actions by graph transition name. First wrap the opening action so it can run while the arm starts moving:
from hpp_exec import BackgroundAction
background_open_gripper = BackgroundAction(open_gripper, name="open_gripper")
Set the transition names where the action dictionaries should apply, then check how many path occurrences use each transition:
APPROACH_TRANSITION = "Loop | f"
GRASP_TRANSITION = "fr3/gripper > box/handle | f_23"
RELEASE_TRANSITION = "fr3/gripper < box/handle | 0-0_21"
segments_by_name = segments_by_transition(segments)
Now fill the pre-action and post-action dictionaries. The keys are exact
transition names, and the values are callables. A dictionary entry
applies to every segment with that transition name, so check the printed table
and the occurrence counts before executing. In this movement, each transition
used below appears once. If a different movement repeats one of these names,
the dictionary action would run for every occurrence; use
segments_by_name[TRANSITION_NAME][i].pre_actions when you need to attach an
action to one chosen occurrence.
pre_actions_by_transition = {
APPROACH_TRANSITION: [background_open_gripper.start],
GRASP_TRANSITION: [background_open_gripper.wait, grasp_box],
RELEASE_TRANSITION: [release_box],
}
post_actions_by_transition = {}
The resulting schedule is:
| Dictionary | Transition | Action | Effect |
|---|---|---|---|
| pre | approach | background_open_gripper.start | start opening in the background |
| pre | grasp | background_open_gripper.wait | wait until opening has finished |
| pre | grasp | grasp_box | attach the box and close fingers |
| pre | release | release_box | open fingers and detach the box |
Conceptually, execution still has three phases:
| # | Phase | What the arm does | Action before phase |
|---|---|---|---|
| 0 | approach | move above the box, descend | start opening |
| 1 | transport | carry the box to the goal | wait, attach, close |
| 2 | retreat | lift and return | open and detach |
background_open_gripper.start() returns immediately, so the arm can begin the
approach while the gripper controller opens the fingers. The later
background_open_gripper.wait() blocks before the grasp transition, and
grasp_box() runs after that segment so the fingers close once the arm has
reached the object. If a dictionary key does not match any segment transition,
execute_segments returns False before running any action or trajectory.
Executing the segments
Send the arm segments to the arm controller and let the segment actions command the gripper controller:
from hpp_exec import execute_segments
close_gripper()
reset_box_pose()
execute_segments(
segments, configs, times,
joint_names=[f"fr3_joint{i}" for i in range(1, 8)],
joint_indices=list(range(7)),
pre_actions_by_transition=pre_actions_by_transition,
post_actions_by_transition=post_actions_by_transition,
)
close_gripper() is only a setup step to make the overlapping opening visible
in Gazebo. During execution you should see the fingers open while the arm
starts the approach, then the plan waits before grasping, closes on the box,
carries it to the goal, opens again, and retreats.
reset_box_pose() detaches the simulated box if needed and places it back at
the planned start pose before execution.
HPP-core
This package implements path planning algorithms for kinematic chains. Kinematic chains are represented by class hpp::pinocchio::Device.
The main classes are:
* hpp::core::Problem: defines a canonical path planning problem,
* hpp::core::PathPlanner: implements an algorithm to solve a problem,
* hpp::core::Roadmap: stores a network of collision-free paths
* hpp::core::SteeringMethod: builds paths between configurations taking into
account kinematic constraints.
* hpp::core::Path: paths for a robot.
Embedding hpp-core into an application
Class hpp::core::ProblemSolver is a container aiming at embedding hpp-core into an application. It stores elements of the problem that can be provided in random order and builds a valid problem upon call of method solve. After completion of method solve, it stores solution paths.
hpp-manipulation
This package is part of the HPP software and extends the functionalities of hpp-core. It implements a solver for manipulation planning problems.
Dependencies
[hpp-manipulation] needs the following package to be installed:
Installation
Make sure you have installed all the dependency.
$ git clone https://github.com/humanoid-path-planner/hpp-manipulation
$ cd hpp-manipulation
$ mkdir build && cd build
$ cmake ..
$ make install
Todo’s
- Online modification of the transition probabilities.
- Solver based on Probabilistic RoadMap.
HPP Constraints
Definition of basic geometric constraints for motion planning
- position, orientation of a frame,
hpp-pinocchio
This package implements a library that wraps the Pinocchio library to be used in the Humanoid Path Planner framework.
Setup
The easiest way to install this package is to uses the installation instructions of HPP. For a manual installation, follow these steps.
To compile this package, it is recommended to create a separate build directory:
mkdir _build
cd _build
cmake [OPTIONS] ..
make install
Please note that CMake produces a CMakeCache.txt file which should
be deleted to reconfigure a package from scratch.
Dependencies
The package depends on several packages which have to be available on your machine.
- Libraries:
- Boost (>=1.48.0) Boost Test is used in the test suite
- Pinochio (>=1.1)
- System tools:
- CMake (>=2.6)
- pkg-config
- usual compilation tools (GCC/G++, make, etc.)
hpp-python package
Provide Python bindings of the HPP software. These bindings differ from the one provided by
hpp-corbaserver. They are native bindings that do not use a middleware.
The bindings are generated by boost::python.
Compilation
Installation follows the standard CMake procedure:
git clone --recursive ...
mkdir hpp-python/build
cd hpp-python/build
cmake -DCMAKE_INSTALL_PREFIX=... -DCMAKE_BUILD_TYPE=Release ..
make
make test
make install
Generate documentation
Script doc/configure.py is used to generate documentation of Python objects from C++ objects.
It reads the XML documentation generated by doxygen so the dependencies must provide such
files. To make it work, do:
- Add
GENERATE_XML=YESintodoc/Doxyfile.extra.inof all the dependency of this project. - Install the generated documentation by adding the following lines to
CMakeLists.txt:
IF(_INSTALL_DOC)
INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc/doxygen-xml
DESTINATION ${CMAKE_INSTALL_DOCDIR})
ENDIF()
File doc/configure.py contains a short documentation of how to document the bindings.
TODO
- Use doxygen to generate XML documentation of the headers included by a file.
Then use the generated XML doc to update the documentation of the files in
src/pyhpp. Doxygen configuration variablesINCLUDE_PATHandSEARCH_INCLUDESmight be helpful.
pyhpp API Reference
Python bindings for HPP — auto-generated from .pyi stubs.
| Module | Description |
|---|---|
pyhpp.core | Path planning problem, planners, optimizers, roadmap, steering methods. |
pyhpp.core.path | Concrete path types: StraightPath, PathVector, splines. |
pyhpp.core.path_optimization | Concrete path optimizer implementations. |
pyhpp.core.problem_target | Problem target types (goal configurations, etc.). |
pyhpp.constraints | Differentiable functions, implicit/explicit constraints, hierarchical solver. |
pyhpp.manipulation | Manipulation-specific Device, constraint graph, path planners. |
pyhpp.manipulation.urdf | URDF/SRDF loading for manipulation devices. |
pyhpp.manipulation.steering_method | Manipulation-specific steering methods. |
pyhpp.pinocchio | Robot model (Device), Lie-group utilities. |
pyhpp.pinocchio.urdf | URDF/SRDF loading for pinocchio devices. |
pyhpp.core
Functions
| def | Description |
|---|---|
def DiscretizedCollision(robot: object, stepSize: float) -> Discretized | Create a discretized collision-checking path validation. |
def DiscretizedCollisionAndJointBound(robot: object, stepSize: float) -> Discretized | Create a discretized path validation checking both collision and joint bounds. |
def DiscretizedJointBound(robot: object, stepSize: float) -> Discretized | Create a discretized joint-bound path validation. |
def NoneProjector(distance: Distance, steeringMethod: SteeringMethod, step: float) -> PathProjector | Return a null path projector (no projection). |
def create(arg1: float, arg2: pyhpp.core.path.bindings.SplineB3) -> PathWrap | |
def getVerbosityLevel() -> int | |
def setVerbosityLevel(arg1: pyhpp.core.path.bindings.SplineB3) -> None |
BiRRTPlanner
Inherits: PathPlanner
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
BiRrtStar
Inherits: PathPlanner
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
CollisionPathValidationReport
Inherits: CollisionValidationReport
hpp::core::CollisionPathValidationReport
| def | Description |
|---|---|
def str(self) -> str |
CollisionValidationReport
Inherits: ValidationReport
hpp::core::CollisionValidationReport
| def | Description |
|---|---|
| |
| |
|
ConfigProjector
Inherits: Constraint
Implicit non-linear constraint
This class defines a numerical constraints on a robot configuration of the form:
Functions are differentiable functions. Vectors are called right hand side.
The constraints are solved numerically by a Newton Raphson like method.
Numerical constraints can be added using method ConfigProjector::add. Default parameter of this method define equality constraints, but inequality constraints can also be defined by passing an object of type ComparisonType to method.
| def | Description |
|---|---|
def init(self, arg2: object, arg3: str, arg4: float, arg5: int) -> object | |
def add(self, numericalConstraint: pyhpp.constraints.bindings.Implicit, priority: int) -> bool | numericalConstraint — The numerical constraint. priority — priority of the function. The last level might be optional. |
| Set error threshold. |
| Get whether the last priority level is treated as optional. |
| Get maximal number of iterations in config projector. |
def numericalConstraints(self) -> list | Return the list of numerical constraints held by this projector. |
def residualError(self) -> float | |
def setRightHandSideFromConfig(self, arg2: numpy.ndarray) -> None | Set right-hand side of all constraints from a configuration. |
def setRightHandSideOfConstraint(self, arg2: pyhpp.constraints.bindings.Implicit, arg3: numpy.ndarray) -> None | Set right-hand side of a specific constraint from a configuration. |
def sigma(self) -> float | |
def solver(self) -> pyhpp.constraints.bindings.BySubstitution | |
| Get/set the line search type. |
ConfigValidation
Abstraction of configuration validation
Instances of this class validate configurations with respect to some criteria
| def | Description |
|---|---|
| config — the config to check for validity, validationReport — report on validation. If non valid, a validation report will be allocated and returned via this shared pointer. |
ConfigValidations
Inherits: ConfigValidation
Validate a configuration with respect to collision
| def | Description |
|---|---|
def add(self, configValidation: ConfigValidation) -> None | Add a configuration validation object. |
def clear(self) -> None | Remove all config validations. |
def numberConfigValidations(self) -> int | Return the number of config validations. |
ConfigurationShooter
Abstraction of configuration shooter
Configuration shooters are used by random sampling algorithms to generate new configurations
| def | Description |
|---|---|
def shoot(self) -> numpy.ndarray | Shoot a random configuration. |
ConnectedComponent
Connected component
Set of nodes reachable from one another.
| def | Description |
|---|---|
def eq(self, arg2: ConnectedComponent) -> bool | Return true if both objects refer to the same connected component. |
def nodes(self) -> list | Access to the nodes. |
def reachableFrom(self) -> list | |
def reachableTo(self) -> list |
Constraint
Constraint applicable to a robot configuration
Constraint::apply takes as input a configuration and changes it into a configuration satisfying the constraint.
User should define impl_compute in derived classes.
| def | Description |
|---|---|
def str(self) -> str | |
def apply(self, arg2: numpy.ndarray) -> bool | Apply constraint to q in-place. Returns true on success. |
def copy(self) -> Constraint | Return a copy of this constraint. |
| Return true if configuration q satisfies the constraint. |
def name(self) -> object | Get name of constraint. |
ConstraintSet
Inherits: Constraint
Set of constraints applicable to a robot configuration
If the set is to contain a ConfigProjector and several LockedJoint instances, the configProjector should be inserted first since following numerical projections might affect locked degrees of freedom.
| def | Description |
|---|---|
def init(self, arg2: object, arg3: str) -> object | |
def addConstraint(self, constraint: Constraint) -> None | Add a constraint to the set. |
def configProjector(self) -> ConfigProjector | Return pointer to config projector if any. |
Dichotomy
Inherits: PathValidation
Abstraction of path validation
Instances of this class compute the latest valid configuration along a path.
Method validate(ConfigurationIn_tq)
is provided to validate single configurations. It is particularly useful to test the initial and goal configurations of a path planning problem using this path validation.
| def | Description |
|---|---|
def init(self, robot: object, tolerance: float) -> object | Create a dichotomy-based continuous path validation. |
DichotomyProjector
Inherits: PathProjector
This class projects a path using constraints.
| def | Description |
|---|---|
def init(self, distance: Distance, steeringMethod: SteeringMethod, step: float) -> object | Create a dichotomy-based path projector with the given step size. |
DiffusingPlanner
Inherits: PathPlanner
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
Discretized
Inherits: PathValidation
Abstraction of path validation
Instances of this class compute the latest valid configuration along a path.
Method validate(ConfigurationIn_tq)
is provided to validate single configurations. It is particularly useful to test the initial and goal configurations of a path planning problem using this path validation.
| def | Description |
|---|---|
def init(self, robot: object, stepSize: float) -> object | Create a discretized collision-checking path validation. |
Distance
Abstract class for distance between configurations.
| def | Description |
|---|---|
|
Dubins
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
GlobalProjector
Inherits: PathProjector
This class projects a path using constraints.
| def | Description |
|---|---|
def init(self, distance: Distance, steeringMethod: SteeringMethod, step: float) -> object | Create a global path projector with the given step size. |
Hermite
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
JointBoundValidationReport
Inherits: ValidationReport
report returned when a configuration is not within the bounds
| def | Description |
|---|---|
| |
| |
| |
| |
|
Kinodynamic
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
LineSearchType
Inherits: int
Node
Node of a roadmap
Stores a configuration.
| def | Description |
|---|---|
| |
def addInEdge(self, edge: object) -> None | |
def addOutEdge(self, edge: object) -> None | |
def configuration(self) -> object | |
| Return the connected component the node belongs to. |
def inEdges(self) -> object | Access to inEdges. |
def isInNeighbor(self, n: Node) -> bool | |
def isOutNeighbor(self, n: Node) -> bool | |
def outEdges(self) -> object | Access to outEdges. |
Parameter
| def | Description |
|---|---|
def init(self) -> Parameter | |
def boolValue(self) -> bool | Return the boolean value of this parameter. |
| Create a Parameter holding a boolean value. |
def floatValue(self) -> float | Return the floating-point value of this parameter. |
def intValue(self) -> int | Return the integer value of this parameter. |
def matrixValue(self) -> numpy.ndarray | Return the matrix value of this parameter. |
def stringValue(self) -> str | Return the string value of this parameter. |
def value(self) -> object | Return the parameter value as a Python object (bool, int, float, str, numpy array). |
def vectorValue(self) -> numpy.ndarray | Return the vector value of this parameter. |
PartialShortcut
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object |
Path
Abstraction of paths: mapping from time to configuration space
A path is defined by:
where
is given by timeRange
is the child class implementation of impl_compute
constraints.apply corresponds to calling Constraint::apply to constraints
Optionally, it is possible to time-parameterize the path with a function . By default, is the identity. The model becomes:
where is the timeParameterization, from timeRange to paramRange.
| def | Description |
|---|---|
| Evaluate path at parameter t. Returns (configuration, success). |
def str(self) -> str | |
def constraints(self) -> ConstraintSet | Return the constraint set attached to the path, or None. |
def copy(self) -> Path | Return a shared pointer to a copy of this. |
def derivative(self, arg2: float, arg3: int) -> numpy.ndarray | Compute derivative of given order at parameter t. Returns a numpy vector. |
def end(self) -> numpy.ndarray | Get the final configuration. |
| Evaluate path at parameter t. Returns (configuration, success). |
| subInterval — interval of definition of the extract path If upper bound of subInterval is smaller than lower bound, result is reversed. :param :is thrown when an end configuration of the returned path could not be computed due to projection failure. |
def initial(self) -> numpy.ndarray | Get the initial configuration. |
def length(self) -> float | Get length of definition interval. |
def outputDerivativeSize(self) -> int | Get size of velocity. |
def outputSize(self) -> int | Get size of configuration space. |
def paramRange(self) -> interval | |
def reverse(self) -> Path | |
def timeRange(self) -> interval | Get interval of definition. |
PathOptimizer
Abstraction of path optimizer
| def | Description |
|---|---|
def interrupt(self) -> None | Interrupt path optimization. |
def maxIterations(self, n: int) -> None | Set maximal number of iterations. |
def optimize(self, path: pyhpp.core.path.bindings.Vector) -> pyhpp.core.path.bindings.Vector | Optimize path. |
def problem(self) -> CppCoreProblem | Get problem. |
def timeOut(self, timeOut: float) -> None | set time out (in seconds) |
PathPlanner
Path planner
Algorithm that computes a path between an initial configuration and a set of goal configurations.
| def | Description |
|---|---|
def computePath(self) -> pyhpp.core.path.bindings.Vector | Find a path in the roadmap and transform it in trajectory. |
def finishSolve(self, path: pyhpp.core.path.bindings.Vector) -> pyhpp.core.path.bindings.Vector | Post processing of the resulting path. |
def interrupt(self) -> None | Interrupt path planning. |
| Get maximal number of iterations. |
def oneStep(self) -> None | User implementation of one step of resolution. |
def problem(self) -> CppCoreProblem | Get problem. |
def roadmap(self) -> Roadmap | Get roadmap. |
def solve(self) -> pyhpp.core.path.bindings.Vector | |
def startSolve(self) -> None | |
def stopWhenProblemIsSolved(self, enable: bool) -> None | |
| Get time out. |
def tryConnectInitAndGoals(self) -> None | Try to connect initial and goal configurations to existing roadmap. |
PathProjector
This class projects a path using constraints.
| def | Description |
|---|---|
| the — input path, the — output path. |
PathValidation
Abstraction of path validation
Instances of this class compute the latest valid configuration along a path.
Method validate(ConfigurationIn_tq)
is provided to validate single configurations. It is particularly useful to test the initial and goal configurations of a path planning problem using this path validation.
| def | Description |
|---|---|
| :param :the path to check for validity, reverse — if true check from the end, the — extracted valid part of the path, pointer to path if path is valid. report — information about the validation process. A report is allocated if the path is not valid. |
def validateConfiguration(self, arg2: numpy.ndarray) -> tuple | Validate a configuration; returns (valid, report). |
PathValidationReport
Inherits: ValidationReport
hpp::core::PathValidationReport
| def | Description |
|---|---|
| |
|
PathWrap
Inherits: Path
| def | Description |
|---|---|
def init(self, arg2: interval, arg3: int, arg4: int) -> None | |
| |
| |
| |
| |
| |
def initPtr(self, arg2: PathWrap) -> None | |
| |
|
PlanAndOptimize
Inherits: PathPlanner
| def | Description |
|---|---|
def init(self, arg2: PathPlanner) -> None |
Problem
Defines a path planning problem for one robot. A path planning problem is defined by
a robot: instance of class hpp::pinocchio::Device,
a set of obstacles: a list of hpp::pinocchio::CollisionObject,
initial and goal configurations,
a SteeringMethod to handle the robot dynamics, Additional objects are stored in this object:
a method to validate paths,
a set of methods to validate configurations. Default methods are collision checking and joint bound checking.
| def | Description |
|---|---|
def init(self, arg2: object) -> None | |
def addConfigValidation(self, configValidation: str) -> None | Add a config validation method. |
def addGoalConfig(self, config: numpy.ndarray) -> None | |
| Add constraints with priorities to the config projector, creating it if needed. |
def addPartialCom(self, arg2: str, arg3: list) -> None | Create a named partial COM computation from a list of joint names. |
def applyConstraints(self, arg2: numpy.ndarray) -> tuple | Project config onto active constraints. Returns (success, projected_config, residual_error). |
def clearConfigValidations(self) -> None | |
| Get the config validations object. |
| Get the configuration shooter. |
def createComBetweenFeet(self, arg2: str, arg3: str, arg4: str, arg5: str, arg6: numpy.ndarray, arg7: numpy.ndarray, arg8: str, arg9: numpy.ndarray, arg10: list) -> pyhpp.constraints.bindings.Implicit | Create an implicit constraint: COM lies between two contact points. |
def createRelativeComConstraint(self, arg2: str, arg3: str, arg4: str, arg5: numpy.ndarray, arg6: list) -> pyhpp.constraints.bindings.Implicit | Create an implicit constraint: relative COM equals a reference point expressed in a joint frame. |
| Create a relative or absolute transformation constraint between two frames, with a 6-bool mask. |
def directPath(self, arg2: numpy.ndarray, arg3: numpy.ndarray, arg4: bool) -> tuple | Compute a direct path using the steering method. Returns (valid, path, report). |
| Get the distance function. |
def getConstraints(self) -> ConstraintSet | Return the active constraint set. |
def getParameter(self, name: str) -> Parameter | name — of the parameter. |
def getPartialCom(self, arg2: str) -> numpy.ndarray | Compute and return the position of the named partial center of mass. |
def initConfig(self, self_: numpy.ndarray) -> None | Get shared pointer to initial configuration. |
def isConfigValid(self, arg2: numpy.ndarray) -> tuple | Validate config against all config validations. Returns (valid, report). |
| Get the path projector. |
| Get the path validation object. |
def resetGoalConfigs(self) -> None | |
def robot(self) -> object | return shared pointer to robot. |
def setConstantRightHandSide(self, arg2: pyhpp.constraints.bindings.Implicit, arg3: bool) -> None | If constant=True, set comparison type to EqualToZero; otherwise to Equality. |
def setConstraints(self, arg2: ConstraintSet) -> None | Set the active constraint set used by applyConstraints. |
| name — of the parameter. value — value of the parameter std — :invalid_argument:if a parameter exists but has a different type. |
def setRightHandSideFromConfig(self, arg2: numpy.ndarray) -> None | Update right-hand side of the config projector from a configuration. |
| Get the steering method. |
| Get the problem target. |
| Error threshold used when creating a new ConfigProjector. |
| Maximum iterations for projection used when creating a new ConfigProjector. |
ProblemTarget
Problem target
This abstract class defines the goal to be reached by a planning algorithm.
Progressive
Inherits: PathValidation
Abstraction of path validation
Instances of this class compute the latest valid configuration along a path.
Method validate(ConfigurationIn_tq)
is provided to validate single configurations. It is particularly useful to test the initial and goal configurations of a path planning problem using this path validation.
| def | Description |
|---|---|
def init(self, robot: object, tolerance: float) -> object | Create a progressive continuous path validation. |
ProgressiveProjector
Inherits: PathProjector
This class projects a path using constraints.
| def | Description |
|---|---|
def init(self, distance: Distance, steeringMethod: SteeringMethod, step: float) -> object | Create a progressive path projector with the given step size. |
RSTimeParameterization
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object |
RandomShortcut
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object |
RecursiveHermiteProjector
Inherits: PathProjector
This class projects a path using constraints.
| def | Description |
|---|---|
def init(self, distance: Distance, steeringMethod: SteeringMethod, step: float) -> object | Create a recursive Hermite path projector with the given step size. |
ReedsShepp
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
Roadmap
Roadmap built by random path planning methods Nodes are configurations, paths are collision-free paths.
| def | Description |
|---|---|
def init(self, arg2: Distance, arg3: object) -> object | |
def str(self) -> str | |
| Add nodes at from and to, then add a directed edge between them. |
def addEdges(self, from_: Node, to: Node, path: Path) -> None | from — first node to — second node :param :path going from |
def addGoalNode(self, config: numpy.ndarray) -> Node | config — configuration If configuration is already in the roadmap, tag corresponding node as goal node. Otherwise create a new node. |
def addNode(self, arg2: numpy.ndarray) -> None | Add a node with the given configuration to the roadmap. |
def addNodeAndEdge(self, arg2: numpy.ndarray, arg3: numpy.ndarray, arg4: Path) -> None | Add node at ‘to’ and a single directed edge from the node nearest to ‘from’. |
def addNodeAndEdges(self, arg2: numpy.ndarray, arg3: numpy.ndarray, arg4: Path) -> None | Add node at ‘to’ and edges from the node nearest to ‘from’. |
def clear(self) -> None | Clear the roadmap by deleting nodes and edges. |
def connectedComponentOfNode(self, arg2: numpy.ndarray) -> ConnectedComponent | Return the connected component of the node nearest to the given configuration. |
def connectedComponents(self) -> list | Return list of all connected components. |
def distance(self) -> Distance | |
def getConnectedComponent(self, arg2: pyhpp.core.path.bindings.SplineB3) -> ConnectedComponent | Return connected component by index. |
def goalNodes(self) -> object | |
| Set the initial node to the given configuration. |
def insertPathVector(self, path: pyhpp.core.path.bindings.Vector, backAndForth: bool) -> None | backAndForth — whether to insert the reverse path as well. |
def merge(self, other: Roadmap) -> None | Add the nodes and edges of a roadmap into this one. |
| Find nearest node to configuration (optionally searching in reverse direction). Returns (configuration, minDistance). |
| Find the k nearest nodes to configuration. Returns a list of nodes. |
def nodes(self) -> list | Return list of all node configurations in the roadmap. |
def nodesConnectedComponent(self, arg2: pyhpp.core.path.bindings.SplineB3) -> list | Return list of configurations in the connected component identified by connectedComponentId. |
def nodesWithinBall(self, configuration: numpy.ndarray, connectedComponent: ConnectedComponent, maxDistance: float) -> object | |
def numberConnectedComponents(self) -> int | Return the number of connected components. |
def pathExists(self) -> bool | Check that a path exists between the initial node and one goal node. |
def resetGoalNodes(self) -> None |
SearchInRoadmap
Inherits: PathPlanner
SimpleShortcut
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object |
SimpleTimeParameterization
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object | |
| The maximum acceleration for each degree of freedom. Not considered if negative. |
| The desired continuity order (0, 1, or 2). |
| A scaling factor for the velocity bounds. |
Snibud
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
SplineBezier3
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
SplineBezier5
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
SplineGradientBased_bezier1
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object | |
| Accuracy of the QP solver (only used by proxqp). |
| In [0,1]. Initial value when interpolating between non-colliding current solution and the optimal colliding trajectory. |
| If true, consider only one (not all) collision constraint per iteration. |
| If true, joint bounds are enforced. |
| Order of the derivative used for the optimized cost function (most likely 1, 2, or 3). |
| Stop optimizing if the cost improves less than this threshold between two iterations. |
| Threshold to detect rows of zeros in the Jacobian (passive DoF). Negative disables the check. |
| If true, collision constraint will be re-linearized at each iteration. |
| If true, intervals in collision are checked first at the next iteration. |
| If true, returns the optimum regardless of collision (for debugging). |
| If true, the initial path length is used to weight the splines. |
SplineGradientBased_bezier3
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object | |
| Accuracy of the QP solver (only used by proxqp). |
| In [0,1]. Initial value when interpolating between non-colliding current solution and the optimal colliding trajectory. |
| If true, consider only one (not all) collision constraint per iteration. |
| If true, joint bounds are enforced. |
| Order of the derivative used for the optimized cost function (most likely 1, 2, or 3). |
| Stop optimizing if the cost improves less than this threshold between two iterations. |
| Threshold to detect rows of zeros in the Jacobian (passive DoF). Negative disables the check. |
| If true, collision constraint will be re-linearized at each iteration. |
| If true, intervals in collision are checked first at the next iteration. |
| If true, returns the optimum regardless of collision (for debugging). |
| If true, the initial path length is used to weight the splines. |
SplineGradientBased_bezier5
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object | |
| Accuracy of the QP solver (only used by proxqp). |
| In [0,1]. Initial value when interpolating between non-colliding current solution and the optimal colliding trajectory. |
| If true, consider only one (not all) collision constraint per iteration. |
| If true, joint bounds are enforced. |
| Order of the derivative used for the optimized cost function (most likely 1, 2, or 3). |
| Stop optimizing if the cost improves less than this threshold between two iterations. |
| Threshold to detect rows of zeros in the Jacobian (passive DoF). Negative disables the check. |
| If true, collision constraint will be re-linearized at each iteration. |
| If true, intervals in collision are checked first at the next iteration. |
| If true, returns the optimum regardless of collision (for debugging). |
| If true, the initial path length is used to weight the splines. |
SteeringMethod
Steering method
A steering method creates paths between pairs of configurations for a robot. They are usually used to take into account nonholonomic constraints of some robots
| def | Description |
|---|---|
def call(self, arg2: numpy.ndarray, arg3: numpy.ndarray) -> Path | Compute a path between two configurations using the steering method. |
| Set constraint set. |
def problem(self) -> CppCoreProblem | |
def steer(self, q1: numpy.ndarray, q2: numpy.ndarray) -> Path |
Straight
Inherits: SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
StraightPath
Inherits: Path
| def | Description |
|---|---|
|
TrapezoidalTimeParameterization
Inherits: PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object | |
| Maximum acceleration for each output degree of freedom. |
| Maximum velocity for each output degree of freedom. |
| Minimum duration assigned to each non-empty subpath. |
ValidationReport
Abstraction of validation report for paths and configurations
This class is aimed at being derived to store information relative to various Validation derived classes
CollisionValidation,
collision related PathValidation classes.
| def | Description |
|---|---|
def str(self) -> str |
VisibilityPrmPlanner
Inherits: PathPlanner
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
WeighedDistance
Inherits: Distance
Weighed distance between configurations
Euclidean distance between configurations seen as vectors. Each degree of freedom is weighed by a positive value.
| def | Description |
|---|---|
def init(self, arg2: object) -> object | |
def asDistancePtr_t(self) -> Distance | Return a clone of this WeighedDistance as a Distance shared pointer. |
def getWeights(self) -> numpy.ndarray | Return the weight vector used when computing distances. |
def setWeights(self, arg2: numpy.ndarray) -> None | Set the weight vector used when computing distances. |
interval
| def | Description |
|---|---|
| |
| |
|
kPrmStar
Inherits: PathPlanner
| def | Description |
|---|---|
def init(self, arg2: Problem) -> None |
pyhpp.core.path
SplineB1
Inherits: pyhpp.core.bindings.Path
| def | Description |
|---|---|
def basisFunctionDerivative(self, arg2: int, arg3: float, arg4: numpy.ndarray) -> None | |
| |
def parameterIntegrate(self, arg2: numpy.ndarray) -> None | |
def parameterSize(self) -> int | |
def rowParameters(self) -> numpy.ndarray | |
def squaredNormBasisFunctionIntegral(self, arg2: int, arg3: numpy.ndarray) -> None | |
def squaredNormIntegral(self, arg2: int) -> float | |
def squaredNormIntegralDerivative(self, arg2: int, arg3: numpy.ndarray) -> None |
SplineB3
Inherits: pyhpp.core.bindings.Path
| def | Description |
|---|---|
def basisFunctionDerivative(self, arg2: int, arg3: float, arg4: numpy.ndarray) -> None | |
| |
def parameterIntegrate(self, arg2: numpy.ndarray) -> None | |
def parameterSize(self) -> int | |
def rowParameters(self) -> numpy.ndarray | |
def squaredNormBasisFunctionIntegral(self, arg2: int, arg3: numpy.ndarray) -> None | |
def squaredNormIntegral(self, arg2: int) -> float | |
def squaredNormIntegralDerivative(self, arg2: int, arg3: numpy.ndarray) -> None |
Vector
Inherits: pyhpp.core.bindings.Path
| def | Description |
|---|---|
def init(self, arg2: int, arg3: int) -> object | Create an empty path vector. param: inputSize dimension of the configuration space, inputDerivativeSize dimension of the tangent space. |
def appendPath(self, path: pyhpp.core.bindings.Path) -> None | Append a path at the end of the vector. |
def concatenate(self, path: Vector) -> None | :param :path to append at the end of this one |
def flatten(self, flattenedPath: Vector) -> None | |
def numberPaths(self) -> int | Get the number of sub paths. |
def pathAtRank(self, rank: int) -> pyhpp.core.bindings.Path | rank — rank of the path in the vector. Should be between 0 and numberPaths (). |
def rankAtParam(self, param: float, localParam: float) -> int | param — parameter in interval of definition, localParam — parameter on sub-path |
Vectors
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, arg2: object) -> None | |
def getitem(self, arg2: object) -> object | |
def init(self) -> None | |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: object, arg3: object) -> None | |
def append(self, arg2: object) -> None | |
def extend(self, arg2: object) -> None |
pyhpp.core.path_optimization
LinearConstraint
| def | Description |
|---|---|
def init(self, arg2: int, arg3: int) -> None | |
def addRows(self, arg2: int) -> None | |
def computeRank(self) -> None | |
def computeSolution(self, arg2: numpy.ndarray) -> None | |
def concatenate(self, arg2: LinearConstraint) -> None | |
def decompose(self, arg2: bool, arg3: bool) -> bool | |
def isSatisfied(self, arg2: numpy.ndarray, arg3: float) -> bool | |
| |
| |
| |
| |
| |
| |
|
QuadraticProgram
| def | Description |
|---|---|
| |
def addRows(self, arg2: int) -> None | |
def computeLLT(self) -> None | |
def decompose(self) -> None | |
def reduced(self, arg2: LinearConstraint, arg3: QuadraticProgram) -> None | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
Report
| def | Description |
|---|---|
| |
| |
|
Reports
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, arg2: object) -> None | |
def getitem(self, arg2: object) -> object | |
def init(self) -> None | |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: object, arg3: object) -> None | |
def append(self, arg2: object) -> None | |
def empty(self) -> bool | |
def extend(self, arg2: object) -> None | |
def push_back(self, arg2: Report) -> None | |
def size(self) -> int |
SplineGradientBasedAbstractB1
Inherits: pyhpp.core.bindings.PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> None | |
def addContinuityConstraints(self, arg2: SplineGradientBasedAbstractB1.Splines, arg3: int, arg4: SplineGradientBasedAbstractB1.SplineOptimizationDatas, arg5: LinearConstraint) -> None | |
def appendEquivalentSpline(self, arg2: pyhpp.core.path.bindings.Vector, arg3: SplineGradientBasedAbstractB1.Splines) -> None | |
def buildPathVector(self, arg2: SplineGradientBasedAbstractB1.Splines) -> pyhpp.core.path.bindings.Vector | |
| |
def initializePathValidation(self, arg2: SplineGradientBasedAbstractB1.Splines) -> None | |
| |
def jointBoundConstraint(self, arg2: SplineGradientBasedAbstractB1.Splines, arg3: LinearConstraint) -> None | |
def updateParameters(self, arg2: numpy.ndarray, arg3: SplineGradientBasedAbstractB1.Splines) -> None | |
def updateSplines(self, arg2: SplineGradientBasedAbstractB1.Splines, arg3: numpy.ndarray) -> None | |
def validatePath(self, arg2: SplineGradientBasedAbstractB1.Splines, arg3: pinocchio.pinocchio_pywrap_default.StdVec_Index, arg4: bool, arg5: bool) -> Reports |
SplineOptimizationData
| def | Description |
|---|---|
| |
| |
| |
|
SplineOptimizationDatas
| def | Description |
|---|---|
def getitem(self, arg2: int) -> SplineGradientBasedAbstractB1.SplineOptimizationData | |
| |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: int, arg3: SplineGradientBasedAbstractB1.SplineOptimizationData) -> None | |
def append(self, arg2: SplineGradientBasedAbstractB1.SplineOptimizationData) -> None |
Splines
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, arg2: object) -> None | |
def getitem(self, arg2: object) -> object | |
def init(self) -> None | |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: object, arg3: object) -> None | |
def append(self, arg2: object) -> None | |
def empty(self) -> bool | |
def extend(self, arg2: object) -> None | |
def push_back(self, arg2: pyhpp.core.path.bindings.SplineB1) -> None | |
def size(self) -> int |
SplineGradientBasedAbstractB3
Inherits: pyhpp.core.bindings.PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> None | |
def addContinuityConstraints(self, arg2: SplineGradientBasedAbstractB3.Splines, arg3: int, arg4: SplineGradientBasedAbstractB3.SplineOptimizationDatas, arg5: LinearConstraint) -> None | |
def appendEquivalentSpline(self, arg2: pyhpp.core.path.bindings.Vector, arg3: SplineGradientBasedAbstractB3.Splines) -> None | |
def buildPathVector(self, arg2: SplineGradientBasedAbstractB3.Splines) -> pyhpp.core.path.bindings.Vector | |
| |
def initializePathValidation(self, arg2: SplineGradientBasedAbstractB3.Splines) -> None | |
| |
def jointBoundConstraint(self, arg2: SplineGradientBasedAbstractB3.Splines, arg3: LinearConstraint) -> None | |
def updateParameters(self, arg2: numpy.ndarray, arg3: SplineGradientBasedAbstractB3.Splines) -> None | |
def updateSplines(self, arg2: SplineGradientBasedAbstractB3.Splines, arg3: numpy.ndarray) -> None | |
def validatePath(self, arg2: SplineGradientBasedAbstractB3.Splines, arg3: pinocchio.pinocchio_pywrap_default.StdVec_Index, arg4: bool, arg5: bool) -> Reports |
SplineOptimizationData
| def | Description |
|---|---|
| |
| |
| |
|
SplineOptimizationDatas
| def | Description |
|---|---|
def getitem(self, arg2: int) -> SplineGradientBasedAbstractB3.SplineOptimizationData | |
| |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: int, arg3: SplineGradientBasedAbstractB3.SplineOptimizationData) -> None | |
def append(self, arg2: SplineGradientBasedAbstractB3.SplineOptimizationData) -> None |
Splines
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, arg2: object) -> None | |
def getitem(self, arg2: object) -> object | |
def init(self) -> None | |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: object, arg3: object) -> None | |
def append(self, arg2: object) -> None | |
def empty(self) -> bool | |
def extend(self, arg2: object) -> None | |
def push_back(self, arg2: pyhpp.core.path.bindings.SplineB3) -> None | |
def size(self) -> int |
pyhpp.core.problem_target
GoalConfigurations
Inherits: pyhpp.core.bindings.ProblemTarget
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.CppCoreProblem) -> object | |
def computePath(self, arg2: pyhpp.core.bindings.Roadmap) -> pyhpp.core.path.bindings.Vector | |
def reached(self, arg2: pyhpp.core.bindings.Roadmap) -> bool |
pyhpp.constraints
BySubstitution
Inherits: HierarchicalIterative
Solve a non-linear system equations with explicit and implicit constraints
This solver is defined in paper https://hal.archives-ouvertes.fr/hal-01804774/file/paper.pdf. We give here only a brief description
The unknows (denoted by ) of the system of equations is a Lie group. It is usually a robot configuration space or the Cartesian product of robot configuration spaces.
The solver stores a set of implicit numerical constraints: . These implicit constraints are added using method HierarchicalIterative::add.
The solver also stores explicit numerical constraints (constraints where some configuration variables depend on others) in an instance of class ExplicitConstraintSet. This instance is accessible via method BySubstitution::explicitConstraintSet.
When an explicit constraint is added using method ExplicitConstraintSet::add, this method checks that the explicit constraint is compatible with the previously added ones. If so, the constraint is stored in the explicit constraint set. Otherwise, it has to be added as an implicit constraint.
See Section III of the above mentioned paper for the description of the constraint resolution.
| def | Description |
|---|---|
def init(self, arg2: pyhpp.pinocchio.bindings.LiegroupSpace) -> None | |
def describeError(self, arg2: numpy.ndarray) -> tuple | Describe the constraint error for configuration q. Returns a list of (constraint_name, error_norm) pairs. |
def explicitConstraintSet(self) -> ExplicitConstraintSet | Get explicit constraint set. |
def explicitConstraintSetHasChanged(self) -> None | Should be called whenever explicit solver is modified. |
| Set right hand side of a constraint. |
| Compute right hand side of equality constraints from a configuration. |
def solve(self, arg2: numpy.ndarray) -> tuple | Solve the constraints from configuration q. Returns (output_config, status). |
| Get error threshold. |
ComparisonType
Inherits: int
ComparisonTypes
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, arg2: object) -> None | |
def getitem(self, arg2: object) -> object | |
def init(self) -> None | |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: object, arg3: object) -> None | |
def append(self, arg2: object) -> None | |
def extend(self, arg2: object) -> None |
DifferentiableFunction
Differentiable function from a Lie group, for instance the configuration space of a robot (hpp::pinocchio::Device) to a another Lie group.
Note that the input Lie group is only represented by the sizes of the elements and of the velocities: methods inputSize and inputDerivativeSize
The output space can be accessed by method outputSpace.
The value of the function for a given input can be accessed by method value . The Jacobian of the function for a given input can be accessed by method jacobian .
| def | Description |
|---|---|
def J(self, arg2: numpy.ndarray) -> numpy.ndarray | Compute Jacobian matrix and return as a numpy array. |
def call(self, arg2: numpy.ndarray) -> pyhpp.pinocchio.bindings.LiegroupElement | Evaluate the function at a given parameter. |
def init(self, arg2: int, arg3: int, arg4: int, arg5: str) -> None | |
def str(self) -> str | |
| |
| |
def inputDerivativeSize(self) -> int | |
def inputSize(self) -> int | Get dimension of input vector. |
def jacobian(self, jacobian: numpy.ndarray, argument: numpy.ndarray) -> None | :param :jacobian will be stored in this argument argument — point at which the jacobian will be computed |
| Get function name. |
def outputDerivativeSize(self) -> int | Get dimension of output derivative vector. |
def outputSize(self) -> int | Get dimension of output vector. |
def outputSpace(self) -> pyhpp.pinocchio.bindings.LiegroupSpace | Get output space. |
def value(self, result: pyhpp.pinocchio.bindings.LiegroupElement, argument: numpy.ndarray) -> None | |
| Get dimension of input derivative vector. |
| Get dimension of output derivative vector. |
| Get dimension of input vector. |
| Get dimension of output vector. |
Explicit
Explicit numerical constraint
DefinitionAn explicit numerical constraint is a constraint such that some configuration variables called output are function of the others called input.
Let
be the list of indices corresponding to ordered input configuration variables,
be the list of indices corresponding to ordered output configuration variables,
be the list of indices corresponding to ordered input degrees of freedom,
be the list of indices corresponding to ordered output degrees of freedom.
Recall that degrees of freedom refer to velocity vectors.
Let us notice that is less than the robot configuration size, and is less than the velocity size. Some degrees of freedom may indeed be neither input nor output.
Then the differential function is of the form
It is straightforward that an equality constraint with this function can be solved explicitely:
If function takes values in a Lie group (SO(2), SO(3)), the above “+” between a Lie group element and a tangent vector has to be undestood as the integration of the constant velocity from the Lie group element:
where is a Lie group element and is a tangent vector.
Considered as an Implicit instance, the expression of the Jacobian of the DifferentiableFunction above depends on the output space of function . The rows corresponding to values in a vector space are expressed as follows.
for any index between 0 and the size of velocity vectors, either
is an input degree of freedom: integer, such that ,
is an output degree of freedom: integer, such that , or
neither input nor output. In this case, the corresponding column is equal to 0.
The rows corresponding to values in SO(3) have the following expression.
where
is the rotation matrix corresponding to unit quaternion ,
is the rotation matrix corresponding to the part of the output value of corresponding to SO(3),
is the Jacobian matrix of function that associates to a rotation matrix the vector such that
“Domain ofdefinition” Some explicit constraints might be defined over only a subspace of the input
space. If the input value is not in the definition subspace, the explicit constraint will throw an exception of type FunctionNotDefinedForThisValue.
| def | Description |
|---|---|
def init(self, arg2: pyhpp.pinocchio.bindings.LiegroupSpace, arg3: DifferentiableFunction, arg4: list, arg5: list, arg6: list, arg7: list, arg8: ComparisonTypes) -> object | Create an explicit constraint mapping output DOF from input DOF. |
ExplicitConstraintSet
Set of explicit constraints
This class combines compatible explicit constraints as defined in the following paper published in Robotics Science and System 2018: https://hal.archives-ouvertes.fr/hal-01804774/file/paper.pdf, Section II-B Definition 4.
An explicit constraint on a robot configuration space is defined by
a subset of input indices ,
a subset of output indices ,
a smooth mapping from to , satisfying the following properties:
,
for any , is defined by
Right hand side.
For manipulation planning, it is useful to handle a parameterizable right hand side . The expression above thus becomes
The right hand side may be set using the various methods ExplicitConstraintSet::rightHandSide and ExplicitConstraintSet::rightHandSideFromInput.
For some applications like manipulation planning, an invertible function (of known inverse ) can be specified for each explicit constraint . The above expression then becomes:
To add explicit constraints, use methods ExplicitConstraintSet::add. If the constraint to add is not compatible with the previous one, this method returns -1.
Method ExplicitConstraintSet::solve solves the explicit constraints.
The combination of compatible explicit constraints is an explicit constraint. As such this class can be considered as an explicit constraint.
We will therefore use the following notation
for the set of indices of input variables,
for the set of indices of output variables.
| def | Description |
|---|---|
def init(self, arg2: pyhpp.pinocchio.bindings.LiegroupSpace) -> None | |
def str(self) -> str | |
def add(self, constraint: Explicit) -> int | constraint — explicit constraint |
def errorSize(self) -> int |
HierarchicalIterative
Solve a system of non-linear equations on a robot configuration
The non-linear system of equations is built by adding equations with method HierarchicalIterative::add.
Note that a hierarchy between the equations can be provided. In this case, the solver will try to solve the highest priority equations first, and then to solve the lower priority equations. Note that priorities are in decreasing order: 0 has higher priority than 1.
The algorithm used is a Newton-Raphson like algorithm that works as follows: for a single level of priority, let be the system of equations where is a mapping from the robot configuration space to a Lie group space .
Starting from initial guess , the method HierarchicalIterative::solve builds a sequence of configurations as follows:
where
is the Moore-Penrose pseudo-inverse of the system Jacobian,
is a sequence of real numbers depending on the line search strategy. Possible line-search strategies are lineSearch::Constant, lineSearch::Backtracking, lineSearch::FixedSequence, lineSearch::ErrorNormBased. until
the residual is below an error threshold, or
the maximal number of iterations has been reached.
The computation of the direction of descent in the case of multiple level of hierarchy is described in this paper.
The error threshold can be accessed by methods HierarchicalIterative::errorThreshold. The maximal number of iterations can be accessed by methods HierarchicalIterative::maxIterations.
Solving equations one after the other
For some applications, it can be more efficient to solve a set of equations one after the other. In other words, an equation is ignored until the previous one is solved (norm below the threshold). To do so, introduce the equations using method HierarchicalIterative::add with increasing value of priority, and call method HierarchicalIterative::solveLevelByLevel(true). Lie group
The unknowns may take values in a more general set than the configuration space of a robot. This set should be a Cartesian product of Lie groups: hpp::pinocchio::LiegroupSpace.
Saturation
Right hand side and comparison types
Instead of , other constraints can be defined. Several comparison types are available:
Equality — , where is a parameterizable right hand side,
EqualToZero — ,
Superior —
Inferior — If several constraint are of type equality, the right hand side of the system of equations can be modified by methods HierarchicalIterative::rightHandSideFromInput, HierarchicalIterative::rightHandSide.
Free variables
Some variables can be locked, or computed explicitely. In this case, the iterative resolution will only change the other variables called free variables. methods
freeVariables (const Indices_t& indices) and
freeVariables (const Indices_t& indices).
| def | Description |
|---|---|
def init(self, arg2: pyhpp.pinocchio.bindings.LiegroupSpace) -> None | |
def str(self) -> str | |
def add(self, constraint: Implicit, priority: int) -> bool | constraint — implicit constraint priority — level of priority of the constraint: priority are in decreasing order: 0 is the highest priority level, |
def constraintsForPriority(self, arg2: int) -> list | Return list of constraints at the given priority level. |
def dimension(self) -> int | Return total dimension of the active constraints. |
def numberStacks(self) -> int | Return the number of priority stacks. |
| Set right hand side of a constraint. |
| Compute right hand side of equality constraints from a configuration. |
| |
| Whether the last priority level is treated as optional. |
| Get maximal number of iterations in config projector. |
| Whether to solve constraints one priority level at a time. |
Implicit
This class represents a parameterizable numerical constraint that compares the output of a function to a right hand side Lie group element.
Definition
The function takes input in a configuration space and output in a Lie group ,
the dimensions of and of its tangent space are respectively .
The comparison is represented by a vector of dimension with values in enum hpp::constraints::ComparisonType = { , , , }.
The right hand side is Lie group element of dimension .
Error
A configuration is said to satisfy the constraint for a given right hand side if and only if the error as computed below is smaller in norm than a given threshold.
Let
for each component ,
if is , ,
if is , ,
if is , ,
if is , .
Mask
A mask is a vector of Boolean values of size . Values set to false means that the corresponding component of the error defined above is not taken into account to determine whether the constraint is satisfied. The active rows of the constraint may be accessed via method activeRows.
Parameterizable right hand side
Lines with comparator in the above definition of the error need a parameter, while lines with comparators , , or do not. As a consequence, the right hand side of the constraint is defined by a vector of parameters of size the number of occurences in vector . The right hand side is then defined as in the following example:
To retrieve the size of vector , call method Implicit::parameterSize (). To set and get the right hand side value, use method Implicit::rightHandSide.
Time varying right hand side
The right hand side of the constraint may depend on time, for instance if the constraint is associated to a trajectory following task. In this case, the right hand side is a function from to .
| def | Description |
|---|---|
def init(self, arg2: DifferentiableFunction, arg3: ComparisonTypes, arg4: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | Create an implicit constraint from a differentiable function and comparison types. |
| Return the ComparisonType. |
def function(self) -> DifferentiableFunction | Return a reference to function . |
def getFunctionOutputSize(self) -> int | Return the output size of the underlying differentiable function. |
def parameterSize(self) -> int | |
def rightHandSideSize(self) -> int |
LockedJoint
Inherits: Implicit
Implementation of constraint specific to a locked joint.
The implicit formulation as defined in class Implicit is given by
where is an element of the configuration space of the locked joint passed to method create.
Note that takes values in where is the dimension of the joint tangent space.
The explicit formulation is given by
where coordinates of corresponding to comparison types different from Equality are set to 0.
As such, the relation between the explicit formulation and the implicit formulation is the default one.
| def | Description |
|---|---|
| Create a locked joint constraint fixing the named joint to the given configuration. |
Manipulability
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: DifferentiableFunction, arg3: object, arg4: str) -> object | Create a manipulability function for the given robot. |
def lockJoint(self, arg2: str) -> None | Lock a joint by name so it is excluded from the Jacobian. |
MinManipulability
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: DifferentiableFunction, arg3: object, arg4: str) -> object | Create a minimum-manipulability function for the given robot. |
def lockJoint(self, arg2: str) -> None | Lock a joint by name so it is excluded from the Jacobian. |
Orientation
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: str, arg3: object, arg4: int, arg5: pinocchio.pinocchio_pywrap_default.SE3, arg6: pinocchio.pinocchio_pywrap_default.SE3, arg7: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | name — name of the constraint, robot — device the constraint applies to, j2 — index of joint that holds frame 2, frame2 (SE3): pose of frame 2 in joint 2, frame1 (SE3): pose of frame 1 in world frame, mask — tuple of Boolean. |
Position
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: str, arg3: object, arg4: int, arg5: pinocchio.pinocchio_pywrap_default.SE3, arg6: pinocchio.pinocchio_pywrap_default.SE3, arg7: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | name — name of the constraint, robot — device the constraint applies to, j2 — index of joint that holds frame 2, frame2 (SE3): pose of frame 2 in joint 2, frame1 (SE3): pose of frame 1 in world frame, mask — tuple of Boolean. |
RelativeCom
Inherits: DifferentiableFunction
Constraint on the relative position of the center of mass
The value of the function is defined as the position of the center of mass in the reference frame of a joint.
where
is the position of the joint,
is the position of the center of mass,
is the desired position of the center of mass expressed in joint frame.
| def | Description |
|---|---|
| Return a shared pointer to a new instance. |
RelativeOrientation
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: str, arg3: object, arg4: int, arg5: int, arg6: pinocchio.pinocchio_pywrap_default.SE3, arg7: pinocchio.pinocchio_pywrap_default.SE3, arg8: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | name — name of the constraint, robot — device the constraint applies to, j1 — index of joint that holds frame 1, j2 — index of joint that holds frame 2, frame1 (SE3): pose of frame 1 in joint 1, frame2 (SE3): pose of frame 2 in joint 2, mask — tuple of Boolean. |
RelativePosition
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: str, arg3: object, arg4: int, arg5: int, arg6: pinocchio.pinocchio_pywrap_default.SE3, arg7: pinocchio.pinocchio_pywrap_default.SE3, arg8: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | name — name of the constraint, robot — device the constraint applies to, j1 — index of joint that holds frame 1, j2 — index of joint that holds frame 2, frame1 (SE3): pose of frame 1 in joint 1, frame2 (SE3): pose of frame 2 in joint 2, mask — tuple of Boolean. |
RelativeTransformation
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: str, arg3: object, arg4: int, arg5: int, arg6: pinocchio.pinocchio_pywrap_default.SE3, arg7: pinocchio.pinocchio_pywrap_default.SE3, arg8: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | name — name of the constraint, robot — device the constraint applies to, j1 — index of joint that holds frame 1, j2 — index of joint that holds frame 2, frame1 (SE3): pose of frame 1 in joint 1, frame2 (SE3): pose of frame 2 in joint 2, mask — tuple of Boolean. |
RelativeTransformationR3xSO3
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: str, arg3: object, arg4: int, arg5: int, arg6: pinocchio.pinocchio_pywrap_default.SE3, arg7: pinocchio.pinocchio_pywrap_default.SE3, arg8: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | name — name of the constraint, robot — device the constraint applies to, j1 — index of joint that holds frame 1, j2 — index of joint that holds frame 2, frame1 (SE3): pose of frame 1 in joint 1, frame2 (SE3): pose of frame 2 in joint 2, mask — tuple of Boolean. |
SolverStatus
Inherits: int
Transformation
Inherits: DifferentiableFunction
| def | Description |
|---|---|
def init(self, arg2: str, arg3: object, arg4: int, arg5: pinocchio.pinocchio_pywrap_default.SE3, arg6: pinocchio.pinocchio_pywrap_default.SE3, arg7: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> object | name — name of the constraint, robot — device the constraint applies to, j2 — index of joint that holds frame 2, frame2 (SE3): pose of frame 2 in joint 2, frame1 (SE3): pose of frame 1 in world frame, mask — tuple of Boolean. |
segment
| def | Description |
|---|---|
| |
| |
|
pyhpp.manipulation
Functions
Device
Inherits: pyhpp.pinocchio.bindings.Device
Device with handles.
As a deriving class of hpp::pinocchio::HumanoidRobot, it is compatible with hpp::pinocchio::urdf::loadHumanoidRobot
This class also contains pinocchio::Gripper, Handle and JointAndShapes_t
| def | Description |
|---|---|
def init(self, arg2: str) -> None | |
def addGripper(self, arg2: str, arg3: str, arg4: pinocchio.pinocchio_pywrap_default.SE3, arg5: float) -> None | Add a gripper to the kinematic chain |
def addHandle(self, arg2: str, arg3: str, arg4: pinocchio.pinocchio_pywrap_default.SE3, arg5: float, arg6: pinocchio.pinocchio_pywrap_default.StdVec_Bool) -> None | Add a handle to the kinematic chain |
| |
def contactSurfaceNames(self) -> list | Return list of contact surface names registered on device |
def contactSurfaces(self) -> dict | Return dict mapping surface names to list of {joint, points} |
def getJointConfig(self, arg2: str) -> list | Return current configuration values of the named joint. |
def getJointNames(self) -> list | Return list of all joint names in the Pinocchio model. |
def grippers(self) -> pyhpp.pinocchio.bindings.GripperMap | Return a map from gripper name to Gripper object. |
def handles(self) -> HandleMap | Return a map from handle name to Handle object. |
def modelsInfo(self) -> modelsInfoVec | Return list of modelsInfo stored in the device, each element contains the urdf path, srdf path, prefix and initial pose of a model loaded in the device |
def setJointBounds(self, arg2: str, arg3: list) -> None | Set joint bounds from a flat list [min0, max0, min1, max1, …]. |
def setRobotRootPosition(self, arg2: str, arg3: pinocchio.pinocchio_pywrap_default.SE3) -> None | Set the root position of a sub-robot (identified by name) relative to its parent joint. |
EndEffectorTrajectory
Inherits: pyhpp.core.bindings.PathPlanner
Plan a path for a robot with constrained trajectory of an end effector
This path planner only works with a steering method of type steeringMethod::EndEffectorTrajectory. The steering method defines the desired end-effector trajectory using a time-varying constraint.
To plan a path between two configurations q_init and q_goal, the configurations must satisfy the constraint at the beginning and at the end of the definition interval respectively.
The interval of definition of the output path is defined by the time-varying constraint of the steering method. This interval is uniformly discretized in a number of samples that can be accessed using method nDiscreteSteps .
The path is planned by successively calling method oneStep that performs the following actions.
A vector of configurations is produced by appending random configurations to q_init. The number of random configurations can be accessed by methods nRandomConfig .
for each configuration in the vector,
the initial configuration of the path is computed by projecting the configuration on the constraint,
the configuration at following samples is computed by projecting the configuration at the previous sample using the time-varying constraint.
In case of failure
in projecting a configuration or
in validating the path for collision, the loop restart with the next random configuration.
Note that continuity is not tested but enforced by projecting the configuration of the previous sample to compute the configuration at a given sample. DeprecatedThis class has been reimplemented and simplified as steeringMethod::Cartesian.
| def | Description |
|---|---|
| |
| If enabled, only add one solution to the roadmap. Otherwise add all solutions. |
| Number of steps to generate goal config (successive projections). |
| Get the number of random configurations used to generate the initial config of the final path. |
EndEffectorTrajectorySteeringMethod
Inherits: pyhpp.core.bindings.SteeringMethod
| def | Description |
|---|---|
def init(self, arg2: object) -> None | |
def setTrajectory(self, arg2: pyhpp.core.bindings.Path, arg3: bool) -> None | Set the right hand side of the trajectory constraint from a path. param se3Output: set to True if the output of path must be understood as SE3. |
def setTrajectoryConstraint(self, arg2: pyhpp.constraints.bindings.Implicit) -> None | Set the constraint whose right hand side will vary along the trajectory. |
EnforceTransitionSemantic
Inherits: pyhpp.core.bindings.PathOptimizer
Recompute the transition relative to each element of the path vector
When executing a sequence of direct paths on a real robot, it is useful to know which
transition of the graph each direct path corresponds to. For example, in a manipulation
motion, before grasping an object, the robot needs to open the gripper. This information
is contained in the transition that leads to a pregrasp waypoint state. The direct path
should therefore have access to the transition.
The information is stored in the hpp::manipulation::ConstraintSet.
of the path and is accessible via method hpp::manipulation::ConstraintSet::edge
If the path vector is produced by a manipulation planner, each direct path has been created
by a transition. However, the path may later be cut by random shortcut or due to collision and
the associated transition become irrelevant. For example if a path is created by a transition
that leads to a pre-grasp, and cut due to a collision, the path does not reach the target
state and the relevant transition is not the one that built the path.
This class takes a hpp::core::PathVector as input an relabel
each direct path with the correct transition.
Precondition — The path should have been created by a manipulation planning algorithm: in other
words, the constraint set of each direct path should be of type
hpp::manipulation::ConstraintSet.
| def | Description |
|---|---|
def init(self, arg2: object) -> object |
Graph
Description of the constraint graph.
This class contains a graph representing a a manipulation problem
One must make sure not to create loop with shared pointers. To ensure that, the classes are defined as follow:
A Graph owns (i.e. has a shared pointer to) the StateSelector s
A StateSelector owns the Node s related to one gripper.
A State owns its outgoing Edge s.
An Edge does not own anything.
The graph and all its components have a unique index starting at 0 for the graph itself. The index of a component can be retrieved using method GraphComponent::id.
| def | Description |
|---|---|
def init(self, arg2: str, arg3: Device, arg4: Problem) -> None | |
def _get_native_graph(self) -> object | Return a capsule wrapping the native C++ Graph object (for external interop). |
def addLevelSetFoliation(self, arg2: Transition, arg3: list, arg4: list) -> None | Add the numerical constraints to a LevelSetTransition that create the foliation. |
def addNumericalConstraint(self, arg2: State, arg3: pyhpp.constraints.bindings.Implicit) -> None | Add a numerical constraint to a state. |
def addNumericalConstraintsForPath(self, arg2: State, arg3: list) -> None | Add numerical constraints for path to a state. |
def addNumericalConstraintsToGraph(self, arg2: list) -> None | Add a list of numerical constraints to all transitions in the graph. |
def addNumericalConstraintsToState(self, arg2: State, arg3: list) -> None | Add numerical constraints to a state. |
def addNumericalConstraintsToTransition(self, arg2: Transition, arg3: list) -> None | Add numerical constraints to a TRANSITION. |
def applyLeafConstraints(self, arg2: Transition, arg3: numpy.ndarray, arg4: numpy.ndarray) -> tuple | Apply transition constraints to a configuration. Returns tuple with success flag, output configuration, and error norm. If success, the output configuration is reachable from q_rhs along the transition. |
def applyStateConstraints(self, arg2: State, arg3: numpy.ndarray) -> tuple | Apply constraints to a configuration. Returns tuple with success flag, output configuration, and error norm. |
def createGraspConstraint(self, arg2: str, arg3: str, arg4: str) -> list | Create grasp, complement and hold constraints for a gripper-handle pair. Returns a list [grasp, complement, hold]. |
def createLevelSetTransition(self, arg2: State, arg3: State, arg4: str, arg5: pyhpp.core.path.bindings.SplineB3, arg6: State) -> Transition | Create a LevelSetTransition. See documentation of class hpp::manipulation::graph::LevelSetEdge for more information. |
| Create placement constraint between object surfaces and environment surfaces. Creates constraints that ensure proper contact between object and environment. |
def createPreGraspConstraint(self, arg2: str, arg3: str, arg4: str) -> pyhpp.constraints.bindings.Implicit | Create a pre-grasp constraint for a gripper-handle pair. |
| Create pre-placement constraint with specified width margin. Used for approaching placement configurations before final placement. |
def createState(self, arg2: str, arg3: bool, arg4: pyhpp.core.path.bindings.SplineB3) -> State | Create one or several states. The order is important - the first should be the most restrictive one as a configuration will be in the first state for which the constraints are satisfied. |
def createSubGraph(self, arg2: str, arg3: pyhpp.core.bindings.Roadmap) -> None | Create a subgraph with guided state selection. |
def createTransition(self, arg2: State, arg3: State, arg4: str, arg5: pyhpp.core.path.bindings.SplineB3, arg6: State) -> Transition | Create a transition. The weights define the probability of selecting a transition among all the outgoing transitions of a state. The probability of a transition is w_i / sum(w_j), where each w_j corresponds to an outgoing transition from a given state. To have a transition that cannot be selected by the M-RRT algorithm but is still acceptable, set its weight to zero. |
def createWaypointTransition(self, arg2: State, arg3: State, arg4: str, arg5: pyhpp.core.path.bindings.SplineB3, arg6: pyhpp.core.path.bindings.SplineB3, arg7: State, arg8: bool) -> Transition | Create a WaypointTransition. See documentation of class hpp::manipulation::graph::WaypointEdge for more information. |
def display(self, arg2: str) -> None | Display the current graph. The graph is printed in DOT format. |
def displayStateConstraints(self, arg2: State) -> str | Print set of constraints relative to a state in a string. |
def displayTransitionConstraints(self, arg2: Transition) -> str | Print set of constraints relative to a transition in a string. |
def displayTransitionTargetConstraints(self, arg2: Transition) -> str | Print set of constraints relative to a transition in a string. |
| Get error threshold in config projector. |
def generateTargetConfig(self, arg2: Transition, arg3: numpy.ndarray, arg4: numpy.ndarray) -> tuple | Generate configuration in destination state on a given leaf. Returns tuple with success flag, output configuration, and error norm. Computes a configuration in the destination state of the transition, reachable from q_rhs. |
def getConfigErrorForState(self, arg2: State, arg3: numpy.ndarray) -> tuple | Get error of a config with respect to a state constraint. Returns whether the configuration belongs to the state. Calls core::ConstraintSet::isSatisfied for the state constraints. |
def getConfigErrorForTransition(self, arg2: Transition, arg3: numpy.ndarray) -> tuple | Get error of a config with respect to a transition constraint. Returns whether the configuration belongs to the transition. Calls core::ConfigProjector::rightHandSideFromConfig with the input configuration and then core::ConstraintSet::isSatisfied on the transition constraints. |
def getConfigErrorForTransitionLeaf(self, arg2: Transition, arg3: numpy.ndarray, arg4: numpy.ndarray) -> tuple | Get error of a config with respect to a transition foliation leaf. Returns whether config can be the end point of a path of the transition starting at leafConfig. |
def getConfigErrorForTransitionTarget(self, arg2: Transition, arg3: numpy.ndarray, arg4: numpy.ndarray) -> tuple | Get error of a config with respect to the target of a transition foliation leaf. Returns whether config can be the end point of a path of the transition starting at leafConfig. |
def getContainingNode(self, arg2: Transition) -> str | Get the name of the state in which a transition is. Paths satisfying the transition constraints satisfy the state constraints. |
def getNodesConnectedByTransition(self, arg2: Transition) -> tuple | Get the names of the states connected by a transition. |
def getNumericalConstraintsForEdge(self, arg2: Transition) -> list | Get numerical constraints of an edge. |
def getNumericalConstraintsForGraph(self) -> list | Get numerical constraints of the graph. |
def getNumericalConstraintsForState(self, arg2: State) -> list | Get numerical constraints of a state. |
def getRelativeMotionMatrix(self, arg2: Transition) -> list | Get relative motion matrix for a transition as list of lists. |
def getSecurityMarginMatrixForTransition(self, arg2: Transition) -> list | Get security margin matrix for a transition as list of lists. |
def getState(self, arg2: str) -> State | Return the state with the given name. |
def getStateFromConfiguration(self, arg2: numpy.ndarray) -> str | Get the name of the state corresponding to the configuration. |
def getStateNames(self) -> list | Return a list of state names. |
def getStates(self) -> list | Return a list of all states in the constraint graph. |
def getTransition(self, arg2: str) -> Transition | Return the transition with the given name. |
def getTransitionNames(self) -> list | Return a list of transition names. |
def getTransitions(self) -> list | Return a list of all transitions in the constraint graph. |
def getWeight(self, arg2: Transition) -> int | Get weight of a transition. |
def initialize(self) -> None | Initialize the graph. Performs final initialization of the constraint graph. |
def isShort(self, arg2: Transition) -> bool | Check if a transition is short. |
| Get maximal number of iterations in config projector. |
def registerConstraints(self, arg2: pyhpp.constraints.bindings.Implicit, arg3: pyhpp.constraints.bindings.Implicit, arg4: pyhpp.constraints.bindings.Implicit) -> None | Register constraints in the graph. |
def removeCollisionPairFromTransition(self, arg2: Transition, arg3: str, arg4: str) -> None | Remove collision pairs from a transition. |
def resetConstraints(self, arg2: State) -> None | Reset constraints of a state. |
def setContainingNode(self, arg2: Transition, arg3: State) -> None | Set in which state a transition is. Paths satisfying the transition constraints satisfy the state constraints. |
def setSecurityMarginForTransition(self, arg2: Transition, arg3: str, arg4: str, arg5: float) -> None | Set collision security margin for a pair of joints along a transition. |
def setShort(self, arg2: Transition, arg3: bool) -> None | Set that a transition is short. When a transition is tagged as short, extension along this transition is done differently in RRT-like algorithms. Instead of projecting a random configuration in the destination state, the configuration to extend itself is projected in the destination state. This makes the rate of success higher. |
def setTargetNodeList(self, arg2: list) -> None | Set the target state list for guided state selection. |
def setWaypoint(self, arg2: Transition, arg3: pyhpp.core.path.bindings.SplineB3, arg4: Transition, arg5: State) -> None | Set waypoint configuration for a waypoint transition. Configures which edge and state to use at the specified waypoint index. |
def setWeight(self, arg2: Transition, arg3: pyhpp.core.path.bindings.SplineB3) -> None | Set weight of a transition. You cannot set weight for waypoint transitions. |
| Return the transition used at a given parameter on a path (static method). |
| The robot device of the constraint graph. |
GraphSteeringMethod
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.SteeringMethod) -> None |
Handle
Frame attached to an object that is aimed at being grasped
Together with a hpp::pinocchio::Gripper, a handle defines a grasp. A vector of 6 Boolean values called a mask can be passed to the constructor to define the symmetries of the handle. For example, {True,True,True,False,True,True} means that the handle can be grasped with free orientation around x-axis. See https://hal.laas.fr/hal-02995125v2 for details. The setter method mask allows users to define the mask.
Along motions where the handle is grasped by a gripper, an additional constraint is enforced, called the complement constraint. This latter constraint ensures that the object is rigidly fixed to the gripper.
However, for some applications, the complement constraint can be customized using setter maskComp. Note that calling setter method mask reinitializes the mask complement.
| def | Description |
|---|---|
def createGrasp(self, gripper: pyhpp.pinocchio.bindings.Gripper, name: str) -> pyhpp.constraints.bindings.Implicit | gripper — object containing the gripper information |
def createGraspAndComplement(self, gripper: pyhpp.pinocchio.bindings.Gripper, name: str) -> pyhpp.constraints.bindings.Implicit | gripper — object containing the gripper information |
def createGraspComplement(self, gripper: pyhpp.pinocchio.bindings.Gripper, name: str) -> pyhpp.constraints.bindings.Implicit | gripper — object containing the gripper information |
def createPreGrasp(self, gripper: pyhpp.pinocchio.bindings.Gripper, shift: float, name: str) -> pyhpp.constraints.bindings.Implicit | gripper — object containing the gripper information |
def getParentJointId(self) -> int | Get index of the joint the handle is attached to in pinocchio Model |
| Approaching direction for pregrasp (unit vector in handle frame, default is x-axis). |
| Distance from the center of the gripper along x-axis that ensures no collision. Also gives an order of magnitude of the gripper size. |
| Local position of the handle in the joint frame. |
| Constraint mask: vector<bool> of size 6 defining the symmetries of the handle. See Handle class documentation for details. |
| Mask of the complement constraint. |
| Name of the handle. |
HandleMap
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, key: str) -> None | |
def getitem(self, key: str) -> Handle | |
def init(self) -> None | |
def iter(self) -> typing.Iterator[str] | |
def len(self) -> int | |
def setitem(self, key: str, value: Handle) -> None |
ManipulationPlanner
Inherits: pyhpp.core.bindings.PathPlanner
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.Problem) -> None |
Problem
Inherits: pyhpp.core.bindings.Problem
| def | Description |
|---|---|
def init(self, arg2: Device) -> None | |
def checkProblem(self) -> None | Check whether the problem is well formulated. |
| Get the graph of constraints. |
def fullSteeringMethod(self, arg2: pyhpp.core.bindings.SteeringMethod) -> None | Set the problem steering method directly. Unlike steeringMethod, this does not wrap the given steering method in a manipulation graph steering method. |
| Get the inner steering method (unwrapped from the graph steering method if applicable). |
RandomShortcut
Inherits: pyhpp.core.bindings.PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: object) -> object |
SplineGradientBased_bezier1
Inherits: pyhpp.core.bindings.PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.Problem) -> object | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
SplineGradientBased_bezier3
Inherits: pyhpp.core.bindings.PathOptimizer
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.Problem) -> object | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
State
State of an end-effector.
States of the graph of constraints. There is one graph for each end-effector.
| def | Description |
|---|---|
def configConstraint(self) -> pyhpp.core.bindings.ConstraintSet | |
def id(self) -> int | Return the component id. |
def name(self) -> str | Get the component name. |
def neighborEdges(self) -> list | Get the list of edges connected to this state. |
StatesPathFinder
Inherits: pyhpp.core.bindings.PathPlanner
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.Problem) -> None |
Transition
Transition between two states of a constraint graph
An edge stores two types of constraints.
Path constraints should be safisfied by paths belonging to the edge. Along any path, the right hand side of the constraint is constant, but can differ between paths. For instance if an edge represents a transit path of a robot that can grasp an object, the right hand side of the constraint represents the position of the object. Along any transit path, the object does not move, but for different paths the object can be at different positions. method pathConstraint.
Configuration constraints are constraints that configurations in the destination state should satisfy and the constraints that paths should satisfy. For instance, if the edge links a state where the robot does not hold the object to a state where the robot holds the object, the configuration constraints represent a fixed relative position of the object with respect to the gripper and a stable position of the object. Configuration constraints are necessary to generate a configuration in the destination state of the edge that is reachable from a given configuration in the start state by an admissible path.
| def | Description |
|---|---|
def id(self) -> int | Return the component id. |
def isWaypointTransition(self) -> bool | Error — Could not find member (.*) isWaypointEdge of class hpp::manipulation::graph::Edge |
def name(self) -> str | Get the component name. |
| Error — Could not find member (.*) nbWaypoints of class hpp::manipulation::graph::Edge |
def pathValidation(self) -> pyhpp.core.bindings.PathValidation | Get path validation associated to the edge. |
def waypoint(self, arg2: pyhpp.core.path.bindings.SplineB3) -> Transition | Error — Could not find member (.*) waypoint of class hpp::manipulation::graph::Edge |
TransitionPlanner
Inherits: pyhpp.core.bindings.PathPlanner
Plan paths in a leaf of a transition
In many manipulation applications, the sequence of actions is knwown in advance or computed by a task planner. There is a need then to connect configurations that lie on the same leaf of a transition. This class performs this computation.
The constraint graph is stored in the Problem instance of the planner. To select the transition, call method setEdge with the index of the transition.
At construction, a core::Problem instance is created, as well as a core::PathPlanner instance. They are respectively called the inner problem and the inner planner.
In order to take into account security margins, when selecting a transition, the list of configuration validations passed to the inner problem are
the PathValidation instance of the transition, cast into core::ConfigValidation type
a core::JointBoundValidation instance.
The leaf of the transition is defined by the initial configuration passed to method planPath . The right hand side of the inner problem constraints is initialized with this configuration.
The class stores path optimizers that are called when invoking method optimizePath .
Method timeParameterization computes a time parameterization of a given path.
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.Problem) -> None | |
def addPathOptimizer(self, pathOptimizer: pyhpp.core.bindings.PathOptimizer) -> None | |
def clearPathOptimizers(self) -> None | Clear path optimizers. |
def computePath(self, arg2: numpy.ndarray, arg3: numpy.ndarray, self_: bool) -> pyhpp.core.path.bindings.Vector | |
def directPath(self, arg2: numpy.ndarray, arg3: numpy.ndarray, arg4: bool) -> tuple | Compute a direct path on a transition. Returns (success, path, status). |
| Get the inner planner. |
def innerProblem(self) -> pyhpp.core.bindings.Problem | Get the inner problem. |
def optimizePath(self, path: pyhpp.core.bindings.Path) -> pyhpp.core.path.bindings.Vector | :param :input path |
def pathProjector(self, pathProjector: pyhpp.core.bindings.PathProjector) -> None | Set the path projector. |
def planPath(self, qInit: numpy.ndarray, qGoals: numpy.ndarray, resetRoadmap: bool) -> pyhpp.core.path.bindings.Vector | qInit — initial configuration, :param qGoals goal:configurations, resetRoadmap — whether to reset the roadmap |
def setEdge(self, id: Transition) -> None | id — index of the transition in the constraint graph |
def setReedsAndSheppSteeringMethod(self, turningRadius: float) -> None | Create a Reeds and Shepp steering method and path it to the problem. |
def setTransition(self, id: Transition) -> None | id — index of the transition in the constraint graph |
def timeParameterization(self, path: pyhpp.core.path.bindings.Vector) -> pyhpp.core.path.bindings.Vector | :param :input path |
def validateConfiguration(self, arg2: numpy.ndarray, arg3: int) -> tuple | Validate configuration against the graph state identified by id. Returns (valid, report). |
map_indexing_suite_HandleMap_entry
| def | Description |
|---|---|
def init(self) -> None | |
def repr(self) -> object | |
def data(self) -> Handle | |
def key(self) -> str |
modelsInfo
| def | Description |
|---|---|
def init(self) -> None | |
| |
| |
| |
|
modelsInfoVec
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, arg2: object) -> None | |
def getitem(self, arg2: object) -> object | |
def init(self) -> None | |
def iter(self) -> object | |
def len(self) -> int | |
def setitem(self, arg2: object, arg3: object) -> None | |
def append(self, arg2: object) -> None | |
def extend(self, arg2: object) -> None |
pyhpp.manipulation.urdf
Functions
| def | Description |
|---|---|
def loadModel(arg1: pyhpp.manipulation.bindings.Device, arg2: int, arg3: str, arg4: str, arg5: str, arg6: str, arg7: pinocchio.pinocchio_pywrap_default.SE3) -> None | Load a robot model from URDF/SRDF files into a manipulation Device, also parsing grasp/contact data from the SRDF. |
def loadModelFromString(arg1: pyhpp.manipulation.bindings.Device, arg2: int, arg3: str, arg4: str, arg5: str, arg6: str, arg7: pinocchio.pinocchio_pywrap_default.SE3) -> None | Load a robot model from URDF/SRDF XML strings into a manipulation Device, also parsing grasp/contact data from the SRDF. |
pyhpp.manipulation.steering_method
Functions
| def | Description |
|---|---|
def makePiecewiseLinearTrajectory(arg1: numpy.ndarray, arg2: numpy.ndarray) -> pyhpp.core.bindings.Path | Build a piecewise linear path. See C++ documentation of class hpp::manipulation::steeringMethod::Cartesian. |
Cartesian
Build a robot trajectory from an end-effector trajectory
This class does not derive from SteeringMethod since it does not link two configurations by a path. Instead, it only takes an initial configuration and a trajectory of an end-effector.
To use this class, the user needs to provide
a constraint with value in . An easy way to create such a constraint is to use method hpp::manipulation::Handle::createGrasp. The constraint is passed to this class using method trajectoryConstraint .
the time-varying right hand side of this constraint along the path the user wants to create in the form of a hpp::core::Path instance with values in . For that, makePiecewiseLinearTrajectory method may be useful.
Once the steering method has been initialized, it can be called with and initial configuration q_init. The interval of definition of the output path is the same as the one of the path provided as the right hand side of the constraint. Note that q_init should satisfy the constraint at times 0.
| def | Description |
|---|---|
def init(self, arg2: pyhpp.core.bindings.Problem) -> None | |
def getRightHandSide(self) -> pyhpp.constraints.bindings.DifferentiableFunction | Get right hand side function of trajectory constraint. |
def planPath(self, arg2: numpy.ndarray) -> tuple | Plan a path starting from an initial configuration. |
| Set right hand side from a hpp::core::Path |
def timeRange(self) -> pyhpp.core.bindings.interval | Get interval of definition of right hand side of trajectory constraint. |
| Error threshold of numerical solver. |
| Maximal number of iterations of numerical solver. |
| Number of discretization steps in the interval of definition where configurations are computed. |
| Constraint with a time-varying right hand side. |
pyhpp.pinocchio
ComputationFlag
Inherits: int
Device
Robot with geometric and dynamic pinocchio.
The creation of the device is done by Device::create(const
std::string name). This function returns a shared pointer to the newly created object. Smart pointers documentation: http://www.boost.org/libs/smart_ptr/smart_ptr.htm
| def | Description |
|---|---|
def init(self, arg2: str) -> object | |
def computeForwardKinematics(self, self_: int) -> None | Compute forward kinematics computing everything. |
def computeFramesForwardKinematics(self) -> None | |
def configSize(self) -> int | |
def configSpace(self) -> LiegroupSpace | Returns a LiegroupSpace representing the configuration space. |
| Get current configuration. |
def data(self) -> pinocchio.pinocchio_pywrap_default.Data | |
def geomData(self) -> pinocchio.pinocchio_pywrap_default.GeometryData | |
def geomModel(self) -> pinocchio.pinocchio_pywrap_default.GeometryModel | |
def getCenterOfMass(self) -> numpy.ndarray | |
def getJointPosition(self, arg2: str) -> list | |
def getJointsPosition(self, arg2: numpy.ndarray, arg3: list) -> list | |
def model(self) -> pinocchio.pinocchio_pywrap_default.Model | |
def name(self) -> str | Get name of device. |
def numberDof(self) -> int | |
def removeJoints(self, arg2: pinocchio.pinocchio_pywrap_default.StdVec_StdString, arg3: numpy.ndarray) -> None | |
def setJointBounds(self, arg2: str, arg3: list) -> None | |
def updateGeometryPlacements(self) -> None | Update the geometry placement to the currentConfiguration. |
def visualModel(self) -> pinocchio.pinocchio_pywrap_default.GeometryModel | |
|
Gripper
Definition of a robot gripper
This class represent a robot gripper as a frame attached to the joint of the robot that holds the gripper.
To graps a box-shaped object with small lengths along x and y, the gripper frame should coincide with the object frame.
| def | Description |
|---|---|
def getParentJointId(self) -> int | Get index of the joint the handle is attached to in pinocchio Model |
def name(self) -> str | |
| |
|
GripperMap
| def | Description |
|---|---|
def contains(self, arg2: object) -> bool | |
def delitem(self, key: str) -> None | |
def getitem(self, key: str) -> Gripper | |
def init(self) -> None | |
def iter(self) -> typing.Iterator[str] | |
def len(self) -> int | |
def setitem(self, key: str, value: Gripper) -> None |
LiegroupElement
hpp::pinocchio::LiegroupElement
| def | Description |
|---|---|
def add(self, arg2: numpy.ndarray) -> object | |
| |
def str(self) -> str | |
def sub(self, arg2: LiegroupElement) -> object | |
def space(self) -> LiegroupSpace | list index out of range |
def vector(self) -> numpy.ndarray | list index out of range |
|
LiegroupElementRef
hpp::pinocchio::LiegroupElementRef
| def | Description |
|---|---|
def add(self, arg2: numpy.ndarray) -> object | |
def init(self, arg2: numpy.ndarray, arg3: LiegroupSpace) -> None | |
def str(self) -> str | |
def sub(self, arg2: LiegroupElementRef) -> object | |
def space(self) -> LiegroupSpace | list index out of range |
def vector(self) -> numpy.ndarray | list index out of range |
|
LiegroupSpace
Cartesian product of elementary Lie groups
Some values produced and manipulated by functions belong to Lie groups For instance rotations, rigid-body motions are element of Lie groups.
Elements of Lie groups are usually applied common operations, like
integrating a velocity from a given element during unit time,
computing the constant velocity that moves from one element to another one in unit time.
By analogy with vector spaces that are a particular type of Lie group, the above operations are implemented as operators + and - respectively acting on LiegroupElement instances.
This class represents a Lie group as the cartesian product of elementaty Lie groups. Those elementary Lie groups are gathered in a variant called LiegroupType.
Elements of a Lie group are represented by class LiegroupElement.
| def | Description |
|---|---|
| rotation — whether values of this space represent angles or lengths. |
| Return as a Lie group. |
| Return . |
| Return as a Lie group. |
| Return . |
| n — dimension of vector space |
| Return . |
| Return . |
def eq(self, arg2: LiegroupSpace) -> object | |
def imul(self, arg2: LiegroupSpace) -> LiegroupSpace | |
def mul(self, arg2: LiegroupSpace) -> LiegroupSpace | |
def ne(self, arg2: LiegroupSpace) -> object | |
def str(self) -> str | |
def dDifference_dq0(self, arg2: object, arg3: numpy.ndarray, arg4: numpy.ndarray, arg5: numpy.ndarray) -> None | |
def dDifference_dq1(self, arg2: object, arg3: numpy.ndarray, arg4: numpy.ndarray, arg5: numpy.ndarray) -> None | |
| |
| |
| Return empty Lie group. |
def mergeVectorSpaces(self) -> None | |
def name(self) -> str | Return name of Lie group. |
map_indexing_suite_GripperMap_entry
| def | Description |
|---|---|
def init(self) -> None | |
def repr(self) -> object | |
def data(self) -> Gripper | |
def key(self) -> str |
pyhpp.pinocchio.urdf
Functions
| def | Description |
|---|---|
def loadModel(arg1: object, arg2: int, arg3: str, arg4: str, arg5: str, arg6: str, arg7: pinocchio.pinocchio_pywrap_default.SE3) -> None | |
def loadModelFromString(arg1: object, arg2: int, arg3: str, arg4: str, arg5: str, arg6: str, arg7: pinocchio.pinocchio_pywrap_default.SE3) -> None |
HPP-gepetto-viewer
HPP Plot
hpp-exec
ROS2 execution utilities for HPP-generated trajectories.
Overview
You write your HPP planning script using pyhpp directly, then use hpp_exec to send the trajectory to ros2_control.
Tutorials
The official tutorials for this package are in hpp-tutorial:
- Tutorial 6: Plan a simple arm motion and execute on Gazebo via
send_trajectory() - Tutorial 7: Pick-and-place with graph segments, gripper actions, and
execute_segments() - Tutorial 8: Pick-and-place while opening the gripper during arm travel
Documentation
- Generated Doxygen documentation: user reference for the API, execution model, and troubleshooting.
Creating configs and times from HPP
After planning and time parameterization with HPP, you have a Path object that maps time (seconds) to robot configurations. For a plain arm trajectory, sample it at regular intervals to get configs:
import numpy as np
from pyhpp.core import TrapezoidalTimeParameterization
# After solving:
# path = planner.solve()
optimizer = TrapezoidalTimeParameterization(problem)
optimizer.maxVelocity = 0.5
optimizer.maxAcceleration = 0.5
p_timed = optimizer.optimize(path)
n_samples = 50
configs = []
times = []
for i in range(n_samples + 1):
t = (i / n_samples) * p_timed.length()
q, success = p_timed(t)
if success:
configs.append(np.array(q))
times.append(t)
# configs: List[np.ndarray] - configuration vectors at each sample
# times: List[float] - timestamps in seconds
The HPP configuration vector typically includes all robot DOFs. Use joint_indices to select which joints to send to ros2_control (e.g., arm joints only, excluding fingers).
Sending to ros2_control
from hpp_exec import send_trajectory
send_trajectory(
configs, times,
joint_names=["joint1", "joint2", ...], # ROS2 joint names
joint_indices=list(range(7)), # Which HPP config indices to use
)
Installation
Docker (recommended)
cd hpp-exec
./run.sh
# First time inside container:
cd ~/devel/src && make all
API
from hpp_exec import (
BackgroundAction,
Segment,
execute_segments,
read_current_configuration,
segments_by_transition,
print_segments,
send_trajectory,
segments_from_graph,
)
# Main function - send trajectory to ros2_control
send_trajectory(
configs, # List[np.ndarray] from HPP
times, # List[float] timestamps in seconds
joint_names, # List[str] ROS2 joint names
controller_topic="...", # FollowJointTrajectory action topic
)
# Expose the HPP graph segments.
configs, times, segments = segments_from_graph(path, graph)
print_segments(segments)
# Inspect every occurrence of each graph transition.
segments_by_name = segments_by_transition(segments)
segments_by_name["fr3/gripper > box/handle | f_23"][0].pre_actions.append(grasp_box)
segments_by_name["fr3/gripper < box/handle | 0-0_21"][0].pre_actions.append(
release_box
)
# Or overlap a blocking action with the next segment's arm motion.
background_open = BackgroundAction(open_gripper, name="open_gripper")
segments[0].pre_actions.append(background_open.start)
segments[2].pre_actions.append(background_open.wait)
segments[2].pre_actions.append(close_gripper)
execute_segments(
segments,
configs,
times,
joint_names,
)
# Dictionary API: instead of the manual appends above, leave segments
# unchanged and attach actions by graph transition name when starting execution.
# This applies each action to every segment with that transition name.
pre_actions = {
"fr3/gripper > box/handle | f_23": [grasp_box],
}
post_actions = {
"fr3/gripper < box/handle | 0-0_21": [release_box],
}
execute_segments(
segments,
configs,
times,
joint_names,
pre_actions_by_transition=pre_actions,
post_actions_by_transition=post_actions,
)
# Read the robot state before planning from the live position.
q_start = read_current_configuration(
node,
joint_names=["joint1", "joint2", ...],
topic="/joint_states",
)
See the generated Doxygen documentation for send_trajectory_async(),
configs_to_joint_trajectory(), and other lower-level helpers.
Tutorials
The maintained end-to-end examples live in hpp_tutorial.
cd ~/devel/src/hpp_tutorial/tutorial_6
python -i init.py
See tutorial 6 for simple arm execution, tutorial 7 for pick-and-place with graph segments, and tutorial 8 for overlapping a gripper action with arm travel.
Structure
hpp-exec/
|-- hpp_exec/ # Python package
| |-- __init__.py
| |-- actions.py # Reusable helpers for segment actions
| |-- joint_state.py # Read JointState messages as ordered configs
| |-- segments.py # Segment data structure
| |-- trajectory_utils.py # HPP config to ROS2 JointTrajectory conversion
| |-- ros2_sender.py # send_trajectory() via FollowJointTrajectory action
| `-- graph_segments.py # Graph segment extraction and display
|-- scripts/ # Launch scripts for Gazebo
|-- robots/ # URDF/SRDF assets
|-- docker/
|-- Dockerfile
`-- run.sh
License
BSD-2-Clause