Sistema para acercar una diana en un campo de tiro.

Hola, buenas tardes.
Estoy intentando hacer un proyecto con arduino nano, dos botones, un driver a4899 y un nema, tengo que aclarar que soy un novato en esto. Me gustaría saber si el código estaría bien. La idea es llevar una diana al sitio de disparo con un botón y traerla con otro.
Necesito mover un numero determinado de pasos en una dirección cuando pulse un botón y que al pulsar el otro botón lo haga en otra dirección. La idea es que entre cada secuencia de pasos el driver se apague. Os dejo el código por aquí. gracias

#define VELOCIDAD 1700 

int steps = 11;       //Posición del pin contador de pasos
int direccion = 9;    //Posición del pin dirección
int reset = 10;       //Posición del reset
int button1 = 3;      //Posicion de tiro
int button2 = 4;       // Posicion de cambio
int pasos = 2000;     //Cantidad de pasos a meter

// La rutina de inicialización
void setup() {                
  
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(steps, OUTPUT); 
  pinMode(direccion, OUTPUT); 
  pinMode(reset, OUTPUT);
}

// La rutina que se repite cíclicamente
void loop() {

  //De primeras damos señal de que el motor esté apagado. Esperamos 100ms y lo encendemos. Colocamos la dirección a HIGH.
  digitalWrite(reset, LOW);    //Mientras reset este en LOW el motor permanecerá apagado y no sufrirá. El chip apagará todos los puertos y no leerá comandos.
  delay(100);
  digitalWrite(reset, HIGH);   //Cuando reset se encuentre en HIGH el motor arrancará y leerá los comandos enviados.
  digitalWrite(direccion, HIGH);
    
  //Se repite un bucle hasta final de carril.
  for (int i = 0; i<pasos; i++)       //Equivale al numero de vueltas (200 es 360º grados) o micropasos

  if (digitalRead(button1) == HIGH);
  {
    digitalWrite(steps, HIGH);  // This LOW to HIGH change is what creates the
    digitalWrite(steps, LOW); // al A4988 de avanzar una vez por cada pulso de energia.  
    delayMicroseconds(VELOCIDAD);     // Regula la velocidad, cuanto mas bajo mas velocidad.

  } 

  //Volvemos a dar señal de que el motor esté apagado. Esperamos 100ms y lo encendemos. Esta vez la dirección es LOW, avanzará en la dirección opuesta.
  digitalWrite(reset, LOW);   //Mientras reset este en LOW el motor permanecerá apagado y no sufrirá. El chip apagará todos los puertos y no leerá comandos.
  delay(100);
  digitalWrite(reset, HIGH);   //Cuando reset se encuentre en HIGH el motor arrancará y leerá los comandos enviados.
  digitalWrite(direccion, LOW);

  for (int i = 0; i<pasos; i++)//Equivale al numero de vueltas (200 es 360º grados) o micropasos

  if (digitalRead(button2) == HIGH);
  {
      
    digitalWrite(steps, LOW);   // LOW to HIGH hace que el motor avance ya que da la orden
    digitalWrite(steps, HIGH);    // al A4988 de avanzar una vez por cada pulso de energia.
    delayMicroseconds(VELOCIDAD);         // Regula la velocidad, cuanto mas bajo mas velocidad.
  }
}

esto esta mal

if (digitalRead(button2) == HIGH);

no debes poner el ; al final porque bloqueas de ese modo el uso de lo que sigue entre {}

debe en ese caso modificarse asi

 if (digitalRead(button2) == HIGH)  {
     
    digitalWrite(steps, LOW);   // LOW to HIGH hace que el motor avance ya que da la orden
    digitalWrite(steps, HIGH);    // al A4988 de avanzar una vez por cada pulso de energia.
    delayMicroseconds(VELOCIDAD);         // Regula la velocidad, cuanto mas bajo mas velocidad.
  }

Otra observación que hago es que está desconectado esto

  //Se repite un bucle hasta final de carril.
  for (int i = 0; i<pasos; i++)       //Equivale al numero de vueltas (200 es 360º grados) o micropaso

con lo que sigue.
De hecho ese for no tiene instrucciónes que se repitan.
en un stepper o motor paso a paso, los pasos que pones ahi son los que aseguran que el motor se desplace X pasos.
Si 200 son una vuelta y 2PixR en mm es el desplazamiento de esa vuelta, entonces sabrás cuando moverte para cumplir con tu objetivo.

Gracias!!

Hoy por la tarde probare el código con los componentes cuando llegue al taller. Lo demás esta bien?

Disculpa, yo respondo y edito mientras voy viendo el código, hay mas comentarios.

Si, entiendo tu forma de proceder y te lo agradezco.

//Se repite un bucle hasta final de carril.
  for (int i = 0; i<pasos; i++)       //Equivale al numero de vueltas (200 es 360º grados) o micropaso

el for esta declarado en

int pasos = 2000;     //Cantidad de pasos a meter

es correcto? necesito dar ese numero de pasos

A ver, no es que esté mal la idea, pero en un campo de tiro ¿de fechas? ¿arma de fuego? ¿LR22, 9mm, .40, .45? ¿al aire libre o en galería?

Normalmente en las galerías un motor continuo, un botón con inversión, dos poleas y cable, mucho cable, pongamos 120m (yo tiro en galería a 50m) es la solución estándar

¿en serio es necesario tanta complicación?

Otra cosa es que te apetezca como iniciación de un nuevo hobby, en cuyo caso, como si lo conectas con un satélite para saber la hora de cada movimiento, pero vamos, me parece "un poquito grande"

Hey.

Yo tiro con carabina de aire comprimido de 4,5mm. en una galería casera de 10 m. He instalado un sistema con dos poleas y en una de estas dos tengo puesto el motor por pasos. Hay un carril con dos cables en los cuales se mueve una plataforma de la cual tira la polea que tracciona. A lo largo del día os mando unas fotos del sistema terminado.

Ok, ¿y un sencillo motor en una y cambiarle la polaridad? pura electrónica simple, sin necesidad de nada digital, si lo deseas digital pues surbyte ya te dio unos consejos y necesitas mover una cantidad de pasos, pero es que, como decía mi madre, es más caro el collar que el perro, por eso lo que comentaba.

Conozco a Tony y te aseguro que tiene mucha razón pero te comprendo.
Si quieres hacerlo con un motor paso a paso, adelante.
He modificado tu código

#define VELOCIDAD 1700

const int dirPin      =  9;     // Posición del pin dirección
const int stepPin     = 11;     // Posición del pin contador de pasos
const int butTiro     =  3;     // Posicion de tiro
const int butCambio   =  4;     // Posicion de cambio
const int reset       = 10;     // Posición del reset
 
const int steps = 2000;
int stepDelay;


// La rutina de inicialización
void setup() {               
   pinMode(butTiro, INPUT);
   pinMode(butCambio, INPUT);
   pinMode(dirPin, OUTPUT);
   pinMode(stepPin, OUTPUT);
   pinMode(reset, OUTPUT); 
}

// La rutina que se repite cíclicamente
void loop() {
   
  //Se repite un bucle hasta final de carril.
  if (digitalRead(butTiro)) {
      digitalWrite(reset, HIGH);   //Cuando reset se encuentre en HIGH el motor arrancará y leerá los comandos enviados.
      // Activar una direccion y fijar la velocidad con stepDelay
      digitalWrite(dirPin, HIGH);
      stepDelay = VELOCIDAD;
      // Giramos 2000 pulsos para hacer una vuelta completa
      // Vueltas x N
      int nVueltas = 10;
      for (int x = 0; x < steps * nVueltas; x++) {
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay);
      }
      // De primeras damos señal de que el motor esté apagado. Esperamos 100ms y lo encendemos. Colocamos la dirección a HIGH.
      digitalWrite(reset, LOW);    //Mientras reset este en LOW el motor permanecerá apagado y no sufrirá. El chip apagará todos los puertos y no leerá comandos.
  }

  if (digitalRead(butCambio)) {
      digitalWrite(reset, HIGH);   //Cuando reset se encuentre en HIGH el motor arrancará y leerá los comandos enviados.
      digitalWrite(dirPin, LOW);
      stepDelay = VELOCIDAD;
      int nVueltas = 10;
      for (int x = 0; x < steps * nVueltas; x++) {
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay);
      }
      // De primeras damos señal de que el motor esté apagado. Esperamos 100ms y lo encendemos. Colocamos la dirección a HIGH.
      digitalWrite(reset, LOW);    //Mientras reset este en LOW el motor permanecerá apagado y no sufrirá. El chip apagará todos los puertos y no leerá comandos.
  }
}

El sistema va perfecto salvo un par de detalles. Primero que no logro que no se repita una pulsación de botón, me explico, al apretar una vez que el sistema se lleve las dianas a la posición de tiro y si por error se pulsa de nuevo no me repita el comando, tengo que poner una variable?

Lo Segundo es que he tenido que modificar algo del código para q haga lo q quiero. Luego os pongo el código.

Un saludo y muchas gracias.

Gracias a todos por los comentarios.

Seguramente haciéndolo con un motor DC inversores fuera más fácil, pero nos aburrimos mucho

Si, con una variable lo solucionas. Por ejemplo, creas una variable bool que pones true cuando mandas la diana al fondo y false cuando viene al frente. Después el boton reacciona según esté esa variable. Algo así

bool alFondo = false;  // asumo que al inicio la diana está al frente

if(botonAtras) {
  if(alFondo == false) {
    alFondo = true;
   // muevo motor atras
  }
}


if(botonAdelante) {
  if(alFondo == true) {
    alFondo = false;
    // muevo motor adelante
  }
}

entonces cuando la diana esté atrás el botón que activa el motor hacia atrás deja de responder porque la variable alFondo en true indica que ya fue enviada hacia allá, al contrario si está adelante, deja de responder el botón que la trae al frente porque lo condiciona la variable en false (que significa que no está en el fondo por ende ya está adelante).

Saludos

Saludos, algo más liberado de trabajo, aunque poco

¿Por qué no pones todo el código que lleves hasta ahora?

Para contextualizarnos y le echamos un vistazo

Si, a ver si en un rato tengo tiempo y subo el código hasta ahora. Y si puedo os dejo fotos del proyecto. De momento todo funciona aunque tendría modificar el tema de la aceleración. Para que el motor se inicie con más torque y luego acelerarlo. Supongo que con dos for seguidos, un for con 10 vueltas a una velocidad baja y otro for con el resto de vueltas a más velocidad sería suficiente, no? Preferiría no usar librerías ya que soy un noob...

He simplificado el código y espero haber interpretado la sugerencia de @gatul.

#define VELOCIDAD 1700
#define TORQUE     500

const int dirPin      =  9;     // Posición del pin dirección
const int stepPin     = 11;     // Posición del pin contador de pasos
const int butTiro     =  3;     // Posicion de tiro
const int butCambio   =  4;     // Posicion de cambio
const int reset       = 10;     // Posición del reset
 
const int steps = 2000;
int stepDelay;
bool alFondo = false;  // asumo que al inicio la diana está al frente
bool estadoCambio, estadoCambioAnt = false;
bool estadoTiro, estadoTiroAnt = false;

// La rutina de inicialización
void setup() {              
   pinMode(butTiro, INPUT);
   pinMode(butCambio, INPUT);
   pinMode(dirPin, OUTPUT);
   pinMode(stepPin, OUTPUT);
   pinMode(reset, OUTPUT);
}

// La rutina que se repite cíclicamente
void loop() {

  estadoTiro = digitalRead(butTiro);
  //Se repite un bucle hasta final de carril.
  if (estadoTiro && !estadoTiroAnt) {
      if (!alFondo)  {
          muevoMotor(10, HIGH);
          alFondo = true;
      }
  }
  estadoTiroAnt = estadoTiro;

  estadoCambio = digitalRead(butCambio);
  if (digitalRead(butCambio)) {
      if (alFondo) {            // si esta en el fondo entonces 
          muevoMotor(10, LOW);
          alFondo = false;
      }
          
  }
  estadoCambio = estadoCambioAnt;
}

void muevoMotor(int vueltas, bool direccion) {
      digitalWrite(reset, HIGH);   //Cuando reset se encuentre en HIGH el motor arrancará y leerá los comandos enviados.
      // Activar una direccion y fijar la velocidad con stepDelay
      digitalWrite(dirPin, direccion);
      stepDelay = TORQUE;  
      for (int x = 0; x < 2; x++) { // da las vueltas ordenadas en el loop
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay);
      }
      stepDelay = VELOCIDAD;
      // Giramos 2000 pulsos para hacer una vuelta completa
      int vueltasRestantes = steps * vueltas - 2;
      for (int x = 0; x < vueltasRestantes; x++) { // da las vueltas ordenadas en el loop
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay);
      }
      // De primeras damos señal de que el motor esté apagado. Esperamos 100ms y lo encendemos. Colocamos la dirección a HIGH.
      digitalWrite(reset, LOW);     // Mientras reset este en LOW el motor permanecerá apagado y no sufrirá. 
                                    // El chip apagará todos los puertos y no leerá comandos.
}

Incluye un arranque lento a velocidad que llamé TORQUE que puedes modificar y luego el resto a velocidad normal.
Tambien se podria hacer una rampa para que no fuera abrupto el cambio.

Guau, eso es como decir prefiero no usar cuerda mientras aprendo a escalar, o como decir, no colimo la mira ya que apenas estoy aprendiendo a tirar

Las librerías son ideales para empezar, es el camino correcto, ni los que estamos acostumbrados a programar o lo hacemos profesionalmente las menospreciamos.

Te las recomiendo y ya veremos el código

[code]
#define VELOCIDAD 580
const int dirPin      = 4;     // Posición del pin dirección
const int stepPin     = 5;     // Posición del pin contador de pasos
const int butTiro     = 3;     // Posicion de tiro
const int butCambio   = 2;     // Posicion de cambio
const int reset       = 6;     // Posición del reset

bool tiro = true;
 
const int steps = 200;
int stepDelay;


// La rutina de inicialización
void setup() {              
   pinMode(butTiro, INPUT);
   pinMode(butCambio, INPUT);
   pinMode(dirPin, OUTPUT);
   pinMode(stepPin, OUTPUT);
   pinMode(reset, OUTPUT);
}

// La rutina que se repite cíclicamente
void loop() {
  
  //Se repite un bucle hasta final de carril.
  if (digitalRead(butTiro)) {
    if (tiro == true) {
      tiro = false;
    }
      delay(1000);
      digitalWrite(reset, HIGH);   //Cuando reset se encuentre en HIGH el motor arrancará y leerá los comandos enviados.
      // Activar una direccion y fijar la velocidad con stepDelay
      digitalWrite(dirPin, HIGH);
      stepDelay = 800;
      // Giramos 2000 pulsos a menor velocidad para ganar torque
      // Vueltas x N
      float nVueltasLentas = 5;
      for (int x = 0; x < steps * nVueltasLentas; x++) {
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay);
      }
         stepDelay = VELOCIDAD;
      // Giramos el resto a mayor velocidad
      // Vueltas x N
      float nVueltasRapidas = 60;
      for (int x = 0; x < steps * nVueltasRapidas; x++) {
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay); 
      }
      // De primeras damos señal de que el motor esté apagado.
      digitalWrite(reset, LOW);    //Mientras reset este en LOW el motor permanecerá apagado y no sufrirá. El chip apagará todos los puertos y no leerá comandos.
  }

  if (digitalRead(butCambio)) {
    if (tiro == false) {
      tiro = true;
    }
      delay(1000);
      digitalWrite(reset, HIGH);   //Cuando reset se encuentre en HIGH el motor arrancará y leerá los comandos enviados.
      digitalWrite(dirPin, LOW);
      stepDelay = 1000;    //Giramos a menor velocidad para ganar torque
      float nVueltasLentas = 5;
      for (int x = 0; x < steps * nVueltasLentas; x++) {
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay);
      }
      stepDelay = VELOCIDAD;
      // Giramos el resto a mayor velocidad.
      // Vueltas x N
      float nVueltasRapidas = 60;
      for (int x = 0; x < steps * nVueltasRapidas; x++) {
          digitalWrite(stepPin, HIGH);
          delayMicroseconds(stepDelay);
          digitalWrite(stepPin, LOW);
          delayMicroseconds(stepDelay); 
      }
      // De primeras damos señal de que el motor esté apagado. Esperamos 100ms y lo encendemos. Colocamos la dirección a HIGH.
      digitalWrite(reset, LOW);    //Mientras reset este en LOW el motor permanecerá apagado y no sufrirá. El chip apagará todos los puertos y no leerá comandos.
  }
}

[/code]
os dejo lo q me funciona hasta ahora, no me funciona el anulador de repeticion del boton

no te quito la razón, aunque la analogía que prefiero yo es no lanzarme solo con las dos ruedas de la bici sin haber aprendido con los ruedines xd. Te he dejado el código en el post anterior. No es que sea novato con Arduino, es que soy novato programando, soy novato con la electrónica...

si bueno, le echo un vistazo, la verdad es que está bastante bien organizado aunque creo que le das muchas vueltas, lo miro un rato

No puedo probar el código, pero yo lo haría así.

Se puede mejorar, te lo dejo e ejercicio

/* ----------------------------------------------------------------------------
    Controlador para una diana movil en campo de tiro

    Autor:    
    Versión:  
    Licencia: 
   ----------------------------------------------------------------------------
 */

/*  -------------------------------------------------------------------------
      CONSTANTES Y DECLARACIONES
    -------------------------------------------------------------------------
*/
// --- Pines del motor
#define PIN_DIR   4     // --- Pin de dirección del motor
#define PIN_PASO  5     // --- Pin indicador de pasos
#define PIN_ACTMT 6     // --- Pin activador y desactivador del motor

// --- Pines como botones
#define BT_TIRO   3     // --- Botón para llevar a posición de tiro
#define BT_CAMB   2     // --- Botón para llevar a posición de cambio de diana


// --- Velocidades del motor y pasos para 360
#define VEL_MAX 580
#define VEL_MIN 1000
#define PS_360  200


/*  -------------------------------------------------------------------------
      Variables
    -------------------------------------------------------------------------
*/
bool posicion;    // --- True  = zona de tiro
                  // --- False = zona de cambio




/*  -------------------------------------------------------------------------
      FUNCIONES GENERALES
    -------------------------------------------------------------------------
*/

// --- Cambiar el estado del motor
void estado_motor(int estado) { digitalWrite(PIN_ACTMT, estado); }
void motor_on()  { estado_motor(HIGH); }
void motor_off() { estado_motor(LOW); }

// --- Mover el motor x pasos
void mover(float vueltas, int velocidad, int direccion) {

    digitalWrite(PIN_DIR, direccion);

    motor_on();
    for (int x = 0; x < vueltas * float(PS_360); x++) {
        digitalWrite(PIN_PASO, HIGH);
        delayMicroseconds(velocidad);

        digitalWrite(PIN_PASO, LOW);
        delayMicroseconds(velocidad);
      }
    motor_off();
}


// --- Esperar que el usuario suelte el botón
void debounce(int boton) {
    while (digitalRead(boton)) {
      // --- Esperar que suelte el botón o acabe el debounce
    }
}




/*  -------------------------------------------------------------------------
      INICIALIZAR SISTEMA
    -------------------------------------------------------------------------
*/
void setup() {             
    // --- Control del motor
    pinMode(PIN_DIR,   OUTPUT);
    pinMode(PIN_PASO,  OUTPUT);
    pinMode(PIN_ACTMT, OUTPUT);

    // --- Botonera
    pinMode(BT_TIRO,    INPUT);
    pinMode(BT_CAMB,    INPUT);

    // --- Parámetros
    posicion = false;   // --- Debería comenzar en zona de cambio
}




/*  -------------------------------------------------------------------------
      PROCESO
    -------------------------------------------------------------------------
*/
void loop() {

    // --- Verificar si se pulsó el botón para llevar a la zona de tiro
    if (digitalRead(BT_TIRO)) {

        // --- Sólo si no está ya en posición de tiro (mejorable el código)
        if (posicion == false) {

            // --- Esperar que suelte el botón
            debounce(BT_TIRO);

            // --- Primeras vueltas lentas, luego rápidas hacia HIGH
            mover(5,  VEL_MIN, HIGH);
            mover(60, VEL_MAX, HIGH);

            // --- Marcamos la diana en posición
            posicion == true;
        }
    }

    // --- Verificar si se pulsó el botón para llevar a la zona de cambio
    if (digitalRead(BT_CAMB)) {

        // --- Sólo si no está ya en posición de cambio
        if (posicion == true) {

            // --- Esperar que suelte el botón
            debounce(BT_CAMB);

            // --- Primeras vueltas lentas, luego rápidas, hacia LOW
            mover(5,  VEL_MIN, LOW);
            mover(60, VEL_MAX, LOW);

            // --- Marcamos la diana en posición
            posicion == true;
        }
    }
}