So you're a Noob? Post your questions here until you graduate! Don't be shy.

User avatar
By MaKinItRight
#74444 Hey guys,

I am currently working on a project in our company where I would like to use micro controllers to count produced parts and send the data via MQTT. So far I am trying it with NodeMCUs due to its simple wifi capabilities and the mySensors library. The NodeMCU is attached to one of the pulse generators (e.g. a cutter or welder) and the NodeMCU receives that signal but it seems like it is counting too many signals (like doubling the real value) and I cannot figure out why.

The highes frequency of pulses (produced parts) I have to deal with are about 2 - 3 per second.

I use the following sketch for it:

Code: Select all// Enable debug prints to serial monitor
#define MY_DEBUG

// Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h
#define MY_BAUD_RATE 9600

#define MY_GATEWAY_MQTT_CLIENT
#define MY_GATEWAY_ESP8266

#define MCU_ID redacted

// Set MQTT client id
#define MY_MQTT_CLIENT_ID MCU_ID

// Set this node's subscribe and publish topic prefix
#define MY_MQTT_PUBLISH_TOPIC_PREFIX redacted
#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX redacted

// Enable these if your MQTT broker requires username/password
#define MY_MQTT_USER redacted
#define MY_MQTT_PASSWORD redacted

// Set WIFI SSID and password
#define MY_ESP8266_SSID redacted
#define MY_ESP8266_PASSWORD redacted

// MQTT broker ip address.
#define MY_CONTROLLER_URL_ADDRESS redacted

// The MQTT broker port to to open
#define MY_PORT 1883

#include <ESP8266WiFi.h>
#include <MySensors.h>
#include <Bounce2.h>

#define CHILD_ID 1
#define BUTTON_PIN  3

#define LEDRED 16
#define LEDGREEN 0

Bounce debouncer = Bounce();
int oldValue=-1;

MyMessage msg(CHILD_ID,V_STATUS);
MyMessage msgCount(CHILD_ID,I_LOG_MESSAGE);
MyMessage msgHeartbeat(CHILD_ID,I_HEARTBEAT_RESPONSE);

int countHeartbeat = 0;

void setup()   
{

  // Setup the button
  pinMode(BUTTON_PIN,INPUT);
  // Activate internal pull-up
  digitalWrite(BUTTON_PIN,HIGH);

  // After setting up the button, setup debouncer
  debouncer.attach(BUTTON_PIN);
  debouncer.interval(5);

  countHeartbeat = 0;

  //Setup the Pulse LED
  pinMode(LEDRED, OUTPUT);

  //Setup the Status LED
  pinMode(LEDGREEN, OUTPUT);
  digitalWrite(LEDGREEN, HIGH);
}

void presentation() {

  sendSketchInfo(MCU_ID, "1.0");
  present(CHILD_ID, S_BINARY);
  //present(HEARTBEAT_ID, S_BINARY);
}


//  Check if digital input has changed and send in new value
void loop()
{
  debouncer.update();
  // Get the update value
  int value = debouncer.read();
  countHeartbeat ++;
  if(countHeartbeat >= 1155000){
    //Serial.println("Heartbeat");
    send(msgHeartbeat.set(1));
    countHeartbeat = 0;
  }
 
  if (value != oldValue) {
     // Send in the new value
     send(msg.set(value==HIGH ? 0 : 1));
     oldValue = value;
     if ( value == 1) {
        //Serial.println("Off");
        digitalWrite(LEDRED, LOW);
        delay(30);
     } else {
        //Serial.println("On");
        digitalWrite(LEDRED, HIGH);
     }
     
  }
  //send(heartbeat.set(value==1));
}



I appreciate any hint or comment and if you know a simpler way to meet the requirements, I am more than happy to try that. :cry:
User avatar
By PuceBaboon
#74460 Your debounce.interval() setting of 5ms seems rather short. Have you tried setting it to something much bigger; 50, 100 or even 200 and checking the result?

I'm assuming that you're getting a direct logic input from the machine to the GPIO and it's not actually a physical button or switch. If that's the case then there's a very good chance (welders and cutters) that you're getting a lot of noise on the input (rather than signal bounce), in which case Pablo2048's suggestion of a low-pass filter on the input is spot on (and maybe add some clamping diodes, too).
User avatar
By MaKinItRight
#74470 Thank you so much, I really appreciate it.

I have completely rewritten the sketch so that there is less overhead. Let me know what you think. I also changed the debounce interval. I am currently fiddling around with protothreading as the reconnection processes (MQTT, WIFI) block my "counting".

Code: Select all#include <ESP8266WiFi.h>
#include <Bounce2.h>
#include <PubSubClient.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

// Sensor ID
const char* node_id = "redacted";

// Wifi Connection
//const char* ssid = "redacted";
//const char* password = "redacted";

const char* ssid = "redacted";
const char* password = "redacted";

// MQTT Config
const char* mqtt_server = "redacted";
const char* mqtt_user = "redacted";
const char* mqtt_pass = "redacted";

const char* mqtt_publish = "redacted";
const char* mqtt_subscribe = "redacted";

const char* mqtt_topic_heartbeat = "redacted";
const char* mqtt_topic_pulse = "redacted";
const char* mqtt_topic_count = "redacted";

//LED definition
#define LEDRED 0
#define LEDGREEN 16

//Machine input definition
#define MACHINE_PIN  3

//Bounce definition
Bounce debouncer = Bounce();
int oldInput = -1;

//Setup NTP
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org");

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
long lastTry = 0;
char msg[50];
int value = 0;
int count = 0;

void setup() {

  Serial.begin(9600);
 
  // Setup the machine
  pinMode(MACHINE_PIN, INPUT);
  // Activate internal pull-up
  digitalWrite(MACHINE_PIN, HIGH);

  // After setting up the input, setup debouncer
  debouncer.attach(MACHINE_PIN);
  debouncer.interval(200);

  //Setup the Pulse LED
  pinMode(LEDRED, OUTPUT);

  //Setup the Status LED
  pinMode(LEDGREEN, OUTPUT);

  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi() {

  delay(2);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  digitalWrite(LEDGREEN, HIGH);
  digitalWrite(LEDRED, HIGH);
  delay(100);
  digitalWrite(LEDGREEN, LOW);
  digitalWrite(LEDRED, LOW);

  timeClient.begin();
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

void reconnect() {
  // Loop until we're reconnected
//  while (!client.connected()) {
  long now = millis();
  if(now - lastTry > 5000){
    lastTry = now;
    Serial.print(timeClient.getFormattedTime() + " - ");
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(node_id, mqtt_user, mqtt_pass)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(mqtt_publish, node_id);
     
      // ... and resubscribe
      client.subscribe(mqtt_subscribe);
      digitalWrite(LEDGREEN, HIGH);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
//      // Wait 5 seconds before retrying
//      delay(5000);
    }
  }
}
void loop() {
//  Serial.println(timeClient.getFormattedTime());
  if (!client.connected()) {
    digitalWrite(LEDGREEN, LOW);
    reconnect();
  }
  client.loop();

 
  //get current state of machine
  debouncer.update();
  // Get the update value
  int input = debouncer.read();
 
  if (input != oldInput) {
    oldInput = input;
    if ( input == 0) {
      count ++;
      Serial.println("On");
      digitalWrite(LEDRED, HIGH);
      if(!client.publish(mqtt_topic_pulse, "1")){
        Serial.println(timeClient.getFormattedTime() + " - Publish failed");
      }
      String tmp = String(count);
      client.publish(mqtt_topic_count, (char*) tmp.c_str());
   } else {
      Serial.println("Off");
      digitalWrite(LEDRED, LOW);
   }
   if (count >= 100000){
      count = 0;
    }
  }

  //Sync NTP
  timeClient.update();

  long now = millis();
  if (now - lastMsg > 30000) {
    lastMsg = now;
    ++value;
    snprintf (msg, 75, "connected", value);
    Serial.print(timeClient.getFormattedTime());
    Serial.println(" - Heartbeat");
    client.publish(mqtt_topic_heartbeat, "1");
  }
}


Can you tell me what else I can do to improve the code regarding false signals or signal processing in general for my use case? And would you be so kind to point me towards what hardware components you would recommend to improve the system?

As I would like to test this sensor in two plants (Europe and America), will I face issues due to different voltages and frequencies? I am currently using the USB power plugs and attach the node mcu (GPIO3) to the machine's pulse generator. Although I was thinking about using the node's VIN instead of the USB port - with a voltage regulator so that the node mcu can be powered regardless of the input voltage (e.g. 120V). Does that make sense to you?

Please bare with me, I am highly interested and willing to learn and understand, but it's not my actual field.

Thanks again.