/*
* "Servo-Angle-and-Stepper-Speed-controled-by-TimeData-Array-in-a-endless-loop"
*
* Keeps a 1:120 - "Windmill"-model moving. Turns the blades in slightly different speeds
* and is moving the blades "into the wind".
* Additional lighting makes the model visible in "nights".
*
* A servo-motor will be handled to reach certain angles after certain times.
* Working with free fillable arrays TimeSteps[] in seconds and ServoAngles[] in
* degrees between 0° and 180°.
* This will be done continously. After reaching last dataset, again start the first...
* The acting speed of the servo will be influenced in ServoSpeed[] array.
* Alternatively a momentary button is usable to shorten the times / switch
* over from one servo-angle in the dataset to the next.
*
* All times the internal LED will be kept blinking 0,5s / 0,5s.
* Monitoring via serial monitoring on PC-screen (if connected).
*
* Project Windmill by N.W.Petzold - 01-2020
*/
#include <Servo.h>
#include <Stepper.h>
// Important: Keep all times the amount of integer-values per array even to the other arrays!
// Count it carafully!
// All Timesteps will be multipied with 1000 -later- to use command "millis".
// Example with 15 data (0-14 counting) and 15 the also reset-value.
int DataCounter = 0;
int ResetCountVal = 15; // This is the amount of datasets in the arrays, for automatic restart.
int TimeSteps[] = {15,10,20,15,10,25,20,25, 10, 15, 30, 20,15,25,15}; // in seconds (millis will be calculated)
int ServoAngles[] = {90, 80,70,55,60,65,75,90,120,140,100,80,90,55,70}; // Dergrees between 0 and 180
long ServoSpeed[] = {30,50,40,30,40,50,60,70, 80, 90, 50, 30,35,40,50}; // delay between each degree in millis
int StepperSpeed[] ={30,40,30,30,30,40,50,40, 30, 30, 30, 30,45,40,40}; // value between 0 and 100
/*
* ATTENTION!
* Pin-Usage as follows:
* - Stepper: 2,3,4,5
* - LED's : 6,7
* - Servo : 10
* - Buttons: 11,12
*
*/
int ServoPin = 10; // here is the servomotor data-line connected.
Servo myservo; // create servo object to control a servo
//
const int stepsPerRevolution = 400;
Stepper myStepper(stepsPerRevolution, 2, 3, 4, 5);
//
// Variable Values permanently changing if program runs:
// SERVO
unsigned long previousSERVOMillis = 0;
unsigned long SERVOinterval = 0; // will be loaded with "TimeSteps"
unsigned long currentSERVOMillis = 0;
//
unsigned long previousAngleMillis = 0;
unsigned long AngleInterval = 0; // will be needed in the "servohandler"
unsigned long currentAngleMillis = 0;
//
// Values for keeping the internal LED constantly blinking
const int ledPin = LED_BUILTIN;
int ledState = LOW;
unsigned long previousLEDMillis = 0;
unsigned long currentLEDMillis = 0;
const long LEDinterval = 500;
//
//
int counter = 0;
int buttonState;
// adapt in the arrays the amount of Buttons you want to use.
// Reset at "2": 0/1 = On / Off --> higher reset values makes more possible with one button!
// But than the %2 (modulo 2 - command) does not work in the button-subroutine
int lastButtonState[4];
int buttonPushCounter[4]; // how often was a certain keypad-key pushed... see serial monitor
int buttonToggling[4]; //array stores button-pushes as "numbers" 0...9 or higher as you programmed till "reset" value
int buttonCountRes[ ] = {4,3,2,2}; // type in when the counter shall restart e.g. 2 for value [0] or 9 for value [3] leads to "0".
//
// Toggle-Buttons-visualisation
const int LED1 = 6; // D6 // comment out, what you do not need
const int LED2 = 7; // D7
//
// Toggled momentarily push-buttons
const int Button1 = 11; // D11
const int Button2 = 12; // D12
//
// end of declarations
//
//
void ServoHandler(int NewAngle, int LastAngle, long AngleDelay){
int AngleToBeSet;
//
currentAngleMillis = millis();
AngleInterval = previousAngleMillis + AngleDelay; // will be loaded with "TimeSteps"
if(currentAngleMillis >= AngleInterval){
if (NewAngle > LastAngle) {LastAngle++; AngleToBeSet = LastAngle; Serial.print(DataCounter); Serial.print(".Step - Servo-Angle + : "); Serial.print(AngleToBeSet); Serial.print(" Wait: [sec.] "); Serial.println(TimeSteps[DataCounter]);}
if (NewAngle < LastAngle) {LastAngle--; AngleToBeSet = LastAngle; Serial.print(DataCounter); Serial.print(".Step - Servo-Angle - : "); Serial.print(AngleToBeSet); Serial.print(" Wait: [sec.] "); Serial.println(TimeSteps[DataCounter]);}
myservo.write(AngleToBeSet);
previousAngleMillis = currentAngleMillis;
} // end if...
} // end ServoHandler
//
//
void ButtonCounter(int buttonState1, int lastButtonState1, int buttonNo) {
int x = 0;
int counter = 0;
// STATUS CHANGED
if (buttonState1 != lastButtonState1) {
if (buttonState1 == 1) {
buttonPushCounter[buttonNo]++;
if (buttonPushCounter[buttonNo] >= buttonCountRes[buttonNo]) {buttonPushCounter[buttonNo] = 0;}
//delay(20);
if (buttonPushCounter[0] == 0){digitalWrite(LED1,LOW); digitalWrite(LED2,LOW);} // Two LED's : 1 off, 2 off
if (buttonPushCounter[0] == 1){digitalWrite(LED1,HIGH);digitalWrite(LED2,LOW);} // 1 on 2 off
if (buttonPushCounter[0] == 2){digitalWrite(LED1,LOW); digitalWrite(LED2,HIGH);} // 1 off 2 on
if (buttonPushCounter[0] == 3){digitalWrite(LED1,HIGH);digitalWrite(LED2,HIGH);} // Reset is 4, 1 on 2 on
//
if (buttonPushCounter[0] == 0){Serial.println("LED1 Off / LED2 Off");}
if (buttonPushCounter[0] == 1){Serial.println("LED1 ON / LED2 Off");}
if (buttonPushCounter[0] == 2){Serial.println("LED1 Off / LED2 ON");}
if (buttonPushCounter[0] == 3){Serial.println("LED1 ON / LED2 ON");}
//
if (buttonPushCounter[1] == 0){Serial.println("Servo and Stepper moving");}
if (buttonPushCounter[1] == 1){Serial.println("Servo OFF Stepper moving");}
if (buttonPushCounter[1] == 2){Serial.println("Servo OFF Stepper OFF");}
//
} // end if buttonstate ==1 ...
} // end if buttonstate != ...
lastButtonState[buttonNo] = buttonState1;
} // End of button handling sequence.
//
void setup() {
// Internal LED
pinMode(ledPin, OUTPUT);
pinMode(LED1,OUTPUT);
pinMode(LED2,OUTPUT);
pinMode(Button1,INPUT);
pinMode(Button2,INPUT);
currentLEDMillis = millis();
currentSERVOMillis = millis();
// Servo-Motor
pinMode(ServoPin, OUTPUT);
myservo.attach(ServoPin); // attaches the servo on pin 9 to the servo object
//
// Buttons
buttonState = 0;
lastButtonState[0] = 0;
lastButtonState[1] = 0;
//
// Serial Monitor
Serial.begin(9600);
Serial.println("Program started.");
//
DataCounter = 0;
} // end of "setup()"
void loop() {
// put your main code here, to run repeatedly:
// Buttons
buttonState = digitalRead(Button1);
ButtonCounter(buttonState, lastButtonState[0], 0);
buttonState = digitalRead(Button2);
ButtonCounter(buttonState, lastButtonState[1], 1);
/* Change here the "usage of the lights" as you may need:
* for "on/off"-(TOGGLING)-only the "buttonCountRes" shall be 2.
* if (buttonToggling[0] == 0){digitalWrite(LED1,LOW);}
* if (buttonToggling[0] == 1){digitalWrite(LED1,HIGH);}
* ... and so one for the other buttons[1]...[3]
*/
// Now go though Datasets: start at zero till "ResetCountVal"...
currentSERVOMillis = millis(); // actual "running time" value
//
SERVOinterval = (TimeSteps[DataCounter]*1000); // Value from Array will be prepared for "millis"-comparison
if (currentSERVOMillis - previousSERVOMillis >= SERVOinterval) { // if interval is over, do something
previousSERVOMillis = currentSERVOMillis;
/* Servo handling:
* The servo handling has to be outside of this IF-loop!
* Because here we do not act as fast as possible - with only one value to be set.
* We act with variable speed with short break between each degree, till target-angle is reached.
* myservo.read(); gives the actual (written-)position on arduino output-pin.
* The target-position is in the array at actual counter position ServoAngles[DataCounter].
* The "speed" is the waiting time between the single servo steps to make the moving more or less slowly.
*/
//
// Next Dataset / Reset if end of array reached.
DataCounter++;
if (DataCounter>=ResetCountVal){DataCounter=0;}
} // closing "if"
// Blocking or Enabling Movement of SERVO...
if (buttonPushCounter[1] == 0){ // if buttonPushCounter is not 1 or 2 Servo is moving
ServoHandler(ServoAngles[DataCounter],myservo.read(),ServoSpeed[DataCounter]);
}
// end of Servo handling
//
// STEPPER Handling
// Blocking or Enabling Movement of STEPPER...
if (buttonPushCounter[1] == 0 or buttonPushCounter[1] == 1) { // if buttonPushCounter is 2 Stepper is moving
myStepper.setSpeed(StepperSpeed[DataCounter]);
myStepper.step(stepsPerRevolution / 100);
}
// Stepper handling finished.
//
// Internal LED handling:
currentLEDMillis = millis();
if (currentLEDMillis - previousLEDMillis >= LEDinterval) {
previousLEDMillis = currentLEDMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
} // closing else...
} // closing "if..."
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
// internal LED handling finished
//
} // end of "loop()" routine
Comments
Please log in or sign up to comment.