1. Introduction

Le tri des déchets est un des plus grands problèmes du 21ème siècle. En effet, une grande partie des déchets jetés pourrait être recyclée. Ce projet présente une possible solution pour améliorer le tri : une poubelle intelligente qui n'accepte que du papier. Quand un objet n’étant pas constitué de papier entre dans la corbeille, le système émette un son continu et une LED clignote. (Le concept pourrait très facilement être inversé pour n'accepte que du plastique.)
Ce projet est découpé en deux parties, une pour l'alarme et une pour la camera.

2. Matériel et méthodes

2.1 Matériel

• 1 Raspberry Pi
• 1 Caméra
• 1 Haut-parleur
• 1 Corbeille
• 1-2 câbles et une résistance électrique de 330 Ohms
• 1 LED
• 1 Mini Bread bord
• 1 GPIO

2.2 Méthode

2.2.1 L'alarme

L'alarme est composée de deux éléments : un son et d'une lumière.
Pour émettre un son, il faut forcément passer par un haut-parleur extérieur car le raspberry n'en a pas. Ici s'ouvrent à nous deux possibilités. On peut utiliser un haut-parleur connecté soit via un câble jack, soit via Bluetooth. (Pour connecter la raspberry pi au haut-parleur, le plus facile est de passer par l'interface graphique du raspberry et d'aller dans l'onglet bluetooth)
Pour la LED, il suffit de brancher sur la mini bread board le GPIO et la LED sur un des pins. (Au cours de ce projet, le pin 17 sera utilisé.) À cette LED, il faut venir ajouter une résistance de 330 Ohm. Voici un schéma du montage:

ElectMontage.png
Figure 2.1-Shéma du montage électrique
LED_Montage.jpg
Figure 2.2-Photo du montage électrique

Pour jouer un son avec le raspberry pi, il est possible d'utiliser la librairie pygame. Un des avantages avec cette librairie est qu'il est possible de demander de jouer un son plusieurs fois sur une seule ligne. Pour utiliser pygame pour lire un son, il faut tout d'abord écrire le code suivant:

  import pygame
  try:
     pygame.mixer.init()
     pygame.mixer.music.load("beep1.ogg")
  except Exception as error:
     print(error)

Avec ce bout de code, il nous sera plus tard possible de demander au programme de jouer le son.
Le "try" et "except" sont là pour détecter d’éventuelles erreurs. Comme notamment l'absence de sortie audio. Ici "beep1.ogg" correspond à un fichier son placer dans le même dossier que le fichier contenant le code.
Pour allumer la LED, il faut utiliser la librairie GPIO. Le code pour setup GPIO est le suivant:

  import RPi.GPIO as GPIO
  LED = 17
  GPIO.setwarnings(False)
  GPIO.setmode(GPIO.BCM)
  GPIO.setup(LED, GPIO.OUT)

L'alarme est constituée de trois fonctions, une pour démarrer le son, une pour faire clignoter la LED et une pour stopper l'alarme.

   def Alarm_Start():
      global has_alarm_started
      has_alarm_started = True
      try:
        pygame.mixer.music.play(1000000)
      except Exception as error:
        print(error)

Cette fonction demande à Pygame de jouer le son beep.ogg un million de fois. Ce qui est très long et qui sera généralement arrêté avant d'avoir fini.

  def Alarm_Tick():
      global LED, led_stat, LED_BLINKS_FRE, LED_STAT
  
      GPIO.output(LED,LED_STAT[int(led_stat)%2])
      led_stat += LED_BLINKS_FRE

Ici, un tableau de variable contenant uniquement "GPIO.LOW" et "GPIO.HIGH" est utilisé pour faire clignoter la LED.

  def Alarm_End():
      global has_alarm_started, has_wrong_object
      GPIO.output(LED, GPIO.LOW)
try: pygame.mixer.music.stop() except Exception as error: print(error) has_alarm_started,has_wrong_object = False, False

Ici le programme éteint la LED et arrête le son.

2.2.2 La caméra

La caméra se connecte dans la petite fente situé entre la sortie HDMI et la sortie audio. (Le côté bleu de la bande doit être orienté vers la prise jack.)

Camera_plugged.jpg
Figure 2.3-Branchement de la camera

Avant de pouvoir utiliser la camera, il faut vérifier que le sunny chip (voir image suivante) soit correctement enfoncer. Car si ce n'est pas le cas la camera ne pourra tout simplement pas fonctionner. Veuillez noter qu'il semblerait que cette puce puisse se déclipser assez facilement.

Camera.jpg
Figure 2.4-Camera et sunny chip

En plus de cela, il faut aussi vérifier que la camera est activé. Cela peut se faire en tapant la commande sudo raspi-config et en allant dans interface/caméra. Après cela, il faut redémarrer le raspberry pi.

Le code pour initialiser la camera est le suivant:

  import numpy
  import picamera
  import picamera.array
camera = picamera.PiCamera() CAMERA_WIDTH = 64 CAMERA_HIGHT = 48
camera.resolution = (CAMERA_WIDTH, CAMERA_HIGHT) camera.exposure_mode = 'auto' camera.awb_mode = 'auto'

Ici la camera aura une résolution de 64x48 car plus la résolution est grande plus le programme sera lent. Il est donc mieux de prendre une résolution assez petite. Pour détecter un mouvement le code est le suivant:

  def Take_Motion_Image():
     capture = picamera.array.PiRGBArray(camera)
     camera.capture(capture, format='rgb')
     return capture.array
motion_capture1 = Take_Motion_Image()
def Scan_Motion(): global motion_capture1, motion_capture2, CAMERA_WIDTH, CANERA_HIGHT, SENSIBILITY, THRESHOLD motionFound = False motion_capture2 = Take_Motion_Image() diffCount = 0 center_x = 0 center_y = 0
for w in range(0, CAMERA_WIDTH): for h in range(0, CAMERA_HIGHT): diff = abs(int(motion_capture1[h][w][1]) - int(motion_capture2[h][w][1])) diffCount += (diff > THRESHOLD) center_x += w*(diff > THRESHOLD) center_y += h*(diff > THRESHOLD)
motionFound, motion_capture1 = (diffCount > SENSIBILITY), motion_capture2
return (motionFound and Scan_Color(center_x/diffCount, center_y/diffCount, COLOR_CHECK_RADIUS))

Ce code s'inspire fortement d'un autre trouvé sur github. (cf référence 1) Ici le programme va parcourir chaque pixel de l'image et les comparer avec l'image précédente (On ne vérifie que la couleur verte car le programme ralentirait si on devait vérifier les autres couleurs.). Si la différence de couleur est trop grande, c'est que quelque chose a bougé. Ce bout de code permette aussi de savoir de quel côté un objet a bougé. Le programme va ensuite aller voir si ce qui a bougé est blanc ou pas:

  def Scan_Color(center_x,center_y,radius):
     global CAMERA_WIDTH, CAMERA_HIGHT,motion_capture2, COLOR_SENSIBILITY, COLOR_THRESHOLD
     color_diff = 0
     
     for a in range(max(0, center_x-radius),min(CAMERA_WIDTH, center_x+radius)):
        for b in range(max(0, center_y-radius),min(CAMERA_HIGHT, center_y+radius)):
           color_diff += (motion_capture2[b, a, 0] < COLOR_THRESHOLD or motion_capture2[b, a, 1] < COLOR_THRESHOLD or motion_capture2[b, a, 2] < COLOR_THRESHOLD)
return (color_diff > COLOR_SENSIBILITY)

Ici le programme va parcourir uniquement les pixels dans la région de mouvement et vérifier si ces pixels sont blancs ou pas.
Après cela, il ne reste plus qu'a vérifié constamment si quelque chose de non blanc passe devant la caméra:

  try:
     while True:
        if (Scan_Motion()):
           if has_pass:
               has_pass = False
               if (has_wrong_object):
                  Alarm_End()
               else:
                  Alarm_Start()
                  has_wrong_object = True
            else:
               has_pass = True
if has_alarm_started: Alarm_Tick()
except KeyboardInterrupt: pass
except Exception as error: print(error)
finally: GPIO.cleanup()

Avec ceci, le programme peut fonctionner. Il ne reste plus qu'à faire varier les constantes pour la sensibilité.

  SENSIBILITY = 100
  THRESHOLD = 10
  
  COLOR_SENSIBILITY = 15
  COLOR_THRESHOLD = 80
  COLOR_CHECK_RADIUS = 5

3. Résultats

Nous avons donc maintenant un programme capable de détecter si quelque si ce qui passe devant la caméra est blanc ou pas. Si ce qui passe devant la caméra n'est pas blanc, une alarme sonore et lumineuse se déclenchant. Ces dernières ne s’arrêtent que quand l'objet repasse devant la caméra.

MontageFinal.png
Figure 3.1-MontageFinal

4. Discussion

Un des problèmes majeurs de ce programme est qu'il est assez lent. En effet, à chaque fois que la camera doit prendre une photo, il se passe environ une demi-seconde avant que le programme ne passe à la suite. Ceci pourrait être corrigé en changeant la façon dont sont analyser les mouvements. Si cette dernière était faite toute les 1/30 de seconde, le programme irait beaucoup plus vite. Cela pourrait être fait en analysant un flux vidéo au lieu de deux images. Une autre alternative pourrait être de réduire la résolution de la caméra à 1x1. Car comme dit un peu plus haut, plus la résolution est petit, moins la camera prend de temps pour générer le tableau de variables.
Un autre des problèmes est que le programme détecte parfois des mouvements sans qu'il y en ait. Pour cela, il faudrait réussir à trouver les bonnes valeurs pour SENSIBILITY et THRESHOLD. Cependant ce problème semble varié en fonction de l'environnement. (Je n'ai jamais eu de fausses détections de mouvement au gymnase alors que j'en ai eu une dizaine chez moi.) Une solution pour cela serait d'ajouter un bout de code pour que le programme se calibre.

5. Conclusion

Malgré les petits problèmes de vitesse et de fausse détection, notre poubelle intelligente fonctionne. Elle reste serte perfectible.
En plus d'avoir une poubelle qui n'accepte que du papier, il serait possible de changer le but du programme en modifiant les opérateurs logiques lors de la détection de couleur. Cependant, ce programme ne pourra surement pas être utilisé pour trier autre chose que des objets de couleurs. Si l'on veut créé une vraie poubelle intelligente, il faudrait surement aussi détecter la forme de l'objet. De cette manière, il sera possible de détecter si une bouteille en PET a été jeter dans la poubelle pour alu. Peut-être même que dans le futur, nous n'aurons plus besoin de trier nos déchets car des robots le feront pour nous.

Références

1) https://gist.github.com/FutureSharks/ab4c22b719cdd894e3b7ffe1f5b8fd91
2) https://picamera.readthedocs.io/
3) https://www.pygame.org/docs/ref/mixer.html