No title

#include <Servo.h>


Servo rpmServo;


// ================= PIN =================

const byte IR_PIN = 2;

const byte SERVO_PIN = 9;


// ================= RPM SETTINGS =================

const float MAX_RPM = 10000.0;


// Shaft par 1 mark = 1 pulse

const byte PULSES_PER_REV = 1;


// ================= SENSOR FILTER =================

// 10,000 RPM par 1 pulse ≈ 6000 microseconds

// Is se kam interval ko noise samjha jayega

const unsigned long MIN_PULSE_INTERVAL = 2000;


// Agar itne time tak pulse na aaye to RPM zero hona shuru

const unsigned long NO_PULSE_TIMEOUT = 2000000UL; // 2 seconds



// ================= INTERRUPT VARIABLES =================

volatile unsigned long lastPulseMicros = 0;

volatile unsigned long pulseInterval = 0;

volatile bool newPulse = false;



// ================= RPM VARIABLES =================

float measuredRPM = 0;

float filteredRPM = 0;



// ================= SERVO VARIABLES =================

float currentAngle = 0;

float targetAngle = 0;


// Servo needle movement

// 0.5 = very smooth

const float SERVO_STEP = 0.5;


// Servo update speed

const unsigned long SERVO_UPDATE = 5;


unsigned long lastServoUpdate = 0;



// ================= RPM FILTER =================

// RPM increase speed

const float RPM_ATTACK = 0.18;


// RPM decrease speed

const float RPM_DECAY = 0.07;



// =====================================================

// IR SENSOR INTERRUPT

// =====================================================


void sensorPulse() {


  unsigned long now = micros();


  if (lastPulseMicros == 0) {

    lastPulseMicros = now;

    return;

  }


  unsigned long interval = now - lastPulseMicros;


  // Noise filtering

  if (interval >= MIN_PULSE_INTERVAL) {


    pulseInterval = interval;

    lastPulseMicros = now;

    newPulse = true;

  }

}



// =====================================================

// SETUP

// =====================================================


void setup() {


  Serial.begin(115200);


  pinMode(IR_PIN, INPUT_PULLUP);


  rpmServo.attach(SERVO_PIN);


  // Start position

  rpmServo.write(0);


  attachInterrupt(

    digitalPinToInterrupt(IR_PIN),

    sensorPulse,

    FALLING

  );

}



// =====================================================

// LOOP

// =====================================================


void loop() {


  // ===================================================

  // GET SENSOR DATA

  // ===================================================


  noInterrupts();


  unsigned long interval = pulseInterval;

  unsigned long lastPulse = lastPulseMicros;

  bool pulse = newPulse;


  newPulse = false;


  interrupts();



  // ===================================================

  // CALCULATE RPM

  // ===================================================


  if (pulse && interval > 0) {


    measuredRPM =

      (60000000.0 / interval) / PULSES_PER_REV;


    // Maximum 10,000 RPM

    if (measuredRPM > MAX_RPM) {

      measuredRPM = MAX_RPM;

    }


    // Remove tiny unwanted values

    if (measuredRPM < 5) {

      measuredRPM = 0;

    }

  }



  // ===================================================

  // NO SIGNAL DETECTION

  // ===================================================


  unsigned long currentMicros = micros();


  if (lastPulse != 0) {


    if ((currentMicros - lastPulse) > NO_PULSE_TIMEOUT) {


      measuredRPM = 0;

    }

  }



  // ===================================================

  // PROFESSIONAL NEEDLE FILTER

  // ===================================================


  // RPM going UP

  if (measuredRPM > filteredRPM) {


    filteredRPM +=

      (measuredRPM - filteredRPM) * RPM_ATTACK;

  }


  // RPM going DOWN

  else {


    filteredRPM +=

      (measuredRPM - filteredRPM) * RPM_DECAY;

  }



  // Small values ko zero

  if (filteredRPM < 1.0) {

    filteredRPM = 0;

  }



  // ===================================================

  // RPM -> SERVO ANGLE

  // ===================================================


  targetAngle =

    (filteredRPM / MAX_RPM) * 180.0;



  // Safety limits

  if (targetAngle < 0) {

    targetAngle = 0;

  }


  if (targetAngle > 180) {

    targetAngle = 180;

  }



  // ===================================================

  // SMOOTH SERVO NEEDLE

  // ===================================================


  if (millis() - lastServoUpdate >= SERVO_UPDATE) {


    lastServoUpdate = millis();



    // Needle UP

    if (currentAngle < targetAngle) {


      currentAngle += SERVO_STEP;


      if (currentAngle > targetAngle) {

        currentAngle = targetAngle;

      }

    }



    // Needle DOWN

    else if (currentAngle > targetAngle) {


      currentAngle -= SERVO_STEP;


      if (currentAngle < targetAngle) {

        currentAngle = targetAngle;

      }

    }



    // Servo position

    rpmServo.write((int)currentAngle);

  }



  // ===================================================

  // SERIAL MONITOR

  // ===================================================


  static unsigned long lastSerial = 0;


  if (millis() - lastSerial >= 200) {


    lastSerial = millis();


    Serial.print("RPM: ");

    Serial.print(filteredRPM, 0);


    Serial.print(" | Angle: ");

    Serial.println(currentAngle, 1);

  }

}

Post a Comment

Previous Post Next Post

Contact Form