// Applique murale à bras articulés et motorisés
// https://forum.arduino.cc/t/applique-murale-a-bras-articules-et-motorises/1301784

#include <Servo.h>

const int8_t servoPin[] = {9, 7, 5, 3};
const size_t ServoNumber = sizeof(servoPin) / sizeof(*servoPin);
#define extendBtnPin  A0
#define stopBtnPin    A1
#define retractBtnPin A2
#define PAUSE_BETWEEN_PULSES 20
#define LED_PACE 200

#define PRESSED  LOW
#define RELEASED HIGH
enum Status : int8_t {STOPPED, EXTENDING, RETRACTING};

Servo servo[ServoNumber];

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

  for (size_t index = 0; index < ServoNumber; index++) {
    servo[index].attach(servoPin[index]);
  }

  pinMode(extendBtnPin, INPUT_PULLUP);
  pinMode(retractBtnPin, INPUT_PULLUP);
  pinMode(stopBtnPin, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  static int16_t servoTargetPos[ServoNumber] = {10, 170, 10, 170};
  static int16_t servoPos[ServoNumber] = {11, 169, 11, 169};
  static size_t servoIndex = ServoNumber - 2;
  static Status status = RETRACTING;
  static uint32_t nextPulse = millis();
  static uint32_t nextLedBlink = 0;
  uint32_t currentTime = millis();

  if (status && currentTime > nextPulse) {
    nextPulse += PAUSE_BETWEEN_PULSES;
    if (servoPos[servoIndex] != servoTargetPos[servoIndex]) {
      // Slowly reach the target position
      if (servoPos[servoIndex] < servoTargetPos[servoIndex]) {
        servoPos[servoIndex]++;
      }
      else {
        servoPos[servoIndex]--;
      }
      // Set the servo to the corresponding position
      servo[servoIndex].write(servoPos[servoIndex]);

      // Serial.print("servo ");
      // Serial.print(servoIndex);
      // Serial.print(" pulse: ");
      // Serial.println(servoPos[servoIndex]);
    }

    if (servoPos[servoIndex + 1] != servoTargetPos[servoIndex + 1]) {
      // Slowly reach the target position
      if (servoPos[servoIndex + 1] < servoTargetPos[servoIndex + 1]) {
        servoPos[servoIndex + 1]++;
      }
      else {
        servoPos[servoIndex + 1]--;
      }
      // Set the servo to the corresponding position
      servo[servoIndex + 1].write(servoPos[servoIndex + 1]);

      // Serial.print("servo ");
      // Serial.print(servoIndex + 1);
      // Serial.print(" pulse: ");
      // Serial.println(servoPos[servoIndex + 1]);
    }
    else if (servoPos[servoIndex] == servoTargetPos[servoIndex]) { // Make sure both target are reached
      if (status == EXTENDING) {
        if (servoIndex < ServoNumber - 2) {
          // Next servo pair
          servoIndex += 2;
        }
        else {
          status = STOPPED;
          Serial.println("Movement done !");
        }
      }
      else {
        if (servoIndex > 0) {
          // Previous servo pair
          servoIndex -= 2;
        }
        else {
          status = STOPPED;
          Serial.println("Movement done !");
        }
      }
    }
    // Serial.flush();
  }
  // Si l’interrupteur est en position 1
  // Ouverture
  if (status != EXTENDING && digitalRead(extendBtnPin) == PRESSED) {
    status = EXTENDING;
    Serial.println("Extending");
    servoTargetPos[0] = 170;
    servoTargetPos[1] = 10;
    servoTargetPos[2] = 170;
    servoTargetPos[3] = 10;
    nextPulse = currentTime;
  }

  // Si l’interrupteur est en position 2
  // Fermeture
  if (status != RETRACTING && digitalRead(retractBtnPin) == PRESSED) {
    status = RETRACTING;
    Serial.println("Retracting");
    servoTargetPos[0] = 10;
    servoTargetPos[1] = 170;
    servoTargetPos[2] = 10;
    servoTargetPos[3] = 170;
    nextPulse = currentTime;
  }

  // Si l’interrupteur est en position 0
  // Arrêt
  if (status != STOPPED && digitalRead(stopBtnPin) == PRESSED) {
    status = STOPPED;
    Serial.println("Stopped");
    servoTargetPos[0] = servoPos[0];
    servoTargetPos[1] = servoPos[1];
    servoTargetPos[2] = servoPos[2];
    servoTargetPos[3] = servoPos[3];
  }

  if (status) {
    if (currentTime > nextLedBlink) {
      digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
      nextLedBlink = currentTime + LED_PACE;
    }
  }
  else {
    if (digitalRead(LED_BUILTIN)) {
      digitalWrite(LED_BUILTIN, LOW);
    }
  }
}
Loading chip...chip-scope