miércoles, 8 de febrero de 2012

Tutorial Servicios Web Semanticos

Tutorial

En este tutorial aprenderemos como hacer un servicio web compuesto que recomienda robots para una determinada tarea, y a marcarlo semánticamente

Herramientas:



Nuestro primer paso será crear la Ontología que representa a los robots. Algunos de los conceptos básicos de una Ontología son las clases, las instancias y las propiedades, estas ultimas se dividen en propiedades de objetos y propiedades de datos; si tratamos de relacionar estos conceptos con el mundo de la programación orientada a objetos podemos ver las clases de una Ontología como clases de la programación, las propiedades de objetos como atributos que son punteros a otros objetos, las propiedades de datos como atributos de tipos de datos primitivos (String, int, float, etc.) y las instancias como instancias de una clase (Objetos)

Abrimos Protégé y creamos un nuevo proyecto tipo OWL / RDF Files


Luego nos pedirá una URI que será la dirección donde estará almacenada la Ontología, en este caso la guardaremos en glassfish por lo que la dirección será localhost


Luego nos pedirá seleccionar un lenguaje, seleccionaremos OWL DL y luego le damos finish

En la pestaña OWL Classes creamos las clases, en OWL toda clase extiende de la clase Thing, los botones encerrados en el recuadro rojo de la imagen siguiente son en orden de izquierda a derecha: Crear una nueva subclase (Una clase que hereda de la clase que se encuentre seleccionada), crear clase hermana (Una clase que esta en el mismo nivel de jerarquía que la que esté seleccionada) y borrar clase


Así creamos diferentes clases que extienden de Robot: Androide, Zoomorfico, Poliarticulado, Movil e Hibrido; y una clase Dispositivo de la cual extienden: Comunicación, Energía, Extremidades, Motor, Sensor y Transporte, de cada una de ellas podemos crear mas subclases y así sucesivamente hasta crear una Ontología bien definida, para ver el funcionamiento del sistema de recomendación y la creación de los servicios web es suficiente con llegar hasta el nivel de jerarquía que se muestra en la imagen


Notemos que un Robot Híbrido puede ser cualquier combinación de los demás robots, por lo cual podemos modelar este hecho de tal forma que Híbrido extienda de todas sus clases hermanas, para esto diremos que tiene como superclases a Androide, Zoomorfico, Robot, Movil y Poliarticulado, nos aseguramos de cambiar a la vista de Propiedades (recuadro azul) y damos clic en agregar una clase (recuadro rojo) y luego seleccionamos toda las clases mencionadas anteriormente


Luego procederemos a crear las propiedades, a la clase robot le adicionaremos una propiedad de objeto llamada "dispositivos" y podrá contener todas las instancias de la clase dispositivos que tiene un robot. Como las clases Zoomorfico, Androide, etc. heredan de la clase Robot, también heredan sus propiedades, así que cualquier robot tendrá dispositivos. En el campo de Propiedades y Restricciones agregaremos una nueva propiedad de Objeto (recuadro rojo); notemos que para esta propiedad el dominio es la clase Robot y el rango es la clase Dispositivo.


En una Ontología podemos crear condiciones y restricciones, por ejemplo, podemos asumir que un robot dentro de sus dispositivos tiene que tener al menos uno de Energía, uno de Comunicación y un Motor. Para crear esta restricción seleccionamos la clase Robot y nos aseguramos de tener activada la vista lógica (recuadro azul), luego damos clic en el botón crear nueva restricción (recuadro rojo), seleccionamos la propiedad sobre la cual haremos la restriccion, en ese caso dispositivos, luego el tipo de restricciones, en este caso "SomeValuesFrom" y en el campo Filler tenemos varias herramientas para crear una expresión lógica, seleccionaremos el botón "Insert class" (recuadro verde) y seleccionamos la clase Comunicación:


Luego en el campo Filler presionamos el botón "and" (recuadro rojo) y luego insertamos una nueva clase, hasta crear la expresion que se muestra en la imagen


Así logramos crear una expresión lógica que obliga a que un Robot tenga al menos una fuente de Energía, un dispositivo de Comunicación y un Motor. Así podemos crear una serie de restricciones en cada uno de los subniveles de la jerarquía. Por ejemplo, podemos decir que un robot Móvil tiene que tener un GPS y un dispositivo de Transporte, además de la restricción heredada de la clase Robot, por lo que se vería algo como:


Crearemos propiedades de datos para cada uno de los dispositivos, vamos a la clase Wifi y creamos una nueva propiedad de datos (recuadro rojo), la cual llamaremos distancia, su rango es int (recuadro azul) y marcaremos la opción Functional (recuadro verde) la cual significa que esta propiedad podrá tener un único valor


Así crearemos una propiedad para cada uno de los dispositivos que indique alguna medición representable como un tipo de dato numérico.
Una vez terminada nuestra Ontología, guardamos el proyecto en File -> Save Project, seleccionaremos la ruta para guardar el proyecto (.pprj) y la Ontología (.owl)


Luego montaremos el archivo .owl al servidor de Glassfish, generalmente la carpeta del servidor es Carpeta del usuario -> .netbeans -> version -> config -> GF3 -> domain1 -> docroot . Allí crearemos una carpeta llamada Ontologías y pegaremos el archivo Robot.owl. 

Ahora crearemos un archivo wsdl en NotePad++ por cada uno de los tres servicios atómicos. Estos se dividirán así:
  • El primer servicio recibe un Array de Dispositivos y devuelve un objeto de la clase Paquete, el cual tiene dos atributos: Un Array de Robots y un array de Dispositivos, será el encargado de consultar en las Ontologías cuales instancias de la clase Robot tienen los dispositivos requeridos y devolverá dicha lista, notemos que no importa si la distancia del Wifi de un Robot A es 50m y dentro de mis requisitos está un Wifi de 80m, este servicio solo obtiene los robots que tengan los dispositivos sin importar sus propiedades de datos. El Paquete devuelto tiene como atributos el Array de robots obtenidos y el Array de dispositivos requeridos, los mismos que se ingresaron como parametro de entrada.
  • El segundo servicio recibirá una clase Paquete y devolverá una clase paquete. Este servicio será el encargado de eliminar los demás dispositivos que no nos interesan para poder aplicar el algoritmo de la correlación de Pearson en el tercer servicio, ya que este necesita que los objetos a comparar tengan las mismas características en común, es decir, si requerimos un robot con Wifi, Brazo y un Motor y encontramos un Robot con Wifi, Motor, Brazo y Bluetooth debemos ocultar el ultimo dispositivo para trabajar con los que son necesarios. Así que este servicio eliminará los dispositivos que no son necesarios.
  • El tercer servicio recibirá un Paquete y devolverá un Array de Robots, Aplicará la correlación de Pearson comparando cada robot con los valores de los dispositivos dados y luego los ordenará, dando así lugar a un Array con los robots que cumplen las caracteristicas solicitadas ordenados de forma tal que el primero es el que mas se parece al requerido.
Un buen tutorial sobre wsdl y servicios web es: http://www.ibm.com/developerworks/ssa/webservices/tutorials/ws-understand-web-services2/index.html

Aqui tenemos el .wsdl y el .xsd del primer servicio

DepuracionService.wsdl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
    name="DepuracionService"
    targetNamespace="http://localhost:8080/Depuracion/DepuracionService"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://localhost:8080/Depuracion/DepuracionService"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <wsdl:types>
        <xsd:schema>
  <xsd:import namespace="http://localhost:8080/Depuracion/DepuracionService"
  schemaLocation="DepuracionServiceXSD.xsd"/>
 </xsd:schema>
    </wsdl:types>
    <wsdl:message name="DispositivosMessage">
        <wsdl:part element="tns:ArrayDispositivos" name="DispositivosPart"/>
    </wsdl:message>
    <wsdl:message name="PaqueteMessage">
        <wsdl:part element="tns:Paquete" name="PaquetePart"/>
    </wsdl:message>
    <wsdl:portType name="DepuracionServicePortType">
        <wsdl:operation name="DepuracionServiceOperation">
            <wsdl:input message="tns:DispositivosMessage"/>
            <wsdl:output message="tns:PaqueteMessage"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="DepuracionServicePortBinding" 
 type="tns:DepuracionServicePortType">
        <soap:binding style="document" 
  transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="DepuracionServiceOperation">
            <soap:operation soapAction=""/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
 </wsdl:binding> 
    <wsdl:service name="DepuracionService">
        <wsdl:port binding="tns:DepuracionServicePortBinding" 
  name="DepuracionServicePort">
            <soap:address 
   location="http://localhost:8080/Depuracion/DepuracionService"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>
DepuracionServiceXSD.xsd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<xs:schema version="1.0" 
targetNamespace="http://localhost:8080/Depuracion/DepuracionService" 
xmlns:tns="http://localhost:8080/Depuracion/DepuracionService" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="DispositivoType">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="nombreDispositivo" type="xs:string"/>
   <xs:element name="valorDispositivo" type="xs:int"/>  
  </xs:sequence>
 </xs:complexType>
</xs:element>
  
<xs:element name="RobotsType">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="nombre" type="xs:string"/>
   <xs:element ref="tns:ArrayDispositivos"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>
  
<xs:element name="ArrayDispositivos">
  <xs:complexType>
    <xs:sequence minOccurs="0" maxOccurs="unbounded"> 
  <xs:element ref="tns:DispositivoType"/>
 </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="ArrayRobots">
  <xs:complexType>
    <xs:sequence minOccurs="0" maxOccurs="unbounded"> 
  <xs:element ref="tns:RobotsType"/>
 </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="Paquete">
 <xs:complexType> 
  <xs:sequence>
   <xs:element ref="tns:ArrayDispositivos"/>
   <xs:element ref="tns:ArrayRobots"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>

</xs:schema>


Aqui tenemos el .wsdl y el .xsd del segundo servicio

ModificarCaracteristicasService.wsdl


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wsdl:definitions
    name="ModificarCaracteristicasService"
    targetNamespace="http://localhost:8080/ModificarCaracteristicas
 /ModificarCaracteristicasService"
 xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://localhost:8080/ModificarCaracteristicas
 /ModificarCaracteristicasService"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
    <wsdl:types>
        <xsd:schema>
  <xsd:import namespace="http://localhost:8080/ModificarCaracteristicas
  /ModificarCaracteristicasService" 
  schemaLocation="ModificarCaracteristicasServiceXSD.xsd"/>
 </xsd:schema>
    </wsdl:types>
    <wsdl:message name="PaqueteInputMessage">
        <wsdl:part element="tns:Paquete" name="PaqueteInputPart"/>
    </wsdl:message>
    <wsdl:message name="PaqueteOutputMessage">
        <wsdl:part element="tns:Paquete" name="PaqueteOutputPart"/>
    </wsdl:message>
    <wsdl:portType name="ModificarCaracteristicasServicePortType">
        <wsdl:operation name="ModificarCaracteristicasServiceOperation">
            <wsdl:input message="tns:PaqueteInputMessage"/>
   <wsdl:output message="tns:PaqueteOutputMessage"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="ModificarCaracteristicasServicePortBinding" 
 type="tns:ModificarCaracteristicasServicePortType">
        <soap:binding style="document" 
  transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="ModificarCaracteristicasServiceOperation">
            <soap:operation soapAction=""/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
 </wsdl:binding> 
    <wsdl:service name="ModificarCaracteristicasService">
        <wsdl:port binding="tns:ModificarCaracteristicasServicePortBinding" 
  name="ModificarCaracteristicasServicePort">
            <soap:address 
   location="http://localhost:8080/ModificarCaracteristicas
   /ModificarCaracteristicasService"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>

ModificarCaracteristicasServiceXSD.xsd


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<xs:schema version="1.0" 
targetNamespace="http://localhost:8080/ModificarCaracteristicas
/ModificarCaracteristicasService" 
xmlns:tns="http://localhost:8080/ModificarCaracteristicas
/ModificarCaracteristicasService" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="DispositivoType">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="nombreDispositivo" type="xs:string"/>
   <xs:element name="valorDispositivo" type="xs:int"/>  
  </xs:sequence>
 </xs:complexType>
</xs:element>
  
<xs:element name="RobotsType">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="nombre" type="xs:string"/>
   <xs:element ref="tns:ArrayDispositivos"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>
  
<xs:element name="ArrayDispositivos">
  <xs:complexType>
    <xs:sequence minOccurs="0" maxOccurs="unbounded"> 
  <xs:element ref="tns:DispositivoType"/>
 </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="ArrayRobots">
  <xs:complexType>
    <xs:sequence minOccurs="0" maxOccurs="unbounded"> 
  <xs:element ref="tns:RobotsType"/>
 </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="Paquete">
 <xs:complexType>
  <xs:sequence> 
   <xs:element ref="tns:ArrayDispositivos"/>
   <xs:element ref="tns:ArrayRobots"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>

</xs:schema>

Aqui tenemos el .wsdl y el .xsd del tercer servicio

MejorRobot.wsl


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wsdl:definitions
    name="MejorRobotService"
    targetNamespace="http://localhost:8080/MejorRobot/MejorRobotService"
 xmlns="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://localhost:8080/MejorRobot/MejorRobotService"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">
    <wsdl:types>
        <xsd:schema>
   <xsd:import namespace="http://localhost:8080/MejorRobot/MejorRobotService" 
   schemaLocation="MejorRobotXSD.xsd"/>
  </xsd:schema>
    </wsdl:types>
    <wsdl:message name="PaqueteMessage">
        <wsdl:part element="tns:Paquete" name="PaquetePart"/>
    </wsdl:message>
    <wsdl:message name="MejorRobotMessage">
        <wsdl:part element="tns:ArrayRobots" name="MejorRobotPart"/>
    </wsdl:message>
    <wsdl:portType name="MejorRobotPortType">
        <wsdl:operation name="MejorRobotOperation">
            <wsdl:input message="tns:PaqueteMessage"/>
   <wsdl:output message="tns:MejorRobotMessage"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="MejorRobotPortBinding" type="tns:MejorRobotPortType">
        <soap:binding style="document" 
  transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="MejorRobotOperation">
            <soap:operation soapAction=""/>
            <wsdl:input>
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
 </wsdl:binding> 
    <wsdl:service name="MejorRobotService">
        <wsdl:port binding="tns:MejorRobotPortBinding" name="MejorRobotPort">
            <soap:address 
   location="http://localhost:8080/MejorRobot/MejorRobotService"/>
        </wsdl:port>
    </wsdl:service>
</wsdl:definitions>



MejorRobotXSD.xsd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<xs:schema version="1.0" 
targetNamespace="http://localhost:8080/MejorRobot/MejorRobotService" 
xmlns:tns="http://localhost:8080/MejorRobot/MejorRobotService" 
xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="DispositivoType">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="nombreDispositivo" type="xs:string"/>
   <xs:element name="valorDispositivo" type="xs:int"/>  
  </xs:sequence>
 </xs:complexType>
</xs:element>
  
<xs:element name="RobotsType">
 <xs:complexType>
  <xs:sequence>
   <xs:element name="nombre" type="xs:string"/>
   <xs:element ref="tns:ArrayDispositivos"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>
  
<xs:element name="ArrayDispositivos">
  <xs:complexType>
    <xs:sequence minOccurs="0" maxOccurs="unbounded"> 
  <xs:element ref="tns:DispositivoType"/>
 </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="ArrayRobots">
  <xs:complexType>
    <xs:sequence minOccurs="0" maxOccurs="unbounded"> 
  <xs:element ref="tns:RobotsType"/>
 </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="Paquete">
 <xs:complexType>
  <xs:sequence> 
   <xs:element ref="tns:ArrayDispositivos"/>
   <xs:element ref="tns:ArrayRobots"/>
  </xs:sequence>
 </xs:complexType>
</xs:element>

</xs:schema>

Ahora crearemos en Netbeans tres proyectos diferentes para cada uno de los proyectos, el poryecto debe ser tipo Java Web -> Web Application


El proyecto lo llamaremos "Depuracion", Luego en el proyecto crearemos un nuevo servicio a partir del WSDL, para ellos vamos a file -> new File, seleccionamos Web Services y luego Web Service from WSDL


Llamaremos al servicio "DepuracionService", seleccionamos un paquete donde se crearán las clases definidas en el .xsd y la direccion del wsdl



Creamos un nuevo paquete llamado "clases" y una clase llamada Main, la cual tendrá el siguiente código:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package clases;

import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import java.util.ArrayList;
import java.util.List;
import localhost._8080.depuracion.depuracionservice.ArrayDispositivos;
import localhost._8080.depuracion.depuracionservice.ArrayRobots;
import localhost._8080.depuracion.depuracionservice.DispositivoType;
import localhost._8080.depuracion.depuracionservice.Paquete;
import localhost._8080.depuracion.depuracionservice.RobotsType;

public class Main {

    private static final String NS = 
            "http://localhost:8080/Ontologias/robot.owl#";
    private static final String ruta = 
            "http://localhost:8080/Ontologias/robot.owl#";
    private OntModel model;

    public Main() {
        model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM, null);
        model.read(ruta, "RDF/XML");
    }

    private static boolean estanTodos(List<DispositivoType> req, 
            List<Statement> prop) {
        for (int i = 0; i < req.size(); i++) {
            boolean esta = false;
            for (int j = 0; j < prop.size(); j++) {
                if (req.get(i).getNombreDispositivo().equals(
                        getTipoDisp(prop.get(j).getObject().asResource()))) {
                    esta = true;
                    break;
                }
            }
            if (esta == false) {
                return false;
            }
        }
        return true;
    }
    
    private static String getTipoDisp(Resource r) {
        return r.getPropertyResourceValue(null).getLocalName();
    }

    private List<DispositivoType> toDispositivos(List<Statement> propiedades) {
        List<DispositivoType> disp = new ArrayList<DispositivoType>();
        for (int i = 0; i < propiedades.size() - 1; i++) {
            Resource objeto = propiedades.get(i).getObject().asResource();
            List<Statement> prop = objeto.listProperties().toList();
            for (int j = 0; j < prop.size() - 1; j++) {
                if (!prop.get(j).getPredicate().getLocalName().
                        equals("nombre")) {
                    DispositivoType d = new DispositivoType();
                    d.setNombreDispositivo(getTipoDisp(objeto));
                    d.setValorDispositivo(prop.get(j).getLiteral().getInt());
                    disp.add(d);
                }
            }
        }
        return disp;
    }

    public Paquete ejecutar(ArrayDispositivos aDisp) {
        List<DispositivoType> dispReq = aDisp.getDispositivoType();
        Paquete paq = new Paquete();
        OntClass claseRaiz = model.getOntClass(NS + "Robot");
        List<RobotsType> robots = new ArrayList<RobotsType>();
        for (ExtendedIterator<OntClass> i = claseRaiz.listSubClasses(); 
                i.hasNext();) {
            OntClass clase = i.next();
            List<Individual> objetos = model.listIndividuals(clase).toList();
            for (int j = 0; j < objetos.size(); j++) {
                Individual robot = objetos.get(j);
                List<Statement> propiedades = robot.listProperties().toList();
                if (estanTodos(dispReq, propiedades)) {
                    RobotsType r = new RobotsType();
                    r.setNombre(robot.getLocalName());
                    ArrayDispositivos dd = new ArrayDispositivos();
                    dd.getDispositivoType().addAll(toDispositivos(propiedades));
                    r.setArrayDispositivos(dd);
                    robots.add(r);
                }
            }
        }
        paq.setArrayDispositivos(aDisp);
        ArrayRobots aRob = new ArrayRobots();
        aRob.getRobotsType().addAll(robots);
        paq.setArrayRobots(aRob);
        return paq;
    }}


Jena es una API que nos permite extraer la información de una Ontología y utilizarla en Java.
Un tutorial sobre Jena se encuentra en: http://jena.sourceforge.net/ontology/index.html

Básicamente lo que hacemos es obtener la clase raíz de la Ontología, en este caso la clase Robot, se recorre las subclases y se obtienen las instancias de cada una de estas, luego podemos proceder a obtener las propiedades que cada instancia tiene y así comparar cada Robot con las condiciones dadas obteniendo los que cumplan con los requerimientos necesarios.
Este proyecto requiere importar la librería de Jena, por lo cual creamos una libreria en netbeans y agregamos todos los .jar que se encuentran en la carpeta lib del archivo descargado de Jena.



El código de la clase DepuracionService.java quedaría como sigue:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package services;

import clases.Main;
import javax.jws.WebService;

@WebService(serviceName = "DepuracionService", 
        portName = "DepuracionServicePort", 
        endpointInterface = "localhost._8080.depuracion.depuracionservice."
        + "DepuracionServicePortType", 
        targetNamespace = "http://localhost:8080/Depuracion/DepuracionService", 
        wsdlLocation = "WEB-INF/wsdl/DepuracionService/DepuracionService.wsdl")
public class DepuracionService {

    public localhost._8080.depuracion.depuracionservice.Paquete 
            depuracionServiceOperation(localhost._8080.depuracion.
                    depuracionservice.ArrayDispositivos dispositivosPart) {
        return new Main().ejecutar(dispositivosPart);
    }}


Similarmente crearemos otros dos proyectos, el segundo servicio llamado "ModificarCaracteristicas" y un servicio llamada "ModificarCaracteristicasService", el código de la clase Main.java y ModificarCaracteristicasService.java de se muestran a continuación


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package clases;

import java.util.ArrayList;
import java.util.List;
import localhost._8080.modificarcaracteristicas.
        modificarcaracteristicasservice.*;

public class Main {

    public static Paquete depurar(Paquete paquete) {
        List<RobotsType> robots = paquete.getArrayRobots().getRobotsType();
        List<DispositivoType> disps = paquete.getArrayDispositivos().
                getDispositivoType();
        for (int i = 0; i < robots.size(); i++) {
            RobotsType robot = robots.get(i);
            List<DispositivoType> dispR = robot.getArrayDispositivos().
                    getDispositivoType();
            List<DispositivoType> dispN = new ArrayList<DispositivoType>();
            for (int j = 0; j < disps.size(); j++) {
                for (int k = 0; k < dispR.size(); k++) {
                    if (dispR.get(k).getNombreDispositivo().equals(disps.get(j).
                            getNombreDispositivo())) {
                        dispN.add(dispR.get(k));
                        break;
                    }
                }
            }
            dispR.clear();
            dispR.addAll(dispN);
        }
        return paquete;
    }}




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package services;

import clases.Main;
import javax.jws.WebService;

@WebService(serviceName = "ModificarCaracteristicasService", 
        portName = "ModificarCaracteristicasServicePort", 
        endpointInterface = "localhost._8080.modificarcaracteristicas.modifi"
        + "carcaracteristicasservice.ModificarCaracteristicasServicePortType", 
        targetNamespace = "http://localhost:8080/ModificarCaracteristicas"
        + "/ModificarCaracteristicasService", 
        wsdlLocation = "WEB-INF/wsdl/ModificarCaracteristicasService"
        + "/ModificarCaracteristicasService.wsdl")
public class ModificarCaracteristicasService {

    public localhost._8080.modificarcaracteristicas.
            modificarcaracteristicasservice.Paquete 
            modificarCaracteristicasServiceOperation(localhost._8080.
                    modificarcaracteristicas.modificarcaracteristicasservice.
                    Paquete paqueteInputPart) {
        return Main.depurar(paqueteInputPart);
    }
    }



El tercer servicio lo llamamos "MejorRobot", a continuacion el codigo de la clase Main.java y de MejorRobotService.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package clases;

import java.util.ArrayList;
import localhost._8080.mejorrobot.mejorrobotservice.Paquete;
import localhost._8080.mejorrobot.mejorrobotservice.RobotsType;
import java.util.List;
import localhost._8080.mejorrobot.mejorrobotservice.ArrayDispositivos;
import localhost._8080.mejorrobot.mejorrobotservice.ArrayRobots;
import localhost._8080.mejorrobot.mejorrobotservice.DispositivoType;

public class Main {

    private Paquete paquete;

    public Main(Paquete paquete) {
        this.paquete = paquete;
    }

    private double pearson(RobotsType robot, List<DispositivoType> disps) {
        List<DispositivoType> dispRobot = robot.getArrayDispositivos().
                getDispositivoType();
        int n = disps.size();
        double sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0, sumY2 = 0,
                xA = 0, yA = 0;
        for (int i = 0; i < n; i++) {
            xA = dispRobot.get(i).getValorDispositivo();
            yA = disps.get(i).getValorDispositivo();
            sumX += xA;
            sumY += yA;
            sumXY += xA * yA;
            sumX2 += xA * xA;
            sumY2 += yA * yA;
        }
        return (n * sumXY - sumX * sumY) / ((Math.sqrt(n * sumX2 - sumX * sumX))
                * Math.sqrt(n * sumY2 - sumY * sumY));
    }

    public ArrayRobots getPearson() {
        List<RobotsType> robots = paquete.getArrayRobots().getRobotsType();
        List<DispositivoType> disp = paquete.getArrayDispositivos()
                .getDispositivoType();
        List<RobotPearson> robotsPer = new ArrayList<RobotPearson>();
        for (int i = 0; i < robots.size(); i++) {
            robotsPer.add(new RobotPearson(robots.get(i),
                    pearson(robots.get(i), disp)));
        }
        ordenarArray(robotsPer);
        ArrayRobots array = new ArrayRobots();
        List<RobotsType> robotsO = new ArrayList<RobotsType>();
        for (int i = 0; i < robotsPer.size(); i++) {
            robotsO.add(robotsPer.get(i).getRobot());
        }
        array.getRobotsType().addAll(robotsO);
        return array;
    }

    private void ordenarArray(List<RobotPearson> robots) {
        for (int i = 0; i < robots.size(); i++) {
            for (int j = i; j < robots.size(); j++) {
                if (robots.get(i).getPearson() < robots.get(j).getPearson()) {
                    RobotPearson aux = robots.get(i);
                    robots.set(i, robots.get(j));
                    robots.set(j, aux);
                }
            }
        }
    }}

class RobotPearson {

    private RobotsType robot;
    private double pearson;

    public RobotPearson(RobotsType robot, double pearson) {
        this.robot = robot;
        this.pearson = pearson;
    }

    public RobotsType getRobot() {
        return robot;
    }

    public void setRobot(RobotsType robot) {
        this.robot = robot;
    }

    public double getPearson() {
        return pearson;
    }

    public void setPearson(double pearson) {
        this.pearson = pearson;
    }}




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package services;

import clases.Main;
import javax.jws.WebService;

@WebService(serviceName = "MejorRobotService",
        portName = "MejorRobotPort", 
        endpointInterface = "localhost._8080.mejorrobot.mejorrobotservice."
        + "MejorRobotPortType", 
        targetNamespace = "http://localhost:8080/MejorRobot/MejorRobotService", 
        wsdlLocation = "WEB-INF/wsdl/MejorRobotService/MejorRobot.wsdl")
public class MejorRobotService {

    public localhost._8080.mejorrobot.mejorrobotservice.ArrayRobots
            mejorRobotOperation(localhost._8080.mejorrobot.mejorrobotservice.
                    Paquete paquetePart) {
        return new Main(paquetePart).getPearson();
    }
    }



Asi tenemos los tres servicios atomicos programados, damos en cada uno clic derecho -> Deploy para ponerlos a correr en GlassFish


Luego procederemos a marcar cada uno de los servicios atómicos y a la composición del servicio web

Abrimos Protege y realizamos los pasos mencionados anteriormente.


Hacemos click en el botón que está dentro del marco rojo e importamos nuestra ontología de dominio.


Si señalamos la pestaña OWLClasses, podremos ver cada una de las clases de nuestra ontología importada.

Luego iremos menú en barra, señalamos project/configure y seleccionamos owlstab; de ésta manera estaremos importando el plug-in de owl-s editor para Protégé y a su vez la ontología para describir servicios web OWL-S.

Al realizar los pasos anteriores tendremos la siguiente vista en nuestro Protégé.



Para realizar el marcado semántico a nuestros servicios web, creamos una nueva instancia de la clase Process declarada en la ontología OWL-S como subclase de ServiceModel.


Observemos el marco rojo, con ese botón crearemos la instacia, luego aparecerá el cuadro que en la anterior imágen tiene como título Choose a Class. En este cuadro seleccionamos Atomic Process.

Luego creamos una nueva instancia de hasInput y tendrémos la siguiente vista.


Luego de darle un identificador a la entrada, especificamos su tipo de dato haciendo click en el botón amarillo con el símbolo de suma.


En nuestro caso señalamos la clase ArrayDispositivos, indicando que el servicio recibe una entrada de este tipo.

Para especificar las salidas, hacemos este mismo proceso pero creando una instancia de hasOutput.

Ahora, supondremos que hemos creado 3 procesos atómicos y crearémos un nuevo process pero señalaremos esta vez Composite Process, para indicar que este es compuesto.


Para realizar este paso es necesario tener instalado el software Graphviz para visualizar un esquema del servicio compuesto. Uno de los botones que tiene forma de rombo rosado, tiene una letra 'S', con este botón crearémos un sequence, ya que nuestro servicio compuesto se comporta como una secuencia.
Creamos varios Perform con el botón que tiene la 'P', un perform por cada atomic process.


Al crear un perform, en la pestaña properties, le damos un nombre al perform y seleccionamos el atomic process correspondiente.

En la siguiente imágen veremos como se especifica que la salida de un atomic process es exactamente la misma entrada del siguiente proceso.


Luego de realizar estos pasos con cada perform, nuestro esquema será de la siguiente manera.


Luego crearemos nuestro grounding, creando una instancia de WsdlGrounding, al crearla, aparecerá un recuadro rojo enmarcando a supportedBy, en la cual se debe especificar el servicio al cual se le está haciendo el grounding. Por el momento no será importante.
Crearemos una instancia de hasAtomicProcessGrounding y allí especificaremos todo acerca de la ubicación de ciertos elementos en el wsdl de cada servicio.
Vamos a tomar como ejemplo el servicio web ModificarCaracteristicasService. El wsdl en nuestro caso está ubicado en nuestro localhost, accediendo a él con la siguiente dirección: http://localhost:8080/ModificarCaracteristicas/ModificarCaracteristicasService?WSDL

Observemos ahora la siguiente imágen.


Cada elemento del wsdl será especificado utilizando la dirección de este último añadiendo # y el nombre del elemento en el wsdl.

Ejemplo: http://localhost:8080/ModificarCaracteristicas/ModificarCaracteristicasService?WSDL#Paquete

De esta manera estaríamos especificando, en este caso, que las salidas de el servicio son de tipo Paquete.

Posteriormente crearemos el serviceProfile, creando una instancia.


En este definiremos las entradas del servicio compuesto y las salidas, indicaremos el procesos que tiene, damos el servicio al cual pertenece, y de manera opcional darémos una breve descripción del servicio en texto.

Luego creamos una instancia de Service e indicamos añadiendo instancias en los respectivos recuadros, el grounding, el profile y el proceso compuesto.


Finalmente, salvámos nuestro proyecto, el cual generará un archivo .owl.

Para más detalles visita: http://owlseditor.semwebcentral.org/documents/tutorial.pdf

Sistema de Recomendación Ontológico usando Servicios Web Semánticos

Introduccion



Los servicios web son una tecnología emergente durante los últimos años y que se ha venido desarrollando en el marco de la Arquitectura Orientada a Servicios (SOA) obedeciendo a la necesidad de implementar procesos de negocios. Este tipo de arquitectura resulta altamente ventajosa con respecto a otras gracias a la escalabilidad e interoperabilidad que ofrece. 
Cada servicio web se comporta como una pieza de software que realiza una tarea acorde a unas entradas (inputs), que son procesadas para luego emitir unas salidas (outputs) que serán finalmente el objetivo principal del servicio.
En nuestro caso particular, poseemos un servicio web (compuesto) que se compone de tres servicios más (atómicos), y al operar éstos últimos entre sí, generan un sólo resultado que se convertirá en el resultado del servicio compuesto. Remitiéndonos a las características esenciales de los servicios web, de que cada uno de éstos es una pieza de software que recibe unas serie de entradas y devuelve el resultado de un proceso, nuestro servicio web recibirá una serie de dispositivos que serán ingresados por un usuario que deseará que el servicio le devuelva el mejor robot que cumpla con dichos dispositivos en algún ambiente particular. Ésto se obtendrá a partir de la tarea específica de cada servicio web atómico, por ejemplo, para la recomendación del robot, se usa un servicio cuya tarea está programada con el algoritmo de la correlación de Pearson.
Un aspecto muy importante a tener en cuenta es que en la comunicación de los servicios web se necesitan una serie de convencionalismos sobre lo que significa cada uno de los datos que intervienen como entradas y salidas, lo que hace que en muchos casos se cometan errores a pesar de la intervención humana. Supongamos que tenemos un servicio web para la búsqueda de libros a partir del nombre de su autor. Este servicio web, tendrá una operación buscar que recibirá un tipo de dato "String" para su funcionamiento. Desde el punto de vista sintáctico, la operación puede ser confundida con otros servicios de búsqueda existentes de productos distintos a libros. Para evitar este tipo de confusiones, es necesario dotar de semántica al servicio, lo cual se hace mediante la creación de una ontología que describe de manera taxonómica el dominio en el cual actúa el servicio web. De esta manera, al definir una ontología de libros y al marcar semánticamente los servicios, la operación buscar quedaría identificada como una operación sólo para los libros. En nuestro caso particular, la ontología del dominio es acerca de robots.
Este tipo de aplicaciones sirven como modelos aplicables a lo que se conoce como "Cloud Robotics" o Robótica en la Nube, suponiendo un ambiente de robots en el cual cada uno está conectado a un servicio web listos para ejecutar un trabajo colaborativo.

Funcionamiento

 

Este sistema que recomienda robots es una aplicación realizada bajo una arquitectura orientada a servicios, ya que contiene tres procesos atómicos independientes que utilizan basados en el protocolo de comunicación sencillo que se trata de enviar un mensaje y recibir otro con las respuestas que se necesitaban. Es una aplicación web semántica ya que se compuso utilizando la ontología owl-s para marcar los servicios y crear con ellos un servicio compuesto utilizado de orquestador.

Creamos en protege una ontología de dominio, teniendo como dominio los robots, con el lenguaje de marcado OWL. Convertimos desde protege la ontología en código de java para que se creen los tipos de datos, relaciones e instancias especificadas en la ontología, importamos ese código, las librerías de protege y las librerías de Jena (para poder leer y manipular la ontología) en un proyecto dentro de la IDE netbeans. 
Además describimos los servicios en wsdl para luego crear a partir de ellos los tres servicios simples que en particular se encargan de:
• Primer servicio: recibe un Array de Dispositivos y devuelve un objeto de la clase Paquete, el cual tiene dos atributos: Un Array de Robots y un array de Dispositivos, será el encargado de consultar en las Ontologías cuales instancias de la clase Robot tienen los dispositivos requeridos y devolverá dicha lista, notemos que no importa si la distancia del Wifi de un Robot A es 50m y dentro de mis requisitos está un Wifi de 80m, este servicio solo obtiene los robots que tengan los dispositivos sin importar sus propiedades de datos. El Paquete devuelto tiene como atributos el Array de robots obtenidos y el Array de dispositivos requeridos, los mismos que se ingresaron como parámetro de entrada.
• Segundo servicio: recibirá una clase Paquete y devolverá una clase paquete. Este servicio será el encargado de eliminar los demás dispositivos que no nos interesan para poder aplicar el algoritmo de la correlación de Pearson en el tercer servicio, ya que este necesita que los objetos a comparar tengan las mismas características en común, es decir, si requerimos un robot con Wifi, Brazo y un Motor y encontramos un Robot con Wifi, Motor, Brazo y Bluetooth debemos ocultar el ultimo dispositivo para trabajar con los que son necesarios. Así que este servicio eliminará los dispositivos que no son necesarios.
• Tercer servicio: recibirá un Paquete y devolverá un Array de Robots, Aplicará la correlación de Pearson comparando cada robot con los valores de los dispositivos dados y luego los ordenará, dando así lugar a un Array con los robots que cumplen las características solicitadas ordenados de forma tal que el primero es el que más se parece al requerido.







Todos los datos de entrada y de salida de los servicios están especificados en la ontología para poder manipularlos con Jena y hacer los procesos necesarios para que se den los resultados esperados.

Luego utilizando OWL-S API instalada en protege, marcamos los servicios web atómicos para crear el compuesto, que se encarga de obtener los inputs y llamar a los demás servicios para que hagan su tarea específica (sin saber con qué fin la están realizando) y devuelvan sus outputs, se hace en forma de secuencia, el mensaje enviado por el cliente al servicio compuesto (un array de dispositivos) va al input del primer servicio que devuelve un objeto de la clase paquete al servicio compuesto, luego ese objeto de la clase paquete es enviado al segundo servicio que devuelve otro objeto de la clase paquete diferente y mejorado que vuelve al servicio compuesto para que se lo envíe al tercer servicio y ese devuelva un array con los robots recomendados al servicio compuesto y este se lo devuelva al cliente.


Conclusiones



·         La aplicación realizada representa un modelo que podría ser aplicable en un ambiente colaborativo de robots, generando una red de éstos, gracias a la funcionalidad que permiten los servicios web.
·         La arquitectura orientada a servicios tiene grandes beneficios, los modelos de negocios evolucionan y hay independencia en la operatividad de las aplicaciones, de esta manera abra mas flexibilidad entre la composición de software complejo .
·         La web semántica se ira expandiendo a medida en que existan más servicios web, mas ontologías asociadas a un dominio particular y unos agentes desarrollados para crear servicios automáticamente.
·         Crear un sistema de recomendación de robots es importante para un futuro cercano, ya que la robótica es un mundo amplio en el que se están aportando mucho. Será algo muy efectivo pero aun es un campo grande y al que se irán aportando más idea a medida que avanza la robótica
·         La robótica en la nube es el futuro de la robótica ya que permitirá procesos más rápidos y complejos que ayuden a la vida diaria en la realización de tareas en diferentes robots.

lunes, 9 de enero de 2012


Identificación de un Área Desconocida e Implementación de un Grafo de Visibilidad para el Cambio de Configuración de un Robot



En la robótica algunos de los desafíos más significativos frente a la robótica autónoma están en el área de planificación automática de movimientos. En esta se busca poder llevar instrucciones generadas en un lenguaje de alto nivel a un robot convirtiéndolas automáticamente a comandos de movimiento de bajo nivel de tal forma que se realice la tarea asignada. Esta tarea consiste típicamente en generar un cambio de configuración del robot de un lugar a otro, mientras se evaden los obstáculos presentes en el ambiente desconocido. Sin embargo, en la mayoría de la literatura se asume que el robot tiene un modelo preciso del ambiente antes de comenzar a desplazarse; menos atención se le ha prestado al problema de los ambientes no conocidos o aquellos parcialmente identificados. Es necesario entonces para resolver este ultimo problema la utilización de sensores capaz de tomar medidas del ambiente a medida que el robot esta en desplazamiento, de tal forma que se pueda generar un modelo del ambiente en el cual basar todas las futuras decisiones que el robot deba tomar; tal modelo, en esta propuesta, es el encargado de generar las principales características de lo que se conoce como grafo de visibilidad, y sobre el cual se planifican todas las posibles trayectorias que se pueden realizar en el ambiente de trabajo del robot. Adicional al uso de lo sensores para la identificación de los diferentes obstáculos presentes en el ambiente, también es fundamental considerar que en todo momento el robot debe conocer su localización en el mundo desconocido, de tal forma que el robot pueda identificar constantemente su ubicación, y la disposición geométrica de los obstáculos dentro del ambiente. Adicional a lo anterior también es de gran relevancia considerar que el robot tiene volumen específico, y por lo tanto no debe ser considerado como un punto en el espacio. Esto permite generar rutas que realmente pueden ser navegadas por el robot sin generar colisión alguna con los obstáculos en el ambiente.

Robot Lego Mindstorm NXT

La aplicación propone implementar el algoritmo de visibilidad sobre un robot Lego Mindstorms NXT 2.0 fabricado por Lego®, el cual es un kit de robótica programable lanzado al mercado en julio del 2006. Este remplazó a la primera generación del kit lego Mindstorm, el cual fue llamado kit de invención de robótica. 
El componente principal en el kit es un computador en forma de ladrillo llamado ladrillo inteligente NXT. En él se pueden conectar y controlar hasta tres motores en los puertos A, B y C y hasta cuatro de los diferentes sensores en los puertos 1, 2,3 y 4. El ladrillo también tiene una pantalla LCD de 100x64 pixeles y cuatro botones que pueden ser utilizados para navegar en los diferentes menús. Además ofrece la opción de conexiones por medio de USB y Bluetooth.  

Sistema sensorial

En esta propuesta se implementa el uso de varios sensores tanto con el fin de identificar el ambiente en el cual el robot esta interactuando como con el  de permitir el mejor posicionamiento posible del robot en el mundo. Los sensores utilizados son:

-          Sensor de ultrasonido: utilizado con el fin de identificar los diferentes obstáculos presentes en el ambiente desconocido, y mediante el posicionamiento del robot identificar las coordenadas de cada obstáculo.

-          Compás magnético: mediante el uso de este sensor se busca que cada vez que el robot haga un giro, este pueda ser realizado con una mayor precisión, y que factores externos como el suelo o las llantas no influyan demasiado en la realización correcta del giro. 
-          Tacómetro: este sensor ubicado en cada uno de los motores, son utilizados para proporcionar las coordenadas del robot en todo momento.   

Reconocimiento de obstáculos

Como fue mencionado antes, en este proyecto se utiliza el sensor de ultrasonido con la intención de identificar los diferentes obstáculos ubicados en el espacio desconocido. Este proceso inicia con un reconocimiento parcial del mundo, recorriendo el área total de trabajo. Por lo tanto es necesario ingresar el punto inicial, final y el área que se debe analizar.
                        
                                         

Luego del ingreso de los datos el robot analiza el área de trabajo y luego identifica los vértices con el fin de generar el grafo de visibilidad. Mediante el uso del sensor de ultrasonido se genera el mapa de un obstaculo mostrado en la parte derecha de la siguiente imagen.


Con dos obstáculos se genera el siguiente mapa



Vídeo de identificación de un obstáculo



Generación de Grafos de Visibilidad y ruta más corta


Luego del reconocimiento de los obstáculos y de la construcción del mapa, se puede realizar el grafo de visibilidad y luego partiendo de este y mediante el algoritmo de Dijkstra se encuentra la ruta mas corta, la cual es recorrida finalmente por el robot. En la siguiente imagen se muestra el grafo de visibilidad generado por el robot al identificar el are con un obstáculo. 




En la siguiente imagen se muestra el grafo de visibilidad generado por el robot al identificar el are con dos obstáculos. 



domingo, 11 de diciembre de 2011

APLICACIÓN DE LA PLANIFICACIÓN ABSTRACTA EN LOS SISTEMAS DE ROBOTS AUTÓNOMOS


1.     Introducción



Los robots móviles autónomos se han estado desarrollando con el objetivo de llevar a cabo tareas complejas en diferentes ambientes, tanto en hábitats humanos como lugares menos amigables, tales como planetas distantes y regiones bajo el agua. 

Para entornos interiores, se proyecta la posibilidad de crear robots móviles autónomos que lleven a cabo tareas solicitadas por los residentes de un edificio o los trabajadores de una planta, tales como: la entrega de correo, guiar visitantes, ir a buscar café, recoger una impresión, o simplemente entregar un mensaje u objeto de un lugar a otro.

En este trabajo se presenta una primera aproximación a la situación planteada donde se centrará la atención en la planificación de tareas, como el nivel superior de abstracción del sistema. Esta abstracción se hace necesaria dado que el uso de planes de muy bajo nivel implicaría ejecutar varios cientos de pasos para resolver cierto problema de navegación donde el espacio de planes de esta magnitud sería tan grande que aun las técnicas de planificación más sofisticadas probablemente no llegarían a una solución en una cantidad razonable de tiempo.

Se presenta a continuación la arquitectura del sistema que integra una capa de planificación de tareas, una capa de planificación de movimientos y por último el ejecutor, que para este caso es un robot lego NXT.




A grandes rasgos el funcionamiento se resume en 4 pasos:

·         El usuario ingresa la descripción del mundo accediendo a la interfaz gráfica
      El usuario especifica los objetivos que debe llevar a cabo el robot
·         El programa genera los archivos Domain.PDDL y Problem.PDDL
·         El planificador arroja una solución, para cumplir los objetivos minimizando la distancia recorrida
·         El programa captura dicha solución y se comunica con la aplicación AppCells para que esta se encargue de ejecutar cada uno de los pasos planteados en el plan.

2.     Descripción del mundo


Se implemento una sección en la que el usuario pueda describir el entorno en el cual trabajará el robot, para ello se consideraron tres aspectos principales:


La inclusión de las áreas.
La inclusión de puntos de conexión entre áreas
La inclusión de los obstáculos al interior de las áreas. 


Un área queda completamente determinada especificando:

el punto del extremo superior izquierdo y el extremo inferior derecho, en un plano coordenado (x,y)


Para la especificación de los puntos de conexión entre áreas se requiere de:

la dupla de áreas conectadas
la ubicación del punto de conexión, en el mismo plano coordenado (x,y)

 

La inclusión de los obstáculos hace parte de la última etapa, donde se hace necesario especificar:

El área donde está ubicado
Los nodos, es decir puntos (x,y) que determinan el obstáculo.




3.Creación del Domain.PDDL y  Problem.PDDL


A esta instancia el robot tiene conocimiento del entorno de trabajo pero aún no se asignan las tareas para empezar un proceso de planificación.

El estandar para llevar a cabo dicho procedimiento es dividir la información en dos archivos que recibe el planificador LPG  como entradas, que consisten de un dominio y un problema, en el dominio se establece el conjunto de estados y el conjunto de acciones, por lo que es estático, es decir, no varía con un problema u otro.

Por otro lado el problema hace referencia a un caso específico y en él está contenida toda la información correspondiente al estado inicial y el estado final.



Con el fin de ilustrar la aplicabilidad de la planificación de tareas a un problema de navegación cotidiano se presenta un mapa que puede corresponder a la distribución de un espacio de trabajo, posteriormente la especificación del dominio y el problema  representarán dicho espacio.

Suponga un espacio distribuido como el de la figura, en él se encuentran 6 áreas, con conexiones definidas solo entre algunas de ellas, además de la inclusión de obstáculos en las áreas 1, 3, 5 y 6.



El proceso de composición del dominio no requiere mayores esfuerzos, se definirán los tipos de objetos que se pueden crear que son: sitio y robot, las funciones recorrido, para almacenar la distancia recorrida por el robot y la función distancia, para almacenar el costo del viaje de un área a otra.

Se crearán además predicados para denotar la ubicación actual del robot, marcar un área como visitada y puntualizar  la existencia de una conexión entre áreas. Por último se creará la acción viajar, que le permitirá al robot desplazarse, siempre y cuando se cumplan la restricciones planteadas.

Usando la sintaxis PDDL el archivo Domain tiene la siguiente forma.











Por otro lado la composición del Problem se convierte en la traducción de la información ingresada por el usuario a la sintaxis PDDL, se puede notar que se crearon 6 objetos de tipo sitio y un objeto de tipo robot.
Se procede a definir los términos en los que se encuentra el estado inicial, definiendo: ubicación inicial, conexiones entre áreas y distancia entre las mismas.
Consecuentemente son agregadas las condiciones del estado final, es decir los objetivos, que consisten para este caso en visitar las 6 áreas definidas y por último se establece una métrica, la cual tiene la finalidad de determinar la calidad de un plan respecto a la minimización del recorrido.

Usando la sintaxis PDDL el archivo Problem tiene la forma expuesta en el siguiente codigo

























5.     Proceso de planificación Abstracta



El problema descrito anteriormente solo contiene seis salas dado que por cuestiones de espacio tener un problema más grande supone un archivo muy extenso para presentar en este artículo, en la práctica, la utilidad de este proceso muestra sus bondades con una situación de quince áreas o más, donde no es siquiera apreciable una solución observando un mapa o la descripción del mundo.

La ejecución del planificador bajo el Domain y Problem descrito anteriormente presenta una solución como se muestra en la siguiente imagen:












6.     Proceso de planificación de movimientos


Para la ejecución del plan se procede a leer el archivo generado por el planificador, extrayendo la información necesaria para componer un archivo .txt que sea interpretable por la aplicación appcells.

El archivo generado deberá estar compuesto por:
è El punto inicial y el punto final
è Dos puntos que determinan la margen del entorno de trabajo
è Cantidad de obstáculos
è Nodos por cada obstáculo
è Nodos del obstáculo

Como se muestra en la siguiente imagen:  


AppCells comprenderá cada uno de estos archivos como una instrucción y procederá a encontrar la ruta al interior de la sala que le permita viajar del punto inicial al punto final evitando los obstáculos, en la siguiente imagen se presenta el mapa generado, incluidos los obstáculos y los puntos inicial y final.



El programa para cumplir el objetivo, tal y como se plantea en el dibujo es enviado al robot lego NXT usando el protocolo Bluetooth.

Para este propósito, el procedimiento fue crear un “NXT Project” y el main se corre como : “LeJOS NXT program”.



7.     Conclusiones




Los resultados de la planificación para estos entornos ha resultado ser satisfactoria en el sentido de que siempre retornará una solución si esta existe, y el proceso asegura entregar la mejor de ellas para la ejecución.

Dado que el proceso de planificación será ejecutado por un computador y luego son enviadas  instrucciones específicas al robot, el costo computacional puede elevarse conforme crezcan las dimensiones del problema disponiendo solo de las capacidades del computador, que para estas aplicaciones es bastante aceptable.

Aunque la planificación abstracta propone un modelo muy ideal, el planificador de movimientos AppCells debe lidiar con aspectos del entorno que afectan el desempeño, estos son debidamente tomados en consideración por un módulo de corrección de errores, pero su exactitud absoluta no se puede asegurar, por lo que asignarle al robot un plan extenso, supone acumulación de errores y una diferencia considerable entre la trayectoria teórica y la real.

Los avances en el campo de la visión artificial serian de gran utilidad en un sistema autónomo como el que aquí se expone, dado que puede dotar al robot de una visualización del entorno en tiempo real, haciéndolo tolerante a ambientes dinámicos.


Escrito por: Andrés Felipe Gutiérrez Salazar. Grupo SINTELWEB. Universidad Nacional de Colombia Sede Medellín.