ENIB 2023 : Les petits voyageurs : Différence entre versions

De Les Fabriques du Ponant
Aller à : navigation, rechercher
(photo de l'équipe)
(Catégories)
 
(44 révisions intermédiaires par un autre utilisateur non affichées)
Ligne 1 : Ligne 1 :
  
 
==Les petits voyageurs:==
 
==Les petits voyageurs:==
[[Fichier:Petits voyageurs 1.jpg|600px]]
+
 
 +
[[Fichier:Fini1.jpeg|600px]]
  
 
==Description courte==
 
==Description courte==
Ligne 8 : Ligne 9 :
 
Déplacer le capteur de couleur dans le labyrinthe pour faire une suite de couleur correspondant au drapeau du pays.
 
Déplacer le capteur de couleur dans le labyrinthe pour faire une suite de couleur correspondant au drapeau du pays.
  
==Matériels et machines envisagés==
+
==Matériels et machines utilisés==
  
* plaque de bois de 30cm x 30cm                           * découpeuse laser
+
* plaque de bois de 30cm x 30cm                          
* 2 boutons poussoirs                                      * poste à souder
+
* 2 boutons poussoirs                                       
* 1 capteur RGB TCS3200                                    * pistolet a colle
+
* 1 capteur RGB TCS3200                                     
 
* carte Arduino                                   
 
* carte Arduino                                   
 
* cartons ( pour créer le prototype)
 
* cartons ( pour créer le prototype)
 
* câbles Dupont
 
* câbles Dupont
* plaque de plexi-glace ( 25cm x 25cm)
+
* plaque de Cork de 30cm x 30cm
 +
* colle à bois
 +
* peintures et pinceaux
 +
* cutter
 +
* pic à broque
 +
* scotch
 +
 
 +
 
 +
* découpeuse laser
 +
* poste à souder
 +
 
 +
== Réalisation==
 +
 
 +
'''Etape 1:'''
 +
Souder les composants si nécessaires.
 +
 
 +
'''Etape 2:'''
 +
Créer les énigmes.
 +
Ci dessous la liste de nos énigmes
 +
[[Fichier:Liste des énigmes.docx]]
 +
 
 +
'''Etape 3:'''
 +
Ecrire le code. (cf code ci dessous)
 +
 
 +
'''Etape 4:'''
 +
Etablir un plan du labyrinthe.
 +
 
 +
[[Fichier:Petits voyageurs 1.jpg|600px]]
 +
 
 +
'''Etape 5:'''
 +
Faire un prototype du labyrinthe en carton.
 +
 
 +
[[Fichier:Petit voyageurs2.jpg|600px]]
 +
 
 +
'''Etape 6:'''
 +
tracer le labyrinthe sur la plaque de bois.
 +
 
 +
[[Fichier:Petit voyageurs3.jpg|600px]]
 +
 
 +
'''Etape 7:'''
 +
Sur inskape, creer un fichier avec toutes les murs du labyrinthe qui doivent être découpés / graver.
 +
 
 +
[[Media:Decoupe laser.svg|téléchargez le svg]]
 +
 
 +
 
 +
'''Etape 8:'''
 +
Découper et graver les murs du labyrinthe à la découpe laser.
 +
 
 +
[[Fichier:Murs.jpeg|600px]]
 +
 
 +
'''Etape 9:'''
 +
Peindre certaines cases du labyrinthe en fonction des couleurs nécessaires.
 +
 
 +
Astuce : Mettre du scotch pour avoir des bords lisses
 +
 
 +
[[Fichier:Peinture.jpeg|600px]]  —> [[Fichier:Peinture2.jpeg|600px]]
 +
 
 +
 
 +
 
 +
'''Etape 10:'''
 +
A l'aide de la colle à bois, coller les murs du labyrinthe.
 +
 
 +
[[Fichier:colle1.jpeg|600px]] —> [[Fichier:colle2.jpeg|600px]]
 +
 
 +
 
 +
'''Etape 11:'''
 +
Creer une petite protection pour le capteur de couleur afin de pouvoir le déplacer dans le labyrinthe.
 +
 
 +
[[Fichier:Protection.jpeg|600px]]
 +
 
 +
'''Etape 12:'''
 +
Rajouter les différents éléments ( carte arduino, capteurs, boutons poussoirs).
 +
 
 +
[[Fichier:Fini1.jpeg.jpeg|600px]]
 +
 +
 
  
 
==Code==
 
==Code==
 +
prog.cpp:
 +
<pre>
 +
 +
#include "color.hpp"
 +
#include "enigme.hpp"
 +
#include <iostream>
 +
#include <random>
 +
#include <vector>
 +
 +
 +
int main()
 +
{
 +
//variable initiale
 +
int erreur=-1;
 +
int test=1;
 +
int bonneReponse=0;
 +
 +
//liste des couleurs disponible pour les drapeaux
 +
deb::Color rouge{1024, 0, 0};
 +
deb::Color bleu{0, 0, 1024};
 +
deb::Color blanc{1024, 1024, 1024};
 +
deb::Color noir{0, 0, 0};
 +
deb::Color vert{0, 1024 ,0};
 +
deb::Color orange{0, 0, 1024};
 +
deb::Color jaune{0, 0, 1024};
 +
 +
//liste des enigmes
 +
deb::Enigme ea{bleu, blanc, rouge, "Pays du champagne"};
 +
deb::Enigme eb{vert, blanc, rouge, "Pays des pâtes"};
 +
deb::Enigme ec{vert, blanc, orange, "Pays des moutons "};
 +
deb::Enigme ed{rouge, blanc, rouge, "Pays d’origine de Marie Antoinette"};
 +
deb::Enigme ee{noir, rouge, jaune, "Pays d’origine des knödels "};
 +
deb::Enigme ef{jaune, vert, rouge, "Quel est ce pays ? Mjubojf"};
 +
deb::Enigme eg{rouge, blanc, bleu, "Quel est ce pays ? .-.. ..- -..- . -- -... --- ..- .-. --."};
 +
deb::Enigme eh{rouge, blanc, bleu, "Quel est ce pays ? Ozxr-Azr"};
 +
deb::Enigme ei{noir, jaune, rouge, "Pays de la gaufre"};
 +
deb::Enigme ej{vert, jaune, bleu, "Mon premier est un mec. Mon second qualifie quelque chose d’agréable."};
 +
deb::Enigme ek{blanc, bleu, noir, "Quel est ce pays ? . ... - --- -. .. ."};
 +
deb::Enigme el{rouge, blanc, rouge, "Quel est ce pays ? 53886643"};
 +
deb::Enigme em{rouge, blanc, vert, "Mon premier est un pronom personnel indéfini. Mon second contient autant de rouge que de vert que de bleu."};
 +
deb::Enigme en{bleu, jaune, rouge, "Quel est ce pays ? Spvnbojf"};
 +
deb::Enigme eo{bleu, jaune, rouge, "Ma capitale est vieille "};
 +
deb::Enigme ep{bleu, jaune, rouge, "Quel est ce pays ? - -.-. .... .- -.."};
 +
deb::Enigme eq{rouge, bleu, orange, "Son papier sent bon "};
 +
deb::Enigme er{bleu, rouge, vert, "Quel est ce pays ? 2937224526"};
 +
deb::Enigme es{rouge, jaune, vert, "Ma capitale est La Paz"};
 +
deb::Enigme et{rouge, jaune, vert, "Mon premier est la plante sous laquelle il faut s’embrasser. Mon second est l’arrivée en ce monde."};
 +
deb::Enigme eu{blanc, vert, rouge, "Mon premier est une sphère d’une substance dans une autre. Mon second est un mec. Mon troisième peut être cantonais, thai ou basmati. "};
 +
deb::Enigme ev{jaune, bleu, rouge, "Ma capitale est Bogota"};
 +
deb::Enigme ew{orange, blanc, vert, "Quel est ce pays ? Dpuf e’Jwpjsf"};
 +
deb::Enigme ex{vert, jaune, rouge, "Quel est ce pays ? -- .- .-.. .."};
 +
deb::Enigme ey{vert, blanc, vert, "Quel est ce pays ? 6443742"};
 +
deb::Enigme ez{rouge, blanc, rouge, "Pays du Macchu Picchu"};
 +
deb::Enigme eea{blanc, bleu, rouge, "Pays du Kremlin"};
 +
deb::Enigme eeb{rouge, blanc, noir, "Quel est ce pays ? Xdldm"};
 +
std::vector<deb::Enigme> vectEnigme{ea,eb,ec,ed,ee,ef,eg,eh,ei,ej,ek,el,em,en,eo,ep,eq,er,es,et,eu,ev,ew,ex,ez,eea,eeb};
 +
 +
//loop
 +
 +
if (appui sur bouton acquisition)  //on enregistre la couleur actuelle
 +
{
 +
int a,b,c = 10,10,1024; //on recupere les valeurs du capteur
 +
 +
if (test==4)
 +
{
 +
bonneReponse=0; //il y a trop de reponse le resultat sera faut
 +
}
 +
 +
if (test==3)
 +
{
 +
if (enigmeEnCours.trois.isitme(a,b,c)) {bonneReponse=bonneReponse+1} //on compare a la couleur du drapeau
 +
test=4;
 +
}
 +
 +
if (test==2)
 +
{
 +
if (enigmeEnCours.deux.isitme(a,b,c)) {bonneReponse=bonneReponse+1} //on compare a la couleur du drapeau
 +
test=3;
 +
}
 +
 +
if (test==1)
 +
{
 +
if (enigmeEnCours.un.isitme(a,b,c)) {bonneReponse=bonneReponse+1} //on compare a la couleur du drapeau
 +
test=2;
 +
}
 +
}
 +
 +
 +
if (appui sur le bouton validé and erreur!=-1)//on regarde le resultat final
 +
{
 +
if (bonneReponse==3)
 +
{
 +
std::cout <<"Victoire ! Si tu veux rejouer, clique sur JSP.\n";
 +
erreur =-1;
 +
}
 +
if (bonneReponse!=3 and erreur==0)
 +
{
 +
std::cout <<"Tu as fait une erreur. Repars de zéro et essaye encore. \n";
 +
erreur =1;
 +
}
 +
if (bonneReponse!=3 and erreur==1)
 +
{
 +
std::cout <<"Tu as perdu. Si tu veux rejouer, clique sur JSP.\n";
 +
erreur =-1;
 +
}
 +
}
 +
 +
 +
if (appui sur bouton validé and erreur==-1) //lancement nouvelle enigme
 +
{
 +
srand((unsigned) time(NULL));
 +
deb::Enigme enigmeEnCours=vectEnigme[rand() % 28];
 +
std::cout << enigmeEnCours.question << "\n";
 +
erreur=0;
 +
test=1;
 +
bonneReponse=0;
 +
}
 +
}
 +
 +
 +
</pre>
 +
 +
color.cpp:
 +
 +
<pre>
 +
 +
 +
//----------------------------------------------------------------------------
 +
 +
#include "color.hpp"
 +
 +
namespace deb
 +
{
 +
bool Color::isitme(int r,int g,int b) const
 +
{
 +
if (r<(red-200)) {return false;}
 +
if (r>(red+200)) {return false;}
 +
if (g<(green-200)) {return false;}
 +
if (g>(green+200)) {return false;}
 +
if (b<(blue-200)) {return false;}
 +
if (b>(blue+200)) {return false;}
 +
return true;
 +
 +
}
 +
 +
 +
}// namespace deb
 +
 +
//----------------------------------------------------------------------------
 +
</pre>
 +
 +
color.hpp:
 +
<pre>
 +
 +
//----------------------------------------------------------------------------
 +
 +
#ifndef DEB_COLOR_HPP
 +
#define DEB_COLOR_HPP
 +
 +
#include <iostream>
 +
 +
namespace deb {
 +
 +
struct Color
 +
  {
 +
    int red,green,blue;
 +
 +
    Color(int red, int green, int blue): red{std::move(red)}, green{std::move(green)}, blue{std::move(blue)}
 +
    {/* nothing to do */}
 +
 +
    bool isitme(int r,int g,int b) const;
 +
  };
 +
 +
 +
 +
} // namespace deb
 +
 +
#endif // DEB_COLOR_HPP
 +
 +
//----------------------------------------------------------------------------
 +
 +
 +
</pre>
 +
 +
 +
 +
enigme.hpp
 +
 +
<pre>
 +
 +
 +
//----------------------------------------------------------------------------
 +
 +
#ifndef DEB_ENIGME_HPP
 +
#define DEB_ENIGME_HPP
 +
 +
#include <iostream>
 +
#include <string>
 +
#include "color.hpp"
 +
 +
namespace deb {
 +
 +
struct Enigme
 +
  {
 +
    Color un,deux,trois;
 +
    std::string question;
 +
 +
    Enigme(Color u, Color d, Color t, std::string q): un{std::move(u)}, deux{std::move(d)}, trois{std::move(t)}, question{std::move(q)}
 +
    {/* nothing to do */}
 +
 +
  };
 +
 +
 +
 +
} // namespace deb
 +
 +
#endif // DEB_ENIGME_HPP
 +
 +
//----------------------------------------------------------------------------
 +
 +
 +
</pre>
 +
 +
'''code BP :'''
 +
 +
Les_petits_voyageurs.ino
 +
 +
<pre>
 +
 +
#include "Test_BP.h"
 +
#include "Arduino.h"
 +
int lancement=0;
 +
 +
void setup()
 +
{
 +
  Serial.begin(115200);
 +
  setup_BP();
 +
  //constantes générées aussi en dehors de la loop
 +
}
 +
 +
 +
void loop()
 +
{
 +
  lancement=BP(lancement);
 +
  if (lancement==1)
 +
  {
 +
    delay(20);
 +
    Serial.println("Bonjour ! ");
 +
  }
 +
}
 +
 +
</pre>
 +
Test_BP.cpp
 +
 +
<pre>
 +
#include "Test_BP.h"
 +
 +
//BP1
 +
const int BP1=4;
 +
 +
int boutonState = 0;
 +
int lastBoutonState = 0;
 +
 +
void setup_BP()
 +
{
 +
  //setup fonction bouton
 +
  pinMode(BP1, INPUT);
 +
}
 +
 +
int BP(int lancement) //permet de détecter les FM/FD du BP
 +
{
 +
  /*
 +
  Serial.print("etat bouton : ");
 +
  Serial.println(boutonState);
 +
  Serial.print("etat bouton precedent : ");
 +
  Serial.println(lastBoutonState);
 +
  */
 +
 +
  boutonState=digitalRead(BP1);
 +
  Serial.println(boutonState);
 +
  if (boutonState==HIGH)
 +
  {
 +
    if (boutonState != lastBoutonState)
 +
    {
 +
      lancement=1;
 +
      //Serial.println("00");
 +
      lastBoutonState=boutonState;
 +
    }
 +
    else
 +
    {
 +
      lancement=0; //état récurrent de lancement, on reste appuyé sur BP
 +
      //Serial.println("10");
 +
    }
 +
  }
 +
  else
 +
  {
 +
    if (boutonState != lastBoutonState)
 +
    {
 +
      //Serial.println("01");
 +
      lancement=0;
 +
      lastBoutonState=boutonState;
 +
    }
 +
    else
 +
    {
 +
      //Serial.println("11");
 +
    }
 +
  }
 +
  //Serial.println(lancement);
 +
 +
  return lancement;
 +
}
 +
 +
</pre>
 +
 +
 
<pre>
 
<pre>
ici je pose mon code documenté !
+
#ifndef TEST_BP_H
 +
#define TEST_BP_H
 +
 
 +
#include <Arduino.h>
 +
 
 +
 
 +
void setup_BP();
 +
int BP(int lancement);
 +
 
 +
#endif
 +
 
 +
</pre>
 +
 
 +
'''code capteur:'''
 +
 
 +
color_detection_methods.hpp
 +
 
 +
<pre>
 +
/* This file is taken from MyOwnBricks project.
 +
* MyOwnBricks is a library for the emulation of LEGO PoweredUp sensors on microcontrollers
 +
* Copyright (C) 2021-2022 Ysard - <ysard@users.noreply.github.com>
 +
*
 +
* This program is free software: you can redistribute it and/or modify
 +
* it under the terms of the GNU General Public License as published by
 +
* the Free Software Foundation, either version 3 of the License, or
 +
* (at your option) any later version.
 +
*
 +
* This program is distributed in the hope that it will be useful,
 +
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 +
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +
* GNU General Public License for more details.
 +
*
 +
* You should have received a copy of the GNU General Public License
 +
* along with this program.  If not, see <https://www.gnu.org/licenses/>.
 +
*/
 +
 
 +
/**
 +
* @brief Discretize colors and return uint8_t color code.
 +
*    Available colors: COLOR_NONE, COLOR_BLACK, COLOR_BLUE,
 +
*    COLOR_GREEN, COLOR_RED, COLOR_WHITE.
 +
*
 +
*    Generally speaking, stable measuring conditions are required, i.e.,
 +
*    a stable measuring distance not exceeding 4 cm, no interfering light
 +
*    reaching the side of the sensor. Think about matt black sensor shroud.
 +
*
 +
*    Metrics:
 +
*      - BASIC_RGB: Simple comparison between channels;
 +
*          Very fast but is likely to produce errors.
 +
*      - MANHATTAN: Sum of absolute values of distances.
 +
*          Quite heavy, but quite accurate if the reference values have been
 +
*          measured seriously and if the measurement environment is controlled
 +
*          (reproducible). Distance between the sensor and the object should be
 +
*          the same as during learning.
 +
*          https://fr.wikipedia.org/wiki/Distance_de_Manhattan
 +
*    - CANBERRA: A weighted version of Manhattan distance;
 +
*          Very heavy but brings a higher accuracy and more tolerance/stability to variations
 +
*          in the measurement environment.
 +
*          Note: The manipulation of decimal numbers should be avoided
 +
*          on microcontrollers... Does it worth it? Probably not.
 +
*          https://en.wikipedia.org/wiki/Canberra_distance
 +
*/
 +
//#define BASIC_RGB
 +
//#define MANHATTAN
 +
//#define CANBERRA
 +
 
 +
// Colors (detected & LED (except NONE for this last one)) expected values
 +
#define COLOR_NONE      0xFF
 +
#define COLOR_BLACK    0
 +
#define COLOR_PINK      1
 +
#define COLOR_PURPLE    2
 +
#define COLOR_BLUE      3
 +
#define COLOR_LIGHTBLUE 4
 +
#define COLOR_CYAN      5
 +
#define COLOR_GREEN    6
 +
#define COLOR_YELLOW    7
 +
#define COLOR_ORANGE    8
 +
#define COLOR_RED      9
 +
#define COLOR_WHITE    10
 +
 
 +
extern uint16_t red, green, blue;
 +
 
 +
 
 +
#ifdef BASIC_RGB
 +
uint8_t detectColor(const uint16_t &red, const uint16_t &green, const uint16_t &blue) {
 +
    if ((red > green) && (red > blue)) {
 +
        return COLOR_RED;
 +
    } else if ((green > red) && (green > blue)) {
 +
        return COLOR_GREEN;
 +
    } else if ((blue > red) && (blue > green)) {
 +
        return COLOR_BLUE;
 +
    }
 +
}
 +
#endif
 +
 
 +
 
 +
#if (defined(MANHATTAN) || defined(CANBERRA))
 +
// *_1: measures at 1 cm
 +
// *_3: measures at 3 cms
 +
const uint16_t SAMPLES[][3] = {
 +
    { 297,  83,  56 }, // RED_1
 +
    {  43,  20,  17 }, // RED_3
 +
    {  35, 142, 193 }, // BLUE_1
 +
    {  35,  94, 116 }, // BLUE_3
 +
    {  86, 257, 257 }, // CYAN_1
 +
    {  36,  98,  97 }, // CYAN_3
 +
    { 120, 141,  46 }, // YELLOW_1
 +
    {  72,  73,  30 }, // YELLOW_3
 +
    { 338, 373, 120 }, // YELLOW_PLQ_1
 +
    { 159, 267, 201 }, // WHITE_1
 +
    {  87, 126, 102 }, // WHITE_3
 +
    {  89, 322, 163 }, // GREEN_1
 +
    {  58, 106,  68 }, // GREEN_3
 +
    { 103, 189,  57 }, // GREEN_LIGHT_1
 +
    {  51,  77,  33 }, // GREEN_LIGHT_3
 +
    {  26,  34,  28 }  // BLACK_1
 +
};
 +
 
 +
const uint8_t SAMPLES_MAP[] = {
 +
    COLOR_RED,    COLOR_RED,
 +
    COLOR_BLUE,  COLOR_BLUE,
 +
    COLOR_BLUE,  COLOR_BLUE,
 +
    COLOR_YELLOW, COLOR_YELLOW,COLOR_YELLOW,
 +
    COLOR_WHITE,  COLOR_WHITE,
 +
    COLOR_GREEN,  COLOR_GREEN,
 +
    COLOR_GREEN,  COLOR_GREEN,
 +
    COLOR_BLACK
 +
};
 +
 
 +
// Number of samples
 +
const uint8_t samplesCount = sizeof(SAMPLES) / sizeof(SAMPLES[0]);
 +
 
 +
uint8_t detectColor(const uint16_t &red, const uint16_t &green, const uint16_t &blue) {
 +
#ifdef MANHATTAN
 +
    uint16_t minDist = 10000;
 +
    uint16_t expDist;
 +
#else
 +
    float minDist = 3;
 +
    float expDist;
 +
#endif
 +
    uint8_t bestSampleIndex = 0;
 +
 
 +
    for (uint8_t i = 0; i < samplesCount; i++) {
 +
#ifdef MANHATTAN
 +
        expDist = abs(static_cast<int16_t>(red - SAMPLES[i][0]))
 +
                  + abs(static_cast<int16_t>(green - SAMPLES[i][1]))
 +
                  + abs(static_cast<int16_t>(blue - SAMPLES[i][2]));
 +
#else
 +
        // Yeah it's ugly but abs() of Arduino is a macro different from the stl implementation
 +
        // moreover the parameter must be explicitly signed.
 +
        // The numerator or denominator must be a float.
 +
        // https://www.best-microcontroller-projects.com/arduino-absolute-value.html
 +
        // https://github.com/arduino/reference-en/issues/362
 +
        expDist = (abs(static_cast<int16_t>(red - SAMPLES[i][0])) / static_cast<float>(red + SAMPLES[i][0]))
 +
                  + (abs(static_cast<int16_t>(green - SAMPLES[i][1])) / static_cast<float>(green + SAMPLES[i][1]))
 +
                  + (abs(static_cast<int16_t>(blue - SAMPLES[i][2])) / static_cast<float>(blue + SAMPLES[i][2]));
 +
#endif
 +
        if (expDist < minDist) {
 +
            bestSampleIndex = i;
 +
            minDist        = expDist;
 +
        }
 +
    }
 +
 
 +
    // Arbitrary threshold to avoid erroneous identifications
 +
#ifdef MANHATTAN
 +
    if (minDist > 100) {
 +
#else
 +
    if (minDist > 1.9) { // Red color is quite difficult to identify even with this high threashold
 +
#endif
 +
        // Matching is not acceptable
 +
        return COLOR_NONE;
 +
    }
 +
    // Get color value expected by the hub
 +
    return SAMPLES_MAP[bestSampleIndex];
 +
}
 +
 
 +
 
 +
#endif
 +
 
 +
</pre>
 +
Color_sensor.ino
 +
<pre>
 +
 
 +
/* This file is taken from MyOwnBricks project.
 +
* MyOwnBricks is a library for the emulation of LEGO PoweredUp sensors on microcontrollers
 +
* Copyright (C) 2021-2022 Ysard - <ysard@users.noreply.github.com>
 +
*
 +
* This program is free software: you can redistribute it and/or modify
 +
* it under the terms of the GNU General Public License as published by
 +
* the Free Software Foundation, either version 3 of the License, or
 +
* (at your option) any later version.
 +
*
 +
* This program is distributed in the hope that it will be useful,
 +
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 +
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +
* GNU General Public License for more details.
 +
*
 +
* You should have received a copy of the GNU General Public License
 +
* along with this program.  If not, see <https://www.gnu.org/licenses/>.
 +
*/
 +
 
 +
/*
 +
*  Sensor  Pro Micro
 +
*  SCL      SCL pin 3
 +
*  SDA      SDA pin 2
 +
*  INT      PCINT4, port PB4, pin 8
 +
*  VIN      VCC (3.3V)
 +
*  GND      GND
 +
*
 +
*  LED pin of the sensor can be connected to its INT pin.
 +
*  By doing this the leds will turn off when the measurements are done.
 +
*
 +
*  Pro Micro:
 +
*  Serial: UART via USB
 +
*  Serial1: pin 1 (TX), pin 0 (RX)
 +
*/
 +
#include <Wire.h>
 +
#include <tcs34725.h>
 +
 
 +
#define MANHATTAN
 +
#include "color_detection_methods.hpp"
 +
 
 +
 
 +
#define RGB_SENSOR_INTERRUPT_PIN    8
 +
#define RGB_SENSOR_INTERRUPT_PORT    PB4 // Port alias of pin 8 to be used in tstPin()
 +
// Equivalent of digitalRead but for PORTB pins & much more quicker for a use in an ISR
 +
// https://www.arduino.cc/en/Reference/PortManipulation
 +
#define tstPin(b)                            ((PINB & (1 << (b))) != 0)
 +
#define LUX_TO_PERCENTAGE(val)                (getPercentage(val, 0.0105, -0.0843))
 +
#define REFLECTED_LIGHT_TO_PERCENTAGE(val)    (getPercentage(val, 0.0017, -8))
 +
 
 +
uint8_t      sensorColor;
 +
uint8_t      reflectedLight;
 +
uint8_t      ambientLight;
 +
uint16_t      red, green, blue, clear, lux;
 +
volatile bool sensorReady;
 +
 
 +
// Default settings: TCS34725_GAIN_4X,  TCS34725_INTEGRATIONTIME_154MS
 +
TCS34725      rgb_sensor;
 +
 
 +
/**
 +
* @brief Callback for PCINT4 interrupt (PCINT0 - PCINT7)
 +
*/
 +
ISR(PCINT0_vect) {
 +
    // If RGB_SENSOR_INTERRUPT_PORT is LOW, sensor is ready
 +
    if (!tstPin(RGB_SENSOR_INTERRUPT_PORT))
 +
        sensorReady = true;
 +
}
 +
 
 +
 
 +
/**
 +
* @brief Map lux/reflected light values to percentages
 +
*    Weights of the equation must be calculated empirically
 +
*    Map equation: y = ax + b
 +
*    System to solve:
 +
*      100% = MaxRawValue * a + b
 +
*      0% = MinRawValue * a + b
 +
*
 +
*    See macros LUX_TO_PERCENTAGE and REFLECTED_LIGHT_TO_PERCENTAGE.
 +
*/
 +
uint8_t getPercentage(const uint16_t rawValue, const float& a_coef, const float& b_coef) {
 +
    int8_t percent = static_cast<int8_t>(rawValue * a_coef + b_coef);
 +
    if (percent > 100)
 +
        return 100;
 +
    if (percent < 0)
 +
        return 0;
 +
    return static_cast<uint8_t>(percent);
 +
}
 +
 
 +
 
 +
void setup() {
 +
    Serial.begin(115200);
 +
    while (!Serial) {
 +
        // Wait for serial port to connect.
 +
    }
 +
 
 +
    // Device config
 +
    sensorColor = COLOR_NONE;
 +
 
 +
    // Colour sensor config
 +
    // Configure PinChange Interrupt
 +
    // See https://github.com/NicoHood/PinChangeInterrupt
 +
    // Note: INT-0,1,2,3 are occupied by UART and i2c transmissions on pro-micro
 +
    // /!\ DO NOT activate pullup from the arduino, the INT pin is usually already
 +
    // pulled up into the sensor board itself to 3.3V. These pins (SCL, SDA, INT)
 +
    // ARE NOT tolerant to more than VDD + 0.5V. Note that I2C pins are connected
 +
    // to level shifters, but not the others.
 +
    pinMode(RGB_SENSOR_INTERRUPT_PIN, INPUT); // TCS interrupt output is Active-LOW and Open-Drain
 +
    cli();                                    // Disable all interrupts: Avoid first and not wanted trigger of the interrupt
 +
    PCICR  |= 0b00000001;                    // enable PORTB pin change interrupt
 +
    PCMSK0 |= 0b00010000;                    // enable PB4, PCINT4, pin 8
 +
    sei();                                    // Enable all interrupts
 +
 
 +
    while (!rgb_sensor.begin()) {
 +
        Serial.println(F("TCS34725 NOT found"));
 +
        delay(200);
 +
    }
 +
    Serial.println(F("Found sensor"));
 +
 
 +
    // Set persistence filter to generate an interrupt for every RGB Cycle,
 +
    // regardless of the integration limits
 +
    rgb_sensor.tcs.write8(TCS34725_PERS, TCS34725_PERS_NONE);
 +
    // RGBC interrupt enable. When asserted, permits RGBC interrupts to be generated.
 +
    rgb_sensor.tcs.setInterrupt(true);
 +
}
 +
 
 +
 
 +
void loop()
 +
{
 +
    if (sensorReady) {
 +
        // Data measurement
 +
        // noDelay param set to true: Asynchronous mode, must be used with interrupt configured.
 +
        bool status = rgb_sensor.updateData(true);
 +
 
 +
        if (status) {
 +
            // Ambient light (lux) computation
 +
            rgb_sensor.updateLux();
 +
 
 +
            int16_t lux = lround(rgb_sensor.lux);
 +
 
 +
            // Sometimes lux values are below 0; this coincides with erroneous data
 +
            // Moreover, we discard data taken below 40 lux.
 +
            if ((lux >= 40) && (static_cast<uint16_t>(lux) <= rgb_sensor.maxlux)) {
 +
                // Set ambient light (lux) - map 0-100
 +
                //ambientLight = map(rgb_sensor.lux, 0, rgb_sensor.maxlux, 0, 100);
 +
                ambientLight = LUX_TO_PERCENTAGE(lux); // cast ?
 +
 
 +
                // RGBC Channels are usable
 +
                // Map values to max ~440;
 +
                // Continuous values from 0-65535 (16bits) to 0-1023 (10bits)
 +
                red  = rgb_sensor.r_comp >> 6,
 +
                green = rgb_sensor.g_comp >> 6,
 +
                blue  = rgb_sensor.b_comp >> 6,
 +
 
 +
                // Set clear channel as reflected light - map 0-100
 +
                reflectedLight = REFLECTED_LIGHT_TO_PERCENTAGE(rgb_sensor.c_comp);
 +
 
 +
                // Set detected color
 +
                sensorColor = detectColor(red, green, blue);
 +
            } else {
 +
                sensorColor = COLOR_NONE;
 +
            }
 +
            clear = rgb_sensor.c_comp >> 6;
 +
            /*
 +
            // Human readable debugging
 +
            Serial.print("Lux: "); Serial.print(rgb_sensor.lux, DEC);
 +
            Serial.print("; max: "); Serial.print(rgb_sensor.maxlux);
 +
            Serial.print("; R: "); Serial.print(red, DEC);
 +
            Serial.print("; G: "); Serial.print(green, DEC);
 +
            Serial.print("; B: "); Serial.print(blue, DEC);
 +
            Serial.print("; C: "); Serial.println(clear, DEC);
 +
            */
 +
 
 +
            // Spreadsheet debugging
 +
            Serial.print(rgb_sensor.lux, DEC); Serial.print(";");
 +
            Serial.print(rgb_sensor.maxlux); Serial.print(";");
 +
            Serial.print(red, DEC); Serial.print(";");
 +
            Serial.print(green, DEC); Serial.print(";");
 +
            Serial.print(blue, DEC); Serial.print(";");
 +
            Serial.println(clear, DEC);
 +
        } else {
 +
            sensorColor = COLOR_NONE;
 +
            Serial.println(F("not valid data! wait next measure"));
 +
        }
 +
        // Interrupt tear down
 +
        rgb_sensor.tcs.clearInterrupt();
 +
        sensorReady = false;
 +
        PCIFR      &= ~(1 << PCIF0); // clear PC interrupt flag in case of bounce
 +
    }
 +
}
 +
 
 +
 
 
</pre>
 
</pre>
  
Ligne 26 : Ligne 787 :
  
 
[[Catégorie:Enib2023]]
 
[[Catégorie:Enib2023]]
 +
 +
[[Catégorie:Arduino]]

Version actuelle datée du 15 janvier 2024 à 16:00

Les petits voyageurs:

Fini1.jpeg

Description courte

Résoudre une énigme faisant deviner un pays.

Déplacer le capteur de couleur dans le labyrinthe pour faire une suite de couleur correspondant au drapeau du pays.

Matériels et machines utilisés

  • plaque de bois de 30cm x 30cm
  • 2 boutons poussoirs
  • 1 capteur RGB TCS3200
  • carte Arduino
  • cartons ( pour créer le prototype)
  • câbles Dupont
  • plaque de Cork de 30cm x 30cm
  • colle à bois
  • peintures et pinceaux
  • cutter
  • pic à broque
  • scotch


  • découpeuse laser
  • poste à souder

Réalisation

Etape 1: Souder les composants si nécessaires.

Etape 2: Créer les énigmes. Ci dessous la liste de nos énigmes Fichier:Liste des énigmes.docx

Etape 3: Ecrire le code. (cf code ci dessous)

Etape 4: Etablir un plan du labyrinthe.

Petits voyageurs 1.jpg

Etape 5: Faire un prototype du labyrinthe en carton.

Petit voyageurs2.jpg

Etape 6: tracer le labyrinthe sur la plaque de bois.

Petit voyageurs3.jpg

Etape 7: Sur inskape, creer un fichier avec toutes les murs du labyrinthe qui doivent être découpés / graver.

téléchargez le svg


Etape 8: Découper et graver les murs du labyrinthe à la découpe laser.

Murs.jpeg

Etape 9: Peindre certaines cases du labyrinthe en fonction des couleurs nécessaires.

Astuce : Mettre du scotch pour avoir des bords lisses

Peinture.jpeg —> Peinture2.jpeg


Etape 10: A l'aide de la colle à bois, coller les murs du labyrinthe.

Colle1.jpeg —> Colle2.jpeg


Etape 11: Creer une petite protection pour le capteur de couleur afin de pouvoir le déplacer dans le labyrinthe.

Protection.jpeg

Etape 12: Rajouter les différents éléments ( carte arduino, capteurs, boutons poussoirs).

600px


Code

prog.cpp:


#include "color.hpp"
#include "enigme.hpp"
#include <iostream>
#include <random>
#include <vector>


int main()
{
	//variable initiale
	int erreur=-1;
	int test=1;
	int bonneReponse=0;

	//liste des couleurs disponible pour les drapeaux 
	deb::Color rouge{1024, 0, 0};
	deb::Color bleu{0, 0, 1024};
	deb::Color blanc{1024, 1024, 1024};
	deb::Color noir{0, 0, 0};
	deb::Color vert{0, 1024 ,0};
	deb::Color orange{0, 0, 1024};
	deb::Color jaune{0, 0, 1024};

	//liste des enigmes 
	deb::Enigme ea{bleu, blanc, rouge, "Pays du champagne"};
	deb::Enigme eb{vert, blanc, rouge, "Pays des pâtes"};
	deb::Enigme ec{vert, blanc, orange, "Pays des moutons "};
	deb::Enigme ed{rouge, blanc, rouge, "Pays d’origine de Marie Antoinette"};
	deb::Enigme ee{noir, rouge, jaune, "Pays d’origine des knödels "};
	deb::Enigme ef{jaune, vert, rouge, "Quel est ce pays ? Mjubojf"};
	deb::Enigme eg{rouge, blanc, bleu, "Quel est ce pays ? .-.. ..- -..- . -- -... --- ..- .-. --."};
	deb::Enigme eh{rouge, blanc, bleu, "Quel est ce pays ? Ozxr-Azr"};
	deb::Enigme ei{noir, jaune, rouge, "Pays de la gaufre"};
	deb::Enigme ej{vert, jaune, bleu, "Mon premier est un mec. Mon second qualifie quelque chose d’agréable."};
	deb::Enigme ek{blanc, bleu, noir, "Quel est ce pays ? . ... - --- -. .. ."};
	deb::Enigme el{rouge, blanc, rouge, "Quel est ce pays ? 53886643"};
	deb::Enigme em{rouge, blanc, vert, "Mon premier est un pronom personnel indéfini. Mon second contient autant de rouge que de vert que de bleu."};
	deb::Enigme en{bleu, jaune, rouge, "Quel est ce pays ? Spvnbojf"};
	deb::Enigme eo{bleu, jaune, rouge, "Ma capitale est vieille "};
	deb::Enigme ep{bleu, jaune, rouge, "Quel est ce pays ? - -.-. .... .- -.."};
	deb::Enigme eq{rouge, bleu, orange, "Son papier sent bon "};
	deb::Enigme er{bleu, rouge, vert, "Quel est ce pays ? 2937224526"};
	deb::Enigme es{rouge, jaune, vert, "Ma capitale est La Paz"};
	deb::Enigme et{rouge, jaune, vert, "Mon premier est la plante sous laquelle il faut s’embrasser. Mon second est l’arrivée en ce monde."};
	deb::Enigme eu{blanc, vert, rouge, "Mon premier est une sphère d’une substance dans une autre. Mon second est un mec. Mon troisième peut être cantonais, thai ou basmati. "};
	deb::Enigme ev{jaune, bleu, rouge, "Ma capitale est Bogota"};
	deb::Enigme ew{orange, blanc, vert, "Quel est ce pays ? Dpuf e’Jwpjsf"};
	deb::Enigme ex{vert, jaune, rouge, "Quel est ce pays ? -- .- .-.. .."};
	deb::Enigme ey{vert, blanc, vert, "Quel est ce pays ? 6443742"};
	deb::Enigme ez{rouge, blanc, rouge, "Pays du Macchu Picchu"};
	deb::Enigme eea{blanc, bleu, rouge, "Pays du Kremlin"};
	deb::Enigme eeb{rouge, blanc, noir, "Quel est ce pays ? Xdldm"};
	std::vector<deb::Enigme> vectEnigme{ea,eb,ec,ed,ee,ef,eg,eh,ei,ej,ek,el,em,en,eo,ep,eq,er,es,et,eu,ev,ew,ex,ez,eea,eeb};

	//loop
	
	if (appui sur bouton acquisition)  //on enregistre la couleur actuelle
	{	
		int a,b,c = 10,10,1024; //on recupere les valeurs du capteur
		
		if (test==4) 
		{
			bonneReponse=0; //il y a trop de reponse le resultat sera faut
		}

		if (test==3)
		{
			if (enigmeEnCours.trois.isitme(a,b,c)) {bonneReponse=bonneReponse+1} //on compare a la couleur du drapeau
			test=4;
		}
		
		if (test==2)
		{
			if (enigmeEnCours.deux.isitme(a,b,c)) {bonneReponse=bonneReponse+1} //on compare a la couleur du drapeau
			test=3;
		}
		
		if (test==1)
		{
			if (enigmeEnCours.un.isitme(a,b,c)) {bonneReponse=bonneReponse+1} //on compare a la couleur du drapeau
			test=2;
		}
	}

		
	if (appui sur le bouton validé and erreur!=-1)//on regarde le resultat final
	{
		if (bonneReponse==3) 
		{
			std::cout <<"Victoire ! Si tu veux rejouer, clique sur JSP.\n";
			erreur =-1;
		}
		if (bonneReponse!=3 and erreur==0) 
		{
			std::cout <<"Tu as fait une erreur. Repars de zéro et essaye encore. \n";
			erreur =1;
		}
		if (bonneReponse!=3 and erreur==1) 
		{
			std::cout <<"Tu as perdu. Si tu veux rejouer, clique sur JSP.\n";
			erreur =-1;
		}
	}


	if (appui sur bouton validé and erreur==-1) //lancement nouvelle enigme
	{	
		srand((unsigned) time(NULL));
		deb::Enigme enigmeEnCours=vectEnigme[rand() % 28];
		std::cout << enigmeEnCours.question << "\n";
		erreur=0;
		test=1;
		bonneReponse=0;
	}
}


color.cpp:



//----------------------------------------------------------------------------

#include "color.hpp"

namespace deb 
{
	bool Color::isitme(int r,int g,int b) const
	{
		if (r<(red-200)) {return false;}
		if (r>(red+200)) {return false;}
		if (g<(green-200)) {return false;}
		if (g>(green+200)) {return false;}
		if (b<(blue-200)) {return false;}
		if (b>(blue+200)) {return false;}	
		return true;

	}


}// namespace deb

//----------------------------------------------------------------------------

color.hpp:


//----------------------------------------------------------------------------

#ifndef DEB_COLOR_HPP
#define DEB_COLOR_HPP

#include <iostream>

namespace deb {

struct Color
  {
    int red,green,blue;

    Color(int red, int green, int blue): red{std::move(red)}, green{std::move(green)}, blue{std::move(blue)}
    {/* nothing to do */}

    bool isitme(int r,int g,int b) const;
  };



} // namespace deb

#endif // DEB_COLOR_HPP

//----------------------------------------------------------------------------



enigme.hpp



//----------------------------------------------------------------------------

#ifndef DEB_ENIGME_HPP
#define DEB_ENIGME_HPP

#include <iostream>
#include <string>
#include "color.hpp"

namespace deb {

struct Enigme
  {
    Color un,deux,trois;
    std::string question;

    Enigme(Color u, Color d, Color t, std::string q): un{std::move(u)}, deux{std::move(d)}, trois{std::move(t)}, question{std::move(q)}
    {/* nothing to do */}

  };



} // namespace deb

#endif // DEB_ENIGME_HPP

//----------------------------------------------------------------------------


code BP :

Les_petits_voyageurs.ino


#include "Test_BP.h"
#include "Arduino.h"
int lancement=0;

void setup()
{
  Serial.begin(115200);
  setup_BP();
  //constantes générées aussi en dehors de la loop
}


void loop()
{
  lancement=BP(lancement);
  if (lancement==1)
  {
    delay(20);
    Serial.println("Bonjour ! ");
  }
}

Test_BP.cpp

#include "Test_BP.h"

//BP1
const int BP1=4;

int boutonState = 0;
int lastBoutonState = 0;

void setup_BP()
{
  //setup fonction bouton
  pinMode(BP1, INPUT);
}

int BP(int lancement) //permet de détecter les FM/FD du BP
{
  /*
  Serial.print("etat bouton : ");
  Serial.println(boutonState);
  Serial.print("etat bouton precedent : ");
  Serial.println(lastBoutonState);
  */

  boutonState=digitalRead(BP1);
  Serial.println(boutonState);
  if (boutonState==HIGH)
  {
    if (boutonState != lastBoutonState)
    {
      lancement=1;
      //Serial.println("00");
      lastBoutonState=boutonState;
    }
    else
    {
      lancement=0; //état récurrent de lancement, on reste appuyé sur BP
      //Serial.println("10");
    }
  }
  else
  {
    if (boutonState != lastBoutonState)
    {
      //Serial.println("01");
      lancement=0;
      lastBoutonState=boutonState;
    }
    else
    {
      //Serial.println("11");
    }
  }
  //Serial.println(lancement);

  return lancement;
}


#ifndef TEST_BP_H
#define TEST_BP_H

#include <Arduino.h>


void setup_BP();
int BP(int lancement);

#endif

code capteur:

color_detection_methods.hpp

/* This file is taken from MyOwnBricks project.
 * MyOwnBricks is a library for the emulation of LEGO PoweredUp sensors on microcontrollers
 * Copyright (C) 2021-2022 Ysard - <ysard@users.noreply.github.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

/**
 * @brief Discretize colors and return uint8_t color code.
 *    Available colors: COLOR_NONE, COLOR_BLACK, COLOR_BLUE,
 *    COLOR_GREEN, COLOR_RED, COLOR_WHITE.
 *
 *    Generally speaking, stable measuring conditions are required, i.e.,
 *    a stable measuring distance not exceeding 4 cm, no interfering light
 *    reaching the side of the sensor. Think about matt black sensor shroud.
 *
 *    Metrics:
 *      - BASIC_RGB: Simple comparison between channels;
 *          Very fast but is likely to produce errors.
 *      - MANHATTAN: Sum of absolute values of distances.
 *          Quite heavy, but quite accurate if the reference values have been
 *          measured seriously and if the measurement environment is controlled
 *          (reproducible). Distance between the sensor and the object should be
 *          the same as during learning.
 *          https://fr.wikipedia.org/wiki/Distance_de_Manhattan
 *     - CANBERRA: A weighted version of Manhattan distance;
 *          Very heavy but brings a higher accuracy and more tolerance/stability to variations
 *          in the measurement environment.
 *          Note: The manipulation of decimal numbers should be avoided
 *          on microcontrollers... Does it worth it? Probably not.
 *          https://en.wikipedia.org/wiki/Canberra_distance
 */
//#define BASIC_RGB
//#define MANHATTAN
//#define CANBERRA

// Colors (detected & LED (except NONE for this last one)) expected values
#define COLOR_NONE      0xFF
#define COLOR_BLACK     0
#define COLOR_PINK      1
#define COLOR_PURPLE    2
#define COLOR_BLUE      3
#define COLOR_LIGHTBLUE 4
#define COLOR_CYAN      5
#define COLOR_GREEN     6
#define COLOR_YELLOW    7
#define COLOR_ORANGE    8
#define COLOR_RED       9
#define COLOR_WHITE     10

extern uint16_t red, green, blue;


#ifdef BASIC_RGB
uint8_t detectColor(const uint16_t &red, const uint16_t &green, const uint16_t &blue) {
    if ((red > green) && (red > blue)) {
        return COLOR_RED;
    } else if ((green > red) && (green > blue)) {
        return COLOR_GREEN;
    } else if ((blue > red) && (blue > green)) {
        return COLOR_BLUE;
    }
}
#endif


#if (defined(MANHATTAN) || defined(CANBERRA))
// *_1: measures at 1 cm
// *_3: measures at 3 cms
const uint16_t SAMPLES[][3] = {
    { 297,  83,  56 }, // RED_1
    {  43,  20,  17 }, // RED_3
    {  35, 142, 193 }, // BLUE_1
    {  35,  94, 116 }, // BLUE_3
    {  86, 257, 257 }, // CYAN_1
    {  36,  98,  97 }, // CYAN_3
    { 120, 141,  46 }, // YELLOW_1
    {  72,  73,  30 }, // YELLOW_3
    { 338, 373, 120 }, // YELLOW_PLQ_1
    { 159, 267, 201 }, // WHITE_1
    {  87, 126, 102 }, // WHITE_3
    {  89, 322, 163 }, // GREEN_1
    {  58, 106,  68 }, // GREEN_3
    { 103, 189,  57 }, // GREEN_LIGHT_1
    {  51,  77,  33 }, // GREEN_LIGHT_3
    {  26,  34,  28 }  // BLACK_1
};

const uint8_t SAMPLES_MAP[] = {
    COLOR_RED,    COLOR_RED,
    COLOR_BLUE,   COLOR_BLUE,
    COLOR_BLUE,   COLOR_BLUE,
    COLOR_YELLOW, COLOR_YELLOW,COLOR_YELLOW,
    COLOR_WHITE,  COLOR_WHITE,
    COLOR_GREEN,  COLOR_GREEN,
    COLOR_GREEN,  COLOR_GREEN,
    COLOR_BLACK
};

// Number of samples
const uint8_t samplesCount = sizeof(SAMPLES) / sizeof(SAMPLES[0]);

uint8_t detectColor(const uint16_t &red, const uint16_t &green, const uint16_t &blue) {
#ifdef MANHATTAN
    uint16_t minDist = 10000;
    uint16_t expDist;
#else
    float minDist = 3;
    float expDist;
#endif
    uint8_t bestSampleIndex = 0;

    for (uint8_t i = 0; i < samplesCount; i++) {
#ifdef MANHATTAN
        expDist = abs(static_cast<int16_t>(red - SAMPLES[i][0]))
                  + abs(static_cast<int16_t>(green - SAMPLES[i][1]))
                  + abs(static_cast<int16_t>(blue - SAMPLES[i][2]));
#else
        // Yeah it's ugly but abs() of Arduino is a macro different from the stl implementation
        // moreover the parameter must be explicitly signed.
        // The numerator or denominator must be a float.
        // https://www.best-microcontroller-projects.com/arduino-absolute-value.html
        // https://github.com/arduino/reference-en/issues/362
        expDist = (abs(static_cast<int16_t>(red - SAMPLES[i][0])) / static_cast<float>(red + SAMPLES[i][0]))
                  + (abs(static_cast<int16_t>(green - SAMPLES[i][1])) / static_cast<float>(green + SAMPLES[i][1]))
                  + (abs(static_cast<int16_t>(blue - SAMPLES[i][2])) / static_cast<float>(blue + SAMPLES[i][2]));
#endif
        if (expDist < minDist) {
            bestSampleIndex = i;
            minDist         = expDist;
        }
    }

    // Arbitrary threshold to avoid erroneous identifications
#ifdef MANHATTAN
    if (minDist > 100) {
#else
    if (minDist > 1.9) { // Red color is quite difficult to identify even with this high threashold
#endif
        // Matching is not acceptable
        return COLOR_NONE;
    }
    // Get color value expected by the hub
    return SAMPLES_MAP[bestSampleIndex];
}


#endif

Color_sensor.ino


/* This file is taken from MyOwnBricks project.
 * MyOwnBricks is a library for the emulation of LEGO PoweredUp sensors on microcontrollers
 * Copyright (C) 2021-2022 Ysard - <ysard@users.noreply.github.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

/*
 *   Sensor   Pro Micro
 *   SCL      SCL pin 3
 *   SDA      SDA pin 2
 *   INT      PCINT4, port PB4, pin 8
 *   VIN      VCC (3.3V)
 *   GND      GND
 *
 *   LED pin of the sensor can be connected to its INT pin.
 *   By doing this the leds will turn off when the measurements are done.
 *
 *   Pro Micro:
 *   Serial: UART via USB
 *   Serial1: pin 1 (TX), pin 0 (RX)
 */
#include <Wire.h>
#include <tcs34725.h>

#define MANHATTAN
#include "color_detection_methods.hpp"


#define RGB_SENSOR_INTERRUPT_PIN     8
#define RGB_SENSOR_INTERRUPT_PORT    PB4 // Port alias of pin 8 to be used in tstPin()
// Equivalent of digitalRead but for PORTB pins & much more quicker for a use in an ISR
// https://www.arduino.cc/en/Reference/PortManipulation
#define tstPin(b)                             ((PINB & (1 << (b))) != 0)
#define LUX_TO_PERCENTAGE(val)                (getPercentage(val, 0.0105, -0.0843))
#define REFLECTED_LIGHT_TO_PERCENTAGE(val)    (getPercentage(val, 0.0017, -8))

uint8_t       sensorColor;
uint8_t       reflectedLight;
uint8_t       ambientLight;
uint16_t      red, green, blue, clear, lux;
volatile bool sensorReady;

// Default settings: TCS34725_GAIN_4X,  TCS34725_INTEGRATIONTIME_154MS
TCS34725      rgb_sensor;

/**
 * @brief Callback for PCINT4 interrupt (PCINT0 - PCINT7)
 */
ISR(PCINT0_vect) {
    // If RGB_SENSOR_INTERRUPT_PORT is LOW, sensor is ready
    if (!tstPin(RGB_SENSOR_INTERRUPT_PORT))
        sensorReady = true;
}


/**
 * @brief Map lux/reflected light values to percentages
 *    Weights of the equation must be calculated empirically
 *    Map equation: y = ax + b
 *    System to solve:
 *      100% = MaxRawValue * a + b
 *      0% = MinRawValue * a + b
 *
 *    See macros LUX_TO_PERCENTAGE and REFLECTED_LIGHT_TO_PERCENTAGE.
 */
uint8_t getPercentage(const uint16_t rawValue, const float& a_coef, const float& b_coef) {
    int8_t percent = static_cast<int8_t>(rawValue * a_coef + b_coef);
    if (percent > 100)
        return 100;
    if (percent < 0)
        return 0;
    return static_cast<uint8_t>(percent);
}


void setup() {
    Serial.begin(115200);
    while (!Serial) {
        // Wait for serial port to connect.
    }

    // Device config
    sensorColor = COLOR_NONE;

    // Colour sensor config
    // Configure PinChange Interrupt
    // See https://github.com/NicoHood/PinChangeInterrupt
    // Note: INT-0,1,2,3 are occupied by UART and i2c transmissions on pro-micro
    // /!\ DO NOT activate pullup from the arduino, the INT pin is usually already
    // pulled up into the sensor board itself to 3.3V. These pins (SCL, SDA, INT)
    // ARE NOT tolerant to more than VDD + 0.5V. Note that I2C pins are connected
    // to level shifters, but not the others.
    pinMode(RGB_SENSOR_INTERRUPT_PIN, INPUT); // TCS interrupt output is Active-LOW and Open-Drain
    cli();                                    // Disable all interrupts: Avoid first and not wanted trigger of the interrupt
    PCICR  |= 0b00000001;                     // enable PORTB pin change interrupt
    PCMSK0 |= 0b00010000;                     // enable PB4, PCINT4, pin 8
    sei();                                    // Enable all interrupts

    while (!rgb_sensor.begin()) {
        Serial.println(F("TCS34725 NOT found"));
        delay(200);
    }
    Serial.println(F("Found sensor"));

    // Set persistence filter to generate an interrupt for every RGB Cycle,
    // regardless of the integration limits
    rgb_sensor.tcs.write8(TCS34725_PERS, TCS34725_PERS_NONE);
    // RGBC interrupt enable. When asserted, permits RGBC interrupts to be generated.
    rgb_sensor.tcs.setInterrupt(true);
}


void loop()
{
    if (sensorReady) {
        // Data measurement
        // noDelay param set to true: Asynchronous mode, must be used with interrupt configured.
        bool status = rgb_sensor.updateData(true);

        if (status) {
            // Ambient light (lux) computation
            rgb_sensor.updateLux();

            int16_t lux = lround(rgb_sensor.lux);

            // Sometimes lux values are below 0; this coincides with erroneous data
            // Moreover, we discard data taken below 40 lux.
            if ((lux >= 40) && (static_cast<uint16_t>(lux) <= rgb_sensor.maxlux)) {
                // Set ambient light (lux) - map 0-100
                //ambientLight = map(rgb_sensor.lux, 0, rgb_sensor.maxlux, 0, 100);
                ambientLight = LUX_TO_PERCENTAGE(lux); // cast ?

                // RGBC Channels are usable
                // Map values to max ~440;
                // Continuous values from 0-65535 (16bits) to 0-1023 (10bits)
                red   = rgb_sensor.r_comp >> 6,
                green = rgb_sensor.g_comp >> 6,
                blue  = rgb_sensor.b_comp >> 6,

                // Set clear channel as reflected light - map 0-100
                reflectedLight = REFLECTED_LIGHT_TO_PERCENTAGE(rgb_sensor.c_comp);

                // Set detected color
                sensorColor = detectColor(red, green, blue);
            } else {
                sensorColor = COLOR_NONE;
            }
            clear = rgb_sensor.c_comp >> 6;
            /*
            // Human readable debugging
            Serial.print("Lux: "); Serial.print(rgb_sensor.lux, DEC);
            Serial.print("; max: "); Serial.print(rgb_sensor.maxlux);
            Serial.print("; R: "); Serial.print(red, DEC);
            Serial.print("; G: "); Serial.print(green, DEC);
            Serial.print("; B: "); Serial.print(blue, DEC);
            Serial.print("; C: "); Serial.println(clear, DEC);
            */

            // Spreadsheet debugging
            Serial.print(rgb_sensor.lux, DEC); Serial.print(";");
            Serial.print(rgb_sensor.maxlux); Serial.print(";");
            Serial.print(red, DEC); Serial.print(";");
            Serial.print(green, DEC); Serial.print(";");
            Serial.print(blue, DEC); Serial.print(";");
            Serial.println(clear, DEC);
        } else {
            sensorColor = COLOR_NONE;
            Serial.println(F("not valid data! wait next measure"));
        }
        // Interrupt tear down
        rgb_sensor.tcs.clearInterrupt();
        sensorReady = false;
        PCIFR      &= ~(1 << PCIF0); // clear PC interrupt flag in case of bounce
    }
}


Catégories