0
votes
Continuous servo rotation Arduino - Stack Overflow
Asked
Viewed 1k times
0

I have a continuous rotation servo that I need to go clockwise and counterclockwise. I have found the mid point being at 100, and the clockwise and counterclockwise speeds I've found to be the most appropriate are 110 and 85, respectively. The servo rotates clockwise when button A is pushed, and counterclockwise when B is pushed.

I want a way to slow down the servo, once the button is released, at an exponential rate, so that it would say go from 110 to 100, or 85 to 100 in t (user definable) seconds. Is there a function anyone knows of that might help me accomplish this? or a way of doing this. Detailed answers appreciated as I am an Arduino noob.

#include <Servo.h>

Servo myservo; // create servo object to control a servo

// CONSTANTS

// PINS
const int crServo = 12; // sets pin 12 as servo
const int buttonPinCW = 2; // sets pin 2 as button; CW => clockwise => FOCUS FAR
const int buttonPinCC = 3; // sets pin 3 as button; CC => counterclockwise => FOCUS NEAR
const int ledPinB = 4; // sets pin 10 as LED
const int ledPinG = 5; // sets pin 10 as LED
const int ledPinR = 6; // sets pin 10 as LED

// SERVO PROPERTIES
const int crSpeedDefault = 100; // is the stay still position, motor should not turn
const int crSpeedCW = 110; // turns the motor full speed clockwise
const int crSpeedCC = 85; // turns the motor full speed counter-clockwise

// SET BUTTON STATES
int buttonStateCW = 0; //sets button 1 as off
int buttonStateCC = 0; // sets button 2 as off

void setup()
{
  myservo.attach(crServo); // attaches the servo on pin 12 to the servo object
  pinMode (buttonPinCW, INPUT); // sets button as input
  pinMode (buttonPinCC, INPUT); // sets button as input
  pinMode (ledPinB, OUTPUT); // sets led as output
  pinMode (ledPinG, OUTPUT); // sets led as output
  pinMode (ledPinR, OUTPUT); // sets led as output
  myservo.write(crSpeedDefault); // default servo to crSpeedDefault
  startup();
}

int startup() {
  blinker(2, ledPinB);
  blinker(1, ledPinG);
  blinker(1, ledPinR);
}

void blinker(int count, int pin) {
    for ( int x = 0; x < count; x++ )
    {
      digitalWrite(pin, HIGH);
      delay(1000);
      digitalWrite(pin, LOW);
      delay(1000);
    }
}

void loop()
{
  buttonStateCW = digitalRead(buttonPinCW);
  buttonStateCC = digitalRead(buttonPinCC);
  // clockwise rotation
  if (buttonStateCW == HIGH) {
    digitalWrite(ledPinR, HIGH);
    myservo.write(crSpeedCW);
    // counterclockwise rotation
  } 
  else if (buttonStateCC == HIGH) {
    digitalWrite(ledPinG, HIGH);
    myservo.write(crSpeedCC);
  } 
  else {
    myservo.write(crSpeedDefault);
    digitalWrite(ledPinR, LOW); 
    digitalWrite(ledPinG, LOW);     // turn the LED off by making the voltage LOW
  }
}

Updated with RMI's answer

#include <Servo.h>

Servo myservo; // create servo object to control a servo

// CONSTANTS

// PINS
const int crServo = 12; // sets pin 12 as servo
const int buttonPinCW = 2; // sets pin 2 as button; CW => clockwise => FOCUS FAR
const int buttonPinCC = 3; // sets pin 3 as button; CC => counterclockwise => FOCUS NEAR
const int ledPinB = 4; // sets pin 10 as LED
const int ledPinG = 5; // sets pin 10 as LED
const int ledPinR = 6; // sets pin 10 as LED

const int t = 1;  // slow down

// SERVO PROPERTIES
const int crSpeedDefault = 100; // is the stay still position, motor should not turn
const int crSpeedCW = 107; // turns the motor full speed clockwise
const int crSpeedCC = 87; // turns the motor full speed counter-clockwise

// SET BUTTON STATES
int buttonStateCW = 0; //sets button 1 as off
int buttonStateCC = 0; // sets button 2 as off

void setup()
{
  myservo.attach(crServo); // attaches the servo on pin 12 to the servo object
  pinMode (buttonPinCW, INPUT); // sets button as input
  pinMode (buttonPinCC, INPUT); // sets button as input
  pinMode (ledPinB, OUTPUT); // sets led as output
  pinMode (ledPinG, OUTPUT); // sets led as output
  pinMode (ledPinR, OUTPUT); // sets led as output
  myservo.write(crSpeedDefault); // default servo to crSpeedDefault
  startup();
}

int startup() {
  //blinker(2, ledPinB);
  //blinker(1, ledPinG);
  //blinker(1, ledPinR);
}

void blinker(int count, int pin) {
  for (int x = 0; x < count; x++)
  {
    digitalWrite(pin, HIGH);
    delay(1000);
    digitalWrite(pin, LOW);
    delay(1000);
  }
}

void loop()
{
  buttonStateCW = digitalRead(buttonPinCW);
  buttonStateCC = digitalRead(buttonPinCC);
  // clockwise rotation
  if (buttonStateCW == HIGH) {
    digitalWrite(ledPinR, HIGH);
    float speed = crSpeedCW;
    Serial.print("CLOCKWISE-ROTATION \n");
    for (int i = 0; i < t * 5; i++) {
      speed += ((float)crSpeedDefault - speed)/ 10;
      Serial.print(speed);
      Serial.print("\n");
      myservo.write((int)speed);
      delay(100);
    }
    myservo.write(crSpeedCW);
  } 
  else if (buttonStateCC == HIGH) {
      digitalWrite(ledPinG, HIGH);
      float speed = crSpeedCC;
      Serial.print("COUNTER-CLOCKWISE-ROTATION \n");
      for (int i = 0; i < t * 5; i++) {
        speed += ((float)crSpeedDefault - speed) / 10;
        Serial.print(speed);
        Serial.print("\n");
        myservo.write((int)speed);
        delay(100);
      }
      myservo.write(crSpeedCC);
    } 
  else {
    myservo.write(crSpeedDefault);
    digitalWrite(ledPinR, LOW); 
    digitalWrite(ledPinG, LOW);     // turn the LED off by making the voltage LOW
  }
}
    3

    Try This.

    void loop()
    {
      ...
      // clockwise rotation
      if (buttonStateCW == HIGH) {
        digitalWrite(ledPinR, HIGH);
        float speed = crSpeedCW;
        for (int i = 0; i < t * 5; i++) {
            speed -= (speed - (float)crSpeedDefault) / 10;
            myservo.write((int)speed);
            delay(200);
        }
        myservo.write(crSpeedCW);
      } 
      else if (buttonStateCC == HIGH) {
        digitalWrite(ledPinG, HIGH);
        // Do the same here in reverse
        myservo.write(crSpeedCC);
      } 
      else {
        ...
      }
    }
    

    This will slow down the speed exponentially. You have to adjust hard coded numbers to suit your the ranges.

    4
    • could you offer more explanation as to the values 5 and 10 in your equations? also could you please specify in the above code what you mean by reverse? furthermore, it is quite odd but for the clockwise rotation the motor goes from 101 to 110 in when it should start at 110 and go to 100
      – Alex
      Apr 25 2014 at 18:25
    • I have updated it to go from 110 to 100. t * 5 specifies how many times the velocity is modified going from 110 to 100. 10 is a sort of exponential deceleration (here larger the value lower the deceleration. 200 is 1000ms/5. Algorithm works like this. starting from 110 take the delta you have to go. i.e. 110 - 100 => 10. then set the next velocity as 90% from that delta. i.e current speed - delta * 10% => 9. In each iteration you set the velocity to a fraction of the current velocity, which is a sort of exponential decay.
      – rmi
      Apr 27 2014 at 16:55
    • Actually this algorithm will not perform well with integers in this kind of short ranges. You have to understand this loop and then try to modify it to go from 85 to 100.
      – rmi
      Apr 27 2014 at 16:56
    • with some trial and error I figure it out with the serial print function. I understand what you mean by short ranges not working that great as I have seen it myself only working if the t is quite "high". But nevertheless thank you for the answer! It addressed my question!
      – Alex
      Apr 27 2014 at 22:43

    Your Answer

    By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

    Not the answer you're looking for? Browse other questions tagged or ask your own question.

     
    1

    1 Answers

    3
    votes

    Try This.

    void loop()
    {
      ...
      // clockwise rotation
      if (buttonStateCW == HIGH) {
        digitalWrite(ledPinR, HIGH);
        float speed = crSpeedCW;
        for (int i = 0; i < t * 5; i++) {
            speed -= (speed - (float)crSpeedDefault) / 10;
            myservo.write((int)speed);
            delay(200);
        }
        myservo.write(crSpeedCW);
      } 
      else if (buttonStateCC == HIGH) {
        digitalWrite(ledPinG, HIGH);
        // Do the same here in reverse
        myservo.write(crSpeedCC);
      } 
      else {
        ...
      }
    }
    

    This will slow down the speed exponentially. You have to adjust hard coded numbers to suit your the ranges.