Arduino - 12V DC Motor with constant RPM

From Blue-IT.org Wiki

Revision as of 03:03, 6 February 2017 by Apos (talk | contribs) (Realisation)

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:

  1. Wind shield 12V motor from an old car, get it from a scrap yard or ebay (~ 15 €)
  2. BTS7960 43A H-Bridge PWM - 5,5 V bis 27V and lot of amps (~ 10 €)
  3. OR a Mosfet Fairchild BUZ11, a big diode (6 amps), resistor 100 Ohm (see: http://bildr.org/2012/03/rfp30n06le-arduino) (~2 €)
  4. 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:

  1. Light barrier sensor - infrared type TCST2103 (~ 2 €)
  2. Two resistors 100 Ohm (some cents)
  3. A simple self made gear wheel (costs: 0)
  4. Arduino

Some Tips

If you like to use it in a real world setup how to wire up your keypad or your LCD is not shown in the code.

I highly recommend using an LCD with an I2C (~ 5 €) and a I2C keypad ( e.g. a folio keypad with I2C chip for around 5 €). This saves you a lot of pins and gives you a much overall easier setup and stability.

You should also not use a mosfet but a strong H-Bridge. Also this is much easier and saver to setup. Dealing with a mosfet, diode, eventually a high capacity condensator (>2000 mF) and a heat sink which can become very hot is not easy.

I am checking ONE direction of the motor. For resolving directory change you need two light barrier sensors and a slightly more complicated code.

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
  // ...
 
  // set PWM pins 9 and 10 to 31000 MHz for better motor management
  TCCR1B = TCCR1B & 0b11111000 | 0x01;  
  pinMode(pwmPin_Motor, OUTPUT);
  pinMode(sensorPinTCST2103, INPUT);

 ///////////////////////////////////////////
 // INIT MOTOR AND TEST
 actualRPM = 2;   // should start the motor 
 ///////////////////////////////////////////

}

 
void loop() {

 // 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
}