Led flashing and servo deceleration control

Hello all,

i am working on a project where I have an RGB LED that is steady green at powerup and when the button is released the RGB LED turns purple and starts rapidly flashing and over 5 seconds slows until it becomes steady purple. At the same time the RGB LED turns purple and starts flashing a continuous servo starts spinning and immediately starts decelerating until stopped with in 5 seconds, the servo speed is 20 RPS or less.

The issue i am having is the servo doesn't start decelerating until after the RGB LED stops flashing and goes steady purple. I am not sure of a way to adjust the script with proper breaks to allow the multiple task to start at the same time.

Any help would be appreciated. I am still learning and to be transparent i have been using Copilot to help lay this out but have found it was full of issue i had to resolve to get to this point. so the lesson have been good so far.

i also loaded a screen shot of the cosplay design to give you more of a visual of what this is. maybe it helps. (its still a work in progress.

#include <Servo.h>

// Define pin numbers
const int buttonPin = 2; // Button connected to digital pin 2
const int redPin = 9;    // Red LED pin
const int greenPin = 10; // Green LED pin
const int bluePin = 11;  // Blue LED pin
const int servoPin = 3;  // Servo connected to digital pin 3

// Variables to store the button state
int buttonState = 0;
int lastButtonState = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

// Adjustable flash rate and duration (in milliseconds)
unsigned long initialFlashRate = 100; // Initial flash rate in milliseconds
unsigned long finalFlashRate = 300;   // Final flash rate in milliseconds
unsigned long flashDuration = 5000;   // Flash duration in milliseconds

// Servo control variables
unsigned long runTime = 5000;         // Programmable run time in milliseconds
int initialServoSpeed = 20;          // Programmable initial speed (0 to 180)
unsigned long slowDownTime = 1000;    // Programmable slow down time in milliseconds
float decelerationRate = 0.9;         // Programmable deceleration rate (1.0 for linear, >1.0 for faster, <1.0 for slower)
bool servoRunning = false;
unsigned long servoStartTime;

// LED flashing variables
unsigned long flashStartTime = 0;
bool flashing = false;
unsigned long lastFlashTime = 0;bool ledState = false;

// Variable to track if the sequence is active
bool sequenceActive = false;

Servo myServo;

void setup() {
  Serial.begin(9600); // Initialize serial communication for debugging
  // Initialize the LED pins as outputs
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  
  // Initialize the button pin as an input
  pinMode(buttonPin, INPUT);
  
  // Attach the servo
  myServo.attach(servoPin);
  
  // Set the initial LED color to green
  setColor(0, 255, 0);
}

void loop() {
  // Read the state of the button
  int reading = digitalRead(buttonPin);

  // Check if the button state has changed
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      // If the button is released and the sequence is not active
      if (buttonState == LOW && !sequenceActive) {
        Serial.println("Button released, starting servo and LED sequence.");
        sequenceActive = true;

        // Start the servo
        servoStartTime = millis();
        servoRunning = true;
        myServo.write(initialServoSpeed); // Start the servo immediately
        Serial.println("Servo started at speed: " + String(initialServoSpeed));

        // Start the LED flashing sequence
        flashStartTime = millis();
        flashing = true;
        lastFlashTime = millis();
      }

      // If the button is pressed and the sequence is active
      if (buttonState == HIGH && sequenceActive) {
        Serial.println("Button pressed, stopping servo and resetting LED.");
        sequenceActive = false;
        // Reset the LED to green
        setColor(0, 255, 0);
      }
    }
  }

  lastButtonState = reading;

  // Servo control
  if (servoRunning) {
    unsigned long currentTime = millis();
    if (currentTime - servoStartTime < runTime) {
      myServo.write(initialServoSpeed); // Run the servo at the set speed
      Serial.println("Servo running at speed: " + String(initialServoSpeed));
    } else {
      unsigned long elapsed = currentTime - (servoStartTime + runTime);
      if (elapsed < slowDownTime) {
        // Proportional control for smooth deceleration
        float proportion = pow((float)(slowDownTime - elapsed) / slowDownTime, decelerationRate);
        int slowSpeed = 0 + (initialServoSpeed - 0) * proportion; // 90 is the stop position for continuous servos
        myServo.write(slowSpeed);
        Serial.println("Servo slowing down, speed: " + String(slowSpeed));
      } else {
        myServo.write(0); // Stop the servo
        servoRunning = false;
        Serial.println("Servo stopped.");
      }
    }
  }

  // LED flashing control
  if (flashing) {
    unsigned long currentTime = millis();
    if (currentTime - flashStartTime < flashDuration) {
      unsigned long flashInterval = initialFlashRate + (finalFlashRate - initialFlashRate) * (currentTime - flashStartTime) / flashDuration;
      if (currentTime - lastFlashTime >= flashInterval) {
        ledState = !ledState;
        if (ledState) {
          setColor(128, 0, 128); // Purple
        } else {
          setColor(0, 0, 0); // Turn off LED
        }
        lastFlashTime = currentTime;
      }
    } else {
      flashing = false;
      setColor(128, 0, 128); // Set to solid purple
    }
  }
}

void setColor(int red, int green, int blue) {
  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
}


Post your wiring to easy our help.

1 Like

Is this true?

The servo only slows when this is true...

(currentTime - servoStartTime < runTime) {

... and this is false:

if (elapsed < slowDownTime) {

wiring added

yes but will probably be much slower in the end, it was just a value i set to test to see the slow down.

A look at Pololu specs show 100RPM is their fastest. Yours seems to be 1200RPM

so this was something i overlooked and assumed the RPM in the sketch was truly RPM and not RPS. the servo i am using has a max RPM of 110, then if i truly want my revolutions to be 20 RPM i should set this for 0.33 RPS about.

it a bit tricky to i am testing all this on tinkercad so the animations and feed back are very limiting. i should have all my parts tomorrow to build a IRL test setup.

Try simulating on wokwi.com... it has the parts you need. The simulation acted as you described when I tried your code.

ok i will look a that one. is it worth buying the premium option for them?

No. "Pro" would be for developers or very advanced hobbyists. There are very good programmers using wokwi.com... one is @uipir_upir on YouTube, who does great work on displays.

@paulthetech

Sometimes you need to "make due" with what is at hand on wokwi. There is a 180 servo, but not at 360 servo. I "faked" 360 servos by using the 180 servo and marking what I should be seeing on a 360. You will understand how to make due.

In your code in post #12, the servo angle of "0" in a 360 servo is "max speed, counter-clockwise".
An "angle" of "90" is the approximate stopping "angle" (value varies with each servo).

Thank you. Now that it's written in front of .e it makes sense

I updated the comments in the simulation in post #11 to better explain angle versus speed.

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