Chronomètre d’escalade

Thème 2023 : l’ingénierie au service du sport

 

 

 

 

 

 

 

Mission du système

Lors d’une épreuve d’escalade chronométrée, il est nécessaire que le chronomètre soit démarré et arrêté à temps, et avec la même précision pour tous les grimpeurs successifs de la voie.

Un chronomètre d’escalade est constitué de deux parties pour contrôler le chronométrage :

  • une au sol pour déclencher le chronomètre lorsque le grimpeur commence l’épreuve,
  • une en haut du mur pour arrêter le chronomètre à la fin de l’épreuve

Un afficheur numérique affiche le temps écoulé.

Font made from oNline Web Fontsis licensed by CC BY 3.0

 

Cahier des charges

Il existe déjà de nombreux chronomètres pour l’escalade mais la plupart n’est pas portable et encore moins autonome en énergie. De plus, ils sont très chers !

L’objectif du projet est de mettre en œuvre un chronomètre à la portée de tous, utilisant des composants simples et faciles à se procurer … et bon marché ! Il est important qu’il soit transportable facilement (léger) et autonome en énergie (au moins 8h).

Il doit être très simple d’utilisation et doit permettre à un grimpeur seul de connaitre son temps un fois redescendu.

 

Contraintes de conception

Le système se compose de deux boitiers seulement (un en haut et un en bas de la voie), chacun alimenté par une batterie rechargeable Li-ion.

Les deux systèmes comportent chacun un microcontrôleur et communiquent par ondes radio.

Composants utilisés

Microcontrôleur

Arduino

Stockage

Batterie lithium-ion
type 18560

Alimentation

Régulateur de charge
type 134N3P

Communication

Module transmetteur sans fil
nRF24L01+

Documentation
Autre ressource
exemple sur arduino.blaisepascal.fr

Affichage

Afficheur 7 segments
DFRobot DFR0645-G

Documentation

Acquisition

Microrupteur

Ressource : le bouton poussoir

 

Boitier et pièces diverses

Les deux boitiers sont préconçus avec un modeleur volumique (Onshape)

Document Onshape Document OnshapeModèle volumique

Aperçu du contacteur-afficheur_BAS

 

Aperçu du contacteur_HAUT

 

 

Programmation

Les microcontrôleurs seront programmés en langage Arduino. On distinguera 3 principales parties, d’abord traitées séparément, puis réunies en 2 programmes pour chacun des boitiers.

Utiliser un afficheur 7 segment 4 digits

Utiliser la page du wiki DFRobot dédiée à l’afficheur choisi :

 

Faire un chronomètre

Voici un exemple de programme qui permet de créer un chronomètre géré avec 2 boutons poussoirs. Il utilise les interruptions.

 

 

const int boutonStart = 2; // ports 2 et 3 obligatoires pour interruptions
const int boutonStop = 3;  // sur Arduino UNO

volatile unsigned long time0; // instant initial (début du chrono en ms)
volatile bool running = false;  // état du chrono
volatile unsigned long chrono = 0;  // valeur du chrono (en ms)

void setup() {
  pinMode(boutonStart, INPUT);
  pinMode(boutonStop, INPUT);
  
  Serial.begin(9600);
  
  // les ISR (fonctions) exécutées quand on agit sur les boutons
  attachInterrupt(digitalPinToInterrupt(boutonStart), start, CHANGE);
  attachInterrupt(digitalPinToInterrupt(boutonStop), stop, CHANGE);
}

void loop() {
  
  if (running) {
  	// Actualisation du chrono (uniquement si démarré)
  	chrono = millis()-time0;
  }
  // Affichage du chrono
  Serial.print(float(chrono)/1000);
  Serial.println(" s");
  
  delay(100) ; // affichage tous les 1/10 secondes
}

void start() {
  if (digitalRead(boutonStart) == HIGH) {
    // le bouton start vient d'être appuyé : remise à zéro
    chrono = 0;
    running = false;
  } else { 
    // le bouton start vient d'être relâché : démarrage chrono
    running = true;
    time0 = millis();
    Serial.println("############### START"); 
  }
  
  
}

void stop() {
  if (digitalRead(boutonStop) == HIGH) {
    // le bouton stop vient d'être appuyé : arrêt chrono
    running = false;
    Serial.println("STOP ###############");
  } else { 
    // le bouton stop vient d'être relâché : ???
    
  }
}

Faire une communication sans fil simplex

Suivre les exemples proposés sur arduino.blaisepascal.fr :

Transmetteur sans fil nRF24L01+

 

 

Feuille de route

Voici les différentes tâches à répartir au sein des équipes :

  1. Réaliser un diagramme (draw.io) représentant le cahier des charges de ce système sous forme d’un diagramme des exigences,
  2. Réaliser un diagramme (draw.io) représentant les chaînes fonctionnelles de ce système,
  3. Mettre en œuvre l’afficheur 7 segments,
  4. Mettre en œuvre une communication sans fil entre deux Arduinos,
  5. Mettre en œuvre un chronomètre avec démarrage/arrêt par deux microrupteurs,
  6. Compléter la maquette volumique en y incluant les composants et en concevant les pièces nécessaires à leur intégration,
  7. Construire le système (impressions, montage, câblage, …),
  8. Tester !

 

 

Réalisation

Boitier BAS : découpe laser et collage

Boitier HAUT : impression 3D et assemblage

 

Programmation

Voici les programmes réalisés pour chacun des deux boitiers :

Programme du boitier du bas

chrono_bas

/*
Transmission d'un unique caractère (réception)
(Basé sur l'exemple Basic_RX)
*/

#include "SPI.h"
#include "NRFLite.h"
#include "DFRobot_LedDisplayModule.h"

const static uint8_t RADIO_ID = 0;       // Identifiant du récepteur
const static uint8_t PIN_RADIO_CE = 9;  
const static uint8_t PIN_RADIO_CSN = 10;

NRFLite _radio;
char message; // la variable contenant le caractère à recevoir
const char CODE_CHRONO = 'c';



const int boutonStart = 2; // ports 2 obligatoires pour interruptions

volatile unsigned long time0; // instant initial (début du chrono en ms)
volatile bool running = false;  // état du chrono
volatile unsigned long chrono = 0;  // valeur du chrono (en ms)
DFRobot_LedDisplayModule LED(&Wire, 0x48);

void setup()
{
  Serial.begin(115200);
  
  if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN))
  {
      Serial.println("Cannot communicate with radio");
      while (1);
  }

  while(LED.begin(LED.e4Bit) != 0)
  {
    Serial.println("Failed to initialize the chip , please confirm the chip connection!");
    delay(1000);
  }
LED.setDisplayArea(1,2,3,4);
  
  pinMode(boutonStart, INPUT_PULLUP);

  // ISR (fonction) exécutée quand on agit sur le bouton
  attachInterrupt(digitalPinToInterrupt(boutonStart), start, CHANGE);
}

void loop()
{
    while (_radio.hasData()) // Attente de réception d'un caractère
    {
        _radio.readData(&message);
        if (message == CODE_CHRONO) {
          stop();          
        }
    }
  
  if (running) {
     // Actualisation du chrono (uniquement si démarré)
     chrono = millis()-time0;
  }
  // Affichage du chrono
  //Serial.print(float(chrono)/1000);
  //Serial.println(" s");
  LED.print(float(chrono)/1000);
  
  delay(100) ; // affichage tous les 1/10 secondes
}

void start() {
  if (digitalRead(boutonStart) == LOW) {
    // le bouton start vient d'être appuyé : remise à zéro
    chrono = 0;
    running = false;
  } else { 
    // le bouton start vient d'être relâché : démarrage chrono
    running = true;
    time0 = millis();
    Serial.println("############### START"); 
  }
  
  
}

void stop() {
    running = false;
    Serial.println("STOP ###############");
}
Programme du boitier du haut

chrono_haut

/*
Transmission d'un unique caractère (envoi)
(Basé sur l'exemple Basic_TX)
*/

#include "SPI.h"
#include "NRFLite.h"

const static uint8_t RADIO_ID = 1;             // Identifiant de l'émetteur
const static uint8_t DESTINATION_RADIO_ID = 0; // Identifiant du récepteur
const static uint8_t PIN_RADIO_CE = 9;
const static uint8_t PIN_RADIO_CSN = 10;

const int boutonStop = 2; // ports 2 obligatoires pour interruptions

NRFLite _radio;
char CODE_CHRONO = 'c'; // variable contenant le caractère à envoyer

void setup()
{
  Serial.begin(115200);
  
  if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN))
  {
      Serial.println("Cannot communicate with radio");
      while (1);
  }
  
  pinMode(boutonStop, INPUT_PULLUP);

  // ISR (fonction) exécutée quand on agit sur le bouton
  attachInterrupt(digitalPinToInterrupt(boutonStop), stop, CHANGE);

}

void loop()
{
    delay(10);
}


void stop() {
  if (digitalRead(boutonStop) == LOW) {
    // le bouton stop vient d'être appuyé : arrêt chrono
    if (_radio.send(DESTINATION_RADIO_ID, &CODE_CHRONO, sizeof(CODE_CHRONO)))
    {
        Serial.println(" ...Succes");
    }
    else
    {
        Serial.println(" ...Echec");
    }
    Serial.println("STOP ###############");
  }
}

 

Résultat

En vidéo

Voici une vidéo réalisée par Antoine SEBBAN, élève de terminale au lycée Blaise Pascal dans la spécialité CAV (cinéma-audiovisuel).

Les scènes ont été filmées dans le gymnase de la cité scolaire, avec l’aide de Mme Seigneur, professeur d’EPS.

Mon projet en 180 secondes :

 

En images

Le jour de la finale académique

 

Instagram

Profil : Jerome_le_chronometre

Merci à nos artistes : 

  • @antoine_en_raw : Réalisateur et monteur de la vidéo, photographe 
  • @atomerouge : Graphiste (réalisation du logo et de l’aspect graphique) 

 

 

Améliorations possibles

  • Utiliser des microcontrôleurs plus légers et économiques (Arduino mini, nano, …)
  • Améliorer la conception des boitiers :
    • boutons de mise sous tensions noyés dans les boitiers pour éviter un allumage intempestif
  • Souder les connexions ou utiliser de meilleurs connecteurs pour plus de robustesse,

 

 

 

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *