Servo rotation error

So i want my servo to start at 90 degrees then go to 135 degrees stay there for x amount of time go to 45 degrees stay there for x amount of time and then back to 90 degrees. But when i upload this code to my arduino it starts at 90 degrees goes to 135 degrees stays there for x time then goes to 120 and then back to 135. It might be something minor or a small numeric mistake but i cant figure it out.
Below is a zip video of what i am describing above.
Thank you

servo.zip (2.8 MB)

 // Libraries
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <dht.h>
#include <Servo.h>


// Variables
float hum;    // Stores humidity value
float temp;   // Stores temperature value
int degrees = 90;  // Initialize degrees to 90
unsigned long lastServoMoveTime = 0;
unsigned long servoMoveInterval = 8000;  // Interval between servo movements (milliseconds)

// Constants
#define DHTPIN 2
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define DHTTYPE DHT22
dht DHT;
Servo SERVO;
#define RELAYPIN 10
#define SERVOMOTOR 9

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.init();
  lcd.clear();
  lcd.backlight();
  pinMode(RELAYPIN, OUTPUT);
  pinMode(SERVOMOTOR, OUTPUT);
  SERVO.attach(9);




  if (degrees != 90) {
      //  if degrees not 90 make 90
      degrees = 90; // Make degrees 90
  }
}

void loop() {
  byte CelsiusSymbol[] = {
    0b11100,
    0b10100,
    0b11100,
    0b00000,
    0b00000,
    0b00000,
    0b00000,
    0b00000
  };

  int chk = DHT.read22(DHTPIN);
  hum = DHT.humidity;
  temp = DHT.temperature;

  lcd.setCursor(0, 0);
  lcd.print("Temp: ");
  lcd.print(temp);
  lcd.print('c');
  lcd.createChar(0, CelsiusSymbol);
  lcd.setCursor(11, 0);
  lcd.write((byte)0);
  lcd.setCursor(0, 1);
  lcd.print("Humidity: ");
  lcd.print(hum);
  lcd.print("%");

  unsigned long currentMillis = millis();

  // Move servo every servoMoveInterval milliseconds
  if (currentMillis - lastServoMoveTime >= servoMoveInterval) {
    lastServoMoveTime = currentMillis;

    if (degrees == 90) {
      // 90 to 135 degrees counter clockwise (aristerostrofa)
      degrees = 105; // Go from 90 to 105
       servoMoveInterval = 2000; //stay 2 seconds
    } else if (degrees == 105) {
      degrees =120; // Go from 105 to 120
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 120) {
      degrees = 135;  // Go from 120 to 135
      servoMoveInterval = 8000;  // Stay at 135 degrees for 8 seconds $$$$


      
      // 135 to 45 degrees clockwise (deksiostrofa)
    } else if (degrees == 135) {
       degrees = 120; // Go from 135 to 120
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 120) {
       degrees = 105; // Go from 120 to 105
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 105) {
       degrees = 90; // Go from 105 to 90
      servoMoveInterval = 2000; // stay 2 seconds
    }  else if (degrees == 90) {
       degrees = 75; // Go from 90 to 75
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 75) {
       degrees = 60; // Go from 75 to 60
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 60) {
      degrees = 45;  // Go from 60 to 45
      servoMoveInterval = 7000;  // Stay at 45 degrees for 7 seconds $$$$$

      // 45 to 90 degrees counterclockwsise (aristerostrofa)
    } else if (degrees == 45) {
       degrees = 60; // Go from 45 to 60
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 60) {
       degrees = 75; // Go from 60 to 75
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 75) {
      degrees = 90;  // Go from 75 to 90
      servoMoveInterval = 8000;  // Stay at 90 degrees for 8 seconds $$$$$$$$
    }

    SERVO.write(degrees);
  }

  // Adjust as needed, this is a small delay to prevent constant servo movement
  delay(2000);
}

[/code]

I see what you're trying to do here. Instead of relying on the degrees value, make yourself another variable and call it state. And for each of these set it to a unique value.

The problem is that when degrees is 120 it hits the first test for that and since it is satisfied it stops there. You have multiple tests for degrees == 120 but if you think about it only the first one will run each time.

} else if (degrees == 105) {
      degrees =120; // Go from 105 to 120
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 120) {
      degrees = 135;  // Go from 120 to 135
      servoMoveInterval = 8000;  // Stay at 135 degrees for 8 seconds $$$$


      
      // 135 to 45 degrees clockwise (deksiostrofa)
    } else if (degrees == 135) {
       degrees = 120; // Go from 135 to 120
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 120) {
       degrees = 105; // Go from 120 to 105
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 105) {

If degrees is 105 or 120 then the first if statement is true and it doesn't go to any of the else clauses. You can't set this type of thing up with multiple cases having the same value to test for.

Instead make yourself a new variable and call it state. You can give it a unique value for each case. Then your if statements are:

if(state == 1) {
    state = 2;
    degrees = 105;
} else if (state == 2) {

etc. etc.

Or add a boolean variable to indication the current direction of travel, and test both that and the angle to determine the next state.

    } else if (degrees == 120) {
      if (increasing)
      {
        degrees = 135;  // Go from 120 to 135
        servoMoveInterval = 8000;  // Stay at 135 degrees for 8 seconds $$
      }
      else
      {
        degrees = 105; // Go from 120 to 105
        servoMoveInterval = 2000; // stay 2 seconds
      }

As noted by @Delta_G, the multiple appearance of 120 means your code doesn't do what you want.

It's an ugly solution, but just changing the targets a wee bit so they would remain very close from a visual inspection, but fully distinct to the logic, viz:

      // 135 to 45 degrees clockwise (deksiostrofa)
    } else if (degrees == 135) {
       degrees = 121; // Go from 135 to 121
      servoMoveInterval = 2000; // stay 2 seconds
    } else if (degrees == 121) {

You'd have to do the same with any other values that were causing the same malfunction.

The better solutions are better, short term or long. :expressionless:

a7

Thank you all for replying.
Now that it was explained i understand why the servo moves like that.
I went with @MarkT solution because its easier for me to understand i changed the degree increment from 15 to 18 so that it is still divisible by 90 so the degrees go:
135 117 99 81 63 45

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.