Hooked on Arduino & Raspberry Pi

Infrared Fan Speed Control

 This project demonstrates using an infrared light beam to measure the speed of a fan, and PWM to adjust the speed to a preset value.  I used a small 12 Vdc fan from a PC CPU heat sink.  It will run on 5V, somewhat slow, and drawing only about 40 mA, perfect for this project.  Although an Arduino digital output could safely drive the fan, I decided to play it safe and use a transistor.  Here's my schematic, created with TinyCAD:
The 10K Ohm pot sets the target speed.  The PWM output on pin D5 drives the transistor to regulate the motor speed.  The fan blades interrupt the infrared beam, and that generates interrupts via pin D3.  Here's the sketch:
Hooked on Arduino & Raspberry Pi/*
 IR_MotorSpeed.pde miketranch comcast.net V0.4 Feb 8, 2013
 10K pot sets desired speed 
 IR detector measures fan speed
 adjusts PWM voltage to regulate speed
 Arduino UNO pins used:
   D3  IR detector, interrupt 1
   D5  PWM output drives motor
   A0  10K pot

const int potPin = 0;    // 10K pot 5V to ground, wiper to pin A0 
const int PWMLED = 5;    // PWM output to transistor to motor
const int IR_Pin = 3;    // Hall Sensor Output on Pin 3
const int IR_Int = 1;    // Int #1 on Pin 3
volatile int count = 0;  // count interrupts from IR Sensor
void setup()
  pinMode(IR_Pin, INPUT_PULLUP); // open collector IR detector
  Serial.println(“\n\nInfrared Fan Motor Speed Control”);

void loop() { 
  // static variables remember their values
  static int PWMval; // latest attempt to set target speed 
  // regular variables are initialized each time loop() executes
  int potVal = analogRead(potPin); // read the voltage on the pot
  // map to desired speed range  
  int SetSpeed = map(potVal, 0, 1023, 50, 400); 
  if (count == 0) {      // motor stopped, kick start it
    PWMval = 254;        // full voltage and power
    Serial.println(“Full Power Start”); 
  } else {               // adjust speed
    float delta = (SetSpeed – count); // speed error
    if (delta > 0 )                   // too slow, increase voltage
      PWMval = PWMval + sqrt(delta);  // by square root of error
    else                              // too fast, decrease voltage 
      PWMval = PWMval – sqrt(-delta); // by square root of error
  PWMval = constrain(PWMval, 0, 255); // PWM must be 0 to 255
  Serial.print(“Set speed: “); Serial.print(SetSpeed);
  Serial.print(” PWM: “);      Serial.print(PWMval);
  Hooked on Arduino & Raspberry Pi schematic  analogWrite(PWMLED, PWMval);  // set the motor voltage level
  delay(1000);       // give motor time to settle to new speed
    count = 0;
  attachInterrupt(IR_Int, IR_ISR, CHANGE); 
  delay(1000);               // measure for 1 second
  detachInterrupt(IR_Int);   // disable interrupt 
  Serial.print(” Speed: “); Serial.println(count);
void IR_ISR() {
It was fun working out the math to get this sketch working well with the hardware.  The interrupt is enabled for 1 second, and counts both edges of each blade, because of the CHANGE keyword.  I empirically determined the motor could be slowed to about 40 interrupts per second, or sped up to about 420 interrupts per second.  The map function converts the 10K pot setting to a SetSpeed value in the range of 50 to 400.
For more detail: Hooked on Arduino & Raspberry Pi

About The Author

Ibrar Ayyub

I am an experienced technical writer holding a Master's degree in computer science from BZU Multan, Pakistan University. With a background spanning various industries, particularly in home automation and engineering, I have honed my skills in crafting clear and concise content. Proficient in leveraging infographics and diagrams, I strive to simplify complex concepts for readers. My strength lies in thorough research and presenting information in a structured and logical format.

Follow Us:

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top