diff --git a/README.rst b/README.rst index 6c794fb..2ab7569 100644 --- a/README.rst +++ b/README.rst @@ -39,6 +39,8 @@ The following tutorials are currently available: - `Tutorial 6: More Informative Rendering `_ - `Tutorial 7: Reset Routines `_ +A page with the exercises only is available `here `_. + How to run the tutorials locally? ================================= @@ -89,5 +91,5 @@ If you are using EAGERx for your scientific publications, please cite: } Acknowledgements -================= +================ EAGERx is funded by the `OpenDR `_ Horizon 2020 project. diff --git a/eagerx_tutorials/pendulum/layover.py b/eagerx_tutorials/pendulum/overlay.py similarity index 96% rename from eagerx_tutorials/pendulum/layover.py rename to eagerx_tutorials/pendulum/overlay.py index 86152dc..4bde40b 100644 --- a/eagerx_tutorials/pendulum/layover.py +++ b/eagerx_tutorials/pendulum/overlay.py @@ -7,9 +7,9 @@ import numpy as np -class Layover(eagerx.Node): +class Overlay(eagerx.Node): @staticmethod - @register.spec("Layover", eagerx.Node) + @register.spec("Overlay", eagerx.Node) def spec( spec, name: str, @@ -17,9 +17,9 @@ def spec( process: int = eagerx.process.ENVIRONMENT, color: str = "cyan", ): - """Layover spec""" + """Overlay spec""" # Fills spec with defaults parameters - spec.initialize(Layover) + spec.initialize(Overlay) # Adjust default params spec.config.update( diff --git a/poetry.lock b/poetry.lock index 8c62744..378b7a5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -294,7 +294,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "eagerx" -version = "0.1.21" +version = "0.1.22" description = "Engine Angostic Gym Environments for Robotics" category = "main" optional = false @@ -2061,8 +2061,8 @@ docutils = [ {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"}, ] eagerx = [ - {file = "eagerx-0.1.21-py3-none-any.whl", hash = "sha256:ee0e4edf09f57bb1e2d4e1591b4648208728494c8059233fce4cc666341ce8b3"}, - {file = "eagerx-0.1.21.tar.gz", hash = "sha256:a6deb5c29ac6c4d1bff82b9d1d727f4de75dce77814eb500c7193f095f5de729"}, + {file = "eagerx-0.1.22-py3-none-any.whl", hash = "sha256:5acb38beaf383a8d3d35129183f6b27d321970fc4ff3e0a6c55d2f6bd0cb0605"}, + {file = "eagerx-0.1.22.tar.gz", hash = "sha256:70333df071e1b201598755736a97ca6c0848eee3f41b5e5a97d596e8f2e5560e"}, ] eagerx-ode = [ {file = "eagerx_ode-0.1.11-py3-none-any.whl", hash = "sha256:a63eabe6f92ded4e7459c07a7abe726890d992d395039f48e7bd7fda1c14da86"}, diff --git a/tests/test_gymbridge.py b/tests/test_gymbridge.py index 64db2f3..c96f745 100644 --- a/tests/test_gymbridge.py +++ b/tests/test_gymbridge.py @@ -35,17 +35,17 @@ def test_gymbridge(): graph.connect(source=pendulum.sensors.theta, observation="angle", window=1) graph.connect(source=pendulum.sensors.dtheta, observation="angular_velocity", window=1) - # Create layover node - import eagerx_tutorials.pendulum.layover # noqa: - layover = eagerx.Node.make("Layover", "layover", rate) - layover.inputs.u.space_converter = pendulum.actuators.u.space_converter - graph.add(layover) + # Create overlay node + import eagerx_tutorials.pendulum.overlay # noqa: + overlay = eagerx.Node.make("Overlay", "overlay", rate) + overlay.inputs.u.space_converter = pendulum.actuators.u.space_converter + graph.add(overlay) # Render image - graph.connect(source=pendulum.sensors.image, target=layover.inputs.base_image) - graph.connect(source=reset.outputs.u, target=layover.inputs.u) - graph.connect(source=pendulum.sensors.theta, target=layover.inputs.theta) - graph.render(source=layover.outputs.image, rate=rate) + graph.connect(source=pendulum.sensors.image, target=overlay.inputs.base_image) + graph.connect(source=reset.outputs.u, target=overlay.inputs.u) + graph.connect(source=pendulum.sensors.theta, target=overlay.inputs.theta) + graph.render(source=overlay.outputs.image, rate=rate) # Make OdeBridge bridge = eagerx.Bridge.make("OdeBridge", rate=rate) diff --git a/tutorials/pendulum/1_environment_creation.ipynb b/tutorials/pendulum/1_environment_creation.ipynb index d41837d..0923ea3 100644 --- a/tutorials/pendulum/1_environment_creation.ipynb +++ b/tutorials/pendulum/1_environment_creation.ipynb @@ -30,14 +30,17 @@ "\n", "with $\\theta$ the angle w.r.t. upright position, $\\dot{\\theta}$ the angular velocity, $u$ the input voltage, $J$ the inertia, $m$ the mass, $g$ the gravitational constant, $l$ the length of the pendulum, $b$ the motor viscous friction constant, $K$ the motor constant and $R$ the electric resistance.\n", "\n", - "" - ] - }, - { - "cell_type": "markdown", - "id": "74487e37-a1bc-4640-a9da-6f6cf27b4519", - "metadata": {}, - "source": [ + "\n", + "\n", + "\n", + "## Activate GPU (Colab only)\n", + "\n", + "When in Colab, you'll need to enable GPUs for the notebook:\n", + "\n", + "- Navigate to Edit→Notebook Settings\n", + "- select GPU from the Hardware Accelerator drop-down\n", + "\n", + "\n", "## Notebook Setup\n", "\n", "In order to be able to run the code, we need to install the *eagerx_tutorials* package and ROS." @@ -71,13 +74,7 @@ "# Setup interactive notebook\n", "# Required in interactive notebooks only.\n", "from eagerx_tutorials import helper\n", - "helper.setup_notebook()\n", - "env = None\n", - "\n", - "# Allows reloading of registered entites from changed files\n", - "# Required in interactive notebooks only.\n", - "%reload_ext autoreload\n", - "%autoreload 1" + "helper.setup_notebook()" ] }, { @@ -109,8 +106,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "... logging to /home/jelle/.ros/log/8a5aba50-cab1-11ec-9a64-612c3b44983f/roslaunch-jelle-Alienware-m15-R4-18483.log\n", - "\u001b[1mstarted roslaunch server http://145.94.217.36:45875/\u001b[0m\n", + "... logging to /home/jelle/.ros/log/91331988-d071-11ec-8414-1f5d9a0d084b/roslaunch-jelle-Alienware-m15-R4-7957.log\n", + "\u001b[1mstarted roslaunch server http://145.94.219.156:41309/\u001b[0m\n", "ros_comm version 1.15.14\n", "\n", "\n", @@ -124,17 +121,17 @@ "NODES\n", "\n", "auto-starting new master\n", - "\u001b[1mprocess[master]: started with pid [18537]\u001b[0m\n", + "\u001b[1mprocess[master]: started with pid [8025]\u001b[0m\n", "\u001b[1mROS_MASTER_URI=http://localhost:11311\u001b[0m\n", - "\u001b[1msetting /run_id to 8a5aba50-cab1-11ec-9a64-612c3b44983f\u001b[0m\n", - "\u001b[1mprocess[rosout-1]: started with pid [18562]\u001b[0m\n", + "\u001b[1msetting /run_id to 91331988-d071-11ec-8414-1f5d9a0d084b\u001b[0m\n", + "\u001b[1mprocess[rosout-1]: started with pid [8052]\u001b[0m\n", "started core service [/rosout]\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -422,112 +419,113 @@ "name": "stdout", "output_type": "stream", "text": [ - "[INFO] [1651562443.303998]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", - "[INFO] [1651562443.448747]: Node \"/PendulumEnv/bridge\" initialized.\n", - "[INFO] [1651562443.646331]: Node \"/PendulumEnv/environment\" initialized.\n", - "[INFO] [1651562443.721903]: Node \"/PendulumEnv/env/render\" initialized.\n", - "[INFO] [1651562443.826245]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", - "[INFO] [1651562443.850971]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", - "[INFO] [1651562443.890103]: START RENDERING!\n", - "Using cpu device\n", + "[INFO] [1652194674.650959]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", + "[INFO] [1652194674.800871]: Node \"/PendulumEnv/bridge\" initialized.\n", + "[INFO] [1652194675.006478]: Node \"/PendulumEnv/environment\" initialized.\n", + "[INFO] [1652194675.100023]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", + "[INFO] [1652194675.171504]: Waiting for nodes \"['env/render']\" to be initialized.\n", + "[INFO] [1652194675.176602]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", + "Using cuda device\n", "Wrapping the env with a `Monitor` wrapper\n", "Wrapping the env in a DummyVecEnv.\n", - "[INFO] [1651562443.916023]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", - "[INFO] [1651562443.930199]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", - "[INFO] [1651562443.941389]: [pendulum/image] START RENDERING!\n", - "[INFO] [1651562443.947704]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", - "[INFO] [1651562443.960112]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", - "[INFO] [1651562443.972254]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", - "[INFO] [1651562444.023590]: Waiting for nodes \"['pendulum/image', 'pendulum/pendulum_actuator', 'pendulum/u']\" to be initialized.\n", - "[INFO] [1651562444.463799]: Nodes initialized.\n", - "[INFO] [1651562444.535006]: Pipelines initialized.\n", + "[INFO] [1652194675.278533]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", + "[INFO] [1652194675.295990]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", + "[INFO] [1652194675.312602]: [pendulum/image] START RENDERING!\n", + "[INFO] [1652194675.312833]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", + "[INFO] [1652194675.328349]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", + "[INFO] [1652194675.342806]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", + "[INFO] [1652194679.730279]: Nodes initialized.\n", + "[INFO] [1652194679.784066]: Pipelines initialized.\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -948 |\n", + "| ep_rew_mean | -975 |\n", "| time/ | |\n", "| episodes | 4 |\n", - "| fps | 71 |\n", - "| time_elapsed | 5 |\n", + "| fps | 81 |\n", + "| time_elapsed | 4 |\n", "| total_timesteps | 404 |\n", "| train/ | |\n", - "| actor_loss | 17.8 |\n", - "| critic_loss | 10.2 |\n", - "| ent_coef | 0.916 |\n", - "| ent_coef_loss | -0.116 |\n", + "| actor_loss | 18.2 |\n", + "| critic_loss | 7.65 |\n", + "| ent_coef | 0.917 |\n", + "| ent_coef_loss | -0.113 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 303 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -915 |\n", + "| ep_rew_mean | -958 |\n", "| time/ | |\n", "| episodes | 8 |\n", - "| fps | 69 |\n", - "| time_elapsed | 11 |\n", + "| fps | 76 |\n", + "| time_elapsed | 10 |\n", "| total_timesteps | 808 |\n", "| train/ | |\n", - "| actor_loss | 31 |\n", - "| critic_loss | 9.61 |\n", - "| ent_coef | 0.832 |\n", - "| ent_coef_loss | -0.193 |\n", + "| actor_loss | 32.2 |\n", + "| critic_loss | 3.78 |\n", + "| ent_coef | 0.831 |\n", + "| ent_coef_loss | -0.221 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 707 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -907 |\n", + "| ep_rew_mean | -928 |\n", "| time/ | |\n", "| episodes | 12 |\n", - "| fps | 68 |\n", - "| time_elapsed | 17 |\n", + "| fps | 75 |\n", + "| time_elapsed | 16 |\n", "| total_timesteps | 1212 |\n", "| train/ | |\n", - "| actor_loss | 44.7 |\n", - "| critic_loss | 4.64 |\n", - "| ent_coef | 0.742 |\n", - "| ent_coef_loss | -0.385 |\n", + "| actor_loss | 46.2 |\n", + "| critic_loss | 3.51 |\n", + "| ent_coef | 0.74 |\n", + "| ent_coef_loss | -0.39 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1111 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -889 |\n", + "| ep_rew_mean | -899 |\n", "| time/ | |\n", "| episodes | 16 |\n", - "| fps | 68 |\n", - "| time_elapsed | 23 |\n", + "| fps | 74 |\n", + "| time_elapsed | 21 |\n", "| total_timesteps | 1616 |\n", "| train/ | |\n", - "| actor_loss | 59.7 |\n", - "| critic_loss | 3.83 |\n", - "| ent_coef | 0.655 |\n", - "| ent_coef_loss | -0.481 |\n", + "| actor_loss | 61.2 |\n", + "| critic_loss | 5.8 |\n", + "| ent_coef | 0.657 |\n", + "| ent_coef_loss | -0.411 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1515 |\n", "---------------------------------\n", - "[INFO] [1651562470.290369]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651562470.291187]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", - "[INFO] [1651562470.291922]: [/PendulumEnv/pendulum/x] Shutting down.\n", - "[INFO] [1651562470.341862]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", - "[INFO] [1651562470.342609]: [/PendulumEnv/pendulum/image] Shutting down.\n", - "[INFO] [1651562470.343375]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", - "[INFO] [1651562470.343929]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", - "[INFO] [1651562470.344609]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", - "[INFO] [1651562470.345255]: [/PendulumEnv/pendulum/u] Shutting down.\n", - "[INFO] [1651562470.345999]: [/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651562470.347328]: [PendulumEnv][/PendulumEnv/env/render] Shutting down.\n", - "[INFO] [1651562470.347893]: [/PendulumEnv/env/render] Shutting down.\n", - "[INFO] [1651562470.350011]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651562470.350553]: [/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651562470.351172]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651562470.351760]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651562470.352371]: [/PendulumEnv/env/supervisor] Shutting down.\n", - "[INFO] [1651562470.355477]: [/PendulumEnv/environment] Shutting down.\n", - "[INFO] [1651562470.357374]: Parameters under namespace \"/PendulumEnv\" deleted.\n" + "[INFO] [1652194703.616794]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", + "[INFO] [1652194703.617589]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652194703.618204]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", + "[INFO] [1652194703.619133]: [/PendulumEnv/pendulum/x] Shutting down.\n", + "[INFO] [1652194703.670342]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", + "[INFO] [1652194703.670951]: [/PendulumEnv/pendulum/image] Shutting down.\n", + "[INFO] [1652194703.671552]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", + "[INFO] [1652194703.672078]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", + "[INFO] [1652194703.672690]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", + "[INFO] [1652194703.673275]: [/PendulumEnv/pendulum/u] Shutting down.\n", + "[INFO] [1652194703.673898]: [/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652194703.675176]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652194703.675735]: [/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652194703.676324]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652194703.676883]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652194703.677540]: [/PendulumEnv/env/supervisor] Shutting down.\n", + "[INFO] [1652194703.680542]: [/PendulumEnv/environment] Shutting down.\n", + "[INFO] [1652194703.682569]: Parameters under namespace \"/PendulumEnv\" deleted.\n", + "[INFO] [1652194676.098388]: START RENDERING!\n", + "[INFO] [1652194676.113344]: Node \"/PendulumEnv/env/render\" initialized.\n", + "[INFO] [1652194703.617740]: [/PendulumEnv/env/render] Shutting down.\n", + "shutdown request: [/eagerx_core] Reason: new node registered with same name\n" ] } ], @@ -571,7 +569,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/tutorials/pendulum/2_reset_and_step.ipynb b/tutorials/pendulum/2_reset_and_step.ipynb index 8cac341..57359eb 100644 --- a/tutorials/pendulum/2_reset_and_step.ipynb +++ b/tutorials/pendulum/2_reset_and_step.ipynb @@ -39,6 +39,15 @@ "\n", "with $\\theta$ the angle w.r.t. upright position, $\\dot{\\theta}$ the angular velocity, $u$ the input voltage, $J$ the inertia, $m$ the mass, $g$ the gravitational constant, $l$ the length of the pendulum, $b$ the motor viscous friction constant, $K$ the motor constant and $R$ the electric resistance.\n", "\n", + "\n", + "\n", + "## Activate GPU (Colab only)\n", + "\n", + "When in Colab, you'll need to enable GPUs for the notebook:\n", + "\n", + "- Navigate to Edit→Notebook Settings\n", + "- select GPU from the Hardware Accelerator drop-down\n", + "\n", "## Notebook Setup\n", "\n", "In order to be able to run the code, we need to install the *eagerx_tutorials* package and ROS." @@ -72,13 +81,7 @@ "# Setup interactive notebook\n", "# Required in interactive notebooks only.\n", "from eagerx_tutorials import helper\n", - "helper.setup_notebook()\n", - "env = None\n", - "\n", - "# Allows reloading of registered entites from changed files\n", - "# Required in interactive notebooks only.\n", - "%reload_ext autoreload\n", - "%autoreload 1" + "helper.setup_notebook()" ] }, { @@ -101,8 +104,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "... logging to /home/jelle/.ros/log/d734afb2-c7c2-11ec-ab25-bdefe663dbb0/roslaunch-jelle-Alienware-m15-R4-63389.log\n", - "\u001b[1mstarted roslaunch server http://145.94.60.89:33347/\u001b[0m\n", + "... logging to /home/jelle/.ros/log/91331988-d071-11ec-8414-1f5d9a0d084b/roslaunch-jelle-Alienware-m15-R4-11727.log\n", + "\u001b[1mstarted roslaunch server http://145.94.219.156:41499/\u001b[0m\n", "ros_comm version 1.15.14\n", "\n", "\n", @@ -115,7 +118,7 @@ "\n", "NODES\n", "\n", - "[INFO] [1651241088.184788]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" + "[INFO] [1652195067.034700]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" ] } ], @@ -291,7 +294,7 @@ "Next we will also define a [reset function](https://eagerx.readthedocs.io/en/master/guide/api_reference/env/index.html#eagerx.core.env.EagerxEnv.reset_fn).\n", "The reset function allows to specify how states are reset at the beginning of an episode.\n", "Remember that we have one object (*Pendulum*) with one state (*model_state*).\n", - "This *model_state* corresponds to $x = \\begin{bmatrix} \\theta \\\\ \\dot{\\theta} \\end{bmatrix}$.\n", + "This *model_state* corresponds to $\\mathbf{x} = \\begin{bmatrix} \\theta \\\\ \\dot{\\theta} \\end{bmatrix}$.\n", "The default reset function as defined in [EagerxEnv](https://eagerx.readthedocs.io/en/master/guide/api_reference/env/index.html?highlight=eagerxenv#eagerx.core.env.EagerxEnv) is:\n", "```python\n", "reset_fn = lambda env: env.state_space.sample()\n", @@ -342,111 +345,113 @@ "name": "stdout", "output_type": "stream", "text": [ - "[INFO] [1651241088.944307]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", - "[INFO] [1651241089.087094]: Node \"/PendulumEnv/bridge\" initialized.\n", - "[INFO] [1651241089.209922]: Node \"/PendulumEnv/environment\" initialized.\n", - "[INFO] [1651241089.236116]: Node \"/PendulumEnv/env/render\" initialized.\n", - "[INFO] [1651241089.311365]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", - "[INFO] [1651241089.383828]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", - "[INFO] [1651241089.454643]: START RENDERING!\n", + "[INFO] [1652195067.731521]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", + "[INFO] [1652195067.876531]: Node \"/PendulumEnv/bridge\" initialized.\n", + "[INFO] [1652195068.001140]: Node \"/PendulumEnv/environment\" initialized.\n", + "[INFO] [1652195068.098543]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", + "[INFO] [1652195068.124122]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", + "[INFO] [1652195068.140844]: Waiting for nodes \"['env/render']\" to be initialized.\n", "Using cuda device\n", "Wrapping the env with a `Monitor` wrapper\n", "Wrapping the env in a DummyVecEnv.\n", - "[INFO] [1651241089.483672]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", - "[INFO] [1651241089.501378]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", - "[INFO] [1651241089.512113]: [pendulum/image] START RENDERING!\n", - "[INFO] [1651241089.518910]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", - "[INFO] [1651241089.533136]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", - "[INFO] [1651241089.547454]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", - "[INFO] [1651241092.752754]: Nodes initialized.\n", - "[INFO] [1651241092.810296]: Pipelines initialized.\n", + "[INFO] [1652195068.266610]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", + "[INFO] [1652195068.284606]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", + "[INFO] [1652195068.302108]: [pendulum/image] START RENDERING!\n", + "[INFO] [1652195068.302376]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", + "[INFO] [1652195068.318674]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", + "[INFO] [1652195068.334803]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", + "[INFO] [1652195071.551435]: Nodes initialized.\n", + "[INFO] [1652195071.602813]: Pipelines initialized.\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -974 |\n", + "| ep_rew_mean | -947 |\n", "| time/ | |\n", "| episodes | 4 |\n", - "| fps | 76 |\n", - "| time_elapsed | 5 |\n", + "| fps | 81 |\n", + "| time_elapsed | 4 |\n", "| total_timesteps | 404 |\n", "| train/ | |\n", - "| actor_loss | 18.1 |\n", - "| critic_loss | 5.39 |\n", + "| actor_loss | 17.8 |\n", + "| critic_loss | 2.25 |\n", "| ent_coef | 0.917 |\n", - "| ent_coef_loss | -0.116 |\n", + "| ent_coef_loss | -0.11 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 303 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -967 |\n", + "| ep_rew_mean | -956 |\n", "| time/ | |\n", "| episodes | 8 |\n", - "| fps | 71 |\n", - "| time_elapsed | 11 |\n", + "| fps | 75 |\n", + "| time_elapsed | 10 |\n", "| total_timesteps | 808 |\n", "| train/ | |\n", - "| actor_loss | 32.6 |\n", - "| critic_loss | 3.2 |\n", - "| ent_coef | 0.823 |\n", - "| ent_coef_loss | -0.258 |\n", + "| actor_loss | 32.5 |\n", + "| critic_loss | 0.691 |\n", + "| ent_coef | 0.819 |\n", + "| ent_coef_loss | -0.28 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 707 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -958 |\n", + "| ep_rew_mean | -935 |\n", "| time/ | |\n", "| episodes | 12 |\n", - "| fps | 70 |\n", - "| time_elapsed | 17 |\n", + "| fps | 73 |\n", + "| time_elapsed | 16 |\n", "| total_timesteps | 1212 |\n", "| train/ | |\n", "| actor_loss | 47.5 |\n", - "| critic_loss | 1.28 |\n", + "| critic_loss | 0.604 |\n", "| ent_coef | 0.727 |\n", - "| ent_coef_loss | -0.437 |\n", + "| ent_coef_loss | -0.444 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1111 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -931 |\n", + "| ep_rew_mean | -892 |\n", "| time/ | |\n", "| episodes | 16 |\n", - "| fps | 70 |\n", + "| fps | 71 |\n", "| time_elapsed | 22 |\n", "| total_timesteps | 1616 |\n", "| train/ | |\n", - "| actor_loss | 62 |\n", - "| critic_loss | 0.991 |\n", - "| ent_coef | 0.648 |\n", - "| ent_coef_loss | -0.488 |\n", + "| actor_loss | 61 |\n", + "| critic_loss | 0.499 |\n", + "| ent_coef | 0.658 |\n", + "| ent_coef_loss | -0.346 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1515 |\n", "---------------------------------\n", - "[INFO] [1651241117.890363]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651241117.891250]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", - "[INFO] [1651241117.891805]: [/PendulumEnv/pendulum/x] Shutting down.\n", - "[INFO] [1651241117.945183]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", - "[INFO] [1651241117.945928]: [/PendulumEnv/pendulum/image] Shutting down.\n", - "[INFO] [1651241117.946558]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", - "[INFO] [1651241117.947154]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", - "[INFO] [1651241117.947795]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", - "[INFO] [1651241117.948419]: [/PendulumEnv/pendulum/u] Shutting down.\n", - "[INFO] [1651241117.949280]: [/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651241117.950547]: [PendulumEnv][/PendulumEnv/env/render] Shutting down.\n", - "[INFO] [1651241117.951180]: [/PendulumEnv/env/render] Shutting down.\n", - "[INFO] [1651241117.953123]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651241117.953688]: [/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651241117.954355]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651241117.954935]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651241117.955613]: [/PendulumEnv/env/supervisor] Shutting down.\n", - "[INFO] [1651241117.958478]: [/PendulumEnv/environment] Shutting down.\n", - "[INFO] [1651241117.960480]: Parameters under namespace \"/PendulumEnv\" deleted.\n" + "[INFO] [1652195096.240716]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", + "[INFO] [1652195096.241600]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652195096.242290]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", + "[INFO] [1652195096.243269]: [/PendulumEnv/pendulum/x] Shutting down.\n", + "[INFO] [1652195096.299408]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", + "[INFO] [1652195096.300328]: [/PendulumEnv/pendulum/image] Shutting down.\n", + "[INFO] [1652195096.302037]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", + "[INFO] [1652195096.303040]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", + "[INFO] [1652195096.303981]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", + "[INFO] [1652195096.304794]: [/PendulumEnv/pendulum/u] Shutting down.\n", + "[INFO] [1652195096.305457]: [/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652195096.306948]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652195096.307713]: [/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652195096.308617]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652195096.309502]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652195096.310881]: [/PendulumEnv/env/supervisor] Shutting down.\n", + "[INFO] [1652195096.314800]: [/PendulumEnv/environment] Shutting down.\n", + "[INFO] [1652195096.316778]: Parameters under namespace \"/PendulumEnv\" deleted.\n", + "[INFO] [1652195069.075569]: START RENDERING!\n", + "[INFO] [1652195069.090253]: Node \"/PendulumEnv/env/render\" initialized.\n", + "[INFO] [1652195096.241795]: [/PendulumEnv/env/render] Shutting down.\n", + "shutdown request: [/eagerx_core] Reason: new node registered with same name\n" ] } ], @@ -476,7 +481,9 @@ { "cell_type": "markdown", "id": "dcd13fcd-7275-40a6-b779-3caef149dd55", - "metadata": {}, + "metadata": { + "tags": [] + }, "source": [ "# Exercises\n", "\n", @@ -521,8 +528,8 @@ "### Add your code to the following blocks: \n", "\n", "1.1 Remove sensor *dtheta* from and add sensor *u* to the list of sensors. \n", - "1.2 Connect sensor *theta* with `window` = 3 to stack the last three observations of $\\theta$ and set `delay` to 0.01. \n", - "1.3 Connect *u* to an observation called *action_applied* with `window` = 1. \n", + "1.2 Remove the connection from sensor *dtheta*. Also, connect sensor *theta* with `window` = 3 to stack the last three observations of $\\theta$ and set `delay` to 0.01. \n", + "1.3 Connect *u* to an observation called *action_applied* with `window` = 1. Do you know why *u* should be an observation to the agent in order to restore the Markov property? \n", "1.4 Update the`step_fn` such that we use an estimate of $\\dot{\\theta}$ to calculate the reward.\n", "Hint: you could use the `previous_observation` for this.\n", "\n", @@ -542,17 +549,22 @@ "At the beginning of each episode, the environment is reset.\n", "In the code as provided above, the pendulum is reset to the downward position with zero velocity each episode.\n", "However, the initial state distribution can have a significant influence on the learning speed.\n", - "If we sample the $x_0 = \\begin{bmatrix} \\pi \\\\ 0 \\end{bmatrix}$ initial state every time, it will take many timesteps for the agent to obtain experience for $-\\frac{\\pi}{2} < \\theta < \\frac{\\pi}{2}$.\n", + "If we sample the $\\mathbf{x}_0 = \\begin{bmatrix} \\pi \\\\ 0 \\end{bmatrix}$ initial state every time, it will take many timesteps for the agent to obtain experience for $-\\frac{\\pi}{2} < \\theta < \\frac{\\pi}{2}$.\n", "Namely, in the beginning the policy will be random and it is unlikely that acting randomly will result in the pendulum gaining enough momentum to move upwards.\n", "This is problematic, since the agent will obtain the highest rewards when the pendulum is pointed upwards.\n", "If the agent does not explore enough (see [the exploration-exploitation trade-off](http://www.incompleteideas.net/book/2/node2.html)), the agent will not know that it can obtain the highest rewards by swinging the pendulum upward.\n", - "Therefore, we will update the `reset_fn`, such that we sample the initial state randomly, rather than sampling $x_0 = \\begin{bmatrix} \\pi \\\\ 0 \\end{bmatrix}$ everytime.\n", + "Therefore, we will update the `reset_fn`, such that we sample the initial state randomly, rather than sampling $\\mathbf{x}_0 = \\begin{bmatrix} \\pi \\\\ 0 \\end{bmatrix}$ everytime.\n", "We also need to make sure that the aforementioned *model_parameters* state that is reset to perform domain randomization.\n", "\n", "### Add your code to the following blocks: \n", "\n", "2.1 Add the state *model_parameters* to the list of states of the pendulum \n", - "2.2 Update the reset function, such that the *model_state* and *model_parameters* states are reset to random values at the beginning of each episode." + "2.2 Update the reset function, such that the *model_state* and *model_parameters* states are reset to random values at the beginning of each episode.\n", + "Hint: you can sample states from the environment's state space as follows:\n", + "```python\n", + "env.state_space[\"[object_name]/[state_name]\"].sample()\n", + "```\n", + "where *object_name* should be replaced with the name of the object and *state_name* with the name of the state." ] } ], @@ -572,7 +584,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/tutorials/pendulum/3_converters.ipynb b/tutorials/pendulum/3_converters.ipynb index 32e0a52..6cc9c06 100644 --- a/tutorials/pendulum/3_converters.ipynb +++ b/tutorials/pendulum/3_converters.ipynb @@ -38,6 +38,15 @@ "\n", "with $\\theta$ the angle w.r.t. upright position, $\\dot{\\theta}$ the angular velocity, $u$ the input voltage, $J$ the inertia, $m$ the mass, $g$ the gravitational constant, $l$ the length of the pendulum, $b$ the motor viscous friction constant, $K$ the motor constant and $R$ the electric resistance.\n", "\n", + "\n", + "## Activate GPU (Colab only)\n", + "\n", + "When in Colab, you'll need to enable GPUs for the notebook:\n", + "\n", + "- Navigate to Edit→Notebook Settings\n", + "- select GPU from the Hardware Accelerator drop-down\n", + "\n", + "\n", "## Notebook Setup\n", "\n", "In order to be able to run the code, we need to install the *eagerx_tutorials* package and ROS." @@ -71,13 +80,7 @@ "# Setup interactive notebook\n", "# Required in interactive notebooks only.\n", "from eagerx_tutorials import helper\n", - "helper.setup_notebook()\n", - "env = None\n", - "\n", - "# Allows reloading of registered entites from changed files\n", - "# Required in interactive notebooks only.\n", - "%reload_ext autoreload\n", - "%autoreload 1" + "helper.setup_notebook()" ] }, { @@ -100,8 +103,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "... logging to /home/jelle/.ros/log/29ef0558-caf3-11ec-a7aa-b9cef6e47e5f/roslaunch-jelle-Alienware-m15-R4-81444.log\n", - "\u001b[1mstarted roslaunch server http://145.94.60.89:46581/\u001b[0m\n", + "... logging to /home/jelle/.ros/log/4c93712a-d075-11ec-8414-1f5d9a0d084b/roslaunch-jelle-Alienware-m15-R4-29580.log\n", + "\u001b[1mstarted roslaunch server http://145.94.219.156:38643/\u001b[0m\n", "ros_comm version 1.15.14\n", "\n", "\n", @@ -115,17 +118,17 @@ "NODES\n", "\n", "auto-starting new master\n", - "\u001b[1mprocess[master]: started with pid [81507]\u001b[0m\n", + "\u001b[1mprocess[master]: started with pid [29643]\u001b[0m\n", "\u001b[1mROS_MASTER_URI=http://localhost:11311\u001b[0m\n", - "\u001b[1msetting /run_id to 29ef0558-caf3-11ec-a7aa-b9cef6e47e5f\u001b[0m\n", - "\u001b[1mprocess[rosout-1]: started with pid [81535]\u001b[0m\n", + "\u001b[1msetting /run_id to 4c93712a-d075-11ec-8414-1f5d9a0d084b\u001b[0m\n", + "\u001b[1mprocess[rosout-1]: started with pid [29668]\u001b[0m\n", "started core service [/rosout]\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -345,18 +348,8 @@ "execution_count": 6, "id": "ce40c187-9a58-4ccd-a52e-852f6b05566c", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Overwriting space_converter.py\n" - ] - } - ], + "outputs": [], "source": [ - "%%writefile space_converter.py\n", - "\n", "# ROS IMPORTS\n", "from std_msgs.msg import Float32\n", "\n", @@ -418,8 +411,6 @@ "metadata": {}, "outputs": [], "source": [ - "%aimport space_converter\n", - "import space_converter\n", "import numpy as np\n", "\n", "# START EXERCISE 1.2\n", @@ -484,73 +475,85 @@ "name": "stdout", "output_type": "stream", "text": [ - "[INFO] [1651590628.310980]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", - "[INFO] [1651590628.456226]: Node \"/PendulumEnv/bridge\" initialized.\n", - "[INFO] [1651590628.579400]: Node \"/PendulumEnv/environment\" initialized.\n", - "[INFO] [1651590628.605630]: Node \"/PendulumEnv/env/render\" initialized.\n", - "[INFO] [1651590628.718226]: Waiting for nodes \"['env/render']\" to be initialized.\n", - "[INFO] [1651590628.718788]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", - "[INFO] [1651590628.744902]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", - "Using cpu device\n", + "[INFO] [1652196276.860409]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", + "[INFO] [1652196277.007821]: Node \"/PendulumEnv/bridge\" initialized.\n", + "[INFO] [1652196277.137154]: Node \"/PendulumEnv/environment\" initialized.\n", + "[INFO] [1652196277.262750]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", + "[INFO] [1652196277.273986]: Waiting for nodes \"['env/render']\" to be initialized.\n", + "[INFO] [1652196277.348828]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", + "[INFO] [1652196277.421473]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", + "[INFO] [1652196277.435717]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", + "[INFO] [1652196277.453405]: [pendulum/image] START RENDERING!\n", + "[INFO] [1652196277.454798]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", + "[INFO] [1652196277.468126]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", + "[INFO] [1652196277.480600]: Node \"/PendulumEnv/pendulum/u\" initialized.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/jelle/.cache/pypoetry/virtualenvs/eagerx-tutorials-NkxrhtGC-py3.8/lib/python3.8/site-packages/stable_baselines3/common/env_checker.py:272: UserWarning: We recommend you to use a symmetric and normalized Box action space (range=[-1, 1]) cf https://stable-baselines3.readthedocs.io/en/master/guide/rl_tips.html\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[INFO] [1652196278.542869]: Nodes initialized.\n", + "[INFO] [1652196278.592621]: Pipelines initialized.\n", + "Using cuda device\n", "Wrapping the env with a `Monitor` wrapper\n", "Wrapping the env in a DummyVecEnv.\n", - "[INFO] [1651590628.788085]: START RENDERING!\n", - "[INFO] [1651590628.813925]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", - "[INFO] [1651590628.829849]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", - "[INFO] [1651590628.838326]: [pendulum/image] START RENDERING!\n", - "[INFO] [1651590628.844743]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", - "[INFO] [1651590628.857453]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", - "[INFO] [1651590628.870081]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", - "[INFO] [1651590629.060968]: Nodes initialized.\n", - "[INFO] [1651590629.123114]: Pipelines initialized.\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -936 |\n", + "| ep_rew_mean | -958 |\n", "| time/ | |\n", "| episodes | 4 |\n", - "| fps | 65 |\n", - "| time_elapsed | 6 |\n", + "| fps | 84 |\n", + "| time_elapsed | 4 |\n", "| total_timesteps | 404 |\n", "| train/ | |\n", - "| actor_loss | 17.4 |\n", - "| critic_loss | 3.67 |\n", + "| actor_loss | 17.5 |\n", + "| critic_loss | 5.62 |\n", "| ent_coef | 0.917 |\n", - "| ent_coef_loss | -0.107 |\n", + "| ent_coef_loss | -0.11 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 303 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -835 |\n", + "| ep_rew_mean | -858 |\n", "| time/ | |\n", "| episodes | 8 |\n", - "| fps | 64 |\n", - "| time_elapsed | 12 |\n", + "| fps | 78 |\n", + "| time_elapsed | 10 |\n", "| total_timesteps | 808 |\n", "| train/ | |\n", - "| actor_loss | 29 |\n", - "| critic_loss | 3.62 |\n", - "| ent_coef | 0.84 |\n", - "| ent_coef_loss | -0.152 |\n", + "| actor_loss | 28.9 |\n", + "| critic_loss | 7.38 |\n", + "| ent_coef | 0.841 |\n", + "| ent_coef_loss | -0.114 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 707 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -801 |\n", + "| ep_rew_mean | -804 |\n", "| time/ | |\n", "| episodes | 12 |\n", - "| fps | 63 |\n", - "| time_elapsed | 18 |\n", + "| fps | 75 |\n", + "| time_elapsed | 15 |\n", "| total_timesteps | 1212 |\n", "| train/ | |\n", - "| actor_loss | 42 |\n", - "| critic_loss | 6.89 |\n", - "| ent_coef | 0.769 |\n", - "| ent_coef_loss | -0.184 |\n", + "| actor_loss | 40.3 |\n", + "| critic_loss | 8.27 |\n", + "| ent_coef | 0.768 |\n", + "| ent_coef_loss | -0.205 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1111 |\n", "---------------------------------\n", @@ -560,36 +563,52 @@ "| ep_rew_mean | -756 |\n", "| time/ | |\n", "| episodes | 16 |\n", - "| fps | 63 |\n", - "| time_elapsed | 25 |\n", + "| fps | 74 |\n", + "| time_elapsed | 21 |\n", "| total_timesteps | 1616 |\n", "| train/ | |\n", - "| actor_loss | 52.7 |\n", - "| critic_loss | 9.31 |\n", - "| ent_coef | 0.714 |\n", - "| ent_coef_loss | -0.12 |\n", + "| actor_loss | 53 |\n", + "| critic_loss | 5.12 |\n", + "| ent_coef | 0.706 |\n", + "| ent_coef_loss | -0.198 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1515 |\n", "---------------------------------\n", - "[INFO] [1651590657.087255]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651590657.088185]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", - "[INFO] [1651590657.088901]: [/PendulumEnv/pendulum/x] Shutting down.\n", - "[INFO] [1651590657.145653]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", - "[INFO] [1651590657.146316]: [/PendulumEnv/pendulum/image] Shutting down.\n", - "[INFO] [1651590657.147119]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", - "[INFO] [1651590657.147808]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", - "[INFO] [1651590657.148654]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", - "[INFO] [1651590657.149370]: [/PendulumEnv/pendulum/u] Shutting down.\n", - "[INFO] [1651590657.151307]: [/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651590657.152801]: [PendulumEnv][/PendulumEnv/env/render] Shutting down.\n", - "[INFO] [1651590657.153490]: [/PendulumEnv/env/render] Shutting down.\n", - "[INFO] [1651590657.155537]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651590657.156192]: [/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651590657.156833]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651590657.157392]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651590657.158026]: [/PendulumEnv/env/supervisor] Shutting down.\n", - "[INFO] [1651590657.161209]: [/PendulumEnv/environment] Shutting down.\n", - "[INFO] [1651590657.163128]: Parameters under namespace \"/PendulumEnv\" deleted.\n" + "[INFO] [1652196305.706701]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", + "[INFO] [1652196305.707372]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196305.708016]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", + "[INFO] [1652196305.708740]: [/PendulumEnv/pendulum/x] Shutting down.\n", + "[INFO] [1652196305.760834]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", + "[INFO] [1652196305.761717]: [/PendulumEnv/pendulum/image] Shutting down.\n", + "[INFO] [1652196305.762348]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", + "[INFO] [1652196305.762875]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", + "[INFO] [1652196305.763460]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", + "[INFO] [1652196305.763975]: [/PendulumEnv/pendulum/u] Shutting down.\n", + "[INFO] [1652196305.764561]: [/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196305.765758]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196305.766298]: [/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196305.766876]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196305.767398]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196305.768017]: [/PendulumEnv/env/supervisor] Shutting down.\n", + "[INFO] [1652196305.770965]: [/PendulumEnv/environment] Shutting down.\n", + "[INFO] [1652196305.772785]: Parameters under namespace \"/PendulumEnv\" deleted.\n", + "[INFO] [1652196278.162504]: START RENDERING!\n", + "[INFO] [1652196278.175010]: Node \"/PendulumEnv/env/render\" initialized.\n", + "[INFO] [1652196305.707546]: [/PendulumEnv/env/render] Shutting down.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "QObject::~QObject: Timers cannot be stopped from another thread\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "shutdown request: [/eagerx_core] Reason: new node registered with same name\n" ] } ], @@ -706,7 +725,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/tutorials/pendulum/4_nodes.ipynb b/tutorials/pendulum/4_nodes.ipynb index 643cde7..6954fb8 100644 --- a/tutorials/pendulum/4_nodes.ipynb +++ b/tutorials/pendulum/4_nodes.ipynb @@ -39,6 +39,15 @@ "\n", "with $\\theta$ the angle w.r.t. upright position, $\\dot{\\theta}$ the angular velocity, $u$ the input voltage, $J$ the inertia, $m$ the mass, $g$ the gravitational constant, $l$ the length of the pendulum, $b$ the motor viscous friction constant, $K$ the motor constant and $R$ the electric resistance.\n", "\n", + "\n", + "## Activate GPU (Colab only)\n", + "\n", + "When in Colab, you'll need to enable GPUs for the notebook:\n", + "\n", + "- Navigate to Edit→Notebook Settings\n", + "- select GPU from the Hardware Accelerator drop-down\n", + "\n", + "\n", "## Notebook Setup\n", "\n", "In order to be able to run the code, we need to install the *eagerx_tutorials* package and ROS." @@ -46,10 +55,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "5c7aa809-ed7d-4cb7-8c82-f83e3f20e7c0", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Not running on CoLab.\n", + "Execute ROS commands as \"!...\".\n", + "ROS noetic available.\n" + ] + } + ], "source": [ "try:\n", " import eagerx_tutorials\n", @@ -62,13 +81,7 @@ "# Setup interactive notebook\n", "# Required in interactive notebooks only.\n", "from eagerx_tutorials import helper\n", - "helper.setup_notebook()\n", - "env = None\n", - "\n", - "# Allows reloading of registered entites from changed files\n", - "# Required in interactive notebooks only.\n", - "%reload_ext autoreload\n", - "%autoreload 1" + "helper.setup_notebook()" ] }, { @@ -83,10 +96,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "881d031b-de70-4816-9d66-f636ac7c1b1c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "... logging to /home/jelle/.ros/log/4c93712a-d075-11ec-8414-1f5d9a0d084b/roslaunch-jelle-Alienware-m15-R4-30194.log\n", + "\u001b[1mstarted roslaunch server http://145.94.219.156:40383/\u001b[0m\n", + "ros_comm version 1.15.14\n", + "\n", + "\n", + "SUMMARY\n", + "========\n", + "\n", + "PARAMETERS\n", + " * /rosdistro: noetic\n", + " * /rosversion: 1.15.14\n", + "\n", + "NODES\n", + "\n", + "[INFO] [1652196341.534326]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" + ] + } + ], "source": [ "import eagerx\n", "import eagerx_tutorials.pendulum # Registers Pendulum\n", @@ -126,13 +161,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "5c77d69f-57bd-4ec6-ac98-a73d01b594fa", "metadata": {}, "outputs": [], "source": [ - "%%writefile node.py\n", - "\n", "import eagerx\n", "import eagerx.converters # Registers space converters\n", "from eagerx.utils.utils import Msg\n", @@ -150,7 +183,7 @@ " ):\n", " \"\"\"\n", " MovingAverage filter\n", - " :param spec: Not provided by user.\n", + " :param spec: Not provided by user. Contains the configuration of this node to initialize it at run-time.\n", " :param name: Node name\n", " :param rate: Rate at which callback is called.\n", " :param n: Window size of the moving average\n", @@ -160,10 +193,13 @@ " spec.initialize(MovingAverageFilter)\n", "\n", " # Modify default node params\n", + " # Default node parameters are: inputs, outputs, states, name, rate, process, color, print_mode and log_level\n", + " # Can be accessed in initialize, reset and callback by self.[parameter_name]\n", " spec.config.update(name=name, rate=rate, process=eagerx.process.ENVIRONMENT, inputs=[\"signal\"], outputs=[\"filtered\"])\n", "\n", " \n", " # Custom node params\n", + " # Custom node params become arguments to the initialize method.\n", " # START EXERCISE 1.1\n", "\n", " # START EXERCISE 1.1\n", @@ -195,41 +231,11 @@ " return dict(filtered=Float32MultiArray(data=[filtered_data]))" ] }, - { - "cell_type": "markdown", - "id": "e6715d9a-2648-4e92-a179-4868282cf912", - "metadata": {}, - "source": [ - "Making a node is very similar to making an object." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6bac1526-81d2-4abb-9ae6-5fa4d3a66ea3", - "metadata": {}, - "outputs": [], - "source": [ - "%aimport node\n", - "import node\n", - "\n", - "# Define rate (depends on rate of ode)\n", - "rate = 30.0\n", - "\n", - "# Make moving average filter\n", - "moving_average_filter = eagerx.Node.make(\"ExampleNode\", \"filter\", rate=rate, n=5)\n", - "\n", - "# Make pendulum\n", - "pendulum = eagerx.Object.make(\"Pendulum\", \"pendulum\", actuators=[\"u\"], sensors=[\"theta\", \"dtheta\", \"image\"], states=[\"model_state\"])" - ] - }, { "cell_type": "markdown", "id": "953b90f4-cf1f-4f92-aa63-56b1f9a0c577", "metadata": {}, "source": [ - "Next, we will add the moving average filter and the pendulum to an empty graph.\n", - "\n", "At this point, we also would like to go a bit more into detail on the graph and its requirements.\n", "The main criterion for the graph to be valid is that there should be no [causal loops](https://en.wikipedia.org/wiki/Causal_loop) when starting from a sensor and following the graph untill we arrive at an actuator.\n", "In other words, if we were to cut the graph at each object, the graph should be a Directed Acyclical Graph ([DAG](https://en.wikipedia.org/wiki/Directed_acyclic_graph)).\n", @@ -261,11 +267,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "fe631f20-365d-4bc5-8f29-1edc05c83759", "metadata": {}, "outputs": [], "source": [ + "# Define rate (depends on rate of ode)\n", + "rate = 30.0\n", + "\n", + "# Make moving average filter\n", + "moving_average_filter = eagerx.Node.make(\"ExampleNode\", \"filter\", rate=rate, n=5)\n", + "\n", + "# Make pendulum\n", + "pendulum = eagerx.Object.make(\"Pendulum\", \"pendulum\", actuators=[\"u\"], sensors=[\"theta\", \"dtheta\", \"image\"], states=[\"model_state\"])\n", + "\n", "# Initialize empty graph\n", "graph = eagerx.Graph.create()\n", "\n", @@ -308,10 +323,41 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "9715d458-cd64-4d0f-933b-18ae23fd2012", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "graph.is_valid()" ] @@ -342,10 +388,141 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "7677d9c7-c136-44c6-b8c3-de2393eef1b7", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[INFO] [1652196342.753072]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", + "[INFO] [1652196342.897874]: Node \"/PendulumEnv/bridge\" initialized.\n", + "[INFO] [1652196343.022529]: Node \"/PendulumEnv/environment\" initialized.\n", + "[INFO] [1652196343.081674]: Node \"/PendulumEnv/filter\" initialized.\n", + "[INFO] [1652196343.155956]: Waiting for nodes \"['env/render']\" to be initialized.\n", + "[INFO] [1652196343.176359]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", + "[INFO] [1652196343.203916]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/jelle/.cache/pypoetry/virtualenvs/eagerx-tutorials-NkxrhtGC-py3.8/lib/python3.8/site-packages/stable_baselines3/common/env_checker.py:272: UserWarning: We recommend you to use a symmetric and normalized Box action space (range=[-1, 1]) cf https://stable-baselines3.readthedocs.io/en/master/guide/rl_tips.html\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[INFO] [1652196343.272465]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", + "[INFO] [1652196343.290150]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", + "[INFO] [1652196343.305917]: [pendulum/image] START RENDERING!\n", + "[INFO] [1652196343.306198]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", + "[INFO] [1652196343.321953]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", + "[INFO] [1652196343.335627]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", + "[INFO] [1652196344.385688]: Nodes initialized.\n", + "[INFO] [1652196344.549213]: Pipelines initialized.\n", + "Using cuda device\n", + "Wrapping the env with a `Monitor` wrapper\n", + "Wrapping the env in a DummyVecEnv.\n", + "----------------------------------\n", + "| rollout/ | |\n", + "| ep_len_mean | 101 |\n", + "| ep_rew_mean | -1.27e+03 |\n", + "| time/ | |\n", + "| episodes | 4 |\n", + "| fps | 83 |\n", + "| time_elapsed | 4 |\n", + "| total_timesteps | 404 |\n", + "| train/ | |\n", + "| actor_loss | 25.3 |\n", + "| critic_loss | 16.2 |\n", + "| ent_coef | 0.918 |\n", + "| ent_coef_loss | -0.0946 |\n", + "| learning_rate | 0.0003 |\n", + "| n_updates | 303 |\n", + "----------------------------------\n", + "----------------------------------\n", + "| rollout/ | |\n", + "| ep_len_mean | 101 |\n", + "| ep_rew_mean | -1.24e+03 |\n", + "| time/ | |\n", + "| episodes | 8 |\n", + "| fps | 76 |\n", + "| time_elapsed | 10 |\n", + "| total_timesteps | 808 |\n", + "| train/ | |\n", + "| actor_loss | 36.9 |\n", + "| critic_loss | 6.27 |\n", + "| ent_coef | 0.846 |\n", + "| ent_coef_loss | -0.128 |\n", + "| learning_rate | 0.0003 |\n", + "| n_updates | 707 |\n", + "----------------------------------\n", + "----------------------------------\n", + "| rollout/ | |\n", + "| ep_len_mean | 101 |\n", + "| ep_rew_mean | -1.15e+03 |\n", + "| time/ | |\n", + "| episodes | 12 |\n", + "| fps | 75 |\n", + "| time_elapsed | 16 |\n", + "| total_timesteps | 1212 |\n", + "| train/ | |\n", + "| actor_loss | 53.9 |\n", + "| critic_loss | 7.76 |\n", + "| ent_coef | 0.767 |\n", + "| ent_coef_loss | -0.234 |\n", + "| learning_rate | 0.0003 |\n", + "| n_updates | 1111 |\n", + "----------------------------------\n", + "----------------------------------\n", + "| rollout/ | |\n", + "| ep_len_mean | 101 |\n", + "| ep_rew_mean | -1.03e+03 |\n", + "| time/ | |\n", + "| episodes | 16 |\n", + "| fps | 74 |\n", + "| time_elapsed | 21 |\n", + "| total_timesteps | 1616 |\n", + "| train/ | |\n", + "| actor_loss | 66.8 |\n", + "| critic_loss | 9.05 |\n", + "| ent_coef | 0.697 |\n", + "| ent_coef_loss | -0.217 |\n", + "| learning_rate | 0.0003 |\n", + "| n_updates | 1515 |\n", + "----------------------------------\n", + "[INFO] [1652196372.046217]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", + "[INFO] [1652196372.047055]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196372.047886]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", + "[INFO] [1652196372.048780]: [/PendulumEnv/pendulum/x] Shutting down.\n", + "[INFO] [1652196372.104167]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", + "[INFO] [1652196372.104926]: [/PendulumEnv/pendulum/image] Shutting down.\n", + "[INFO] [1652196372.105660]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", + "[INFO] [1652196372.106248]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", + "[INFO] [1652196372.106903]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", + "[INFO] [1652196372.107513]: [/PendulumEnv/pendulum/u] Shutting down.\n", + "[INFO] [1652196372.108162]: [/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196372.109586]: [PendulumEnv][/PendulumEnv/filter] Shutting down.\n", + "[INFO] [1652196372.110172]: [/PendulumEnv/filter] Shutting down.\n", + "[INFO] [1652196372.111653]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196372.113029]: [/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196372.114334]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196372.115065]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196372.116136]: [/PendulumEnv/env/supervisor] Shutting down.\n", + "[INFO] [1652196372.120426]: [/PendulumEnv/environment] Shutting down.\n", + "[INFO] [1652196372.123830]: Parameters under namespace \"/PendulumEnv\" deleted.\n", + "[INFO] [1652196344.098380]: START RENDERING!\n", + "[INFO] [1652196344.111623]: Node \"/PendulumEnv/env/render\" initialized.\n", + "[INFO] [1652196372.047287]: [/PendulumEnv/env/render] Shutting down.\n", + "shutdown request: [/eagerx_core] Reason: new node registered with same name\n" + ] + } + ], "source": [ "import numpy as np\n", "from typing import Dict\n", @@ -496,7 +673,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/tutorials/pendulum/5_engine_implementation.ipynb b/tutorials/pendulum/5_engine_implementation.ipynb index af83816..1f35bfa 100644 --- a/tutorials/pendulum/5_engine_implementation.ipynb +++ b/tutorials/pendulum/5_engine_implementation.ipynb @@ -31,7 +31,14 @@ "\n", "We will assume that we already have the object definition of the underactuated pendulum that we used in the [first](https://colab.research.google.com/github/eager-dev/eagerx_tutorials/blob/master/tutorials/pendulum/1_environment_creation.ipynb) tutorial with its dynamics simulated by the ODE bridge and corresponding ordinary differential equations (ODEs).\n", "\n", - "Our goal is to interface the underactuated pendulum we used in the previous tutorials with a different physics-engine. This allows us to investigate the effect of the physics engine on the learned performance. \n", + "Our goal is to interface the underactuated pendulum we used in the previous tutorials with a different physics-engine. This allows us to investigate the effect of the physics engine on the learned performance.\n", + "\n", + "## Activate GPU (Colab only)\n", + "\n", + "When in Colab, you'll need to enable GPUs for the notebook:\n", + "\n", + "- Navigate to Edit→Notebook Settings\n", + "- select GPU from the Hardware Accelerator drop-down\n", "\n", "## Notebook Setup\n", "\n", @@ -66,13 +73,7 @@ "# Setup interactive notebook\n", "# Required in interactive notebooks only.\n", "from eagerx_tutorials import helper\n", - "helper.setup_notebook()\n", - "env = None\n", - "\n", - "# Allows reloading of registered entites from changed files\n", - "# Required in interactive notebooks only.\n", - "%reload_ext autoreload\n", - "%autoreload 1" + "helper.setup_notebook()" ] }, { @@ -95,8 +96,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "... logging to /home/r2ci/.ros/log/9cefdd38-cdf1-11ec-9c64-bf766e5c8881/roslaunch-r2ci-Alienware-m15-R4-40365.log\n", - "\u001b[1mstarted roslaunch server http://192.168.68.129:40697/\u001b[0m\n", + "... logging to /home/jelle/.ros/log/4c93712a-d075-11ec-8414-1f5d9a0d084b/roslaunch-jelle-Alienware-m15-R4-30809.log\n", + "\u001b[1mstarted roslaunch server http://145.94.219.156:44711/\u001b[0m\n", "ros_comm version 1.15.14\n", "\n", "\n", @@ -109,7 +110,7 @@ "\n", "NODES\n", "\n", - "[INFO] [1651919899.138003]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" + "[INFO] [1652196398.676144]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" ] } ], @@ -192,7 +193,7 @@ "Registered entity_id=`Pendulum`:\n", " entity_type: `Object`\n", " module: `eagerx_tutorials.pendulum.objects`\n", - " file: `/home/r2ci/eagerx-dev/eagerx_tutorials/eagerx_tutorials/pendulum/objects.py`\n", + " file: `/home/jelle/eagerx_dev/eagerx_tutorials/eagerx_tutorials/pendulum/objects.py`\n", "\n", "Supported bridges:\n", " - OdeBridge\n", @@ -274,7 +275,7 @@ "Registered entity_id=`GymBridge`:\n", " entity_type: `Bridge`\n", " module: `eagerx.bridges.openai_gym.bridge`\n", - " file: `/home/r2ci/.cache/pypoetry/virtualenvs/eagerx-tutorials-t4w5hBSU-py3.8/lib/python3.8/site-packages/eagerx/bridges/openai_gym/bridge.py`\n", + " file: `/home/jelle/.cache/pypoetry/virtualenvs/eagerx-tutorials-NkxrhtGC-py3.8/lib/python3.8/site-packages/eagerx/bridges/openai_gym/bridge.py`\n", "\n", "Make this spec with (use `entity_id: str = \"GymBridge\"`):\n", " spec = Bridge.make(entity_id: str, rate, process: Union[int, NoneType] = 0, sync: Union[bool, NoneType] = True, real_time_factor: Union[float, NoneType] = 0, simulate_delays: Union[bool, NoneType] = True, log_level: Union[int, NoneType] = 40)\n", @@ -393,7 +394,7 @@ "Registered entity_id=`Pendulum`:\n", " entity_type: `Object`\n", " module: `eagerx_tutorials.pendulum.objects`\n", - " file: `/home/r2ci/eagerx-dev/eagerx_tutorials/eagerx_tutorials/pendulum/objects.py`\n", + " file: `/home/jelle/eagerx_dev/eagerx_tutorials/eagerx_tutorials/pendulum/objects.py`\n", "\n", "Supported bridges:\n", " - OdeBridge\n", @@ -514,12 +515,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "[INFO] [1651919899.476883]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", - "[INFO] [1651919899.619231]: Node \"/PendulumEnv/bridge\" initialized.\n", - "[INFO] [1651919899.750160]: Node \"/PendulumEnv/environment\" initialized.\n", - "[INFO] [1651919899.825991]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", - "[INFO] [1651919899.869510]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", - "[INFO] [1651919899.881449]: Waiting for nodes \"['env/render']\" to be initialized.\n" + "[INFO] [1652196399.139893]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", + "[INFO] [1652196399.285888]: Node \"/PendulumEnv/bridge\" initialized.\n", + "[INFO] [1652196399.410301]: Node \"/PendulumEnv/environment\" initialized.\n", + "[INFO] [1652196399.505974]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", + "[INFO] [1652196399.545025]: Waiting for nodes \"['env/render']\" to be initialized.\n", + "[INFO] [1652196399.563543]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n" ] } ], @@ -575,103 +576,134 @@ "name": "stdout", "output_type": "stream", "text": [ - "[INFO] [1651919899.940472]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", - "[INFO] [1651919900.120698]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", - "[INFO] [1651919900.139842]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", - "[INFO] [1651919900.161545]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", - "[INFO] [1651919900.179271]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", + "[INFO] [1652196399.633790]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", + "[INFO] [1652196399.923561]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", + "[INFO] [1652196399.947680]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", + "[INFO] [1652196399.969535]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", + "[INFO] [1652196399.988124]: Node \"/PendulumEnv/pendulum/u\" initialized.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/jelle/.cache/pypoetry/virtualenvs/eagerx-tutorials-NkxrhtGC-py3.8/lib/python3.8/site-packages/stable_baselines3/common/env_checker.py:272: UserWarning: We recommend you to use a symmetric and normalized Box action space (range=[-1, 1]) cf https://stable-baselines3.readthedocs.io/en/master/guide/rl_tips.html\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[INFO] [1652196400.173113]: [pendulum/image] START RENDERING!\n", + "[INFO] [1652196400.690531]: Nodes initialized.\n", + "[INFO] [1652196400.876420]: Pipelines initialized.\n", "Using cpu device\n", "Wrapping the env with a `Monitor` wrapper\n", "Wrapping the env in a DummyVecEnv.\n", - "[INFO] [1651919900.350122]: [pendulum/image] START RENDERING!\n", - "[INFO] [1651919901.173836]: Nodes initialized.\n", - "[INFO] [1651919901.243847]: Pipelines initialized.\n", "----------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -1.38e+03 |\n", + "| ep_rew_mean | -1.17e+03 |\n", "| time/ | |\n", "| episodes | 4 |\n", - "| fps | 68 |\n", + "| fps | 72 |\n", "| time_elapsed | 5 |\n", "| total_timesteps | 404 |\n", "| train/ | |\n", - "| actor_loss | 27.1 |\n", - "| critic_loss | 33.5 |\n", - "| ent_coef | 0.914 |\n", - "| ent_coef_loss | -0.133 |\n", + "| actor_loss | 23 |\n", + "| critic_loss | 5.12 |\n", + "| ent_coef | 0.921 |\n", + "| ent_coef_loss | -0.0769 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 303 |\n", "----------------------------------\n", "----------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -1.21e+03 |\n", + "| ep_rew_mean | -1.16e+03 |\n", "| time/ | |\n", "| episodes | 8 |\n", - "| fps | 69 |\n", - "| time_elapsed | 11 |\n", + "| fps | 65 |\n", + "| time_elapsed | 12 |\n", "| total_timesteps | 808 |\n", "| train/ | |\n", - "| actor_loss | 42.6 |\n", - "| critic_loss | 20.6 |\n", - "| ent_coef | 0.831 |\n", - "| ent_coef_loss | -0.197 |\n", + "| actor_loss | 33.6 |\n", + "| critic_loss | 3.71 |\n", + "| ent_coef | 0.846 |\n", + "| ent_coef_loss | -0.16 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 707 |\n", "----------------------------------\n", - "---------------------------------\n", - "| rollout/ | |\n", - "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -1.1e+03 |\n", - "| time/ | |\n", - "| episodes | 12 |\n", - "| fps | 68 |\n", - "| time_elapsed | 17 |\n", - "| total_timesteps | 1212 |\n", - "| train/ | |\n", - "| actor_loss | 56.3 |\n", - "| critic_loss | 14 |\n", - "| ent_coef | 0.76 |\n", - "| ent_coef_loss | -0.253 |\n", - "| learning_rate | 0.0003 |\n", - "| n_updates | 1111 |\n", - "---------------------------------\n", "----------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -1.01e+03 |\n", + "| ep_rew_mean | -1.09e+03 |\n", + "| time/ | |\n", + "| episodes | 12 |\n", + "| fps | 62 |\n", + "| time_elapsed | 19 |\n", + "| total_timesteps | 1212 |\n", + "| train/ | |\n", + "| actor_loss | 47.8 |\n", + "| critic_loss | 4.59 |\n", + "| ent_coef | 0.763 |\n", + "| ent_coef_loss | -0.277 |\n", + "| learning_rate | 0.0003 |\n", + "| n_updates | 1111 |\n", + "----------------------------------\n", + "----------------------------------\n", + "| rollout/ | |\n", + "| ep_len_mean | 101 |\n", + "| ep_rew_mean | -1.02e+03 |\n", "| time/ | |\n", "| episodes | 16 |\n", - "| fps | 68 |\n", - "| time_elapsed | 23 |\n", + "| fps | 61 |\n", + "| time_elapsed | 26 |\n", "| total_timesteps | 1616 |\n", "| train/ | |\n", - "| actor_loss | 70.4 |\n", - "| critic_loss | 15.9 |\n", + "| actor_loss | 61.4 |\n", + "| critic_loss | 4.48 |\n", "| ent_coef | 0.692 |\n", - "| ent_coef_loss | -0.277 |\n", + "| ent_coef_loss | -0.182 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1515 |\n", "----------------------------------\n", - "[INFO] [1651919926.632417]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", - "[INFO] [1651919926.633238]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651919926.633937]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", - "[INFO] [1651919926.634665]: [/PendulumEnv/pendulum/x] Shutting down.\n", - "[INFO] [1651919926.681074]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", - "[INFO] [1651919926.681995]: [/PendulumEnv/pendulum/image] Shutting down.\n", - "[INFO] [1651919926.682710]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", - "[INFO] [1651919926.683310]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", - "[INFO] [1651919926.683918]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", - "[INFO] [1651919926.684594]: [/PendulumEnv/pendulum/u] Shutting down.\n", - "[INFO] [1651919926.685410]: [/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651919926.686953]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651919926.687701]: [/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651919926.688666]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651919926.689635]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651919926.690794]: [/PendulumEnv/env/supervisor] Shutting down.\n", - "[INFO] [1651919926.695745]: [/PendulumEnv/environment] Shutting down.\n", - "[INFO] [1651919926.698809]: Parameters under namespace \"/PendulumEnv\" deleted.\n" + "[INFO] [1652196430.273293]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", + "[INFO] [1652196430.274320]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196430.275301]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", + "[INFO] [1652196430.276185]: [/PendulumEnv/pendulum/x] Shutting down.\n", + "[INFO] [1652196430.333415]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", + "[INFO] [1652196430.334151]: [/PendulumEnv/pendulum/image] Shutting down.\n", + "[INFO] [1652196430.335024]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", + "[INFO] [1652196430.335637]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", + "[INFO] [1652196430.336298]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", + "[INFO] [1652196430.336842]: [/PendulumEnv/pendulum/u] Shutting down.\n", + "[INFO] [1652196430.337586]: [/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196430.338870]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196430.339472]: [/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196430.340141]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196430.340721]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196430.341432]: [/PendulumEnv/env/supervisor] Shutting down.\n", + "[INFO] [1652196430.344951]: [/PendulumEnv/environment] Shutting down.\n", + "[INFO] [1652196430.347016]: Parameters under namespace \"/PendulumEnv\" deleted.\n", + "[INFO] [1652196400.475885]: START RENDERING!\n", + "[INFO] [1652196400.489584]: Node \"/PendulumEnv/env/render\" initialized.\n", + "[INFO] [1652196430.274494]: [/PendulumEnv/env/render] Shutting down.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "QObject::~QObject: Timers cannot be stopped from another thread\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "shutdown request: [/eagerx_core] Reason: new node registered with same name\n" ] } ], @@ -739,16 +771,8 @@ "1.2 Select the GymBridge by uncommenting the marked line. Run the code *(note: you may need to restart your kernel)*. \n", "\n", "1.3 Now, select sensor `u` (not to be mistaken with the actuator `u`!!) for the pendulum and connect it as an `observation`. Run the code and observe that it fails. As the error states, we did not provide an implementation for sensor `u`. This highlights that it is not compulsory to implement every actuator, sensor, or state that was defined by the object. You are free to only support a subset of them. However, you **will** get an error if you try to run with one that does not have an *engine-specific* implementation for the selected bridge. \n", - "1.4 Switch back to using the OdeBridge (while still selecting sensor `u`). Run the code. It should again run without problems, as the OdeBridge **does** have an implementation for the sensor `u`. \n" + "1.4 Switch back to using the OdeBridge (while still selecting sensor `u`). Run the code. It should again run without problems, as the OdeBridge **does** have an implementation for the sensor `u`. " ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d07659e4-9d17-43d7-8fb3-1d6e34ddc9ee", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -767,7 +791,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/tutorials/pendulum/6_rendering.ipynb b/tutorials/pendulum/6_rendering.ipynb index e6027f4..3636d5b 100644 --- a/tutorials/pendulum/6_rendering.ipynb +++ b/tutorials/pendulum/6_rendering.ipynb @@ -32,6 +32,13 @@ "\n", "Our goal is to make the rendered images more informative. We will lay the actions, selected by the agent, over the raw images produced by the image sensor of the pendulum. We will then visualise the augmented images instead of the raw images from the image sensor.\n", "\n", + "## Activate GPU (Colab only)\n", + "\n", + "When in Colab, you'll need to enable GPUs for the notebook:\n", + "\n", + "- Navigate to Edit→Notebook Settings\n", + "- select GPU from the Hardware Accelerator drop-down\n", + "\n", "## Notebook Setup\n", "\n", "In order to be able to run the code, we need to install the *eagerx_tutorials* package and ROS." @@ -65,13 +72,7 @@ "# Setup interactive notebook\n", "# Required in interactive notebooks only.\n", "from eagerx_tutorials import helper\n", - "helper.setup_notebook()\n", - "env = None\n", - "\n", - "# Allows reloading of registered entites from changed files\n", - "# Required in interactive notebooks only.\n", - "%reload_ext autoreload\n", - "%autoreload 1" + "helper.setup_notebook()" ] }, { @@ -94,8 +95,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "... logging to /home/r2ci/.ros/log/9cefdd38-cdf1-11ec-9c64-bf766e5c8881/roslaunch-r2ci-Alienware-m15-R4-47684.log\n", - "\u001b[1mstarted roslaunch server http://192.168.68.129:42777/\u001b[0m\n", + "... logging to /home/jelle/.ros/log/4c93712a-d075-11ec-8414-1f5d9a0d084b/roslaunch-jelle-Alienware-m15-R4-38176.log\n", + "\u001b[1mstarted roslaunch server http://145.94.219.156:46405/\u001b[0m\n", "ros_comm version 1.15.14\n", "\n", "\n", @@ -108,7 +109,7 @@ "\n", "NODES\n", "\n", - "[INFO] [1651919956.899805]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" + "[INFO] [1652196444.935475]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" ] } ], @@ -357,109 +358,113 @@ "name": "stdout", "output_type": "stream", "text": [ - "[INFO] [1651919957.588579]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", - "[INFO] [1651919957.730204]: Node \"/PendulumEnv/bridge\" initialized.\n", - "[INFO] [1651919957.852467]: Node \"/PendulumEnv/environment\" initialized.\n", - "[INFO] [1651919957.936105]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", - "[INFO] [1651919957.981980]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", - "[INFO] [1651919957.983833]: Waiting for nodes \"['env/render']\" to be initialized.\n", + "[INFO] [1652196445.761356]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", + "[INFO] [1652196445.905941]: Node \"/PendulumEnv/bridge\" initialized.\n", + "[INFO] [1652196446.032032]: Node \"/PendulumEnv/environment\" initialized.\n", + "[INFO] [1652196446.120418]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", + "[INFO] [1652196446.167797]: Waiting for nodes \"['env/render']\" to be initialized.\n", + "[INFO] [1652196446.171144]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", "Using cpu device\n", "Wrapping the env with a `Monitor` wrapper\n", "Wrapping the env in a DummyVecEnv.\n", - "[INFO] [1651919958.043329]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", - "[INFO] [1651919958.061206]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", - "[INFO] [1651919958.083694]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", - "[INFO] [1651919958.084498]: [pendulum/image] START RENDERING!\n", - "[INFO] [1651919958.103086]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", - "[INFO] [1651919958.121359]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", - "[INFO] [1651919959.194804]: Nodes initialized.\n", - "[INFO] [1651919959.249067]: Pipelines initialized.\n", - "---------------------------------\n", - "| rollout/ | |\n", - "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -1.2e+03 |\n", - "| time/ | |\n", - "| episodes | 4 |\n", - "| fps | 63 |\n", - "| time_elapsed | 6 |\n", - "| total_timesteps | 404 |\n", - "| train/ | |\n", - "| actor_loss | 24 |\n", - "| critic_loss | 10.9 |\n", - "| ent_coef | 0.918 |\n", - "| ent_coef_loss | -0.103 |\n", - "| learning_rate | 0.0003 |\n", - "| n_updates | 303 |\n", - "---------------------------------\n", + "[INFO] [1652196446.238205]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", + "[INFO] [1652196446.259319]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", + "[INFO] [1652196446.281689]: [pendulum/image] START RENDERING!\n", + "[INFO] [1652196446.281988]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", + "[INFO] [1652196446.301505]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", + "[INFO] [1652196446.319921]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", + "[INFO] [1652196447.390980]: Nodes initialized.\n", + "[INFO] [1652196447.442707]: Pipelines initialized.\n", "----------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -1.02e+03 |\n", + "| ep_rew_mean | -1.13e+03 |\n", "| time/ | |\n", - "| episodes | 8 |\n", - "| fps | 64 |\n", - "| time_elapsed | 12 |\n", - "| total_timesteps | 808 |\n", + "| episodes | 4 |\n", + "| fps | 56 |\n", + "| time_elapsed | 7 |\n", + "| total_timesteps | 404 |\n", "| train/ | |\n", - "| actor_loss | 35.4 |\n", - "| critic_loss | 5.53 |\n", - "| ent_coef | 0.84 |\n", - "| ent_coef_loss | -0.163 |\n", + "| actor_loss | 21 |\n", + "| critic_loss | 5.94 |\n", + "| ent_coef | 0.916 |\n", + "| ent_coef_loss | -0.119 |\n", "| learning_rate | 0.0003 |\n", - "| n_updates | 707 |\n", + "| n_updates | 303 |\n", "----------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -935 |\n", + "| ep_rew_mean | -986 |\n", + "| time/ | |\n", + "| episodes | 8 |\n", + "| fps | 57 |\n", + "| time_elapsed | 14 |\n", + "| total_timesteps | 808 |\n", + "| train/ | |\n", + "| actor_loss | 34.8 |\n", + "| critic_loss | 5.99 |\n", + "| ent_coef | 0.835 |\n", + "| ent_coef_loss | -0.17 |\n", + "| learning_rate | 0.0003 |\n", + "| n_updates | 707 |\n", + "---------------------------------\n", + "---------------------------------\n", + "| rollout/ | |\n", + "| ep_len_mean | 101 |\n", + "| ep_rew_mean | -896 |\n", "| time/ | |\n", "| episodes | 12 |\n", - "| fps | 63 |\n", - "| time_elapsed | 19 |\n", + "| fps | 57 |\n", + "| time_elapsed | 21 |\n", "| total_timesteps | 1212 |\n", "| train/ | |\n", - "| actor_loss | 47.3 |\n", - "| critic_loss | 6.07 |\n", - "| ent_coef | 0.762 |\n", - "| ent_coef_loss | -0.222 |\n", + "| actor_loss | 47.4 |\n", + "| critic_loss | 4.44 |\n", + "| ent_coef | 0.76 |\n", + "| ent_coef_loss | -0.238 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1111 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -869 |\n", + "| ep_rew_mean | -841 |\n", "| time/ | |\n", "| episodes | 16 |\n", - "| fps | 63 |\n", - "| time_elapsed | 25 |\n", + "| fps | 57 |\n", + "| time_elapsed | 28 |\n", "| total_timesteps | 1616 |\n", "| train/ | |\n", - "| actor_loss | 61 |\n", - "| critic_loss | 4.97 |\n", - "| ent_coef | 0.699 |\n", - "| ent_coef_loss | -0.203 |\n", + "| actor_loss | 59.1 |\n", + "| critic_loss | 5.66 |\n", + "| ent_coef | 0.7 |\n", + "| ent_coef_loss | -0.187 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1515 |\n", "---------------------------------\n", - "[INFO] [1651919986.540698]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", - "[INFO] [1651919986.541542]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651919986.542227]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", - "[INFO] [1651919986.542872]: [/PendulumEnv/pendulum/x] Shutting down.\n", - "[INFO] [1651919986.597756]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", - "[INFO] [1651919986.598776]: [/PendulumEnv/pendulum/image] Shutting down.\n", - "[INFO] [1651919986.600023]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", - "[INFO] [1651919986.600626]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", - "[INFO] [1651919986.601283]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", - "[INFO] [1651919986.601852]: [/PendulumEnv/pendulum/u] Shutting down.\n", - "[INFO] [1651919986.602490]: [/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651919986.603741]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651919986.604360]: [/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651919986.605014]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651919986.605585]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651919986.606255]: [/PendulumEnv/env/supervisor] Shutting down.\n", - "[INFO] [1651919986.609506]: [/PendulumEnv/environment] Shutting down.\n", - "[INFO] [1651919986.611503]: Parameters under namespace \"/PendulumEnv\" deleted.\n" + "[INFO] [1652196477.588193]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", + "[INFO] [1652196477.589210]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196477.590331]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", + "[INFO] [1652196477.591426]: [/PendulumEnv/pendulum/x] Shutting down.\n", + "[INFO] [1652196477.646198]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", + "[INFO] [1652196477.647194]: [/PendulumEnv/pendulum/image] Shutting down.\n", + "[INFO] [1652196477.648095]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", + "[INFO] [1652196477.648838]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", + "[INFO] [1652196477.649782]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", + "[INFO] [1652196477.650409]: [/PendulumEnv/pendulum/u] Shutting down.\n", + "[INFO] [1652196477.651106]: [/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196477.652349]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196477.652976]: [/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196477.653680]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196477.654209]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196477.654891]: [/PendulumEnv/env/supervisor] Shutting down.\n", + "[INFO] [1652196477.658197]: [/PendulumEnv/environment] Shutting down.\n", + "[INFO] [1652196477.660268]: Parameters under namespace \"/PendulumEnv\" deleted.\n", + "[INFO] [1652196447.086873]: START RENDERING!\n", + "[INFO] [1652196447.100938]: Node \"/PendulumEnv/env/render\" initialized.\n", + "[INFO] [1652196477.589380]: [/PendulumEnv/env/render] Shutting down.\n", + "shutdown request: [/eagerx_core] Reason: new node registered with same name\n" ] } ], @@ -566,7 +571,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/tutorials/pendulum/7_reset_routine.ipynb b/tutorials/pendulum/7_reset_routine.ipynb index b556af7..29763b1 100644 --- a/tutorials/pendulum/7_reset_routine.ipynb +++ b/tutorials/pendulum/7_reset_routine.ipynb @@ -32,6 +32,13 @@ "\n", "Our goal is to create a [`ResetNode`](https://eagerx.readthedocs.io/en/master/guide/api_reference/node/reset_node.html) that can reset the pendulum to a desired state (i.e. $\\theta=\\theta_\\text{des}$ and $\\dot{\\theta}=0$) without requiring a simulator reset. In other words, the [`ResetNode`](https://eagerx.readthedocs.io/en/master/guide/api_reference/node/reset_node.html) will receive the desired state as a target and it will send actuator commands until the pendulum has reached this state.\n", "\n", + "## Activate GPU (Colab only)\n", + "\n", + "When in Colab, you'll need to enable GPUs for the notebook:\n", + "\n", + "- Navigate to Edit→Notebook Settings\n", + "- select GPU from the Hardware Accelerator drop-down\n", + "\n", "## Notebook Setup\n", "\n", "In order to be able to run the code, we need to install the *eagerx_tutorials* package and ROS." @@ -88,8 +95,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "... logging to /home/r2ci/.ros/log/9cefdd38-cdf1-11ec-9c64-bf766e5c8881/roslaunch-r2ci-Alienware-m15-R4-32962.log\n", - "\u001b[1mstarted roslaunch server http://192.168.68.129:36423/\u001b[0m\n", + "... logging to /home/jelle/.ros/log/4c93712a-d075-11ec-8414-1f5d9a0d084b/roslaunch-jelle-Alienware-m15-R4-45543.log\n", + "\u001b[1mstarted roslaunch server http://145.94.219.156:45085/\u001b[0m\n", "ros_comm version 1.15.14\n", "\n", "\n", @@ -102,23 +109,8 @@ "\n", "NODES\n", "\n", - "auto-starting new master\n", - "\u001b[1mprocess[master]: started with pid [33011]\u001b[0m\n", - "\u001b[1mROS_MASTER_URI=http://localhost:11311\u001b[0m\n", - "\u001b[1msetting /run_id to 9cefdd38-cdf1-11ec-9c64-bf766e5c8881\u001b[0m\n", - "\u001b[1mprocess[rosout-1]: started with pid [33036]\u001b[0m\n", - "started core service [/rosout]\n" + "[INFO] [1652196519.115797]: Roscore cannot run as another roscore/master is already running. Continuing without re-initializing the roscore.\n" ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ @@ -398,112 +390,115 @@ "name": "stdout", "output_type": "stream", "text": [ - "[INFO] [1651919815.595556]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", - "[INFO] [1651919815.741111]: Node \"/PendulumEnv/bridge\" initialized.\n", - "[INFO] [1651919815.914065]: Node \"/PendulumEnv/environment\" initialized.\n", - "[INFO] [1651919816.015099]: Node \"/PendulumEnv/reset_angle\" initialized.\n", - "[INFO] [1651919816.042641]: Waiting for nodes \"['env/render']\" to be initialized.\n", - "[INFO] [1651919816.054446]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", - "[INFO] [1651919816.080170]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", - "Using cpu device\n", + "[INFO] [1652196519.902557]: Node \"/PendulumEnv/env/supervisor\" initialized.\n", + "[INFO] [1652196520.050113]: Node \"/PendulumEnv/bridge\" initialized.\n", + "[INFO] [1652196520.174265]: Node \"/PendulumEnv/environment\" initialized.\n", + "[INFO] [1652196520.234826]: Node \"/PendulumEnv/reset_angle\" initialized.\n", + "[INFO] [1652196520.311833]: Waiting for nodes \"['env/render']\" to be initialized.\n", + "[INFO] [1652196520.375947]: Node \"/PendulumEnv/pendulum/theta\" initialized.\n", + "[INFO] [1652196520.406640]: Node \"/PendulumEnv/pendulum/dtheta\" initialized.\n", + "Using cuda device\n", "Wrapping the env with a `Monitor` wrapper\n", "Wrapping the env in a DummyVecEnv.\n", - "[INFO] [1651919816.142294]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", - "[INFO] [1651919816.158228]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", - "[INFO] [1651919816.175462]: [pendulum/image] START RENDERING!\n", - "[INFO] [1651919816.175653]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", - "[INFO] [1651919816.188318]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", - "[INFO] [1651919816.199715]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", - "[INFO] [1651919817.286460]: Nodes initialized.\n", - "[INFO] [1651919817.411295]: Pipelines initialized.\n", + "[INFO] [1652196520.508030]: Adding object \"pendulum\" of type \"Pendulum\" to the simulator.\n", + "[INFO] [1652196520.529470]: Node \"/PendulumEnv/pendulum/x\" initialized.\n", + "[INFO] [1652196520.553598]: [pendulum/image] START RENDERING!\n", + "[INFO] [1652196520.555102]: Node \"/PendulumEnv/pendulum/image\" initialized.\n", + "[INFO] [1652196520.576348]: Node \"/PendulumEnv/pendulum/pendulum_actuator\" initialized.\n", + "[INFO] [1652196520.597573]: Node \"/PendulumEnv/pendulum/u\" initialized.\n", + "[INFO] [1652196523.765033]: Nodes initialized.\n", + "[INFO] [1652196523.848110]: Pipelines initialized.\n", "----------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -1.08e+03 |\n", + "| ep_rew_mean | -1.05e+03 |\n", "| time/ | |\n", "| episodes | 4 |\n", - "| fps | 62 |\n", + "| fps | 65 |\n", "| time_elapsed | 6 |\n", "| total_timesteps | 404 |\n", "| train/ | |\n", - "| actor_loss | 20.5 |\n", - "| critic_loss | 2.93 |\n", - "| ent_coef | 0.918 |\n", - "| ent_coef_loss | -0.0997 |\n", + "| actor_loss | 20.8 |\n", + "| critic_loss | 3.19 |\n", + "| ent_coef | 0.917 |\n", + "| ent_coef_loss | -0.099 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 303 |\n", "----------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -953 |\n", + "| ep_rew_mean | -929 |\n", "| time/ | |\n", "| episodes | 8 |\n", - "| fps | 64 |\n", - "| time_elapsed | 12 |\n", + "| fps | 61 |\n", + "| time_elapsed | 13 |\n", "| total_timesteps | 808 |\n", "| train/ | |\n", - "| actor_loss | 34.5 |\n", - "| critic_loss | 1.16 |\n", - "| ent_coef | 0.832 |\n", - "| ent_coef_loss | -0.198 |\n", + "| actor_loss | 33.3 |\n", + "| critic_loss | 0.994 |\n", + "| ent_coef | 0.833 |\n", + "| ent_coef_loss | -0.199 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 707 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -886 |\n", + "| ep_rew_mean | -871 |\n", "| time/ | |\n", "| episodes | 12 |\n", - "| fps | 64 |\n", - "| time_elapsed | 18 |\n", + "| fps | 60 |\n", + "| time_elapsed | 20 |\n", "| total_timesteps | 1212 |\n", "| train/ | |\n", - "| actor_loss | 48.1 |\n", - "| critic_loss | 0.472 |\n", - "| ent_coef | 0.75 |\n", - "| ent_coef_loss | -0.229 |\n", + "| actor_loss | 46.7 |\n", + "| critic_loss | 0.446 |\n", + "| ent_coef | 0.751 |\n", + "| ent_coef_loss | -0.319 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1111 |\n", "---------------------------------\n", "---------------------------------\n", "| rollout/ | |\n", "| ep_len_mean | 101 |\n", - "| ep_rew_mean | -825 |\n", + "| ep_rew_mean | -819 |\n", "| time/ | |\n", "| episodes | 16 |\n", - "| fps | 64 |\n", - "| time_elapsed | 24 |\n", + "| fps | 60 |\n", + "| time_elapsed | 26 |\n", "| total_timesteps | 1616 |\n", "| train/ | |\n", - "| actor_loss | 59.4 |\n", - "| critic_loss | 0.619 |\n", + "| actor_loss | 58.1 |\n", + "| critic_loss | 0.673 |\n", "| ent_coef | 0.693 |\n", - "| ent_coef_loss | -0.108 |\n", + "| ent_coef_loss | -0.181 |\n", "| learning_rate | 0.0003 |\n", "| n_updates | 1515 |\n", "---------------------------------\n", - "[INFO] [1651919843.762226]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", - "[INFO] [1651919843.763085]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651919843.763754]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", - "[INFO] [1651919843.764547]: [/PendulumEnv/pendulum/x] Shutting down.\n", - "[INFO] [1651919843.825222]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", - "[INFO] [1651919843.826648]: [/PendulumEnv/pendulum/image] Shutting down.\n", - "[INFO] [1651919843.827811]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", - "[INFO] [1651919843.828558]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", - "[INFO] [1651919843.829467]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", - "[INFO] [1651919843.830096]: [/PendulumEnv/pendulum/u] Shutting down.\n", - "[INFO] [1651919843.830786]: [/PendulumEnv/bridge] Shutting down.\n", - "[INFO] [1651919843.832136]: [PendulumEnv][/PendulumEnv/reset_angle] Shutting down.\n", - "[INFO] [1651919843.832775]: [/PendulumEnv/reset_angle] Shutting down.\n", - "[INFO] [1651919843.833533]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651919843.834180]: [/PendulumEnv/pendulum/theta] Shutting down.\n", - "[INFO] [1651919843.834869]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651919843.835497]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", - "[INFO] [1651919843.836236]: [/PendulumEnv/env/supervisor] Shutting down.\n", - "[INFO] [1651919843.839689]: [/PendulumEnv/environment] Shutting down.\n", - "[INFO] [1651919843.841672]: Parameters under namespace \"/PendulumEnv\" deleted.\n" + "[INFO] [1652196553.288316]: [PendulumEnv] Send termination signal to '/PendulumEnv/env/render'.\n", + "[INFO] [1652196553.289182]: [PendulumEnv][/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196553.290008]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/x'.\n", + "[INFO] [1652196553.290879]: [/PendulumEnv/pendulum/x] Shutting down.\n", + "[INFO] [1652196553.359674]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/image'.\n", + "[INFO] [1652196553.360538]: [/PendulumEnv/pendulum/image] Shutting down.\n", + "[INFO] [1652196553.361551]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/pendulum_actuator'.\n", + "[INFO] [1652196553.362245]: [/PendulumEnv/pendulum/pendulum_actuator] Shutting down.\n", + "[INFO] [1652196553.362998]: [/PendulumEnv/bridge] Shutting down '/PendulumEnv/pendulum/u'.\n", + "[INFO] [1652196553.363661]: [/PendulumEnv/pendulum/u] Shutting down.\n", + "[INFO] [1652196553.364405]: [/PendulumEnv/bridge] Shutting down.\n", + "[INFO] [1652196553.365880]: [PendulumEnv][/PendulumEnv/reset_angle] Shutting down.\n", + "[INFO] [1652196553.366550]: [/PendulumEnv/reset_angle] Shutting down.\n", + "[INFO] [1652196553.367300]: [PendulumEnv][/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196553.367988]: [/PendulumEnv/pendulum/theta] Shutting down.\n", + "[INFO] [1652196553.368746]: [PendulumEnv][/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196553.369477]: [/PendulumEnv/pendulum/dtheta] Shutting down.\n", + "[INFO] [1652196553.370311]: [/PendulumEnv/env/supervisor] Shutting down.\n", + "[INFO] [1652196553.373993]: [/PendulumEnv/environment] Shutting down.\n", + "[INFO] [1652196553.376186]: Parameters under namespace \"/PendulumEnv\" deleted.\n", + "[INFO] [1652196521.332089]: START RENDERING!\n", + "[INFO] [1652196521.347384]: Node \"/PendulumEnv/env/render\" initialized.\n", + "[INFO] [1652196553.289365]: [/PendulumEnv/env/render] Shutting down.\n" ] } ], @@ -608,7 +603,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/tutorials/pendulum/figures/tutorial_6_gui.svg b/tutorials/pendulum/figures/tutorial_6_gui.svg index 1118c5b..7f8ed29 100644 --- a/tutorials/pendulum/figures/tutorial_6_gui.svg +++ b/tutorials/pendulum/figures/tutorial_6_gui.svg @@ -116,7 +116,7 @@ - layover + overlay diff --git a/tutorials/pendulum/node.py b/tutorials/pendulum/node.py deleted file mode 100644 index f34bcdd..0000000 --- a/tutorials/pendulum/node.py +++ /dev/null @@ -1,64 +0,0 @@ - -import eagerx -import eagerx.converters # Registers space converters -from eagerx.utils.utils import Msg -from std_msgs.msg import Float32, Float32MultiArray - - -class MovingAverageFilter(eagerx.Node): - @staticmethod - @eagerx.register.spec("ExampleNode", eagerx.Node) - def spec( - spec, - name: str, - rate: float, - n: int, - ): - """ - MovingAverage filter - :param spec: Not provided by user. - :param name: Node name - :param rate: Rate at which callback is called. - :param n: Window size of the moving average - :return: - """ - # Performs all the steps to fill-in the params with registered info about all functions. - spec.initialize(MovingAverageFilter) - - # Modify default node params - spec.config.name = name - spec.config.rate = rate - spec.config.process = eagerx.process.ENVIRONMENT - spec.config.inputs = ["signal"] - spec.config.outputs = ["filtered"] - - # Custom node params - # START ASSIGNMENT 1.1 - - # START ASSIGNMENT 1.1 - - # Add space converters - spec.inputs.signal.space_converter = eagerx.SpaceConverter.make("Space_Float32", -3, 3, dtype="float32") - spec.outputs.filtered.space_converter = eagerx.SpaceConverter.make("Space_Float32MultiArray", [-3], [3], dtype="float32") - - # START ASSIGNMENT 1.2 - def initialize(self): - pass - # END ASSIGNMENT 1.2 - - @eagerx.register.states() - def reset(self): - # START ASSIGNMENT 1.3 - pass - # END ASSIGNMENT 1.3 - - @eagerx.register.inputs(signal=Float32) - @eagerx.register.outputs(filtered=Float32MultiArray) - def callback(self, t_n: float, signal: Msg): - data = signal.msgs[-1].data - - # START ASSIGNMENT 1.4 - filtered_data = data - # END ASSIGNMENT 1.4 - - return dict(filtered=Float32MultiArray(data=[filtered_data]))