Menu Fermer

Raspberry Pi 3, Java, Python depuis Linux Ubuntu

Très gros travail pour cet article pour le rendre simple et sans avoir vraiment besoin du livre! L’idée est montrer un petit exemple en Python et en Java pour allumer ou éteindre deux leds, une verte et une rouge, suivant si un senseur de lumière détecte qu’il y a ou non assez de lumière! La méthode utilisée est la même que pour le livre et tous les composants attachés au GPIO: schéma Fritzing, test en Python et codage en Java.

Au contraire du livre, sous Windows PC, tout se fera ici sur un PC Ubuntu.

Dans l’avant-propos de mon livre, dont les outils sont spécifiques à Windows 10,  j’ai écrit à la page VI:

Pour le développement, je n’ai considéré ici que l’environnement Windows 10. Mais certains outils comme Eclipse existent aussi sous Linux (par exemple, Ubuntu) et sous Mac. Des programmes comme PuTTY ou WinSCP ont également leurs équivalents dans ces systèmes d’exploitation.

La référence pour cet article-ci est Ubuntu 18.04.1 LTS, mais devrait être applicable pour d’autres versions de Linux. J’assume que les utilisateurs ont de bonnes connaissances Linux et de développement. Moi-même je ne suis qu’un utilisateur Ubuntu occasionnel et qui aurait de la peine à ajouter un raccourci à Eclipse sur le bureau après installation. Toutes les personnes désirant améliorer cet article peuvent me contacter et m’envoyer du matériel

Pour la vérification, j’ai utilisé un Raspberry Pi Zero WH qui avait déjà une micro carte SD installée depuis Windows 10 et fonctionnelle. J’ai donc commencé par faire une sauvegarde (chapitre 3 du livre) de l’image. Une sauvegarde sous Linux se fait avec la commande dd (voir ci-dessous) avec les paramètres if et of inversés.

Lorsqu’on utilise une carte déjà utilisée, il n’est pas possible d’appliquer les procédures décrites sous https://www.raspberrypi.org/documentation/installation/installing-images/linux.md, procédure que j’ai d’ailleurs utilisées et décrites ici plus simplement.

Formatage

Il manque donc ici le formatage, absolument nécessaire sur une micro carte SD non vierge,  et nous utiliserons l’utilitaire Disks d’Ubuntu, ou un autre, pour le faire.

Téléchargement

Depuis le site Raspbian France, j’ai téléchargé le fichier Raspbian_latest.zip pour extraire l’image 2018-11-13-raspbian-stretch.img  J’ai déposé cette dernière dans mon répertoire Ubuntu /home/jbb/raspberryPi que j’avais préalablement créé.

Ecriture de l’image

Pour le formatage et l’écriture, nous utiliserons le même adaptateur USB de carte SD que celui décrit au chapitre 3.

L’utilitaire Linux lsblk exécuté dans une console Linux Terminal est essentiel pour déterminer le « device » de notre micro carte SD. Chaque fois que nous ressortirons notre carte ou retirerons le câble USB, il faudra correctement éjecter  ou umount le device.

Ici les deux dernières lignes de lsbk avec ma carte installée avant formatage:


sdf 8:80 1 14.9G 0 disk
├─sdf1 8:81 1 43.9M 0 part /media/jbb/boot
└─sdf2 8:82 1 3.1G 0 part /media/jbb/rootfs

Le  /media/jbb/boot est équivalent au boot (K:) sous Windows.

Un ls /media/jbb/boot est toujours possible pour examiner les fichiers.
Conclusion: /dev/sdf est bien le device à utiliser, mais pourrait éventuellement être différent.

Après formatage (pas nécessaire pour une carte vierge) et après avoir retiré et remis notre carte, nous pourrons alors copier l’image Raspbian sur la micro carte SD:

sudo dd bs=4M if=2018-11-13-raspbian-stretch.img of=/dev/sdf conv=fsync

366+0 records out
1535115264 bytes (1.5 GB, 1.4 GiB) copied, 111.427 s, 13.8 MB/s

Un sync pour terminer est toujours conseillé.

Comme précédemment, nous allons sortir correctement et remettre la carte avant un nouveau lsblk:

sdf 8:80 1 14.9G 0 disk
├─sdf1 8:81 1 43.9M 0 part /media/jbb/boot
└─sdf2 8:82 1 3.1G 0 part /media/jbb/rootfs

Définition de l’adresse IP

Comme décrit dans le livre au chapitre 3, il faut appliquer la procédure pour que le routeur puisse définir une adresse IP à notre Raspberry Pi que nous n’avons pas encore soumis à un premier démarrage. Ensuite nous irons dans le routeur pour définir l’adresse static, donc fixe.

Avec notre micro carte SD toujours dans le lecteur et monté, un éditeur de texte sous Linux, voir avec vi expliqué dans le livre, et dans une console Terminal, nous allons créer un fichier ssh vide dans le répertoire  /media/jbb/boot de la micro carte SD monté. Lorsque terminé:

ls -l ssh
0 bytes

Le fichier le plus important, c’est wpa_supplicant.conf , qui doit se trouver aussi  dans le répertoire  /media/jbb/boot. C’est lui qui va être utilisé et ensuite effacé automatiquement au premier démarrage. Il nous permettra de définir une adresse IP à notre Raspberry Pi. Avec vi ou un autre éditeur, nous déposerons le contenu suivant dans ce fichier:

country=FR
update_config=1
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
network={
ssid= »xxxx »
psk= »yyyy »
key_mgmt=WPA-PSK
}

xxxx est le nom du routeur et yyyy la clé (le mot de passe), les mêmes que lorsque nous définissons une connexion WiFi pour un Smartphone. Le country peut être différent. C’est clair.

Après vérification de la présence et du contenu de ces deux fichiers, nous pourrons alors retirer la micro carte SD avec un Eject sur l’icône du bureau de ce device ou alors avec un umount /media/jbb/boot, mais après avoir quitté son répertoire dans la console Terminal, c’est clair.

Premier démarrage

C’est la même procédure que est décrite au chapitre 3: on insert la carte sur ou sous le Rasperry Pi suivant le modèle, on l’alimente et on vérifie l’adresse IP.

La commande arp -a dans une console Terminal est la même que sous Windows et l’adresse physique devrait commencer par b8-. Cette valeur de début indique un Raspberry Pi récent. J’ai constaté que cette commande arp ne réagissait pas immédiatement: donc un peu de patience.

En utilisant arp -a avant le démarrage du Raspberry Pi, nous pourrions alors vérifier la différence et identifier la nouvelle adresse si nous avions plusieurs Raspberry Pi.

Ce sera alors le bon moment pour accéder à notre routeur avec une interface Web et d’y fixer l’adresse IP.

Outils réseaux sur Ubuntu

Ce n’est pas vraiment très clair de ce qu’il faut vraiment au sujet des outils réseaux Ubuntu et un

sudo apt install net-tools

n’est pas inutile!

Access ssh depuis Ubuntu

Pour accéder au Raspberry Pi la commande ssh suffira:

ssh pi@192.168.1.134

et nous recevrons du Raspberry Pi :

pi@192.168.1.134’s password:

Nous pourrons alors accéder à notre Raspberry Pi comme avec puTTY sous Windows avec le mot de passe raspberry.

Configuration du Raspberry Pi

Dans l’article Raspberry Pi Zero WH nous en discutons quelques aspects mais il faudra se référer au livre pour, avec sudo raspi-config, changer le mot de passe et définir la zone européenne correcte de l’heure. Nous devrons aussi installer le Pi4J, la librairie Java utilisée pour les applications du livre, avec curl -s get.pi4j.com | sudo bash.

Installation de FileZila

FileZila est l’équivalent WinScp sous Windows 10. Il va nous permettre de transférer des fichiers Java compilés et des script Python. Pour l’installation sur Ubuntu, si nécessaire et pas encore installé:

sudo apt-get install filezilla

Installation d’Eclipse

Il faut se rendre sur le site d’Eclipse,
https://www.eclipse.org/downloads/packages/ et télécharger
eclipse-java-2018-09-linux-gtk-x86_64.tar.gz.

De même pour le JDK de Java et nous prendrons la version 8 dont nous avons besoin pour le développement d’application Pi4J pour le Raspberry Pi: https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html.
Le fichier sera jdk-8u191-linux-x64.tar.gz et nous l’installerons dans le répertoire /home/jbb/jdk1.8.0_191 où jbb est mon nom d’utilisateur Ubuntu.

Nous déposerons Eclipse dans le répertoire /home/jbb/eclipse-java-2018-09-linux-gtk-x86_64.

Avant de pouvoir démarrer Eclipse, il faudra définir quelques variables d’environnement:

sudo gedit /etc/profile
JAVA_HOME=/home/jbb/jdk1.8.0_191
PATH=$PATH:$HOME/bin:$JAVA_HOME/bin
export JAVA_HOME
export JRE_HOME
export PATH

Ensuite un reboot d’Ubuntu sera nécessaire.

Dans le répertoire /home/jbb/eclipse-java-2018-09-linux-gtk-x86_64/eclipse se trouve notre binaire eclipse que nous pourrons démarrer avec ./eclipse &.

Nous définirons alors l’espace de travail dans la fenêtre présentée
/home/jbb/eclipse-workspace .

En suivant les instruction du livre, nous pourrons créer un nouveau project Hello et y définir une classe de test:

public class Hello {
  public static void main(String[] args) {
    System.out.println(« Hello Ubuntu »);
  }
}

Pour la vérification, c’est la même démarche que dans l’article Raspberry Pi Zero WH mais en utilisant FileZilla pour le téléchargement et ssh pour exécuter les scripts Python ou le code Java.

Schéma Fritzing

Des schémas Fritzing, des scripts Python et des classes Java pour des LEDs et le capteur de lumière se trouvent dans le livre aux chapitres 6, 8 et 16. L’installation et l’utilisation de Frizing y sont même expliquées. Ce schéma a été crée pour cet article:

Les pins GPIO et le logiciel sont équivalent pour le Raspberry Pi 3 B ou le Zero WH. La position des broches est en annexe du livre ou sur le site du Pi4J.

Les résistances de 330 Ohm sont nécessaires pour protéger les circuits du Raspberry Pi.  La capacité devra être positionné correctement où le côté positif devrait être marqué.

Le fil jaune est connecté à la broche 13 physique (GPIO_02 du Pi4J). Les fils vert et orange utilisent les mêmes broches que le circuit au chapitre 5 et utilisé dans le script Python blink2led.py du chapitre suivant et dans l’article PyDev, un IDE Python pour Eclipse (usage: le GPIO du Raspberry Pi).

Image du circuit avec le Raspberry Pi Zero WH:

Script Python

Le code Python suivant, déposé dans le fichier lightleds.py, reçoit en continu l’intensité lumineuse du capteur. La référence du code source Python se trouve dans l’avant-propos du livre.

La limite de 9000 allume la led rouge. La valeur reçue est inverse à l’intensité. En dessus de 9000, on pourrait allumer un luminaire contrôler par un relais (chapitre 15 du livre).

# coding: utf-8
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)

#Définition des pins sur les broches 13, 12 et 15
lightPin = 13 # (GPIO 2)
LedPinGreen = 12 # pin15 (Pi4J GPIO_01)
LedPinRed = 15 # pin15 (Pi4J GPIO_03)
# pin3 la terre

def rc_time (lightPin):
  count = 0

  #Configuration en sortie
  GPIO.setup(lightPin, GPIO.OUT)
  GPIO.output(lightPin, GPIO.LOW)
  time.sleep(0.1) #pause de charge

  #Configuration en entrée
  GPIO.setup(lightPin, GPIO.IN)

  #Comptage
  while (GPIO.input(lightPin) == GPIO.LOW):
    count += 1

return count

try:
  GPIO.setup(LedPinRed, GPIO.OUT) # LedPinRed en mode output
  GPIO.setup(LedPinGreen, GPIO.OUT) # LedPinGreen en mode  output

  # Boucle éternelle
  while True:
    value = rc_time(lightPin)
    print value
    if value > 9000:
      GPIO.output(LedPinRed, GPIO.HIGH) # Allume la led rouge
      GPIO.output(LedPinGreen, GPIO.LOW) # Eteint la led verte
    else:
      GPIO.output(LedPinGreen, GPIO.HIGH) # Allume la led verte
      GPIO.output(LedPinRed, GPIO.LOW) # Eteint la led rouge

except KeyboardInterrupt:
  pass
finally:
  GPIO.cleanup()

GPIO.setmode(GPIO.BOARD)

L’instruction GPIO.setmode(GPIO.BOARD) indique que nous travaillons avec les broches physique.

Ce script Python peut être directement préparé sur le Raspberry Pi avec un éditeur et exécuté avec la commande python lightleds.py. Attention si nous copions collons d’Ubuntu au Raspberry Pi, de bien vérifier l’indentation indispensable aux scripts Python.

L’article Programmez en Java sans le Pi4J explique comment nous pourrions exécuter ce script en Java sans utiliser la librairie Pi4J.

Exercices

Exercice 1

Modifier lightleds.py pour qu’il reçoive comme paramètre la valeur limite (ici 9000) et un y/n pour montrer ou non à l’écran la valeur mesurée  (c’est à dire print value). Programmez correctement le script pour que les deux paramètres soient optionnels et dans n’importe quel ordre.

Partie Java

Ecrire le code Java sous Eclipse contenant la même fonction que le code Python ci-dessus, est la procédure habituelle adoptée dans le livre.

Le code présenté ici ne contiendra ni de code de simulation côté PC Ubuntu ni de System.out.print() de test et sera donc beaucoup plus simple que les exemples dans le livre. Il faudra juste qu’il compile sous Eclipse et Ubuntu, pas plus. Donc, attention aux erreurs.

Dans le livre nous vérifions avec du code Java le système d’exploitation et nous simulons la présence de composants GPIO. Pour le capteur de lumière nous utilisons la méthode Math.random()  pour générer des valeurs aléatoires.

Si nous désirons utiliser du code du livre pour l’exécuter sous Eclipse d’Ubuntu, il faudra juste corriger:

if (System.getProperty(« os.name »).startsWith(« Windows »)) {

avec:

if (System.getProperty(« os.name »).startsWith(« Linux »)) {

Le code qui suit a été développé sous Windows dont le projet Eclipse LightReadLeds a été ensuite copié sur un PC Ubuntu dans son Workspace. Je n’ai évidemment  utilisé que mon livre: un bon exercice de vérification pour moi. Il faudra consulter le chapitre 16 et la classe LightRead pour les détails de l’implémentation qui est similaire ici.

La classe LightReadLeds

Nous trouverons ici le code source de cette classe qui est un peu différente de LightRead du livre.

import java.util.ArrayList;
import java.util.Collections;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalMultipurpose;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinMode;
import com.pi4j.io.gpio.PinPullResistance;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;

public class LightReadLeds {
  private GpioController gpio;
  private GpioPinDigitalMultipurpose pin;
  private GpioPinDigitalOutput ledPinR;
  private GpioPinDigitalOutput ledPinV;

  private ArrayList listOfValues;

  public LightReadLeds(Pin pinPi4jLight,
    Pin pinPi4jLedR, Pin pinPi4jLedV) {
    gpio = GpioFactory.getInstance();
    pin = gpio.provisionDigitalMultipurposePin(pinPi4jLight,    
                        PinMode.DIGITAL_INPUT, 
                        PinPullResistance.PULL_DOWN);

    ledPinR = gpio.provisionDigitalOutputPin(pinPi4jLedR);
    ledPinV = gpio.provisionDigitalOutputPin(pinPi4jLedV);
  }

  public void ledsOnOff(int level, int limit) {
    if (level < limit) {
      ledPinR.setState(PinState.HIGH);
      ledPinV.setState(PinState.LOW);
    }
    else {
      ledPinR.setState(PinState.LOW);
      ledPinV.setState(PinState.HIGH);
    }
  }

  public int getValue(int nbRead) { //Valeur de la lumière ambiante
    listOfValues = new ArrayList();
 
    for (int i = 0; i < nbRead; i++) {
      pin.setMode(PinMode.DIGITAL_OUTPUT); //Comme sortie

      pin.setState(PinState.LOW);
      try {
        Thread.sleep(100);
      }
      catch (InterruptedException e) {
      }

      // Configure the pin as an input pin now
      pin.setMode(PinMode.DIGITAL_INPUT); //Comme entrée

      int value = 0; //Niveau de recharge
      for (int j = 0; j < 20000; j++) {
        if (pin.getState() == PinState.HIGH) {
          break;
        }
        value++;
      }

      listOfValues.add(value);
   }

    return computeAverage(nbRead, 2); //Moyenne
  }

  public int computeAverage(int nbTrials, int nbFirst) {
    Collections.sort(listOfValues);

    int count1 = 0;
    int count2 = 0;
    int sum = 0;

    for (Integer oneValue : listOfValues) {
      if (count1 >= ((nbTrials/4) + nbFirst)) {
        if (count1 < (nbTrials - (nbTrials / 4))) {
          count2++;
          sum += oneValue;
        }
      }
      count1++;
    }

    return sum / count2;
  }

  public static void main(String[] args) throws InterruptedException {
    LightReadLeds lRB = 
                  new LightReadLeds(RaspiPin.GPIO_02, RaspiPin.GPIO_01
                                    RaspiPin.GPIO_03);
    for (int i = 0; i < 20; i++) {
      int level = lRB.getValue(10); //10 lectures
      System.out.println("Value: " + level);

      lRB.ledsOnOff(level, 600);
      Thread.sleep(100);
    }
  }
}

Nous avons défini dans le constructeur de la classe LightReadLeds la définition des 3 broches correspondants au schéma Fritzing ci-dessus.

Pour les détails des classes du Pi4J, il faudra se référer au livre. Une classe comme GpioPinDigitalMultipurpose , par exemple, est évidemment référencé dans l’index et ensuite nous retrouverons un ou plusieurs cas d’utilisation avec la description et le code Java.

La méthode getValue() va nous permettre d’obtenir une valeur d’intensité de lumière. C’est identique au code Python: nous chargeons la capacité, nous changeons de direction la broche, et nous calculons le temps de décharge. Nous déposons le résultat dans la collection listOfValues.

La méthode computeAverage() va nous trier les valeurs pour pouvoir retirer les premières valeurs (nbFirst) et calculer la moyenne.

Le main() va boucler 20 fois, et la méthode ledsOnOff() va allumer une des LEDs suivant la valeur calculée, inverse de l’intensité.

Exécuter LightReadLeds sur le Raspberry Pi

Après compilation de LightReadLeds dans Eclipse, de la même manière que décrite dans le livre, nous pourrons transférer avec FileZilla le fichier LightReadLeds.class dans /home/pi/java et créer un fichier exécutable .sh avec ssh depuis Ubuntu contenant

java -Dpi4j.linking=dynamic -classpath .:/opt/pi4j/lib/’*’ LightReadLeds

C’est exactement la même procédure que pour la classe LightRead du chapitre 16.

Date de la dernière modification: 12 février 2019