Project showcase
Pimp up a model-railways "wind-mill"

Pimp up a model-railways "wind-mill" © LGPL

Servo, Stepper and some LED's mounted into a 1:120 model of an "old wooden corn-mill" - making the model to an "living" highlight.

  • 997 views
  • 1 comment
  • 3 respects

Components and supplies

Ard nano
Arduino Nano R3
×1
Elegoo Stepper Motor
28BYJ-48 5V Stepper Motor + ULN2003 Motor Driver Board for Arduino
×1
APM on-off-on momentary switch single-contact
or comparable
×1
31ac4603 40
Hook Up Wire Kit, 22 AWG
mainly red and blue
×1
09590 01
LED (generic)
I used one white and two orange LED*s
×3

Necessary tools and machines

About this project

Some pictures at first. To get an imagination about this very small model-building.

I'm not that familiar with "Fritzing" -sorry for that- but I tried it several times, unfortunately I did'nt find the right components in the databases and was'nt successful to download Elgoo-Parts for Fritzing from internet. So I put in a circuit diagram patchworked "Fritzing" and "paint"-graphics.

The project makes a normally still standing plastic-model-building of an "old wooden corn-wind-mill" for my model railway (1:120) moving. But not only constantly rotating blades (boring) - the mill turns the "head into the wind" -coming from different directions- and the blades are from time to time more or less fast in rotation, imaginating the wind is more or less strong. In the "night" you can switch on with pushing one single momentary button up to four times two lights in all variants. A second button is enabling or disabling the movements - 3 times pushing is switching off the servo, than the stepper and than both motors - at least both motors are on again...

All that is controled by simply to adjust servo- and stepper-speed-, angle- and time-data located in arrays. That makes the sketch easily usable for a lot of "moving models".

I did this for fun, to create an eye catcher for my model railways "surface-equipment". Have fun testing and adapting this for your needs.

Code

Code for Arduino NanoArduino
The Arduino-code used in my model. Feel free to use and modify.
/*
 * "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

Schematics

Parts and connections.
To put the real components welded into the model, keep the wiring short and well insulated.
Windmill project xhluhit5ap

Comments

Similar projects you might like

Quick RC Robot controlled by iOS app

Project showcase by Georges Giroux

  • 9,593 views
  • 5 comments
  • 22 respects

Renewing the Nikko Turbo 2 RC Car

Project tutorial by MarcoGPS

  • 4,417 views
  • 2 comments
  • 10 respects

Big Track Rover "ENHANCED EDITION" Obstacle Avoidance Bot

Project showcase by Sam

  • 1,473 views
  • 1 comment
  • 3 respects

Buzz Wire with Score Counter

Project tutorial by behrooz66

  • 7,081 views
  • 24 comments
  • 34 respects

Tobor, the Arm

Project showcase by NerdFatherRJ

  • 4,864 views
  • 1 comment
  • 7 respects

How to Make a Smart Central Lock System for Motorcycle

Project tutorial by Shubham Shinganapure

  • 3,315 views
  • 1 comment
  • 11 respects
Add projectSign up / Login