Table des matières

Stage LPH: février 2019

Introduction

Stage LPH de février à L'UBO Open Factory

L'objectif de cet atelier est de réaliser une petite station météo et domotique à base d'arduino.

Public cible 12 jeunes
Date 18, 19 et 20 février
Lieu UBO Open Factory

Modalités

Une inscription est nécessaire pour pouvoir planifier. Une adhésion (de 20 euros) et une participation financière (60 euros) pour le matériel (en fonction du projet) seront demandées.

Planning et contenu

État du stock et matériel pour le stage

Stock à vérifier en fonction des projets. Voici une première liste de matériel à apporter avec nous pour le stage:

Intitulé Quantité dans le stock A commander/produire
Servo moteur (1 par kit)
Arduino nano (avec câble USB)
Câbles élec
écran pour le vidéo-projecteur
vidéo-projecteur
2 rallonges
4 multiprise
12 PCs: (j'en ai déjà 5 de prêt, il m'en reste 2/3 à préparer)
alimentations PC
souris PC
12 cartes arduinos (avec cordons USB)
12 DHT 11
12 relais
12 transistors
12 servo moteurs
12 LDR
12 ventilateurs
cartes de support pour les éléments
fils de connexion
3/4 fers à souder
4 tapis pour fer à souder
4 support fer à souder
étain
fils
en option (afficheurs LCD, module bluetooth)

Liste de tâches

Tâche Qui Opération
Faire l'état du stock Christian et Stéphane
Commande matériel Christian et Stéphane
Communication sur les listes de diffusion Christian et Stéphane
Communication “Affiche”
Gestion des inscriptions
Validation des inscriptions
Planification des projets

Présent pour animer

Animation de l'atelier:

Déroulé du projet

Contacts

Structure Nom Prénom Rôle sur le projet / poste
Maison du libre Stéphane Blanc Logistique et animation
Maison du libre Christian JACOLOT Logistique et animation

Remerciements

Nous remercions Yves et Matthieu pour accueillir le stage dans les locaux de l'UBO Open Factory.

Préparation des PC

Installation de xubuntu 18.04 sur les PC, iso sur clé USB.

Mise à jour et installation des logiciels/paquets nécessaires:

$ sudo apt update
$ sudo apt upgrade
$ sudo apt install git mercurial build-essential arduino-core arduino-mk gcc-avr avr-libc openjdk-8-jdk
$ sudo apt install squeak-vm squeak-plugins-scratch
$ sudo apt install nodejs npm
$ id
$ sudo usermod -a -G dialout $USER
$ more /etc/group
# télécharger arduino sur arduino.cc / linux 32 bits
$ cd Téléchargements/
$ tar xf arduino-1.8.8-linux32.tar.xz 
$ cd arduino-1.8.8/
$ ./install.sh 
$ cd
# démarrer arduino IDE
# menu Outils / Gérer les bibliothèques
# installer: circuit playground, unified sensor, DHT sensor library
$ sudo npm install -g --unsafe-perm node-red
$ node-red
# navigateur web sur localhost:1880
# installer via palette: node-red-node-serialport et node-red-dashboard
$ sudo apt install logisim openssh-server 
$ sudo apt install gcc-avr avr-libc flashplugin-installer algobox blender python3-dev python3-setuptools python3-numpy
$ sudo apt install python3-opengl ffmpeg libsdl-image1.2-dev libsdl-mixer1.2-dev libsdl-ttf2.0-dev libsmpeg-dev libsdl1.2-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev libtiff5-dev libx11-6 libx11-dev fluid-soundfont-gm timgm6mb-soundfont xfonts-base xfonts-100dpi xfonts-75dpi xfonts-cyrillic fonts-freefont-ttf libfreetype6-dev 
$ java -version
$ javac -version
$ sudo update-alternatives --config java
# choisir java 8
$ java -version
$ sudo add-apt-repository ppa:openscad/releases
$ sudo apt update
$ sudo apt install openscad
$ sudo apt install fritzing fritzing-parts gimp

Présentation

Documents

Fichier de présentation mdl_stage_lph_fevrier_2019.odp

Code

Code Arduino pour piloter le relai tout en récupérant la température et l'humidité:

int relayPin = 3;                           // relay pin -- Digital 3
int relayState = HIGH;                      

int incomingByte = 0;   // for incoming serial data

unsigned long previousMillis = 0;  

long checkDHT = 2000;

void setup() {
  Serial.begin(9600); 
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, relayState);
  previousMillis = millis();
}

void loop() {
  // send data only when you receive data:
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();
//    Serial.print("I received: ");
//    Serial.println(incomingByte, DEC);    
    if (incomingByte == 49) { // ASCII: 1 => 49
      relayState = HIGH;
    } else {
      relayState = LOW;
    }
  }
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= checkDHT) {
    previousMillis = currentMillis;  // Remember the time
    Serial.print("{\"hum\":");
    Serial.print(random(20,80));
    Serial.print(",\"temp\":");
    Serial.print(random(0,50));
    Serial.println("}");
  }
  // set the relay: 
  digitalWrite(relayPin, relayState);
}

Nodered flow:

Avec servo moteur

#include <VarSpeedServo.h> 
#include <ArduinoJson.h>

VarSpeedServo myservo;    // create servo object to control a servo 
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position
int positionServo = 0;
int speedServo = 100;

// Serial reading buffer
const byte numChars = 60;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;

StaticJsonBuffer<120> jsonBuffer;

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
   
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}


void setup() {
  pinMode(9, OUTPUT);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin(9600);
  // myservo.write(positionServo, speedServo, true);
  newData = false;
}

void loop() {
  recvWithEndMarker();
  if (newData == true) {
    JsonObject& root = jsonBuffer.parseObject(receivedChars);

    if (!root.success()) {
      Serial.println("parseObject() failed");
      return;
    }

    // Fetch values.
    //
    // Most of the time, you can rely on the implicit casts.
    // In other case, you can do root["time"].as<long>();
    if(root.containsKey("servo")) {
      positionServo = root["servo"][0];
      speedServo = root["servo"][1];

      // Print values.
      Serial.println(positionServo);
      Serial.println(speedServo);
      // myservo.write(positionServo, speedServo); //, true);        // move to 180 degrees, use a speed of 30, wait until move is complete
    } else {
      Serial.println("parseObject() servo key not found");      
    }
  
  newData = false;
  }  
}

Arduino: Programme complet (JSON, relai, ventilo, LDR, DHT11, servo-moteur):

#include <VarSpeedServo.h> 
#include <ArduinoJson.h>
#include "DHT.h"

#define LDRPIN 0
#define DHTPIN 2     // Digital pin connected to the DHT sensor
#define VENTILOPIN 7
#define RELAIPIN 8
#define SERVOPIN 9

#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
VarSpeedServo myservo;

unsigned long time;
unsigned long diff;
int ldrValue = 0;

int relayState = LOW;
int ventiloState = LOW;

int positionServo = 0;
int speedServo = 100;

long checkDHT = 2000;

// Serial reading buffer
const byte numChars = 60;
char receivedChars[numChars];   // an array to store the received data
boolean newData = false;

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
   
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}


void setup() {
  pinMode(VENTILOPIN, OUTPUT);
  pinMode(RELAIPIN, OUTPUT); // relai, broche en mode sortie
  pinMode(SERVOPIN, OUTPUT);

  time = millis();
  dht.begin();
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin(9600);
  newData = false;
}

void loop() {
  StaticJsonBuffer<120> jsonBuffer;
  recvWithEndMarker();
  if (newData == true) {
    JsonObject& root = jsonBuffer.parseObject(receivedChars);

    if (!root.success()) {
      Serial.println("parseObject() failed");
      receivedChars[0] = '\0';
      return;
    }
    if(root.containsKey("servo")) {
      positionServo = root["servo"][0];
      speedServo = root["servo"][1];
      myservo.write(positionServo, speedServo, true);
    }
    
    if (root.containsKey("ventilo")) {
      int ventiloValue = root["ventilo"];
      if (ventiloValue == 1) {
        ventiloState = HIGH;
      } else {
        ventiloState = LOW;
      }            
    }
    
    if (root.containsKey("relai")) {
      int relaiValue = root["relai"];
      if (relaiValue == 1) {
        relayState = HIGH;
      } else {
        relayState = LOW;
      }
    } else {
      Serial.println("parseObject() servo key not found");
    }
  
  newData = false;
  }
  diff = millis() - time;
  if (diff >= checkDHT) {
    time = millis();
    float h = dht.readHumidity();
    float t = dht.readTemperature();
    // read the value from the sensor:
    ldrValue = analogRead(LDRPIN);

    Serial.print("{\"hum\":");
    Serial.print(h);
    Serial.print(",\"temp\":");
    Serial.print(t);
    Serial.print(",\"ldr\":");
    Serial.print(ldrValue);
    Serial.println("}");
  } 
  // set the relay: 
  digitalWrite(RELAIPIN, relayState);

  // set the ventilo: 
  digitalWrite(VENTILOPIN, ventiloState);
}

Nodered flow

[{"id":"3d2aea77.badaf6","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"3f949c8b.e9662c","type":"serial in","z":"3d2aea77.badaf6","name":"Arduino liaison série","serial":"7934b4c5.a4c6ac","x":118.50001525878906,"y":105,"wires":[["58f6c8f2.f84108","ee8168db.c30cd8"]]},{"id":"58f6c8f2.f84108","type":"debug","z":"3d2aea77.badaf6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":708.5,"y":70,"wires":[]},{"id":"ee8168db.c30cd8","type":"json","z":"3d2aea77.badaf6","name":"","property":"payload","action":"","pretty":false,"x":108.49998474121094,"y":204,"wires":[["47a6359d.a05d6c","ad8bab3b.6151e"]]},{"id":"47a6359d.a05d6c","type":"debug","z":"3d2aea77.badaf6","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":709.5,"y":162,"wires":[]},{"id":"ad8bab3b.6151e","type":"function","z":"3d2aea77.badaf6","name":"Récupérer Humidity","func":"msg.payload = msg.payload.hum;\nreturn msg;","outputs":1,"noerr":0,"x":156.50001525878906,"y":291,"wires":[["49353fa9.b11378","5aa63008.6e225"]]},{"id":"49353fa9.b11378","type":"ui_chart","z":"3d2aea77.badaf6","name":"","group":"6236518f.ee41e8","order":1,"width":0,"height":0,"label":"Humidité","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"10","removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":798.5,"y":274.9999694824219,"wires":[[],[]]},{"id":"5aa63008.6e225","type":"switch","z":"3d2aea77.badaf6","name":"Humidité >= 60","property":"payload.state","propertyType":"msg","rules":[{"t":"gte","v":"60","vt":"num"},{"t":"lt","v":"60","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":147.83338928222656,"y":384.333251953125,"wires":[["13b76f6c.0304c9"],["2c7f8898.6e7d38"]]},{"id":"3a206f96.153a9","type":"ui_button","z":"3d2aea77.badaf6","name":"","group":"6236518f.ee41e8","order":3,"width":0,"height":0,"passthru":true,"label":"Arrêter le ventilo","tooltip":"","color":"","bgcolor":"","icon":"","payload":"2","payloadType":"str","topic":"","x":512.8333740234375,"y":646.3333740234375,"wires":[[]]},{"id":"902a3c34.bdb6d","type":"serial out","z":"3d2aea77.badaf6","name":"Arduino sortie","serial":"7934b4c5.a4c6ac","x":822.833251953125,"y":400.16668701171875,"wires":[]},{"id":"e06793a6.3b1558","type":"ui_switch","z":"3d2aea77.badaf6","name":"","label":"Automatique","tooltip":"","group":"6236518f.ee41e8","order":4,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":328.8333740234375,"y":531.3333740234375,"wires":[["77a8e113.0544f"]]},{"id":"77a8e113.0544f","type":"switch","z":"3d2aea77.badaf6","name":"","property":"payload","propertyType":"msg","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":551.8333740234375,"y":552.3333740234375,"wires":[[],[]]},{"id":"13b76f6c.0304c9","type":"function","z":"3d2aea77.badaf6","name":"Démarrer ventilo","func":"msg.payload = \"{\\\"ventilo\\\":1}\\n\"\nreturn msg;","outputs":1,"noerr":0,"x":371.8333740234375,"y":355.66668701171875,"wires":[["902a3c34.bdb6d"]]},{"id":"2c7f8898.6e7d38","type":"function","z":"3d2aea77.badaf6","name":"Arrêter ventilo","func":"msg.payload = \"{\\\"ventilo\\\":0}\\n\"\nreturn msg;","outputs":1,"noerr":0,"x":347.2833251953125,"y":437.73333740234375,"wires":[["902a3c34.bdb6d"]]},{"id":"7934b4c5.a4c6ac","type":"serial-port","z":"","serialport":"/dev/ttyUSB0","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":true,"responsetimeout":"10000"},{"id":"6236518f.ee41e8","type":"ui_group","z":"","name":"Chambre","tab":"ad170f6e.de74f8","disp":true,"width":"6","collapse":false},{"id":"ad170f6e.de74f8","type":"ui_tab","z":"","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]