pypot/pypot-master/samples/notebooks/Accessing pypot REST API through HTTP requests.ipynb
2025-07-30 11:57:45 +08:00

507 lines
13 KiB
Plaintext

{
"metadata": {
"name": "",
"signature": "sha256:7a1296f1470068a26e12a6e9eae79f37b84cd8aa3b3b14d6a900280ca6850afd"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Accessing pypot REST API through HTTP requests"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Introduction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example, we will illustrate how to start an HTTP server permitting the remote access of any Poppy creature through the pypot [REST API](https://github.com/poppy-project/pypot/blob/REST-API-2.0/REST-APIs.md). More precisely, we will show how we can retrieve motor position and set new ones."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For this, we will use the simulated version of the Poppy humanoid. Thus, anyone even without having a \"real\" poppy creature on its table, will be able to try. Adapting this tutorial to a \"real\" robot should be straightforward."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The client side of the example - meaning the HTTP requests - will be realised using *curl*."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Note: For this tutorial you will need:*\n",
"* [V-REP](http://www.coppeliarobotics.com)\n",
"* [pypot](https://github.com/poppy-project/pypot) >= 2.x\n",
"* [poppytools](https://github.com/poppy-project/poppy-software)\n",
"* [bottle](http://bottlepy.org/docs/dev/index.html)"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Create the Robot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, we will instantiate a robot using V-REP (see [this post](https://forum.poppy-project.org/t/howto-connect-pypot-to-your-simulated-version-of-poppy-humanoid-in-v-rep/332/) for details on how this can be done)."
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Launch V-REP"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First launch a V-REP instance. We will assume below that the remoteApi is bind to *'127.0.0.1'* using the port *19997* (its default configuration)."
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Connect pypot to the V-REP scene"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import os\n",
"import json\n",
"\n",
"import pypot\n",
"import poppytools\n",
"\n",
"from pypot.vrep import from_vrep\n",
"\n",
"# Load the robot configuration\n",
"configfile = os.path.join(os.path.dirname(poppytools.__file__),\n",
" 'configuration', 'poppy_config.json')\n",
"\n",
"with open(configfile) as f:\n",
" robot_config = json.load(f)\n",
" \n",
"# Load a V-REP scene with poppy sitting\n",
"scene = os.path.join(os.path.dirname(pypot.__file__), \n",
" '..', 'samples', 'notebooks', 'poppy-sitting.ttt')\n",
"\n",
"# Connect to the simulated robot\n",
"robot = from_vrep(robot_config, '127.0.0.1', 19997, scene,\n",
" tracked_objects=['head_visual'])"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Create the HTTPServer"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will now starts the HTTP server providing the remote access of our robot."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It will run on *http://127.0.0.1:8080/*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from pypot.server.httpserver import HTTPRobotServer\n",
"\n",
"server = HTTPRobotServer(robot, host='127.0.0.1', port=8080)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default, the bottle server is launch using [tornado](http://www.tornadoweb.org/en/stable/) - for effiency puposes. Yet, as [IPython notebook](http://ipython.org/notebook.html) also uses the tornado server, it seems to cause trouble. Here, we use the [wsgiref](https://docs.python.org/2/library/wsgiref.html) server instead."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from threading import Thread\n",
"\n",
"Thread(target=lambda: server.run(quiet=True, server='wsgiref')).start()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As the [run method](http://poppy-project.github.io/pypot/pypot.server.html#pypot.server.httpserver.HTTPServer.run) of the server is blocking we launch it inside a thread. Thus, we can use the same notebook to send requests."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Sending requests"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that the server is launched, you should be able to directly access the robot using the [REST API](https://github.com/poppy-project/pypot/blob/REST-API-2.0/REST-APIs.md)."
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Getting values"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For instance, to retrieve the list of all motors name:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!curl http://127.0.0.1:8080/motor/list.json"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{\"motors\": [\"l_elbow_y\", \"r_elbow_y\", \"r_knee_y\", \"head_y\", \"head_z\", \"r_arm_z\", \"r_ankle_y\", \"r_shoulder_x\", \"r_shoulder_y\", \"r_hip_z\", \"r_hip_x\", \"r_hip_y\", \"l_arm_z\", \"l_hip_x\", \"l_hip_y\", \"l_hip_z\", \"abs_x\", \"abs_y\", \"abs_z\", \"l_ankle_y\", \"bust_y\", \"bust_x\", \"l_knee_y\", \"l_shoulder_x\", \"l_shoulder_y\"]}"
]
}
],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Or to access a specific register of a motor:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!curl http://127.0.0.1:8080/motor/head_z/register/present_position"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{\"present_position\": 0.2}"
]
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similarly, you can retrieve the list of sensors and their respective registers:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!curl http://127.0.0.1:8080/sensor/list.json"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{\"sensors\": [\"head_visual\"]}"
]
}
],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!curl http://127.0.0.1:8080/sensor/head_visual/register/list.json"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{\"registers\": [\"position\", \"orientation\"]}"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!curl http://127.0.0.1:8080/sensor/head_visual/register/position"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{\"position\": [-0.011824678629636765, -0.029312146827578545, 0.53340655565261841]}"
]
}
],
"prompt_number": 8
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Sending values"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The following requests should make the head of the robot moves."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!curl -X POST -d \"100\" http://127.0.0.1:8080/motor/head_z/register/goal_position/value.json \\\n",
" --header \"Content-Type:application/json\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{}"
]
}
],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!curl -X POST -d \"-100\" http://127.0.0.1:8080/motor/head_z/register/goal_position/value.json \\\n",
" --header \"Content-Type:application/json\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"{}"
]
}
],
"prompt_number": 10
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Using the [requests](http://docs.python-requests.org/en/latest/) module instead"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Similar behaviors can be achieved directly in Python, for instance using the [request](http://docs.python-requests.org/en/latest/) module."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import requests"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 11
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To retrieve a position:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"r = requests.get('http://127.0.0.1:8080/motor/head_z/register/present_position')\n",
"r.json()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 12,
"text": [
"{u'present_position': -100.3}"
]
}
],
"prompt_number": 12
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To set a new position:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import time\n",
"\n",
"pos = 50\n",
"\n",
"for _ in range(3):\n",
" requests.post('http://127.0.0.1:8080/motor/head_z/register/goal_position/value.json', \n",
" data=json.dumps(pos), \n",
" headers={'content-type': 'application/json'})\n",
" \n",
" pos *= -1\n",
" time.sleep(1.)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Just as a very basic benchmark:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%timeit\n",
"\n",
"r = requests.get('http://127.0.0.1:8080/motor/head_z/register/present_position')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"100 loops, best of 3: 3.37 ms per loop\n"
]
}
],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}