mardi 6 mai 2014

Nouvelle version

La commande se fait maintenant avec les touches du clavier. On ajoute un événement gérant l'appuie sur une touche et dans la fonction, on émet un socket en fonction de la touche appuyée que l'on détecte par son code présent dans keyCode :
touche    code
haut        38
bas         40
gauche   37
droite     39
espace    32
z             90
s             83

Ce qui donne l'instruction suivante:

document.addEventListener('keydown', function(e) {
              if(e.keyCode==38) socket.emit('avance','Avancer');
              if(e.keyCode==40) socket.emit('recule','Reculer');
              if(e.keyCode==37) socket.emit('gauche','A gauche');
              if(e.keyCode==39) socket.emit('droite','A droite');
              if(e.keyCode==32) socket.emit('arrete','Arreter');
              if(e.keyCode==90) socket.emit('haut','En haut');
              if(e.keyCode==83) socket.emit('bas', 'En bas');
             }, false);

Dans le fichier app.js peu de changements sauf que l'on gère maintenant le placement de la caméra vers le haut ou le bas, l'angle fourni au servomoteur numéro 2 est dans la variable cam qui est incrémentée ou décrémentée de 10.
Ce qui donne les deux fonctions suivantes appelées suite à l'appuie sur les touches z ou s:

socket.on('haut', function (message) {
    console.log('En haut');
    cam-=10;
    pwm.setPWM(2, 0, cam);
  });
  socket.on('bas', function (message) {
    console.log('En bas');
    cam+=10;
    pwm.setPWM(2, 0, cam);
  });   

Les programmes complets:
App.js:
var http = require('http');
var fs = require('fs');
var PwmDriver = require('adafruit-i2c-pwm-driver');

var pwm = new PwmDriver(0x40);
var servoMin = 150;
var servoMax = 600;
var cam=400;

var setServoPulse = function(channel, pulse) {
  var pulseLength;
  pulseLength = 1000000;
  pulseLength /= 60;
  print("%d us per period" % pulseLength);
  pulseLength /= 4096;
  print("%d us per bit" % pulseLength);
  pulse *= 1000;
  pulse /= pulseLength;
  return pwm.setPWM(channel, 0, pulse);
};

pwm.setPWMFreq(60);

var server = http.createServer(function(req, res) {
  fs.readFile('./index.html', 'utf-8', function(error, content) {
    res.writeHead(200, {"Content-Type": "text/html"});
    res.end(content);
  });
});

var io = require('socket.io').listen(server, { log: false});

io.sockets.on('connection', function (socket) {
  socket.emit('message', 'Vous êtes bien connecté !');
  socket.on('avance', function (message) {
    console.log('Avance');
    pwm.setPWM(0, 0, servoMin);
    pwm.setPWM(1, 0, servoMax);
  });
  socket.on('arrete', function (message) {
    console.log('Arrete');
    pwm.setPWM(0, 0, 410);
    pwm.setPWM(1, 0, 410);
  });
  socket.on('recule', function (message) {
    console.log('Recule');
    pwm.setPWM(0, 0, servoMax);
    pwm.setPWM(1, 0, servoMin);
  });
  socket.on('gauche', function (message) {
    console.log('A gauche');
    pwm.setPWM(0, 0, servoMax);
    pwm.setPWM(1, 0, servoMax);
  });
  socket.on('droite', function (message) {
    console.log('A droite');
    pwm.setPWM(0, 0, servoMin);
    pwm.setPWM(1, 0, servoMin);
  });

  socket.on('haut', function (message) {
    console.log('En haut');
    cam-=10;
    pwm.setPWM(2, 0, cam);
  });
  socket.on('bas', function (message) {
    console.log('En bas');
    cam+=10;
    pwm.setPWM(2, 0, cam);
  });   

});
server.listen(8080);

Index.html:
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>CamBot</title>
    </head>

    <body>
        <h1>Commande du robot</h1>

        <script src="/socket.io/socket.io.js"></script>
        <script>
            var socket = io.connect('http://192.168.1.10:8080');
            socket.on('message', function(message) {
              alert('Le serveur a un message pour vous: ' + message);
            })
            
            document.addEventListener('keydown', function(e) {
              if(e.keyCode==38) socket.emit('avance','Avancer');
              if(e.keyCode==40) socket.emit('recule','Reculer');
              if(e.keyCode==37) socket.emit('gauche','A gauche');
              if(e.keyCode==39) socket.emit('droite','A droite');
              if(e.keyCode==32) socket.emit('arrete','Arreter');
              if(e.keyCode==90) socket.emit('haut','En haut');
              if(e.keyCode==83) socket.emit('bas', 'En bas');
             }, false);

        </script>
    </body>
</html>

mercredi 8 janvier 2014

Création du serveur pour la commande à distance via une interface web



Quelques généralités:

Un serveur informatique va offrir à des clients différents services comme le partage de fichiers, le partage d'imprimante, le courrier électronique, l’accès à une page web ...
Un serveur web permet à des clients d'accéder à des pages web, c'est à dire des fichiers au format HTML à partir d'un navigateur installé sur un ordinateur distant.
Le serveur web est donc un logiciel capable d'interpréter des requêtes suivant un protocole HTTP et de fournir des réponses avec ce même protocole.
L'un des principaux serveur web sur le marché est Apache.

Node.js permet d'utiliser le langage JavaScript pour générer des pages web. Précisons d'abord que le JavaScript et le Java sont deux langages complètement différents, c'est pour des raisons historiques que leur nom se ressemble. C'est un langage de programmation interprété exécuté par le navigateur de l'internaute donc du côté client. Il permet de dynamiser une page web en ajoutant des interactions avec l'utilisateur. JavaScript était donc habituellement utilisé côté client et Node.js nous permet d'utiliser ce langage côté serveur en remplacement des langages habituels comme PHP.

L'intégration de la commande des servomoteurs avec le circuit adafruit se fait grâce à un module nodejs que l'on trouve sur npmjs.org.

Liens: 
http://fr.openclassrooms.com/informatique/cours/des-applications-ultra-rapides-avec-node-js
http://nodejs.developpez.com/tutoriels/javascript/node-js-livre-debutant/
http://blog.rueedlinger.ch/2013/03/raspberry-pi-and-nodejs-basic-setup/
http://fr.openclassrooms.com/informatique/cours/des-applications-ultra-rapides-avec-node-js/socket-io-passez-au-temps-reel
https://npmjs.org/package/adafruit-i2c-pwm-driver

Je vous laisse à la lecture de ces tutoriels pour les détails de la création du serveur.

Fichier principal:

var http = require('http');
var fs = require('fs');
var PwmDriver = require('adafruit-i2c-pwm-driver');

var pwm = new PwmDriver(0x40);

var servoMin = 150;
var servoMax = 600;

var setServoPulse = function(channel, pulse) {

  var pulseLength;
  pulseLength = 1000000;
  pulseLength /= 60;
  print("%d us per period" %pulseLength);
  pulse *= 1000;
  pulse /= pulseLength;
  return pwm.setPWM(channel, 0, pulse);
};

pwm.setPWMFreq(60);


var server = http.createServer(function(req, res) {

  fs.readFile('./index.html', 'utf-8', function(error, content) {
    res.writeHead(200, {"Content-Type": "text/html"});
  });
});

var io = require('socket.io').listen(server, { log: false});


io.sockets.on('connection', function (socket) {

  socket.emit('message', 'Vous êtes bien connecté !');
  socket.on('avance', function (message) {
    console.log('Avance');
    pwm.setPWM(0, 0, servoMin);
    pwm.setPWM(1, 0, servoMax);
  });
  socket.on('arrete', function (message) {
    console.log('Arrete');
    pwm.setPWM(0, 0, 410);
    pwm.setPWM(1, 0, 410);
  });
  socket.on('recule', function (message) {
    console.log('Recule');
    pwm.setPWM(0, 0, servoMax);
    pwm.setPWM(1, 0, servoMin);
  });
  socket.on('gauche', function (message) {
    console.log('A gauche');
    pwm.setPWM(0, 0, servoMax);
    pwm.setPWM(1, 0, servoMax);
  });
  socket.on('droite', function (message) {
    console.log('A droite');
    pwm.setPWM(0, 0, servoMin);
    pwm.setPWM(1, 0, servoMin);
  });
});
server.listen(8080);


Fichier index.html:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>CamBot</title>
    </head>

    <body>

        <h1>Commande du robot</h1>

        <p><input type="button" value="Avancer" id="Forward" /></p>

        <p><input type="button" value="Arreter" id="Stop" /></p>
        <p><input type="button" value="Reculer" id="Backward" /></p>
        <p><input type="button" value="A gauche" id="Left" /></p>  

        <p><input type="button" value="A droite" id="Right" /></p>      

        <script src="/socket.io/socket.io.js"></script>

        <script>
            var socket = io.connect('http://192.168.1.10:8080');
            socket.on('message', function(message) {
              alert('Le serveur a un message pour vous: ' + message);
            })
            var bouton1 = document.getElementById('Forward');
            var bouton2 = document.getElementById('Stop');
            var bouton2 = document.getElementById('Backward');
            var bouton2 = document.getElementById('Left');
            var bouton2 = document.getElementById('Right');
            bouton1.addEventListener('mousedown', function() {

              socket.emit('avance', 'Avancer');
            }, false);
            bouton1.addEventListener('mouseup', function() {
              socket.emit('arrete', 'Arreter');
            }, false);
            bouton2.addEventListener('mousedown', function() {

              socket.emit('arrete', 'Arreter');
            }, false);
            bouton3.addEventListener('mousedown', function() {
              socket.emit('recule', 'Reculer');
            }, false);
            bouton3.addEventListener('mouseup', function() {
              socket.emit('arrete', 'Arreter');
            }, false);
            bouton4.addEventListener('mousedown', function() {
              socket.emit('droite', 'A droite');
            }, false);
            bouton4.addEventListener('mouseup', function() {
              socket.emit('arrete', 'Arreter');
            }, false);
            bouton5.addEventListener('mousedown', function() {
              socket.emit('gauche', 'A gauche');
            }, false);
            bouton5.addEventListener('mouseup', function() {
              socket.emit('arrete', 'Arreter');
            }, false);
        </script>
    </body>
</html>


jeudi 26 septembre 2013

Contrôle des servomoteurs avec le raspberry pi

Deux servomoteurs à rotation continue serviront au déplacement, une bille appelée ball-caster servira à la stabilité de l'ensemble.

Un ou deux servomoteurs à rotation fixes, c'est à dire capables de garder une position fixe, serviront au contrôle de la caméra montée sur une tourelle.
Le contrôle du servomoteur se fait par un câble à trois fils, un pour la masse, un pour l'alimentation 5V et un pour le contrôle. Celui-ci se fait à l'aide d'un signal PWM, Modulation de Largeur d'Impulsion en français.
On génère un signal rectangulaire à fréquence fixe mais dont on modifie le rapport cyclique (duty cycle), c'est à dire le temps pendant lequel le signal reste à l'état haut.
Il n'existe qu'une sortie PWM implantée dans le GPIO du Raspberry Pi.
Pour avoir plus de sorties PWM, il est possible de générer ces signaux de manière logicielle avec le raspberry pi en contrôlant le temps pendant lequel une sortie reste à l'état haut. C'est une solution de dépannage mais elle n'est pas idéale car elle manque de précision du fait que l'on n'a pas un contrôle précis du timing, en effet un OS multitache tourne derrière et peut modifier le déroulement du programme.
Il vaut donc mieux un circuit externe qui génère ces impulsions. On peut utiliser un arduino par exemple. La solution que j'ai retenue est un contrôleur développé par Adafruit (http://www.adafruit.com/products/815) piloté par l'interface I2C (http://fr.wikipedia.org/wiki/I2C) et permettant de contrôler jusqu'à 16 sorties PWM.

Adafruit fournit une documentation complète ainsi qu'une library python rendant l'utilisation très simple.(http://learn.adafruit.com/adafruit-16-channel-servo-driver-with-raspberry-pi). (Si un jour j'ai le temps, je ferai une documentation en français).
Voici un exemple:

from Adafruit_PWM_Servo_Driver import PWM
import time

pwm = PWM(0x40, debug=True)

def avance():
    pwm.setPWM(0, 0, 500)
    pwm.setPWM(1, 0, 300)
    
def stop():
    pwm.setPWM(0, 0, 410)
    pwm.setPWM(1, 0, 410)
    
def gauche():
    pwm.setPWM(0, 0, 500)
    pwm.setPWM(1, 0, 500)
    
def droite():
    pwm.setPWM(0, 0, 300)
    pwm.setPWM(1, 0, 300)
    
def recule():
    pwm.setPWM(0, 0, 300)
    pwm.setPWM(1, 0, 500)
    
def tourelle_gauche():
    pwm.setPWM(3, 0, 500)
    
def tourelle_droite():
    pwm.setPWM(3,0,300)
    
def tourelle_haut():
    pwm.setPWM(2,0,500)
    
def tourelle_bas():
    pwm.setPWM(2,0,300)

pwm.setPWMFreq(60)

stop()
tourelle_gauche()
tourelle_bas()
time.sleep(1)
tourelle_droite()
tourelle_haut()
time.sleep(1)
tourelle_bas()
tourelle_gauche()
avance()
time.sleep(5)
stop()
    

samedi 21 septembre 2013

Objectif

L'objectif est de développer un drone roulant comportant une caméra et pilotable à distance via une interface web avec retour vidéo.
Les choix suivants ont été faits:
- raspberry pi
- connexion par wifi via un dongle
- caméra raspberry pi
- Servomoteurs
- alimentation externe USB pour le raspberry pi
- piles pour les moteurs
- circuit de commande PWM pour piloter les servomoteurs (http://www.adafruit.com/products/815).