Diferencia entre revisiones de «Actividad TeleButia»
(→Experiencias y pruebas) |
(→Experiencias y pruebas) |
||
Línea 64: | Línea 64: | ||
def get_bus(self): | def get_bus(self): | ||
# Genera un bus por el cual se obtienen las IPs de las Xos de la Red AdHoc | # Genera un bus por el cual se obtienen las IPs de las Xos de la Red AdHoc | ||
− | |||
if os.path.exists(OLPC_SESSION_BUS): | if os.path.exists(OLPC_SESSION_BUS): | ||
− | |||
address = "unix:path=%s" % OLPC_SESSION_BUS | address = "unix:path=%s" % OLPC_SESSION_BUS | ||
return dbus.bus.BusConnection(address_or_type=address) | return dbus.bus.BusConnection(address_or_type=address) | ||
Línea 82: | Línea 80: | ||
buddies = map(lambda b: bus.get_object(PRESENCE_SERVICE, b), ps_iface.GetBuddies()) | buddies = map(lambda b: bus.get_object(PRESENCE_SERVICE, b), ps_iface.GetBuddies()) | ||
− | |||
xos = [] | xos = [] | ||
for buddy in buddies: | for buddy in buddies: | ||
− | |||
buddy_iface = dbus.Interface(buddy, BUDDY_IFACE) | buddy_iface = dbus.Interface(buddy, BUDDY_IFACE) | ||
try: | try: | ||
Línea 91: | Línea 87: | ||
ip = "%s" % (props['ip4-address'].encode('utf-8')) | ip = "%s" % (props['ip4-address'].encode('utf-8')) | ||
nick = "%s" % (props['nick'].encode('utf-8')) | nick = "%s" % (props['nick'].encode('utf-8')) | ||
− | print"ip: "+ ip | + | print "ip: "+ ip |
print "nick: " + nick | print "nick: " + nick | ||
xo = DataXo.DataXo(ip, nick) | xo = DataXo.DataXo(ip, nick) | ||
Línea 100: | Línea 96: | ||
pass | pass | ||
return xos | return xos | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Utilizamos la funcionalidad anterior de la siguiente manera en la ventana principal de la actividad (activity.py) para cargar un combobox con las IPs y Nicks: | ||
+ | <syntaxhighlight lang="python"> | ||
+ | ... | ||
+ | import Red | ||
+ | import DataXo | ||
+ | ... | ||
+ | def listarComboBoxRed (self): | ||
+ | # Se llama a la clase Red que obtiene las Ip y nick de los hosts. | ||
+ | # FALTA FILTRAR LA IP Y NICK DE LA XO QUE EJECUTA ESTE CODIGO | ||
+ | red = Red.Red() | ||
+ | xos = red.get_Xos() | ||
+ | |||
+ | self.comboBox = ComboBox() | ||
+ | for xo in xos: | ||
+ | nombre = xo.getNombre() | ||
+ | ip = xo.getIp() | ||
+ | nombreIp = nombre+"-"+ip | ||
+ | print nombreIp | ||
+ | self.comboBox.append_item(None,nombreIp, None, None) | ||
+ | self.box1.pack_start(self.comboBox, False, False, 0) | ||
+ | self.comboBox.show() | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Revisión del 11:21 31 ene 2013
Actividad para Sugar donde se puede teleoperar el robot Butiá mediante los acelerómetros de las XOs y obtener streaming de video del robot en la XO del teleoperador.
Contenido
Introduccion
La telerobótica es el área de la robótica que se ocupa del control de los robots a distancia, a través de conexiones inalámbricas como WiFi, Bluetooth, entre otras. Se compone de dos subcampos: la teleoperación y la telepresencia.
La teleoperación refiere a "hacer algo a distancia", como es en particular que una persona comande a un robot a distancia.
Mientras que la telepresencia significa "sentir como si fuera alguien más".
La telerobótica ha sido empleada en diversas actividades como son los vehículos telerobóticos enviados en expediciones espaciales, en cirugía permitiendo operar a través de pequeños orificios, manipuladores de materiales peligrosos (redioactivos por ejemplo), y más.
Objetivos
Desarrollar una actividad para el Sistema Operativo Sugar, para que se pueda teleoperar el robot Butiá aprovechando el acelerómetro de las XOs, y a su vez capturar el entorno del mismo a través de la webcam de la XO que se encuentre sobre el robot, contemplando que sea amigable, intuitiva y sencilla para los niños.
Experiencias previas
Script ejecutado desde consola:
Descripción de la solución
El robot Butiá dispone de un servidor, programado en Lua, que se encarga del comportamiento de los sensores y actuadores que cuente el robot y de una API (Interfaz de programación de aplicaciones) llamada ButiaAPI, programada en Python, que permite obtener valores de los sensores y ejecutar acciones de los actuadores, y se comunica con el servidor antes mencionado.
Tanto para transmitir directamente el streaming de video del robot al controlador, como para la comunicación del controlador con la ButiaAPI del robot necesitábamos las IPs de las demás XOs de la red. Basándonos en la aplicación JAMTank, obtuvimos las IPs y los nombres de las máquinas en una red mesh mediante dbus que brinda el sistema operativo. Para el envío del streaming de video, la comunicación entre las XOs, y que la interfaz gráfica se mantenga activa, se emplearon subprocesos que están implementados por Python.
La interfaz gráfica se implementó en Python tratando de utilizar al máximo los componentes del paquete gráfico que dispone sugar, para que sea similar al que están habituados a usar los niños. Al comienzo se consulta si la actividad está siendo ejecutada en el robot o en el controlador. En ambos casos el paso siguiente es seleccionar de una lista la ip y el nick de la otra XO que está ejecutando el otro rol. A continuación, la XO que está en el robot comienza a mandar el streaming de video, y se da la opción de regresar a la pantalla anterior, mientras que la XO controladora, recibe el video y tele-opera el robot mediante el acelerómetro de la misma.
En cuanto a la arquitectura, empezamos desarrollando todo en un solo archivo, y luego migramos a varios, y utilizamos clases para hacer la aplicación más modular.
El subproceso popen_obj es el que mandan y reciben stream según cuál sea el rol de la xo. bobot es el que ejecuta la xo que está en el robot para levantar un servidor lua y popen_n4b ejecuta lo ejecuta la xo controladora leyendo del acelerómetro para enviar ordenes all servidor lua que esta escuchando en la xo del robot.
Experiencias y pruebas
El proceso fue incremental.
Empezamos implementando la parte gráfica, y fuimos probando las interacciones entre las diferentes pantallas de la aplicación. Basándonos en la aplicación de Sugar "Hello World!" comenzamos a implementar la actividad, logrando ubicar distintos botones en la misma y que cumplan alguna funcionalidad básica. Diseñamos las pantallas simples, con el tema del propio sistema operativo, e intuitivas para que sea mas fácil usar el programa.
Luego a través de la interfaz gráfica comenzamos a probar la conexión entre ambas XO, y a resolver el tema de las IP. También realizamos muchas pruebas para ésto, utilizando router o comunicándonos XO contra XO. Obtuvimos la lista de IPs (es necesaria para transmitir el streaming directamente, haciéndolo más eficiente) y los Nicks de las demas pcs de la red, para que se pueda identificar al robot y al teleoperador. Investigando la aplicacion JAMTank y consultando a su implementador, logramos obtener las IPs de las Xos de la red y los Nicks mediante dbus.
Módulo encargado de obtener las IPs y Nicks de las demás XOs:
import sys
import dbus
import os
import string
import DataXo
OLPC_SESSION_BUS = "/tmp/olpc-session-bus"
PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
PRESENCE_PATH = "/org/laptop/Sugar/Presence"
PRESENCE_IFACE = "org.laptop.Sugar.Presence"
BUDDY_IFACE = "org.laptop.Sugar.Presence.Buddy"
class Red:
def __init__(self):
print "entro en el constructor de Red"
def get_bus(self):
# Genera un bus por el cual se obtienen las IPs de las Xos de la Red AdHoc
if os.path.exists(OLPC_SESSION_BUS):
address = "unix:path=%s" % OLPC_SESSION_BUS
return dbus.bus.BusConnection(address_or_type=address)
else:
if 'DBUS_SESSION_BUS_ADDRESS' in os.environ:
del os.environ['DBUS_SESSION_BUS_ADDRESS']
return dbus.bus.BusConnection()
def get_Xos(self):
#devuelve la ip y el nombre de todas las xo en la red
#En realidad devuelve el nick de todas las xos y las ip de la mesh de las demas xos
bus = self.get_bus()
ps = bus.get_object(PRESENCE_SERVICE, PRESENCE_PATH)
ps_iface = dbus.Interface(ps, PRESENCE_IFACE)
buddies = map(lambda b: bus.get_object(PRESENCE_SERVICE, b), ps_iface.GetBuddies())
xos = []
for buddy in buddies:
buddy_iface = dbus.Interface(buddy, BUDDY_IFACE)
try:
props = buddy_iface.GetProperties()
ip = "%s" % (props['ip4-address'].encode('utf-8'))
nick = "%s" % (props['nick'].encode('utf-8'))
print "ip: "+ ip
print "nick: " + nick
xo = DataXo.DataXo(ip, nick)
xos.append(xo)
except dbus.DBusException:
print "en la excepcion"
pass
return xos
Utilizamos la funcionalidad anterior de la siguiente manera en la ventana principal de la actividad (activity.py) para cargar un combobox con las IPs y Nicks:
...
import Red
import DataXo
...
def listarComboBoxRed (self):
# Se llama a la clase Red que obtiene las Ip y nick de los hosts.
# FALTA FILTRAR LA IP Y NICK DE LA XO QUE EJECUTA ESTE CODIGO
red = Red.Red()
xos = red.get_Xos()
self.comboBox = ComboBox()
for xo in xos:
nombre = xo.getNombre()
ip = xo.getIp()
nombreIp = nombre+"-"+ip
print nombreIp
self.comboBox.append_item(None,nombreIp, None, None)
self.box1.pack_start(self.comboBox, False, False, 0)
self.comboBox.show()
Una vez resuelto el tema de las IPs, comenzamos con el streaming de video, lo que nos introdujo el problema de manejar hilos para que la ventana no se quedara congelada cuando se mostraba el video, o se enviaba señales del acelerómetro. Probamos insertar en la misma ventana de la aplicación ésta ventana, sin éxito. Resolvimos dejar por fuera la ventana del streaming (como una ventana emergente).
Luego pasamos a la lectura del acelerómetro en conjunto con la comunicación con el Butia. Para ésto investigamos más a fondo el Butia API para luego integrarla a nuestro proyecto, a medida que avanzamos fuimos probando cada funcionalidad que desarrollamos.
Una vez acabado el proyecto, realizamos cortas pruebas de navegación con la actividad funcionando completamente en cada XO con resultados buenos. Y seguimos trabajando y probando la navegación dentro de la aplicación para un uso correcto, adecuado e intuitivo.
Dificultades encontradas
- El uso de python no era habitual para algunos de los integrantes, lo cual trajo demoras y problemas en principio para hacer que las cosas funcionen.
- El uso de gtk, para el manejo gráfico dentro de Sugar no fue sencillo.
- Para obtener la IP correspondiente al controlador, o al robot por medio de la red nos generó dificultades, ya que no dábamos con las primitivas y tipos correctos. Luego con una aplicación que encontramos en internet, la cuál no andaba y era solo un prototipo logramos obtener las IP y nombres de cada XO.
- Para insertar el streaming de video dentro de la aplicación sugar, estuvimos investigando y probando de muchas maneras, y no logramos éxito. Por lo tanto la ventana del streaming lo hicimos por fuera de la ventana principal de la aplicación.
- Los permisos en los archivos los cuales se acceden, nos trajeron problemas. Una vez dados los permisos adecuados, se solucionó.
- Los threads con gtk, tuvimos problemas con las operaciones y funcionamiento de los mismos. Optamos por utilizar subprocesos en vez de threads. Ésto fue una ventaja porque era más transparente al desarrollo, podíamos monitorearlos, matarlos, etc.
- Al cerrar la aplicación, el robot quedaba con la última orden enviada, y no había forma de pararlo. Al principio pensamos en exigir que para cerrar la aplicación los acelerómetros estuvieran en 0. Luego decidimos enviar una señal al robot, deteniendo los motores justo antes de cerrar la aplicación.
Mejoras a realizar
- Integrar el Streaming de video a la ventana principal de la aplicación. Creemos que sería mejor con la ultilización de threads.
- Nuestra aplicación no permite correr el robot en una XOs con procesador ARM y la XO con acelerometro tiene un procesador ARM. Habría que hacer unas modificaciones para realizar ésta tarea. Consideramos una posible alternativa la de exigir tener instalado el TurtleBots y usar la ButiaApi, Lua y demás directamente de ahí, para independizar esta actividad de la XO empleada.
- Mostrar en la pantalla del controlador los distintos sensores que disponga el robot.
Integrantes
- Sebastián Sánchez
- Juan Martín Valsangiacomo
- Juan Enrique Pirez