serveur WEB APACHE sur RPI

créer un serveur WEB avec votre raspberry PI c’est possible , nous allons voir comment faire tout cela.

MISE A JOUR DU PI:

comme toujours avant toute manip d’installation , faire une mise a jour de votre systeme:

sudo apt update
sudo apt upgrade 

INSTALLER APACHE :

nous allons commencer par installer la couche logicielle du serveur WEB , à savoir APACHE2 . rien de plus facile , taper:

sudo apt install apache2

TESTER L’INSTALLATION:

une fois l’installation faite , pour vérifier que tout fonctionne, essayer une connexion sur votre RPI via un PC lui aussi connecté sur votre réseau domestique . tout d’abord , récupérer l’adresse IP de votre RPI. pour cela positionner le pointeur de votre souris sur l’icône de connexion réseau dans la barre de menu du RPI ( en haut ou en bas a droite suivant le type d’affichage choisis).

vous devriez voir apparaitre quelque chose du genre:

eth0: Configured 193.168.1.17

c’est l’adresse IP de votre RPI sur votre reseau domestique.

ouvrez votre navigateur WEB et taper dans la barre de navigation l’adresse IP trouvée avec devant “http://” :

http://193.168.1.17

si tout est OK vous devriez voir apparaitre une page de ce type signe que tout fonctionne:

APACHE est donc installé et il utilise le répertoire /var/www/html comme racine pour le site.

l’installation a déposé dans le repertoire /var/www/html un fichier Index.html qui est la page d’exemple qui s’affiche .

quand on contact l’adresse IP du RPI , on se connecte sur le port 80 du RPI (commande http://…) et apache va cherche dans le repertoire /var/www/html/.

par exemple , si vous tappez : http:// 193.168.1.17/monsite apache cherchera automatiquement le fichier “monsite” dans le repertoire /var/www/html/ et si on ne rajoute pas de nom de fichier et juste la commande: http:// 193.168.1.17/ , apache va chercher le fichier index.html comme tout appel classique a un site internet .

DONNER LES DROITS D’ACCÈS:

nous allons donner des droits d’accès au dossier d’apache , ce qui permettra d’administrer les sites installes . Pour cela, lancez les commandes suivantes :

sudo chown -R pi:www-data /var/www/html/
sudo chmod -R 770 /var/www/html/

INSTALLER PHP:

pour pouvoir faire fonctionner votre serveur et par exemple installer un site internet , il faudra pour interpréter des commandes PHP. pour cela nous allons devoir installer l’interpréteur PHP qui exécutera ces commandes PHP.

pour installer PHP sur votre RPI, taper:

sudo apt install php php-mbstring

TESTER PHP:

avant de continuer plus loin, comme pour apache, nous allons tester le fonctionnement de PHP. pour cela avec l’explorateur du RPI ou en ligne de commande , aller supprimer le fichier Index.html qui est dans le répertoire /var/www/html/ puis créer un fichier index.php avec un editeur de texte et mettez y la commande simple suivante:

<?php echo "Coucou, comment allez vous"; ?>

MÉTÉO ARDUINO ETHERNET basique

une station météo ARDUINO en réseau privé via votre BOX c’est possible avec un Ethernet Shield . nous allons voir comment.

le tuto est basé sur l’utilisation d’un Shield ethernet Keyestudio mais le principe est le même avec d’autre shield Ethernet. l’avantage du shield Keyestudio est qu’il comporte en plus un slot pour carte micros SD. outre la transmission Ethernet des données, il sera donc également possible de les sauvegarder sur carte micro SD.

petit problème global avec les Shield Ethernet , contrairement au shiel SD , ils n’ont pas d’Horloge RTC intégrée , il va donc falloir en ajouter une. dans ce tuto , on utilisera un module TinyRTC I2C. mais tout autre module RTC peut convenir.

par ailleurs , nous allons profiter de ce module pour notre premier exemple de transmission de données via câble réseau Ethernet en affichant tout simplement la date et l’heure récupérée sur le module dans une page de navigateur .

LE MONTAGE :

pas besoin de schéma fritzing , ici la connexion est simple , on relie les broche Vcc et GND du module RTC aux borches GND et 5V de l’arduino uno et les broches SCL et SDA respectivement au broche Analogiques A5 et A4 de l’Arduino UNO.

LE PROGRAMME :

#include <SPI.h>
#include <Ethernet.h>
#include "RTClib.h"
RTC_DS1307 rtc;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
EthernetServer server(80);

void setup() {
  rtc.begin();
  SPI.begin();
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop() {  
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
          DateTime time = rtc.now();
          client.print("DATE: ");
          client.println(time.timestamp(DateTime::TIMESTAMP_DATE));
          client.print("TIME: ");
          client.println(time.timestamp(DateTime::TIMESTAMP_TIME));
          break;
     }
    delay(100);
    client.stop();
  }
}

les librairies sont standard , si pas disponibles dans votre IDE , une petite recherche internet vous permettra de les récupérer. en début de programme , via les instruction byte mac[] et IPadress on fixe l’adresse Mac et l’adresse IP du shield ( a modifier suivant les données de votre Box internet) . ensuite la partie void setup , démarre les librairies , et la partie void loop ouvre le serveur puis la boucle while exécute les lignes suivantes tant que la connexion est OK . dans la boucle on lit les données date et heure du module TinyRTC puis on les imprime sur le serveur client via une instruction type “client.print() “

ne reste plus qu’a lire tout ça a l’adresse IP avec un navigateur Web . pas très compliqué , ouvrir votre navigateur préféré et tapez l’adresse IP (ici 192.168.1.15) et vous devriez voir apparaitre quelque chose comme ci dessous:

bien entendu , si vous utilisez votre smartphone connecté en WIFI a votre réseau domestique, ça marche aussi avec l’explorateur web du smartphone.

le problème avec l’affichage obtenu c’est que la structure est extrêmement minimale et surtout la page ne se régénère pas automatiquement , il faut la régénère à la main pour voire l’heure évoluer.

nous allons donc mettre en place une page web basique en HTML avec régénération automatique. et rajouter des test pour la connexion. le programme plus bas est une modification pure et simple d’un programme exemple livré avec la bibliothèque “Ethernet.h” que l’on trouve sous l’IDE ARDUINO dans le chemin:

Fichier/example/Ethernet/Webserver

STRUCTURE MINIMALE D’UNE PAGE HTML

première chose a intégrer , la structure minimale standard obligatoire d’une page web en HTML . ci dessous un petit schéma qui montre les éléments (balises) constitutifs d’une page web standard minimale.

  • <!DOCTYPE html> est la balise qui précise le langage utilisé .
  • <html> est la balise délimite le début la zone de contenu html
  • </html> est la balise qui symbolise la fin de la zone html
  • a l’intérieur de cette zone html , on va trouver deux types de balises:
  • <head> et </head> pour définir debut et fin de la zone des données d’entête
  • <body> et</body> qui délimitent la zone de texte (corps) de la page web

la zone d’entête doit comporter le titre de la page entre les balises <title> et </title>

et le type d’encodage utilisé ici <meta charset=”utf-8″>

petite particularité , sous C++ ARDUINO , concernant la rédaction, il faudra écrire:

<meta charset=\”utf-8\”> </meta>

pour demander la régénération de la page , il faudra insérer Refresh: x avec X le temps de rafraichissement.

passons au programme modifié avec en violet les rajouts par rapport au programme initial .

#include <SPI.h>
#include <Ethernet.h>
#include "RTClib.h"
RTC_DS1307 rtc;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
EthernetServer server(80);

void setup() {
  rtc.begin();
  SPI.begin();
  Ethernet.begin(mac, ip);
  server.begin();
}

void loop() {  
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // cloture connexion
          client.println("Refresh: 10");  // rafraichissement de page toute les 10s
          client.println();
          client.println("<!DOCTYPE HTML>");  // specifie le type de document=HTML
          client.println("<html>");  // debut de la page
              client.println("<head>");
                  client.println("<meta charset=\"utf-8\"></meta>"); //encodage page
                  client.println("<title>METEO LOCALE</title>");  // titre de la page
              client.println("</head>");
              client.println("<body>"); // debut de zone du contenu visible
                    DateTime time = rtc.now();
                    client.print("DATE: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_DATE));
                    client.print("  TIME: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_TIME));
              client.println("</body>"); // fin de zone du contenu 
          client.println("</html>");   // fin de la page         
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1000);
    // close the connection:
    client.stop();
  }
}

une fois le programme déversé dans l’arduino , si l’on ouvre le navigateur et que l’on saisi l’adresse 192.168.1.15 , voici ce que donne l’affichage :

on remarque que maintenant la page a un titre “METEO LOCALE” , date et heure sont sur la même ligne et sont mises a jour toutes les 10″ ( seule l’heure varie apres mise a jour).

AJOUT DES CAPTEURS METEO

pour l’étape suivante , ne reste plus qu’a connecter vos capteur météo, pour changer de la version développée ici , nous allons simplifier le montage et remplacer les 2 capteur DHT22 et BMP280 , par un capteur BME280 qui intègre les 3 fonctions; température, pression et Humidité sur un seul module .

c’est un capteur I2C dont le câblage sera donc extrêmement simple, il viendra en parallèle de l’Horloge RTC elle même branchée sur l’I2C. comme toujours avec l’I2C , il faudra contrôler les adresses I2C de chaque composant ( Ici 0x76 pour le capteur BME280 et 0x50 pour l’horloge RTC) et vérifier dans les fichiers des bibliothèques utilisées que les adresses sont les bonnes et faire les modif le cas échéant).

voyons maintenant le programme :

par rapport a la version précédente du programme , en violet les ajouts/évolutions concernant le capteur , et pour rendre les données plus visible sur la page , la taille des caractères a été augmentée => ajout d’une ligne ” client.print(“<font size=’10’>”);

pour aérer la page , chaque information est affichée sur une ligne différente , le saut de ligne se fait par l’envoi d’un client.print(“<br/>”);

#include <Wire.h>
#include <SPI.h>
#include <Ethernet.h>
#include "RTClib.h"
#include <SparkFunBME280.h>
RTC_DS1307 rtc;
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192, 168, 1, 15);
BME280 mySensor;
EthernetServer server(80);

void setup() {
  Wire.begin();
  rtc.begin();
  SPI.begin();
  Ethernet.begin(mac, ip);
  server.begin();
  mySensor.beginI2C();
}

void loop() {  
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  
          client.println("Refresh: 10");  
          client.println();
          client.println("<!DOCTYPE HTML>");  
          client.println("<html>");  
              client.println("<head>");
                  client.println("<meta charset=\"utf-8\"></meta>");
                  client.println("<title>METEO LOCALE</title>");     
              client.println("</head>");
              client.println("<body>"); 
                    DateTime time = rtc.now();
                    client.print("<font size='10'>");
                    client.print("Date: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_DATE));
                    client.print("<br/>");
                    client.print("heure: ");
                    client.print(time.timestamp(DateTime::TIMESTAMP_TIME));
                    client.print("<br/>");
                    client.print("temperature: ");
                    client.print(mySensor.readTempC());
                    client.print("<br/>");
                    client.print("pression: ");
                    client.print(mySensor.readFloatPressure());
                    client.print("<br/>");
                    client.print("Humidité: ");
                    client.print(mySensor.readFloatHumidity());        
              client.println("</body>"); 
          client.println("</html>");   
          break;
        }
        if (c == '\n') {
                   currentLineIsBlank = true;
        } else if (c != '\r') {
                    currentLineIsBlank = false;
        }
      }
    }
    delay(1000);
    client.stop();
  }
}

si tout est OK âpres compilation et déversement dans l’ARDUINO UNO , si on ouvre le navigateur sur son PC et que l’on se connecte a l’adresse 192.168.1.15 de l’arduino uno et son ethernet shield on obtient l’affichage ci dessous qui se rafraichis automatiquement toutes les 5 secondes :

STATION METEO Arduino basique

petit montage a base d’ ARDUINO pour faire une station météo avec 3 fonctions basiques: température , pression et hygrométrie et une fonction d’enregistrement des données sur carte SD.

MATERIEL:

  • un Arduino Uno
  • un SD RTC shield (DeekRobot ou Adafruit)
  • une carte SD
  • un module DHT 22
  • un module BMP280
  • alimentation par pile 9V et cordon jack

SD RTC SHIELD:

sa fonction est de proposer sur un shield les fonctions lecture/écriture sur carte SD ainsi qu’une horloge temps réelle a pile de sauvegarde. cette carte a été abordée de façon plus détaillée ici .

le module DHT 22

c’est le même type de module que le DHT11 utilisé en exemple dans la rubrique ARDUINO SD RTC shiel mais avec des caractéristiques plus performantes ( plage de température et précision). comme le DHT 11 , il délivre la température et l’hygrométrie

le module BMP280

le module BMP280 délivre lui 2 informations ; une température et une pression

CABLAGE

broche out du DHT22 sur la broche 2 de l’arduino et Vcc et GND sur 5V et GND arduino

pour le BMP280, nous allons l’utiliser en mode I2C . il faut donc brancher GND et Vcc sur GND et 5V arduino et SCL et SDA du BMP280 sur les broche SCL et SDA de l’arduino uno . l’arduino UNO possede 2 paires de broches I2C ( SCL + SDA)=> voir le pinout ICI

le SD RTC shield doit etre “pluggué” sur l’arduino UNO puis les 2 composants (DHT22 et BMP280) ainsi que la pile reliés a l’UNO ( le SD shield n’est pas représenté sur le schéma fritzing ci dessus) : pour le DHT22 et le BMP280 , utiliser une petite platine proto .

NOTA: attention, une pile type 9V ne permet un fonctionnement que de quelques heures. pour une station météo d’observatoire , il faudra soit une alim secteur soit une alim batterie sur panneau solaire.

PROGRAMME ARDUINO

le programme est un “melting-pot” de plusieurs programmes d’exemples joints avec les différentes librairies utilisées.

très synthétiquement, on charge les différentes librairies nécessaires ( wire.h pour l’I2C, SPI.h pour le lecteur SD, SD.h pour l’utilisation de la carte SD, RTClib.h pour l’horloge temps réel, Adafruit_BMP.h pour le BMP280, DHT.H pour le DHT22), puis on defini quelques constante et brochage . le programme void setup lance les differentes fonctions et parametres liées aux librairies, la boucle “void loop” lit les données des capteurs et les stocke dans des variables ainsi que année, mois, jour et heures/minutes/secondes de l’horloge RTC.

pour la temperature , on recuperer les 2 temperatures t1 et t2 des 2 capteurs et on calcule la moyenne des 2 => ligne ” tm = (t1+t2)/2

une serie de parametres “filename[x] permet de definir chaque caractère du nom de fichier d’enregistrement des données => un fichier par jour de l’année suivant la syntaxe : année mois jour. puis le fichier est ouvert , les données enregistrées dedans sous forme string CSV et le fichier est refermé , le programme attends 60 secondes puis recommence => un enregistrement de données toutes les minutes.

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <RTClib.h>
#include <Adafruit_BMP280.h>
#include "DHT.h"
const int chipSelect = 10;
#define DHTPIN 2 
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
RTC_DS1307 RTC;
Adafruit_BMP280 bmp; // I2C

char filename [] = "00000000.CSV";

void setup() {
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  // ligne suivante pour initialiser l'heure du RTC/PC  la premiere fois 
  // decocher les // , telecharger , puis remettre les // 
  // RTC.adjust(DateTime(__DATE__, __TIME__));
  dht.begin();
  bmp.begin(); 
   /* config par defaut suivant datasheet */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     
                  Adafruit_BMP280::SAMPLING_X2,     
                  Adafruit_BMP280::SAMPLING_X16,    
                  Adafruit_BMP280::FILTER_X16,     
                  Adafruit_BMP280::STANDBY_MS_500); 
  SD.begin(chipSelect);               
}

void loop() { 
  float h = dht.readHumidity();
  float t1 = dht.readTemperature();
  float t2 = bmp.readTemperature();
  float p = bmp.readPressure();
  float  tm = (t1+t2)/2 ;   
  DateTime now = RTC.now();
  uint16_t year1 = now.year();
  uint16_t month1 = now.month();
  uint16_t day1 = now.day();
  uint16_t hour1 = now.hour();
  uint16_t minute1 = now.minute();
  uint16_t second1 = now.second();
  filename[0] = (year1/1000)%10 + '0';
  filename[1] = (year1/100)%10 + '0';
  filename[2] = (year1/10)%10 + '0';
  filename[3] = (year1)%10 + '0';
  filename[4] = month1/10 + '0'; 
  filename[5] = (month1)%10 + '0'; 
  filename[6] = day1/10 + '0'; 
  filename[7] = (day1)%10 + '0';
  filename[8] = '.';
  filename[9] = 'c';
  filename[10] ='s';
  filename[11] ='v';
  File dataFile = SD.open(filename, FILE_WRITE);
  String dataReg = String(year1) + "/" + String( month1) + "/" + String(day1) +";" + String(hour1) + ":"+ String(minute1) + ":" + String(second1) + ";" + String(tm) + ";" + String(h) + ";" + String(p) + ";" ; 
  dataFile.println(dataReg);
  dataFile.close();
  delay(60000);
}

voici un exemple de données enregistrées:

fichier CSV ouvert avec wordpad: date ; heure ; température ; humidité ; pression (en pascals)

le même fichier CSV ouvert avec LibreOffice ou Excel , l’enregistrement avec des “;” séparant les paquets de données permet de récupérer chaque paquet dans une colonne différente sur le tableur.

AMELIORATION

nous allons améliorer la station météo en ajoutant un écran LCD I2C 4 lignes de 20 caractères pour y afficher , date et heure sur la première ligne, température sur la deuxième ligne , humidité et pression sur la troisième ligne. la quatrième ligne est en réserve pour la vitesse et la direction du vent .

le schéma de câblage avec l’écran I2C devient:

le programme deviens (évolutions en bleu):

#include <Wire.h>
#include <SPI.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <RTClib.h>
#include <Adafruit_BMP280.h>
#include "DHT.h"
const int chipSelect = 10;
#define DHTPIN 2 
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
RTC_DS1307 RTC;
Adafruit_BMP280 bmp; // I2C
LiquidCrystal_I2C lcd(0x27,20,4);
char filename [] = "00000000.CSV";
void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  Wire.begin();
  RTC.begin();
  // ligne suivante pour initialiser l'heure du RTC/PC  la premiere fois 
  // decocher les // , telecharger , puis remettre les // 
  // RTC.adjust(DateTime(__DATE__, __TIME__));
  dht.begin();
  bmp.begin(); 
   /* config par defaut suivant datasheet */
  bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,     
                  Adafruit_BMP280::SAMPLING_X2,     
                  Adafruit_BMP280::SAMPLING_X16,    
                  Adafruit_BMP280::FILTER_X16,     
                  Adafruit_BMP280::STANDBY_MS_500); 
  SD.begin(chipSelect);               
}
void loop() { 
  float h = dht.readHumidity();
  float t1 = dht.readTemperature();
  float t2 = bmp.readTemperature();
  float p = bmp.readPressure();
  float tm = (t1+t2)/2;  
  DateTime now = RTC.now();
  uint16_t year1 = now.year();
  uint16_t month1 = now.month();
  uint16_t day1 = now.day();
  uint16_t hour1 = now.hour();
  uint16_t minute1 = now.minute();
  uint16_t second1 = now.second();
  filename[0] = (year1/1000)%10 + '0';
  filename[1] = (year1/100)%10 + '0';
  filename[2] = (year1/10)%10 + '0';
  filename[3] = (year1)%10 + '0';
  filename[4] = month1/10 + '0'; 
  filename[5] = (month1)%10 + '0'; 
  filename[6] = day1/10 + '0'; 
  filename[7] = (day1)%10 + '0';
  filename[8] = '.';
  filename[9] = 'c';
  filename[10] ='s';
  filename[11] ='v';  
  String date = String(day1) + "/" + String(month1) + "/" + String(year1);
  String time = String(hour1) + ":" + String(minute1) + ":" + String(second1);
  lcd.setCursor(0,0);
  lcd.print(date) ;
  lcd.setCursor(11,0);
  lcd.print(time) ;
  lcd.setCursor(7,1);
  lcd.print(tm) ; 
  lcd.setCursor(12,1);
  lcd.print(char(223)) ;
  lcd.setCursor(13,1);
  lcd.print("C") ;     
  lcd.setCursor(0,2);
  lcd.print(h) ;
  lcd.setCursor(5,2);
  lcd.print("%Hu") ; 
  int roundp =  int(p);
  lcd.setCursor(9,2);
  lcd.print(p) ;
  lcd.setCursor(18,2);
  lcd.print("Pa") ;  
  File dataFile = SD.open(filename, FILE_WRITE);
  String dataReg = String(year1) + "/" + String( month1) + "/" + String(day1) +";" + String(hour1) + ":"+ String(minute1) + ":" + String(second1) + ";" + String(tm) + ";" + String(h) + ";" + String(p) + ";" ; 
  dataFile.println(dataReg);
  dataFile.close();
  delay(60000);
}

et visuellement , le montage fini en fonctionnement , ressemble a cela:

la version finale de la station integrera un anemometre et une girouette

pour rendre la station autonome , elle sera alimentée par un panneau solaire 12V – 5 watts alimentant une batterie 12V.

communication serie PI <=> ARDUINO

voyons ici quelques bases pour la communication serie bidirectionnele entre un Raspberry PI et un arduino UNO .

ce sujet est abordé brièvement ici mais uniquement sur l’aspect communication unidirectionnelle de l’arduino vers le raspberry Pi pour la réception de données et l’enregistrement sur le raspberry PI . nous allons essayer, ici, de le compléter avec quelques exemples centrés sur la communication bidirectionnelle dans le but d’instaurer des échanges type action/réaction entre les deux , cela a un interet par exemple pour les dialogue RPI <=> station meteo Arduino, pour les interaction electromecaniques ( arduino pilote des actionneurs et RPI envoi les commandes et sert d’interface homme machine pour gerer les menus et interactions ecran/claviers/souris/etc..)

EXEMPLE 1:

le premier exemple sera très simple, le RPI envoie un message a l’Arduino qui lui réponds, pour cela installer les 2 programmes ci dessous respectivement sur votre ARDUINO et votre Raspberry PI :

void setup() {
    Serial.begin(9600);
}

void loop() {
  if (Serial.available()>0) {
    String data=Serial.readStringUntil('\n');
    Serial.print("message reçu: ");
    Serial.println(data);
  }
}
import serial
import time
ser=serial.Serial(port='/dev/ttyACM0',baudrate=9600, timeout=0.2)

while True:
    ser.write(b"Coucou du RPI4\n")
    line=ser.readline().decode('utf-8').rstrip()
    print(line)
    time.sleep(1)

le programme C++ arduino , “ecoute” les données qui arrive sur le port série et renvoi sur celui ci le message “message reçu:” avec derriere le message reçu du RPI.

le programme Python du RPI , envoi sur le port USB le message “Coucou du RPI4” avec un retour chariot (\n) puis met dans la variable “line” ce qu’il lit en retour de l’arduino puis l’imprime (print(line) et attends 1 seconde avant de recommencer. voici ci dessous petite copie d’ecran des 2 programmes ouverts sur le RPI4 avec le résultat du lancement du pgme python qui s’affiche dans la fenêtre shell de thonny python.

EXEMPLE 2:

a partir du meme programme arduino que plus haut , a titre didactique, nous allons reprendre les bases du deuxième exemple de la rubrique “evenement CLAVIER SOURIS” pour batir un programme qui envoi a l’arduino des valeurs de mouvements x et Y sous forme de chaine de caractères et lit en retour le message renvoyé par l’arduino (à savoir la commande envoyée qui est retournée par l’arduino)

import tkinter as tk
root=tk.Tk()
root.geometry("500x500+450+100")
canvas1=tk.Canvas(root, width=500, heigh=500)
canvas1.pack()
command='M00'
def keypressed(k):
    x=0
    y=0
    global command
    if k.keysym=='Up':
        y=-1
    if k.keysym=='Down':
        y=1
    if k.keysym=='Left':
        x=-1
    if k.keysym=='Right':
        x=1
    command='M'+str(x)+str(y) 
    ser.write(command.encode('utf-8'))
    line=ser.readline().decode('utf-8').rstrip()
    print(line)
root.bind('<KeyPress>', keypressed)
root.mainloop()

la commande envoyée est de la forme Mxy avec x et y des valeurs de déplacements valant +1 ou -1 sous forme de caractères . il est asses facile ensuite de demander au programme Arduino de décoder ces 2 valeurs et les transformer par exemple en valeur Step pour commander un moteur pas a pas branché sur l’Arduino. même principe pour commander la rotation d’un moteur . on pourrait également demander a l’Arduino de retourner une valeur de fin de course ou de capteur sous forme de chaine type Cab (C pour capteur et a/b pour les valeurs a prendre en compte). avec ce type de principe il est donc facile de mettre en place un protocole de communication aller/retour et traiter chaque information de chaque coté en fonction du code de commande associé a la première lettre …

évènements CLAVIER et SOURIS avec TK inter

dans un programme python sur raspberry pi pour des appli astro il peut être intéressant d’utiliser clavier et souris pour des commandes spécifiques autre que de la saisie de données. par exemple, utiliser les touches fleches du clavier pour commander des mouvements de moteurs pas a pas sur une monture équatoriale motorisée.

nous allons voir ici les bases de la gestion des événements clavier et souris avec Tkinter.

EXEMPLE BASIQUE:

les quelques lignes de python ci dessous permettent d’exploiter de façon tres basique la gestion des evenements clavier et souris avec Tkinter. a noter que cela fonctionne egalement avec les clavier avec track pad reconnus comme une souris par Tkinter.

import tkinter as tk

def keypressed(k):
    print(k.keysym, k.keycode)
def mouse(m):
    print(m)
def button(b):
    print(b)
      
root=tk.Tk()
root.geometry("500x500+400+100")
root.bind('<KeyPress>', keypressed)
root.bind('<Motion>', mouse)
root.bind('<Button>',button)

root.mainloop()

dans le programme , on defini une fenetre “root=tk.Tk()” avec TKinter, ainsi que sa géometrie (largeur/hauteur :500×500 et position x/Y: 400+100) via la ligne :

root.geometrie(“500×500+400+100”)

la partie “stratégique” de ce bout de python est constituée des 3 lignes “root.bind()“. avec les 3 fonction bind permettant chacune d’associer des événements a des fonctions définies en début de programme. les 3 fonctions définies , impriment les paramètres des événements concernés; symbole et code de la touche clavier préssée, coordonnées X et Y de la souris dans le cadre root et bouton de souris enfoncé. voici ci dessous copie d’écran du résultat sous thonny Python avec un raspberry; le résultat des actions s’affiche dans la fenetre du shell en bas a gauche:

concernant l’architecture de la commande bind , elle est asses simple:

root.bind(‘<evenement>’, appel fonction)

ci dessous les principaux événements reconnus par Tkinter:

événements clavier:

événements souris:

a partir de ces éléments fondamentaux , il est possible ensuite d’implémenter des fonctions et actions évoluées a partir des événements souris ou clavier . par exemple, faire tourner un moteur pas a pas branché sur le GPIO du raspberry PI dans un sens ou dans l’autre avec les flèches gauche et droite du clavier (voir ici pour la commande d’un NEMA17), actionner un moteur CC d’ouverture de toiture , commander l’orientation d’une monture equatoriale, etc …

à titre d’exemple un peu plus complet , ci dessous petit programme qui bouge le caracter X , en partant du centre, dans la zone de fenetre Tkinter via les touches fleches droite -gauche-haut-bas . pour faire tourner 2 NEMA17 , il suffit d’utiliser les variables X et Y comme valeur STEP et envoyer ça sur 2 drivers Pololu A4988 via le GPIO . pas plus compliqué que ça ….

import tkinter as tk
root=tk.Tk()
root.geometry("500x500+450+100")
canvas1=tk.Canvas(root, width=500, heigh=500)
canvas1.pack()
x=250
y=250

def keypressed(k):
    global x
    global y
    if k.keysym=='Up':
        y+=-1
    if k.keysym=='Down':
        y+=1
    if k.keysym=='Left':
        x+=-1
    if k.keysym=='Right':
        x+=1
    text=tk.Label(root, text= 'X', fg='yellow', bg='blue')
    canvas1.create_window(x,y, window=text)

root.bind('<KeyPress>', keypressed)
root.mainloop()

et le resultat apres quelques appuis variés:

voila , ce sera tout pour cette rubrique sur la fonction bind() , quelques liens complémentaires utiles ci dessous :

http://tkinter.fdex.eu/doc/event.html

understanding TKinter event

Fichier NGC avec Python

en astronomie , les objets du ciel profond sont souvent désignés au travers de leur code du catalogue NGC . nous allons voir ici quelques manipulations avec Python sur le fichier NGC.

pour les exemples de programmes python , ci dessous le fichier NGC au format csv a télécharger et installer par exemple dans votre répertoire home/pi/Documents :

le format CSV , alias Comma-Separated Values , est un format texte ouvert, représentant des données tabulaires sous forme de valeurs séparées par des virgules. il est reconnu par excel , OpenOffice et LibreOffice.

les objets NGC sont enregistrés sous la forme ci dessous ( NGC0224=Andromède):

NGC0224;00:42:44.35;+41:16:08.6

chaque ligne du fichier fait 31 caractères avec un retour chariot a la fin de la ligne( non visible). on trouve dans les 7 premiers caractères la référence NGC , ensuite un point virgule derrière lequel on trouve l’ascension droite en heures:minutes:secondes (2 chiffres après la virgule), puis un nouveau point virgule puis la déclinaison en degrés, minutes, secondes (un seul chiffre après la virgule).

EXEMPLE 1: ouverture du fichier et lecture puis impression des lignes du fichier

import time
f = open("home/pi/Documents/NGC.csv", "rt")
for x in f:
	print(x)
	time.sleep(0.5)

comme souvent en python, rien de très compliqué , le fichier est stocké dans une variable f ( le fichier est considéré comme un array) via la commande open() , dans laquelle on précise le chemin d’accès et le nom, puis le type d’ouverture . la librairie time est ouverte et une ligne time.sleep() est rajoutée pour ralentir un peu le programme . ici “rt” qui veut dire Read Text soit une ouverture du fichier en mode lecture et au format text . pour écrire/enregistrer un fichier au format texte ce serait open(“nomfichier.csv”, “wt”) pour write Text . ci dessous le lien vers la page Python pour les fichiers:

lien doc python

EXEMPLE 2: petite variation du programme précédent, ouverture du fichier et recherche d’une référence NGC puis impression de la ligne correspondante . ici comme on affiche une seule ligne trouvée dans le fichier , pas besoin de la librairie time ni de la ligne time.sleep()

f = open("home/pi/Documents/NGC.csv")
for x in f:
	if "NGC3200" in x:
		print(x)

encore une fois rien de compliqué , avec 4 lignes de python , on ouvre le fichier , on trouve l’enregistrement et on imprime son contenu.

EXEMPLE 3: amélioration du programme précédent , on emballe tout ça dans une petite interface graphique sous tkinter, avec fenêtre de saisie de la ref NGC et bouton de recherche a cliquer pour lancer la recherche :

import tkinter as tk
root=tk.Tk()
canvas1=tk.Canvas(root, width=400, heigh=300)
canvas1.pack()
entry1=tk.Entry(root)
canvas1.create_window(200, 140, window=entry1)

def NGCsearch():
    x1 = entry1.get()
    f = open("/home/pi/Documents/FICHIERS NGC/NGC.csv", "rt")
    for x in f:
        if x1 in x:
            label1=tk.Label(root, text= x)
            canvas1.create_window(200,230, window=label1)
button1= tk.Button(text='recherche', command=NGCsearch)
canvas1.create_window(200, 180, window=button1)

root.mainloop()

ci dessous copie d’écran du résultat après recherche de NGC0224

pour finir voici a titre d’exemple , le resultat d’un petit programme de recherche , affichage et calcul pour un module GOTO en python . on entre les references NGC de l’objet de reference ( pointé avec un viseur laser) , puis la reference NGC de l’objet cible a rechercher , le programme ouvre le fichier NGC.CSV , trouve les datas des 2 objets NGC, les affiche puis calcule les delta angulaire AD et DEC pour envoyer a la monture DIY qui fait tourner les moteurs pas a pas du nombre de pas correspondant aux valeurs d’ecarts.

USB HAT

pas asses de port USB sur votre raspberry PI , rassurez vous il existe des USB HAT pour étendre la capacité .

il en existe autant de modèles que de type de RPI et de type de port USB ( USB 2 ou USB 3).

voici quelques photos d’un HAT ( chapeau en anglais) avec port USB 3 pour raspberry PI 4B:

il se monte sur le RPI via des colonnettes et est fourni avec une petite platine de raccordement pour le port USB3 du RPI ( a droite sur la photo ci dessous)

il n’est pas obligatoire de le monter par dessus , le RPI , il peut etre connecté via un cordon USB classique ( prendre le cordon adapté au type d’USB).

voici une configuration sur SSD BOARD avec le RPI sur un ecran HDMI 7″ touschscreen 1024 x 600:

RPI 4B – Boot sur disque SSD USB

Rasbian installé sur carte SD montre vite ses limites . voyons ici comment booter le RPI 4 sur DD SSD USB3 .

il est possible de brancher un Disque Dur SSD sur port USB3 du RPI 4B via un cordon, mais pour garder la compacité et l’homogénéité de l’ensemble , je recommande l’investissement dans une carte SSD Board telle que celle ci dessous ( Geekworm Raspberry Pi 4 SATA X825 V2.0 , 38€ sur Amazone en mai 2021)

le disque dur ce fixe en partie inférieur de la carte et une petite platine USB assure la liaison USB3 entre platine et RPI4.

ci dessous photo d’une configuration RPI 4B+ 4Go sur SSD BOARD avec SSD 120 Go , USB HAT avec port USB3, ecran HDMI 7″ Tactile 1024×600

voyons maintenant les étapes d’installations du systeme .

NOTA: on suppose que RASBIAN est déjà installé sur carte SD introduite dans le RPI => : lien

ETAPE 1: Mise à jour de votre Raspberry Pi 4

faire une mise a jour complete de votre systeme , en envoyant successivement les commandes SHELL ci dessous ( procedure d’environ 20 minutes) . ne pas oublier d’activer la connexion internet pour toutes les opérations de mise a jour (Etape 1 et 2)

sudo apt update
sudo apt full-upgrade
sudo rpi-update

une fois les mises a jours faites , il faut redémarrer le RPI 4 pour appliquer toutes les MAJ.

ETAPE 2: Installation du dernier Bootloader

pour cela taper la commande shell suivante:

sudo rpi-eeprom-update -d -a

si votre RPI4B est recent , il ne se passera peut etre pas grand chose et vous aurez un message du genre “BOOTLOADER : up to date”

dans le cas contraire le shell fera la mise a jour

ETAPE 3: Configuration du Boot USB

taper la commande shell suivante:

sudo raspi-config

vous arrivez dans le menu de configuration, On se rend dans la ligne 6 “Advanced Options” , on fait “entrée”

puis on selectionne la ligne A7 “Bootloader Version“:

et la on valide l’option E1 ” select latest or default boot ROM software”.

attention, dans l’ecran suivant , le pointeur se place automatiquement sur “Yes” , il faut choisir “No”, sinon les paramètres seront remis a défaut .

Une fois enregistré, l’écran vous confirme la réinitialisation des paramètres.

dans l’écran “Advanced Options“, on sélectionne maintenant “A6 Boot Order“:

Puis“B2 USB Boot“, pour donner la priorité a l’Usb, par rapport a la micro SD.

L’écran suivant confirme que l’Usb est devenu le boot par défaut.

l’écran suivant, propose de redémarrer le RPI .

ce n’est pas nécessaire , nous allons choisir “No” puis ressortir du menu de config et arreter le RPI en tapant la commande shell:

sudo halt

ETAPE 4: installation de Rasbian sur le SSD

la procédure est la même que pour l’installation sur carte micro SD=> : lien

ici , avec l’imager on va juste préciser que l’os est a installer sur le SSD:

pour l’installation, il faudra connecter le disque Dur SSD au PC Windows via un cordon dédié type SATA vers USB.

une fois l’installation de Debian sur le SSD faite, il ne reste plus qu’a monter le SSD sur la carte SSD board , tout raccorder (alimentation, ecran,etc..) et rebooter le RPI en prenant soin d’enlever la carte micro SD devenue inutile ( on peut la garder en securité si pbme avec le SSD).

PAUSES LONGUES avec une PI cam HQ

la dernière née des PI camera , outre une meilleure définition (4056 x 3040) offre la possibilité de faire des pauses longues jusqu’à 200 secondes pour l’astrophotographie du ciel profond . nous allons voir comment exploiter ces capacités en Python.

tout d’abord petit rappel des caractéristiques des différentes PIcam dans le tableau comparatif ci dessous:

voyons un premier petit bout de programme python basique utilisant les propriétés pause longue de la bibliothèque Pi camera.

import picamera
from time import sleep
from fractions import Fraction

camera = picamera.PiCamera()

# camera en resolution max
camera.resolution=(4056, 3040)
# framerate a 6s
camera.framerate =Fraction(1,6)
# capteur en mode Pause longue (mode 3) 
camera.sensor_mode=3
# vitesse d'obturation a 6 secondes
camera.shutter_speed = 6000000
#sensibilite ISO a 800 pour un gain maximum en condition nocturnes
camera.iso = 800
# pause de 10 secondes pour balance des blanc auto
sleep(10)
# exposure mode off pour figer les parametres balance des blanc et gain
camera.exposure_mode = 'off'
#prise de vue et sauvegarde sous le nom 'pauselongue.jpg'
camera.capture('pauselongue.jpg')

la version txt a télécharger n’a pas les commentaire et se réduit donc a 12 lignes , ce qui permet de voir qu’avec quelques simples lignes de commandes python on peut déclencher une prise de vue pause longue de 6 secondes a 800 ISO et sauvegarder le fichier résultant.

outre le fait que l’on peut paramétrer tout un tas de valeurs de reglage ( gain, AWB, ISO, résolution, shuter speed, etc …) . il est important de noter que la vitesse d’obturation (shutter speed ) est en fait dépendante directement du framerate. il est donc indispensable de ne jamais dissocier les deux => donc on défini systématiquement le framerate avec la fonction Fraction , et ensuite le shutter speed a l’identique avec la même valeur x 1000000.

deuxime chose importante a prendre en compte , ne pas oublier d’inclure une pause ( sleep(10) avant la prise de vue pour laisser le temps a la camera d’ajuster la balance des blancs en automatique. l’autre solution étant de fixer manuellement la valeur de balance des blancs et ainsi pouvoir se passer du sleep().

la PI camera HQ est fournie en standard avec un cadre fileté au pas de monture photo Type C . pour l’utiliser sur un telescope ou une lunette , il faut lui adjoindre un adaptateur d’oculaire au pas de la monture type C ( 11€ sur Amazone tarif mai 2021):

sur la base du premier programme , il est facile de programmer une sequence de prise de vues pause longue en automatique en ajoutant une boucle while avec increment et de numeroter automatiquement le nom du fichier a l’enregistrement :

import picamera
from time import sleep
from fractions import Fraction

camera = picamera.PiCamera()

camera.resolution=(4056, 3040)
camera.framerate =Fraction(1,6)
camera.sensor_mode=3
camera.shutter_speed = 6000000
camera.iso = 800
sleep(10)
camera.exposure_mode = 'off'

i=1
while i=< 5
	camera.capture('pauselongue' + str(i) +'.jpg')
	sleep(10)
	i=i+1

ce deuxieme programme fait donc une série de 5 photos en pause de 6 secondes chacune avec un temps d’attente de 10 secondes entre chaque photo.

sur ces bases et en utilisant Tkinter ( voir rubrique ICI et ICI ) il est possible de faire des menu et d’intégrer des boutons et sliders pour paramétrer le nombre de photos, le temps de pause , le temps interpose , la sensibilité ISO et tous les autres paramètres potentiels utilisables.

exemple d’une appli perso qui transforme la PI cam HQ en capteur multimode combinant Video / timelapse Photo / timelaps pauses longues, l’ensemble très pratique en mode nomade avec un ecran TFT HDMI touschscreen qui permet d’activer les sliders et boutons sans clavier ni souris …

a vos clavier pour developper vos appli perso ….

pour aller plus loin , voici le lien vers la documentation picamera:

https://picamera.readthedocs.io/en/release-1.13/index.html

OpenCV – installation

pour pouvoir utiliser openCV en Python , il faut installer la bibliothèque adéquate. ci dessous la procédure .

première chose a faire vérifier que tout est a la dernière version coté systeme et coté PIP.

donc lancer les classiques commandes shell suivantes:

sudo apt update
sudo apt upgrade

pour l’installation , pas de grosses difficultés , il y a plusieurs package openCV pour python dont les 2 principaux sont le package principal et celui avec tous les modules d’extensions . voici les commandes shell respectives pour l’installation sous python 3:

package de base: pip3 install opencv-python

package complet: pip3 install opencv-contrib-python

si ensuite a l’utilisation sous python , vous avez des problèmes avec des messages d’erreur c’est qu’il manque des “pré-requis” , pour cela lancer la ligne complète ci dessous:

sudo apt-get install -y libatlas-base-dev libhdf5-dev libhdf5-serial-dev  libjasper-dev  libqtgui4  libqt4-test

ou en version lignes a lignes:

sudo apt-get install libhdf5-dev
sudo apt-get install libhdf5-serial-dev
sudo apt-get install libatlas-base-dev
sudo apt-get install libjasper-dev 
sudo apt-get install libqtgui4 
sudo apt-get install libqt4-test

si malgré ceci des messages d’erreur subsistent , faire une recherche Google en tapant le message d’erreur reçu .

a toute fin utile , ci dessous quelques liens d’aide:

python software foundation

site openCV installation Linux