White Matter Vibration Monitor

0 10546 Medium

Box providing insight into your machine's health and safety using vibration, current monitoring, Rfid, and cloud data logging.

projectImage

Things used in this project

 

Hardware components

HARDWARE LIST
1 DFRobot Gravity: Digital Piezo Disk Vibration Sensor
1 Particle Argon
1 RFID reader (generic)
1 ControlEverything.com Particle Electron 1 channel 20 amp current monitoring controller
1 ElectroPeak 0.96" OLED 64x128 Display Module
1 Rotary Encoder with Push-Button

Hand tools and fabrication machines

 

scrollsaw

 

Laser cutter (generic)

Story

 

The purpose of my project was to create an automated way to tell if a saw blade might need to be changed or cleaned. I used a current monitor and piezo sensor to monitor the changes in current and vibrations for a machine with a sharp blade vs. one with a dull blade. I added a Rfid reader and controllable power strip to control when a machine could be turned on. The engine won't power on unless a valid access card has been presented.

projectImage

Being able to tell when a machine might need its blade replaced is essential for any woodshop or machinist shop because of the hazards that a dull blade might cause and because a dull blade could provide uneven cuts of wood.

projectImage

My solution is to use a vibration sensor with logging to Google sheets/excel to create FFT models in Excel and STD calculations to monitor waveforms. The data logged in Google Sheets could be processed in Matlab or any vibration analysis software. My project also includes sending values to Adafruit dashboard for real-time graphing of the current and vibration values.

projectImage

Below is a graph depicting the difference in a dull blade vs a sharp blade.

projectImage

Custom parts and enclosures

 

Laser Cut Acrylic Box

projectImage

Schematics

projectImage

Code

 

White Matter Vibration Monitor

C/C++

You use a current monitor and piezo disk to monitor for variations in the system

CODE
/*
 * Project Capstone_Project
 * Description: RFID Capstone Project
 * Author: Daniel Mills
 * Date:04-13-2022
 */

//SYSTEM_MODE(SEMI_AUTOMATIC);

///////////////////////////////
//-----Include and Objects Block
#include "credential.h"                    //creddential for ada fruit dashboard
#include "math.h"
#include <Adafruit_GFX.h>                   //library for graphics
#include <Adafruit_SSD1306.h>               //library for OLED
#include <Adafruit_MQTT.h>                  //Library for publishing to Adafruit
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "clickButton.h"
#include <Encoder.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_PN532.h>

//Var for Encoder
Encoder myEnc(D2, D3);
int oldPosition;
int newPosition;
int encoderMap;

//Initialization
#define OLED_RESET D4
Adafruit_SSD1306 display(OLED_RESET);
String DateTime, TimeOnly;

//Rfid Vars
const int PN532_IRQ  = A0;
const int PN532_RESET = A1;  
Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);
uint8_t valid;

//Validation System for Rfid
uint8_t masterKey[4] = {0x13, 0x99, 0xC9, 0x1E};
uint8_t uidArray[4];
bool correctKey;
bool powerAccess;

//Button Vars
const int BUTTONPIN2 = D5;
int function = 0;


//Vars For Current and Vibration
//PECMAC125A I2C address is 0x2A(42) //Piezo is 0x50
#define Addr 0x2A
#define AddrP 0x50

//Piezo ((Pvalues)
long vibdat[4096][2];
int i;
int j;
byte dataP[2];
int raw_adc = 0;

float pSensor;         //stores the piezo sensor readings for google sheet

//Current Vars
byte data[36];
int typeOfSensor = 0;
int maxCurrent = 0;
int noOfChannel = 0;
float current = 0.0;


//Vibration Bin Sorting Values
int x, y, c, d;
static int xx, yy, cc, dd;
    
//time vars
int startTime;
int last;
int lastTime2;

//Power Strip Var
const int POWERSTRIP = A5;
int Power;  //MQTT Power Button Var
byte buf;

//Connecting to Adafruit Webservice
TCPClient TheClient; 

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. 
Adafruit_MQTT_SPARK mqtt(&TheClient,AIO_SERVER,AIO_SERVERPORT,AIO_USERNAME,AIO_KEY);

/**** Feeds *********/ 
// Setup Feeds to publish or subscribe 
Adafruit_MQTT_Publish mqttvib = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/vib");
Adafruit_MQTT_Publish mqttcurrent = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/current");
Adafruit_MQTT_Publish mqttuid = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/uid");
//Power 
Adafruit_MQTT_Subscribe mqttPower = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/Power");  

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

  attachInterrupt(D5, getMode, FALLING);
  
  //Setup For Rfid
  Serial.printf("Init Reader \n");
  nfc.begin();
  
  //////
  //Rfid
  rfidBegin();
  
  //Setting Time for button clicks -- measured in millis
  pinMode(BUTTONPIN2, INPUT_PULLUP);
  pinMode(POWERSTRIP, OUTPUT);

  //Getting Time Info -- This is for if info wanted to be recorded with the date
  Time.zone(-7);
  Particle.syncTime();

  //Connect to Wifi
  WiFi.connect();
  while(WiFi.connecting()){
    Serial.printf(".");
  }

  mqtt.subscribe(&mqttPower);  //subscribe to power button from Adafruit 

  //Sets System Access False and turns the power off
  powerAccess = false;
  digitalWrite(POWERSTRIP, LOW);

  //##Setup Information for the OLED
  display.begin(SSD1306_SWITCHCAPVCC, 0x3c);  // initialize with the I2C addr 0x3D (for the 128x64)
  display.display(); // show splashscreen

  
  display.setTextSize(1);
  display.clearDisplay();             //clears the display 
  display.setCursor(0,0);             // Start at top-left corner
  display.setTextColor(WHITE);
  display.printf("Please Scan Card");   //Outputs Switch Case
  display.display(); 

  //Setup for Reading Current and Piezo through I2C
  //Initialise I2C communication as MASTER
  Wire.begin();
  // Initialise Serial Communication, set baud rate = 9600
  Serial.begin(9600);

  //Start I2C transmission
  Wire.beginTransmission(Addr);
  //Command header byte-1
  Wire.write(0x92);
  //Command header byte-2
  Wire.write(0x6A);
  //Command 2 is used to read no of sensor type, Max current, No. of channel
  Wire.write(0x02);
  //Reserved
  Wire.write(0x00);
  //Reserved
  Wire.write(0x00);
  //Reserved
  Wire.write(0x00);
  //Reserved
  Wire.write(0x00);
  //CheckSum
  Wire.write(0xFE);
  //Stop I2C transmission
  Wire.endTransmission();

  //Request 6 bytes of data
  Wire.requestFrom(Addr, 6);

  //Read 6 bytes of data
  if (Wire.available() == 6)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
    data[2] = Wire.read();
    data[3] = Wire.read();
    data[4] = Wire.read();
    data[5] = Wire.read();
  }
  typeOfSensor = data[0];
  maxCurrent = data[1];
  noOfChannel = data[2];
}


void loop() {

  //*MQTT Start
  MQTT_connect();
  //Ping MQTT Broker every 2 minutes to keep connection alive
  if ((millis()-last)>120000) {               //function to ping the MQTT broker
      Serial.printf("Pinging MQTT \n");             
      if(! mqtt.ping()) {
        Serial.printf("Disconnecting \n");
        mqtt.disconnect();
      }
    last = millis();
  }

  //*MQTT Subscription
  Adafruit_MQTT_Subscribe *subscription;                                             //looks for MQTT subscriptions for button input to turn on motor pump
  while ((subscription = mqtt.readSubscription(100))) {                              //looks for receiving signal
     if (subscription == &mqttPower) {
        Power = atoi((char *)mqttPower.lastread);                                    //takes last data and converts it char and converts it to a float
        Serial.printf("Received %i from Adafruit.io feed Power Button \n", Power);   //prints to screen
     }
  }

  //Power Button
  if (Power == 1){    //turns off the power if input was recieved from Adafruit
    digitalWrite(POWERSTRIP, LOW);
    Serial.printf("Power was turned off \n");
  }

  ////Current Reader
  for (int j = 1; j < noOfChannel + 1; j++){
    //Commands for Reading Data
    Wire.beginTransmission(Addr);
    Wire.write(0x92);  //Command for byte-1
    Wire.write(0x6A);  //Command for byt-2
    Wire.write(0x01);
    Wire.write(j);
    Wire.write(j);
    Wire.write(0x00);
    Wire.write(0x00);
    // CheckSum
    Wire.write((0x92 + 0x6A + 0x01 + j + j + 0x00 + 0x00) & 0xFF);
    // Stop I2C Transmission
    Wire.endTransmission();
    
    // Request 3 bytes of data
    Wire.requestFrom(Addr, 3);

    // Read 3 bytes of data
    // msb1, msb, lsb  
    int msb1 = Wire.read();
    int msb = Wire.read();
    int lsb = Wire.read();
    current = (msb1 * 65536) + (msb * 256) + lsb;

    // Convert the data to ampere
    current = current / 1000;
  }
   
  rfidCardRead();

  

  ///////////////////////////////
  //Info will only show if Access is granted
  if (powerAccess == TRUE){

    //Encoder Info for Menu
    int newPosition = myEnc.read();
    if (newPosition != oldPosition) {
      function = 0;
      oldPosition = newPosition;
      if (newPosition > 20){
        myEnc.write(20);
      }
      if (newPosition < 0){
        myEnc.write(0);
      }
    }

    //maps the encoder to the Switch Case
    encoderMap = map(newPosition, 0, 20, 0, 2);

     // enter switch case
    switch(encoderMap)
    {
      //Start
      case 0: 
        if (function == 0){
          display.clearDisplay();             //clears the display 
          display.setCursor(0,0);             // Start at top-left corner
          display.setTextColor(WHITE);
          display.printf("MENU: \n->Current Read  \nVib Read \nPublish Values \n");   //Outputs Switch Case
          display.display(); 
        }
        else{
          if(function == 1){ 
            display.clearDisplay();             //clears the display 
            display.setCursor(0,0);             // Start at top-left corner
            display.setTextColor(WHITE);
            display.printf("Channel: %i \n", j);
            display.printf("Current Value: %0.2f \n", current); 
            display.display();
          }
        }
       
        // Output data to dashboard
        Serial.printf("Channel: %i \n", j);
        Serial.printf("Current Value: %0.2f \n", current); 

        //Second Click ends logging and returns to menu
        if(function == -1){ 
          Serial.printf("SINGLE LONG click \n");  //for testing
          function = 0;
          break;
        }
        Serial.printf("Function %i", function);
      break;
      //Start
      case 1: 
        Serial.printf("Function %i \n", function);

        if (function == 0){
          display.clearDisplay();      //clears the display
          display.setTextColor(WHITE);
          display.setCursor(0,0);             // Start at top-left corner
          display.printf("MENU: \nCurrent Read \n->Vib Read  \nPublish Values \n");   //Outputs Switch Case
          display.display();
        }
        else{
          piezoRead();  // function collects values from the piezo sensor
          if (function == 1){
            //12-bit Resolution output every 1 second
            if ((millis() - startTime > 1000)){
              Serial.printf("\n%i,%i\n",millis(), raw_adc);
              if(raw_adc >= 0 && raw_adc <= 25 ){
                xx = 0;
                xx = x++;
              }
              if(raw_adc >= 26 && raw_adc <= 50 ){
                yy = 0;
                yy = y++;
              }
              if(raw_adc >= 51 && raw_adc <=  75){
                cc = 0;
                cc = c++;
              }
              if(raw_adc >= 76){
                dd = 0;
                dd = d++;
              }

              display.clearDisplay();      //clears the display 
              display.setTextColor(WHITE);
              display.setCursor(0,0);             // Start at top-left corner
              display.printf("Vib Values: %i\n", raw_adc);   //Prints values to OLED
              display.printf("0-25:  %i\n", xx);   //Prints values to OLED
              display.printf("26-50: %i\n", yy);   //Prints values to OLED
              display.printf("51-75: %i\n", cc);   //Prints values to OLED
              display.printf("Vib > 76:%i\n", dd);   //Prints values to OLED
              display.display();
              startTime = millis();
            }
          }
        }

        if(function == -1){ 
          Serial.printf("SINGLE LONG click \n");  //for testing
          function = 0;
          break;
        } 
      break;
      case 2:
        Serial.printf("Function %i \n", function);

        if (function == 0){
          display.clearDisplay();      //clears the display 
          display.setTextColor(WHITE);
          display.setCursor(0,0);             // Start at top-left corner
          display.printf("MENU: \nCurrent Read \nVib Read \n->Publish Values  \n ");   //Outputs Switch Case
          display.display();
        }
        else{
          if (function == 1){  
            piezoRead();  // function collects values from the piezo sensor
            pSensor = raw_adc;  
            Particle.publish("pSensor", String(pSensor));  //reads the vibration sensor values and puts them into a var to send to google sheets
            //*Reads and Publishes Values to Adafruit 
            if((millis()-lastTime2 > 5000)) {
              if(mqtt.Update()) {  //starts MQTT updats
                mqttcurrent.publish(current);                                      //publishes the current values  Adafruit
                Serial.printf("Publishing Current %0.2f \n", current);             //prints current values to serial monitor
                mqttvib.publish(raw_adc);                                          //pub the piezo values
                Serial.printf("Publishing Vib %i \n", raw_adc);                    //prints piezo to serial monitor
                                                         
                
                //Prints Values to the OLED
                display.clearDisplay();      //clears the display 
                display.setTextColor(WHITE);
                display.setCursor(0,0);             // Start at top-left corner
                display.printf("Publishing Current: \n"); 
                display.printf("%0.2f \n", current);  
                display.printf("Publishing Vibration:"); 
                display.printf("%i \n", raw_adc); 
                //display.printf("Publishing Vib to \n"); 
                display.display();
              }
              lastTime2 = millis();
            }
          }
        }

        if(function == -1){ 
          Serial.printf("SINGLE LONG click \n");  //for testing
          function = 0;
          break;
        } 
      break;
      default:
      function = 0;
      break;
      oldPosition = encoderMap;
    }
  }
}

   

///////////////////////////
//////////////////////////
//Void Functions
//Function Starts Rfid
void rfidBegin(){
   uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata){
    Serial.printf("Didn't find PN53x board");
    while (1);
  }

  Serial.printf("\nFound chip PN5"); Serial.print((versiondata>>24) & 0xFF, HEX);
  Serial.printf("\nFirmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.printf("."); Serial.print((versiondata >>8) & 0xFF, DEC);

  nfc.SAMConfig();
  nfc.setPassiveActivationRetries(0xFF);
  Serial.printf("\nWaiting for Card \n");
}

//Function for Looping Rfid
void rfidCardRead(){
  uint8_t success;
  uint8_t uid[] = {0, 0, 0, 0, 0, 0, 0}; //Buffer to store the returned UID
  uint8_t uidLength;  //Length of the UID (4 or 7 bytes)

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
  if (success) {
    Serial.printf("\nSuccess getting target ID \n");

    // Display some basic information about the card
    Serial.printf("Card Type ISO14443A card \n");
    Serial.printf("UID Value: ");
    nfc.PrintHex(uid, uidLength);
 
    Serial.printf("............. \n");

    if (uidLength == 4){
      Serial.printf("Mifare Classic Card \n");
      Serial.printf("Authenticating Card \n");
      uint8_t keya[6] = { 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF };
	  
      success = nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keya);

      if (success){
        //Serial.printf("Sector 1 has been authenticated \n");
        uint8_t data[16];

        success = nfc.mifareclassic_ReadDataBlock(4, data);

        if(success){
          Serial.printf("Reading... \n");
          nfc.PrintHexChar(data, 16);

          correctKey = isMatched(uid, masterKey);
      
          if (correctKey == 1) {
            Serial.printf("Valid Access Card \n"); 
          }
          else{
            Serial.printf("Invalid Access Card \n"); 
          }
        }
        else{
          Serial.printf("Card Reading Error \n");
        } 
      }
    }
  }
  Serial.printf("#####BREAK######");
}

//Function for Validating master card 
bool isMatched (uint8_t uid[4], uint8_t masterKey[4]) {
  int i;
  for(i=0; i < 4; i++){
    Serial.printf("%i", uid[i]);
    
    if(uid[i] != masterKey[i] ){
      Serial.printf("*Invalid Key \n");
      Serial.printf(" \n");
      Serial.printf("Your UID Value: %i \n", uid);


      display.clearDisplay();             
      display.setTextColor(WHITE);
      display.setCursor(0,0);           
      display.printf("Invalid Key - Access Denied"); //Outputs Switch Case Access
      display.display();
      //delay(1000);

      powerAccess = FALSE;
      digitalWrite(POWERSTRIP, LOW);
      
      Serial.printf("Power strip is OFF");
      Serial.printf("PowerAccess %i \n", powerAccess);
      return false;
    }
  }
  Serial.printf("*Valid Key \n");

  display.clearDisplay();            
  display.setTextColor(WHITE);
  display.setCursor(0,0);             
  display.printf("Valid Key - Access Granted");     //Output for Switch Case access
  display.display();
 
  powerAccess = TRUE;
  digitalWrite(POWERSTRIP, HIGH);

  Serial.printf("Power strip is ON");
  Serial.printf("PowerAccess %i \n", powerAccess);
  return true;
}

//Function for changing button state
void getMode(){
  function++;
  if(function == 2){
    function = -1;
    Serial.printf("Inside -1(2c) %i \n", function);
  }
  if(function != 2){
    Serial.printf("Outide Function 0(0c) %i \n", function);
  }
}


// Function to connect and reconnect as necessary to the MQTT server.
void MQTT_connect() {  //this function is important to include for connecting to MQTT
  int8_t ret;
  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }
  Serial.print("Connecting to MQTT... ");
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
      Serial.printf("%s\n",(char *)mqtt.connectErrorString(ret));
      Serial.printf("Retrying MQTT connection in 5 seconds..\n");
      mqtt.disconnect();
      delay(5000);  // wait 5 seconds
  }
  Serial.printf("MQTT Connected!\n");   //output for if connection was successful
}

////////////////////////////
//Function For Getting Piezo Values
void piezoRead(){

  for(i=0;i<4096;i++) {
    // Start I2C transmission
    Wire.beginTransmission(AddrP);  
    // Calling conversion result register, 0x00(0)
    Wire.write(0x00);
    // Stop I2C transmission
    Wire.endTransmission();

    // Request 2 bytes
    Wire.requestFrom(AddrP, 2);
    
    // Read 2 bytes of data, raw_adc msb, raw_adc lsb
    if(Wire.available() == 2){  
      dataP[0] = Wire.read();
      dataP[1] = Wire.read();
    }
    
    // Convert the data to 12 bits
    raw_adc = ((dataP[0] * 256) + dataP[1]) & 0x0FFF;

    vibdat[i][0] = micros();
    vibdat[i][1] = raw_adc;            
  }
}

The article was first published in hackster, April 22, 2022

cr: https://www.hackster.io/daniel-mills/white-matter-vibration-monitor-7973e4

author: Daniel Mills

License
All Rights
Reserved
licensBg
0