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. More precisely, we will show how we can retrieve motor position and set new ones.
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.
The client side of the example - meaning the HTTP requests - will be realised using curl.
Note: For this tutorial you will need:
First, we will instantiate a robot using V-REP (see this post for details on how this can be done).
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).
import os
import json
import pypot
import poppytools
from pypot.vrep import from_vrep
# Load the robot configuration
configfile = os.path.join(os.path.dirname(poppytools.__file__),
'configuration', 'poppy_config.json')
with open(configfile) as f:
robot_config = json.load(f)
# Load a V-REP scene with poppy sitting
scene = os.path.join(os.path.dirname(pypot.__file__),
'..', 'samples', 'notebooks', 'poppy-sitting.ttt')
# Connect to the simulated robot
robot = from_vrep(robot_config, '127.0.0.1', 19997, scene,
tracked_objects=['head_visual'])
We will now starts the HTTP server providing the remote access of our robot.
It will run on http://127.0.0.1:8080/
from pypot.server.httpserver import HTTPRobotServer
server = HTTPRobotServer(robot, host='127.0.0.1', port=8080)
By default, the bottle server is launch using tornado - for effiency puposes. Yet, as IPython notebook also uses the tornado server, it seems to cause trouble. Here, we use the wsgiref server instead.
from threading import Thread
Thread(target=lambda: server.run(quiet=True, server='wsgiref')).start()
As the run method of the server is blocking we launch it inside a thread. Thus, we can use the same notebook to send requests.
Now that the server is launched, you should be able to directly access the robot using the REST API.
For instance, to retrieve the list of all motors name:
!curl http://127.0.0.1:8080/motor/list.json
{"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"]}
Or to access a specific register of a motor:
!curl http://127.0.0.1:8080/motor/head_z/register/present_position
{"present_position": 0.2}
Similarly, you can retrieve the list of sensors and their respective registers:
!curl http://127.0.0.1:8080/sensor/list.json
{"sensors": ["head_visual"]}
!curl http://127.0.0.1:8080/sensor/head_visual/register/list.json
{"registers": ["position", "orientation"]}
!curl http://127.0.0.1:8080/sensor/head_visual/register/position
{"position": [-0.011824678629636765, -0.029312146827578545, 0.53340655565261841]}
The following requests should make the head of the robot moves.
!curl -X POST -d "100" http://127.0.0.1:8080/motor/head_z/register/goal_position/value.json \
--header "Content-Type:application/json"
{}
!curl -X POST -d "-100" http://127.0.0.1:8080/motor/head_z/register/goal_position/value.json \
--header "Content-Type:application/json"
{}
Similar behaviors can be achieved directly in Python, for instance using the request module.
import requests
To retrieve a position:
r = requests.get('http://127.0.0.1:8080/motor/head_z/register/present_position')
r.json()
{u'present_position': -100.3}
To set a new position:
import time
pos = 50
for _ in range(3):
requests.post('http://127.0.0.1:8080/motor/head_z/register/goal_position/value.json',
data=json.dumps(pos),
headers={'content-type': 'application/json'})
pos *= -1
time.sleep(1.)
Just as a very basic benchmark:
%%timeit
r = requests.get('http://127.0.0.1:8080/motor/head_z/register/present_position')
100 loops, best of 3: 3.37 ms per loop