11/11/2015

Sphero-Carto

Le but de cet article est de proposer une utilisation du robot Sphero d'Orbotix pour établir la cartographie d'un environnement.
le code est disponible là : https://drive.google.com/file/d/0B0zEK4yLB5C6TUhLc0FRbVVKMVU/view?usp=sharing

En effet dans le projet Smag0, et d'après les trucs que j'ai pu lire un peu partout (SMA Ferber...), un robot/agent autonome se doit d'avoir une représentation de son environnement. J'avais donc envisagé il y a longtemps, d'utiliser le robot Sphero afin d'établir une cartographie de l'environnement en le faisant se balader dans l'environnement, en récupérant ses coordonnées, et en notant les points de collision. Cela pourrait permettre, par exemple à déterminer si une pièce est rangée et s'il faut envoyer d'autres robots autonomes pour la ranger.

Exemple d'application au projet Smag0 : Sphero établit une cartographie un jour où la chambre est rangée et la stocke comme étant la cartographie de référence avec points de collision pour les pieds de meubles, et autres objets. Lorsque les jours suivants, Sphero repasse, on compare les deux cartographies, si les points de collision se sont déplacés : les objets ont bougé, et il faut envisager de les ranger, ou déterminer si leur nouvelle position est respectable.

Après cette brève introduction, passons au fourneau :


LA RECETTE DU SPHERO-CARTO.
Ingrédients :
- 1 script sphero.js permettant d'accéder au fonctionnalités du robot Sphéro : https://github.com/orbotix/sphero.js  (les fonctionnalités sont là : https://github.com/orbotix/sphero.js/blob/master/lib/devices/sphero.js )
- 1 serveur node.js
- quelques workers JS...


"C'est dans les vieux pots qu'on fait la meilleure soupe"
Pensons maintenant notre appli comme un système multi-agents, comme des programmes autonomes qui communiquent entre eux, nous aurons par exemple :
- un module (ou worker en javascript) qui s'occupera du serveur de fichier,
- un autre de la gestion des commandes du robot sphero,
- un autre de l'interface visuelle,
- un autre s'occupera de la conception de la carte,
- on pourra en trouver un qui se chargera du stockage de l'information,
- un déterminera l'algorithme à utiliser pour une meilleure exploration de l'environnement...
- ... (on pourra en ajouter d'autre selon le besoin et les fonctionnalités envisagées)


Le serveur de fichier : 
Commençons par installer nodejs si ce n'est pas encore fait, puis installez le module sphero : "$ npm install sphero" comme préconisé ici https://github.com/orbotix/sphero.js

le module socket.io et le module keypress "npm install socket.io",  `npm install keypress`

Ensuite, je me suis basé sur le tutoriel du nouveau site P5.js pour l'interaction entre le serveur node.js et le module d'affichage p5.js : http://p5js.org/tutorials/ ou https://github.com/processing/p5.js/wiki/p5.js,-node.js,-socket.io

Choix a faire : Socket ? worker ?

code  de base du serveur serveur.js , à lancer avec la commande : node serveur.js


// http://smag0.blogspot.fr/2015/11/sphero-carto.html
// HTTP Portion
var http = require('http');
// URL module
var url = require('url');
var path = require('path');
// Using the filesystem module
var fs = require('fs');
// make sure you install this first - `npm install keypress`
var keypress = require("keypress");
var server = http.createServer(handleRequest);
server.listen(8080);
console.log('Server started on port 8080');
//SPHERO
var sphero = require("sphero");
var orb = sphero("COM3");
var stop = orb.roll.bind(orb, 0, 0),
  roll = orb.roll.bind(orb, 150);
var detectionCollisionInterval; //interval pour la detection de collision
var collisionBool=0;
var xSphero,ySphero=0;
var direction=0;
function handleRequest(req, res) {
  // What did we request?
  var pathname = req.url;
  // If blank let's ask for index.html
  if (pathname == '/') {
    pathname = '/index.html';
  }
  // Ok what's our file extension
  var ext = path.extname(pathname);
  // Map extension to file type
  var typeExt = {
    '.html': 'text/html',
    '.js': 'text/javascript',
    '.css': 'text/css'
  };
  // What is it?  Default to plain text
  var contentType = typeExt[ext] || 'text/plain';
  // User file system module
  fs.readFile(__dirname + pathname,
    // Callback function for reading
    function(err, data) {
      // if there is an error
      if (err) {
        res.writeHead(500);
        return res.end('Error loading ' + pathname);
      }
      // Otherwise, send the data, the contents of the file
      res.writeHead(200, {
        'Content-Type': contentType
      });
      res.end(data);
    }
  );
}
// WebSocket Portion
// WebSockets work with the HTTP server
var io = require('socket.io').listen(server);
var socketA;
// Register a callback function to run when we have an individual connection
// This is run for each individual user that connects
io.sockets.on('connection',
  // We are given a websocket object in our function
  function(socket) {
    console.log("We have a new client: " + socket.id);
socketA=socket;
    // When this user emits, client side: socket.emit('otherevent',some data);
    socket.on('mouse',
      function(data) {
        // Data comes in as whatever was sent, including objects
        console.log("Received: 'mouse' " + data.x + " " + data.y);
        // Send it to all other clients
        socket.broadcast.emit('mouse', data);
        // This is a way to send to everyone including sender
        // io.sockets.emit('message', "this goes to everyone");
      }
    );
    socket.on('color',
      function(data) {
        // Data comes in as whatever was sent, including objects
        console.log("Received: 'color' " + data.r + " " + data.g + " " + data.b);
        orb.color({
          red: data.r,
          green: data.g,
          blue: data.b
        });
        // Send it to all other clients
        // socket.broadcast.emit('mouse', data);
        // This is a way to send to everyone including sender
        // io.sockets.emit('message', "this goes to everyone");
      }
    );
    socket.on('start',
      function() {
        // Data comes in as whatever was sent, including objects
        console.log("Received: 'start' ");
        start();
      }
    );
    socket.on('stop',
      function() {
        // Data comes in as whatever was sent, including objects
        console.log("Received: 'stop' ");
        clearInterval(detectionCollisionInterval);
        orb.roll(0, 0);
      }
    );
    socket.on('startCalib',
      function() {
        // Data comes in as whatever was sent, including objects
        console.log("Received: 'startCalib' ");
        console.log("::START CALIBRATION::");
        orb.startCalibration();
      }
    );
    socket.on('stopCalib',
      function() {
        // Data comes in as whatever was sent, including objects
        console.log("Received: 'stopCalib' ");
        initialiseLocator();
        console.log("::FINISH CALIBRATION::");
        orb.finishCalibration();
      }
    );
    socket.on('disconnect', function() {
      console.log("Client has disconnected");
    });
  }
);
////////////////////////////////
// SPHERO
////////////////////////////////
orb.connect(function() {
  listen();
  orb.color("green");
  //option configurelocator
  initialiseLocator();
  orb.getBluetoothInfo(function(err, data) {
    console.log("bluetooth info fetched");
    if (err) {
      console.error("err:", err);
    }
    console.log("data:", data);
  });
   orb.detectCollisions();
  // orb.streamVelocity();
  // orb.streamGyroscope();
  var opts = {
    n: 200,
    m: 1,
    mask1: 0x00000000,
    pcnt: 0,
    mask2: 0x0D800000
  };
  orb.setDataStreaming(opts);
  orb.on("velocity", function(data) {
    console.log("::STREAMING VELOCITY::");
    console.log("  data:", data);
  });
  orb.on("dataStreaming", function(data) {
    //console.log("streaming data packet recieved");
 //  console.log("  data:", data);
 xSphero=data.xOdometer.value;
 ySphero=data.yOdometer.value*-1;
 collisionBool=0;
    console.log(data.xOdometer.value+" "+data.yOdometer.value);
 var dataToSend = {
    x: xSphero,
    y: ySphero,
z: collisionBool // 0 car pas de collision
  };
 socketEmit("position", dataToSend);
  });
  orb.on("gyroscope", function(data) {
    console.log("::STREAMING GYROSCOPE::");
    console.log("  data:", data);
  });
  orb.on("collision", function(data) {
    console.log("collision detected");
   // console.log("  data:", data);
    orb.color("red");
    collisionBool=1;
 var dataToSend = {
    x: xSphero,
    y: ySphero,
z: collisionBool // 0 car pas de collision
  };
 socketEmit("position", dataToSend);
    setTimeout(function() {
      orb.color("green");
   collisionBool=0;
    }, 1000);
  });
});
function socketEmit(entete , data){
if(socketA!=null){
socketA.emit(entete, data);
}
};
function start() {/*
orb.roll(200, direction);
//Determinons les premieres limites
//limite haute
while(collisionBool==0){
setInterval(function() {
orb.roll(200, direction);
}, 2000);
}
direction=direction*-1; //demi-tour
//limite basse
while(collisionBool==0){
setInterval(function() {
orb.roll(200, direction);
}, 2000); 
}
*/
if(collisionBool==0){
detectionCollisionInterval =setInterval(function() {
   //direction = Math.floor(Math.random() * 360);
    orb.roll(150, direction);
  }, 2000);
}else{
console.log("collision ne peut avancer");
direction = Math.floor(Math.random() * 360);
}
  // roll orb in a random direction, changing direction every second
 /* detectionCollisionInterval = setInterval(function() {
    var direction = Math.floor(Math.random() * 360);
    orb.roll(100, direction);
    //  readLocator()
  }, 2000);*/
};
function initialiseLocator() {
  var opts = {
    flags: 0x01,
    x: 0x0000,
    y: 0x0000,
    yawTare: 0x0
  };
  orb.configureLocator(opts, function(err, data) {
    console.log(err || "CONFIGURE LOCATOR data: " + data);
  });
  orb.setHeading(0, function(err, data) {
      console.log(err || "Heading réglé sur 0: " + data);
    });
direction=0;
};
function readLocator() {
  orb.readLocator(function(err, data) {
    if (err) {
      console.log("error: ", err);
    } else {
      console.log("dataLocator:");
      console.log("  xpos:", data.xpos);
      console.log("  ypos:", data.ypos);
      console.log("  xvel:", data.xvel);
      console.log("  yvel:", data.yvel);
      console.log("  sog:", data.sog);
      console.log(data);
      console.log(data[0]);
      console.log("");
    }
  });
};
function handle(ch, key) {
  var stop = orb.roll.bind(orb, 0, 0),
    roll = orb.roll.bind(orb, 60);
  if (key.ctrl && key.name === "c") {
    process.stdin.pause();
    process.exit();
  }
  if (key.name === "e") {
    orb.startCalibration();
  }
  if (key.name === "q") {
    orb.finishCalibration();
  }
  if (key.name === "up") {
    roll(0);
  }
  if (key.name === "down") {
    roll(180);
  }
  if (key.name === "left") {
    roll(270);
  }
  if (key.name === "right") {
    roll(90);
  }
  if (key.name === "space") {
    stop();
    clearInterval(detectionCollisionInterval);
  }
}
function listen() {
  keypress(process.stdin);
  process.stdin.on("keypress", handle);
  console.log("starting to listen for arrow key presses");
  process.stdin.setRawMode(true);
  process.stdin.resume();
}


fichier sketch.js

//les exemples pour SPHERO : https://github.com/orbotix/sphero.js/blob/master/examples/
//https://github.com/orbotix/sphero.js

/*
 * @name Slider
 * @description You will need to include the 
 * <a href="http://p5js.org/reference/#/libraries/p5.dom">p5.dom library</a>
 * for this example to work in your own project.<br><br>
 * Move the sliders to control the R, G, B values of the background.
 */
var rSlider, gSlider, bSlider,speedSlider;
var myDiv0;
var rougeDiv;
var vertDiv;
var bleuDiv;
// Keep track of our socket connection
var socket;
var xSphero, ySphero;
var positionsSphero = [];
var positionSphero;

function setup() {
  // create canvas
  createCanvas(windowWidth, windowHeight);
  background(0);
  positionSphero = createVector(0, 0, 0);
  // Start a socket connection to the server
  // Some day we would run this server somewhere else
  socket = io.connect('http://localhost:8080');
  // We make a named event called 'mouse' and write an
  // anonymous callback function
  socket.on('mouse',
    // When we receive data
    function(data) {
      console.log("Got: " + data.x + " " + data.y);
      // Draw a blue circle
      fill(0, 0, 255);
      noStroke();
      ellipse(data.x, data.y, 80, 80);
    }
  );

  socket.on('position',
    // When we receive data
    function(data) {
      console.log("Position: " + data.x + " " + data.y + " " + data.z);
      // Draw a blue circle
      // fill(100, 100, 255);
      // noStroke();
      // ellipse(data.x, data.y, 10, 10);
      xSphero = data.x;
      ySphero = data.y;
      collision = data.z;
      positionSphero = createVector(xSphero, ySphero, collision);
      append(positionsSphero, positionSphero);
    }
  );

  textSize(15)
  noStroke();

  // create sliders
  rSlider = createSlider(0, 255, 255);
  rSlider.position(720, 20);
  gSlider = createSlider(0, 255, 230);
  gSlider.position(720, 50);
  bSlider = createSlider(0, 255, 107);
  bSlider.position(720, 80);
  speedSlider= createSlider(0, 255, 66);
  speedSlider.position(720, 110);

  //boutons
  button = createButton('start Calibration');
  button.position(20, 120);
  button.mousePressed(startCalib);
  button = createButton('stop Calibration');
  button.position(150, 120);
  button.mousePressed(stopCalib);
  button = createButton('start');
  button.position(20, 150);
  button.mousePressed(start);
  button = createButton('stop');
  button.position(100, 150);
  button.mousePressed(stop);
    button = createButton('clear');
  button.position(180, 150);
  button.mousePressed(clear);

  //affiche
  rougeDiv = document.getElementById("rouge");
  vertDiv = document.getElementById("vert");
  bleuDiv = document.getElementById("bleu");
  xDiv = document.getElementById("positionX");
  yDiv = document.getElementById("positionY");
}

function draw() {
  var r = rSlider.value();
  var g = gSlider.value();
  var b = bSlider.value();
  var speed=speedSlider.value();
  background(r, g, b);
  text("red", 800, 20);
  text("green", 800, 50);
  text("blue", 800, 80);
   text("speed", 800, 110);
   
  // console.log(r, g, b);
  if ((r != rougeDiv.innerHTML) || (g != vertDiv.innerHTML) || (b != bleuDiv.innerHTML)) {
    rougeDiv.innerHTML = r;
    vertDiv.innerHTML = g;
    bleuDiv.innerHTML = b;
    sendRGB(r, g, b);
  }
  xDiv.innerHTML = xSphero;
  yDiv.innerHTML = ySphero;
  translate(width / 2, height / 2);
  fill(0);
  ellipse(xSphero, ySphero, 10, 10);
  for (i in positionsSphero) {
    var position = positionsSphero[i];
    if (position.z == 0) {
      fill(0, 255, 0);
    } else {
      fill(255, 0, 0);
    }
    ellipse(position.x, position.y, 3, 3);
  }
}


function start() {
  console.log("start p5");
  socket.emit('start', null);
}

function stop() {
  console.log("stop p5");
  socket.emit('stop', null);
}

function clear() {
  console.log("clear");
  positionsSphero = [];
  positionSphero = createVector(0, 0, 0);
 // socket.emit('clear', null);
}

function startCalib() {
  console.log("start calib");
  socket.emit('startCalib', null);
}

function stopCalib() {
  console.log("stop calib");
  socket.emit('stopCalib', null);
}


/*
function mouseDragged() {
  // Draw some white circles
  fill(255);
  noStroke();
  ellipse(mouseX, mouseY, 80, 80);
  // Send the mouse coordinates
  sendmouse(mouseX, mouseY);
}*/
//ENVOI de la couleur
function sendRGB(r, g, b) {
  // Make a little object with rgb 
  var data = {
    r: r,
    g: g,
    b: b
  };
  // Send that object to the socket
  socket.emit('color', data);
}
// Function for sending to the socket
function sendmouse(xpos, ypos) {
  // We are sending!
  console.log("sendmouse: " + xpos + " " + ypos);

  // Make a little object with  and y
  var data = {
    x: xpos,
    y: ypos
  };

  // Send that object to the socket
  socket.emit('mouse', data);
}



fichier index.html

 <!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Sphero</title>
    <script src="libraries/p5.js" type="text/javascript"></script>

    <script src="libraries/p5.dom.js" type="text/javascript"></script>
    <script src="libraries/p5.sound.js" type="text/javascript"></script>

    <style> body {padding: 0; margin: 0;} canvas {vertical-align: top;} </style>

   <!-- <script language="javascript" type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.2.9/p5.min.js"></script>-->
    <script language="javascript" type="text/javascript" src="sketch.js"></script>
    <script language="javascript" type="text/javascript" src="/socket.io/socket.io.js"></script>
  </head>
  <body>
  <!-- <div id="connected" style="width:100px;height:100px">not connected</div> -->
  <div id="rouge">r</div>
  <div id="vert">b</div>
  <div id="bleu">v</div>
  <div id="positionX">X</div>
   <div id="positionY">Y</div>
  </body>
</html>

le code est disponible là : https://drive.google.com/file/d/0B0zEK4yLB5C6TUhLc0FRbVVKMVU/view?usp=sharing


Pour la gestion des webworkers avec nodejs : npm install webworker

01/11/2015

Kit de matériel pour construire le pcduino Rover

Maintenant que j'ai réussi à construire mon petit PcDuino Rover, je vous propose d'en faire autant,
si le kit vous intéresse, je suis en train de le préparer, n'hésitez pas à vous manifester pour faire partie des premiers servis. 

18/09/2015

Inventeur, innovateur, entrepreneur

Pour le mot "inventeur", sur Wikipedia, on trouve ceci :

-> Un inventeur est un individu qui invente c'est-à-dire qui est le premier à avoir l'idée.
Il faut le distinguer de l'innovateur et de l'entrepreneur.



-> Un innovateur est une personne qui innove, c'est-à-dire qui produit une innovation. Il se définit donc au premier titre par la nature de sa contribution, qui est nouvelle.
Il faut le distinguer d'un entrepreneur, qui, sans nécessairement apporter une contribution nouvelle, agit sur le monde et participe aussi à le transformer.

-> Le terme entrepreneur recouvre différentes significations connexes mais distinctes :
  • l'usage courant l'assimile à un chef d'entreprise, tantôt porteur d'un projet d'entreprise en phase de démarrage, tantôt dirigeant d'une entreprise d'avantage établie, à laquelle le plus souvent il s'identifie étroitement et personnellement ; [...]

On nous parle d'aide pour les entrepreneurs, de soutien à l'innovation, mais quelqu'un connaitrait-il une aide pour les inventeurs qui tâtonnent, bidouillent, essaie dans leur coin?

Inventeurs qui ne peuvent déposer de brevet pour toutes les géniales idée qu'ils produisent, et qui risquent dès qu'ils exposent leurs fameuses idées (afin de trouver le moindre financement pour leurs travaux) se les faire piquer par les "innovateurs" et les "entrepreneurs" , qui sauront, eux en tirer des bénéfices consequents...

Et vous ? Vous sentez-vous vous  personnellement plutôt inventeur, innovateur ou entrepreneur ?

À noter :  Smag0 recherche des inventeurs... Si vous vous sentez l'âme d'un inventeur, envoyez-moi un petit mail à scenaristeur@gmail.com 

08/08/2015

DreamCatcher, l'attrape rêves

DreamCatcher est une application gratuite opensource permettant de transmettre des informations aux objets connectes et autres robots de ma maison.
Par extension, elle peut être utilisée pour présenter et partager ses idées entre les humains également ;-) .

La dernière version 1 est accessible ici : http://smag-smag0.rhcloud.com/DreamCatcher .
ou plus facile à retenir (http://goo.gl/tViQ3Q) ... "t'es vicu trois culs avec t et i en minuscule" ;-D
(Le développement sur smartphone n'est pas encore totalement implémenté, à utiliser sur PC avec Chrome ou Firefox).
 [ Nouvelle version en cours de développement avec P5js en 3D : http://smag0.blogspot.fr/2015/12/dreamcatcher-ou-comment-partager-des.html ]

[ v1,v2 ou v3 ? faisons le point sur les versions de Dreamcatcher : http://smag0.blogspot.fr/2016/02/dreamcatcher-v3-integration-dans-meteor.html ]

Historique : 

L'idée de départ était de créer une interface pour le projet Smag0 (un robot qui range ma chambre).

Pour Smag0, nous avons besoin d'une interface simple pour transmettre des informations au robot (ou groupe de robots, objets connectes...) qui serait en mesure de ranger notre chambre, puisque c'est le but du projet.


Pour que ces "futurs hypothétiques robots" communiquent et échangent des informations, il a été pris parti de formater les informations au format RDF/OWL, ces informations décrivent des relations entre deux concepts, plutôt qu'un concept seul, sous forme de triplet.
(voir : Robolution + Homme 2.0 = Information 2.0)



Au départ, donc, cette interface devait servir, pour l'utilisateur, à transmettre facilement des informations à la maison, qui les partagerait ensuite avec les différents robots et objets connectés que l'on pourrait avoir dans notre maison.

Par extension, et au fil des développement, je me suis aperçu qu'elle pouvait également être utile pour exposer ses idées et les visualiser sous forme de graphes. Il est alors plus facile de partager ses idées.
Un petit schéma valant toujours mieux qu'un long discours, le graphe donne la possibilité d'atteindre directement l'information qui nous intéresse, et de cerner rapidement les informations qui sont liées.

Cette application dont le but est de faciliter la captation de mes idées ou de mes rêves a donc un nom tout trouvé : DreamCatcher (Attrape Revês)...

Le code source pour ceux qui voudraient modifier l'application est disponible en bas de la page de l'application.


Utilisation : 

L'utilisation de DreamCatcher est très simple.

Ouverture : 

A l'ouverture, un jeu de données est présent. Il suffit de cliquer dans l'espace de travail pour que le graphe correspondant à ces données prenne forme.
On peut alors zoomer avec la flèche "haut" du clavier et dézoomer avec la flèche "bas". Avec la souris, on peut aussi déplacer le graphe pour consulter une zone particulière.
La barre "espace" de votre clavier rétablit la position initiale.
Voir l'aide pour plus de fonctionnalités (nouveau graphe, sauvegarde du graphe sous forme d'image...)

Les données correspondantes au graphe apparaissent sur la droite sous forme de blocs bleus en dessous de "Dernière Activité".
Elles sont déjà enregistrées sous forme de triplet {sujet, prédicat, objet}.



En cliquant sur l'un de ces blocs bleus, vous le sélectionnez, il passe alors directement dans l'espace "Informations sélectionnées" et devient vert.
En même temps, la partie du graphe correspondant à cette information s'éclaire dans le graphe (si le graphe ne s'actualise pas automatiquement, cliquez à l'intérieur de l'espace de travail) :

  • le sujet du triplet en jaune,
  • la propriété (ou prédicat) en vert,
  • et l'objet du triplet en bleu.

Vous pouvez sélectionner plusieurs informations en même temps et les voir apparaître dans le graphe.
Pour les faire disparaître, il suffit de les désélectionner en cliquant sur le bloc vert correspondant. L'information redescend automatiquement dans l'espace "Dernière Activité" et redevient bleue .


Créer un nouveau Graphe

Pour créer un nouveau graphe, il suffit de cliquer dans l'espace de travail pour être certain qu'il soit bien activé, et de presser la touche "n" de votre clavier. (la touche "d" permet de recharger la démo).

Lorsque vous pressez la touche "n", l'espace de travail est nettoyé, et vous pouvez glisser les blocs "Chose/Thing" dans l'espace de travail pour décrire une nouvelle chose, idem pour "Acteur" et "Environnement"... ("Un type de chose" correspondant à une classe au sens OWL)

D'autres fonctionnalités sont en cours de développement, comme la modification des informations, l'ajout de propriétés à un sujet, la visualisation à différents niveaux, la recherche de liens avec les vocabulaires et bases de données existants (http://wiki.dbpedia.org/online-access/DBpediaLivehttp://lov.okfn.org/dataset/lov/), la création de sessions où l'on peut travailler à plusieurs sur le même graphe, l'utilisation de l'interface DreamCatcher pour fusionner les idées comme évoqué ici : https://www.linkedin.com/pulse/large-concept-collider-georges-le-nigen , une interface mobile permettant d'enregistrer messages vocaux et formater infos pour DreamCatcher...

N'hésitez pas proposer des modifications ou critiquer, proposez également de nouvelles fonctionnalités, et surtout dites-moi ce que vous n'avez pas compris... c'est le meilleur moyen de faire avancer les choses, et de proposer une interface la plus accessible possible pour proposer cette application aussi bien à mon fils de 8 ans qu'à ma grand-mère de 70 ans... ;-) 

Utilisez les commentaires au bas de cet article ou l'espace de discussion prévu à cet effet : https://groups.google.com/forum/#!topic/smag0/HpqEGB7cH4g


Accéder à DreamCatcher http://goo.gl/tViQ3Q

 [ Nouvelle version en cours de développement avec P5js : http://smag0.blogspot.fr/2015/12/dreamcatcher-ou-comment-partager-des.html ]


[... Document en cours de création...]

13/07/2015

Visualiser le graphe d'une ontologie online (Processing, Javascript, XML)

Vous avez un fichier (ontologie ou base de connaissance) au format owl ou rdf, vous pouvez visualiser les classes le graphe (enfin pour l'instant, il n'y a que les classes : http://smag-smag0.rhcloud.com/saisie_projet (update : une version plus récente : http://smag0.blogspot.fr/2015/08/dreamcatcher-lattrape-reves.html )

Si vous n'en avez pas, vous pouvez tester avec la méthode Diamond, http://smag-smag0.rhcloud.com/ontologies/diamondMethode.owl que l'on a créé précedemment (http://smag0.blogspot.fr/2015/06/comment-creer-une-methode-pour-smag0-la.html)

Ou mieux, encore avec la pizza.owl ( http://protege.stanford.edu/ontologies/pizza/pizza.owl ), bien connue de tous ceux qui se sont intéressés un jour aux ontologies ;-).

--> possibilité de charger un fichier depuis votre disque dur
--> possibilité de glisser de nouveaux éléments pour créer un nouveau Projet (projet, acteur, environnement...)
--> possibilité de déplacer les noeuds,
--> possibilité de selectionner les noeuds (se positionner sur un noeud + touche CTRL)
--> possibilité de sauvegarde/chargement  des graphes ( les données sont stockées sur votre ordinateur, dans le localstore (en test) :



Tout ça avec P5Js, version web de Processing, en mode Javascript... 

02/07/2015

Robolution, Homme 2.0, Information 2.0

ROBOLUTION


J'entends parler, de-ci, de-là, de Robolution, comme quoi, d'ici 10 à 15 ans, les robots seront partout, que d'ici 5 ans, il y aura je ne sais combien d'objets connectés...

Mais ça me fait peur, moi, ils vont me prendre mon boulot, et je serais espionné, avec toutes ces caméras et ces capteurs qui collectent des informations sur moi, et les envoient à je ne sais quelle multinationale...

Il parait qu'ils seront plus intelligents que nous, avec leur puissance de calcul et auront accès à beaucoup pus d'informations, puisqu'ils seront connectés...

Et moi??? Qu'est-ce que je deviens, là-dedans ???

Vais-je être exterminé, les robots considérant qu'ils n'ont pas besoin des êtres humains (êtres inférieurs) ???

Dans cet article : https://wtvox.com/2015/06/roboethics-universal-robot-rights-ethics-and-legislation/, par exemple, il est déjà question de leurs droits, savoir si on a le droit de "tuer un robot" qui serait plus intelligent que nous, et à qui on aurait appris à réfléchir, à avoir des émotions...


HOMME 2.0

L'homme, pour survivre, a dû s'adapter aux nombreux changements de son environnement. Il semble que nous nous trouvions engagés dans l'un de ces changements majeurs. La course à la technologie que nous menons actuellement provoque des changements importants dans les habitudes et les comportements, et nous avons du mal à imaginer jusqu'où cela va nous mener.

STOP ! 

On a loupé une marche, ça va trop vite, et l'humain de base que je suis, préoccupé par son travail, ses enfants, son quotidien,... n'a pas pris le train dès le départ, on m'a catapulté dedans plus tard, et il avait déjà une bonne vitesse, ce train...

On me propose des outils (smartphone, objets connectés,...) qui certes sont sensés me rendre la vie plus facile en me fournissant des tonnes d'infos, mais j'ai raté le passage en gare de la "Société de l'Information", cette société dont on nous vantait les mérites dans les années 90 a déjà disparu, remplacée par des sociétés plus innovantes, plus connectées, plus plus plus ...

Mais l'information n'a pas connu sa révolution et c'est pourtant un point d'étape obligé, si l'homme ne veut pas se retrouver "exterminé" par une société de robots qui s'approprieraient ces informations...

Dans les années 80-90, on a usé du concept de "Société de l'Information", car on avait accès à des tonnes d'informations, grâce à Internet, mais une fois consultée, on s'en moquait, ou on la retenait, on l'exploitait peu...


INFORMATION 2.0


Aujourd'hui, les Intelligences Artificielles (IA) sont capables de capter, stocker, relier, interpréter, fusionner, traiter des données instantanément, elles sont supérieures à nous dans ce domaine.

Pour ne pas être dépasser, je dois moi aussi apprendre à communiquer avec ces intelligences artificielles et ces robots.

L'information de base, comme je la connais, comme je l'exploite au quotidien est matérialisable sous forme de textes, d'idée, de concepts définis dans un dictionnaire.

Mais l'information doit évoluer, être précisée...  On ne peut , par exemple plus se contenter de dire " ma maison", car cette notion regroupe des paramètres particuliers, des données différentes en fonction de chacun.
Si je dis "Je prends le bus pour venir", on ne saura de quel bus il s'agit réellement que si on connait le point de départ et le point d'arrivée, et encore, il faudra prendre en compte les habitudes, le contexte...

On a maintenant besoin de détailler l'information, il faut passer à l'information 2.0


Qu'est ce que l'information 2.0 ?

Quand on parle d'information 2.0, on ne parle plus d'un mot, d'une idée, ou d'un concept, mais d'une relation, d'une propriété, qui peut évoluer, ou encore être différente selon les points de vue.

La structure de base d'une information 2.0 est donc un triplet, et permet de décrire tout et n'importe quoi, comme une méthode (http://smag0.blogspot.fr/2015/06/visualiser-un-methode-pour-la-modifier.htmll).

Un triplet est un ensemble de trois élements tel que celui-ci  {sujet, predicat, objet} (https://fr.wikipedia.org/wiki/Resource_Description_Framework ) et permet d'établir une relation entre deux concepts, on retrouve une structure identique en xml, avec des elements, des clés et des valeurs.

on écrire par exemple  :
{VoitureDeDavid, type, Voiture }
{VoitureDeDavid, couleur, "jaune" }
{VoitureDeDavid, propriétaire, David }
{VoitureDeDavid, vitesse_de_pointe, 120Km/h}
{David, type, Humain}
{Voiture, sous_classe_de, Vehicule}
{VoitureDeDavid, marque, "Opel"}
...etc...
ainsi , quand on utilisera VoitureDeDavid, toutes les propriétés qu'on vient de rattacher pourront être exploitables, et visualisables en un instant, ou filtrables par un mécanisme de requêtes(Sparql)

Et RDF, permet de surcroît d'interconnecter les sources d'informations,et les graphes, permettent une visualisation et une appropriation plus claire de l'information, de la même manière que les cartes mentales, ou mindmap .

Les mindmaps sont une première étape, pour passer à l'information 2.0, car elles relient deux concepts, mais il leur manque souvent la nature du lien, ce que fournit RDF...

Une autre piste à explorer pour le stockage de grandes quantités d'informations est SPARK



19/06/2015

Visualiser une méthode pour la modifier


Depuis l'article d'hier, où l'on a vu comment enregistrer une méthode simple pour l'envoyer à notre maison, ou à tout système Smag0, je l'ai un petit peu remaniée.
 Pour quelle soit encore plus simple, j'ai utilisé le format .xls propre à Excel... Qui ne connait pas Excel... (Possible aussi avec LibreOffice, Openoffice...).

J'ai donc repris la méthode que l'on a confectionné hier, et j'en ai fait un fichier .xls de trois colonne, la première représentant un sujet, la deuxième, une propriété, et la troisième l'objet au sens de RDF (voir l'article précédent pour ceux qui auraient loupé la séance d'hier) avec nos déclarations :

CuireDesPâtes rdf:type Methode
FaireBouillirEau rdf:type Etape
AjouterSel rdf:type Etape
VerserPâtes rdf:type Etape
Remuer rdf:type Etape
Attendre10Min rdf:type Etape
EgoutterPâtes rdf:type Etape
CuireDesPâtes dc:hasPart FaireBouillirEau
CuireDesPâtes dc:hasPart AjouterSel
CuireDesPâtes dc:hasPart VerserPâtes
CuireDesPâtes dc:hasPart Remuer
CuireDesPâtes dc:hasPart Attendre10Min
CuireDesPâtes dc:hasPart EgoutterPâtes
CuireDesPâtes rdf:first FaireBouillirEau
FaireBouillirEau xhv:next AjouterSel
AjouterSel xhv:next VerserPâtes
VerserPâtes xhv:next Remuer
VerserPâtes xhv:next Attendre10Min
Attendre10Min xhv:next EgoutterPâtes
EgoutterPâtes xhv:next MethodeServirPâtes
FaireBouillirEau dc:hasPart SortirCasserole
FaireBouillirEau dc:hasPart RemplirEau
FaireBouillirEau dc:hasPart PoserSurGaziniere
FaireBouillirEau dc:hasPart AllumerLeFeu
SortirCasserole dc:hasPart AllerDevantPlacardBasGauche
SortirCasserole dc:hasPart OuvrirPortePlacardBasGauche
SortirCasserole dc:hasPart AttraperCasserole
SortirCasserole dc:hasPart Reculer
SortirCasserole dc:hasPart FermerPlacardBasGauche
SortirCasserole dc:hasPart SeDeplacerVersEvier
AllerDevantPlacardBasGauche xhv:next OuvrirPortePlacardBasGauche
OuvrirPortePlacardBasGauche xhv:next AttraperCasserole
AttraperCasserole xhv:next Reculer
Reculer xhv:next FermerPlacardBasGauche
FermerPlacardBasGauche xhv:next SeDeplacerVersEvier
SeDeplacerVersEvier xhv:next RemplirEau
MethodeServirPâtes rdf:type Methode
CuireDesPâtes xhv:next MethodeServirPâtes
PoserSurGaziniere xhv:next AllumerLeFeu
RemplirEau dc:hasPart PlacerCasseroleSousRobinet
RemplirEau dc:hasPart AllumerRobinet
RemplirEau dc:hasPart RemplirCasseroleAuTroisQuarts
RemplirEau dc:hasPart FermerRobinet
FermerRobinet xhv:next PoserSurGaziniere
PlacerCasseroleSousRobinet xhv:next AllumerRobinet
AllumerRobinet xhv:next RemplirCasseroleAuTroisQuarts
RemplirCasseroleAuTroisQuarts xhv:next FermerRobinet
FermerRobinet xhv:next PoserSurGaziniere


 Bon, ok, j'ai rajouté quelques petits trucs depuis hier.

Mais ça commence à devenir intéressant...

ça nous donne ça  :




En utilisant Processing et la librairie Traer.physics un peu remaniée ( pour pouvoir ensuite l'intégrer dans une page web, j'ai utilisé cette version ci-> http://svbreakaway.info/tp-downloads.php#tpjs )

Pour télécharger le code Processing c'est ici :
https://drive.google.com/file/d/0B0zEK4yLB5C6MEhnVkdlZC1ZQ0U/view?usp=sharing

reste à modifier la couleur des liens, la longueur en fonctions de la propriété, indique clairement le nom des propriétés, pour facilement trouver la première sous-étape de chaque étape.

A voir, mais on peu peut-être modifier  :

VerserPâtesxhv:nextRemuer
VerserPâtesxhv:nextAttendre10Min

en une nouvelle étape de type Boucle ou Alternance (voir si ça existe, ou si on doit les créer) , ou je ne sais quoi, qui aurait une durée de 10 Minutes, serait composé de deux sous étapes : Remuer et Attendre, qui aurait elles aussi aurait une propriété durée...( remuer 10 secondes, attendre 1minute)

Prochaine étape : intégrer une méthode sur la page d'un projet .


A voir aussi avec tree.js http://mrdoob.github.io/three.js/examples/#webgl_nearestneighbour, pour visualiser les informations, http://workshop.chromeexperiments.com/ pour le GUI, ou https://github.com/blprnt/Infinite-Weft.html et http://sketchpad.cc/mwxwmUdIVC?exampleType=topic&exampleName= pour faire des tests