Un tableau élastique?

Bonjour,
Je continue mon petit projet de potentiomètre avec un signal analogique.
Je voudrais faire ceci:

Une boucle {
Je tourne le potentiomètre
Si j'appuie sur le bouton rouge => Arduino enregistre la position dans un tableau en et incrémente i++

  • Si j'appuie sur le bouton jaune => On lance la fonction PLAY() }*
    PLAY()
    For (int i=0;i<n;i++) { //où n est la taille totale et finale de mon tableau
    Lire les positions stockées dans le tableau
    Placer le servo dans cette position
    }
    Créer un tableau, je vais y arriver, chercher dans le tableau des valeurs, ça va aller...
    Mon souci, c'est que je ne sais pas quelle taille devra faire mon tableau. Selon que j'enregistre 3 positions ou 17486, comment définir sa taille. L'idée serait de faire quelque chose du genre
    "à chaque écriture agrandir le tableau d'un emplacement"
    Je pense que vous m'avez compris. Je ne trouve rien de crédible sur le net, de plus, il semblerait que d'une version d'IDE à une autre, les tableaux ne fonctionneraient pas de la même manière exactement...

Je continue de fouiller le net, mais c'est très confus pour moi et plus je cherche, plus je lis de bêtises, et moins je comprends.
Merci aux volontaires ^^

C'est typiquement une définition de programme qui se prête bien à la programmation par machine à états et ici les états sont super simples puisqu'il n'y en a pas :slight_smile: (cf mon tuto éventuellement)

Pour vous simplifier la vie prenez pour le moment une librairie qui gère les boutons pour vous comme par exemple OneButton et attachez des fonctions qui font ce qu'il faut quand vous touchez les boutons

// La librairie de gestion des boutons
#include <OneButton.h> // https://github.com/mathertel/OneButton
const byte boutonRougePin = 6;
const byte boutonJaunePin = 7;
const byte potentionmetrePin = A0;

OneButton boutonRouge(boutonRougePin, true); // true pour le mettre en INPUT_PULLUP
OneButton boutonJaune(boutonJaunePin, true); // true pour le mettre en INPUT_PULLUP

const byte memoireMax = 100; // on peut avoir 100 valeurs au max
uint16_t valeurs[memoireMax]; // le tableau
byte positionMemoire = 0; // là prochaine case à remplir

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

void play()
{
  Serial.println(F("----------------------"));
  for (byte i = 0; i < positionMemoire; i++) {
    Serial.print(F("Valeurs["));
    Serial.print(i);
    Serial.print(F("] = "));
    Serial.println(valeurs[i]);
  }
  Serial.println();
}

// ------ LES CALLBACKS ------

// fonction appelée quand le bouton rouge est appuyé
void rouge()
{
  Serial.println(F("ROUGE!"));
  if (positionMemoire < memoireMax) valeurs[positionMemoire++] = analogRead(potentionmetrePin);
  else Serial.println(F("ERREUR: Tableau plein"));
}


// fonction appelée quand le bouton jaune est appuyé
void jaune()
{
  Serial.println(F("JAUNE!"));
  play();
}

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

void setup() {
  Serial.begin(115200);
  pinMode(potentionmetrePin, INPUT);

  boutonRouge.attachClick(rouge);   // On attache la fonction rouge() comme callBack en cas de simple click sur le bouton rouge

  boutonJaune.attachClick(jaune);   // On attache la fonction jaune() comme callBack en cas de simple click sur le bouton jaune
 
  Serial.println(F("C'EST PARTI !"));
}

void loop() {
  // On vérifie l'état des boutons, ce qui déclenche l'appel d'une des fonctions callBack si nécessaire
  boutonRouge.tick();
  boutonJaune.tick();

  // ici on peut faire autre chose si on veut du moment que ce n'est pas trop long
}

(code tapé ici, non testé)

Punaise, pépé, t'es une encyclo!

Alors j'ai deux solutions à mon problème:

Soit je crée un tableau de 100 entrées par exemple, et si vraiment ça déborde, j'en crée un de 200,

Soit j'opère par liste, et ça me semble souple et adapté à ma question.

Enfin, reste que, si un jour j'ai un énorme tableau ou une groooosse liste à stocker, je mets ça sur carte SD

Bon je me lance, je cherche un tuto et je fais un code qui marche.

Merci

Bonjour JML

Alors là je suis épaté ^^ prochaine fois je passe commande :slight_smile:

j'ai déjà vu passer cette bibliothèque, mais j'ai pas trop bien compris ce qu'elle apporte, preuve que je n'ai pas tout compris, cqfd.

Merci pour le code, je vais le déchiffrer, j'ai tapé un petit code qui marche avec les deux boutons, la loop() n'a que ça à faire, le reste, c'est des fonctions.

Bon bah j'ai du boulot

Merci pour le code, je vais le déchiffrer, j'ai tapé un petit code qui marche avec les deux boutons, la loop() n'a que ça à faire, le reste, c'est des fonctions.

c'est encore mieux de faire soi même ! n'hésitez pas à poster votre code on vous dira si vous êtes sur le bon chemin

(la librairie gère les rebonds des boutons et permet d'attacher des fonctions suivant les évènements genre click, double click etc)

Et utiliser l'EEPROM pour stocker le tableau, c'est faisable ? Elle fait 1 ko, c'est peut-être trop peu ?

Classiquement en C++, on utilise pour cela un objet vector, issu de la STL (Standard Template Library) du C++.
"Vectors are sequence containers representing arrays that can change in size."

En googlant un peu, je vois qu'il existe des implémentations de la STL pour Arduino.
https://www.arduinolibraries.info/libraries/arduino-stl

Je n'ai testé aucune de ces solutions, et j'ai conscience que de toutes façons la mémoire limitée de l'Arduino ne permet pas toutes les galipettes.
Mais bon, si cette fonction est déterminante pour ton projet et que tu as envie de tester un peu, fais nous connaître le résultat :slight_smile:

le second lien de mon précédent post ne marche pas, essayer:
https://www.arduinolibraries.info et chercher "STL"

mais ici son tableau n'a pas vraiment besoin de changer de taille.. comme l'a dit pepe sur un petit micro-contrôleur il vaut mieux dimensionner statiquement son tableau (sauf si l'usage est transitoire)

pour info, je viens de tester la biblio ArduinoSTL, elle est proposée dans la liste des biblios de l'IDE (1.8 )
le prog suivant marche correctement:

#include <ArduinoSTL.h>

std::vector<int> x;

void print_x ( )
{
  for ( int i=0; i<x.size(); i++ ) {
    Serial.print ( x[i] ); Serial.print ( " " );
  }
  Serial.println ();
}
// ------------------------------
void setup() {
  Serial.begin ( 115200);

  x.push_back ( 1 );
  print_x ();
  x.push_back ( 2 );
  print_x ();
  x.push_back ( 3 );
  print_x ();

}
// -------------------------------
void loop() {}

C'est chouette! Merci
J'étudie ça avant de dormir ^^

Bon pour être franc, mon code fonctionne, maintenant.
Je peux bien tourner mon servo, je peux enregistrer des positions.
La lecture est carrément foireuse, c'est clair, ça ne marche pas super bien ^^
Je dois convertir les positions enregistrées sur A0 en signal pour commander mon servo en digital.

Hier avec lesept, nous avions trouvé l'équation. J'ai refait les calculs, j'ai trouvé pareil.

DEUX PROBLEMES:
-l'équation ne semble pas marcher écrite comme ça, ne m'en veuillez pas, j'ai arrêté les maths au CP, et parfois, on s'en aperçoit
-je n'arrive pas à arrondir, dès que c'est des maths ...

Le code n'est pas très long, le problème est repérable, j'ai mis plein de /////

On essaie avec le code, maintenant? :smiley:

#include <Servo.h>  //on lance la bibliotheque
Servo servo; //on declare le servo
int Pos = 0; //variable compteur
float tableau[10];  //tableau de stockage des positions
int Led = 13; //  //on place une led sur D13
int Record = 2; //bouton Record sur pin D0
int Play = 3; //bouton play sur pin D1
// le signal analogique du servo est lu sur le pinA0

void setup() {
  Serial.begin(9600);  //demarrage port serie
  pinMode (Led, OUTPUT);  //la led est une sortie
  servo.attach(5); //le servo est sur le pin D5
  pinMode (Record, INPUT_PULLUP);  // bouton
  pinMode (Play, INPUT_PULLUP);    // bouton
  digitalWrite(5, LOW);
  servo.detach();  //le servo est tout mou
}

void loop() {
  //détecter l'utilisation d'un bouton

  //bouton RECORD
  int RecVal = digitalRead(Record); //variable lue sur pin record
  if (RecVal == HIGH) { //Si bouton REC appuyé
    Flash(5);  //fonction Flash, 5 flash
    PosRec();
  }
  //bouton PLAY
  int PlayVal = digitalRead(Play); // variable lue sur Play
  if (PlayVal == HIGH) { //Si bouton PLAY appuyé
    Flash(1);  //fonction Flash, une fois
    PosPlay();
  }
  //dépassement du tableau
  if (Pos > 9) {
    Debordement();
  }
}



void Debordement() { //si on deborde du tableau
  Flash(10); //on clignote comme des foufous
  Pos = 9;  //rétablir une valeur max à Pos
  Serial.println("Depassement de tableau");
  delay(500);
  Flash(10);
  PosPlay();  //on lance la lecture
}

void PosRec() { //fonction pour enregistrer des positions
  digitalWrite(Led, HIGH); //allume la led
  Serial.println("Record");
  tableau[Pos] = analogRead(A0);  //stocke le signal dans l'emplacement i du tableau position
  Serial.println(Pos);
  Serial.println(analogRead(A0));  Pos++;
  digitalWrite(Led, LOW); //eteint la led
}

void PosPlay() { // fonction pour lire les données du tableau
  servo.attach(5);  //on attache le servo au pin5
  Serial.println("Play");
  digitalWrite(Led, HIGH); //allume led
  delay(50);  //pause
  digitalWrite(Led, LOW); //eteint led

  for (int i = 0; i < 10; i++) { //boucle pour lire toutes les valeurs du tableau
    Serial.print(i);
    Serial.print("    ");


    //Le problème est ici////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    int PosEntier = ((tableau[i] / 1.993) + 95.133); //x=(y/a)+b  //j'essaie de faire de la valeur dans le tableau en position [i] un entier
    servo.write(PosEntier);
    delay(500);
  }
}

void Flash(int N) {  //fait N flashs
  delay(200);
  for (int i = 0; i < N; i++) {
    digitalWrite(Led, HIGH);
    delay(5);
    digitalWrite(Led, LOW);
    delay(95);
  }
  delay(200);
}

kammo:
DEUX PROBLEMES:
-l'équation ne semble pas marcher écrite comme ça, ne m'en veuillez pas, j'ai arrêté les maths au CP, et parfois, on s'en aperçoit
-je n'arrive pas à arrondir, dès que c'est des maths ...

Le code n'est pas très long, le problème est repérable, j'ai mis plein de /////

Tu peux poster des détails ? que veux-tu dire par "l'équation ne semble pas marcher écrite comme ça" ?

EDIT : ton code vient d'arriver. :slight_smile:
En effet :
int PosEntier = ((tableau[i] / 1.993) + 95.133);ne calcule pas ce que tu veux...
Essaye :

float PosFloat = ((tableau[i] / 1.993) + 95.133);
int PosEntier = PosFloat;

Ouep
En fait les positions que ça envoie au servo ne sont pas bonnes.
Déjà, j'ai des décimales et elles ne sont pas comprises entre 0 et 180.

Voici ce que j'obtiens en remettant des serial.println dans le code:

Premier Record, à fond à gauche, le second, à fond à droite.

En play il devrait me donner 0 et 180, comme ceci

0 ( dans le tableau)
0 (l'angle en digital que j'envoie dans le servo)
1 ( dans le tableau)
180 (l'angle en digital que j'envoie dans le servo)
Mais horreur, voici ce qu'il me donne
Record
0
479
Record
1
78
Play
0
*335 *
1
*133 *

J'espère que c'est clair ^^

les chiffres RECORD sont ceux enregistrés par A0
La position dans le tableau, puis la valeur. J'en ai fait deux
Ensuite viennent les valeur convertie par l'équation, précédées elles aussi de leur place dan le tableau

Peut-être une piste. Dans la fonction Posrec, tu mets :

  tableau[Pos] = analogRead(A0);  //stocke le signal dans l'emplacement i du tableau position
  Serial.println(Pos);
  Serial.println(analogRead(A0));  Pos++;

Donc tu n'affiches pas ce qui est mémorisé mais une mesure faite un chouia plus tard. Il faudrait :

  tableau[Pos] = analogRead(A0);  //stocke le signal dans l'emplacement i du tableau position
  Serial.println(Pos);
  Serial.println(tableau[Pos]);  Pos++;

???

lesept:
En effet :

int PosEntier = ((tableau[i] / 1.993) + 95.133);

ne calcule pas ce que tu veux...
Essaye :

float PosFloat = ((tableau[i] / 1.993) + 95.133);

int PosEntier = PosFloat;

? ? ? ? ? je ne vois pas la différence ?

Je pense que la division dans le premier cas est une division entière donc peu précise. De même on perd les chiffres après la virgule de 95.133
Dans le second cas, les calculs sont faits en float puis arrondis en entiers.

... non ? ...

  pinMode (Record, INPUT_PULLUP);  // bouton
  .../...
  int RecVal = digitalRead(Record); //variable lue sur pin record
  if (RecVal == HIGH) { //Si bouton REC appuyé

Si ton bouton est monté en pull-up, il est appuyé si Recval == LOW

Bon en tous cas on a un mieux

Record
0
478.00
Record
1
77.00
Play
0
334
1
133

334 et 133? Essaierait-il de communiquer et dire 360 et 180?
On s'approcherait, mais les valeurs sont inversées, on devrait avoir 180 et 360. En fait on attend 0 et 180 ...

Je mets à jour mon code (enfin NOTRE code) et je le post. Voici ce que ça dit:

#include <Servo.h>  //on lance la bibliotheque
Servo servo; //on declare le servo
int Pos = 0; //variable compteur
float tableau[10];  //tableau de stockage des positions
int Led = 13; //  //on place une led sur D13
int Record = 2; //bouton Record sur pin D0
int Play = 3; //bouton play sur pin D1
// le signal analogique du servo est lu sur le pinA0

void setup() {
  Serial.begin(9600);  //demarrage port serie
  pinMode (Led, OUTPUT);  //la led est une sortie
  servo.attach(5); //le servo est sur le pin D5
  pinMode (Record, INPUT_PULLUP);  // bouton
  pinMode (Play, INPUT_PULLUP);    // bouton
  digitalWrite(5, LOW);
  servo.detach();  //le servo est tout mou
}

void loop() {
  //détecter l'utilisation d'un bouton

  //bouton RECORD
  int RecVal = digitalRead(Record); //variable lue sur pin record
  if (RecVal == HIGH) { //Si bouton REC appuyé
    Flash(5);  //fonction Flash, 5 flash
    PosRec();
  }
  //bouton PLAY
  int PlayVal = digitalRead(Play); // variable lue sur Play
  if (PlayVal == HIGH) { //Si bouton PLAY appuyé
    Flash(1);  //fonction Flash, une fois
    PosPlay();
  }
  //dépassement du tableau
  if (Pos > 9) {
    Debordement();
  }
}



void Debordement() { //si on deborde du tableau
  Flash(10); //on clignote comme des foufous
  Pos = 9;  //rétablir une valeur max à Pos
  Serial.println("Depassement de tableau");
  delay(500);
  Flash(10);
  PosPlay();  //on lance la lecture
}

void PosRec() { //fonction pour enregistrer des positions
  digitalWrite(Led, HIGH); //allume la led
  Serial.println("Record");
  tableau[Pos] = analogRead(A0);  //stocke le signal dans l'emplacement i du tableau position
  Serial.println(Pos);
  Serial.println(tableau[Pos]);  Pos++;
  digitalWrite(Led, LOW); //eteint la led
}

void PosPlay() { // fonction pour lire les données du tableau
  servo.attach(5);  //on attache le servo au pin5
  Serial.println("Play");
  digitalWrite(Led, HIGH); //allume led
  delay(50);  //pause
  digitalWrite(Led, LOW); //eteint led

  for (int i = 0; i < 10; i++) { //boucle pour lire toutes les valeurs du tableau
    Serial.println(i);

    float PosFloat = ((tableau[i] / 1.993) + 95.133); //on convertir le signal A0 en signal  digital
    int PosEntier = PosFloat;  //on en fait un entier
    servo.write(PosEntier);  //on commande le servo
    Serial.print(PosEntier);
    Serial.println("    ");
    delay(500);
  }
}

void Flash(int N) {  //fait N flashs
  delay(200);
  for (int i = 0; i < N; i++) {
    digitalWrite(Led, HIGH);
    delay(5);
    digitalWrite(Led, LOW);
    delay(95);
  }
  delay(200);
}

lesept:
Je pense que la division dans le premier cas est une division entière donc peu précise.

Non, car le dénominateur est explicitement un float. Le compilateur convertit le numérateur en float et fait la division en float.

De même on perd les chiffres après la virgule de 95.133

Non, car le compilateur fait une addition des floats.

Dans le second cas, les calculs sont faits en float puis arrondis en entiers.

Oui, mais c'est pareil que dans le 1er cas (sauf que ça prend 2 lignes et 2 variables)