20-24 janvier : intersemestre au Téléfab… des projets dans tous les sens !
Depuis lundi, des étudiants de l’EESAB et des étudiants de Télécom Bretagne se plongent dans l’univers passionant des objets et matériaux interactifs ou intelligents.
Petit tour d’horizon :
– Signalétique d’intensité sonore dans une salle de classe : capteur de son, moyen d’affichage
avec Jérémy, César, Marine, Lucie et Quentin
– Retranscription d’une image en sensation utilsant des capteurs et des vibrations
avec Solène, Erlé, Alexandre, Erwan et Jean-Baptiste
– Voiture télécommandée équipée de capteurs environnementaux
avec Chloé, Laurianne, Younes, Matias, Carlos, Przemyslaw et Oussama
–Convertir des photos en dessin
avec Rodolphe, Marie et Beidi
–Réglage d’ambiance lumineuse selon les données de la station météo connectée
avec Thibault, Hui, Zi, Xing et Zhongxian
– Textile lumineux réagissant au toucher
avec Juliette, Noémi, Corentin, Arlette, Mohamed Ali et Ismaïl
– Clignotant et feux stops pour vélo
avec Aurélien et He
Rendez-vous entre 11h et 13h30, vendredi 24 janvier au centre vie de Télécom Bretagne pour voir le résultat !
Programmer un ATMega
Au Téléfab, nous utilisons beaucoup d’Arduino pour prototyper simplement les projets qui sont développés. C’est un outil intéressant, mais qui devrait rester dédié au prototypage, pour plusieurs raisons. Dans mon cas, je dispose de deux Arduino, et quand je commence un projet, je suis obligé de démonter le projet précédent.
Arduino est un projet d’électronique Open Source, et nous avons donc accès au schéma de la carte. Il est donc possible de créer une nouvelle carte, similaire à une Arduino, mais dédiée à l’application qui nous intéresse. Ce n’est pas forcément moins cher qu’une Arduino, à cause du coût de gravure d’un prototype de circuit imprimé. Mais ça permet de finaliser un projet.
Le composant principal des cartes Arduino Uno est l’ATMega328P. C’est un microprocesseur RISC à faible consommation énergétique, basé sur l’architecture AVR développée par Atmel. Il rentre dans la même catégorie que les célébres PIC de MicroChip. Pour plus d’information sur l’architecture ATMega, vous pouvez consulter la page d’Atmel (http://www.atmel.com/products/microcontrollers/avr/default.aspx). D’une manière simplifiée, l’architecutre AVR inclut une EEPROM (dont la taille dépend du modèle de processeur), qui permet de stocker le code qui sera exécuté. Il contient également ce qu’on appelle les « fuses » en anglais (les fusibles), qui permettent de configurer le processeur.
Pour programmer un ATMega, on utilise un programmateur ISP (In-System Programming), qui utilise un protocole de type SPI (non, il n’y a pas de coquilles, l’ordre des lettres est important !). Ce type de programmateur peut se révéler relativement cher, mais comme on dispose d’une carte Arduino qui est équipée pour être programmée en ISP via l’USB, c’est une dépense inutile !
Le programme qui implante le programmateur est disponible dans les exemples de code fournis avec le logiciel Arduino, il s’appelle ArduinoISP.
Scanner 3D Kinect
Projet réalisé par :
Adrien Moreau
Ayoub Hadfat
Christophe Masoni
Thomas Gaydier
1.Introduction
Depuis quelques années, Télécom Bretagne dispose d’un FabLab appelé Téléfab, lieu de création de divers projets alliant mécanique, électronique et informatique. Le FabLab s’est doté il y a peu de temps d’une imprimante 3D pour imprimer des objets. Il souhaiterait également pouvoir imprimer des objets à partir d’objets existants, en les scannant au préalable. Ainsi notre groupe de projet a entrepris la conception, à partir d’une Kinect, d’un système permettant de reproduire virtuellement et de manière tridimensionnelle la forme d’un objet que l’on désirerait scanner. Plus précisément, l’objectif est de récupérer, à partir d’un objet de dimensions adaptées aux capacités techniques de la Kinect, un nuage de points destiné ensuite à être traité afin de reconstituer une image en 3D visualisable sur un écran.
Ce projet est constitué de 3 parties :
- Le plateau tournant : permet de faire tourner l’objet.
- La Kinect : récupère le nuage de point.
- Un PC : gère le plateau (grâce à Arduino) et traite le nuage de point pour en faire un modèle 3D.
Figure 1 : Les différentes parties du système
Chaque partie sera traité individuellement, la mise en relation se fera à la fin.
2.Le plateau tournant
2.1.Objectifs
Dans un premier temps, pour obtenir simplement une image 3D de l’objet de bonne qualité, nous avons décidé de prendre 3 photos de l’objet à 0°, 120°, et 240° (que nous nommerons par la suite « positions-cibles » de l’objet). Le plateau tournant doit donc permettre la rotation de l’objet à scanner pour récupérer les images aux bons angles.
2.2.Le tourne-disque : base du plateau
Nous avons utilisé comme base du plateau tournant un ancien tourne-disque. Cette partie peut bien sûr être réalisé en construisant le plateau tournant.
Figure 2 : Photos du tourne-disque en vue de dessus (à gauche) et de dessous (à droite)
Nous avons dû scier la pointe en métal au centre du plateau tournant qui servait initialement à mettre le disque sur le plateau tournant (voir le résultat sur la photo de gauche).
2.3.Moteur continu
Le tourne-disque fonctionne avec un moteur continu alimenté par 12V. L’arbre moteur entraîne une courroie qui fait tourner le plateau.
Il est aussi possible d’utiliser un moteur pas-à-pas en mettant en place un régulateur pour moteur à l’aide d’un pont en H.
Néanmoins, il faut garder en tête que le plateau tournant devra s’arrêter aux positions-cibles. Ainsi, il faudra prendre en compte l’inertie restante après désalimentation du moteur. Pour le moteur continu utilisé, nous avons l’avons sous alimenté (alimentation à 3.3V) pour limiter le phénomène d’inertie.
2.4.Comment déclencher la prise de photo de la Kinect aux trois « positions-cibles » de l’objet (0°, 120°, 240°) ?
Nous avons opté pour un système «LED+photorésistances».
2.4.1.Principe
On détecte les 3 positions grâce à une LED qui passe devant une photorésistance aux trois positions voulues, entraînant un pic d’intensité. Il suffit alors de demander à la Kinect de déclencher une photo lorsque l’intensité passe au-dessus d’un certain seuil.
Étudions le principe sur un exemple.
Ici l’objectif est de faire clignoter une LED plus ou moins vite selon la luminosité ambiante.
Matériel :
- des fils de connexion
- une breadboard (ou plaque d’essai sans soudure)
- une résistance de 10 kΩ
- une photo-résistance
- une LED
- une carte Arduino
Figure 3 : illustration de l’utilisation d’Arduino par un exemple simple
Le code Arduino :
/*Lit la luminosité etfait clignoter une LED à vitesse variable.*/
// Numéro de la broche du capteur de luminositéconst int luminosityPin = A0;
// Numéro de la broche de la LEDconst int ledPin = 9;
void setup() {// Initialise la communication avec l'ordinateur
Serial.begin(9600);
// Indique que la broche de la LED est une sortie
pinMode(ledPin, OUTPUT);
}
void loop() {
// Lit la valeur du capteur de luminosité
int sensorValue = analogRead(luminosityPin);
// affiche la valeur du capteur dans le "moniteur" sur l'ordinateur
Serial.print(" Valeur du Capteur = " );
Serial.print(sensorValue);
// Convertit la valeur en durée d'attente pour la LED
// il sera nécessaire d'adapter les valeurs du "mapping" en
// fonction de la luminosité ambiante
int waitTime = map(sensorValue, 0, 1023, 20, 1000);
// Envoie le résultat vers l'ordinateur
Serial.print("\t Delai de clignotement (millisecondes) = ");
Serial.println(waitTime);
// Fait clignoter la LED au rythme de la luminosité
digitalWrite(ledPin, HIGH); // allume la LED
delay(waitTime); // attends la durée choisie
digitalWrite(ledPin, LOW); // éteinds la LED
delay(waitTime); // attends la durée choisie
}
La photorésistance (entre les fils noir et vert sur la figure 3) est branchée en parallèle avec une résistance. Elle est alimentée par le 5V de l’Arduino (fil rouge) et est reliée à une entrée analogique de l’Arduino (fil vert). La photorésistance est reliée à un port de sortie. Le code ci-dessus, écrit sur l’interface Arduino permet de faire clignoter la LED en fonction de la luminosité de la photorésistance.
La partie haute du montage (LED) ne nous intéresse pas. Nous ne voulons en effet pas faire clignoter une LED. En revanche nous voulons déclencher la prise de photographies de la Kinect en fonction des valeurs de luminosité des LED. La partie basse du montage sera donc exactement la même pour notre projet, et sera faite trois fois (pour les trois photorésistances).
2.4.2.Choix de la valeur de la résistance en série avec la photorésistance
Le choix de la résistance est important, il détermine les valeurs de la luminosité captée par la photorésistance lorsqu’elle est sous une luminosité ambiante (telle que l’on peut avoir au FabLab), et lorsqu’elle est éclairée par une LED.
L’important est que ces deux valeurs soient bien distinctes pour pouvoir détecter sans ambiguïté lorsque la photorésistance est éclairée par la LED, indépendamment des contraintes de l’environnement (éclairage accidentel…).
Nous avons testé pour différentes valeurs du résistor la valeur de la résistance de la photorésistance lorsque celle-ci est éclairée par la LED ou pas. Nous avons choisi le résistor qui permettait d’avoir le meilleur contraste de résistance, à savoir 100kΩ.
2.4.3.Que mettre sur la partie tournante : LED ou photorésistance ?
Au début, nous avions l’intention de mettre une photorésistance sur la partie tournante et trois LEDs sur la partie fixe (aux trois positions correspondant à 0°, 120° et 240°) (voir figure ci-dessous).

Figure 4 : Schéma du montage initialement prévu
La photorésistance doit être reliée à la breadboard puisque c’est grâce aux pics de sa luminosité que l’on déclenchera la prise de photos de la Kinect. En revanche, les LEDs doivent être uniquement alimentées par source de tension.
Or le fait que la photorésistance, donc la partie reliée à la breadboard, soit sur la partie tournante du plateau pose problème. En effet, les fils s’enrouleront autour de l’objet au fur et à mesure que le plateau tournera, ce qui n’est évidemment pas souhaitable. Le problème est le fait passer les fils par « en dessous »
C’est donc pour cela que nous avons plutôt choisi de faire le montage ci-dessous qui résout
ces problèmes. On a inversé LED et photorésistances (qui sont maintenant trois).

Figure 5 : Schéma du montage finalement réalisé
Pour éviter les problèmes de fils, il suffit alors d’alimenter la LED avec une pile qui sera fixée avec
celle-ci sur la partie tournante.
2.4.4.Fixation de la LED et réalisation du circuit d’alimentation
Pour gêner le moins possible la prise de photos de la Kinect, nous avons décidé de fixer le circuit en dessous du plateau et de simplement faire ressortir la LED en perçant un trou. Mais sous le plateau il y a peu de place et il faut que le circuit soit assez plat pour ne pas rentrer en collision avec l’arbre du moteur (moins de 8mm environ).
La solution retenue permettant de concilier à la fois la petite taille, et la forme plate, est d’utiliser comme alimentation une pile plate.
Un autre problème s’est posé : on ne peut pas se contenter de souder la pile directement à la LED. Il faut pouvoir changer la pile quand celle-ci est usée.
Nous avons donc utilisé un morceau de connecteur masculin-féminin. Après découpage d’un morceau de plaque et soudure, voici le résultat ci-dessous (Figure 6).
Figure 6 : Circuit d’alimentation de la LED
2.4.5.Réalisation des circuits des photorésistance
Ce qui nous intéresse est de faire la partie du circuit encadrée en jaune trois fois, pour les trois « positions-cibles ».
Figure 7 : Montage à réaliser pour relier chaque photorésistance à l’Arduino
Ce qui donne après un peu de soudure :
Figure 8 : Photos du montage de la figure 7
Les trois photorésistances seront reliées au 5V de l’Arduino, et les trois masses sur le port GND de l’Arduino, comme respectivement les fils rouge et noir sur la figure 15. Les fils « verts » seront reliés à trois entrées analogiques différentes(ANALOG IN sur la figure 15), pour mesurer indépendamment les valeurs des résistances des trois photorésistances.
Les trois circuits sont fixés sur le plateau aux positions-cibles en utilisant de la colle.
2.5.Alimentation du moteur
L’alimentation est faite grâce à un générateur. Le moteur est aussi relié à l’Arduino pour pouvoir l’arrêter aux positions-cibles. Un problème persiste : l’intensité utilisé par le moteur est élevée et risquerait d’endommager l’Arduino pour éviter cela il faut mettre un transistor entre ces deux éléments.
2.6.Comment fixer les objets sur le plateau ?
Cette question se pose puisqu’elle correspond à l’une des contraintes que l’on s’est fixée : l’objet ne doit pas bouger lorsque le plateau tourne.
La meilleure solution retenue pour sa simplicité est d’utiliser de la pâte à modeler que l’on aplatira entre le plateau et l’objet.
2.7.Code et montage final
Voici le code final de l’arduino :
// Numéro de la broche du capteur de luminosité
const int luminosityPin1 = A0;
const int luminosityPin2 = A1;
const int luminosityPin3 = A2;
// Seuil de luminosité
const int seuil1 = 155;
const int seuil2 = 175;
const int seuil3 = 130;
// Numéro de la broche de la LED
const int ledPin = 9;
//numero de la branche transistor
const int traPin = 2;
// Variable gérant l'intervalle de prise de valeurs
long previousMillis = 20;
long interval = 20;
//état du moteur ( 0= arret , 1 = marche )
int state = 1;
boolean depasseSeuil = false;
void setup(){
Serial.begin(9600);
pinMode (traPin, OUTPUT);
digitalWrite(traPin, HIGH);
}
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
// Lit la valeur du capteur de luminosité
int sensorValue1 = analogRead(luminosityPin1);
int sensorValue2 = analogRead(luminosityPin2);
int sensorValue3 = analogRead(luminosityPin3);
if (sensorValue1 > seuil1) depasseSeuil = true;
else if (sensorValue2 > seuil2) depasseSeuil = true;
else if (sensorValue3 > seuil3) depasseSeuil = true;
// affiche la valeur du capteur dans le "moniteur" sur l'ordinateur
Serial.print("\n " );
Serial.print(sensorValue1); //envoit la valeur du capteur a Processing
Serial.print(" / " );
Serial.print(sensorValue2); //envoit la valeur du capteur a Processing
Serial.print(" / " );
Serial.print(sensorValue3); //envoit la valeur du capteur a Processing
if(depasseSeuil){
state = 0;
digitalWrite(traPin, LOW);//stop le moteur
delay(3000);
digitalWrite(traPin, HIGH);
Serial.println("start");
}
else
{
state = 1;
digitalWrite(traPin, HIGH);//relance le moteur
}
depasseSeuil=false;
// Vérifie les valeurs envoyés par Processing
//checkSerial();
if(state==1){
digitalWrite(traPin, HIGH);
}
}
}
void checkSerial(){ // vérifie les données envoyés par Processing
if (Serial.available() > 1) {
char trigger = Serial.read();
if(trigger == 'S'){
state = 1;
}
}
}
Voici le montage final de la partie plateau tournant :
Figure 9 : Schéma du montage de la partie plateau tournant
3.Kinect
Attention, dans la partie suivante nous avons décidé de travailler sous Ubuntu 12.04 avec un ordinateur ne contenant aucun USB3.0 car la Kinect ne fonctionne pas avec de tels ports USB. Nous avons aussi utilisé Processing 1.5.1, Arduino 1.0.5.
3.1.Présentation de la Kinect
La Kinect, initialement appelée sous le nom de code Project Natal, est un périphérique qui fut développé par PrimeSense puis commercialisé par Microsoft début novembre 2010 comme contrôleur de jeux vidéo. Très vite les programmeurs du monde entier ont réalisé le plein potentiel de l’appareil et en décembre 2010 pour éviter la multiplication des drivers non officiel, PrimeSense à mis à disposition à la communauté des drivers OpenSource. Comme ceux de l’API OpenNI ensuite complété par ceux de l’API NITE augmentant ainsi les capacités de l’appareil.
Notons qu’ils existent deux types de Kinect : Kinect XBOX 360 ( reconnaissable par le XBOX 360 sur sa façade) et Kinect for Windows ( reconnaissable par le XBOX sur sa façade). Nous avons travaillé avec une Kinect XBOX 360. L’autre type de Kinect pouvant rencontrer différents types d’erreur avec les différentes librairies.
La Kinect permet de récupérer plusieurs informations sur son environnement. Elle capte trois types d’images différentes : une image de profondeur, une image RGB et une image infrarouge. On peut la schématiser de la manière suivante :
Figure 10 : Schéma de la Kinect
La résolution de l’image RGB et de l’image IR est de 640×480 pixels. Les informations de profondeur sont récupérées à partir du capteur infrarouge et modélisé par des niveaux de gris allant de 2048 (blanc) à 0 (noir).
La Kinect est dotée de plusieurs pilotes : un pour la camera et un pour le moteur.
Les pilotes ne font pas de post-traitement sur les données, ils nous donnent juste accès au flux de données brutes de la Kinect et nous permettent de contrôler la LED et le moteur.
Par la suite des API OpenSource ont été développés pour récupérer et travailler ces données. Parmi eux on peut en citer 3 et leur associés l’environnement de travail associé : en effet ces différentes API ne fonctionnent pas toujours sous tous les systèmes d’exploitation.
|
Librairies |
Auteur |
API |
OS |
|
Openkinect |
Daniel Shiffman |
OpenKinect/Libfreenect |
Mac OS X |
|
dLibs |
Thomas Diewald |
OpenKinect/Libfreenect |
Windows |
|
Simple-OpenNI |
Max Rheiner |
OpenNI/NITE |
Mac OS X, Windows, Linux |
Nous avons décidé de travailler sous le système d’exploitation Linux car les ordinateurs du fablab ont une puissance limité et tourneront sous Linux.
C’est pourquoi nous nous sommes tournés vers la bibliothèque de Max Rheiner pour développer la partie logicielle de notre scanner. Intéressons-nous de plus près à Simple-OpenNi.
3.2.Présentation de Simple-OpenNI
OpenNi ( Open Natural Interaction ) est une API qui fournit un soutien pour la reconnaissance visuel.
NITE permet de suivre les mouvements d’un squelette.
Simple-OpenNi est un paquet de fonction associé à la plateforme de programmation Processing, utilisant OpenNi et NITE. Toute les fonctions de OpenNi ne sont pas prises en charge mais il est destiné à un usage plus simple de la bibliothèque de fonctions. Il permet l’utilisation de la Kinect avec le langage de programmation Procesing.
3.3.Présentation du langage de programmation utilisé
Nous avons en plus utilisé le langage de programmation Processing pour communiquer et traiter les données entre le PC et la kinect. En effet, nous avons hésité entre deux langages de programmation : Processing et C#. Le C# est un langage qui se rapproche du Java étudié à Telecom Bretagne. Cependant, il existe avec Processing des modèles de fonctions construits à partir de la librairie libfreenect permettant de travailler facilement avec la Kinect. Ce choix nous permettait aussi de nous appuyer sur la documentation apporté par l’ouvrage Arduino and Kinect Projects.
On récupère grâce à des fonctions déjà prédéfinies dans cette librairie, les informations de profondeurs. On peut les représenter ensuite grâce à un code couleur RGB : plus l’objet est proche ( resp. loin ) et plus la couleur sera chaude ( resp. froide ).
Actuellement, la bibliothèque est capable de nous rendre les données disponibles de quatre façons :
- Une image RVB (image où chaque pixel est défini par une valeur de Bleu, Rouge et Vert) de la caméra Kinect comme une PImage.
- Échelle de gris prise à partir de l’image de la caméra IR (infrarouge) en tant que PImage
- L’image en niveaux de gris avec la luminosité de chaque pixel cartographié à la profondeur (plus clair = plus proche).
- Données de profondeur brutes (nombre de 11 bits entre 0 et 2048) en tant que int [] array
3.4.Fonctions supplémentaires
Cependant pour reconstituer l’objet en 3D nous avons décidé de travailler avec un nuage de point. Nous l’obtenons en ne récupérant qu’un pixel sur 4 permettant ainsi de reconstituer notre nuage de point avec une perte d’information et de qualité minimum. Toute l’information que récupère la Kinect n’est pas non plus essentielle pour reconstituer notre objet. En effet notre objet scanné possède une taille maximale et il existe une distance minimale entre l’objet et la kinect ; on peut donc considérer que toute les données de profondeur en dehors d’un cube prédéfini (de taille 400*400*400 centré par rapport à la kinect) ne nous intéresse pas.
De plus ce scanner sera utilisé pour l’imprimante 3D qui reconstitue l’objet scanné sans se soucier de sa couleur, les informations RGB de l’objet ne sont donc pas nécessaire. Il est donc inutile de récupérer toute les données de la Kinect.
3.5.Installation de Processing sous Linux
Téléchargez l’archive avec la version de Processing qui convient sur le lien : http://www.processing.org/download/
La version de Processing 2.0 étant encore à l’état de béta, ce qui veut dire que certains bug peuvent exister, nous travaillerons avec la version stable : Processing 1.5.1.
Pour un Linux 32 bit : http://processing.googlecode.com/files/processing-1.5.1-linux.tgz
Pour décompresser l’archive dans votre dossier personnel utilisez la commande :
tar -zxvf processing-xxx.tgz
Un dossier sera automatiquement créer : /home/MonDossierPersonnel/processing-1.5.1.
Pour exécutez Processing, placez-vous dans le répertoire suivant :
cd /home/VotreDossierPersonnel/Processing-xxx/
Puis pour autorisez l’exécution de Processing sur l’ordinateur :
chmod +x processing
Maintenant pour exécuter Processing sur l’ordinateur il suffira de se placer dans le dossier /home/MonDossierPersonnel/processing-1.5.1 et d’entrer la commande :
./processing
Processing requiert Java pour fonctionner, si Java n’est pas installé sur l’ordinateur entrez la commande suivante pour l’obtenir :
sudo apt-get install openjdk-6-jdk
3.6.Installation de Simple-OpenNI sous Linux
Suivez les différentes étapes suivantes pour obtenir les pilotes OpenNi et PrimeSense pour pouvoir travailler avec la Kinect sous une distribution Ubuntu (12.04 x32 lors de notre projet). Si l’on travaille avec une architecture 64 bits, il faudra télécharger les dossiers associés
1ère étape :
Vous aurez besoin de plusieurs logiciels ; entrez la commande suivante pour les installer :
sudo apt-get install git-core cmake freeglut3-dev pkgconfig build-essential libxmu-dev libxi-dev libusb-1.0-0-dev doxygen graphviz mono-complete
Ensuite téléchargez la source contenant OpenNi à partir de Github et stockez là dans un répertoire kinect :
mkdir ~/kinect cd ~/kinect git clone https://github.com/OpenNI/OpenNI.git
Puis executez le script RedistMaker dans le dossier Platform/Linux et installez les « outpu binairies » :
cd OpenNI/Platform/Linux/CreateRedist/ chmod +x RedistMaker ./RedistMaker cd ../Redist/OpenNI-Bin-Dev-Linux-x32-v1.5.2.23/ sudo ./install.sh
Ensuite copiez le dossier SensorKinect provenant de Github dans le répertoire Kinect :
cd ~/kinect git clone git://github.com/avin2/SensorKinect.git
Puis executez le script RedistMaker dans le dossier Platform/Linux et installez les « outpu binairies » :
cd SensorKinect/Platform/Linux/CreateRedist/ chmod +x RedistMaker ./RedistMaker cd ../Redist/Sensor-Bin-Linux-x32-v5.1.0.25/ chmod +x install.sh sudo ./install.sh
Ensuite télécharger le dossier NITE-Bin-Dev-Linux-x32-v1.5.2.21 et extrayez l’archive dans le répertoire ~/kinect. L’archive peut être obtenue en cliquant sur le lien suivant : https://code.google.com/p/simple-openni/downloads/detail?name=OpenNI_NITE_Installer-Linux32-0.27.zip&can=2&q=
Puis allez dans le répertoire des données qu’il contient :
cd NITE-Bin-Dev-Linux-x32-v1.5.2.21/Data
Pour que Simple-OpenNi fonctionne il faut maintenant modifier la licence. Pour cela modifiez à l’aide d’un éditeur de texte chaque fichiers : Sample-Scene.xml, Sample-Tracking.xml et ample-user.xml.
Changez : <license Vendor= »PrimeSense » key= » »/>
Avec : <license Vendor= »PrimeSense » key= « 0KOIk2JeIBYCIPWVnMoRKn5cdY4=»/>
Ensuite revenez dans le répertoire NITE :
Cd ..
Et exécutez le script d’installation :
sudo ./install.sh
C’est tout en ce qui concerne Simple-OpenNi !
3.7.Code Processing final
Le code processing ayant permis de récupérer et de représenter les données de la Kinect est le suivant. Il est composé de deux fonctions principales : setup() qui permet d’initialiser les paramètres du code et draw() qui est une boucle infinie et permet de récupérer constamment les données envoyés par la Kinect. On définit ensuite les fonctions secondaires ayant été utilisées dans le code principale.
Voici le code final de Processing :
import processing.opengl.*; import SimpleOpenNI.*; import kinectOrbit.*; // Initialisation des paramètres Orbit and simple-openni KinectOrbit myOrbit; SimpleOpenNI kinect; // Initialisation des listes de vecteurs pour le nuage de points et les couleurs associés ArrayList<PVector> scanPoints = new ArrayList<PVector>(); // Nuage de Points ArrayList<PVector> objectPoints = new ArrayList<PVector>(); // Nuage de Points // Variable d'espace float baseHeight = -5; // hauteur de la base du modèle float modelWidth = 400; float modelHeight = 400; //tout objet contenue dans ce cube sera scanné PVector axis = new PVector(0, baseHeight, 1050); // Paramètres du scan int scanLines = 200; // définie la largeur du scan (pour une valeur de 1 : une seule ligne verticale de l'objet est scanné) int scanRes = 1; // définie le nombre de pixel que nous prenons dans le scan ( 1 est la valeur correspondant à la plus haute résolution) boolean scanning; // valeur booléenne associer à l'état de numérisation boolean arrived; // valeur booléenne : sommes nous à une position devant être scanné ? float[] shotNumber = new float[3]; // nombre de scan que nous comptons effectuer : ici 3 int currentShot = 0; // valaur du nombre de prise de vue déjà prise public void setup() { size(800, 600, OPENGL); // Orbit myOrbit = new KinectOrbit(this, 0, "kinect"); myOrbit.drawCS(true); myOrbit.drawGizmo(true); myOrbit.setCSScale(200); myOrbit.drawGround(true); // Simple-openni kinect = new SimpleOpenNI(this); kinect.setMirror(false); kinect.enableDepth(); for (int i = 0; i < shotNumber.length; i++) { shotNumber[i] = i * (2 * PI) / shotNumber.length; } } public void draw() { kinect.update(); // Actualise les données de la Kinect background(0); myOrbit.pushOrbit(this); // fonction permettant de gérer la perspective updateObject(scanLines, scanRes); // actualise les positions des données de l'objet if ( scanning) { //scan à la main scan(); scanning = false; } // si on doit scanné et que l'on est sur la bonne position alors on scan stroke(255,255,255); drawObjects(); // on dessine les points déjà pris auparavant drawBoundingBox(); // on dessine le cube autour de l'objet scanné kinect.drawCamFrustum(); // on dessine l'image de la Kinect myOrbit.popOrbit(this); // arrète la fonction permettant de gérer la perspective } void drawPointCloud(int steps) { // Création du nuage de point "grossier" scanné int index; PVector realWorldPoint; stroke(255); for (int y = 0; y < kinect.depthHeight(); y += steps) { for (int x = 0; x < kinect.depthWidth(); x += steps) { index = x + y * kinect.depthWidth(); realWorldPoint = kinect.depthMapRealWorld()[index]; stroke(150); point(realWorldPoint.x, realWorldPoint.y, realWorldPoint.z); } } } void drawObjects() { // Dessine les points scanné pushStyle(); for (int i = 1; i < objectPoints.size(); i++) { point(objectPoints.get(i).x, objectPoints.get(i).y, objectPoints.get(i).z + axis.z); } for (int i = 1; i < scanPoints.size(); i++) { point(scanPoints.get(i).x, scanPoints.get(i).y, scanPoints.get(i).z + axis.z); } popStyle(); } void drawBoundingBox() { // dessine le cube ou l'objet est scanné stroke(255, 0, 0); line(axis.x, axis.y, axis.z, axis.x, axis.y + 100, axis.z); noFill(); pushMatrix(); translate(axis.x, axis.x + baseHeight + modelHeight / 2, axis.z); box(modelWidth, modelHeight, modelWidth); popMatrix(); } void scan() { // numérise l'objet et ne prend en considération que les nouveaux points à une distance de plus d'1mm des autres for (PVector v : scanPoints) { boolean newPoint = true; for (PVector w : objectPoints) { // on regarde si les pixels de l'objet scanné ne sont pas trop proches de la prise de vue précédente if (v.dist(w) < 1) newPoint = false; } if (newPoint) { objectPoints.add(v.get()); } } if (currentShot < shotNumber.length-1) { currentShot++; } else { scanning = false; } arrived = false; } // Fonctions auxiliaires void updateObject(int scanWidth, int step) { // Fonction actualisant l'image et les valeurs scannés int index; PVector realWorldPoint; scanPoints.clear(); float angle = shotNumber[currentShot]; pushMatrix(); translate(axis.x, axis.y, axis.z); rotateY(angle); line(0, 0, 100, 0); popMatrix(); int xMin = (int) (kinect.depthWidth() / 2 - scanWidth / 2); int xMax = (int) (kinect.depthWidth() / 2 + scanWidth / 2); for (int y = 0; y < kinect.depthHeight(); y += step) { for (int x = xMin; x < xMax; x += step) { index = x + (y * kinect.depthWidth()); realWorldPoint = kinect.depthMapRealWorld()[index]; if (realWorldPoint.y < modelHeight + baseHeight && realWorldPoint.y > baseHeight) { if (abs(realWorldPoint.x - axis.x) < modelWidth / 2) { // Vérification de x if (realWorldPoint.z < axis.z + modelWidth / 2 && realWorldPoint.z > axis.z - modelWidth / 2) { // Vérification de z PVector rotatedPoint; realWorldPoint.z -= axis.z; realWorldPoint.x -= axis.x; rotatedPoint = vecRotY(realWorldPoint, angle); scanPoints.add(rotatedPoint.get()); } } } } } } PVector vecRotY(PVector vecIn, float phi) { // Fonction permettant de prendre en compte la rotation de l'objet lors de la représentation sur ordinateur // On considère une rotation autour de l'axe Y PVector rotatedVec = new PVector(); rotatedVec.x = vecIn.x * cos(phi) - vecIn.z * sin(phi); rotatedVec.z = vecIn.x * sin(phi) + vecIn.z * cos(phi); rotatedVec.y = vecIn.y; return rotatedVec; } public void keyPressed() { // Fonction permettant de définir des actions avec les touches du clavier switch (key) { case 'r': // 'r' reinitialise le scan objectPoints.clear(); currentShot = 0; scanning = false; break; case 's': // 's' démarre le scan de l'objet scanning = true; arrived = false; break; case 'e': // 'e' exporte le nuage de point ( format PLY ) exportPly('0'); break; case '+': // '+' augmente la résolution du nuage de points ( scanned lines ++ ) scanLines++; println(scanLines); break; case '-': // '-' diminue la résolution du nuage de points ( scanned lines -- ) scanLines--; println(scanLines); break; } } void exportPly(char key) { // Fonction permettant d'exporter le nuage de point au format PLY PrintWriter output; String viewPointFileName; viewPointFileName = "myPoints" + key + ".ply"; output = createWriter(dataPath(viewPointFileName)); output.println("ply"); output.println("format ascii 1.0"); output.println("comment This is your Processing ply file"); output.println("element vertex " + (objectPoints.size()-1)); output.println("property float x"); output.println("property float y"); output.println("property float z"); output.println("end_header"); for (int i = 0; i < objectPoints.size() - 1; i++) { output.println((objectPoints.get(i).x / 1000) + " " + (objectPoints.get(i).y / 1000) + " " + (objectPoints.get(i).z / 1000) + " "); } output.flush(); // On écrit les données dans le fichier output.close(); // On termine le fichier }
4.Traitement des données reçues par l’ordinateur pour former le nuage de points
Après avoir récupéré le nuage de points, il faut désormais reconstruire la surface initiale. Pour cela plusieurs algorithmes existent, ainsi que des logiciels « open source » qui permettent de réaliser cette opération.
Pour notre projet nous avons utilisé MeshLab qui est un logiciel de traitement et d’édition de maillage 3D.
MeshLab lit les fichiers .ply, il suffit donc d’ouvrir le fichier précédemment obtenu. Pour certains fichiers, nous avons rencontré une erreur « Unexpected end of file ».Cette erreur survient dans le cas où le nombre de points affichés est différent du nombre de points déclarés dans le fichier .ply. Dans ce cas, il faut suivre les étapes suivantes :
- Activer la vue des points (Points view) dans la barre du haut.
- Aller au menu Rendu (Render) et choisir Couleur/Par Sommet (Colors/Per Vertex).
Après cette manipulation, le nuage de points s’affichera et sera coloré. (figure 11)
On peut cependant observer des points incohérents, qu’il faudra supprimer manuellement avant de lancer le processus de reconstruction de la forme. Ces points sont parfois dus à un mauvais calibrage de la Kinect par rapport à la plate-forme tournante. Pour supprimer ces points, il faut utiliser l’outil Sélectionner Sommets (Select Vertexes) dans la barre du haut. Après avoir sélectionné les points indésirables, il faut cliquer sur Supprimer Points Sélectionnés (Delete Selected Vertices) dans la barre du haut. Il est possible de sélectionner plusieurs points en gardant enfoncée la touche Control du clavier.(figure 12)

Figure 12 : Points incohérents du nuage de points 3D
La prochaine étape est le processus de reconstruction. Tout d’abord, il faut générer le vecteur perpendiculaire à la surface voisine de chaque point. Ceci permet à l’algorithme d’avoir les informations sur la topologie de l’objet nécessaires à la reconstruction. Il faut aller au menu Filtres/Jeu de points (Filters/Point Set) et choisir Générer les normales aux jeux de points (Compute normal for point sets). Dans le menu qui apparaît, il faut choisir 16 comme nombre de points voisins. À la fin du processus, pour afficher les normales, il faut activer Afficher les normales aux sommets (Show Vertex Normals) dans le menu Rendu (Render).
Il ne reste plus qu’à lancer le processus de reconstruction en allant dans Filtres/Jeu de points (Filters/Point Set) et en choisissant Reconstruction de Surface : Poisson (Surface Reconstruction : Poisson). Un menu s’affiche alors, contenant plusieurs paramètres qu’il faut renseigner. Ces paramètres influent sur la précision de la reconstruction, les valeurs qu’il faut
rentrer dépendent de l’objet et de la qualité du scan. Il faut donc essayer de trouver les paramètres optimaux pour chaque objet.
Le modèle 3D est généré à la fin du processus. (figure 13)
Pour le colorer, il faut aller dans Filtres/Échantillonnage (Filters/Sampling) et choisir Transfert des attributs des points (Vertex Attributes Transfer), choisir comme source le nuage de points et comme cible le maillage Poisson, cocher Transfert de couleur (Transfer Color) puis appliquer. Si le résultat n’est pas satisfaisant, il faut transférer la géométrie aussi dans le menu
précédent. Il suffit donc de cocher géométrie aussi avant d’appuyer sur appliquer. (figure 14)

Figure 14 : Modèle 3D coloré
Ensuite il faut lisser le modèle, pour cela il faut aller dans Filtres/Lissage, Carénage, Déformation (Filters/Smoothing, Fairing, Deformation) et appliquer HC Lissage Laplacien (HC Laplacian Smooth) autant de fois qu’il le faut pour avoir une surface suffisamment lisse. (figure 15)
Figure 15 : Modéle 3D coloré et lissé
MeshLab permet d’exporter ce modèle dans différents formats pouvant être utilisés par un
logiciel de modélisation 3D, mais aussi par une imprimante 3D.
5.Le système Final
Figure 16:Schéma du système global
Les différentes parties présentées précédemment communiquent entre elles pour réaliser le scan de l’objet. L’ordinateur commande au plateau de tourner. Quand la lumière est détectée par l’une des photorésistances, l’Arduino envoie un message à l’ordinateur. Dès lors l’ordinateur envoie un ordre à la Kinect pour lancer la capture. Le nuage de points résultant est enregistré grâce à Processing. Ce processus est réitéré trois fois pour récupérer trois nuages de points qui sont ensuite traités par Processing pour construire le nuage 3D.
Ce nuage est enfin traité sur Meshlab pour générer le modèle 3D.
Projet quadcoptère
Bonjour à tous,
Voici le premier article d’une longue série sur le projet quadcoptère dont je suis l’un des collaborateurs. À mes côtés se trouvent Quentin Gilladin, Aymeric Legal et Hugo Chauvary. Ce projet nous est fourni par un ancien collègue de Quentin ainsi que quelques pièces pour fabriquer un objet volant basé sur ce qui se trouve sur le site www.aeroquad.com.
Pour cela, il nous a fourni les composants nécessaires à la réalisation de cet quadcoptère. Nous avons donc à notre disposition le matériel suivant :
– une carte de contrôle Arduino Duelmilanove ou une UNO (site officiel : http://arduino.cc)
– un shield Aeroquad v1.8 qui comprend :
– un accéléromètre qui a pour fonction de fournir les accélérations suivants les 3 axes que fera notre super quadcoptère
– un gyroscope qui a pour fonction de fournir les rotations suivants les 3 axes effectuées par notre super quadcoptère
– un convertisseur de niveau logique
– Quatre « ESC » Turnigy Plush 18A qui sont des contrôleurs de vitesse électroniques
– Quatre moteurs électriques Tunigy TR2217/16
– Quatre hélices composites 12×3.8 (deux à pas à droite et deux à pas à gauche)
– une batterie au lithium ZIPPY 4000mAh 11.1V
Le but de notre projet est non seulement d’arriver à fabriquer un quadcoptère qui décolle et se déplace correctement, mais aussi de permettre à celui-ci d’embarquer du matériel pour rendre le vol plus ludique ou plus utile. La finalité serait de pouvoir prendre des clichés ou des vidéos à distance ou encore des capteurs diverses et variés pour prendre des relevés couplables avec les informations fournies par le quadcoptère lui même.
Vous l’aurez peut-être remarqué, mais parmi le matériel fourni, il n’y a pas de structure pour le quadcoptère. La modélisation et la fabrication de celle-ci nous échoie donc. Pour ce qui est de la modélisation, elle a été effectuée à l’aide d’un logiciel de DAO et pour ce qui est de la fabrication, c’est la section mécanique de Télécom Bretagne qui nous fournira des pièces en aluminium.
Nous écrirons sur ce site pour vous tenir au courant de nos problèmes rencontrés, de nos réussites improbables, et de toutes les petites astuces qui seront nécessaire à la réussite de votre propre quadcoptère. Nous espérons que cela vous permettra d’éviter de commettre des erreurs similaires aux nôtres.
Semaine après semaine, nous tiendrons donc à jour ce site pour vous fournir nos dernières avancées.
À très bientôt,
Maxime Lasserre
How to : connecter un arduino et un téléphone Android
Le concept :
Arduino et Android sont deux technologie très puissantes et ouvertes. Il peut être très intéressant de les connecter.
C’est ce que nous avons fait pour notre projet LED’s draw !
Nous avons un peu peiné à mettre en place un environnement de travail Android – Arduino. Ils existent de nombreux tutoriels sur le sujet, mais nous n’en avons trouvé aucun qui suffise. Je vais donc tenter de les regrouper ici pour faciliter une telle liaison.
Les tutoriels sur lesquels nous allons nous baser :
- la page de la carte Arduino Mega ADK, sur laquelle on peut brancher un téléphone Android :
http://arduino.cc/en/Main/ArduinoBoardADK
Le problème du tutoriel disponible sur le site d’Arduino est qu’il ne marche qu’avec Processing pour programmer l’application. Je déconseille fortement d’utiliser ce logiciel, c’est beaucoup plus dur de programmer pour Android en C/C++ qu’en Java avec Eclipse.
- la page Google pour utiliser des cartes Arduino – like avec Android
http://developer.android.com/tools/adk/adk.html
La page 2011 présente comment faire. La page 2012 est moins bien.
Le problème est qu’ils présentent surtout leur carte à eux.
- Enfin, voici un tutoriel plutôt sympa : http://allaboutee.com/2011/12/31/arduino-adk-board-blink-an-led-with-your-phone-code-and-explanation/
L’environnement Eclipse pour Android
Tout d’abord, installez l’environnement Eclipse pour Android. C’est long à télécharger, donc autant commencer par ça.
Si vous n’avez pas Eclipse
Vous pouvez tout télécharger ici : http://developer.android.com/sdk/index.html
Normalement c’est bien expliqué.
Si vous avez déjà Eclipse
Vous pouvez l’ouvrir, et installer l’environnement Android : Help/Install New Software/Add/
Mettez le nom que vous voulez, et pour location : http://dl-ssl.google.com/android/eclipse/
Plus d’info ici : http://developer.android.com/sdk/installing/installing-adt.html
Il faut ensuite télécharger les sdks android dans Eclipse : Windows/Android SDK Manager
Sélectionner le sdk que vous voulez (normalement ça marche à partir de Android 3.2 (API 13).
Installer « SDK plateform », et « Google APIs ».
Installer Arduino IDE :
Suivre la procédure pour installer l’arduino IDE et l’arduino ADK sur votre ordinateur (sur le site arduino). Si vous êtes sous Windows, ne pas oublier d’installer le driver ! Pour cela, démarrer/panneau de configuration/système et sécurité/Gestionnaire de périphériques
En branchant votre arduino ADK, vous devriez voir apparaître un nouveau périphérique. Une petit bulle-info peut apparaître. Ouvrez-le/la, installer le pilote, et installation manuelle, aller dans votre dossier arduino contenant le dossier drivers. Sélectionnez celui-ci (qui contient un fichier Arduino Mega ADK) pour y trouver le driver.
Dans le gestionnaire des périphériques, on peut vérifier si l’installation s’est bien passée : l’arduino ADK doit apparaître sous ce nom dans le gestionnaire des périphériques. On peut aussi tester grâce au programme Blink Led (dans les exemples de arduino IDE).
Installer les outils Google :
On passe maintenant sur le tutoriel de Google : http://developer.android.com/tools/adk/adk.html
De « Getting Started with the ADK » jusqu’à « Installing the firmware to the ADK board » inclus.
Ne pas télécharger la librairie CapSense, elle n’est plus à jour n’est pas utile. Ne pas faire Running the Demokit Android application (c’est plutôt réservé à la carte de Google).
Vous pouvez lire la suite, mais il est plus simple de passer au tutoriel suivant :
Un exemple pour bien commencer :
On va donc maintenant regarder un tutoriel pour transférer des données du téléphone à la board.
http://allaboutee.com/2011/12/31/arduino-adk-board-blink-an-led-with-your-phone-code-and-explanation/
Vous pouvez le suivre, ou reprendre directement le projet ici :
En important le code dans Eclipse, il est probable que vous ayez des erreurs aux lignes suivantes :
import com.android.future.usb.UsbAccessory ;
import com.android.future.usb.UsbManager ;
Pour régler le problème, il faut régler la « build target » en google api, c’est-à-dire :
Pour le télécharger, sur Eclipse : windows/android sdk manager/
télécharger la google api qui vous convient (la version 3.2 fonctionne, si vous avez besoin d’une version plus récente ça devrait marcher aussi).
projet/properties/Android
Problème classique :
Si vous refaites un projet « from scratch », vous risquez de rencontrer un problème de layout : une erreur avec « android.R.layout ». NE PAS importer R. ça ne fera qu’empirer les choses. Il faut au choix :
- reprendre le projet au dessus ;
- supprimer les dossiers values-v11 et values-v14 situés dans le dossier res ;
- trouver une vraie solution…
Normalement, ça devrait fonctionner !
Dansons la lumière !
Ce projet a été réalisé durant la semaine d’intersemestre 2013 « Fablab & Design », en coopération avec les étudiants de l’ESAB.
Ont participé à ce projet Alice Dejoux et Morgane Joly, de l’EESAB BREST, et Victor Dubois, de Télécom Bretagne.
Concept :
» Dansons la lumière » est une installation retranscrivant un lien, une connexion entre un mouvement et la lumière. Nous nous sommes concentrés ici sur le mouvement de la main, mais nous imaginons ce projet à l’échelle du corps pour que la danse devienne lumière. La lumière serait écho du danseur ou son partenaire.
D’un coté, des capteurs de lumière reprennent le mouvement effectué par la main et de l’autre un cube à LEDs retranscrit ce mouvement en points lumineux. La lumière devient empreinte du mouvement.
Matériel :
- 1 Arduino Mega 2560
- 2 ou 3 télémètre à ultrason (par exemple : un clone du PING de Parallax, ou un SRF05)
- un cube à LED
- des fils, une breadboard, de la patience !
Nous avons réutilisé le cube à LED réalisé lors du projet « Cube à LED Météo« , dont nous avons modifié le code.
Fonctionnement :
Le cube à LED est placé devant soi, avec un télémètre de part et d’autre. Les télémètres sont dirigés vers le haut. On place alors ses mains au dessus des télémètres, et en fonction de la distance des mains par rapport aux télémètres, l’image du cube change.
Le principe des télémètres à ultrasons est qu’ils émettent une onde ultrason, et attendent la réponse. Ils mesurent alors le temps que met le son à faire l’aller-retour entre l’émetteur et le premier obstacle rencontré. C’est cette information qui est fournie à Arduino. Nous avons utilisé deux types d’ultrason : un clone du PING de Parallax, et un SRF05.
Améliorations :
Si nous avions eu le temps, nous aurions essentiellement travaillé deux points :
Tout d’abord, ajouter un troisième ultrason. Cela permettrait de faire des visualisation plus intéressantes encore. La principale difficulté réside dans les interférences entre ultrasons : comme nous n’utilisons que des capteurs classiques, ils sont tous à la même fréquence standard : 40kHz. Si une onde émise par un capteur parvient à un autre, par exemple en rebondissant sur la main du manipulateur, alors les mesures sont faussées et la visualisation n’est pas celle attendue. Il faut donc prendre des précautions et bien séparer les capteurs.
Ensuite, nous nous serions penché sur le problème du clignotement du cube. En effet, le principe du cube à LED est d’allumer rangée par rangée. Elles clignotent alors très vite, donnant l’illusion d’être allumée en permanence. Le problème est que les télémètres mobilisent l’Arduino, l’empêchant pendant un court instant de changer l’état des LEDs. Pour palier ce problèmes, nous avons quelques pistes, mais la seule qui nous parait réellement fiable est d’utiliser deux Arduinos : l’un dédié au cube à LEDs, qui ne s’arrête jamais d’allumer et d’éteindre les LEDs ; et un autre, dédié aux capteurs. Celui-ci peut être mobilisé sans risque sur l’affichage. On utiliserait alors une liaison I2C entre les deux Arduinos, en ne transmettant que les valeurs des capteurs. Nous n’avons malheureusement pas eu le temps d’implémenter cette solution.
Pour finir, voici quelques vues du cube en fonctionnement :
Réaliser sa propre installation domotique : architecture
La première étape pour réaliser notre installation domotique est de définir l’architecture de notre installation. Cette architecture n’est bien sûr pas figée, et pourrait très bien être modifiée au gré de l’évolution des besoins et des solutions.
Afin de pouvoir traiter les informations et agir en conséquence, il sera nécessaire de disposer d’un serveur allumé en permanence. Cependant, pour limiter les coûts et la consommation électrique, la contrainte est la suivante : le serveur doit pouvoir tourner sans problèmes sans une carte faible puissance, comme par exemple une Raspberry Pi ou une BeagleBoard. Il existe plusieurs solutions domotiques libres, je vous conseille l’excellent article de linuxfr.org qui fait un tour d’horizon intéressant des technologies.
Le choix de la solution conditionne les interfaces utilisées pour communiquer entre les différents éléments. C’est donc un choix primordial. Trois solutions ont retenu mon attention :
- LinuxMCE, qui est une distribution Linux complète basée sur Ubuntu. Elle utilise beaucoup de solutions libres, mais l’utilisation d’une distribution Linux dédiée limite grandement la généricité de la solution.
- OpenRemote, qui est une solution professionnelle basée sur Java. C’est une solution qui a l’air intéressante, qui propose des applications pour la plupart des écrans de la maison, mais le Java s’adapte encore mal à des plateformes faibles puissances.
- Domogik, qui est une solution très jeune, développée par des français. C’est la solution que j’ai adoptée, pour trois raisons principales. Tout d’abord, elle est développée en Python. Ce n’est pas que j’apprécie particulièrement ce langage, mais il est efficace, simple d’accès, et dispose d’une communauté assez active. Ensuite, Domogik intégre déjà beaucoup de protocoles, sous la forme de plugins. Les plugins sont faciles à développer, et permettent de sélectionner quels éléments seront actifs. Ce fonctionnement par plugin signifie aussi qu’on peut limiter facilement le champ d’action de Domogik, et interfacer d’autres logiciels. Finalement, Domogik est basé sur xPL, qui est un protocole de communication simple et efficace, à base de texte. Pas besoin de cablage compliqué, il suffit d’une interface permettant d’envoyer des caractères.
L’architecture de la solution domotique sera donc axée autour du xPL. Tous les éléments devront, à un moment donné, finir par « parler » le xPL. Cependant, il est facile de réaliser celà sans pour autant perdre en généricité, le xPL étant un protocole situé assez haut dans les couches de la pile protocolaire (en fait, normalement, le xPL s’utilise au dessus de l’Ethernet…). Domogik a également le bon goût de permettre d’avoir plusieurs « serveurs », ou plus précisément plusieurs hôtes, qui communiqueront en Ethernet. Ainsi la solution, bien que centralisée (il y a toujours un hôte principal), permet une certaine distribution de l’information, et surtout une réutilisation de l’infrastructure existante.
Installer Domogik est relativement aisé. J’ai installé la version de développement, disponible via Mercurial. Pour contrôler tout ça, j’ai également installé Domoweb, l’interface Web de Domogik, et Domodroid, l’interface Android. Le site de Domogik, bien que très très lent, est complet, et l’information est assez simple à trouver. Le tutorial pour l’installation en particulier est très bien fait.
Une fois que tout est installé, on se retrouve avec un serveur domotiqe, un moyen de le contrôler, mais rien à récupérer ou à contrôler… Nous verrons ça dans la prochaine note !
Réaliser sa propre installation domotique : Introduction
Je me suis lancé depuis début 2013 dans un projet à long terme, visant à mettre au point une installation domotique complète à la maison. De manière simplifiée, je me suis fixé les objectifs suivants pour mon projet :
- la solution ne doit pas être une solution de bricolage. Elle doit pouvoir rivaliser en efficacité avec les solutions disponibles (à prix d’or ! ) dans le commerce. Elle ne doit pas fonctionner que chez moi, mais être transposable sans trop de difficultés dans n’importe quel cas. Le côté esthétique du produit final est également à prendre en compte.
- la solution ne doit pas être trop chère. La notion de chère dépend bien sûr des moyens de chacun, et des éléments dont on parle. Pour chacun des éléments de la solution final, il faudra discuter du prix.
- pour des raisons d’éthique personnelle, la solution devra s’appuyer uniquement sur du logiciel libre et du matériel ouvert. Tout matériel dont l’intégration nécessite du reverse-engineering ne sera pas pris en compte. Le matériel n’a pas besoin d’être libre, mais il doit pouvoir être utilisé sans avoir à réfléchir au moyen de communiquer avec lui (on excluera typiquement de la solution toutes les solutions de transmission sans fil du commerce pour lesquels il n’existe pas de pile libre). Afin de respecter cet esprit d’ouverture, toutes mes contributions seront elles aussi mises à disposition.
- la solution doit être sécurisée. Le principe de ce projet est de centraliser l’intégralité des informations de mon logement. Je ne veux pas que ces informations soient utilisables par n’importe qui, ni que quiconque puisse venir jouer avec mes réglages de chauffage sans que je l’ai autorisé. Plus embêtant encore, si j’ajoute une caméra dans mon appartement, je ne veux pas que n’importe qui puisse utiliser cette caméra pour m’espionner. Même si la notion de sécurité ne sera pas primordiale au début du projet, il faudra la prendre en compte à un moment ou à un autre, en gardant bien à l’esprit qu’il n’existe pas de solutions inviolables.
Ce type de projet au long cours a l’avantage (et l’inconvénient aussi) de fournir un nombre conséquent de mini-projets. J’essaierai de faire des notes assez régulière sur l’avancement du projet, sur le choix des différentes solutions, …. Certaines parties du projet seront probablement l’occasion de proposer des réalisations dans le portfolio. Je suis ouvert à toute discussion pour me proposer des solutions plus efficaces, plus élégantes, ou tout simplement différentes de celles que je proposerai.
Dans la prochaine note, je présenterai un peu quels sont les objectifs pour la première version de mon installation, et quel fonctionnement j’adopterai pour le développement. Je présenterai également succintement l’écosystème de la domotique.
PARKUINO
PARKUINO ? Par qui ? Pour qui ?
PARKUINO est un projet développé durant la première semaine d’inter-semestre 2013 par le trio d’élèves FARHANE Karim, ELIDRISSI Yassir, HADFAT Ayoub.
Il est destiné à venir en aide au stationnement des voitures dans les parkings ou les garages.
Le fruit de ce projet se présente sous forme de deux boîtiers :
- L’un posé sur l’obstacle devant lequel la voiture veut se garer ; il permet l’allumage de feux de signalisation (verts/jaunes/rouges) au fur et à mesure que la voiture s’approche de l’obstacle et finalement la sonnerie d’alarme d’un buzzer lorsque celle-ci est trop proche.
- L’autre situé à l’intérieur de la voiture ; il permet d’afficher la distance de la voiture à l’obstacle.
La réalisation de ce projet a nécessité le recours au matériel suivant :
- 2 Arduino UNO.
- 2 Shields Xbee.
- 2 LED rouges, 2 LED jaunes, 2 LED vertes.
- 1 Buzzer.
- 1 Télémètre SRF.
- 1 Afficheur LCD, 1 potentiomètre.
Schéma du montage et principe de fonctionnement :
Montage émetteur
Code Emetteur :
const int Spin = 8; // pin du télémètre
const int led[] = {9,2,3,4,5,6}; // leds indicatrices
const int hp = 7; // haut-parleur
const int borne[] = {5, 15, 30, 60, 90, 120}; // on définit les distances d’activation des leds
const byte borneLim=240;//Limite au-delà de laquelle on éteint l’afficheur du montage récépteur
void setup() {
for(int i=0; i<6; i++){
pinMode(led[i], OUTPUT);
}
pinMode(hp, OUTPUT);
Serial.begin(9600); // démarrage port série
}
void loop() {
byte distance=calculDistance();
if (distance < borne[0] ) {
for(int i =0; i<6;i++){
digitalWrite(led[i], HIGH);
}
digitalWrite(hp, HIGH);
}
if (distance > borne[0] and distance <= borne[1] ) {
for(int i =0; i < 5;i++){
digitalWrite(led[i], HIGH);
}
digitalWrite(led[5], LOW);
digitalWrite(hp, LOW);
}
if (distance > borne[1] and distance <= borne[2]) {
for(int i =0; i < 4;i++){
digitalWrite(led[i], HIGH);
}
for(int i =4; i < 6;i++){
digitalWrite(led[i], LOW);
}
digitalWrite(hp, LOW);
}
if (distance > borne[2] and distance <= borne[3]) {
for(int i =0; i < 3;i++){
digitalWrite(led[i], HIGH);
}
for(int i =3; i < 6;i++){
digitalWrite(led[i], LOW);
}
digitalWrite(hp, LOW);
}
if (distance > borne[3] and distance <= borne[4]) {
for(int i =0; i < 2;i++){
digitalWrite(led[i], HIGH);
}
for(int i =2; i < 6;i++){
digitalWrite(led[i], LOW);
}
digitalWrite(hp, LOW);
}
if (distance > borne[4] and distance < borne[5]) {
for(int i =0; i < 1;i++){
digitalWrite(led[i], HIGH);
}
for(int i =1; i < 6;i++){
digitalWrite(led[i], LOW);
}
digitalWrite(hp, LOW);
}
if (distance >= borne[5] and distance <= borneLim) {
for(int i =0; i < 6;i++){
digitalWrite(led[i], LOW);
}
digitalWrite(led[0], LOW);
digitalWrite(hp, LOW);
}
if(distance > borneLim) distance =borneLim+1;
Serial.write(distance);
delay(100);
}
byte calculDistance() { //Fonction pour calculer la distance
byte distance = 0;
int duration;
pinMode(Spin, OUTPUT);
digitalWrite(Spin, LOW);
delayMicroseconds(2);
digitalWrite(Spin, HIGH);
delayMicroseconds(10);
digitalWrite(Spin, LOW);
pinMode(Spin, INPUT);
duration = pulseIn(Spin, HIGH);
distance = duration / 58;
return(distance);
}
Montage récepteur
Code Récepteur:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
byte incomingByte;
const byte borneLim=241;
void setup() {
Serial.begin(9600);
lcd.begin(16,2);
}
void loop() {
if (Serial.available() > 0) {
incomingByte = Serial.read();
Serial.println(incomingByte);
}
if(!(incomingByte==borneLim)) {
lcd.setCursor(0, 0);
lcd.print(« DISTANCE: « );
lcd.print(incomingByte);
lcd.print( » cm »);
lcd.setCursor(0,1);
if(incomingByte < 10) lcd.print(« ATTENTION ! »);
if(incomingByte >= 10 and incomingByte < 30) lcd.print(« DOUCEMENT »);
if(incomingByte >= 30) lcd.print(« CONTINUEZ »);
lcd.setCursor(16,1);
}
else {
}
delay(100);
lcd.clear();
}
Le télémètre SRF mesure constamment la distance de la voiture à l’obstacle.
Au fur et à mesure que celle-ci descend au dessus des bornes prédéfinies, une LED de plus s’allume suivant cet ordre :
1 LED verte → 2 LEDs vertes → 2 LEDs vertes + 1 LED jaune → 2 LEDs vertes + 2 LEDs jaunes →
2 LEDs vertes + 2 LEDs jaunes + 1 LED rouges → 2 LEDs vertes + 2 LEDs jaunes + 2 LEDs rouges
Lorsque toutes les LEDs sont allumées, la sonnerie d’alarme du buzzer se déclenche en plus, signalant que la voiture a atteint une position critique.
En même temps, le Xbee monté sur l’Arduino émetteur se charge d’envoyer la distance (en centimètres) captée par le télémètre à l’autre Xbee monté sur l’Arduino récepteur.
Cette distance est alors affichée sur l’afficheur LCD (en centimètres) et accompagnée d’une commande qui en dépend :
-
« Continuez » tant qu’aucune LED jaune n’est allumée.
-
« Doucement » tant qu’aucune LED rouge n’est allumée.
-
« Attention ! » lorsque toutes les LEDs sont allumées et que la sonnerie du buzzer est déclenchée.
Remarques :
-
Le potentiomètre qu’on peut voir sur le montage sert à régler la luminosité de l’afficheur LCD.
-
Pour des raisons de codage sur 1 byte, la distance maximale à partir de laquelle le capteur télémètre devient sensible est 255 cm.
Version 2.0 ?
Comme les stationneurs deviennent de plus en plus paresseux, nous sommes conscients que la version actuelle du projet ne peut pas les satisfaire entièrement.
Une perspective d’amélioration serait donc d’intégrer au système un moyen de reconnaissance vocale permettant de lire via un haut parleur la distance affichée sur l’écran LCD.
Encore mieux : ajouter au système une caméra permettant au chauffeur de voir en temps réel l’évolution de son espace de stationnement.
Le Téléfab en ébullition
Du 21 janvier au 25 janvier, puis du 28 janvier au 1er février, l’activité a été intense au Téléfab…
Les intersemestres ont permis à une trentaine d’étudiants de Télécom Bretagne et à une quinzaine d’étudiants de L’ESAB de Brest, de prendre en main les technologies disponibles au fablab, d’imaginer, créer et mettre au point des projets variés.
Apprendre par soi même et à l’aide des autres, expérimenter, confronter ses idées, des semaines riches en apprentissage.
Visitez le portfolio pour avoir une idée de la diversité des projets :
- des « cubes à leds » : cubes à leds météo, Led’s zeppelin, leds et mouvement
- des jeux : la bataille navale en solo, télé-nunchuck et arduino, maison piégée, tourelle
- des applications connectées au web : gmail notifier
- du dessin smartphone-afficheur à leds : led’s draw,
- de l’interactivité : une poignée émotive okaeri, Touch my Yoda
- de la musique : Theremin, escalier musical
- des effets lumineux : jouer avec la persistance rétinienne











































