Controlar estado del servomotor con pulsador

Buenas, estoy realizando con mis compañeros de instituto un radar que detecta obstrucciones con un servomotor y un sensor ultrasónico (HC-SR04) conectado a un arduino 2560 y quisimos controlar su activación y apagado con un pulsador.

Estuvimos buscando tutoriales y recopilando códigos por internet y logramos casi todo, excepto que una vez el servomotor está funcionando no deja de funcionar cuando vuelvo a apretar el pulsador, como si no saliera del loop, adjunto la codificación debajo. Gracias.

// Includes the Servo library
#include <Servo.h>. 

int buttonState=0;
boolean state;

// DEFINIMOS TODOS LOS PINES, PULSADOR, TRIG Y ECO
int pulsador=9;

const int trigPin = 10;
const int echoPin = 11;

// Variables for the duration and the distance
long duration;
int distance;
Servo myServo; // Creates a servo object for controlling the servo motor
void setup() {
  pinMode(pulsador, INPUT);
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
  Serial.begin(9600);
  myServo.attach(12); // PIN DEL SERVOMOTOR
}
void loop() {
  buttonState=digitalRead(pulsador);
  
  if (buttonState==HIGH){
    if(state==false){
      state=!state;
      delay(250);
    }
    else{
      state=false;
      delay(250);
    }
  }
  
 if(state==true){
  
  for(int i=0;i<=180;i++){  
  myServo.write(i);
  delay(40);
  distance = calculateDistance();// Calls a function for calculating the distance measured by the Ultrasonic sensor for each degree
  
  Serial.print(i); // Sends the current degree into the Serial Port
  Serial.print(","); // Sends addition character right next to the previous value needed later in the Processing IDE for indexing
  Serial.print(distance); // Sends the distance value into the Serial Port
  Serial.print("."); // Sends addition character right next to the previous value needed later in the Processing IDE for indexing
  }
  

  // Repeats the previous lines from 180 to 0 degrees
  for(int i=180;i>0;i--){  
  myServo.write(i);
  delay(40);
  distance = calculateDistance();
  Serial.print(i);
  Serial.print(",");
  Serial.print(distance);
  Serial.print(".");
  }
}


}
// Function for calculating the distance measured by the Ultrasonic sensor
int calculateDistance(){ 
  
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH); // Reads the echoPin, returns the sound wave travel time in microseconds
  distance= duration*0.034/2;
  return distance;
}

Hola. No se si es mi pantalla sucia o hay un punto al final de #include <Servo.h>

Con respecto a tu consulta, es lógico que pase eso porque mientras state==false te la pasas leyendo en el loop el pin del botón, pero una vez que state==true entras en dos ciclos for muy extensos y para colmo con delay de 40 milisegundos cada uno donde en ningún momento lees el estado el botón por si quieres detener el radar.

¿Y cómo solucionarías que me lea el botón para detenerlo?

¿Me estas solicitando que yo les haga la tarea del instituto?

En principio tienes que leer el estado del botón muy seguido, porque así como lo tienes ahora, por lo menos pasan 15 segundos sin leerse, y una vez que se lee por un instante vuelves a caer en los dos ciclos for.

Así como tienes el código desde if(state==true){ hasta el final de los ciclos for podría funcionar sin a la variable state el cambias el estado true o false mediante una interrupción.

Cada vez que tu código entra en los dos ciclos for deja de prestar atención al resto del punto por 180x2x40 mseg = 14400 mseg o sea 14.4 seg

La forma de evitar eso es como en este foro decimos siempre

  1. No uses delay
  2. aprende a usar millis() en su reemplazo para todo lo que sea controlar tiempos.

Hay que modificar tu código para que cuando este barriendo el radar y el sensor ultrasónico consulte si hay o no objetos que de algun modo se verifique el estado del pulsador.

una forma burda sería (sin cambar mucho) introducir la consulta del estado del pulsador dentro de la barrida 0 a 180 o de 180 a 0.

Otra forma es olvidar todos los delay() y usar millis().

El primer cambio que sugiero es este aunque no modificará la respuesta del código a tu pulsador

if (buttonState == HIGH){
     state =! state;
  }

Todo lo demas con los delay de 250 mseg no tienen sentido y menos sentido tiene que preguntes el estado del pulsador y luego lo cambies cada 250 mseg si lo mantienes presionado.

La idea siempre es crear otra variablle bool como buttonStateAnt y usarlo para ver flanco

  if (buttonState && !buttonStateAnt){
     state =! state;
  }
  buttonStateAnt = buttonState;

Aca se ve el flanco y cada vez que se presiona el pulsador se cambia el estado de state.

Esta versión debería funcionar mucho mejor

La prueban y me comentan

// Includes the Servo library
#include <Servo.h>

int buttonState=0;
boolean state;

// DEFINIMOS TODOS LOS PINES, PULSADOR, TRIG Y ECO
int pulsador=9;

const int trigPin = 10;
const int echoPin = 11;

// Variables for the duration and the distance
long duration;
int distance;
Servo myServo; // Creates a servo object for controlling the servo motor
int i             = 0;
int incremento    = 1;   // puede tomar dos valores 1 o -1
byte estado       = 0;
unsigned long start;

void setup() {
  Serial.begin(9600);
  pinMode(pulsador, INPUT);
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
  pinMode(echoPin, INPUT); // Sets the echoPin as an Input
  myServo.attach(12); // PIN DEL SERVOMOTOR
}

void loop() {
  buttonState = digitalRead(pulsador);
  
  if (buttonState == HIGH){
     state =! state;
  }
  
  if (state){
      switch(estado) {
          case 0: myServo.write(i);
                  i = i + incremento;
                  if (i == 180) {
                      incremento = -1;
                  }
                  if (i == 0) {
                      incremento = 1;
                  }
                  estado = 1;
                  start = millis();
                  break;
          case 1: if (millis() - start > 40UL) {
                      distance = calculateDistance();// Calls a function for calculating the distance measured by the Ultrasonic sensor for each degree
                      Serial.print(i); // Sends the current degree into the Serial Port
                      Serial.print(","); // Sends addition character right next to the previous value needed later in the Processing IDE for indexing
                      Serial.print(distance); // Sends the distance value into the Serial Port
                      Serial.print("."); // Sends addition character right next to the previous value needed later in the Processing IDE for indexing
                      estado = 0;
                  }
                  break;
              
      }
  }
}

// Function for calculating the distance measured by the Ultrasonic sensor
int calculateDistance(){ 
  
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  // Sets the trigPin on HIGH state for 10 micro seconds
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH); // Reads the echoPin, returns the sound wave travel time in microseconds
  distance= duration*0.034/2;
  return distance;
}

Solo les voy a recomendar que

  1. No compien y peguen códigos sin intentar entenderlos.
  2. Vayan a a Documentación => Indice de temas tutoriales => millis() y maquina de estados.

Esta ha sido la solución que implementé.

Si tienen dudas no hay problema en responderlas.

Muchísimas gracias genio! Me sirvió y nos pusimos con mis compañeros a leer todo lo que nos remarcaste para entender un poco más.

Como podrás comprender no estamos nada inmiscuidos en la programación de arduino y nos costó mucho empezar a entender de cero cómo funcionan las variables y sentencias.

Me sirvió todo lo que me remarcaste y reemplazando el código que me dejaste pude lograr que me funcione aunque creo que nuestro pulsador está algo defectuoso pues a veces cuando presiono no lo toma.

Muchas gracias de nuevo.

un presion acciona y otra no.
Para eso es esto

if (buttonState && !buttonStateAnt){
     state =! state;
  }
  buttonStateAnt = buttonState;

buttonState se pondrá en 1 o HIGH pero el estado anterior buttonStateAnt estará en LOW entonces cuando venimos de LOW y pasamos a HIGH cambias el estado de state gracias a tu parte de código

state = !state;

luego lo único que hago es guardar el nuevo estado de buttonState en la variable anterior buttonStateAnt

Cada pulsación entonces cambia el state de LOW a HIGH y otra vez a LOW