Arduino - 12V DC Motor with constant RPM
From Blue-IT.org Wiki
Motivation
There are many manuals out there how to control large DC motors with e.g. a Mosfet or ready to install pwm boards with an arduino. In practical usage however you will be confronted with some problems using this methods in real world setups. Especially when a nearly constant revolution speed is needed.
You could use a large stepper motor to achieve this. But this could be very expensive. On the other hand the approach shown here is very simple and only needs very few skills.
Realisation
We will power an 12V wind shield motor:
- Wind shield 12V motor from an old car, get it from a scrap yard or ebay (~ 15 €)
- BTS7960 43A H-Bridge PWM - 5,5 V bis 27V and lot of amps (~ 10 €)
- OR a Mosfet Fairchild BUZ11, a big diode (6 amps), resistor 100 Ohm (see: http://bildr.org/2012/03/rfp30n06le-arduino) (~2 €)
- Power supply 12V (for LED) 80W (~ 12 €)
What we do for this is a feedback from the motor about its driving speed. We will therefore need a sensor:
- Light barrier sensor - infrared type TCST2103 (~ 2 €)
- Two resistors 100 Ohm (some cents)
- A simple self made gear wheel (costs: 0)
- Arduino
Code
const int pwmPin_Motor = 9; const int sensorPinLB_TCST2103 = A0; int minSpeed_Motor = 30; // minimum PWM to get the motor turning int increment_Motor = 5; // increment in PWM (soft speedup / - down) int actualRPM = 0; // range: 0 - 9; // theoretical speed of the motor // multiplier necessary see later in the code int actualPWM = 0; // range: 0 - 255; int pulseCount = 0; // max. Interval 0-9 when using a foiled keyboard like me int prevLBLevel = 0; // for TCST2103 // Generally, you should use "unsigned long" for variables that hold time // The value will quickly become too large for an int to store unsigned long previousMillis = 0; // will store last time of action was updated // interval at which to check pulses (milliseconds) // be careful changing: affects pulseCountExzenter! const unsigned long interval = 1000; void setup() { // lcd and other stuff // ... TCCR1B = TCCR1B & 0b11111000 | 0x01; pinMode(pwmPin_Motor, OUTPUT); pinMode(sensorPinTCST2103, INPUT); // INIT MOTOR AND TEST actualRPM = 2; // should start the motor } void loop() { // Drehgeber (pulseCount) // you have to determine in which range the TCST2103 delivers data. // in my setup ( twp 100 ohm resistors) it delivers data between 740 and 900 (theoretically 0-1023) int actLBLevel = map(analogRead(sensorPinLB_TCST2103),740,900,0,9); if ( prevLBLevel == actLBLevel ) { // wait until the next segment is comming ... } else { if (actLBLevel >= 5 && prevLBLevel < 3 ) // actual Level is High (Sensor is hidden) { pulseCount +=1; prevLBLevel = actLBLevel; } if (actLBLevel < 3 && prevLBLevel >= 5 ) // actual Level is LOW (Sensor is free) { pulseCount +=1; prevLBLevel = actLBLevel; } } //////////////////////////////////// // CHECK ONLY EVERY 1000ms (usigned interval) // check to see if it's time to do something - // the difference between the current time and last time unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // save the last time previousMillis = currentMillis; //////////////////////////////////////////////////////////////// // SpeedUP the motor according due to its possibilities // actualRPMExzenter is limited to 9 // pulseCountExzenter depends on the motor - you should reach a value // slightly above 200 - to have reserves at maximum speed pulseCountExzenter = (int)(pulseCountExzenter/1.2); int increment = increment_Motor; if (actualPWM <= 255 && actualPWM >= 0) { if ( pulseCount == actualRPM ) { // Motor speed is reached - do nothing } else { // increase speed if (pulseCount < actualRPM) { if ( actualPWM < minSpeed_Motor ) { actualPWM += minSpeed_Motor; } // almost reached, only 1 PWM steps ... else if ( pulseCount >= actualRPM-1 ) { actualPWM += 1; } // not over 255 else if (actualPWM <= ( 255 - increment ) ) { actualPWM += increment; } } // decrease speed else { if ( pulseCount <= actualRPM+1 ) actualPWM -= 1; else actualPWM -= increment; } } } analogWrite(pwmPin_Motor, actualPWM); // RESET pulseCountExzenter pulseCount = 0; // end if for interval } // end loop }