Merge pull request #1 from robotlearn/master

Update
This commit is contained in:
dbonattoj
2019-07-08 17:22:47 +02:00
committed by GitHub
423 changed files with 65232 additions and 2504 deletions
-147
View File
@@ -1,147 +0,0 @@
# PyRoboLearn
This repository contains the code for the *PyRoboLearn* (PRL) framework: a Python framework for Robot Learning.
This framework revolves mainly around 7 axes: simulators, worlds, robots, interfaces, learning tasks (= environment and policy), learning models, and learning algorithms.
**Warning**: The development of this framework is ongoing, and thus some substantial changes might occur. Sorry for the inconvenience.
## Requirements
The framework has been tested with Python 2.7 and Ubuntu 16.04 and 18.04. We also tested parts of it with Python 3.5 on Ubuntu 16.04 and so far so good, but there might be some errors that escaped my attention.
## Installation
### Docker
At the moment the docker is a self contained Ubuntu image with all the libraries installed. When launched we have access to a Python3.6 interpreter and we can import pyrobolearn directly.
In the future, ROS may be splitted in another container and linked to this one.
1. Install Docker and nvidia-docker
```bash
$ sudo apt-get update
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable # you should replace bionic by your version
$ sudo apt update
$ sudo apt install docker-ce
$ sudo systemctl status docker # check that docker is active
```
2. Build the image
```bash
$ docker build -t pyrobolearn .
```
3. Launch
You can now start the python interpreter with every library already installed
```bash
$ docker run -p 11311:11311 -v $PWD/dev:/pyrobolearn/dev/:rw -ti pyrobolearn python3
```
To open an interactive terminal in the docker image use:
```bash
$ docker run -p 11311:11311 -v $PWD/dev:/pyrobolearn/dev/:rw -ti pyrobolearn /bin/bash
```
4. nvidia-docker
if the GPU is not recognized in the interpreter, you can install nvidia-docker
```bash
$ curl -sL https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -sL https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
$ sudo apt-get update
$ sudo apt-get install nvidia-docker2
sudo pkill -SIGHUP dockerd
```
And use:
```bash
$ nvidia-docker run -p 11311:11311 -v $PWD/dev:/pyrobolearn/dev/:rw -ti pyrobolearn
```
### Ubuntu
1. First download the `pip` Python package manager and create a virtual environment for Python as described in the following link: https://packaging.python.org/guides/installing-using-pip-and-virtualenv/
On Ubuntu, you can install `pip` and `virtualenv` by typing in the terminal:
- In Python 2.7:
```bash
sudo apt install python-pip
sudo pip install virtualenv
```
- In Python 3.5:
```bash
sudo apt install python3-pip
sudo pip install virtualenv
```
You can then create the virtual environment by typing:
```bash
virtualenv -p /usr/bin/python<version> <virtualenv_name>
# activate the virtual environment
source <virtualenv_name>/bin/activate
```
where `<version>` is the python version you want to use (select between `2.7` or `3.5`), and `<virtualenv_name>` is a name of your choice for the virtual environment. For instance, it can be `py2.7` or `py3.5`.
To deactivate the virtual environment, just type:
```bash
deactivate
```
2. clone this repository and install the requirements by executing the setup.py
In Python 2.7:
```bash
git clone https://github.com/robotlearn/pyrobolearn
cd pyrobolearn
pip install numpy cython
pip install http://github.com/cornellius-gp/gpytorch/archive/alpha.zip # this is for Python 2.7
pip install -e . # this will install pyrobolearn as well as the required packages (so no need for: pip install -r requirements.txt)
```
In Python 3.5:
```bash
git clone https://github.com/robotlearn/pyrobolearn
cd pyrobolearn
pip install numpy cython
pip install gpytorch # this is for Python 3.5
pip install -e . # this will install pyrobolearn as well as the required packages (so no need for: pip install -r requirements.txt)
```
Depending on your computer configuration and the python version you use, you might need to install also the following packages through `apt-get`:
```bash
sudo apt install python-tk # if python 2.7
sudo apt install python3-tk # if python 3.5
```
## How to use it?
Check the `README.md` file in the `examples` folder.
## Citation
```
@misc{delhaisse2019pyrobolearn,
author = {Delhaisse, Brian and Xin, Songyan and Rozo, Leonel, and Caldwell, Darwin},
title = {PyRoboLearn: A Python Framework for Robot Learning Practitioners},
howpublished = {\url{https://github.com/robotlearn/pyrobolearn}},
year=2019,
}
```
If you use a specific learning model, algorithm, robot, controller, and so on, please cite the corresponding paper. The reference(s) can usually be found in the class documentation (at the end), and sometimes in the README file in the corresponding folder.
## Acknowledgements
Currently, we mainly use the PyBullet simulator.
- *PyBullet, a Python module for physics simulation for games, robotics and machine learning*,
Erwin Coumans and Yunfei Bai, 2016-2019
- references for each robot, model, and others can be found in the corresponding class documentation
- Locomotion controllers were provided by Songyan Xin (see `pyrobolearn/controllers/locomotion`).
+174
View File
@@ -0,0 +1,174 @@
PyRoboLearn
===========
This repository contains the code for the *PyRoboLearn* (PRL) framework: a Python framework for Robot Learning.
This framework revolves mainly around 7 axes: simulators, worlds, robots, interfaces, learning tasks (= environment and policy), learning models, and learning algorithms.
**Warning**: The development of this framework is ongoing, and thus some substantial changes might occur. Sorry for the inconvenience.
Requirements
------------
The framework has been tested with Python 2.7 and Ubuntu 16.04 and 18.04. We also tested parts of it with Python 3.5 on Ubuntu 16.04 and so far so good, but there might be some errors that escaped my attention.
Installation
------------
Docker
~~~~~~
At the moment the docker is a self contained Ubuntu image with all the libraries installed. When launched we have access to a Python3.6 interpreter and we can import pyrobolearn directly.
In the future, ROS may be splitted in another container and linked to this one.
1. Install Docker and nvidia-docker
.. code-block:: bash
sudo apt-get update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable # you should replace bionic by your version
sudo apt update
sudo apt install docker-ce
sudo systemctl status docker # check that docker is active
2. Build the image
.. code-block:: bash
docker build -t pyrobolearn .
3. Launch
You can now start the python interpreter with every library already installed
.. code-block:: bash
docker run -p 11311:11311 -v $PWD/dev:/pyrobolearn/dev/:rw -ti pyrobolearn python3
To open an interactive terminal in the docker image use:
.. code-block:: bash
docker run -p 11311:11311 -v $PWD/dev:/pyrobolearn/dev/:rw -ti pyrobolearn /bin/bash
4. nvidia-docker
if the GPU is not recognized in the interpreter, you can install nvidia-docker
.. code-block:: bash
curl -sL https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -sL https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install nvidia-docker2
sudo pkill -SIGHUP dockerd
And use:
.. code-block:: bash
nvidia-docker run -p 11311:11311 -v $PWD/dev:/pyrobolearn/dev/:rw -ti pyrobolearn
Ubuntu
~~~~~~
1. First download the ``pip`` Python package manager and create a virtual environment for Python as described in the following link: https://packaging.python.org/guides/installing-using-pip-and-virtualenv/
On Ubuntu, you can install ``pip`` and ``virtualenv`` by typing in the terminal:
- In Python 2.7:
.. code-block:: bash
sudo apt install python-pip
sudo pip install virtualenv
- In Python 3.5:
.. code-block:: bash
sudo apt install python3-pip
sudo pip install virtualenv
You can then create the virtual environment by typing:
.. code-block:: bash
virtualenv -p /usr/bin/python<version> <virtualenv_name>
# activate the virtual environment
source <virtualenv_name>/bin/activate
where ``<version>`` is the python version you want to use (select between ``2.7`` or ``3.5``), and ``<virtualenv_name>`` is a name of your choice for the virtual environment. For instance, it can be ``py2.7`` or ``py3.5``.
To deactivate the virtual environment, just type:
.. code-block:: bash
deactivate
2. clone this repository and install the requirements by executing the ``setup.py``
In Python 2.7:
.. code-block:: bash
git clone https://github.com/robotlearn/pyrobolearn
cd pyrobolearn
pip install numpy cython
pip install http://github.com/cornellius-gp/gpytorch/archive/alpha.zip # this is for Python 2.7
pip install -e . # this will install pyrobolearn as well as the required packages (so no need for: pip install -r requirements.txt)
In Python 3.5:
.. code-block:: bash
git clone https://github.com/robotlearn/pyrobolearn
cd pyrobolearn
pip install numpy cython
pip install gpytorch # this is for Python 3.5
pip install -e . # this will install pyrobolearn as well as the required packages (so no need for: pip install -r requirements.txt)
Depending on your computer configuration and the python version you use, you might need to install also the following packages through ``apt-get``:
.. code-block:: bash
sudo apt install python-tk # if python 2.7
sudo apt install python3-tk # if python 3.5
How to use it?
--------------
Check the ``README.rst`` file in the ``examples`` folder.
Citation
--------
.. code-block:: latex
@misc{delhaisse2019pyrobolearn,
author = {Delhaisse, Brian and Xin, Songyan and Rozo, Leonel, and Caldwell, Darwin},
title = {PyRoboLearn: A Python Framework for Robot Learning Practitioners},
howpublished = {\url{https://github.com/robotlearn/pyrobolearn}},
year=2019,
}
If you use a specific learning model, algorithm, robot, controller, and so on, please cite the corresponding paper. The reference(s) can usually be found in the class documentation (at the end), and sometimes in the README file in the corresponding folder.
Acknowledgements
----------------
Currently, we mainly use the PyBullet simulator.
- *PyBullet, a Python module for physics simulation for games, robotics and machine learning*, Erwin Coumans and Yunfei Bai, 2016-2019
- references for each robot, model, and others can be found in the corresponding class documentation
- Locomotion controllers were provided by Songyan Xin (see ``pyrobolearn/controllers/locomotion``)
+19
View File
@@ -0,0 +1,19 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

+35
View File
@@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# . venv/bin/activate
rm -Rf build
rm -Rf source/docstring
sphinx-apidoc -f -o source/docstring/ ../pyrobolearn
make html
+28
View File
@@ -0,0 +1,28 @@
Actions
=======
In PRL, every concept is modelized as a class. This is also true for actions which are used by the policies.
.. figure:: ../figures/environment.png
:alt: environment
:align: center
The agent-environment interaction
Design
------
How to use a particular action?
------------------------------
example of actions with robot
How to create your own action?
------------------------------
FAQs
----
+2
View File
@@ -0,0 +1,2 @@
Algorithms
==========
+14
View File
@@ -0,0 +1,14 @@
Approximators
=============
An ``Approximator`` accepts as inputs the ``State``, ``Action``, and learning ``Model``, and connects them.
Approximators are used by other classes in the PRL framework.
How to use an approximator?
---------------------------
How to create your own approximator?
------------------------------------
+187
View File
@@ -0,0 +1,187 @@
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../..'))
# -- Project information -----------------------------------------------------
project = u'PyRoboLearn'
copyright = u'2019, Brian Delhaisse'
author = u'Brian Delhaisse'
# The short X.Y version
version = u''
# The full version, including alpha/beta/rc tags
release = u'0.0.1'
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'sphinx.ext.githubpages',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme' # 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'PyRoboLearndoc'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'PyRoboLearn.tex', u'PyRoboLearn Documentation',
u'Brian Delhaisse', 'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'pyrobolearn', u'PyRoboLearn Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'PyRoboLearn', u'PyRoboLearn Documentation',
author, 'PyRoboLearn', 'One line description of project.',
'Miscellaneous'),
]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# -- Extension configuration -------------------------------------------------
# -- Options for intersphinx extension ---------------------------------------
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}
+157
View File
@@ -0,0 +1,157 @@
Environments
============
The environment is one of the main concept in imitation and reinforcement learning as defined in the following figures (inspired by [1]_):
.. figure:: ../figures/environment.png
:alt: environment
:align: center
The agent-environment interaction
The environment is notably responsible to perform a step in the world, compute the next state, compute the rewards, and others.
Design
------
In PRL, the environment is an abstraction layer class that regroups:
- the world; an instance of ``World`` which will be used to perform a step in the world (simulator). This is called at each step performed by the environment.
- the states: an instance of ``State`` (or a list of them). The states are updated at each time step by the environment.
- the rewards (optional): an instance of ``Reward`` (or a list of them). It is optional because some environments like in imitation learning does not require a reward function. The reward functions are computed at each time step.
- the terminal conditions (optional): an instance of ``TerminalCondition`` (or a list of them) that checks at each time step if the goal of the environment has been achieved. A ``TerminalCondition`` also details if the environment ended with a success or failure.
- the initial state generators (optional): an instance of ``StateGenerator`` (or a list of them) which are called to generate the initial states each time the environment is reset.
- the physics randomizers (optional): an instance of ``PhysicsRandomizer`` (or a list of them) to randomize the physical properties of bodies in the simulator, or the simulator itself, each time the environment is reset.
- the actions (optional): an instance of ``Action`` (or a list of them). The actions are not used nor updated by the environment. This is left to the ``Policy`` or ``Controller``.
By favoring `composition over inheritance <https://en.wikipedia.org/wiki/Composition_over_inheritance>`_ for the environment class, we improve the flexibility of the framework and the reuse of different modules. This leads ultimately to less code duplication, and ease the process of creating environments.
.. figure:: ../UML/environment.png
:alt: UML diagram for Environment
:align: center
UML diagram for environment
How to use an environment?
--------------------------
Let's assume that you have an environment where you have a manipulator, and the goal is to reach an object (such as a cube) on a table.
Here is a short snippet showing the basic usage of an environment:
.. code-block:: python
:linenos:
import pyrobolearn as prl
# define the simulator and world (and load what you want in it)
sim = ...
world = ...
robot = ...
# define state, action, and reward (and possibly action)
state = ...
action = ...
reward = ...
# you can give the reward function to your RL environment
# which will use it when calling `env.step()`.
env = prl.envs.Env(world, state, reward)
# like in OpenAI gym environments, you can reset and step in the environment
obs = env.reset()
for t in count():
obs, rew, done, info = env.step()
Few notes regarding the code above:
- the ``action`` can also be given to the environment but it won't be called by the environment. This is carried out by the policy(ies)/agent(s). The main reason why you can give an action to an environment is when later you will create your own environment class (that inherits from ``prl.envs.Env``), you will be able to get the states and actions for your policies in the following way:
.. code-block:: python
:linenos:
import pyrobolearn as prl
# define your environment
class MyEnv(prl.envs.Env):
...
# create the environment and provide possible arguments
env = MyEnv(args)
# get states and actions from your environment
states, actions = env.states, env.actions
# create policy
policy = Policy(states, actions)
- the observation ``obs`` is a list of arrays that are returned by the environment. This is a bit different from what it is usually returned by gym environments (which is an array). The reason is that the states returned by the environment might have different dimensions (e.g. joint positions = 1D array, camera = 2D/3D array, etc) so you can not return one array.
- You can easily update the state, reward function, world, and other modules that are given to environment. This results in less code duplication and greater flexibility.
Few more examples can be found in `pyrobolearn/examples/environments <https://github.com/robotlearn/pyrobolearn/tree/master/examples/environments/>`_.
If you would like other people to use your environment, implement your environment class like described in the section below.
How to create my own environment?
---------------------------------
Using the same example as the section above REF.
.. code-block:: python
:linenos:
class MyEnv(Env): # inherit from the PRL Env class
"""Description"""
# specify what the user is allowed to change in your environment by providing optional inputs
# in this case, let's say he is allowed to change the manipulator: use Franka Panda instead of Kuka
def __init__(self, manipulator=None, ...):
# initialize the world as you would like by loading different objects in it
world = ...
...
# make sure the given manipulator is valid
if manipulator is None:
manipulator = world.load_robot('kuka_iiwa', ...)
if not isinstance(manipulator, prl.robots.Manipulator):
raise TypeError("Expecting a manipulator, instead got: {}".format(type(manipulator)))
# create the states
states = state1(manipulator) + ...
# create the reward
reward = ...
# other stuffs
...
# call the parent's constructor
super(MyEnv, self).__init__(world, states, rewards, ...)
You normally don't have to implement anything else (like the ``step``, ``reset``, and other functions are automatically implemented based on what you provided to the parent's constructor).
What are the differences with the OpenAI gym's environments?
------------------------------------------------------------
To better depict the differences, let's consider an environment which contains a quadruped robot and the goal is that it learns to walk. Usually, as it can be seen on multiple repositories, people would inherit from the gym ``Env`` class and call it something similar to ``QuadrupedFlatTerrainWalkEnv(Env)``. Inside of ``step`` function, they would compute the next states and rewards. Now suppose, you would like to change ...
In our framework, the ``world``, ``states``, and ``rewards`` are given to the PRL ``Env`` class. This means that if you would like to change the world, reward function, or states you can do it outside the function.
- Actions
Having said that, we tried to make PRL compatible with OpenAI gym at the exception that the returned state is not a array but a list of arrays.
References
----------
.. [1] "Reinforcement Learning: An Introduction", Sutton and Barto, 1998
+2
View File
@@ -0,0 +1,2 @@
.. include:: ../../examples/README.rst
+6
View File
@@ -0,0 +1,6 @@
FAQs
====
* How to add a completely new component, for instance, a state estimator or navigation (SLAM) module? There are multiple steps: 1. you have to divide your code into submodules that are minimal, do not depend on various pieces of code. 2. Compositonality 3. Flexibility: if I want to change something how easy is it?
+55
View File
@@ -0,0 +1,55 @@
.. PyRoboLearn documentation master file, created by
sphinx-quickstart on Thu Jun 20 20:28:11 2019.
You can adapt this file completely to your liking, but it should at least
contain the root toctree directive.
Welcome to PyRoboLearn's documentation!
=======================================
.. toctree::
:maxdepth: 2
:caption: Introduction
readme
.. toctree::
:maxdepth: 3
:caption: Installation
installation
.. toctree::
:maxdepth: 4
:caption: PyRoboLearn
pyrobolearn
simulators
worlds
robots
interfaces
states
actions
rewards
environments
models
approximators
algorithms
.. toctree::
:maxdepth: 2
:caption: Examples
examples
.. toctree::
:maxdepth: 3
:caption: Package Reference
docstring/modules
.. toctree::
:maxdepth: 2
:caption: Index
indices
+6
View File
@@ -0,0 +1,6 @@
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
+145
View File
@@ -0,0 +1,145 @@
Installation
============
There are 2 ways to install the PyRoboLearn framework.
1. via :ref:`Docker`
2. using a :ref:`Virtual Environment`
.. _Docker:
Docker
-------
At the moment the docker is a self contained Ubuntu image with all the libraries installed. When launched we have access to a Python3.6 interpreter and we can import pyrobolearn directly.
In the future, ROS may be splitted in another container and linked to this one.
1. Install Docker and nvidia-docker
.. code-block:: bash
sudo apt-get update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable # you should replace bionic by your version
sudo apt update
sudo apt install docker-ce
sudo systemctl status docker # check that docker is active
2. Build the image
.. code-block:: bash
docker build -t pyrobolearn .
3. You can now start the python interpreter with every library already installed
.. code-block:: bash
docker run -p 11311:11311 -v catkin_ws:/pyrobolearn/catkin_ws/ -ti pyrobolearn python3
To open an interactive terminal in the docker image use:
.. code-block:: bash
docker run -p 11311:11311 -v catkin_ws:/pyrobolearn/catkin_ws/ -ti pyrobolearn /bin/bash
4. If the GPU is not recognized in the interpreter, you can install ``nvidia-docker``
.. code-block:: bash
curl -sL https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -sL https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install nvidia-docker2
sudo pkill -SIGHUP dockerd
And use:
.. code-block:: bash
nvidia-docker run -p 11311:11311 -v catkin_ws:/pyrobolearn/catkin_ws/ -ti pyrobolearn
.. _Virtual Environment:
Virtual Environment
-------------------
0. Prerequisites: install the following packages on your Ubuntu system
.. code-block:: bash
sudo apt-get install cmake gfortran
1. First download the ``pip`` Python package manager and create a virtual environment for Python as described in the following link: https://packaging.python.org/guides/installing-using-pip-and-virtualenv/
On Ubuntu, you can install ``pip`` and ``virtualenv`` by typing in the terminal:
- In Python 2.7:
.. code-block:: bash
sudo apt install python-pip
sudo pip install virtualenv
- In Python 3.5:
.. code-block:: bash
sudo apt install python3-pip
sudo pip install virtualenv
You can then create the virtual environment by typing:
.. code-block:: bash
virtualenv -p /usr/bin/python<version> <virtualenv_name>
# activate the virtual environment
source <virtualenv_name>/bin/activate
where ``<version>`` is the python version you want to use (select between ``2.7`` or ``3.5``), and ``<virtualenv_name>`` is a name of your choice for the virtual environment. For instance, it can be ``py2.7`` or ``py3.5``.
To deactivate the virtual environment, just type:
.. code-block:: bash
deactivate
2. clone this repository and install the requirements by executing the ``setup.py``
In Python 2.7:
.. code-block:: bash
git clone https://github.com/robotlearn/pyrobolearn
cd pyrobolearn
pip install numpy cython
pip install http://github.com/cornellius-gp/gpytorch/archive/alpha.zip # this is for Python 2.7
pip install -e . # this will install pyrobolearn as well as the required packages (so no need for: pip install -r requirements.txt)
In Python 3.5:
.. code-block:: bash
git clone https://github.com/robotlearn/pyrobolearn
cd pyrobolearn
pip install numpy cython
pip install gpytorch # this is for Python 3.5
pip install -e . # this will install pyrobolearn as well as the required packages (so no need for: pip install -r requirements.txt)
Depending on your computer configuration and the python version you use, you might need to install also the following packages through ``apt-get``:
.. code-block:: bash
sudo apt install python-tk # if python 2.7
sudo apt install python3-tk # if python 3.5
+85
View File
@@ -0,0 +1,85 @@
Interfaces and Bridges
======================
**I/O interfaces** allows you to receive/send data from/to different devices. Interfaces are divided into 3 categories, ``InputInterface`` which can only receive data from a particular device and save it in memory, ``OutputInterface`` which can only send data given by PRL to the interface, and ``InputOutputInterface`` which allows you to receive and send data. Interfaces include for instance webcam, speaker, mouse, keyboard, game controller, and so on.
To avoid a direct coupling with the interface and an element in PRL such as a robot, **bridges** are introduced. Bridges makes the connection between an interface and an element in PRL (like a robot, an object in the world, the world itself, the world camera, etc). For instance, you could have a game controller and when moving one of its joystick forward, you would like for a quadcopter to take off while for a wheeled robot to move forward instead. For both examples, the values returned by the joystick is the same but you would like to have different behaviors depending on the type of robots. It might be even the case that someone would like to map the game controller events in a different way that you did. This is exactly the raison d'être of such bridges; to map an interface with an element in PRL. Different bridges can be implemented for the same interface as the user sees fit.
Available interfaces in PRL include:
- camera: webcam, asus_xtion, kinect, openpose
- controllers: mouse+keyboard, spacemouse, playstation, xbox
- speech: recognizer, translator, and synthesizer
- VR: Oculus (through Windows)
They are available in `pyrobolearn/tools/interfaces/ <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/tools/interfaces>`_ folder while bridges are available in the `pyrobolearn/tools/bridges/ <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/tools/bridges>`_ folder.
How to use an interface/bridge in PRL?
--------------------------------------
The following snippet show how to use the space mouse interface.
You can check for more examples in the `examples/interfaces <https://github.com/robotlearn/pyrobolearn/tree/master/examples/interfaces>`_ folder.
How to create your own interface/bridge?
----------------------------------------
Let's say that you have a new interface, for instance, an EMG sensor that measures the electrical activity of muscles, and you would like based on the sensed values makes a robot behave in a certain way. For instance, you would like the robot to be more stiff (see teleimpedance for more info).
- In order to create your interface, you will have to inherit one of the following interfaces: ``InputInterface``, ``OutputInterface``, ``InputOutputInterface`` based on the type of device you have. In our case, we have an EMG sensor which provides the sensed values as *inputs* to PRL, thus we will inherit from ``InputInterface``.
.. code-block:: python
:linenos:
# please add the word `Interface` at the end of your class so we can based on its name alone
# knows it is an interface.
class EMGInterface(InputInterface):
"""
Description
"""
def __init__(self, use_thread=False, sleep_dt=0, verbose=False, *args, **kwargs):
# initialize your variables/attributes
...
# call at the end the parent constructor
super(EMGInterface, self).__init__(self, use_thread, sleep_dt, verbose)
def run(self):
"""main method to implement. This method is automatically called when using threads, and you
have to call it when you are not using threads."""
# get the last sensed data and save it in one of the attributes of this class
...
- Now, let's create a bridge that connects the above interface with a manipulator robot.
.. code-block:: python
:linenos:
# please add the word `Interface` at the end of your class so we can based on its name alone
# knows it is an interface.
class EMGBridge(InputInterface):
FAQs and Troubleshootings
-------------------------
- I have an ``ImportError`` with one of the interface, why? Some libraries have to be installed and configured manually. To ease the installation process, there is a docker file as well as bash scripts in the `pyrobolearn/scripts/ <https://github.com/robotlearn/pyrobolearn/tree/master/scripts>`_ folder.
Future works
------------
* add an interface to get the values sensed by an android/Iphone smartphone (which might have an accelerometer, gyroscope, microphone, etc.)
* add HTC Vive interface
* add a Facial Expression Recognition (FER) module
* add Google assistant / Alexa
* implement interfaces for haptic devices
* improve the VR interface; right now, I have something for Oculus but it requires to use a Windows system in parallel (see VIDEO)
* implement the Xsens suit interface; I also have a code for this but pretty old and it also requires a Windows system.
+89
View File
@@ -0,0 +1,89 @@
Models
======
Learning models versus algorithms.
As shown on the following figures:
Learning models can be divided into 2 categories:
- General function approximators (aka step-based learning models)
- Linear models
- Polynomial models
- Deep Neural Networks (DNNs)
- Gaussian processes (GPs)
- Trajectory based learning models:
- Dynamic Movement Primitives (DMPs)
- Central Pattern Generators (CPGs)
- Gaussian Mixture Models and Gaussian Mixture Regression (GMMs/GMRs)
- Probabilistic Movement Primitives (ProMPs)
- Kernel Movement Primitives (KMPs)
For few of these models, we provide a wrapper around popular libraries such as ``pytorch`` or ``gpytorch``. The other models have been reimplemented to be the most general possible.
Design
------
Models are independent of the other elements in PRL, but are used by other elements in PRL.
UML
The models is notably used by approximators and policies, and their (hyper-)parameters are optimized by algorithms.
How to use a learning model?
----------------------------
.. code-block:: python
:linenos:
import torch
import pyrobolearn as prl
x = torch.rand(4)
model = prl.models.LinearModel(num_inputs=4, num_outputs=2)
print(model.predict(y))
How to create your own model?
-----------------------------
.. code-block:: python
:linenos:
import pyrobolearn as prl
class MyModel(prl.models.Model):
"""Description"""
def __init__(self, ...):
pass
# implement the various abstract methods
def ...
Comparisons between the various models?
---------------------------------------
A question that you might have, especially if you are new to the field, what are the differences between the different models that have been proposed in the literature? In this section, I will try to provide the differences (strengths and weaknesses) of each model, and when you should favor one over another one.
The below table summarizes:
- General function approximator (aka step-based learning models) vs trajectory based learning models: trajectory based models accepts as inputs the time and outputs a trajectory (a sequence).
- Parametric vs Non-parametric: In a nutshell, parametric models have parameters that are tuned by the learning algorithm based on the given dataset. Depending on the number of parameters, they might require a lot of data or to have been pretrained on similar datasets. Once trained, parametric models do not need the dataset anymore. On the other hand, non-parametric models don't have parameters but few hyper-parameters. They remember each data point in the dataset, and when given a new input they compare that new input with previous ones, and outputs an estimate based on it. Non-parametric models are very good when you don't have a lot of data points and don't have a pretrained model.
- Linear vs Non-linear: Linear models are the most simple models that makes the least assumption about the data, but can be quite limited in their expressiveness.
- Deterministic vs Probabilistic: Deterministic models predicts a point estimate as output without any quantity that captures the uncertainty associated with that output. Meanwhile, probabilistic models provide a probability distribution for each output.
- Discriminative vs Generative: discriminative models model learn the mapping ``p(y|x)`` where x is the input and y is the output, while generative models use to learn the data distribution ``p(x,y)``. Generative models are more powerful as given the prior ``p(x)`` or ``p(y)``, you can get back ``p(y|x)`` or ``p(x|y)``. Generative models might require more data.
Future works
------------
* add methods to combine different models together
* provide few other functionalities for the various models
+3
View File
@@ -0,0 +1,3 @@
Priority Tasks
==============
+52
View File
@@ -0,0 +1,52 @@
PyRoboLearn
===========
PyRoboLearn is a Python framework in robot learning for education and research. PyRoboLearn is meant to be a free and open-source tool.
Goal
Problem formulation
-------------------
General idea.
- lack of benchmarks
- lack of flexibility and modularity
- lack of generalization
- high coupling
For instance:
Full example.
Main idea of PyRoboLearn and solution to above problem.
Hardware/Software requirements
------------------------------
The PyRoboLearn framework has been tested on Ubuntu 16.04 and 18.04, with Python 2.7, 3.5 and 3.6.
Design Decisions
----------------
While designing PRL, we focused on the five following features:
- modularity: design a module (i.e. class) for each different concept
- abstraction: add a layer of abstraction for combination of low-level modules
- reusability: easy to reuse the different modules and to combine them
- low coupling between the different modules
- flexibility: this is mainly achieved by favoring composition over inheritance.
The Python language has been selected.
.. figure:: ../UML/pyrobolearn_uml.png
:alt: UML diagram of PyRoboLearn
:align: center
UML diagram of PyRoboLearn
+15
View File
@@ -0,0 +1,15 @@
.. include:: ../../README.rst
Citation
========
.. code-block:: latex
@misc{delhaisse2019pyrobolearn,
author = {Delhaisse, Brian and Xin, Songyan and Rozo, Leonel, and Caldwell, Darwin},
title = {PyRoboLearn: A Python Framework for Robot Learning Practitioners},
howpublished = {\url{https://github.com/robotlearn/pyrobolearn}},
year=2019,
}
+121
View File
@@ -0,0 +1,121 @@
Rewards
=======
In PRL, every concept is modelized as a class. This is also true for rewards which are returned by the environment as shown in the figure below (inspired by [1]_):
.. figure:: ../figures/environment.png
:alt: environment
:align: center
The agent-environment interaction
The reward function might be defined as [1]_:
- :math:`r: \mathcal{S} \rightarrow \mathbb{R}`: given the state :math:`s \in \mathcal{S}`, it returns the reward value :math:`r(s)`.
- :math:`r: \mathcal{S} \times \mathcal{A} \rightarrow \mathbb{R}`: given the state :math:`s \in \mathcal{S}` and action :math:`a \in \mathcal{A}`, it returns the reward value :math:`r(s,a)`.
- :math:`r: \mathcal{S} \times \mathcal{A} \times \mathcal{S} \rightarrow \mathbb{R}`: given the state :math:`s \in \mathcal{S}`, action :math:`a \in \mathcal{A}`, and next state :math:`s' \in \mathcal{S}`, it returns the reward value :math:`r(s,a,s')`.
Note that the cost function is just minus the reward function, i.e. it is given by :math:`c(s,a,s') = -r(s,a,s')`.
Design
------
In PRL, all reward functions inherit from the abstract ``Reward`` class defined in `pyrobolearn/rewards/reward.py <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/rewards>`_, and several methods and operations are provided.
You can for instance:
* provide the ``State`` and/or ``Action`` instances to some reward functions that will compute the reward value based on their value.
* access to the range of the reward function.
* add, multiply, divide, subtract, and apply basic functions such as :math:`\exp`, :math:`\cos`, :math:`\sin`, and others on reward functions. The resulting range is automatically scaled based on the operations.
* define your own rewards/costs and reuse them in your code.
How to use a particular reward?
-------------------------------
Here is a short snippet showing the basic usage of reward functions:
.. code-block:: python
:linenos:
import pyrobolearn as prl
from pyrobolearn.rewards import FixedReward, YourReward
# define the simulator and world (and load what you want in it)
sim = ...
world = ...
...
# define your state / action for your reward function
state = ...
action = ...
# define the reward function
reward = 2 * FixedReward(3) + 0.5 * YourReward(state, action)
# print the range of the reward function
print(reward.range)
# compute the reward value
value = reward()
print(value)
# update the state for instance
state() # this will modify the internal state data
# recompute the reward value
value = reward()
print(value) # you will normally get a different value
# you can give the reward function to your RL environment
# which will use it when calling `env.step()`.
env = prl.envs.Env(world, state, reward)
More examples on how to use the rewards can be found in `pyrobolearn/examples/rewards <https://github.com/robotlearn/pyrobolearn/tree/master/examples/rewards/>`_.
How to create your own reward?
------------------------------
In order to create your own reward, you have to inherit from ``Reward`` defined in `pyrobolearn/rewards/reward.py <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/rewards>`_.
.. code-block:: python
:linenos:
import pyrobolearn as prl
class MyReward(prl.rewards.Reward):
"""Description"""
def __init__(self, args):
# initialize your reward function based on the args
...
# gives initial value to your reward
# this attribute will be used to cache the computed value
self.value = 0
def _compute(self):
# compute the reward function
...
# save the computed value and return it
self.value = ...
return self.value
Once done, you will be able to use your reward function and perform operations on it (such as addition, substraction, etc).
FAQs
----
* If you have any questions, please submit an issue on the `Github page <https://github.com/robotlearn/pyrobolearn>`_.
References:
-----------
.. [1] "Reinforcement Learning: An Introduction", Sutton and Barto, 1998
+337
View File
@@ -0,0 +1,337 @@
Robots
======
Robots constitute one of the main elements in the *PyRoboLearn* (PRL) framework. PRL provides a high-level abstraction and common interface to many robots, offering better consistency and generalization between them. This allows for instance to check if one particular controller or algorithm works with other robots as well.
More than 60+ robots are currently available in PRL covering a large range of robotic platforms. Among them, manipulators, biped robots, quadrupeds, hexapods, wheeled robots, quadcopters, and many others as shown below:
GIF
.. image:: ../figures/coman.png
:width: 9%
:alt: coman
.. image:: ../figures/wam.png
:width: 9%
:alt: wam
.. image:: ../figures/fetch.png
:width: 9%
:alt: fetch
.. image:: ../figures/cassie.png
:width: 9%
:alt: cassie
.. image:: ../figures/hyq2max.png
:width: 9%
:alt: hyq2max
.. image:: ../figures/phantomx.png
:width: 9%
:alt: phantomx
.. image:: ../figures/pleurobot.png
:width: 9%
:alt: pleurobot
.. image:: ../figures/softhand.png
:width: 9%
:alt: softhand
.. image:: ../figures/centauro.png
:width: 9%
:alt: baxter
.. image:: ../figures/walkman.png
:width: 9%
:alt: walkman
Note that for few of them such as the ones that require the simulation of fluids (e.g. quadcopters). If the simulator does not simulate fluids, the corresponding robot class implements a simple dynamics simulation. For such classes, as I did not spend too much time one it, some improvements might be needed for better realism.
Design
------
The most abstract class is the ``Body`` class which is described in `pyrobolearn/robots/base.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/robots/base.py>`_. From it, you can already access to multiple functionalities/attributes, such as its position and orientation. It only depends on the simulator.
.. figure:: ../UML/robots.png
:alt: UML diagram for Robot
:align: center
UML diagram for Robot
Inheriting from one of its child classes is the most interesting (for our purpose) ``Robot`` class, described in `robot.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/robots/robot.py>`_. It is the parent class of several classes such as:
- ``Manipulator`` defined in `manipulator.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/robots/manipulator.py>`_
- ``LeggedRobot`` defined in `legged_robot.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/robots/legged_robot.py>`_
- ``WheeledRobot`` defined in `wheeled_robot.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/robots/wheeled_robot.py>`_
- ``Hand`` defined in `hand.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/robots/hand.py>`_
- etc.
Note that ``Robot`` only depends on the simulator interface (aggregation relationship), and is independent of other modules in PRL (at the exception of some util methods that are useful to perform some transformations).
How to use a robot in PRL?
--------------------------
.. code-block:: python
:linenos:
from itertools import count
import pyrobolearn as prl
# create simulator
simulator = prl.simulators.Bullet()
# create basic world (with floor and gravity)
world = prl.worlds.BasicWorld(simulator)
# load robot in the world at the specified (x, y) position (you can also give a (x,y,z) position)
# For other possible parameters, check the method documentation.
robot = world.load_robot('robot_name', position=[0., 0.], ...)
# print some info about the robot
robot.print_info()
print(dir(robot)) # print available methods
# main loop
for _ in count():
# perform something with the robot for instance some kinematic / dynamic control
...
# perform a step in the world and sleep for `sim.dt`
world.step(sim.dt)
You can check for more examples in the `examples/robots <https://github.com/robotlearn/pyrobolearn/tree/master/examples/robots>`_ folder. You can also check for `examples/kinematics <https://github.com/robotlearn/pyrobolearn/tree/master/examples/kinematics>`_ and `examples/dynamics <https://github.com/robotlearn/pyrobolearn/tree/master/examples/dynamics>`_.
- Kinematics
- Dynamics
How to create your own robot?
-----------------------------
To illustrate how to create your own robot, let's assume you want to create a humanoid robot (biped and bi-manipulator) called ``Asimov``.
1. First, you have to get (or create) its URDF file and the associated meshes. Let's put them in a directory called ``asimov``, and move it in the ``pyrobolearn/robots/urdfs/`` folder where all the other URDFs are.
2. If you want to use it directly and to not create a specific class, you can just call:
.. code-block:: python
:linenos:
import pyrobolearn as prl
# create simulator and basic world
simulator = prl.simulators.Bullet()
# create world
world = prl.worlds.BasicWorld(simulator)
# create robot
urdf = "path/to/urdf"
position = None # position [x,y,[z]]. If None, by default, it will be set to (0,0,0)
orientation = None # quaternion [x,y,z,w]. If None, by default, it will be set to (0,0,0,1)
robot = Robot(simulator, urdf, position, orientation, fixed_base=False)
# main loop
while True:
# do something with robot
...
# perform a step in the world and pause for `sim.dt`
world.step(sim.dt)
3. Instead of the second point, let's create a proper class ``Asimov`` that inherits from the ``BipedRobot`` and ``BiManipulator`` (and thus inherits their functionalities) in a Python file ``asimov.py``:
.. code-block:: python
:linenos:
#!/usr/bin/env python
"""Short description about your robot
Long description about the robot
"""
# import libraries you need
import ...
# import the classes to inherit from
from pyrobolearn.robots.legged_robot import BipedRobot
from pyrobolearn.robots.manipulator import BiManipulator
class Asimov(BipedRobot, BiManipulator):
r"""Asimov Robot
Add description about the robot here, such as the number of degrees of freedom, the various sensors/actuators that are available.
References:
- [1] reference 1; e.g. link to the robot webpage
- [2] reference 2: e.g. link to original URDF
"""
# define static variables here, e.g.
BASE_HEIGHT = 1
def __init__(self, simulator, position=(0, 0, 0), orinetation=(0, 0, 0, 1), fixed_base=False, scale=1.,
urdf=os.path.dirname(os.path.abspath(__file__)) + '/relative/path/to/your/urdf/wrt/this/python/file.urdf')
# check parameters and set default parameters if necessary
if position is None: # it receives None notably when the world load the robot if a position is not specified
position = (0, 0, 0)
if len(position) == 2: # assume (x,y) are given
position = tuple(position) + (self.BASE_HEIGHT,)
if orientation is None: # it receives None notably when the world load the robot if an orientation is not specified
orientation = (0, 0, 0, 1) # quaternion [x,y,z,w]
if fixed_base is None: # it receives None notably when the world load the robot if fixed_base is not specified
fixed_base = False
# call parent constructor
super(Asimov, self).__init__(simulator, urdf, position, orientation, fixed_base, scale)
# define common attributes to all bimanipulator/biped robot (see their respective classes)
# for bimanipulator
self.arms = [] # list of arms where each arm is a list of link ids
self.hands = [] # list of end-effector/hand link ids
# default values set in BiManipulator class that you can modify if necessary
# self.left_arm_id, self.left_hand_id = 0, 0 # used e.g. for self.arms[self.left_arm_id]
# self.right_arm_id, self.right_hand_id = 1, 1 # used e.g. for self.arms[self.right_arm_id]
# for biped (similar than for bimanipulator): check corresponding `BipedRobot` class
self.legs = [] # list of legs where a leg is a list of links
self.feet = [] # list of feet ids
...
# define your own sensors and actuators
...
3. If you want to be able to load your robot from the world using its name (by calling ``world.load_robot('asimov')``), add the Python file ``asimov.py`` in the `pyrobolearn/robots/ <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/robots>`_ folder. The ``__init__.py`` inside that folder will automatically go through all the files and add the robots inside the ``implemented_robots`` list which is accessed by ``World``. Note that you can also access this list by calling ``pyrobolearn.robots.implemented_robots``. If you also want to be able to call your robot using ``from pyrobolearn.robots import Asimov``, you will have to add the line ``from .asimov import Asimov`` in the `pyrobolearn/robots/__init__.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/robots/__init__.py>`_.
4. Now, you can call your robot in the framework.
.. code-block:: python
:linenos:
from itertools import count
import pyrobolearn as prl
simulator = prl.simulators.Bullet()
# create world and load robot inside (recommended)
world = prl.worlds.BasicWorld(simulator)
robot = world.load_robot('asimov')
# or directly created the robot in the simulator (not recommended unless you are doing experiments on the real robot
# and thus the world is not useful)
# robot = prl.robots.Asimov(simulator)
robot.print_info()
# main loop
for _ in count():
world.step(sleep_dt=sim.dt)
Sensors and Actuators
---------------------
* Sensors
* Actuators
FAQs and Troubleshootings
-------------------------
- The mass/inertia matrix of some links are not correct in the simulator, what should I do?
- If you use the Bullet simulator (which uses ``pybullet``), you have to specify the mass and inertia matrix for each link. If a link doesn't have these attributes defined, pybullet automatically attribute a mass of 1kg and an identity inertia matrix (which is ridiculous huge). Normally, links without a mass and inertia matrices defined in a URDF file are dummy links that are used to represent a reference frame. To set a reasonable inertia matrix, please refer to `"Adding Physical and Collision Properties to a URDF Model" <http://wiki.ros.org/urdf/Tutorials/Adding%20Physical%20and%20Collision%20Properties%20to%20a%20URDF%20Model>`_ and `"Inertial parameters of triangle meshes" <http://gazebosim.org/tutorials?tut=inertia&cat=build_robot>`_.
- It is possible that some masses / inertia matrices have not been correctly set in the original URDF. I cleaned most of the URDF files but some links might have escaped my attention. Please open an issue on `Github <https://github.com/robotlearn/pyrobolearn>`_, or check the 2 `links <http://wiki.ros.org/urdf/Tutorials/Adding%20Physical%20and%20Collision%20Properties%20to%20a%20URDF%20Model>`_ `above <http://gazebosim.org/tutorials?tut=inertia&cat=build_robot>`_ on how to set reasonable inertia values.
- How to convert a xacro file to a URDF file? Type ``rosrun xacro xacro --inorder path/to/<robot>.urdf.xacro > <robot>.urdf`` or ``rosrun xacro xacro.py --inorder path/to/<robot>.urdf.xacro > <robot>.urdf``
- When I set the ``fixed_base`` to ``False``, the robot has still a fixed base, what is happening? The first link (often called base_link or world_link in most URDF files) shouldn't have a mass/inertia of zero, this causes the robot to have a fixed base. Remove the corresponding tag from the urdf.
- What are the differences when a robot has a floating-based and a fixed base? When the robot has a floating base, the total number of degrees of freedom becomes 6 + the number of actuated joints. This appears when computing the Jacobian and Inertia matrices.
- I noticed that some functionalities are missing in one of the robot class? I probably forgot to implement it. Please open an issue on `Github <https://github.com/robotlearn/pyrobolearn>`_ or create a pull request.
- There is an error in one of the functionalities? Or, I have another question or want to suggest an improvement? Please open an issue on `Github <https://github.com/robotlearn/pyrobolearn>`_ or a create a pull request.
Future works
------------
- add more robots. Here are few other robots that might interest the users:
- `hexapods <https://github.com/resibots/hexapod_ros/tree/master/hexapod_description>`_
- `ROS robots <https://robots.ros.org/>`_
- `Universal robots <https://github.com/ros-industrial/universal_robot>`_
- improve the flexibility/modularity by allowing to remove/add/replace links to/from the main robot. For instance:
- add a gripper to a manipulator robot, or replace a gripper with another
- remove a leg from a legged robot (which is interesting to simulate damage recovery scenarios)
- might need to define different URDFs for different simulators
References
----------
All the robots were found in the following github repositories (and several were cleaned by me):
- `Aibo <https://github.com/dkotfis/aibo_ros>`_
- `Allegrohand <https://github.com/simlabrobotics/allegro_hand_ros>`_
- `Ant <https://github.com/bulletphysics/bullet3/tree/master/examples/pybullet/gym/pybullet_data/mjcf>`_
- Atlas: `1 <https://github.com/openai/roboschool>`_, `2 <https://github.com/erwincoumans/pybullet_robots>`_
- `Ballbot <https://github.com/CesMak/bb>`_
- `Baxter <https://github.com/RethinkRobotics/baxter_common>`_
- BB8: `1 <http://www.theconstructsim.com/bb-8-gazebo-model/>`_, `2 <https://github.com/eborghi10/BB-8-ROS>`_
- `Blackbird <https://hackaday.io/project/160882-blackbird-bipedal-robot>`_
- `Cartpole <https://github.com/bulletphysics/bullet3/blob/master/data/cartpole.urdf>`_ but modified to be able to have multiple links specified at runtime
- Cassie: `1 <https://github.com/UMich-BipedLab/Cassie_Model>`_, `2 <https://github.com/agilityrobotics/cassie-gazebo-sim>`_, `3 <https://github.com/erwincoumans/pybullet_robots>`_
- `Centauro <https://github.com/ADVRHumanoids/centauro-simulator>`_
- `Cogimon <https://github.com/ADVRHumanoids/iit-cogimon-ros-pkg>`_
- `Coman <https://github.com/ADVRHumanoids/iit-coman-ros-pkg>`_
- `Crab <https://github.com/tuuzdu/crab_project>`_
- `Cubli <https://github.com/xinsongyan/cubli>`_
- `Darwin <https://github.com/HumaRobotics/darwin_description>`_
- `e.Do <https://github.com/Comau/eDO_description>`_
- `E-puck <https://github.com/gctronic/epuck_driver_cpp>`_
- `F10 racecar <https://github.com/erwincoumans/pybullet_robots/tree/master/data/f10_racecar>`_
- `Fetch <https://github.com/fetchrobotics/fetch_ros>`_
- `Franka Emika <https://github.com/frankaemika/franka_ros>`_
- `Half Cheetah <https://github.com/bulletphysics/bullet3/tree/master/examples/pybullet/gym/pybullet_data/mjcf>`_
- `Hopper <https://github.com/bulletphysics/bullet3/tree/master/examples/pybullet/gym/pybullet_data/mjcf>`_
- `Hubo <https://github.com/robEllenberg/hubo-urdf>`_
- `Humanoid <https://github.com/bulletphysics/bullet3/tree/master/examples/pybullet/gym/pybullet_data/mjcf>`_
- `Husky <https://github.com/husky/husky>`_
- `HyQ <https://github.com/iit-DLSLab/hyq-description>`_
- `HyQ2Max <https://github.com/iit-DLSLab/hyq2max-description>`_
- ICub: `1 <https://github.com/robotology-playground/icub-models>`_, `2 <https://github.com/robotology-playground/icub-model-generator>`_. There are currently few problems with this robot.
- `Jaco <https://github.com/JenniferBuehler/jaco-arm-pkgs>`_
- KR5: `1 <https://github.com/a-price/KR5sixxR650WP_description>`_, `2 <https://github.com/ros-industrial/kuka_experimental>`_
- Kuka IIWA: `1 <https://github.com/IFL-CAMP/iiwa_stack>`_, `2 <https://github.com/bulletphysics/bullet3/tree/master/data/kuka_iiwa>`_
- Kuka LWR: `1 <https://github.com/CentroEPiaggio/kuka-lwr>`_, `2 <https://github.com/bulletphysics/bullet3/tree/master/data/kuka_lwr>`_
- `Laikago <https://github.com/erwincoumans/pybullet_robots>`_
- `Little Dog <https://github.com/RobotLocomotion/LittleDog>`_
- `Manipulator2D <https://github.com/domingoesteban/robolearn_robots_ros>`_
- `Minitaur <https://github.com/bulletphysics/bullet3/tree/master/examples/pybullet/gym/pybullet_data/quadruped>`_
- `Lincoln MKZ car <https://bitbucket.org/DataspeedInc/dbw_mkz_ros>`_
- `Morphex <https://gist.github.com/lanius/cb8b5e0ede9ff3b2b2c1bc68b95066fb>`_
- Nao: `1 <https://github.com/ros-naoqi/nao_robot>`_, and `2 <https://github.com/ros-naoqi/nao_meshes>`_
- OpenDog: `1 <https://github.com/XRobots/openDog>`_, and `2 <https://github.com/wiccopruebas/opendog_project>`_
- `Pepper <https://github.com/ros-naoqi/pepper_robot>`_
- `Phantom X <https://github.com/HumaRobotics/phantomx_description>`_
- `Pleurobot <https://github.com/KM-RoBoTa/pleurobot_ros_pkg>`_
- `PR2 <https://github.com/pr2/pr2_common>`_
- `Quadcopter <https://github.com/wilselby/ROS_quadrotor_simulator>`_
- `Rhex <https://github.com/grafoteka/rhex>`_
- `RRbot <https://github.com/ros-simulation/gazebo_ros_demos>`_
- Sawyer: `1 <https://github.com/RethinkRobotics/sawyer_robot>`_, `2 <https://github.com/erwincoumans/pybullet_robots>`_
- `SEA hexapod <https://github.com/alexansari101/snake_ws>`_
- `SEA snake <https://github.com/alexansari101/snake_ws>`_
- `Shadow hand <https://github.com/shadow-robot/sr_common>`_
- `Soft hand <https://github.com/CentroEPiaggio/pisa-iit-soft-hand>`_
- `Swimmer <https://github.com/bulletphysics/bullet3/tree/master/examples/pybullet/gym/pybullet_data/mjcf>`_
- `Valkyrie <https://github.com/openhumanoids/val_description>`_
- `Walker 2D <https://github.com/bulletphysics/bullet3/tree/master/examples/pybullet/gym/pybullet_data/mjcf>`_
- `Walk-man <https://github.com/ADVRHumanoids/iit-walkman-ros-pkg>`_
- `Wam <https://github.com/jhu-lcsr/barrett_model>`_
- `Youbot <https://github.com/youbot>`_: this includes the youbot base without any arms, one kuka arm, 2 kuka arms, and the kuka arm without the wheeled base.
+97
View File
@@ -0,0 +1,97 @@
Simulators
==========
The simulator is the starting point in the **PyRoboLearn** (PRL) framework. To avoid a tight coupling with a particular simulator, a ``Simulator`` interface class (from which all the other simulators inherit from) has been implemented. Other .
We provide the ``Bullet`` interface, which uses the ``pybullet`` library.
The general idea is that you would be able to change the simulator if you wish without having to modify any other lines of code. See example below.
Design
------
The important goal when designing the simulators was that it should be a stand alone interface.
.. figure:: ../UML/simulator.png
:alt: UML diagram for Simulators
:align: center
UML diagram for simulators
Currently, the only fully functional simulator is ``Bullet``. While other simulators have been considered such as Gazebo (with ROS), Mujoco, Dart, and others, few of them required a particular license or do not have strong Python bindings.
Note that each simulator implements static methods which provide information about the simulator itself; if it can for instance simulate fluids or not, etc.
How to use a particular simulator in PRL?
-----------------------------------------
For the moment, the only fully operational interface is ``Bullet``. Some few other interfaces have been partially implemented (see Future works). Here is a snippet on how to use the ``Bullet`` simulator in PRL:
.. code-block:: python
from itertools import count
import pyrobolearn as prl
# create simulator
simulator = prl.simulators.Bullet()
# later: you would be able to change the simulator by `BulletROS` or `RBDL_ROS` to command a real robot using ROS
# create world, robots, etc
...
# main loop
for _ in count():
# do something
...
# perform a step in the world and sleep for `sim.dt`
sim.step(sim.dt)
You can check for more examples in the `examples/simulators <https://github.com/robotlearn/pyrobolearn/tree/master/examples/simulators>`_ folder.
How to create an interface to a simulator?
------------------------------------------
To create your own Simulator, you have to inherit from the ``Simulator`` class defined in `pyrobolearn/simulators/simulator.py <https://github.com/robotlearn/pyrobolearn/blob/master/pyrobolearn/simulators/simulator.py>`_.
.. code-block:: python
import pyrobolearn as prl
class MySimulator(prl.simulators.Simulator):
"""Description"""
# implement all the abstract methods in Simulator
FAQs and Troubleshootings
-------------------------
* What are the differences between `BulletClient <https://github.com/bulletphysics/bullet3/blob/master/examples/pybullet/gym/pybullet_utils/bullet_client.py>`_ and the ``Bullet`` defined in PRL? There are few differences but the design of the abstract ``Simulator`` class as well as the `Bullet` class was heavily inspired by the methods provided in PyBullet. The subtil differences include:
* a full documentation embedded in the code of ``Bullet``. The documentation for each function provided in the original pybullet is described on a Google doc available `here <https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA>`_. This is not optimal when coding where a user often wants to access the documentation through the code using ``function?`` or ``help(function)`` in a Python console.
* follow the PEP8 style guideline. For instance, the names of the method are given by ``create_collision_shape`` instead of ``createCollisionShape``.
* automatic conversion to numpy arrays from lists that are returned by ``pybullet``, and vice-versa. Some methods (not all of them) in the original pybullet raises an error when given a numpy array. I identified these methods and convert these numpy arrays to lists. Also, some matrices returned by some methods in the original pybullet are returned as a list of int/float instead of numpy arrays. The conversion to numpy array and the reshaping to the correct shapes is thus also performed in the ``Bullet`` class.
* enforce consistency; for instance, some angles that were returned from or provided to some methods in the original pybullet, were for some in degrees while for others in radians. This can lead to some bugs that could be hard to detect if the user is not aware of that. In ``Bullet``, all the returned/provided angles are in radians.
Future works
------------
My main objectives for future works are the implementation of:
- the Mujoco interface; I originally did not start with it as it is closed-source and requires a License. However, it is used a lot in research and thus it could be interesting to have it as well.
- the Gazebo-ROS interface; a part has already been implemented but it is far from over.
- the Isaac interface if Nvidia provided a nice Python API.
Possible other future works might include the implementation of:
- the DART interface; there is a minimal implementation of it when I was playing around with it
- the opensim interface; this interface is for musculoskeletal models but this can be interesting when testing algorithms/models.
+108
View File
@@ -0,0 +1,108 @@
States
======
In PRL, every concept is modelized as a class. This is also true for states which are returned by the environment.
.. figure:: ../figures/environment.png
:alt: environment
:align: center
The agent-environment interaction
States are given to the policy and the environment. The environment is responsible to update them while policies read their ``data`` and feed it to the underlying learning model. In the case we use a physics simulator like PyBullet, the environment performs one step in the simulation and calls the ``states()`` which updates the ``data`` they contained. Instead, if you have a dynamical model function, the environment can call this one to update the ``data`` of the various ``states`` without having to call the ``states()`` itself to update their values.
States can also be given to dynamical models (which predicts the next state given the current state and last action), value function approximators (which predicts a scalar value given a state and possibly an action), reward functions, etc.
Design
------
UML
How to use a particular state?
------------------------------
Let's assume you have a quadruped robot, and you would like to get its joint positions, velocities, and base position.
.. code-block:: python
:linenos:
from itertools import count
import pyrobolearn as prl
from pyrobolearn.states import BasePositionState, JointPositionState, JointVelocityState
# create simulator
sim = prl.simulators.Bullet()
# load robot
robot = prl.robots.HyQ2Max(sim)
# create the states
base_pos_state = BasePositionState(robot)
joint_pos_state = JointPositionState(robot, joint_ids=robot.legs) # you can specify which joints you would like to get the position
joint_vel_state = JointVelocityState(robot, joint_ids=robot.legs) # you can specify which joints you would like to get the velocity
state = base_pos_state + joint_pos_state + joint_vel_state
# run simulation
for t in count():
# call and print the state
print(state())
# perform a step in the world
world.step(sim.dt)
All the states accept also as inputs:
- ``window_size``: size (by default, it is set to one)
- ``ticks``: the number of simulation ticks to sleep before getting the next state.
In the example above, for joint states, you could also specify the joints that you would like to get the states from by setting ``joint_ids``. Note that in order to be able to generalize to other robots, avoid to give manually the joint ids but instead gives an attribute of the robot, like, ``robot.legs`` (wich is a list containing the joint ids associated with each leg).
Now, let's assume that you forgot to include the robot's base orientation and its linear/angular velocity in the state. In other frameworks, it is very likely that you would have to change manually the state and everything that depends on it (the policy / value function approximator which accepts as input the state, the step function in the environment which compute the next state, possibly the reward function which is often based on the current state, etc). In PRL, everything is automatized, and thus setting:
.. code-block:: python
state = state + BaseOrientationState(robot) + BaseLinearVelocity(robot)
will automatically results the other components to update their input size or because this new state is provided to them.
How to create your own state?
-----------------------------
Let's assume that you want to create a state that accepts as inputs the game controller .
.. code-block:: python
:linenos:
import pyrobolearn as prl
class MyState(prl.states.State): # inherit from the abstract State class
"""Description"""
def __init__(self, ...):
super(MyState, self).__init__(...)
FAQs
----
Other functionalities
---------------------
- `State generator <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/states/generators>`_: generate a state (used as initial state generator)
- `State processor <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/states/processors>`_: process the given state (before giving it to another model such as a policy)
Future works
------------
* add a ``rate`` attribute to the states which is used when we set the real-time on the simulator. Or better, using the ``ticks`` and ``sim.dt`` infer the rate.
+82
View File
@@ -0,0 +1,82 @@
Worlds
======
The world is the second important item in PRL; it is, with the ``Body`` class (see next section), the only class that can access the simulator. As it name implies, it allows you to create a world in the simulator, load various objects in it, and change the world's and objects' physical properties. From it, you can also access to the main camera (if the GUI is enabled in the simulator), and move it as you wish. The world can be seen as a wrapper around the simulator which provides you extra functionalities where each function calls different methods of the simulator. Finally, the world also allows you to load and generate terrains.
Design
------
As it can be seen on the UML diagram below the ``World`` depends on the ``Simulator`` and the various ``Body`` (see next section) loaded in it (as well as few util functions).
.. figure:: ../UML/world.png
:alt: UML diagram for World
:align: center
UML diagram for world
Later, we will see that world is notably given to the environment along with the states and rewards.
How to use the world in PRL?
----------------------------
Here is a snippet showing how to create a simple world in PRL:
.. code-block:: python
:linenos:
from itertools import count
import pyrobolearn as prl
# create simulator
simulator = prl.simulators.Bullet()
# create basic world (with floor and gravity)
world = prl.worlds.BasicWorld(simulator)
# load a sphere in the world
sphere = world.load_sphere(position=[0, 0, 5])
# run the simulator
for t in count():
# follow the sphere falling with the main camera
world.camera.follow(sphere, distance=2)
# perform a step in the simulator and sleep for `sim.dt`
world.step()
Note that you can get access to the world camera, and change its position and orientation. You can also follow an object moving with the camera as done in the code above.
For more examples, you can check the `examples/worlds <https://github.com/robotlearn/pyrobolearn/tree/master/examples/worlds>`_ folder.
How to create your own world?
-----------------------------
Creating your own world basically boils down to inheriting from the ``World`` or ``BasicWorld`` (if you want a floor and enable gravity by default) class, and write in the constructor what you want your world to load when instantiated.
FAQs and Troubleshootings
-------------------------
- Why do the ``Body`` class (and all the classes that inherit from it such as ``Robot``) can access the simulator as well?
- This is because, creating a world when the ``Simulator`` consists to be the real world doesn't make much sense. The ``Robot`` is completely independent of the ``World``, while the converse is not true.
- I got an error while loading a 3D object / mesh?
- The most common error is because the given format is not supported by the simulator. Try to convert it in ``.obj`` using for instance `meshlab <http://www.meshlab.net/>`_ (which is an open-source free tool to process and edit 3D meshes)
Where can I find 3d models to load in the world?
------------------------------------------------
- If it a combination of simple shapes linked together, you can build it in the simulator.
- `Pybullet data <https://github.com/bulletphysics/bullet3/tree/master/data>`_
- `Gazebo database <https://bitbucket.org/osrf/gazebo_models/src/default/>`_
- `Turbosquid <www.turbosquid.com>`_
- `free3d <free3d.com>`_
- `sketchfab <sketchfab.com>`_
-9
View File
@@ -1,9 +0,0 @@
## Examples
In this folder, you will find different examples on how to use the framework.
You can check the following folders:
- `gym/cartpole`: policies are trained with different algorithms on the gym Cartpole environment.
- `robots`: check how to load a specific robot into the world.
- `states`: how to query the states / observations.
+21
View File
@@ -0,0 +1,21 @@
Examples
========
In this folder, you will find different examples on how to use the framework.
Warning: this folder is currently being updated; few files might still have some bugs or not
implemented completely. Some other folders will be added in the upcoming days.
You can check the following folders on:
- ``simulators``: how to use a particular simulator. Currently, the Bullet simulator is the one fully operational.
- ``worlds``: how to create a world in the simulator, load various objects inside and interact with them, use the camera, and load or generate terrains.
- ``robots``: how to load a specific robot (biped, quadruped, wheeled, etc) into the world.
- ``interfaces``: the various interfaces (game controllers, webcam, etc) and bridges that you can use.
- ``kinematics``: how to use forward and inverse kinematics as well as position and velocity control.
- ``dynamics``: how to use forward and inverse dynamics as well as force control.
- ``manipulability``: how to use the velocity and dynamic manipulability ellipsoids.
- ``states``: how to query the states / observations.
- ``models``: the different learning models that you can use.
- ``imitation``: how to use imitation learning with the framework.
- ``gym/cartpole``: policies that are trained with different algorithms on the gym Cartpole environment.
+9
View File
@@ -0,0 +1,9 @@
## Robot dynamics
We provide examples on how to perform forward and inverse dynamics, as well as force control.
References:
- [1] "Robotics: Modelling, Planning and Control", Siciliano et al., 2010
- [2] "Springer Handbook of Robotics", Siciliano et al., 2008
- [3] "Rigid Body Dynamics Algorithms", Featherstone, 2008
- [4] [Lecture on Impedance Control](http://www.diag.uniroma1.it/~deluca/rob2_en/15_ImpedanceControl.pdf) by Prof. De Luca, Universita di Roma
+20
View File
@@ -0,0 +1,20 @@
### Force control
In a nutshell, you have different control modes:
* motion control: specify the desired task (or joint) positions / velocities
* force control: specify the desired task (or joint) forces
* indirect force control:
* impedance control
* admittance control
* direct force control:
* hybrid force/position control
* parallel force/position control
Here are the few examples that you can find in this folder:
1. `no_forces.py`: this example loads a RRBot robot and disable the motors. It does not apply any joint torques.
2. `gravity_compensation.py`: compute the necessary joint torques to compensate for gravity.
3. `attractor_point.py`: compute the necessary joint torques (using impedance control) such that the end-effector
is attracted by a 3D Cartesian point.
For these 3 above examples, try to move the robot's end effector with your mouse and see what happens.
@@ -0,0 +1,69 @@
#!/usr/bin/env python
"""Attractor point using impedance control with RRBot
Try to move the end-effector using the mouse, and see what happens. Compare the obtained results with
`force/no_forces.py` and `force/gravity_compensation.py`.
"""
import numpy as np
from itertools import count
import pyrobolearn as prl
# Create simulator
sim = prl.simulators.Bullet()
# create world
world = prl.worlds.BasicWorld(sim)
# load robot
robot = prl.robots.RRBot(sim)
robot.disable_motor() # disable motors; comment the `robot.set_joint_torques(torques)` to see what happens
robot.print_info()
robot.change_transparency()
# define variables
link_id = robot.get_link_ids('hokuyo_link') # the link we are interested to
com_frame = robot.get_link_states(link_id)[2]
x_des = robot.get_link_world_positions(link_id) # desired cartesian position
# gains
K = 100 * np.identity(3)
D = 2 * np.sqrt(K) # critically damped
D = 3 * D # manually increase damping
# draw a sphere at the desired location
world.load_visual_sphere(position=x_des, radius=0.1, color=(0, 1, 0, 0.5))
# run simulator
for _ in count():
# get current joint positions, velocities, accelerations
q = robot.get_joint_positions()
dq = robot.get_joint_velocities()
ddq = np.zeros(len(q))
# get current link position and velocity
x = robot.get_link_world_positions(link_id)
dx = robot.get_link_world_linear_velocities(link_id)
# compute torques (Coriolis, centrifugal and gravity compensation) using inverse dynamics
torques = robot.calculate_inverse_dynamics(ddq, dq, q)
# get linear jacobian
Jlin = robot.get_linear_jacobian(link_id=link_id, local_position=com_frame)
# attractor point: compute cartesian forces (PD control)
F = K.dot(x_des - x) - D.dot(dx)
# add torques resulting from them
torques += Jlin.T.dot(F)
# torques += Jlin.T.dot(- D.dot(dx)) # active compliance
# torques = Jlin.T.dot(F)
# impedance control
robot.set_joint_torques(torques=torques)
# perform a step in the world
world.step(sleep_dt=1./240)
@@ -0,0 +1,41 @@
#!/usr/bin/env python
"""Force control: gravity compensation with RRBot
Try to move the end-effector using the mouse, and see what happens. Compare the obtained results with
`force/no_forces.py` and `impedance/attractor_point.py`.
"""
import numpy as np
from itertools import count
import pyrobolearn as prl
# Create simulator
sim = prl.simulators.Bullet()
# create world
world = prl.worlds.BasicWorld(sim)
# load robot
robot = prl.robots.RRBot(sim)
robot.disable_motor() # disable motors; comment the `robot.set_joint_torques(torques)` to see what happens
robot.print_info()
robot.change_transparency()
# run simulator
for _ in count():
# get current joint positions, velocities, accelerations
q = robot.get_joint_positions()
dq = robot.get_joint_velocities()
ddq = np.zeros(len(q))
# compute torques (Coriolis, centrifugal and gravity compensation) using inverse dynamics
torques = robot.calculate_inverse_dynamics(ddq, dq, q)
# force control
robot.set_joint_torques(torques=torques)
# perform a step in the world
world.step(sleep_dt=sim.dt)
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env python
"""Force control: apply no forces/torques.
Try to move the end-effector using the mouse, and see what happens. Compare the obtained results with
`force/gravity_compensation.py` and `impedance/attractor_point.py`.
"""
import numpy as np
from itertools import count
import pyrobolearn as prl
# Create simulator
sim = prl.simulators.Bullet()
# create world
world = prl.worlds.BasicWorld(sim)
# load robot
robot = prl.robots.RRBot(sim)
robot.disable_motor() # disable motors
robot.print_info()
robot.change_transparency()
# run simulator
for _ in count():
# force control: apply no forces/torques
robot.set_joint_torques(torques=np.zeros(len(robot.joints)))
# perform a step in the world
world.step(sleep_dt=sim.dt)
+92
View File
@@ -0,0 +1,92 @@
Environments
============
In this folder, we provide examples on how to define and use environments which are notably useful for imitation and reinforcement learning.
An environment is defined as the following figures (inspired by [1]_):
.. image:: ../../docs/figures/environment.png
:alt: environment
:align: center
In PRL, the environment is an abstraction layer class that regroups:
- the world; an instance of ``World`` which will be used to perform a step in the world (simulator). This is called at each step performed by the environment.
- the states: an instance of ``State`` (or a list of them). The states are updated at each time step by the environment.
- the rewards (optional): an instance of ``Reward`` (or a list of them). It is optional because some environments like in imitation learning does not require a reward function. The reward functions are computed at each time step.
- the terminal conditions (optional): an instance of ``TerminalCondition`` (or a list of them) that checks at each time step if the goal of the environment has been achieved. A ``TerminalCondition`` also details if the environment ended with a success or failure.
- the initial state generators (optional): an instance of ``StateGenerator`` (or a list of them) which are called to generate the initial states each time the environment is reset.
- the physics randomizers (optional): an instance of ``PhysicsRandomizer`` (or a list of them) to randomize the physical properties of bodies in the simulator, or the simulator itself, each time the environment is reset.
- the actions (optional): an instance of ``Action`` (or a list of them). The actions are not used nor updated by the environment. This is left to the ``Policy`` or ``Controller``.
By favoring `composition over inheritance <https://en.wikipedia.org/wiki/Composition_over_inheritance>`_ for the environment class, we improve the flexibility of the framework and the reuse of different modules.
This leads ultimately to less code duplication, and ease the process of creating environments.
Here is a short snippet showing the basic usage of an environment:
.. code-block:: python
:linenos:
import pyrobolearn as prl
# define the simulator and world (and load what you want in it)
sim = ...
world = ...
robot = ...
# define state, action, and reward (and possibly action)
state = ...
action = ...
reward = ...
# you can give the reward function to your RL environment
# which will use it when calling `env.step()`.
env = prl.envs.Env(world, state, reward)
# like in OpenAI gym environments, you can reset and step in the environment
obs = env.reset()
for t in count():
obs, rew, done, info = env.step()
Few notes regarding the code above:
- the ``action`` can also be given to the environment but it won't be called by the environment. This is carried out by the policy(ies)/agent(s). The main reason why you can give an action to an environment is when later you will create your own environment class (that inherits from ``prl.envs.Env``), you will be able to get the states and actions for your policies in the following way:
.. code-block:: python
:linenos:
import pyrobolearn as prl
# define your environment
class MyEnv(prl.envs.Env):
...
# create the environment and provide possible arguments
env = MyEnv(args)
# get states and actions from your environment
states, actions = env.states, env.actions
# create policy
policy = Policy(states, actions)
- the observation ``obs`` is a list of arrays that are returned by the environment. This is a bit different from what it is usually returned by gym environments (which is an array). The reason is that the states returned by the environment might have different dimensions (e.g. joint positions = 1D array, camera = 2D/3D array, etc) so you can not return one array.
- You can easily update the state, reward function, world, and other modules that are given to environment. This results in less code duplication and greater flexibility.
For more info, please check the documentation.
Examples
~~~~~~~~
Here are few examples that you can find in this folder that better demonstrate how to use the environment:
1. ``basics.py``: show the flexibility of how to build an environment and use it.
2. ``manipulator.py``: show how to define an environment where the goal is to reach a target object using a manipulator.
References:
.. [1] "Reinforcement Learning: An Introduction", Sutton and Barto, 1998
+15 -2
View File
@@ -1,4 +1,17 @@
## Interfaces
## Interfaces and Bridges
In this folder, you will find examples on what interfaces you can use and on how you can collect the data from them.
You will also be able to connect an interface with an element of the world (in this case, a robot) using bridges, and see that different bridges can lead to different behaviors while getting the data from the same interface.
You will also be able to connect an interface with an element of the world (in this case, a robot) using bridges,
and see that different bridges can lead to different behaviors while getting the data from the same interface.
Here are few examples that depict the various interfaces available to the user:
1. `mouse_keyboard.py`: use the mouse keyboard interface
2. `webcam.py`: use the webcam interface
3. `playstation.py`: use the Playstation game controller interface
4. `xbox.py`: use the Xbox game controller interface
5. `asus_xtion.py`: use the Asus Xtion interface
6. `openpose.py`: use the Openpose interface
7. `speech.py`: use the speech (recognizer/translator) interface
8. `spacemouse.py`: use the (3Dconnexion) SpaceMouse interface
**Note**: some interfaces require to install different libraries, and possibly to configure them. Check the raised errors.
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env python
"""Run the Asus Xtion interface.
Make sure that the `openni` library is installed with all the correct environment variables set, and that the Asus
Xtion is connected before running this code. Note that it can take some time to initialize the interface.
"""
import argparse
import matplotlib.pyplot as plt
from pyrobolearn.tools.interfaces.camera.asus_xtion import AsusXtionInterface
# create parser
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--use_thread', help='If we should run the webcam interface in a thread.', type=bool,
default=False)
parser.add_argument('-r', '--use_rgb', help='If we should get RGB images. Note that RGB and IR images can not be '
'captured at the same time.', type=bool,
default=True)
parser.add_argument('-d', '--use_depth', help='If we should get depth images.', type=bool,
default=True)
parser.add_argument('-i', '--use_ir', help='If we should get IR images. Note that RGB and IR images can not be '
'captured at the same time.', type=bool,
default=False)
args = parser.parse_args()
# get which pictures to capture
use_rgb, use_depth, use_ir = args.use_rgb, args.use_depth, args.use_ir
if use_rgb and use_ir:
use_ir = False
# create Asus Xtion interface
interface = AsusXtionInterface(use_rgb=use_rgb, use_depth=use_depth, use_ir=use_ir)
# plotting using matplotlib in interactive mode
fig, axes = plt.subplots(1, 2)
plots = [None]*2
titles = []
if use_rgb:
titles.append('RGB')
if use_ir:
titles.append('IR')
if use_depth:
titles.append('Depth')
plt.ion() # interactive mode on
while True:
# if don't use thread call `step` or `run`
data = interface.run()
# get the frame and plot it with matplotlib
if plots[0] is None:
for i in range(len(plots)):
plots[i] = axes[i].imshow(data[i])
axes[i].set_title(titles[i])
else:
for plot, img in zip(plots, data):
plot.set_data(img)
# pause a bit
plt.pause(0.01)
# check if the figure is closed, and if so, get out of the loop
if not plt.fignum_exists(fig.number):
break
plt.ioff() # interactive mode off
plt.show()
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python
"""Load the mouse keyboard interface.
"""
from itertools import count
import pyrobolearn as prl
from pyrobolearn.tools.interfaces.mouse_keyboard import MouseKeyboardInterface
# create simulator
sim = prl.simulators.Bullet()
# create mouse keyboard interface
# Note that to give the simulator `sim` to the interface can be optional especially if there is only one simulator.
# The interface will look in the memory to check the instantiated simulators and take the first one if it exists.
interface = MouseKeyboardInterface(sim)
# run interface
for _ in count():
# perform a step with the interface
interface.step()
# print pressed keys
if len(interface.key_pressed) > 0:
print("Keys that are pressed: {}".format(interface.key_pressed))
if len(interface.key_down) > 0:
print("Keys that are down: {}".format(interface.key_down))
# perform a step with the simulator
sim.step(sleep_time=sim.dt)
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python
"""Run the Openpose interface.
Make sure that the webcam is connected, and that the openpose framework has been installed before running this code.
For this code to work, you have to specify the path to the openpose framework, or set the `OPENPOSE_PATH` environment
variable. Note that it can take some time to initialize the interface.
"""
import cv2
import argparse
from pyrobolearn.tools.interfaces.camera.openpose import OpenPoseInterface
# create parser
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--path', help='Absolute path to the openpose framework. If not specified, it will check '
'for the environment variable `OPENPOSE_PATH`.', type=str, default='')
parser.add_argument('-t', '--use_thread', help='If we should run the openpose interface in a thread.', type=bool,
default=False)
parser.add_argument('-f', '--detect_face', help='If we should detect the face with openpose.', type=bool,
default=True)
parser.add_argument('-a', '--detect_hands', help='If we should detect the hands with openpose.', type=bool,
default=False)
args = parser.parse_args()
path = None if args.path == '' else args.path
# create openpose interface
if args.use_thread:
# create and run interface in a thread
interface = OpenPoseInterface(openpose_path=path, detect_face=args.detect_face, detect_hands=args.detect_hands,
use_thread=True, sleep_dt=1. / 10, verbose=True)
raw_input('Press key to stop the openpose interface')
else:
# create interface
interface = OpenPoseInterface(openpose_path=path, detect_face=args.detect_face, detect_hands=args.detect_hands)
# run interface
while True:
frame, keypoints = interface.run()
cv2.imshow("OpenPose 1.4.0 - Tutorial Python API", frame)
# quit display if 'esc' button is pressed
key = cv2.waitKey(15) & 0xFF
if key == 27:
cv2.destroyWindow('frame')
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python
"""Load the Playstation game controller interface
How to run:
```
$ python playstation.py --help # for help
$ python playstation.py --controller ps # to use any PS game controller (by default)
$ python playstation.py --controller ps3 # to use PS3 game controller
$ python playstation.py --controller ps4 # to use PS4 game controller
```
Note that these game controllers are blocking by default, thus set `use_thread` to True to avoid to be blocked.
"""
import time
import argparse
from pyrobolearn.tools.interfaces.controllers.playstation import *
# create parser to select the game controller
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--use_thread', help='If we should run the PlayStation controller in a thread.', type=bool,
default=True)
parser.add_argument('-c', '--controller', help='The Playstation game controller to use (ps, ps3, or ps4)', type=str,
choices=['ps', 'ps3', 'ps4'], default='ps')
args = parser.parse_args()
# load corresponding Playstation controller interface
if args.controller == 'ps':
controller = PSControllerInterface(use_thread=args.use_thread, verbose=False)
if args.controller == 'ps3':
controller = PS3ControllerInterface(use_thread=args.use_thread, verbose=False)
elif args.controller == 'ps4':
controller = PS4ControllerInterface(use_thread=args.use_thread, verbose=False)
else:
raise NotImplementedError("Unknown game controller")
# run controller
print('Running controller...')
while True:
# run one step with the interface
controller.step() # same as `step()` if we are not using threads
# get the last update and print it
b = controller.last_updated_button
print("Last updated button: {} with value: {}".format(b, controller[b]))
# sleep a bit
time.sleep(0.01)
@@ -0,0 +1,85 @@
#!/usr/bin/env python
"""Control a quadcopter in the air using an Xbox or Playstation game controller.
how to run:
```
$ python quadcopter_controller.py --help # for help
$ python quadcopter_controller.py --controller keyboard # to use the keyboard
$ python quadcopter_controller.py --controller xbox # to use Xbox game controller
$ python quadcopter_controller.py --controller ps # to use PS game controller
```
Mapping of the keyboard interface:
- `top arrow`: move forward
- `bottom arrow`: move backward
- `left arrow`: move sideways to the left
- `right arrow`: move sideways to the right
- `ctrl + top arrow`: ascend
- `ctrl + bottom arrow`: descend
- `ctrl + left arrow`: turn to the right
- `ctrl + right arrow`: turn to the left
- `space`: switch between first-person and third-person view
Mapping between the controller and the quadcopter:
- left joystick: use to move the quadcopter
- right joystick: use to ascend/descend and turn
- south button (X on PlayStation and A on Xbox): change between the first-person and third-person view.
- east button (circle on PlayStation and B on Xbox): increase the speed
- west button (square on PlayStation and X on Xbox): decrease the speed
"""
# import numpy as np
from itertools import count
import argparse
import pyrobolearn as prl
# create parser to select the game controller
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--controller', help='the controller to use', type=str,
choices=['keyboard', 'xbox', 'ps'], default='keyboard')
args = parser.parse_args()
# load corresponding interface
if args.controller == 'keyboard': # keyboard interface
from pyrobolearn.tools.interfaces.mouse_keyboard.mousekeyboard import MouseKeyboardInterface as Controller
from pyrobolearn.tools.bridges.mouse_keyboard.bridge_mousekeyboard_quadcopter \
import BridgeMouseKeyboardQuadcopter as Bridge
elif args.controller == 'xbox': # Xbox interface
from pyrobolearn.tools.interfaces.controllers.xbox import XboxControllerInterface as Controller
from pyrobolearn.tools.bridges.controllers.robots.bridge_controller_quadcopter import BridgeControllerQuadcopter \
as Bridge
elif args.controller == 'ps': # PS interface
from pyrobolearn.tools.interfaces.controllers.playstation import PSControllerInterface as Controller
from pyrobolearn.tools.bridges.controllers.robots.bridge_controller_quadcopter import BridgeControllerQuadcopter \
as Bridge
else:
raise NotImplementedError("Unknown game controller")
# create simulator
sim = prl.simulators.Bullet()
# create basic world (with a floor and gravity enabled by default)
world = prl.worlds.BasicWorld(sim)
# load quadcopter
robot = prl.robots.Quadcopter(sim, position=[0., 0., 2.])
world.load_robot(robot)
# load interface that accepts input events
controller = Controller(use_thread=True, verbose=False)
# load bridge that connects the interface/controller with the quadcopter
# The bridge is the one that maps the input events from the interface to commands sent to the quadcopter
bridge = Bridge(quadcopter=robot, interface=controller)
# run simulator
for t in count():
# perform a step with the bridge and interface
bridge.step(update_interface=True)
# perform one step in the world
world.step(sleep_dt=1. / 240)
@@ -0,0 +1,41 @@
#!/usr/bin/env python
"""Control a quadcopter in the air using speech.
Try to say:
- turn right/left
- move/go higher/lower/forward/backward/right/left
- go faster/slower
- anything else will ask the robot to hover
"""
from itertools import count
import pyrobolearn as prl
from pyrobolearn.tools.bridges.audio.robots.bridge_speech_quadcopter import BridgeSpeechRecognizerQuadcopter
# create simulator
sim = prl.simulators.Bullet()
# create basic world (with a floor and gravity enabled by default)
world = prl.worlds.BasicWorld(sim)
# load quadcopter
robot = prl.robots.Quadcopter(sim, position=[0., 0., 2.])
world.load_robot(robot)
# load bridge that connects the speech interface with the quadcopter
# Note that it will create automatically the Speech Recognizer interface inside the bridge
bridge = BridgeSpeechRecognizerQuadcopter(robot=robot, interface=None, verbose=True)
# run simulator
for t in count():
# perform a step with the bridge and interface
bridge.step(update_interface=True)
# ask the world camera to follow the wheeled robot
world.follow(robot, distance=2)
# perform one step in the world
world.step(sleep_dt=1. / 240)
@@ -0,0 +1,79 @@
#!/usr/bin/env python
"""Control a wheeled robot using a keyboard, an Xbox or Playstation game controller.
how to run:
```
$ python wheeled_controller.py --help # for help
$ python wheeled_controller.py --controller keyboard # to use the keyboard
$ python wheeled_controller.py --controller xbox # to use Xbox game controller
$ python wheeled_controller.py --controller ps # to use PS game controller
```
Mapping of the keyboard interface:
* `top arrow`: move forward
* `bottom arrow`: move backward
* `left arrow`: turn/steer to the left
* `right arrow`: turn/steer to the right
Mapping between the controller and the wheeled robot:
- left joystick: velocity of the wheeled robot
- east button (circle on PlayStation and B on Xbox): increase the speed
- west button (square on PlayStation and X on Xbox): decrease the speed
"""
# import numpy as np
from itertools import count
import argparse
import pyrobolearn as prl
# create parser to select the game controller
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--controller', help='the controller to use', type=str,
choices=['keyboard', 'xbox', 'ps'], default='keyboard')
args = parser.parse_args()
# load corresponding interface
if args.controller == 'keyboard': # keyboard interface
from pyrobolearn.tools.interfaces.mouse_keyboard.mousekeyboard import MouseKeyboardInterface as Controller
from pyrobolearn.tools.bridges.mouse_keyboard.bridge_mousekeyboard_wheeled \
import BridgeMouseKeyboardDifferentialWheeledRobot as Bridge
elif args.controller == 'xbox': # Xbox interface
from pyrobolearn.tools.interfaces.controllers.xbox import XboxControllerInterface as Controller
from pyrobolearn.tools.bridges.controllers.robots.bridge_controller_wheeled import BridgeControllerWheeledRobot \
as Bridge
elif args.controller == 'ps': # PS interface
from pyrobolearn.tools.interfaces.controllers.playstation import PSControllerInterface as Controller
from pyrobolearn.tools.bridges.controllers.robots.bridge_controller_wheeled import \
BridgeControllerWheeledRobot as Bridge
else:
raise NotImplementedError("Unknown game controller")
# create simulator
sim = prl.simulators.Bullet()
# create basic world (with a floor and gravity enabled by default)
world = prl.worlds.BasicWorld(sim)
# load wheeled robot
robot = prl.robots.Epuck(sim, position=[0., 0.])
world.load_robot(robot)
# load interface that accepts input events
controller = Controller(use_thread=True, verbose=False)
# load bridge that connects the interface/controller with the quadcopter
# The bridge is the one that maps the input events from the interface to commands sent to the quadcopter
bridge = Bridge(robot=robot, interface=controller)
# run simulator
for t in count():
# perform a step with the bridge and interface
bridge.step(update_interface=True)
# perform one step in the world
world.step(sleep_dt=1. / 240)
@@ -0,0 +1,41 @@
#!/usr/bin/env python
"""Control a wheeled robot in the air using speech.
Try to say:
- turn right/left
- move/go forward/backward
- go faster/slower
- anything else will ask the robot to hover
"""
from itertools import count
import pyrobolearn as prl
from pyrobolearn.tools.bridges.audio.robots.bridge_speech_wheeled import BridgeSpeechRecognizerDifferentialWheeledRobot
# create simulator
sim = prl.simulators.Bullet()
# create basic world (with a floor and gravity enabled by default)
world = prl.worlds.BasicWorld(sim)
# load wheeled robot
robot = prl.robots.Epuck(sim, position=[0., 0.])
world.load_robot(robot)
# load bridge that connects the speech interface with the wheeled robot
# Note that it will create automatically the Speech Recognizer interface inside the bridge
bridge = BridgeSpeechRecognizerDifferentialWheeledRobot(robot=robot, interface=None, verbose=True)
# run simulator
for t in count():
# perform a step with the bridge and interface
bridge.step(update_interface=True)
# ask the world camera to follow the wheeled robot
world.follow(robot, distance=2)
# perform one step in the world
world.step(sleep_dt=1. / 240)
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python
"""Run the Space mouse interface.
Make sure that the `spnav` library is installed, and the space mouse (by 3Dconnexion) is connected to the computer
before running this code.
"""
import argparse
import time
from pyrobolearn.tools.interfaces.mouse_keyboard.spacemouse import SpaceMouseInterface
# create parser
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--use_thread', help='If we should run the webcam interface in a thread.', type=bool,
default=True)
args = parser.parse_args()
# create webcam interface
if args.use_thread:
# create and run interface in a thread
interface = SpaceMouseInterface(use_thread=True, sleep_dt=0.001, verbose=True)
raw_input('Press key to stop the space mouse interface')
else:
# create interface
interface = SpaceMouseInterface(use_thread=False, verbose=True)
while True:
# perform a `step` with the interface
interface.step()
time.sleep(0.001)
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env python
"""Run the speech interface.
This will perform speech recognition, translation, and synthesization. Make sure that your computer has a microphone
connected.
In the future, interfaces using the Google assistant, Alexa, or a similar tool will be implemented.
"""
import argparse
from pyrobolearn.tools.interfaces.audio.speech import SpeechRecognizerInterface, SpeechTranslatorInterface
# get the available languages.
languages = SpeechRecognizerInterface.available_languages
print("Available languages are: {}".format(languages))
# create parser
parser = argparse.ArgumentParser()
# parser.add_argument('-t', '--use_thread', help='If we should run the webcam interface in a thread.', type=bool,
# default=False)
parser.add_argument('-l', '--lang', help='The language that needs to be recognized.', type=str, choices=languages,
default='english')
parser.add_argument('-a', '--target_lang', help='If we should get depth images.', type=str, choices=languages,
default='english')
args = parser.parse_args()
# create speech recognizer/translator interface
# interface = SpeechRecognizerInterface(verbose=True, lang=args.lang)
interface = SpeechTranslatorInterface(verbose=True, from_lang=args.lang, target_lang=args.target_lang)
# run the interface
while True:
data = interface.step()
+41 -23
View File
@@ -1,34 +1,52 @@
#!/usr/bin/env python
"""Load the Webcam interface.
"""Run the Webcam interface.
Make sure that the webcam is connected before running this code. Note that it can take some time to initialize
the interface.
"""
from itertools import count
import argparse
import matplotlib.pyplot as plt
from pyrobolearn.tools.interfaces.camera.webcam import WebcamInterface
# create interface
interface = WebcamInterface(use_thread=True, sleep_dt=1./10, verbose=False)
# plotting using matplotlib in interactive mode
fig = plt.figure()
plot = None
plt.ion() # interactive mode on
# create parser
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--use_thread', help='If we should run the webcam interface in a thread.', type=bool,
default=False)
args = parser.parse_args()
for _ in count():
# # if don't use thread call `step` or `run` (note that `run` returns the frame but not
# interface.step()
# get the frame and plot it with matplotlib
frame = interface.frame
if plot is None:
plot = plt.imshow(frame)
else:
plot.set_data(frame)
plt.pause(0.01)
# create webcam interface
if args.use_thread:
# create and run interface in a thread
interface = WebcamInterface(use_thread=True, sleep_dt=1./10, verbose=True)
raw_input('Press key to stop the webcam interface')
else:
# create interface
interface = WebcamInterface()
# check if the figure is closed, and if so, get out of the loop
if not plt.fignum_exists(fig.number):
break
# plotting using matplotlib in interactive mode
fig = plt.figure()
plot = None
plt.ion() # interactive mode on
plt.ioff() # interactive mode off
plt.show()
while True:
# perform a `step` with the interface
interface.step()
# get the frame and plot it with matplotlib
frame = interface.frame
if plot is None:
plot = plt.imshow(frame)
else:
plot.set_data(frame)
plt.pause(0.01)
# check if the figure is closed, and if so, get out of the loop
if not plt.fignum_exists(fig.number):
break
plt.ioff() # interactive mode off
plt.show()
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env python
"""Load the Xbox game controller interface
How to run:
```
$ python xbox.py --help # for help
$ python xbox.py --controller xbox # to use any Xbox game controller (by default)
$ python xbox.py --controller xbox-360 # to use Xbox 360 game controller
$ python xbox.py --controller xbox-one # to use Xbox One game controller
```
Note that these game controllers are blocking by default, thus set `use_thread` to True to avoid to be blocked.
"""
import time
import argparse
from pyrobolearn.tools.interfaces.controllers.xbox import XboxControllerInterface, XboxOneControllerInterface, \
Xbox360ControllerInterface
# create parser to select the game controller
parser = argparse.ArgumentParser()
parser.add_argument('-t', '--use_thread', help='If we should run the Xbox controller in a thread.', type=bool,
default=True)
parser.add_argument('-c', '--controller', help='The Xbox game controller to use.', type=str,
choices=['xbox', 'xbox-360', 'xbox-one'], default='xbox')
args = parser.parse_args()
# load corresponding Xbox controller interface
if args.controller == 'xbox':
controller = XboxControllerInterface(use_thread=args.use_thread, verbose=False)
elif args.controller == 'xbox-360':
controller = Xbox360ControllerInterface(use_thread=args.use_thread, verbose=False)
elif args.controller == 'xbox-one':
controller = XboxOneControllerInterface(use_thread=args.use_thread, verbose=False)
else:
raise NotImplementedError("Unknown game controller")
# run controller
print('Running controller...')
while True:
# run one step with the interface
controller.step()
# get the last update and print it
b = controller.last_updated_button
print("Last updated button: {} with value: {}".format(b, controller[b]))
# sleep a bit
time.sleep(0.01)
+13
View File
@@ -2,6 +2,19 @@
We provide examples on how to perform forward and inverse kinematics.
Here are the forward kinematics (FK) examples that the user can try:
1. `fk.py`: simple forward kinematics example where we directly sent desired joint positions to the Kuka
manipulator.
Here are the inverse kinematics (IK) examples that the user can try:
1. `ik.py`: simple inverse kinematics example where the Kuka manipulator has to reach a certain target position
in the world. In this example, the user can also choose the damped-least-squares IK solver.
2. `ik_libraries.py`: comparison between different IK libraries including `pybullet`, `PyKDL`, `trac_ik`, and
`rbdl` using the Kuka manipulator.
3. `moving_sphere.py`: damped-least-squares IK with the Kuka manipulator where the goal is to follow a sphere
that moves in a circular manner.
References:
- [1] "Robotics: Modelling, Planning and Control", Siciliano et al., 2010
- [2] "Springer Handbook of Robotics", Siciliano et al., 2008
+1 -1
View File
@@ -43,7 +43,7 @@ sphere = Body(sim, body_id=sphere)
for t in count():
# if no more joint positions, get out of the loop
if t > len(positions):
if t >= len(positions):
break
# set joint positions
+14 -5
View File
@@ -8,16 +8,25 @@ Set the `solver_flag` to a number between 0 and 1 (see lines [19,22]) to select
import numpy as np
from itertools import count
import argparse
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import KukaIIWA
# create parser to select the IK solver
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--solver', help='the IK solver to select (0: use robot.calculate_inverse_kinematics(), '
'1: use damped-least-squares IK using Jacobian)', type=int,
choices=[0, 1], default=1)
args = parser.parse_args()
# select IK solver, by setting the flag:
# 0 = pybullet + calculate_inverse_kinematics()
# 1 = pybullet + damped-least-squares IK using Jacobian (provided by pybullet)
solver_flag = 1 # 1 and 4 gives pretty good results
solver_flag = args.solver # 1 gives a pretty good result
# Create simulator
@@ -34,6 +43,7 @@ robot.print_info()
dt = 1./240
link_id = robot.get_end_effector_ids(end_effector=0)
joint_ids = robot.joints # actuated joint
# joint_ids = joint_ids[2:]
damping = 0.01 # for damped-least-squares IK
wrt_link_id = -1 # robot.get_link_ids('iiwa_link_1')
@@ -41,11 +51,10 @@ wrt_link_id = -1 # robot.get_link_ids('iiwa_link_1')
xd = np.array([0.5, 0., 0.5])
world.load_visual_sphere(xd, radius=0.05, color=(1, 0, 0, 0.5))
# joint_ids = joint_ids[2:]
# change the robot visual
robot.change_transparency()
robot.draw_link_frames([-1, 0])
robot.draw_bounding_boxes(joint_ids[0])
robot.draw_link_frames(link_ids=[-1, 0])
robot.draw_bounding_boxes(link_ids=joint_ids[0])
# robot.draw_link_coms([-1,0])
qIdx = robot.get_q_indices(joint_ids)
+46 -31
View File
@@ -14,40 +14,23 @@ Set the `solver_flag` to a number between 0 and 4 (see lines [53,60]) to select
import os
import numpy as np
from itertools import count
import argparse
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import KukaIIWA
# import PyKDL
try:
import PyKDL as kdl
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `PyKDL`: '
'sudo apt-get install ros-<distribution>-python-orocos-kdl'
'or install it manually from `https://github.com/orocos/orocos_kinematics_dynamics`')
# import kdl_parser_py
try:
import kdl_parser_py.urdf as KDLParser
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `kdl_parser_py`: '
'sudo apt-get install ros-<distribution>-kdl-parser-py')
# import track_ik_python
try:
from trac_ik_python.trac_ik import IK as TracIK
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `trac_ik_python`: '
'sudo apt-get install ros-<distribution>-trac-ik-python')
# import rbdl
try:
import rbdl
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `rbdl` manually from `https://bitbucket.org/rbdl/rbdl`')
# create parser to select the IK solver
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--solver', help='the IK solver to select:\n'
'0: use robot.calculate_inverse_kinematics()\n'
'1: use damped-least-squares IK using Jacobian (provided by simulator)\n'
'2: use PyKDL\n'
'3: use trac_ik\n'
'4: use rbdl + damped-least-squares IK using Jacobian (provided by rbdl)',
type=int, choices=[0, 1, 2, 3, 4], default=1)
args = parser.parse_args()
# TO BE SET BY THE USER
# select IK solver, by setting the flag:
@@ -56,7 +39,39 @@ except ImportError as e:
# 2 = PyKDL
# 3 = trac_ik
# 4 = rbdl + damped-least-squares IK using Jacobian (provided by rbdl)
solver_flag = 1 # 1 and 4 gives pretty good results
solver_flag = args.solver # 1 and 4 gives pretty good results
if solver_flag == 2: # PyKDL
# import PyKDL
try:
import PyKDL as kdl
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `PyKDL`: '
'sudo apt-get install ros-<distribution>-python-orocos-kdl'
'or install it manually from '
'`https://github.com/orocos/orocos_kinematics_dynamics`')
# import kdl_parser_py
try:
import kdl_parser_py.urdf as kdl_parser
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `kdl_parser_py`: '
'sudo apt-get install ros-<distribution>-kdl-parser-py')
elif solver_flag == 3: # trac_ik_python
# import trac_ik_python
try:
from trac_ik_python.trac_ik import IK as trac_ik
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `trac_ik_python`: '
'sudo apt-get install ros-<distribution>-trac-ik-python')
elif solver_flag == 4: # rbdl
# import rbdl
try:
import rbdl
except ImportError as e:
raise ImportError(repr(e) + '\nTry to install `rbdl` manually from `https://bitbucket.org/rbdl/rbdl`')
# Create simulator
@@ -181,7 +196,7 @@ elif solver_flag == 1:
##################
elif solver_flag == 2:
print("Using PyKDL:")
model = KDLParser.treeFromFile(urdf)
model = kdl_parser.treeFromFile(urdf)
if model[0]:
model = model[1]
else:
@@ -237,7 +252,7 @@ elif solver_flag == 3:
urdf_string = open(urdf, 'r').read()
# create IK solver
ik_solver = TracIK(base_link=base_name, tip_link=end_effector_name, urdf_string=urdf_string, solve_type='Distance')
ik_solver = trac_ik(base_link=base_name, tip_link=end_effector_name, urdf_string=urdf_string, solve_type='Distance')
# define upper and lower limits (optional)
# lb, ub = -np.ones(6)*100, np.ones(6)*100
@@ -0,0 +1,41 @@
#!/usr/bin/env python
"""Draw the 2D velocity and force manipulability ellipsoids on the end-effector of a 3-link planar manipulator.
References:
[1] "Robotics: Modelling, Planning and Control" (section 3.9), Siciliano et al., 2010
"""
import time
# from itertools import count
import numpy as np
import pyrobolearn as prl
# create simulator
sim = prl.simulators.Bullet()
# create world
world = prl.worlds.BasicWorld(sim)
# create robot
robot = world.load_robot('manipulator2d')
robot.reset_joint_states(q=[0.64453457, -1.65045902, -0.31141744])
# change camera view
world.camera.reset(distance=2, yaw=-np.pi / 2, pitch=-np.pi/2.01)
# draw 2d velocity manipulability ellipsoid
# print(robot.end_effector_names)
end_effector_id = robot.get_link_ids('gripper')
jacobian = robot.get_linear_jacobian(link_id=end_effector_id)
jjt = robot.get_JJT(jacobian)
robot.draw_velocity_manipulability_ellipsoid(link_id=end_effector_id, JJT=jjt, color=(0, 1, 0, 0.7)) # green
robot.draw_force_manipulability_ellipsoid(link_id=end_effector_id, JJT=jjt, color=(1, 0, 0, 0.7)) # red
# TODO: fix bug
time.sleep(10000)
# run simulator
# for t in count():
# world.step(sleep_dt=1./240)
+10
View File
@@ -2,6 +2,16 @@
We provide examples on how to use manipulability ellipsoids.
Here are a short description of the various examples the user can try:
1. `2d_manipulability.py`: draw the 2D velocity and force manipulability ellipsoids on the end-effector of a
3-link planar manipulator.
2. `com_manipulability_tracking.py`: track the velocity manipulability ellipsoid of the center of mass of a robot
with a fixed base.
3. `com_manipulability_tracking_with_balance.py`: track the velocity manipulability ellipsoid of the center of mass
of a floating-base robot while keeping its balance.
4. `com_dynamic_manipulability_tracking_with_balance.py`: track the dynamic manipulability ellipsoid of the center
of mass of a floating-base robot while keeping its balance.
References:
- [1] "Robotics: Modelling, Planning and Control", Siciliano et al., 2010
- [2] "Springer Handbook of Robotics", Siciliano et al., 2008
@@ -185,13 +185,13 @@ CoMr = robot.get_center_of_mass_position() # Desired CoM
print("CoMr: {}".format(CoMr))
if robot.name == 'centauro':
xref_l1f = robot.get_link_frame_world_positions(left_foot1_id) # Desired position for left foot
xref_r1f = robot.get_link_frame_world_positions(right_foot1_id) # Desired position for right foot
xref_l2f = robot.get_link_frame_world_positions(left_foot2_id) # Desired position for left foot
xref_r2f = robot.get_link_frame_world_positions(right_foot2_id) # Desired position for right foot
xref_l1f = robot.get_link_world_frame_positions(left_foot1_id) # Desired position for left foot
xref_r1f = robot.get_link_world_frame_positions(right_foot1_id) # Desired position for right foot
xref_l2f = robot.get_link_world_frame_positions(left_foot2_id) # Desired position for left foot
xref_r2f = robot.get_link_world_frame_positions(right_foot2_id) # Desired position for right foot
else:
xref_lf = robot.get_link_frame_world_positions(left_foot_id) # Desired position for left foot
xref_rf = robot.get_link_frame_world_positions(right_foot_id) # Desired position for right foot
xref_lf = robot.get_link_world_frame_positions(left_foot_id) # Desired position for left foot
xref_rf = robot.get_link_world_frame_positions(right_foot_id) # Desired position for right foot
# Display initial and desired manipulability ellipsoid
@@ -220,13 +220,13 @@ for i in range(num_samples):
robot.draw_com_position(0.03)
if robot.name == 'centauro':
xt_l1f = robot.get_link_frame_world_positions(left_foot1_id) # Current position for left foot
xt_r1f = robot.get_link_frame_world_positions(right_foot1_id) # Current position for right foot
xt_l2f = robot.get_link_frame_world_positions(left_foot2_id) # Current position for left foot
xt_r2f = robot.get_link_frame_world_positions(right_foot2_id) # Current position for right foot
xt_l1f = robot.get_link_world_frame_positions(left_foot1_id) # Current position for left foot
xt_r1f = robot.get_link_world_frame_positions(right_foot1_id) # Current position for right foot
xt_l2f = robot.get_link_world_frame_positions(left_foot2_id) # Current position for left foot
xt_r2f = robot.get_link_world_frame_positions(right_foot2_id) # Current position for right foot
else:
xt_lf = robot.get_link_frame_world_positions(left_foot_id) # Current left foot pos
xt_rf = robot.get_link_frame_world_positions(right_foot_id) # Current right foot pos
xt_lf = robot.get_link_world_frame_positions(left_foot_id) # Current left foot pos
xt_rf = robot.get_link_world_frame_positions(right_foot_id) # Current right foot pos
# Simple balance control with IK kinematics for CoM and feet
# Get Jacobians: Jcom, Jlf, and Jrf
@@ -181,15 +181,15 @@ CoMr = robot.get_center_of_mass_position() # Desired CoM
print("CoMr: {}".format(CoMr))
if robot.name == 'centauro':
xref_l1f = robot.get_link_frame_world_positions(left_foot1_id) # Desired position for left foot
xref_r1f = robot.get_link_frame_world_positions(right_foot1_id) # Desired position for right foot
xref_l2f = robot.get_link_frame_world_positions(left_foot2_id) # Desired position for left foot
xref_r2f = robot.get_link_frame_world_positions(right_foot2_id) # Desired position for right foot
xref_l1f = robot.get_link_world_frame_positions(left_foot1_id) # Desired position for left foot
xref_r1f = robot.get_link_world_frame_positions(right_foot1_id) # Desired position for right foot
xref_l2f = robot.get_link_world_frame_positions(left_foot2_id) # Desired position for left foot
xref_r2f = robot.get_link_world_frame_positions(right_foot2_id) # Desired position for right foot
else:
xref_lf = robot.get_link_frame_world_positions(left_foot_id) # Desired position for left foot
# Qref_lf = robot.get_link_frame_world_orientations(leftFootId)
xref_rf = robot.get_link_frame_world_positions(right_foot_id) # Desired position for right foot
# Qref_rf = robot.get_link_frame_world_orientations(rightFootId)
xref_lf = robot.get_link_world_frame_positions(left_foot_id) # Desired position for left foot
# Qref_lf = robot.get_link_world_frame_orientations(leftFootId)
xref_rf = robot.get_link_world_frame_positions(right_foot_id) # Desired position for right foot
# Qref_rf = robot.get_link_world_frame_orientations(rightFootId)
# Display initial and desired manipulability ellipsoid
@@ -221,14 +221,14 @@ for i in range(400):
robot.draw_com_position(0.03)
if robot.name == 'centauro':
xt_l1f = robot.get_link_frame_world_positions(left_foot1_id) # Current position for left foot
xt_r1f = robot.get_link_frame_world_positions(right_foot1_id) # Current position for right foot
xt_l2f = robot.get_link_frame_world_positions(left_foot2_id) # Current position for left foot
xt_r2f = robot.get_link_frame_world_positions(right_foot2_id) # Current position for right foot
xt_l1f = robot.get_link_world_frame_positions(left_foot1_id) # Current position for left foot
xt_r1f = robot.get_link_world_frame_positions(right_foot1_id) # Current position for right foot
xt_l2f = robot.get_link_world_frame_positions(left_foot2_id) # Current position for left foot
xt_r2f = robot.get_link_world_frame_positions(right_foot2_id) # Current position for right foot
else:
xt_lf = robot.get_link_frame_world_positions(left_foot_id) # Current left foot pos
# Qt_lf = robot.get_link_frame_world_orientations(leftFootId)
xt_rf = robot.get_link_frame_world_positions(right_foot_id) # Current right foot pos
xt_lf = robot.get_link_world_frame_positions(left_foot_id) # Current left foot pos
# Qt_lf = robot.get_link_world_frame_orientations(leftFootId)
xt_rf = robot.get_link_world_frame_positions(right_foot_id) # Current right foot pos
# Simple balance control with IK kinematics for CoM and feet
# Get Jacobians: Jcom, Jlf, and Jrf
+73
View File
@@ -0,0 +1,73 @@
Rewards
=======
In this folder, we provide examples on how to use reward/cost functions which are provided to reinforcement learning environments.
We show the available operations you can use on these.
The reward function might be defined as [1]_:
- :math:`r: \mathcal{S} \rightarrow \mathbb{R}`: given the state :math:`s \in \mathcal{S}`, it returns the reward value :math:`r(s)`.
- :math:`r: \mathcal{S} \times \mathcal{A} \rightarrow \mathbb{R}`: given the state :math:`s \in \mathcal{S}` and action :math:`a \in \mathcal{A}`, it returns the reward value :math:`r(s,a)`.
- :math:`r: \mathcal{S} \times \mathcal{A} \times \mathcal{S} \rightarrow \mathbb{R}`: given the state :math:`s \in \mathcal{S}`, action :math:`a \in \mathcal{A}`, and next state :math:`s' \in \mathcal{S}`, it returns the reward value :math:`r(s,a,s')`.
Note that the cost function is just minus the reward function, i.e. it is given by :math:`c(s,a,s') = -r(s,a,s')`.
In PRL, all reward functions inherit from the abstract ``Reward`` class defined in `pyrobolearn/rewards/reward.py <https://github.com/robotlearn/pyrobolearn/tree/master/pyrobolearn/rewards>`_, and several methods and operations are provided.
You can for instance:
* provide the ``State`` and/or ``Action`` instances to some reward functions that will compute the reward value based on their value.
* access to the range of the reward function.
* add, multiply, divide, subtract, and apply basic functions such as :math:`\exp`, :math:`\cos`, :math:`\sin`, and others on reward functions. The resulting range is automatically scaled based on the operations.
* define your own rewards/costs and reuse them in your code.
Here is a short snippet showing the basic usage of reward functions:
.. code-block:: python
:linenos:
import pyrobolearn as prl
from pyrobolearn.rewards import FixedReward, YourReward
# define the simulator and world (and load what you want in it)
sim = ...
world = ...
...
# define your state / action for your reward function
state = ...
action = ...
# define the reward function
reward = 2 * FixedReward(3) + 0.5 * YourReward(state, action)
# print the range of the reward function
print(reward.range)
# compute the reward value
value = reward()
print(value)
# update the state for instance
state() # this will modify the internal state data
# recompute the reward value
value = reward()
print(value) # you will normally get a different value
# you can give the reward function to your RL environment
# which will use it when calling `env.step()`.
env = prl.envs.Env(world, state, reward)
Examples
~~~~~~~~
Here are few examples that you can find in this folder that better demonstrate how to use the reward functions:
1. ``basics.py``: demonstrate the various features (operations) you can use with the ``Reward`` class.
2. ``manipulator.py``: show how the distance cost decreases as you move the manipulator (with your mouse) closer to the target object in the world.
3. ``forward_progress.py``: show how the reward function that measures how much a robot has moved forward increases / decreases based on the robot velocity. Use the arrow keys on your keyboard to move the robot, and observe how the computed reward value changes.
References:
.. [1] "Reinforcement Learning: An Introduction", Sutton and Barto, 1998
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python
"""Demonstrate the various features (operations) you can use with the ``Reward`` class.
To illustrate the various operations we use the ``FixedReward``.
See the other examples to see how to use more complex reward functions.
"""
import numpy as np
# You can import in two ways reward functions
import pyrobolearn as prl # import PRL
from pyrobolearn.rewards import FixedReward # specify which function you want to import
# You can also import all the reward functions and the mathematical functions but I usually avoid it because
# we do not know while reading the code where the various classes and other functionalities come from
# from pyrobolearn.rewards import *
# define two fixed reward functions
r1 = prl.rewards.FixedReward(value=3)
r2 = FixedReward(value=2, range=(-2, 2))
# print their value by calling them
print("\nInitial rewards: r1 = {}, and r2 = {}".format(r1, r2))
print("Initial reward value: r1() = {}, and r2() = {}".format(r1(), r2()))
print("Initial reward range: range(r1) = {}, and range(r2) = {}".format(r1.range, r2.range))
# try to define a fixed reward function where the initial value is not in the defined range
try:
r3 = FixedReward(value=2, range=(-1, 1))
except ValueError as e:
print("\nTrying `r3=FixedReward(value=2, range=(-1,1))` results in an error: \n" + str(e) + "\n")
# perform some mathematical operations on them
r4 = 2 * prl.rewards.cos(r1) - 3 * r2
# print its value and range
print("Perform mathematical operations on r1 and r2:")
print("r4 = 2 * cos(r1) - 3 * r2 = {}".format(r4()))
print("2 * cos(3) - 3 * 2 = {}".format(2 * np.cos(3) - 3 * 2))
print("range(r4) = {}".format(r4.range))
# try to perform an operation which it not authorized
try:
r5 = r1 / r2 # the range of r2 is [-2, 2] and thus there is a chance it could be 0 at one point
except ValueError as e:
print("\nTrying `r5 = r1 / r2` results in an error: \n" + str(e) + "\n")
# The range of r2 is [-2, 2], if a reward function computes a reward value which is not in the range,
# it will automatically be clipped.
r2.value = 3 # you can only set the value for the FixedReward
print("Setting r2.value=3 while its range is [-2, 2], and computing the reward will result in: r2={}".format(r2()))
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env python
"""Demonstrate how the reward function that measures how much a robot has moved forward increases / decreases based on
the robot velocity. Use the arrow keys on your keyboard to move the robot, and observe how the computed reward value
changes.
"""
from itertools import count
import pyrobolearn as prl
# Create simulator
sim = prl.simulators.Bullet()
# create world
world = prl.worlds.BasicWorld(sim)
# create wheeled robot
robot = world.load_robot('epuck')
# create interface and bridge to control the robot with the keyboard
interface = prl.tools.interfaces.MouseKeyboardInterface()
bridge = prl.tools.bridges.BridgeMouseKeyboardDifferentialWheeledRobot(robot=robot, interface=interface)
# create state
state = prl.states.BasePositionState(robot)
# create reward
reward = 1000 * prl.rewards.ForwardProgressReward(state=state, direction=(1, 0, 0))
# run simulation
for t in count():
# perform a step with the bridge and interface
bridge.step(update_interface=True)
# update state: in this case it will get the base position state and will save it in the state instance
state()
# compute reward: this will look in the previously given state instance its current state data
print("Reward value = {}".format(reward()))
# perform a step in the simulator
world.step(sim.dt)
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env python
"""Demonstrate how the distance cost decreases as you move the manipulator (with your mouse) closer to the target
object in the world.
"""
from itertools import count
import pyrobolearn as prl
# Create simulator
sim = prl.simulators.Bullet()
# create world
world = prl.worlds.BasicWorld(sim)
# create robot
robot = world.load_robot('kuka_iiwa')
end_effector_id = robot.end_effectors[0]
robot.print_info()
# desired position
sphere = world.load_visual_sphere([0.5, 0., 0.], radius=0.05, color=(1, 0, 0, 0.5), return_body=True)
# create state
state = prl.states.LinkWorldPositionState(robot, link_ids=end_effector_id)
# create reward
# note that the given 'sphere' to the cost is not a state, and thus a PositionState will automatically be created
# for that 'sphere', and called at each time the reward is computed.
reward = prl.rewards.DistanceCost(state, sphere)
# run simulation
for t in count():
# update state
state()
# compute reward
print("Reward value = {}".format(reward()))
# perform a step in the simulator
world.step(sim.dt)
+19 -2
View File
@@ -1,5 +1,22 @@
## Robot examples
You can try to load different robot by typing `python <robot>.py`.
More than 60 robots (of various types) are available through `pyrobolearn`.
To turn the camera in the simulator, keep pressing the `ctrl` key and the left button on the mouse, and move this last one.
Here are the few examples that you can find in this folder:
1. `load_robot.py <robot_name>`: load the given robot in the world.
2. `visualize_robot.py <robot_name>`: test different visualization tools that can be used on the robot to show its
joint axis, bounding boxes, and others.
3. `robot_with_sliders.py <robot_name>`: load the given robot in the world and allow you to manipulate the robot's
joints with sliders.
4. `distribute_epucks.py`: distribute several e-pucks in the world and make them move forward.
5. `quadcopter_controller.py`: move a quadcopter in the air using an Xbox or Playstation game controller.
6. `robots/<robot>.py`: load the given robot in the simulator by directly instantiating it. Some of these files do
more than just loading the robot.
Notes: to turn the camera in the simulator, keep pressing the `ctrl` key and the left button on the mouse, and
move this last one.
#### What to check next?
Check the `pyrobolearn/examples/interfaces` or `pyrobolearn/examples/kinematics` folder.
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python
"""Distribute several e-pucks in the world and make them move forward.
You can move in the world using the keyboard and mouse:
- `ctrl + left click`: rotate the camera
- `scroll wheel` or `ctrl + right click`: zoom in/out
- `ctrl + middle click`: move the camera
- `left click` on an object: if the object has a mass and a collision shape, you can interact with it with the mouse
- `w`: wireframe (see collision shapes)
- `g`: show/hide menu
- `esc`: quit the simulator
"""
import numpy as np
from itertools import count
import argparse
import pyrobolearn as prl
# create function for the parser to check the number of robots
def check(number):
"""check that the number of robots is between 1 and 100."""
number = int(number)
if number < 1:
number = 1
if number > 100:
number = 100
return number
# create parser to select the robot
parser = argparse.ArgumentParser()
parser.add_argument('-n', '--number', help='the number of epucks in the world', type=check, default=10)
args = parser.parse_args()
# create simulator
sim = prl.simulators.Bullet()
# create basic world (with a floor and gravity enabled by default)
world = prl.worlds.BasicWorld(sim, scaling=1)
# specify distribution ranges for position (x,y,z) and orientation (r,p,y)
low_position, high_position = [-3, -3, 0], [3, 3, 0] # x,y,z
low_orientation, high_orientation = [0, 0, -np.pi], [0, 0, np.pi] # r,p,y
# distribute the epucks in the world
robots = world.distribute(world.load_robot, size=args.number, position_range=(low_position, high_position),
rpy_range=(low_orientation, high_orientation), return_body=True, robot='epuck')
# run simulator
for t in count():
# move each robot forward
for robot in robots:
robot.drive(speed=5)
# perform one step in the world
world.step(sleep_dt=1. / 240)
+35 -24
View File
@@ -1,33 +1,44 @@
# This file creates a basic world, load each robot that can be found in the PRL framework
#!/usr/bin/env python
"""Load a robot in a basic world.
from pyrobolearn.simulators import BulletSim
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import implemented_robots
You can move in the world using the keyboard and mouse:
- `ctrl + left click`: rotate the camera
- `scroll wheel` or `ctrl + right click`: zoom in/out
- `ctrl + middle click`: move the camera
- `left click` on an object: if the object has a mass and a collision shape, you can interact with it with the mouse
- `w`: wireframe (see collision shapes)
- `g`: show/hide menu
- `esc`: quit the simulator
"""
robot_not_working = set(['icub'])
from itertools import count
import argparse
import pyrobolearn as prl
# get implemented robots
robots = prl.robots.implemented_robots
print("All the robots (total number of robots = {}): {}".format(len(robots), robots))
# create parser to select the robot
parser = argparse.ArgumentParser()
parser.add_argument('-r', '--robot', help='the robot to load in the world', type=str,
choices=robots, default='hyq2max')
args = parser.parse_args()
print("All the robots (total number of robots = {}): {}".format(len(implemented_robots), implemented_robots))
# create simulator
sim = BulletSim()
sim = prl.simulators.Bullet()
# create basic world with floor and gravity
world = BasicWorld(sim)
world = prl.worlds.BasicWorld(sim)
# create one robot at a time
for i, robot_name in enumerate(implemented_robots):
if robot_name not in robot_not_working:
# instantiate the given robot
robot = world.load_robot(robot_name)
# load the robot in the world (note that you can create the robot outside the world (not recommended),
# and then give it to the `world.load_robot` method to let know the world that a robot was loaded)
robot = world.load_robot(robot=args.robot, position=[0., 0.])
# print info about the robot
print("Robot n{}: {}".format(i+1, robot))
# robot.print_info()
# run for few moments in the world
for t in range(250):
# run one step and sleep a bit
world.step(sleep_dt=1./240)
# remove the robot from the world
world.remove(robot)
# run simulator
for _ in count():
# perform one step in the world
world.step(sleep_dt=1. / 240)
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env python
"""Control a quadcopter in the air using an Xbox or Playstation game controller.
how to run:
```
$ python quadcopter_controller.py --help # for help
$ python quadcopter_controller.py --controller keyboard # to use the keyboard
$ python quadcopter_controller.py --controller xbox # to use Xbox game controller
$ python quadcopter_controller.py --controller ps # to use PS game controller
```
Mapping of the keyboard interface:
- `top arrow`: move forward
- `bottom arrow`: move backward
- `left arrow`: move sideways to the left
- `right arrow`: move sideways to the right
- `ctrl + top arrow`: ascend
- `ctrl + bottom arrow`: descend
- `ctrl + left arrow`: turn to the right
- `ctrl + right arrow`: turn to the left
- `space`: switch between first-person and third-person view
Mapping between the controller and the quadcopter:
- left joystick: use to move the quadcopter
- right joystick: use to ascend/descend and turn
- south button (X on PlayStation and A on Xbox): change between the first-person and third-person view.
- east button (circle on PlayStation and B on Xbox): increase the speed
- west button (square on PlayStation and X on Xbox): decrease the speed
"""
# import numpy as np
from itertools import count
import argparse
import pyrobolearn as prl
# create parser to select the game controller
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--controller', help='the controller to use', type=str,
choices=['keyboard', 'xbox', 'ps'], default='keyboard')
args = parser.parse_args()
# load corresponding interface
if args.controller == 'keyboard': # keyboard interface
from pyrobolearn.tools.interfaces.mouse_keyboard.mousekeyboard import MouseKeyboardInterface as Controller
from pyrobolearn.tools.bridges.mouse_keyboard.bridge_mousekeyboard_quadcopter \
import BridgeMouseKeyboardQuadcopter as Bridge
elif args.controller == 'xbox': # Xbox interface
from pyrobolearn.tools.interfaces.controllers.xbox import XboxControllerInterface as Controller
from pyrobolearn.tools.bridges.controllers.robots.bridge_controller_quadcopter import BridgeControllerQuadcopter \
as Bridge
elif args.controller == 'ps': # PS interface
from pyrobolearn.tools.interfaces.controllers.playstation import PSControllerInterface as Controller
from pyrobolearn.tools.bridges.controllers.robots.bridge_controller_quadcopter import BridgeControllerQuadcopter \
as Bridge
else:
raise NotImplementedError("Unknown game controller")
# create simulator
sim = prl.simulators.Bullet()
# create basic world (with a floor and gravity enabled by default)
world = prl.worlds.BasicWorld(sim)
# load quadcopter
robot = prl.robots.Quadcopter(sim, position=[0., 0., 2.])
world.load_robot(robot)
# load interface that accepts input events
controller = Controller(use_thread=True, verbose=False)
# load bridge that connects the interface/controller with the quadcopter
# The bridge is the one that maps the input events from the interface to commands sent to the quadcopter
bridge = Bridge(quadcopter=robot, interface=controller)
# run simulator
for t in count():
# perform a step with the bridge and interface
bridge.step(update_interface=True)
# perform one step in the world
world.step(sleep_dt=1. / 240)
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python
"""Manipulate the robot's joints with sliders.
You can move in the world using the keyboard and mouse:
- `ctrl + left click`: rotate the camera
- `scroll wheel` or `ctrl + right click`: zoom in/out
- `ctrl + middle click`: move the camera
- `left click` on an object: if the object has a mass and a collision shape, you can interact with it with the mouse
- `w`: wireframe (see collision shapes)
- `g`: show/hide menu
- `esc`: quit the simulator
"""
from itertools import count
import argparse
import pyrobolearn as prl
# create parser to select the robot
parser = argparse.ArgumentParser()
parser.add_argument('-r', '--robot', help='the robot to load in the world', type=str,
choices=prl.robots.implemented_robots, default='coman')
parser.add_argument('-f', '--fixed_base', help='if we should fix the base when the robot has initially a floating '
'base', type=bool, default=True)
args = parser.parse_args()
# create simulator
sim = prl.simulators.Bullet()
# create basic world with floor and gravity
world = prl.worlds.BasicWorld(sim)
# load the robot in the world
robot = world.load_robot(robot=args.robot, position=[0., 0.], fixed_base=args.fixed_base)
# add a slider for each specified joint
robot.add_joint_slider(joint_ids=robot.joints)
# run simulator
for _ in count():
# update the joint slider
robot.update_joint_slider()
# perform one step in the world
world.step(sleep_dt=1. / 240)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Aibo
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import AllegroHand
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Ant
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Atlas
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Ballbot
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Baxter
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import BB8
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -85,12 +85,12 @@ class LQR(object):
if __name__ == "__main__":
import numpy as np
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import World
from pyrobolearn.robots import CartPole
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = World(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Cassie
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Centauro
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Cogimon
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)
@@ -3,12 +3,12 @@
"""
from itertools import count
from pyrobolearn.simulators import BulletSim
from pyrobolearn.simulators import Bullet
from pyrobolearn.worlds import BasicWorld
from pyrobolearn.robots import Coman
# Create simulator
sim = BulletSim()
sim = Bullet()
# create world
world = BasicWorld(sim)

Some files were not shown because too many files have changed in this diff Show More