Faire fonctionner des moteurs PAP néma 17 avec un affichage dans le moniteur série

Bonsoir
Le montage et le code suivants permettent de faire tourner un des deux moteurs de type nema 17 ou les deux en même temps lorsque l'on appuie sur les boutons qui leurs sont dédiés de tel nombre de pas ou en continue s'il l'on reste appuyé sur le(s) bouton(s).

#include "AccelStepper.h"     // https://www.pjrc.com/teensy/td_libs_AccelStepper.html

int boutonPin = 3;
int boutonPin2 = 4;
const int boutonPinEtatOn = LOW;     // Etat lu du bouton quand pressé (LOW pour PULL_UP)

const int mpapDirPin = 5;     // Pour driver MPAP pin pas
const int mpapStepPin = 6;     // Pour driver MPAP pin direction
const int mpapDirPin2 = 2;     // Pour driver MPAP pin pas
const int mpapStepPin2 = 7;     // Pour driver MPAP pin direction


AccelStepper mpap1(1, mpapStepPin, mpapDirPin);     // 1 pour A4988
AccelStepper mpap2(1, mpapStepPin2, mpapDirPin2); 

int mpapNombreDePasAtourner = 200;

void setup()
{
  mpap1.setMaxSpeed(2000);
  mpap1.setAcceleration(2000);
  mpap2.setMaxSpeed(1000);
  mpap2.setAcceleration(1000);
  
  pinMode(boutonPin, INPUT_PULLUP);
  pinMode(boutonPin2, INPUT_PULLUP);

  //                    DIR    STEP  ENA
  mpap1.setPinsInverted(false, false, true);
  mpap1.enableOutputs();     // Activer les signaux du MPAP
  mpap2.setPinsInverted(false, false, true);
  mpap2.enableOutputs();     // Activer les signaux du MPAP
}

void loop()
{
  
  boolean etatBouton=digitalRead(boutonPin);
  if (etatBouton == boutonPinEtatOn)
  {
    mpap1.move(mpapNombreDePasAtourner*2);
  }
  mpap1.run();
  
  boolean etatBouton2=digitalRead(boutonPin2);
  if (etatBouton2 == boutonPinEtatOn)
  {
    mpap2.move(mpapNombreDePasAtourner);
  }
  mpap2.run();
}

A présent j'aimerai associer le montage et code précédent avec le montage et code suivant qui fonctionnent avec des potentiomètres.

const byte pinPotIngredient1 = A1;
const byte pinPotIngredient2 = A2;

const int minPotIngredient1 = 0;
const int maxPotIngredient1 = 1023;

const int minPotIngredient2 = 0;
const int maxPotIngredient2 = 1023;

    int Ingredient1 = constrain(map(analogRead(pinPotIngredient1), minPotIngredient1, maxPotIngredient1, 0, 100), 0, 100);
    int Ingredient2 = constrain(map(analogRead(pinPotIngredient2), minPotIngredient2, maxPotIngredient2, 0, 100), 0, 100);
    Serial.print("Ingredient1: "); Serial.print(ratio(Ingredient1, Ingredient2));  Serial.print("%\t");
    Serial.print("Ingredient2: "); Serial.print(ratio(Ingredient2, Ingredient1)); Serial.println("%");
    delay(500);

L'ennui est que même avec des moteurs de type nema 17 le code des potentiomètres empêche les moteurs de tourner correctement (ils semblent tourner comme les aiguilles d'une montre et s'arrêter après avoir parcouru le nombre de pas dans le programme) lorsque les deux programme sont combinés comme suit.

#include "AccelStepper.h"    

int boutonPin = 3;
int boutonPin2 = 4;

const byte pinPotIngredient1 = A1;
const byte pinPotIngredient2 = A2;

const int minPotIngredient1 = 0;
const int maxPotIngredient1 = 1023;

const int minPotIngredient2 = 0;
const int maxPotIngredient2 = 1023;

const int boutonPinEtatOn = LOW;     // Etat lu du bouton quand pressé (LOW pour PULL_UP)

const int mpapDirPin = 5;     // Pour driver MPAP pin pas
const int mpapStepPin = 6;     // Pour driver MPAP pin direction
const int mpapDirPin2 = 2;     // Pour driver MPAP pin pas
const int mpapStepPin2 = 7;     // Pour driver MPAP pin direction


AccelStepper mpap1(1, mpapStepPin, mpapDirPin);     // 1 pour A4988
AccelStepper mpap2(1, mpapStepPin2, mpapDirPin2); 

int mpapNombreDePasAtourner = 200;

int ratio(int nb1, int nb2){
  if ((nb1 == 0) && (nb2 == 0)) return 0;
  return (100.0 * nb1) / (nb1 + nb2);
}

void setup()
{
  mpap1.setMaxSpeed(2000);
  mpap1.setAcceleration(2000);
  mpap2.setMaxSpeed(1000);
  mpap2.setAcceleration(1000);
  
  pinMode(boutonPin, INPUT_PULLUP);
  pinMode(boutonPin2, INPUT_PULLUP);

  //                    DIR    STEP  ENA
  mpap1.setPinsInverted(false, false, true);
  mpap1.enableOutputs();     // Activer les signaux du MPAP
  mpap2.setPinsInverted(false, false, true);
  mpap2.enableOutputs();     // Activer les signaux du MPAP

  Serial.begin(115200);
}

void loop()
{
  
  boolean etatBouton=digitalRead(boutonPin);
  if (etatBouton == boutonPinEtatOn)
  {
    mpap1.move(mpapNombreDePasAtourner*2);
  }
  mpap1.run();
  
  boolean etatBouton2=digitalRead(boutonPin2);
  if (etatBouton2 == boutonPinEtatOn)
  {
    mpap2.move(mpapNombreDePasAtourner);
  }
  mpap2.run();
    int Ingredient1 = constrain(map(analogRead(pinPotIngredient1), minPotIngredient1, maxPotIngredient1, 0, 100), 0, 100);
    int Ingredient2 = constrain(map(analogRead(pinPotIngredient2), minPotIngredient2, maxPotIngredient2, 0, 100), 0, 100);
    Serial.print("Ingredient1: "); Serial.print(ratio(Ingredient1, Ingredient2));  Serial.print("%\t");
    Serial.print("Ingredient2: "); Serial.print(ratio(Ingredient2, Ingredient1)); Serial.println("%");
    delay(500);
}

On peut placer les instructions d'affichage dans la condition comme suit mais cela empêches les moteurs de continuer à tourner en continue, or je voudrais que les moteurs effectuent un pas pour une pression et continuent de tourner si l'on reste appuyer sur leurs boutons.

#include "AccelStepper.h"    

int boutonPin = 3;
int boutonPin2 = 4;

const byte pinPotIngredient1 = A1;
const byte pinPotIngredient2 = A2;

const int minPotIngredient1 = 0;
const int maxPotIngredient1 = 1023;

const int minPotIngredient2 = 0;
const int maxPotIngredient2 = 1023;

const int boutonPinEtatOn = LOW;     // Etat lu du bouton quand pressé (LOW pour PULL_UP)

const int mpapDirPin = 5;     // Pour driver MPAP pin pas
const int mpapStepPin = 6;     // Pour driver MPAP pin direction
const int mpapDirPin2 = 2;     // Pour driver MPAP pin pas
const int mpapStepPin2 = 7;     // Pour driver MPAP pin direction


AccelStepper mpap1(1, mpapStepPin, mpapDirPin);     // 1 pour A4988
AccelStepper mpap2(1, mpapStepPin2, mpapDirPin2); 

int mpapNombreDePasAtourner = 200;

int ratio(int nb1, int nb2){
  if ((nb1 == 0) && (nb2 == 0)) return 0;
  return (100.0 * nb1) / (nb1 + nb2);
}

void setup()
{
  mpap1.setMaxSpeed(2000);
  mpap1.setAcceleration(2000);
  mpap2.setMaxSpeed(1000);
  mpap2.setAcceleration(1000);
  
  pinMode(boutonPin, INPUT_PULLUP);
  pinMode(boutonPin2, INPUT_PULLUP);

  //                    DIR    STEP  ENA
  mpap1.setPinsInverted(false, false, true);
  mpap1.enableOutputs();     // Activer les signaux du MPAP
  mpap2.setPinsInverted(false, false, true);
  mpap2.enableOutputs();     // Activer les signaux du MPAP

  Serial.begin(115200);
}

void loop()
{
  
  boolean etatBouton=digitalRead(boutonPin);
  if (etatBouton == boutonPinEtatOn)
  {
    mpap1.move(mpapNombreDePasAtourner*2);
    int Ingredient1 = constrain(map(analogRead(pinPotIngredient1), minPotIngredient1, maxPotIngredient1, 0, 100), 0, 100);
    int Ingredient2 = constrain(map(analogRead(pinPotIngredient2), minPotIngredient2, maxPotIngredient2, 0, 100), 0, 100);
    Serial.print("Ingredient1: "); Serial.print(ratio(Ingredient1, Ingredient2));  Serial.print("%\t");
    Serial.print("Ingredient2: "); Serial.print(ratio(Ingredient2, Ingredient1)); Serial.println("%");
    delay(500);
  }
  mpap1.run();
  
  boolean etatBouton2=digitalRead(boutonPin2);
  if (etatBouton2 == boutonPinEtatOn)
  {
    mpap2.move(mpapNombreDePasAtourner);
    int Ingredient1 = constrain(map(analogRead(pinPotIngredient1), minPotIngredient1, maxPotIngredient1, 0, 100), 0, 100);
    int Ingredient2 = constrain(map(analogRead(pinPotIngredient2), minPotIngredient2, maxPotIngredient2, 0, 100), 0, 100);
    Serial.print("Ingredient1: "); Serial.print(ratio(Ingredient1, Ingredient2));  Serial.print("%\t");
    Serial.print("Ingredient2: "); Serial.print(ratio(Ingredient2, Ingredient1)); Serial.println("%");
    delay(500);
  }
  mpap2.run();
}

J'ai donc essayer d'ajouter une fonction "affichage" ainsi:

#include "AccelStepper.h"    

int boutonPin = 3;
int boutonPin2 = 4;

const byte pinPotIngredient1 = A1;
const byte pinPotIngredient2 = A2;

const int minPotIngredient1 = 0;
const int maxPotIngredient1 = 1023;

const int minPotIngredient2 = 0;
const int maxPotIngredient2 = 1023;

const int boutonPinEtatOn = LOW;     // Etat lu du bouton quand pressé (LOW pour PULL_UP)

const int mpapDirPin = 5;     // Pour driver MPAP pin pas
const int mpapStepPin = 6;     // Pour driver MPAP pin direction
const int mpapDirPin2 = 2;     // Pour driver MPAP pin pas
const int mpapStepPin2 = 7;     // Pour driver MPAP pin direction


AccelStepper mpap1(1, mpapStepPin, mpapDirPin);     // 1 pour A4988
AccelStepper mpap2(1, mpapStepPin2, mpapDirPin2); 

int mpapNombreDePasAtourner = 200;

int ratio(int nb1, int nb2){
  if ((nb1 == 0) && (nb2 == 0)) return 0;
  return (100.0 * nb1) / (nb1 + nb2);
}

void setup()
{
  mpap1.setMaxSpeed(2000);
  mpap1.setAcceleration(2000);
  mpap2.setMaxSpeed(1000);
  mpap2.setAcceleration(1000);
  
  pinMode(boutonPin, INPUT_PULLUP);
  pinMode(boutonPin2, INPUT_PULLUP);

  //                    DIR    STEP  ENA
  mpap1.setPinsInverted(false, false, true);
  mpap1.enableOutputs();     // Activer les signaux du MPAP
  mpap2.setPinsInverted(false, false, true);
  mpap2.enableOutputs();     // Activer les signaux du MPAP

  Serial.begin(115200);
}

void loop(){
  boolean etatBouton=digitalRead(boutonPin);
  if (etatBouton == boutonPinEtatOn)
  {
    mpap1.move(mpapNombreDePasAtourner*2);
  }
  mpap1.run();
  
  boolean etatBouton2=digitalRead(boutonPin2);
  if (etatBouton2 == boutonPinEtatOn)
  {
    mpap2.move(mpapNombreDePasAtourner);
  }
  mpap2.run();
  affichage(etatBouton, etatBouton2);
}

void affichage(boolean nombre1, boolean nombre2){
  if ((nombre1==HIGH)&&(nombre2==HIGH)){
    int Ingredient1 = constrain(map(analogRead(pinPotIngredient1), minPotIngredient1, maxPotIngredient1, 0, 100), 0, 100);
    int Ingredient2 = constrain(map(analogRead(pinPotIngredient2), minPotIngredient2, maxPotIngredient2, 0, 100), 0, 100);
    Serial.print("Ingredient1: "); Serial.print(ratio(Ingredient1, Ingredient2));  Serial.print("%\t");
    Serial.print("Ingredient2: "); Serial.print(ratio(Ingredient2, Ingredient1)); Serial.println("%");
    delay(500);
  }
}

Après téléversement j'ai alors rencontré deux soucis:
1-le moteur ne continue pas de tourner lorsque l'on reste appuyé et attend le relachement avant d'avancer d'un pas
2-le dernier moteur dont le bouton a été appuyé (ou les deux si leur boutons ont été appuyé en même temps) continue à tourner une fois son bouton relaché de très petit pas comme les aiguilles d'une montre.

J'ai essayé de convertir le code accelstepper en respectant les normes de la bibliothèque MTstepStepper pour voir ce que cela donnerait de la manière suivante:

//#include "AccelStepper.h"
#include "MTstepStepper.h"
#include "MTbutton.h"

int boutonPin = 3;
int boutonPin2 = 4;

const byte pinPotIngredient1 = A1;
const byte pinPotIngredient2 = A2;

const int minPotIngredient1 = 0;
const int maxPotIngredient1 = 1023;

const int minPotIngredient2 = 0;
const int maxPotIngredient2 = 1023;

const int boutonPinEtatOn = LOW;     // Etat lu du bouton quand pressé (LOW pour PULL_UP)

const int mpapDirPin = 5;     // Pour driver MPAP pin pas
const int mpapStepPin = 6;     // Pour driver MPAP pin direction
const int mpapDirPin2 = 2;     // Pour driver MPAP pin pas
const int mpapStepPin2 = 7;     // Pour driver MPAP pin direction


//AccelStepper mpap1(1, mpapStepPin, mpapDirPin);     
//AccelStepper mpap2(1, mpapStepPin2, mpapDirPin2); 

MTstepStepper mpap1(pin_Step mpapStepPin, pin_Dir mpapDirPin);


int mpapNombreDePasAtourner = 200;

int ratio(int nb1, int nb2){
  if ((nb1 == 0) && (nb2 == 0)) return 0;
  return (100.0 * nb1) / (nb1 + nb2);
}

void avance(void)
{
  mpap1.move(500);
}

MTbutton Bouton(boutonPin, avance);

void setup()
{
  //mpap1.setMaxSpeed(2000);
  //mpap1.setAcceleration(2000);
  
  
  //mpap2.setMaxSpeed(1000);
  //mpap2.setAcceleration(1000);
  
  pinMode(boutonPin, INPUT_PULLUP);
  pinMode(boutonPin2, INPUT_PULLUP);

  //                    DIR    STEP  ENA
  //mpap1.setPinsInverted(false, false, true);
  //mpap1.enableOutputs();     // Activer les signaux du MPAP
  //mpap2.setPinsInverted(false, false, true);
  //mpap2.enableOutputs();     // Activer les signaux du MPAP

  Serial.begin(115200);
}

void loop(){
  /*boolean etatBouton=digitalRead(boutonPin);
  if (etatBouton == boutonPinEtatOn)
  {
    mpap1.move(mpapNombreDePasAtourner*2);
  }
  mpap1.run();
  
  boolean etatBouton2=digitalRead(boutonPin2);
  if (etatBouton2 == boutonPinEtatOn)
  {
    mpap2.move(mpapNombreDePasAtourner);
  }
  mpap2.run();*/

  int Ingredient1 = constrain(map(analogRead(pinPotIngredient1), minPotIngredient1, maxPotIngredient1, 0, 100), 0, 100);
  int Ingredient2 = constrain(map(analogRead(pinPotIngredient2), minPotIngredient2, maxPotIngredient2, 0, 100), 0, 100);
  Serial.print("Ingredient1: "); Serial.print(ratio(Ingredient1, Ingredient2));  Serial.print("%\t");
  Serial.print("Ingredient2: "); Serial.print(ratio(Ingredient2, Ingredient1)); Serial.println("%");
  delay(500);
}

Il semblerait qu'a cause des mes connaissances limités de cette bibliothèque le programme ne soit pas au point. Comment puis je m'y prendre pour que le programme fasse marcher les moteurs comme voulu tout en affichant les valeurs des potentiomètres dans le moniteur série ?

Cordialement

Bonjour enash

C'est normal, c'est l'instruction delay(500); dite bloquante qui empêche les instructions mpap1.run(); et mpap2.run(); de s'exécuter régulièrement.
Si tu veux une temporisation entre 2 affichages, il faut utiliser les millis() comme ceci:

unsigned long displayTempo = 500;     // Toutes les 1/2 secondes
unsigned long displayMillis = millis();

void setup() 
{
	Serial.begin(115200);
}

void loop()
{
	if (millis()-displayMillis >= displayTempo)
	{
		Serial.println("Ingredient1: ");
		Serial.println("Ingredient2: ");		
		
		displayMillis = millis();
	}
	
}

Dans ce type de projet, il faut bannir les fonctions dites bloquantes comme delay().

Cordialement
jpbbricole

Ce n'est pas dans ce type de projet, mais avec AccelStepper qu'il faut faire un code non bloquant.

Bonjour vileroi

Pour autant que l'on utilise AccelStepper avec une une fonction qui nécessite stepper.run(), faut-il encore le préciser.
Je confirme ma "pensée", c'est bien Dans ce type de projet qu'il faut éviter delay().

Cordialement
jpbbricole

Non, il faut utiliser un code non bloquant à cause de steper.run() c'est à dire à cause d'AccelStepper. Cela ne dépend pas du projet.

Dans ce type de mouvement, je n'utilise personnellement pas accelStepper à cause de cela, et mes moteurs peuvent tourner pendant un delay sans problème. C'est juste un problème de bibliothèque. Il y a des bibliothèques qui acceptent que le code non bloquant (AccelStepper par exemple) et d'autres qui acceptent aussi du code bloquant ce qui simplifie la programmation.

Pour faire tourner un pas à pas avec une Arduino, on n'est pas obligé d'utiliser AccelStepper.

Bonjour vileroi

Pas seulement, il y a plein de choses qui peuvent être gênées dans ce type de projet par un delay().

delay() est à éviter pour autant que faire se peut.

Cordialement
jpbbricole

Tu diras le contraire quand tu ne seras plus débutant. Si on doit bannir toutes les fonctions bloquantes, il faudrait aussi bannir les serial.print, et surtout les fonctions d'affichage au moins sur les tft. C'est plus simple de bannir AccelStepper et de faire un programme plus simple.

Bonsoir vileroi

Mort de rire, tu as oublié le smiley?

Concernant

Oh oui tu as entièrement raison!

Cordialement pbbricole

Pas vraiment. Serial.print() se contente de placer les caractères à émettre dans un buffer, et active une interruption pour l'émission proprement dite.
On ne peut pas parler de fonction bloquante dans ce cas, elle est bloquante seulement durant le temps nécessaire à son déroulement, comme n'importe quelle fonction.

Elle devient bloquante lorsqu'on sature le buffer d'émission, il me semble

Cela vaut mieux.