Passons à la détection des billes pour notre projet PI-GBC. J'ai opté pour des optocoupleur à fourche dont l'écartement est idéal pour les billes prévues pour les modules GBC. Pour l'acquisition des données, nous nous tournerons vers l'Arduino. Ce microcontrôleur offre plus de possibilité que notre Raspberry surtout pour les entrées analogiques.
Pour ce projet, nous avons besoin d'un comptage de billes fiable pour pouvoir réaliser un séquencement des modules.
Grâce à la puissance du PI 4, nous allons pouvoir programmer notre arduino, directement à partir de celui-ci.
Pour ce projet, nous avons besoin d'un comptage de billes fiable pour pouvoir réaliser un séquencement des modules.
Grâce à la puissance du PI 4, nous allons pouvoir programmer notre arduino, directement à partir de celui-ci.
1 Installation du logiciel Arduino IDE
Nous avons la possibilité de télécharger le logiciel sur la page officielle d'Arduino. Il faudra choisir la version ARM 32 bits. Vous trouverez un tutoriel très bien fait pour l'installation de ce logiciel.
Après avoir téléchargé le fichier, extraire l'archive dans /home/pi/Documents
Sur le raspberry, la lecture du fichier peut être assez longue, patientez.
Ouvrir le dossier de l'archive et cliquez sur Outils -> Ouvrir le dossier actuel dans un terminal.
Installez l'IDE Arduino en lançant la commande suivante.
sudo ./install.sh
L'IDE Arduino est présent dans le menu
Nous pouvons commencer à travailler avec l'Arduino. Ne pas oublier de sélectionner le port USB ou est branché l'Arduino.
2 Expérimentation avec l'optocoupleur
Je ne vais pas vous faire un grand cours théorique des optocoupleur, d'autres le font mieux que moi. Pour le matériel, j'ai choisi l'optocoupleur à fourche LTH301-32 acheté sur le site Gotronic. Mon premier projet que je voulais présenter l'année dernière se basait sur la lecture de la valeur de sortie du phototransistor de l'optocoupleur.
2.1 Lecture de la valeur de sortie
Pour cela, je me suis basé sur cet article http://www.martyncurrey.com/connecting-an-photo-interrupter-to-an-arduino/. Voici le schéma de principe avec l'ajout des deux diodes led. Contrairement à l'article, j'utilise une résistance de 220 ohms car je n'ai pas de 150 ohms.
Et le schéma en platine d'essai.
Voici le code qu'il faudra télécharger dans l'Arduino
/* Test optocoupleur */
int ruptPin = 2; // select the input pin for the optocoupleur
int val = 0; // variable to store the value coming from the sensor
int LedRed = 2;
int LedGreen = 3;
void setup()
{
Serial.begin(9600); // set up Serial library at 9600 bps
pinMode(LedRed, OUTPUT);
pinMode(LedGreen, OUTPUT);
}
void loop()
{
val = analogRead(ruptPin); // read the value from the sensor
Serial.println(val); // print the sensor value to the serial monitor
if (val < 600) {
digitalWrite(LedGreen, LOW);
digitalWrite(LedRed, HIGH);
}
else {
digitalWrite(LedGreen, HIGH);
digitalWrite(LedRed, LOW);
}
delay(50);
}
Le moniteur série nous permet de visualiser la valeur en temps réel qui est environ de plus de 900 sans détection d'objet. La valeur de détection de 600 est empirique et est fonction de la luminosité ambiante. Il faut faire attention à la lumière parasite qui peut affecter la détection.
Un défaut subsiste avec ce type de montage, la détection de plusieurs billes dans un délai très court peut être masquée par la boucle procédurale du programme. On appelle ceci le polling, on scrute en permanence l'état de la broche, c'est pour cela que l'on ajoute une méthode delay pour ralentir le microcontrôleur mais risque de masquer une détection de bille.
Un défaut subsiste avec ce type de montage, la détection de plusieurs billes dans un délai très court peut être masquée par la boucle procédurale du programme. On appelle ceci le polling, on scrute en permanence l'état de la broche, c'est pour cela que l'on ajoute une méthode delay pour ralentir le microcontrôleur mais risque de masquer une détection de bille.
00:00
/
00:00
2.1 Câblage de l'optiocoupleur
Comme je veux que mon montage soit réutilisable pour d'autres projets, j'ai réalisé le câblage des optocoupleur comme ci-dessous. On les connectera à un shield grove avec les câbles prévus à cet effet.
Et voici quelques photos du montage de mes optocoupleurs.
2.2 Utilisation des interruptions externes INT0
Nous allons donc utiliser les interruptions externes de l'Arduino. Commençons par les interruptions INT0/INT1, les plus faciles à programmer. On en profitera pour ajouter un écran LCD pour contrôler le résultat. Voici le schéma avec l'interruption INT0 (D2).
Et le schéma en platine d'essai.
Voici le code qu'il faudra télécharger dans l'Arduino
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 6);
volatile int comptageImpulsion=0;
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
attachInterrupt(0, gestionINT0, RISING);
lcd.print("Nb balle");
lcd.setCursor(0,1);
lcd.print(comptageImpulsion);
}
void loop(){
lcd.setCursor(0,1);
lcd.print(comptageImpulsion);
delay(50);
}
void gestionINT0() {
comptageImpulsion=comptageImpulsion+1;
Serial.print("Nombre impulsions = ");
Serial.println(comptageImpulsion);
}
Voici un exemple de fonctionnement en testant en envoyant neuf billes en même temps. Le programme détecte toutes les billes. Attention à la lumière ambiante parasite, il y a un meilleur résultat en confinant les optocoupleurs surtout dans une pièce très éclairée.
00:00
/
00:00
2.2 Utilisation des interruptions externes PCINT2
Notre projet devra pouvoir commander sept moteurs. Nous aurons besoin autant de capteurs donc nous allons utiliser les interruptions de type PCINT2. Pour cela, il faudra utiliser une routine spéciale et faire la distinction des interruptions dans une fonction appelé ISR. Le programme suivant fonctionne avec deux interruptions sur les broches D2 et D7 pour l'instant car l'afficheur LCD prend les broches D3 à D6.
Mise à jour de mon programme, j'ai déplacé la routine d'affichage qui se trouvait dans la procédure ISR vers la fonction loop. Il est préférable de minimiser les traitement à l'intérieur de la procédure ISR.
Mise à jour de mon programme, j'ai déplacé la routine d'affichage qui se trouvait dans la procédure ISR vers la fonction loop. Il est préférable de minimiser les traitement à l'intérieur de la procédure ISR.
/*Interruption PCINT2*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 6);
volatile int opto1=0;
volatile int opto2=0;
void pciSetup(byte pin)
{
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
ISR(PCINT2_vect) // handle pin change interrupt for D0 to D7 here
{
if (digitalRead(2) == LOW){
opto1=opto1+1;
}
if (digitalRead(7) == LOW){
opto2=opto2+1;
}
}
void setup()
{
lcd.begin(16, 2);
pciSetup(7);
pciSetup(2);
lcd.print("Number balls");
lcd.setCursor(0,1);
String chaine = "1: " + String(opto1) + " 2: " + String(opto2);
lcd.print(chaine);
}
void loop()
{
lcd.setCursor(0,1);
String chaine = "1: " + String(opto1) + " 2: " + String(opto2);
lcd.print(chaine);
delay(100);
}
Et voici la démo du programme avec deux modules Lego GBC.
00:00
/
00:00
2.2 Utilisation des interruptions externes PCINT1 et PCINT2 et d'un affichage LCD avec I2C
Nous utiliserons un kit grove pour l'affichage LCD avec la communication I2C. Cela permet de n'utiliser que deux broches de l'Arduino et de libérer les broche D3 à D6 pour leur prochaine utilisation. Le câblage est d'une grande simplicité comme le montre cette photo. Malheureusement, avec la carte Shield Grove, nous ne pourrons pas utiliser les entrées D0 et D1. Nous allons utiliser les interruptions de type PCINT1 pour avoir nos sept entrées. Nous utiliserons l'entrée A0 en plus des entrées D2 à D7.
Pour utiliser cet afficheur, vous devrez importer une librairie spécifique, vous trouvez les informations sur cette page.
Pour utiliser cet afficheur, vous devrez importer une librairie spécifique, vous trouvez les informations sur cette page.
Voici le programme complet. Attention, pour un bon fonctionnement, toutes les entrées programmées devront être équipées de capteur pour éviter d'avoir des résultats incohérents.
/*Interruption PCINT1-PCINT2 with I2C*/
#include <Wire.h>
#include "rgb_lcd.h"
rgb_lcd lcd;
const int colorR = 255;
const int colorG = 0;
const int colorB = 0;
volatile int opto1=0;
volatile int opto2=0;
volatile int opto3=0;
volatile int opto4=0;
volatile int opto5=0;
volatile int opto6=0;
volatile int opto7=0;
void pciSetup(byte pin)
{
*digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin
PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
ISR(PCINT2_vect) // handle pin change interrupt for D2 to D7 here
{
if (digitalRead(2) == LOW){
opto1=opto1+1;
}
if (digitalRead(3) == LOW){
opto2=opto2+1;
}
if (digitalRead(4) == LOW){
opto3=opto3+1;
}
if (digitalRead(5) == LOW){
opto4=opto4+1;
}
if (digitalRead(6) == LOW){
opto6=opto5+1;
}
if (digitalRead(7) == LOW){
opto6=opto6+1;
}
}
ISR(PCINT1_vect) // handle pin change interrupt for A0 to A5 here
{
if (digitalRead(A0) == LOW){
opto7=opto7+1;
}
}
void setup()
{
lcd.begin(16, 2);
lcd.setRGB(colorR, colorG, colorB);
pciSetup(2);
pciSetup(3);
pciSetup(4);
pciSetup(5);
pciSetup(6);
pciSetup(7);
pciSetup(A0);
lcd.print("2 3 4 5 6 7 A");
}
void loop()
{
lcd.setCursor(0,1);
String chaine = String(opto1) + " " + String(opto2) + " " + String(opto3) + " " + String(opto4) + " " + String(opto5) + " " + String(opto6) + " " + String(opto7);
lcd.print(chaine);
delay(100);
}
Maintenant que nous avons vu comment effectuer le comptage des billes, nous allons voir la commande des moteurs par les GPIO.
Références
Les interruptions de l'Arduino : https://www.locoduino.org/spip.php?article64
Simple Pin Change Interrupt on all pins : https://playground.arduino.cc/Main/PinChangeInterrupt/
Installation du grove-LCD : http://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/
Simple Pin Change Interrupt on all pins : https://playground.arduino.cc/Main/PinChangeInterrupt/
Installation du grove-LCD : http://wiki.seeedstudio.com/Grove-LCD_RGB_Backlight/