#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)