I can't Calculate the exact Rpm and current. Pls check the code what i can changes should be done in my code?

#include "HX711.h"
#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <Servo.h>  // Include the Servo library

// HX711 scale connections
#define DOUT 6
#define CLK 7

// IR sensor pin
#define IR_SENSOR_PIN 2

// Current sensor pin
#define CURRENT_SENSOR_PIN A0

// LM393 comparator pin
#define LM393_PIN 8

// Calibration factor for the scale
#define CALIBRATION_FACTOR -204150.00

// Constants
#define LB2KG 453.52
#define BLADES 1  // Number of propeller blades

HX711 scale;
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Servo esc;  // Create a servo object to control the ESC

volatile unsigned long pulseCount = 0;
unsigned long previousMillis = 0; // Stores the last time we updated RPM
const unsigned long interval = 1000; // Interval at which RPM is updated (1 second)
const int PULSES_PER_ROTATION = 1; // Adjust based on your setup
const int pwmPin = A1; // Pin for reading PWM signal

char key = ' ';  // Variable to store key press

// Interrupt service routine for IR sensor
void IR_ISR() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  
  // Debounce the IR sensor
  if (interruptTime - lastInterruptTime > 11) {  // 5 ms debounce time
    pulseCount++;
    lastInterruptTime = interruptTime;
  }
}

void setup() {
  // Serial setup
  Serial.begin(115200);

  Serial.println("System started");
  Serial.println("MLX90614 IR Temperature");

  if (!mlx.begin()) {
    Serial.println("Error connecting to MLX90614 sensor. Check your wiring and try again.");
    while (1);
  }

  // HX711 setup
  scale.begin(DOUT, CLK);
  scale.set_scale(CALIBRATION_FACTOR / LB2KG);
  scale.tare(); // Zero the scale
  
  // IR sensor setup
  pinMode(IR_SENSOR_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(IR_SENSOR_PIN), IR_ISR, RISING);

  // PWM pin setup
  pinMode(pwmPin, INPUT);

  // Current sensor setup
  pinMode(CURRENT_SENSOR_PIN, INPUT);

  // LM393 comparator setup
  pinMode(LM393_PIN, INPUT);

  // ESC setup
  esc.attach(9);  // Attach the ESC to pin 9
  esc.writeMicroseconds(1000);  // Send minimum throttle signal to arm the ESC
  delay(2000);  // Wait for 2 seconds (arming delay)

  Serial.println("Setup done...");
}

void loop() {
  if (Serial.available()) {
    key = Serial.read();
    if (key == 's') {
      esc.writeMicroseconds(1000);  // Send minimum throttle signal to stop the motor
      Serial.println("Motor stopped.");
      while (true);  // Infinite loop to stop further execution
    }
  }

  // Calculate temperature
  double ambientTempC = mlx.readAmbientTempC();
  double objectTempC = mlx.readObjectTempC();

  // Print the temperatures to the serial monitor
  Serial.print("Ambient Temperature: ");
  Serial.print(ambientTempC);
  Serial.print(" °C / ");
  Serial.print("Object Temperature: ");
  Serial.print(objectTempC);
  Serial.print(" °C / ");

  // Read weight
  float weight = scale.get_units();
  Serial.print("Weight: ");
  Serial.print(weight, 3);
  Serial.println("g");

  // Read current (with averaging for better accuracy)
  const int numSamples = 20;
  long sum = 0;
  for (int i = 0; i < numSamples; i++) {
    sum += analogRead(CURRENT_SENSOR_PIN);
    delay(10);  // Small delay between samples
  }

  float averageReading = sum / numSamples;
  float voltage = averageReading * (5.0 / 1023.0); // Assuming 5V reference and 10-bit ADC
  float current = (voltage - 2.5) / 0.066; // Adjusted scaling factor based on ACS712 ELC-30A sensitivity (66mV/A)
  Serial.print("Current: ");
  Serial.print(current, 2);
  Serial.println(" A");

  // Measure RPM over a fixed interval
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    // Calculate RPM (pulses per minute)
    float rpm = (pulseCount * 60.0) / (interval / 1000.0); 
    Serial.print("RPM: ");
    Serial.print(rpm, 2);
    Serial.println(" rpm");

    pulseCount = 0; // Reset pulse count for the next interval
}

  // Measure the duration of the HIGH state of the PWM signal
  unsigned long highTime = pulseIn(pwmPin, HIGH);
  unsigned long lowTime = pulseIn(pwmPin, LOW);
  unsigned long totalTime = highTime + lowTime;

  // Calculate the duty cycle as a percentage
  float dutyCycle = (highTime * 100.0) / totalTime;

  // Print the high time, low time, and duty cycle to the serial monitor
  Serial.print("High Time: ");
  Serial.print(highTime);
  Serial.print(" us, Low Time: ");
  Serial.print(lowTime);
  Serial.print(" us, Duty Cycle: ");
  Serial.print(dutyCycle);
  Serial.println("%");

  // Read LM393 output
  int lm393Value = digitalRead(LM393_PIN);
  Serial.print("LM393 Output: ");
  Serial.println(lm393Value);

  // Set a fixed throttle value
  int throttleValue = 1100;  // Example throttle value
  esc.writeMicroseconds(throttleValue);  // Send the throttle signal to the ESC

  // Short delay
  delay(1000);
}

I moved your topic to an appropriate forum category.

In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.

This is an important part of responsible forum usage, as explained in the "How to get the best out of this forum" guide. The guide contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.


So do you need 5ms or 11ms ?

Too short and you'll have bouncing, too long and you might miss events...


this should be done in a critical section or with a copy of pulseCount as it could change during the math

I’m trying to calculate the RPM of a motor using a reflective tape and an IR sensor placed at the side view, with the motor having three blades. However, I haven't factored in the number of blades, and the RPM reading I'm getting is not as accurate as compared to a digital tachometer. I'm unsure of the exact code to write. Could you please help me with that?

the max RPM is ~5400 if you limit incrementing pulseCount to once every 11 msec and there's one pulse/ revolution. It's less if there are more pulse / revolution.

do you need to debounce a non-mechanical sensor? you said you're using a reflective IR sensor.

instead of reseting pulseCount each interval, why not capture it's value in loop() and calculate the delta since the last interval. capture it's value between calls to noInterrupts() and interrupts() to delay the ISR until after the mulitbyte value is copied

i doubt pulse needs to be unsigned long.

#include "HX711.h"
#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <Servo.h>  // Include the Servo library

// HX711 scale connections
#define DOUT 6
#define CLK 7

// IR sensor pin
#define IR_SENSOR_PIN 2

// Current sensor pin
#define CURRENT_SENSOR_PIN A0

// LM393 comparator pin
#define LM393_PIN 8

// Calibration factor for the scale
#define CALIBRATION_FACTOR -204150.00

// Constants
#define LB2KG 453.52
#define BLADES 3  // Number of propeller blades

HX711 scale;
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Servo esc;  // Create a servo object to control the ESC

volatile unsigned long pulseCount = 0;
unsigned long previousMicros = 0; // Stores the last time we updated RPM
const unsigned long intervalMicros = 1000000; // Interval at which RPM is updated (1 second in microseconds)
unsigned long lastPulseCount = 0;  // Store the previous pulse count for delta calculation
const int PULSES_PER_ROTATION = 1; // Adjust based on your setup
const int pwmPin = A1; // Pin for reading PWM signal

char key = ' ';  // Variable to store key press

// Interrupt service routine for IR sensor
void IR_ISR() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  
  // Debounce the IR sensor
  if (interruptTime - lastInterruptTime > 5) {  // 5 ms debounce time
    pulseCount++;
    lastInterruptTime = interruptTime;
  }
}

void setup() {
  // Serial setup
  Serial.begin(115200);

  Serial.println("System started");
  Serial.println("MLX90614 IR Temperature");

  if (!mlx.begin()) {
    Serial.println("Error connecting to MLX90614 sensor. Check your wiring and try again.");
    while (1);
  }

  // HX711 setup
  scale.begin(DOUT, CLK);
  scale.set_scale(CALIBRATION_FACTOR / LB2KG);
  scale.tare(); // Zero the scale
  
  // IR sensor setup
  pinMode(IR_SENSOR_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(IR_SENSOR_PIN), IR_ISR, RISING);

  // PWM pin setup
  pinMode(pwmPin, INPUT);

  // Current sensor setup
  pinMode(CURRENT_SENSOR_PIN, INPUT);

  // LM393 comparator setup
  pinMode(LM393_PIN, INPUT);

  // ESC setup
  esc.attach(9);  // Attach the ESC to pin 9
  esc.writeMicroseconds(1000);  // Send minimum throttle signal to arm the ESC
  delay(2000);  // Wait for 2 seconds (arming delay)

  Serial.println("Setup done...");
}

void loop() {
  if (Serial.available()) {
    key = Serial.read();
    if (key == 's') {
      esc.writeMicroseconds(1000);  // Send minimum throttle signal to stop the motor
      Serial.println("Motor stopped.");
      while (true);  // Infinite loop to stop further execution
    }
  }

  // Calculate temperature
  double ambientTempC = mlx.readAmbientTempC();
  double objectTempC = mlx.readObjectTempC();

  // Print the temperatures to the serial monitor
  Serial.print("Ambient Temperature: ");
  Serial.print(ambientTempC);
  Serial.print(" °C / ");
  Serial.print("Object Temperature: ");
  Serial.print(objectTempC);
  Serial.print(" °C / ");

  // Read weight
  float weight = scale.get_units();
  Serial.print("Weight: ");
  Serial.print(weight, 3);
  Serial.println(" g");

  // Read current (with averaging for better accuracy)
  const int numSamples = 20;
  long sum = 0;
  for (int i = 0; i < numSamples; i++) {
    sum += analogRead(CURRENT_SENSOR_PIN);
    delay(10);  // Small delay between samples
  }

  float averageReading = sum / numSamples;
  float voltage = averageReading * (5.0 / 1023.0); // Assuming 5V reference and 10-bit ADC
  float current = (voltage - 2.5) / 0.066; // Adjusted scaling factor based on ACS712 ELC-30A sensitivity (66mV/A)
  Serial.print("Current: ");
  Serial.print(current, 2);
  Serial.println(" A");

  // Measure RPM over a fixed interval
  unsigned long currentMicros = micros();
  if (currentMicros - previousMicros >= intervalMicros) {
    previousMicros = currentMicros;

    // Disable interrupts while capturing pulse count
    noInterrupts();
    unsigned long currentPulseCount = pulseCount;
    interrupts();

    // Calculate the delta (change in pulse count)
    unsigned long deltaPulseCount = currentPulseCount - lastPulseCount;

    // Calculate RPM (pulses per minute)
    float rpm = (deltaPulseCount * 60000000.0) / intervalMicros; 
    Serial.print("RPM: ");
    Serial.print(rpm, 2);
    Serial.println(" rpm");

    lastPulseCount = currentPulseCount;  // Update last pulse count
  }

  // Measure the duration of the HIGH state of the PWM signal
  unsigned long highTime = pulseIn(pwmPin, HIGH);
  unsigned long lowTime = pulseIn(pwmPin, LOW);
  unsigned long totalTime = highTime + lowTime;

  // Calculate the duty cycle as a percentage
  float dutyCycle = (highTime * 100.0) / totalTime;

  // Print the high time, low time, and duty cycle to the serial monitor
  Serial.print("High Time: ");
  Serial.print(highTime);
  Serial.print(" us, Low Time: ");
  Serial.print(lowTime);
  Serial.print(" us, Duty Cycle: ");
  Serial.print(dutyCycle);
  Serial.println("%");

  // Read LM393 output
  int lm393Value = digitalRead(LM393_PIN);
  Serial.print("LM393 Output: ");
  Serial.println(lm393Value);

  // Set a fixed throttle value
  int throttleValue = 1100;  // Example throttle value
  esc.writeMicroseconds(throttleValue);  // Send the throttle signal to the ESC

  // Short delay
  delay(1000);
}

I've updated the code, and now the IR sensor gives approximate values, but the problem is that when I measure the RPM using a tachometer, the values differ of motor with and without the propeller. My code is designed to detect the propeller blades. What changes can I make to ensure that the IR sensor accurately detects the motor RPM both with and without the propeller?

how is this other tachometer measuring rpm? what does it measure: sound, propeller blade somehow?

what are the difference? what are the values.

this has been clear from the start. no need to repeat it

try to provide as much data as posisble from both sets of measurements

So basically, I used a digital tachometer to measure the RPM. I pointed it at the motor with a piece of reflective tape attached to the motor shaft. When I removed the propeller and pointed the tachometer at the rotating motor, it showed around 120,000 RPM at 1200 throttle. However, when I attached the propeller, the tachometer reading dropped to 3,000-4,000 RPM. On the other hand, my IR sensor continued to show around 12,000 RPM, which created a significant discrepancy between the tachometer and the IR sensor readings.

Did the tachometer and your IR sensor ever agreed ?

What about a slow pace ?

can this be accurate? 2000 rev/sec? 1 rev every 0.5 msec?

what is the motor spec? rpm vs voltage?

is this saying it measured 12,000 with and without the propeller?

#include "HX711.h"
#include <Wire.h>
#include <Adafruit_MLX90614.h>
#include <Servo.h>

#define DOUT 6
#define CLK 7
#define IR_SENSOR_PIN 3
#define CURRENT_SENSOR_PIN A0
#define LM393_PIN 8
#define CALIBRATION_FACTOR -204150.00
#define LB2KG 453.52
#define BLADES 3

HX711 scale;
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Servo esc;

volatile unsigned long pulseCount = 0;
unsigned long previousMicros = 0;
const unsigned long intervalMicros = 1000000;
unsigned long lastPulseCount = 0;
const int PULSES_PER_ROTATION = 1;
const int pwmPin = A1;

char key = ' ';

void IR_ISR() {
  static unsigned long lastInterruptTime = 0;
  unsigned long interruptTime = millis();
  if (interruptTime - lastInterruptTime > 5) {
    pulseCount++;
    lastInterruptTime = interruptTime;
  }
}

void setup() {
  Serial.begin(115200); // Start Serial communication for debugging
  Serial2.begin(115200); // Start Serial2 to communicate with ESP32

  if (!mlx.begin()) {
    Serial.println("Error connecting to MLX90614 sensor.");
    while (1);
  }
  
  scale.begin(DOUT, CLK);
  scale.set_scale(CALIBRATION_FACTOR / LB2KG);
  scale.tare();

  pinMode(IR_SENSOR_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(IR_SENSOR_PIN), IR_ISR, RISING);
  pinMode(pwmPin, INPUT);
  pinMode(CURRENT_SENSOR_PIN, INPUT);
  pinMode(LM393_PIN, INPUT);

  esc.attach(9);
  esc.writeMicroseconds(1000);
  delay(2000);

  Serial.println("Setup done..");
}

void loop() {
  if (Serial.available()) {
    key = Serial.read();
    if (key == 's') {
      esc.writeMicroseconds(1000);
      Serial.println("Motor stopped.");
      while (true);
    }
  }

  double ambientTempC = mlx.readAmbientTempC();
  double objectTempC = mlx.readObjectTempC();
  float weight = scale.get_units();

  long sum = 0;
  for (int i = 0; i < 50; i++) {
    sum += analogRead(CURRENT_SENSOR_PIN);
    delay(10);
  }
  float averageReading = sum / 50.0;
  float voltage = averageReading * (5.0 / 1023.0);
  float offset = 2.5;
  float current = (voltage - offset) / 0.066;

  unsigned long currentMicros = micros();
  if (currentMicros - previousMicros >= intervalMicros) {
    previousMicros = currentMicros;
    noInterrupts();
    unsigned long currentPulseCount = pulseCount;
    interrupts();
    unsigned long deltaPulseCount = currentPulseCount - lastPulseCount;
    float rpm = (deltaPulseCount * 60000000.0) / intervalMicros;
    lastPulseCount = currentPulseCount;
    
    unsigned long highTime = pulseIn(pwmPin, HIGH);
    unsigned long lowTime = pulseIn(pwmPin, LOW);
    unsigned long totalTime = highTime + lowTime;
    float dutyCycle = (highTime * 100.0) / totalTime;

    int lm393Value = digitalRead(LM393_PIN);
    int throttleValue = 1100;
    esc.writeMicroseconds(throttleValue);

    // Send data to ESP32 over Serial2
    Serial2.print("Ambient Temp: ");
    Serial2.print(ambientTempC);
    Serial2.print(" °C, Object Temp: ");
    Serial2.print(objectTempC);
    Serial2.print(" °C, Weight: ");
    Serial2.print(weight, 3);
    Serial2.print(" g, Current: ");
    Serial2.print(current);
    Serial2.print(" A, RPM: ");
    Serial2.print(rpm, 2);
    Serial2.print(" rpm, Duty Cycle: ");
    Serial2.print(dutyCycle);
    Serial2.print(" %, LM393: ");
    Serial2.print(lm393Value);
    Serial2.println();
  }
  delay(1000);
}
#include <WiFi.h>

const char* ssid = "AA";
const char* password = "123456789";
WiFiServer server(80);

void setup() {
  Serial.begin(115200);     // Start Serial for debugging
  Serial2.begin(115200);    // Initialize Serial2 for communication with Arduino Mega

  // Set up the access point
  WiFi.softAP(ssid, password);
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  server.begin();
}

void loop() {
  if (Serial2.available()) {
    String data = Serial2.readStringUntil('\n');
    Serial.println("Received from Serial2: " + data); // Debug print
  }

  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        currentLine += c;
        if (c == '\n') {
          if (currentLine.length() == 2) {
            // HTTP headers
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // Send HTML response
            client.println("<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
            client.println("<body><h1>Sensor Data</h1>");
            
            // Display the buffered data
            if (Serial2.available()) {
              String sensorData = Serial2.readStringUntil('\n');
              client.println("<p>" + sensorData + "</p>");
            } else {
              client.println("<p>No data available from Serial2.</p>");
            }

            client.println("</body></html>");
            client.println();
            break;
          } else {
            currentLine = "";
          }
        }
      }
    }
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Now the problem is that although the ESP32 WROVER is connected to receive data directly from the Arduino Mega via serial communication, the data is not being transmitted to the local host. The data is correctly displayed on the ESP32's serial monitor but not on the local host. But text data like Sensor Data is showing in local host.

do you see "New Client" being printed ?

if so, in the HTML generation you go read Serial2 again

but you likely emptied that message at the start of the loop when you did

so instead of trying to read from Serial2 again, you should just pass what was read before into data

#include <WiFi.h>

const char* ssid = "AA";
const char* password = "123456789";
WiFiServer server(80);

String serialData = "";  // Global variable to store the Serial2 data

void setup() {
  Serial.begin(115200);     // Start Serial for debugging
  Serial2.begin(115200);    // Initialize Serial2 for communication with Arduino Mega

  // Set up the access point
  WiFi.softAP(ssid, password);
  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  server.begin();
}

void loop() {
  // Read data from Serial2 and store it in the global variable
  if (Serial2.available()) {
    serialData = Serial2.readStringUntil('\n');
    Serial.println("Received from Serial2: " + serialData); // Debug print
  }

  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        currentLine += c;
        if (c == '\n') {
          if (currentLine.length() == 2) {
            // HTTP headers
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // Send HTML response
            client.println("<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>");
            client.println("<body><h1>Sensor Data</h1>");
            
            // Use the stored Serial2 data
            if (serialData.length() > 0) {
              client.println("<p>" + serialData + "</p>");
            } else {
              client.println("<p>No data available from Serial2.</p>");
            }

            client.println("</body></html>");
            client.println();
            break;
          } else {
            currentLine = "";
          }
        }
      }
    }
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Still not getting Arduino data in esp32 but in serial monitor it was showing!


The screenshot is not necessary and hard to read... Just copy the text and paste it here using code tags. that will be much easier and takes less internet bandwidth....

As far as I can tell your screen shot does not show anything related to

➜ I don't see "Received from Serial2" so serialData is likely empty and thus what you see in the web interface makes sense.

what is supposed to send stuff on Serial2?

I only want to see data coming from the Arduino, such as RPM, current, weight, and temperature, on the ESP32 local host. However, it is currently only showing 'Sensor Data,' and no data is available from Serial2.

answer this question

can you clarify what your exact circuit is?

Arduino & ESP32 WROVER
RX-RX
TX-TX
GND-GND

I know that RX-TX have to connect opposite but only when if i connect in same then it only can send data in ESP32 Serial Monitor.
But not in Local Host!

the code you posted on #12 runs on the ESP I suppose.
You have some other code running on the MEGA spitting out data at 115200 bauds .

The MEGA is a 5V device. The ESP32 a 3.3V device. You need to handle the voltage difference for Arduino Tx to ESP Rx

How can i handle the voltage difference, first i upload the code in esp32 from laptop then in new sketch i upload the code of arduino from laptop.

I take it you are aware that IR sensors are very susceptible to any kind of discharge lamp lighting and sunlight.
I'd be using a hall effect and a magnet.
...............and before you say it, no, the magnet does nOT have to be on the motor shaft.
The break/no break can come from a shaft mounted metal disc with a hole in it, magnet at front, hall sensor at rear (or visa-versa)