NOTE before starting
To change the notebook which is launched by default by the "programming with Jupyter" tab in puppet-master interface
jupyter()
function (around line 191)default_notebook
This notebook will guide you for connect another programmation language (not beginner tutorial)
What you will see in this notebook:
snap server
http server
Access to API
Get request
Post request
Add new entries in API
Add tab in puppet-master interface
The native language of Poppy robots is the python language. In python, all of the robot's functionalities are available.
Check notebooks «Discover your Poppy robot» and «Benchmark your Poppy robot» (in folder My Documents/ python notebook) for more information.
You can also read the documentation for even more information.
An application programming interface (API) is a computing interface which defines interactions between multiple software intermediaries.
Show Wikipedia for more informations.
What interests us here is how to use a language other than Python.
On the Poppy robot, you can access to the API via two server: one named "http", the other named "snap".
These two server allow you to control your robot through some url requests
Http server
You can access to this server via the 8080
port (value by default).
With this server, you can use the HTTP request of GET
and POST
method.
All valid urls are visible at the root url: http://poppy.local:8080/
Snap server
You can access to this server via the 6969
port (value by default).
With this server, you can use the HTTP request of only GET
method.
All valid urls are visible at the root url: http://poppy.local:6969/
Snap! (formerly BYOB) is a visual, drag-and-drop programming language. It is an extended reimplementation of Scratch (a project of the Lifelong Kindergarten Group at the MIT Media Lab) that allows you to Build Your Own Blocks.
Show Wikipedia and/ or Snap! website for more informations. What interests us here is how Snap! use the robot API to control it.
Snap! allows you to create blocks from initial blocks. These blocks correspond to functions. Among these, one of them allows you to send requests urls. On this basis, we have built a series of blocks to control the robot via the API. All these blocks have in common to end with the emission of the url request.
Here, in python, we will see how to use these urls. The methodology will be the same for another language. An example applied is that of poppy-monitor (primitive manager) and that of poppy-viewer (web viewer). Both are coded in JavaScript. Check the source code, respectively here: My Documents/ Poppy Source-code/ poppy-monitor and here: My Documents/ Poppy Source-code/ poppy-viewer
First
Launch an instance of the robot with http and/or snap server.
You can do this in two différente way:
By default, API auto-starting is enable (and there is no need to click on start API button), change this option in «settings» tab.
from pypot.creatures import PoppyErgoJr
poppy = PoppyErgoJr(use_http=True, use_snap=True)
# If you want to use another robot (humanoid, torso, ...) adapt this code
#from pypot.creatures import PoppyTorso
#poppy = PoppyTorso(use_http=True, use_snap=True)
# If you want to use the robot with the camera unpluged,
# you have to pass the argument camera='dummy
#poppy = PoppyErgoJr(camera='dummy', use_http=True, use_snap=True)
# If you want to use a simulated robot in the 3D web viewer aka "poppy simu"
# you have to pass the argument simulator='poppy-simu'
#poppy = PoppyErgoJr(simulator='poppy-simu', use_http=True, use_snap=True)
Second
Allow python to use url import request
and to show HTML content inline import HTML
import requests
from IPython.core.display import HTML
#Testing Snap API access
valid_url_for_snap_server=''
try:
response = requests.get('http://poppy.local:6969/')
if response.status_code==200:
valid_url_for_snap_server=response.text
except:
print('http://poppy.local:6969/ is unreachable')
HTML(valid_url_for_snap_server)
Each url execute an action on the robot (in the native langage) and return a value. All applications able to send a url request can use the snap API to interact with the robot (including your web browser). Be careful, the format of each url is different as well as the type of returned value. For exemple:
;
From there, we can create a function simplifying the emission of the url request. In Snap!, we would speak of blocks, and not of function, the idea is the same for another language.
def to_api(url, hostname='poppy.local', port='6969'):
url_root='http://{}:{}/'.format(hostname, port)
print('> call:',url_root+url)
try:
response = requests.get(url_root+url)
if response.status_code==200:
return response.text
else:
return 'ERROR'
except:
print('{} is unreachable'.format(url_root))
def get_ip():
return to_api('ip/')
def get_all_positions():
return [float(val) for val in to_api('motors/get/positions').split(';')]
print(get_ip())
print(get_all_positions())
> call: http://poppy.local:6969/ip/ 192.168.1.100 > call: http://poppy.local:6969/motors/get/positions [4.25, -39.15, 78.15, -17.74, 53.81, -4.84]
Some urls have variables. They are identified by the symbols <
and >
For exemple in url :
http://poppy.local:6969/motor/<alias>
\Replace <alias>
by the name of the motor group
def get_motors_alias():
return to_api('motors/alias').split('/')
def get_motors_name(alias='motors'):
return to_api('motors/'+alias).split('/')
print(get_motors_alias())
print(get_motors_name())
print('these motors: {}, are in group of motors named: {}.'.format(
get_motors_name(get_motors_alias()[0]),
get_motors_alias()[0])
)
> call: http://poppy.local:6969/motors/alias ['base', 'tip'] > call: http://poppy.local:6969/motors/motors ['m1', 'm2', 'm3', 'm4', 'm5', 'm6'] > call: http://poppy.local:6969/motors/alias > call: http://poppy.local:6969/motors/base > call: http://poppy.local:6969/motors/alias these motors: ['m1', 'm2', 'm3'], are in group of motors named: base.
http://poppy.local:6969/motor/<motor>/get/<register>
\Replace <motor>
by the name of the motor, and <register>
by name of register:
def get_register(motor_id, register):
url='motor/m{}/get/{}'.format(motor_id, register)
return to_api(url)
def get_register_list(motor_id=1):
out=get_register(motor_id, 'registers')
if 'ERROR' in out: return out
else: return eval(out) #type == list
def get_position(motor_id):
out=get_register(motor_id, 'present_position')
if 'ERROR' in out: return out
else: return float(out)
def get_compliant(motor_id):
out=get_register(motor_id, 'compliant')
if 'ERROR' in out: return out
else: return bool(out)
def get_color(motor_id):
return get_register(motor_id, 'led') #type == str
print('all avalible register are: {}'.format(', '.join(get_register_list())))
print('m1 is in position {}°'.format(get_register(1, 'present_position')))
print('m1 is in position {}°'.format(get_position(1)))
print('m1 compliant register is {}'.format(get_register(1, 'compliant')))
print('m1 compliant register is {}'.format(get_compliant(1)))
print('led of m1 is {}'.format(get_register(1, 'led')))
print('led of m1 is {}'.format(get_color(1)))
#print('motor sensitivity {}'.format([get_position(2)==get_position(2) for _ in range(10)]))
> call: http://poppy.local:6969/motor/m1/get/registers all avalible register are: registers, goal_speed, compliant, safe_compliant, angle_limit, id, name, model, present_position, goal_position, present_speed, moving_speed, present_load, torque_limit, lower_limit, upper_limit, present_voltage, present_temperature, pid, led, control_mode > call: http://poppy.local:6969/motor/m1/get/present_position m1 is in position 4.25° > call: http://poppy.local:6969/motor/m1/get/present_position m1 is in position 4.25° > call: http://poppy.local:6969/motor/m1/get/compliant m1 compliant register is True > call: http://poppy.local:6969/motor/m1/get/compliant m1 compliant register is True > call: http://poppy.local:6969/motor/m1/get/led led of m1 is off > call: http://poppy.local:6969/motor/m1/get/led led of m1 is off
Some urls have multiple input. They are identified by the letter s
For exemple in url, where motor variable have an s
:
http://poppy.local:6969/motors/<motors>/get/<register>
\Replace <motors>
by the name of one or multiple motors (split by ;
), and <register>
by name of register:
;
def get_registers(motors_id, register):
if type(motors_id)!=list: return 'Type ERROR'
targets=[]
for motor_id in motors_id:
targets.append('m'+str(motor_id))
url='motors/{}/get/{}'.format(';'.join(targets), register)
return to_api(url).split(';')
def get_positions(motors_id):
out=get_registers(motors_id, 'present_position')
if 'ERROR' in out: return out
else: return [float(val) for val in out]
def get_compliants(motors_id):
out=get_registers(motors_id, 'compliant')
if 'ERROR' in out: return out
else: return [bool(val) for val in out]
def get_colors(motors_id):
out=get_registers(motors_id, 'led')
if 'ERROR' in out: return out
else: return [str(val) for val in out]
print('m1 and m2 are respectively in position {}'.format(get_registers([1,2], 'present_position')))
print('m1 and m2 are respectively in position {}'.format(get_positions([1,2])))
print('m1 and m2 compliant register are respectively {}'.format(get_registers([1,2], 'compliant')))
print('m1 and m2 compliant register are respectively {}'.format(get_compliants([1,2])))
print('led of m1 and m2 are respectively {}'.format(get_registers([1,2], 'led')))
print('led of m1 and m2 are respectively {}'.format(get_colors([1,2])))
> call: http://poppy.local:6969/motors/m1;m2/get/present_position m1 and m2 are respectively in position ['4.25', '-39.15'] > call: http://poppy.local:6969/motors/m1;m2/get/present_position m1 and m2 are respectively in position [4.25, -39.15] > call: http://poppy.local:6969/motors/m1;m2/get/compliant m1 and m2 compliant register are respectively ['True', 'True'] > call: http://poppy.local:6969/motors/m1;m2/get/compliant m1 and m2 compliant register are respectively [True, True] > call: http://poppy.local:6969/motors/m1;m2/get/led led of m1 and m2 are respectively ['off', 'off'] > call: http://poppy.local:6969/motors/m1;m2/get/led led of m1 and m2 are respectively ['off', 'off']
For these previous urls, the Snap API only returns the requested value(s). The following urls performs an action on the robot and return always 'Done!':
http://poppy.local:6969/motor/<motor>/set/<register>/<value>
def set_register(motor_id, register, value):
url='motor/m{}/set/{}/{} '.format(motor_id, register, value)
return to_api(url)
def set_position(motor_id, position):
return set_register(motor_id, 'goal_position', position)
def set_compliant(motor_id, state):
return set_register(motor_id, 'compliant', state)
def set_color(motor_id, color):
return set_register(motor_id, 'led', color)
#note: the motor must be in the non-compliant state to be control it in position
print('set m1 compliant state to false: {}'.format(set_compliant(1,0)))
print('set m1 position to 15°: {}'.format(set_position(1,15)))
print('set m1 compliant state to true: {}'.format(set_compliant(1,1)))
> call: http://poppy.local:6969/motor/m1/set/compliant/0 set m1 compliant state to false: Done! > call: http://poppy.local:6969/motor/m1/set/goal_position/15 set m1 position to 15°: Done! > call: http://poppy.local:6969/motor/m1/set/compliant/1 set m1 compliant state to true: Done!
http://poppy.local:6969/motors/set/registers/<motors_register_value>
\Replace <motors_register_value>
by the name of motors, name of register, value to give to the register (split by :
like this: m1:led:pink
) then iterate for each moteurs (split by ;
like this: m1:led:pink;m2:led:pink
)
motor m1 started from where it was and arrived in position 15° ; motor m1 lit green ; motor m6 lit yellow
def valid_registers_input(motors_id, registers, values):
if type(motors_id)!=list or type(registers)!=list or type(values)!=list:
return 'Type ERROR'
if len(motors_id) != len(registers) or len(motors_id) != len(values):
return 'Size ERROR'
return motors_id, registers, values
def set_registers(motors_id, registers, values):
registers_input = valid_registers_input(motors_id, registers, values)
if 'ERROR' in registers_input:
return registers_input
else:
motors_id, registers, values = registers_input
cmd=[]
for i, motor_id in enumerate(motors_id):
cmd.append('m{}:{}:{}'.format(motor_id, registers[i], values[i]))
cmd=';'.join(cmd)
url='motors/set/registers/'+cmd
return to_api(url)
def set_positions(motors_id, positions):
return set_registers(motors_id, ['goal_position']*len(motors_id), positions)
def set_compliants(motors_id, states):
return set_registers(motors_id, ['compliant']*len(motors_id), states)
def set_colors(motors_id, colors):
return set_registers(motors_id, ['led']*len(motors_id), colors)
print(set_compliants([1,2],[1,1]))
print(set_registers([1,1,2,3],['led', 'goal_position', 'goal_position', 'led'],['yellow', 45, 25, 'blue']))
print(set_positions([1],[0]))
print(set_compliants([1,2],[0,0]))
print(set_colors([1,2,3],['green']*3))
> call: http://poppy.local:6969/motors/set/registers/m1:compliant:1;m2:compliant:1 Done! > call: http://poppy.local:6969/motors/set/registers/m1:led:yellow;m1:goal_position:45;m2:goal_position:25;m3:led:blue Done! > call: http://poppy.local:6969/motors/set/registers/m1:goal_position:0 Done! > call: http://poppy.local:6969/motors/set/registers/m1:compliant:0;m2:compliant:0 Done! > call: http://poppy.local:6969/motors/set/registers/m1:led:green;m2:led:green;m3:led:green Done!
'''
prepare input for set_register function:
accept:
python list of values,
str list of values (split by space),
int, float, bool
return: python list of str values
'''
def set_type(value):
if type(value)==str:
value=value.split(' ')
elif type(value) in (float, int, bool):
value=[str(value)]
elif type(value)!=list:
return 'Type ERROR'
else:
for i, v in enumerate(value): value[i]=str(v)
return value
'''
re-write valid_registers_input function
valid_registers_input is use by set_registers function
add set_type function
add check size, accept one value for default for each motor
return couple of tree values, each is a list of str values
'''
number_of_all_motors=len(get_motors_name())
all_valid_register=get_register_list()
def valid_registers_input(motors_id, registers, values):
motors_id, registers, values = set_type(motors_id), set_type(registers), set_type(values)
if 'ERROR' in (motors_id or registers or values):
return 'Type ERROR'
if len(registers) == 1:
registers=registers*len(motors_id)
elif len(motors_id) != len(registers):
return 'Size ERROR'
if len(values) == 1:
values=values*len(motors_id)
elif len(motors_id) != len(values):
return 'Size ERROR'
number_of_motors=number_of_all_motors
valid_register=all_valid_register
#assume that value of values variable are check before
for i, motor_id in enumerate(motors_id):
if int(motor_id) <1 or int(motor_id) > number_of_motors or registers[i] not in valid_register:
return 'Value ERROR'
return motors_id, registers, values
'''
No need to re-write set_registers function
but get_registers function need to:
add set_type function to avoid error
add check values
'''
def get_registers(motors_id, register):
motors_id=set_type(motors_id)
if 'ERROR' in motors_id: return motors_id
valid_register=all_valid_register
if register not in valid_register: return 'Value ERROR'
number_of_motors=number_of_all_motors
targets=[]
for i, motor_id in enumerate(motors_id):
if int(motor_id) <1 or int(motor_id) > number_of_motors:
return 'Value ERROR'
else:
targets.append('m'+motor_id)
url='motors/{}/get/{}'.format(';'.join(targets), register)
return to_api(url).split(';')
> call: http://poppy.local:6969/motors/motors > call: http://poppy.local:6969/motor/m1/get/registers
'''
re-write function
add check value
'''
def set_positions(motors_id, positions):
positions=set_type(positions)
if 'ERROR' in positions: return positions
for position in positions:
if float(position) < -90 or float(position) > 90:
return 'Value ERROR'
return set_registers(motors_id, 'goal_position', positions)
def set_compliants(motors_id, states):
states=set_type(states)
if 'ERROR' in states: return states
for state in states:
if state == 'True': state='1'
elif state == 'False': state='0'
elif state not in ('0', '1'): return 'Value ERROR'
return set_registers(motors_id, 'compliant', states)
def set_colors(motors_id, colors):
colors=set_type(colors)
if 'ERROR' in colors: return colors
for color in colors:
if color not in ['red','green','pink','blue','yellow','off']:
return 'Value ERROR'
return set_registers(motors_id, 'led', colors)
#before syntaxe, work always + check values
print(set_compliants([1,2],[0,0]))
print(set_registers([1,1,2,3],['led', 'goal_position', 'goal_position', 'led'],['yellow', 45, 25, 'blue']))
print(set_positions([1],[0]))
print(set_compliants([1,2],[1,1]))
print(set_colors([1,2,3],['green']*3))
# + more flxible syntaxe
print(set_compliants('1 2',0))
print(set_registers('1 1 2 3','led goal_position goal_position led','yellow 45 25 blue'))
print(set_positions(1,0))
print(set_compliants([1,2],1))
print(set_colors('1 2 3','green'))
> call: http://poppy.local:6969/motors/set/registers/m1:compliant:0;m2:compliant:0 Done! > call: http://poppy.local:6969/motors/set/registers/m1:led:yellow;m1:goal_position:45;m2:goal_position:25;m3:led:blue Done! > call: http://poppy.local:6969/motors/set/registers/m1:goal_position:0 Done! > call: http://poppy.local:6969/motors/set/registers/m1:compliant:1;m2:compliant:1 Done! > call: http://poppy.local:6969/motors/set/registers/m1:led:green;m2:led:green;m3:led:green Done! > call: http://poppy.local:6969/motors/set/registers/m1:compliant:0;m2:compliant:0 Done! > call: http://poppy.local:6969/motors/set/registers/m1:led:yellow;m1:goal_position:45;m2:goal_position:25;m3:led:blue Done! > call: http://poppy.local:6969/motors/set/registers/m1:goal_position:0 Done! > call: http://poppy.local:6969/motors/set/registers/m1:compliant:1;m2:compliant:1 Done! > call: http://poppy.local:6969/motors/set/registers/m1:led:green;m2:led:green;m3:led:green Done!
#use your function
import time
for i in range(1,7):
print(set_colors(i,'pink'))
print(get_colors(i))
time.sleep(0.5)
print(set_colors(i,'off'))
print(get_colors(i))
#time.sleep(0.5)
for _ in range(2):
for c in ['red','green','pink','blue','yellow']:
print(set_colors('1 2 3 4 5 6', c))
print(get_colors('1 2 3 4 5 6'))
time.sleep(0.5)
print(set_colors('1 2 3 4 5 6','off'))
print(get_colors('1 2 3 4 5 6'))
time.sleep(0.5)
> call: http://poppy.local:6969/motors/set/registers/m1:led:pink Done! > call: http://poppy.local:6969/motors/m1/get/led ['pink'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off Done! > call: http://poppy.local:6969/motors/m1/get/led ['off'] > call: http://poppy.local:6969/motors/set/registers/m2:led:pink Done! > call: http://poppy.local:6969/motors/m2/get/led ['pink'] > call: http://poppy.local:6969/motors/set/registers/m2:led:off Done! > call: http://poppy.local:6969/motors/m2/get/led ['off'] > call: http://poppy.local:6969/motors/set/registers/m3:led:pink Done! > call: http://poppy.local:6969/motors/m3/get/led ['pink'] > call: http://poppy.local:6969/motors/set/registers/m3:led:off Done! > call: http://poppy.local:6969/motors/m3/get/led ['off'] > call: http://poppy.local:6969/motors/set/registers/m4:led:pink Done! > call: http://poppy.local:6969/motors/m4/get/led ['pink'] > call: http://poppy.local:6969/motors/set/registers/m4:led:off Done! > call: http://poppy.local:6969/motors/m4/get/led ['off'] > call: http://poppy.local:6969/motors/set/registers/m5:led:pink Done! > call: http://poppy.local:6969/motors/m5/get/led ['pink'] > call: http://poppy.local:6969/motors/set/registers/m5:led:off Done! > call: http://poppy.local:6969/motors/m5/get/led ['off'] > call: http://poppy.local:6969/motors/set/registers/m6:led:pink Done! > call: http://poppy.local:6969/motors/m6/get/led ['pink'] > call: http://poppy.local:6969/motors/set/registers/m6:led:off Done! > call: http://poppy.local:6969/motors/m6/get/led ['off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:red;m2:led:red;m3:led:red;m4:led:red;m5:led:red;m6:led:red Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['red', 'red', 'red', 'red', 'red', 'red'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:green;m2:led:green;m3:led:green;m4:led:green;m5:led:green;m6:led:green Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['green', 'green', 'green', 'green', 'green', 'green'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:pink;m2:led:pink;m3:led:pink;m4:led:pink;m5:led:pink;m6:led:pink Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['pink', 'pink', 'pink', 'pink', 'pink', 'pink'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:blue;m2:led:blue;m3:led:blue;m4:led:blue;m5:led:blue;m6:led:blue Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['blue', 'blue', 'blue', 'blue', 'blue', 'blue'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:yellow;m2:led:yellow;m3:led:yellow;m4:led:yellow;m5:led:yellow;m6:led:yellow Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['yellow', 'yellow', 'yellow', 'yellow', 'yellow', 'yellow'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:red;m2:led:red;m3:led:red;m4:led:red;m5:led:red;m6:led:red Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['red', 'red', 'red', 'red', 'red', 'red'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:green;m2:led:green;m3:led:green;m4:led:green;m5:led:green;m6:led:green Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['green', 'green', 'green', 'green', 'green', 'green'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:pink;m2:led:pink;m3:led:pink;m4:led:pink;m5:led:pink;m6:led:pink Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['pink', 'pink', 'pink', 'pink', 'pink', 'pink'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:blue;m2:led:blue;m3:led:blue;m4:led:blue;m5:led:blue;m6:led:blue Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['blue', 'blue', 'blue', 'blue', 'blue', 'blue'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off'] > call: http://poppy.local:6969/motors/set/registers/m1:led:yellow;m2:led:yellow;m3:led:yellow;m4:led:yellow;m5:led:yellow;m6:led:yellow Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['yellow', 'yellow', 'yellow', 'yellow', 'yellow', 'yellow'] > call: http://poppy.local:6969/motors/set/registers/m1:led:off;m2:led:off;m3:led:off;m4:led:off;m5:led:off;m6:led:off Done! > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/led ['off', 'off', 'off', 'off', 'off', 'off']
set_compliants('1 2 3 4 5 6', 0)
set_positions('1 2 3 4 5 6', '0 10 -15 10 0 0')
time.sleep(1.5)
print('motors in position: ', get_positions([1, 2, 3, 4, 5, 6]))
set_positions('1 2 3 4 5 6', -10)
time.sleep(.5)
print('motors in position: ', get_positions('1 2 3 4 5 6'))
set_compliants('1 2 3 4 5 6', 1)
time.sleep(.5)
for i in range(1,7): print('m{} in position {}°'.format(i, get_positions(i)))
> call: http://poppy.local:6969/motors/set/registers/m1:compliant:0;m2:compliant:0;m3:compliant:0;m4:compliant:0;m5:compliant:0;m6:compliant:0 > call: http://poppy.local:6969/motors/set/registers/m1:goal_position:0;m2:goal_position:10;m3:goal_position:-15;m4:goal_position:10;m5:goal_position:0;m6:goal_position:0 > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/present_position motors in position: [0.73, 41.5, 30.06, -13.05, 55.57, -4.84] > call: http://poppy.local:6969/motors/set/registers/m1:goal_position:-10;m2:goal_position:-10;m3:goal_position:-10;m4:goal_position:-10;m5:goal_position:-10;m6:goal_position:-10 > call: http://poppy.local:6969/motors/m1;m2;m3;m4;m5;m6/get/present_position motors in position: [0.73, 41.5, 30.06, -13.05, 55.57, -4.84] > call: http://poppy.local:6969/motors/set/registers/m1:compliant:1;m2:compliant:1;m3:compliant:1;m4:compliant:1;m5:compliant:1;m6:compliant:1 > call: http://poppy.local:6969/motors/m1/get/present_position m1 in position [-10.7]° > call: http://poppy.local:6969/motors/m2/get/present_position m2 in position [-11.88]° > call: http://poppy.local:6969/motors/m3/get/present_position m3 in position [-10.7]° > call: http://poppy.local:6969/motors/m4/get/present_position m4 in position [-10.7]° > call: http://poppy.local:6969/motors/m5/get/present_position m5 in position [-8.36]° > call: http://poppy.local:6969/motors/m6/get/present_position m6 in position [-5.43]°
Another URL
http://poppy.local:6969/motors/set/goto/<motors_position_duration>
motor m1 started from where it was and arrived in position 0° in 1 seconde ;
motor m2 started from where it was and arrived in position 15° in 2 secondes ;
motor m6 started from where it was and arrived in position 45° in 1.5 secondes
number_of_all_motors=len(get_motors_name())
def valid_goto_input(motors_id, positions, durations):
motors_id, positions, durations = set_type(motors_id), set_type(positions), set_type(durations)
if 'ERROR' in (motors_id or positions or durations):
return 'Type ERROR'
if len(positions) == 1:
positions=positions*len(motors_id)
elif len(motors_id) != len(positions):
return 'Size ERROR'
if len(durations) == 1:
durations=durations*len(motors_id)
elif len(durations) != len(durations):
return 'Size ERROR'
number_of_motors=number_of_all_motors
for i, motor_id in enumerate(motors_id):
if int(motor_id) <1 or int(motor_id) > number_of_motors:
return 'Value ERROR'
if float(positions[i]) < -90 or float(positions[i]) > 90:
return 'Value ERROR'
if float(durations[i]) < 0:
return 'Value ERROR'
return motors_id, positions, durations
def set_goto(motors_id, positions, durations):
goto_input = valid_goto_input(motors_id, positions, durations)
if 'ERROR' in goto_input:
return goto_input
else:
motors_id, positions, durations = goto_input
cmd=[]
for i, motor_id in enumerate(motors_id):
cmd.append('m{}:{}:{}'.format(motor_id, positions[i], durations[i]))
cmd=';'.join(cmd)
url='motors/set/goto/'+cmd
return to_api(url)
print(set_compliants('1 2 3 4 5 6', False))
print(set_goto('1 2 3 4 5 6', 10, 1))
time.sleep(1.5)
print(set_goto('1 2 3 4 5 6', -10, 2))
time.sleep(2.5)
print(set_compliants('1 2 3 4 5 6', True))
> call: http://poppy.local:6969/motors/motors > call: http://poppy.local:6969/motors/set/registers/m1:compliant:False;m2:compliant:False;m3:compliant:False;m4:compliant:False;m5:compliant:False;m6:compliant:False Done! > call: http://poppy.local:6969/motors/set/goto/m1:10:1;m2:10:1;m3:10:1;m4:10:1;m5:10:1;m6:10:1 Done! > call: http://poppy.local:6969/motors/set/goto/m1:-10:2;m2:-10:2;m3:-10:2;m4:-10:2;m5:-10:2;m6:-10:2 Done! > call: http://poppy.local:6969/motors/set/registers/m1:compliant:True;m2:compliant:True;m3:compliant:True;m4:compliant:True;m5:compliant:True;m6:compliant:True Done!
to_api(url)
get_ip()
get_all_positions()
get_motors_alias()
get_motors_name()
get_register(motor_id, register)
get_register_list()
get_position(motor_id)
get_compliant(motor_id)
get_color(motor_id)
get_registers(motors_id, register)
get_positions(motors_id)
get_compliants(motors_id)
get_colors(motors_id)
set_register(motor_id, register, value)
set_position(motor_id, value)
set_compliant(motor_id, value)
set_color(motor_id, value)
set_type(value)
valid_registers_input(motors_id, registers, values)
set_registers(motors_id, registers, values)
set_positions(motors_id values)
set_compliants(motors_id, values)
set_colors(motors_id, values)
valid_goto_input(motors_id, positions, durations)
set_goto(motors_id, positions, durations)
def get_api(url, hostname='poppy.local', port='8080'):
url_root='http://{}:{}/'.format(hostname, port)
print('> get:',url_root+url)
try:
response = requests.get(url_root+url)
if response.status_code==200:
return response
else:
return 'ERROR {}!'.format(response.status_code)
except:
print('{} is unreachable'.format(url_root))
def post_api(url, value, hostname='poppy.local', port='8080'):
url_root='http://{}:{}/'.format(hostname, port)
print('> post: url=', url_root+url, ' ; value=', value)
try:
response = requests.post(url_root+url, json=value)
if response.status_code==200:
return 'Done!'
else:
return 'ERROR {}!'.format(response.status_code)
except:
print('{} is unreachable'.format(url_root))
HTML(get_api('').text)
> get: http://poppy.local:8080/
def get_motor_list(alias='motors'):
url='motor/{}/list.json'.format(alias)
return get_api(url).json()
def get_motor_register_list(motor_id=1):
url = 'motor/m{}/register/list.json'.format(motor_id)
return get_api(url).json()
def get_motor_register_value(motor_id, register):
url = 'motor/m{}/register/{}'.format(motor_id, register)
return get_api(url).json()[register]
print(get_motor_list())
print(get_motor_register_list())
print(get_motor_register_value(1, 'name'))
print(get_motor_register_value(1, 'present_position'))
print(get_motor_register_value(1, 'compliant'))
print(get_motor_register_value(1, 'angle_limit'))
print(get_motor_register_value(1, 'led'))
> get: http://poppy.local:8080/motor/motors/list.json {'motors': ['m1', 'm2', 'm3', 'm4', 'm5', 'm6']} > get: http://poppy.local:8080/motor/m1/register/list.json {'registers': ['registers', 'goal_speed', 'compliant', 'safe_compliant', 'angle_limit', 'id', 'name', 'model', 'present_position', 'goal_position', 'present_speed', 'moving_speed', 'present_load', 'torque_limit', 'lower_limit', 'upper_limit', 'present_voltage', 'present_temperature', 'pid', 'led', 'control_mode']} > get: http://poppy.local:8080/motor/m1/register/name m1 > get: http://poppy.local:8080/motor/m1/register/present_position -10.7 > get: http://poppy.local:8080/motor/m1/register/compliant True > get: http://poppy.local:8080/motor/m1/register/angle_limit [-150.0, 150.0] > get: http://poppy.local:8080/motor/m1/register/led off
def get_sensor_list():
return get_api('sensor/list.json').json()
def get_sensor_register_list(sensor):
url = 'sensor/{}/register/list.json'.format(sensor)
return get_api(url).json()
def get_sensor_register_value(sensor, register):
url = 'sensor/{}/register/{}'.format(sensor, register)
return get_api(url).json()[register]
print(get_sensor_list())
print(get_sensor_register_list('camera'))
print(get_sensor_register_value('camera', 'fps'))
print(get_sensor_register_value('camera', 'resolution'))
print(get_sensor_register_value('camera', 'frame'))
> get: http://poppy.local:8080/sensor/list.json {'sensors': ['camera', 'marker_detector']} > get: http://poppy.local:8080/sensor/camera/register/list.json {'registers': ['frame', 'resolution', 'fps', 'index']} > get: http://poppy.local:8080/sensor/camera/register/fps 20.0 > get: http://poppy.local:8080/sensor/camera/register/resolution [640, 480] > get: http://poppy.local:8080/sensor/camera/register/frame
IOPub data rate exceeded. The notebook server will temporarily stop sending output to the client in order to avoid crashing it. To change this limit, set the config variable `--NotebookApp.iopub_data_rate_limit`. Current values: NotebookApp.iopub_data_rate_limit=1000000.0 (bytes/sec) NotebookApp.rate_limit_window=3.0 (secs)
def get_primitive_list():
return get_api('primitive/list.json').json()
def get_primitive_property(primitive_name):
url='primitive/{}/property/list.json'.format(primitive_name)
return get_api(url).json()
def get_primitive_method(primitive_name):
url='primitive/{}/method/list.json'.format(primitive_name)
return get_api(url).json()
print(get_primitive_list())
print(get_primitive_property(get_primitive_list()['primitives'][0]))
print(get_primitive_method(get_primitive_list()['primitives'][0]))
> get: http://poppy.local:8080/primitive/list.json {'primitives': ['safe_power_up', 'dance', 'base_posture', 'rest_posture', 'curious_posture', 'tetris_posture', 'tracking_feedback']} > get: http://poppy.local:8080/primitive/list.json > get: http://poppy.local:8080/primitive/safe_power_up/property/list.json {'property': []} > get: http://poppy.local:8080/primitive/list.json > get: http://poppy.local:8080/primitive/safe_power_up/method/list.json {'methods': ['start', 'stop', 'pause', 'resume']}
def post_motor_value(motor, register, value):
url = 'motor/m{}/register/{}/value.json'.format(motor, register)
return post_api(url, value)
import time
print(post_motor_value(1, 'compliant', False))
print(get_motor_register_value(1, 'compliant'))
print(post_motor_value(1, 'goal_speed', 25))
print(post_motor_value(1, 'goal_position', 25))
for _ in range(10):
print(get_motor_register_value(1, 'present_position'))
time.sleep(0.1)
print(post_motor_value(1, 'goal_position', 0))
for _ in range(10):
print(get_motor_register_value(1, 'present_position'))
time.sleep(0.1)
print(post_motor_value(1, 'comlpiant', True))
> post: url= http://poppy.local:8080/motor/m1/register/compliant/value.json ; value= False Done! > get: http://poppy.local:8080/motor/m1/register/compliant False > post: url= http://poppy.local:8080/motor/m1/register/goal_speed/value.json ; value= 25 Done! > post: url= http://poppy.local:8080/motor/m1/register/goal_position/value.json ; value= 25 Done! > get: http://poppy.local:8080/motor/m1/register/present_position -10.7 > get: http://poppy.local:8080/motor/m1/register/present_position -6.6 > get: http://poppy.local:8080/motor/m1/register/present_position -2.79 > get: http://poppy.local:8080/motor/m1/register/present_position 1.32 > get: http://poppy.local:8080/motor/m1/register/present_position 5.13 > get: http://poppy.local:8080/motor/m1/register/present_position 8.94 > get: http://poppy.local:8080/motor/m1/register/present_position 13.05 > get: http://poppy.local:8080/motor/m1/register/present_position 16.57 > get: http://poppy.local:8080/motor/m1/register/present_position 21.26 > get: http://poppy.local:8080/motor/m1/register/present_position 25.07 > post: url= http://poppy.local:8080/motor/m1/register/goal_position/value.json ; value= 0 Done! > get: http://poppy.local:8080/motor/m1/register/present_position 25.37 > get: http://poppy.local:8080/motor/m1/register/present_position 21.85 > get: http://poppy.local:8080/motor/m1/register/present_position 18.04 > get: http://poppy.local:8080/motor/m1/register/present_position 13.64 > get: http://poppy.local:8080/motor/m1/register/present_position 9.82 > get: http://poppy.local:8080/motor/m1/register/present_position 5.13 > get: http://poppy.local:8080/motor/m1/register/present_position 0.15 > get: http://poppy.local:8080/motor/m1/register/present_position -0.15 > get: http://poppy.local:8080/motor/m1/register/present_position -0.15 > get: http://poppy.local:8080/motor/m1/register/present_position -0.15 > post: url= http://poppy.local:8080/motor/m1/register/comlpiant/value.json ; value= True Done!
def post_sensor_value(sensor, register, value):
url = 'sensor/{}/register/{}/value.json'.format(sensor, register)
return post_api(url, value)
print(get_sensor_list())
print(get_sensor_register_list('camera'))
print(get_sensor_register_value('camera', 'fps'))
print(post_sensor_value('caemra', 'fps', 15.0))
print(get_sensor_register_value('camera', 'fps'))
> get: http://poppy.local:8080/sensor/list.json {'sensors': ['camera', 'marker_detector']} > get: http://poppy.local:8080/sensor/camera/register/list.json {'registers': ['frame', 'resolution', 'fps', 'index']} > get: http://poppy.local:8080/sensor/camera/register/fps 20.0 > post: url= http://poppy.local:8080/sensor/caemra/register/fps/value.json ; value= 15.0 ERROR 500! > get: http://poppy.local:8080/sensor/camera/register/fps 20.0
def post_primitive_property(primitive, prop, value):
url = 'primitive/{}/property/{}/value.json'.format(primitive, prop)
return post_api(url, value)
def post_primitive_method(primitive, meth, value):
url = 'primitive/{}/method/{}/args.json'.format(primitive, meth)
return post_api(url, value)
print(get_primitive_list())
print(get_primitive_property('rest_posture'))
print(get_primitive_method('rest_posture'))
print(post_primitive_method('rest_posture', 'start', 'start'))
time.sleep(2)
print(post_primitive_method('rest_posture', 'stop', 'stop'))
> get: http://poppy.local:8080/primitive/list.json {'primitives': ['safe_power_up', 'dance', 'base_posture', 'rest_posture', 'curious_posture', 'tetris_posture', 'tracking_feedback']} > get: http://poppy.local:8080/primitive/rest_posture/property/list.json {'property': []} > get: http://poppy.local:8080/primitive/rest_posture/method/list.json {'methods': ['start', 'stop', 'pause', 'resume']} > post: url= http://poppy.local:8080/primitive/rest_posture/method/start/args.json ; value= start ERROR 500! > post: url= http://poppy.local:8080/primitive/rest_posture/method/stop/args.json ; value= stop ERROR 500!
def set_primitive_action(primitive, action):
if action not in ['start','stop','pause','resume']:
return 'Value ERROR'
url = 'primitive/{}/{}.json'.format(primitive, action)
if get_api(url).status_code==200:
return '{} of {} Done!'.format(action, primitive)
else:
return '{} of {} Fail! Error {}'.format(action, primitive, get_api(url).status_code)
print(get_primitive_list())
print(set_primitive_action('rest_posture', 'start'))
time.sleep(2)
print(set_primitive_action('rest_posture', 'stop'))
> get: http://poppy.local:8080/primitive/list.json {'primitives': ['safe_power_up', 'dance', 'base_posture', 'rest_posture', 'curious_posture', 'tetris_posture', 'tracking_feedback']} > get: http://poppy.local:8080/primitive/rest_posture/start.json start of rest_posture Done! > get: http://poppy.local:8080/primitive/rest_posture/stop.json stop of rest_posture Done!
Add an specific url, in the good file, with the good syntaxe, and do everything python can be do. Both server have access to the RESTRobot class to munipulate the robot. If you need, add an entries here as well My Documents/ Poppy Source-code/ pypotserver/ rest.py
Snap server are define here: My Documents/ Poppy Source-code/ pypotserver/ snap.py
Standard entry is written like this:
#~/pypot/server/snap.py
class SnapRobotServer(AbstractServer):
def __init__(self, robot, host='0.0.0.0', port='6969', quiet=True):
...
@self.app.get('/specific/url/with/<var_1>/and/<var_2>')
def what_will_be_done(var_1, var_2):
rr.what_the_robot_do(var_1)
return 'what you want'
#wherre rr is the restfuul_robot intitiate by RESTRobot class
#An exemple, ligne 202:
@self.app.get('/motors/<motors>/get/<register>')
def get_motors_registers(motors, register):
motors = motors.split(';')
return ';'.join(str(rr.get_register_value(m, register)) for m in motors)
Http server are define here: My Documents/ Poppy Source-code/ pypotserver/ httpserver.py
Standard entry is written like this:
#add specific url in url_path ligne 234 and write associate function
(r'/specific/url/with/(?P<var_1>[a-zA-Z0-9_]+)/and/(?P<var_2>[a-zA-Z0-9_]+)/value\.json', what_will_be_done_1),
class what_will_be_done_when_post_here(PoppyRequestHandler):
def post(self, var_1, var_2):
data = json.loads(self.request.body.decode())
self.restful_robot.what_the_robot_do(var_1, var_2, data)
self.write_json({})
(r'/primitive/list\.json', what_will_be_done_2),
class what_will_be_done_when_get_here(PoppyRequestHandler):
def get(self):
self.write_json({
'key': self.restful_robot.value()
})
#where self.restful_robot is the restfull_robot intitiate by RESTRobot class
#An exemple, ligne 86, get methode:
(r'/motor/(?P<alias>[a-zA-Z0-9_]+)/?list\.json', MotorsListHandler)
class MotorsListHandler(PoppyRequestHandler):
def get(self, alias='motors'):
self.write_json({
alias: self.restful_robot.get_motors_list(alias)
})
#An exemple, ligne 121, post methode:
(r'/motor/(?P<motor_name>[a-zA-Z0-9_]+)/register/(?P<register_name>[a-zA-Z0-9_]+)/value\.json', UpdateMotorRegisterHandler)
class UpdateMotorRegisterHandler(PoppyRequestHandler):
def post(self, motor_name, register_name):
data = json.loads(self.request.body.decode())
self.restful_robot.set_motor_register_value(motor_name, register_name, data)
self.write_json({})
In My Documents/ Poppy Source-code/ puppet-master/ templates/ programming.html add a tab:
Standard entry is written like this:
<div class="large-4 medium-6 columns menu-tile">
<a href="your_specific_url" data-equalizer-watch>
<h3>
<svg class="pp-icon pp-icon-name">
<title>Your Langage</title>
<use xlink:href="#pp-icon-name"></use>
</svg>
</h3>
<p>Your Langage</p>
</a>
</div>
where svg icon are define in My Documents/ Poppy Source-code/ puppet-master/ templates/ defs-svg.html
You can also add a simple png file in folder: My Documents/ Poppy Source-code/ puppet-master/ static/ img and use this Standard entry:
<div class="large-4 medium-6 columns menu-tile">
<a href=""your_specific_url" data-equalizer-watch>
<h3>
<img width="63" height="62" src="{{ url_for('static', filename='img/My-logo.png') }}">
</h3>
<p>Your Langage</p>
</a>
</div>