RPMs with an Accelerometer Part 1(video 193)

Howdy, this is Ed Malloy again, and this article is all about the code. The gregarious Dr. S Beakman will take over when we get to the data. The editor told me this video did not go as planned, but I think you will find it interesting. We started with an internet rumor and will prove it true or false. Can you compute RPMs based on vibration? We will do a few videos trying to find out. So far, we have a good plan for collecting and displaying the data. This one may have failed, but rest assured, we will figure it out.

The Nextion display code is straightforward. Below is a list of the components I added to the HMI file.

NEXTION ELEMENTS

  • SLIDER – Contains the code to control the motor speed
  • TEXT BOX – Label of the RPM value
  • NUMBER FIELD – Display the RPMs and the PROG_STATUS variable
  • WAVEFORM – Display the vibration data
  • DUAL STATE BUTTON – Start the vibration data collection

ARDUINO NANO CODE

I am not going to cover all the code in this blog. If you have trouble understanding, comment below, and I will add more information to this post. If you need more help, select “Need Help” and get more personalized responses.

To complete this, we need to consider a couple of things. First, the vibration data will need to be collected quickly. The RPM calculation will happen whenever vibration is not being collected. I used a PROG_STATUS variable to keep track of the current status. Below is a brief description of each value of the PROG_STATUS variable.

PROG_STATUS

  • 0 – Collect the RPM data
  • 1 – Reset the accelerometer timing variables
  • 2 – Collect and store the vibration data
  • 3 – display the data and reset the varaiable back to 0

This is where we have to do the math. The editor will poke fun at my mathematical abilities. I will do my best to explain. We start by collecting the RPMs. This is done with a Hall Effect device. I have two magnets attached to the blades of the windmill. A pulse is generated as the magnets pass by the Hall Effect device. Those pulses are counted over a 1-second period of time. There are two pulses counted during each rotation. We multiply by 30 to convert from cycles per second to per minute. There are two sections of code. One to collect the pulses and an asynchronous delay set to 1000 milliseconds. The RPMs are calculated in the delay code.

PROG_STATUS = 0

PULSE COLLECTION

  if(HE_STATE != digitalRead(HE_SENSOR)){// NOTE : Did it change state?
    HE_STATE = !HE_STATE;// NOTE : Yes - change the state
    if(HE_STATE==1){// NOTE : Did it go from high to low?
      HE_COUNTER++;// NOTE : Yes - increment the counter
      //Serial.println("HE COUNTER = " + String(HE_COUNTER));
    }
  }

RPM CALCULATION

int RPM = HE_COUNTER * 30;// NOTE : use 30 because of 2 magnets
Serial.println("HE COUNTER = "+String(HE_COUNTER)+" : MOTOR RPM = "+String(RPM));
Serial2.print("n0.val=" + String(RPM) + endChar);
HE_COUNTER = 0;// NOTE : reset the counter

PROG_STATUS = 1

A value sent from the Nextion will start the process and set the PROG_STATUS to 1. The Nextion can also send a motor speed signal. In both cases, the Arduino interprets a command by a leading “C:C” and a trailing “?” delimiter. The first three characters after “C:C” are the command. The remaining characters after the command and before the “?” are the value. The value can be any length and is initially a string. You must use the toInt command to convert it to an integer. Below is the code, with notes to help explain.

dfd += char(Serial2.read());// NOTE : store one character at a time
if(dfd.length()>3 && dfd.substring(0,3)!="C:C") dfd="";// Reset dfd if not C:C
else{// NOTE : number of characters collected more than 3 and ends with ?
  if(dfd.substring((dfd.length()-1),dfd.length()) == "?"){
    // NOTE : charaters 4,5, and 6 are command. 
    //         A set command length allows a variable value length
    String command = dfd.substring(3,6);
    // NOTE : starting from 7, ending at 1 minus the length are the value
    //        this plan allows the value to be any length
    String value = dfd.substring(6,dfd.length()-1);
    // NOTE : FOR TESTING
    Serial.println(command + " : " + value);
    // NOTE : TEST COMMAND "CMD"
    if(command == "SPD"){
      analogWrite(MTR2,value.toInt());
      //Serial2.print("n0.val=" + value + endChar);
    }
    if(command == "BTN"){
      PROG_STATUS=value.toInt();
      Serial2.print("n0.val=" + value + endChar);
    }
    dfd="";
  }
}

PROG_STATUS = 2

During this step, the data is collected and stored in an array. After that, we stop collecting additional data, so the processing time is fast. In the video, I continued evaluating the state of the Hall Effect device. I think I will stop that process in the next version. In an upcoming article, the stupendous Dr. Beakman will evaluate the data for the simple-minded Sarah Jean.

// NOTE : The next four lines configure the I2C for the accelerometer   
Wire.beginTransmission(0x68);
Wire.write(0x3B);// NOTE : 0x3B for accel and 0x43 for gyro -- 0x41 for temp
Wire.endTransmission(false);//NOTE : read from bus but don't end transmission
Wire.requestFrom(0x68,4,true);
// NOTE : Read the two registers for each axis
short XRaw =  (Wire.read() << 8 | Wire.read());
short YRaw =  (Wire.read() << 8 | Wire.read());
// NOTE : Depending on the settings the Raw data needs divided by a factor
float XFloat = (float) XRaw / 8192;//16384 - original
float YFloat = (float) YRaw / 8192;//16384 - original
// NOTE : The converted values need converted to integer for the waveform
// NOTE : and stored in the array
xArray[xArrayCounter] = int((XFloat+3)*30);
xArrayCounter++;
yArray[yArrayCounter] = int((YFloat+3)*30); 
yArrayCounter++;

PROG_STATUS = 3

Writing the data to the waveform uses the Nextion “add” command. I will start with the section that writes data to the waveform on the Nextion display. I start the video by writing the values that are collected. Later I extrapolate out extra data. The “add” command is used to write to the waveform on the display. You have to know the ID of the waveform. Not the name. Below is a photo of the waveform attribute with s0 as the name and one as the ID. I have convinced our cheap-skate editor to spend a few bucks on a larger display for the next installment.

Waveform ID
ID VS. Name

The code below is used to step through the ARRAY of data for the x-axis. The “add” command has three attributes. The first is the ID. For this example, the waveform has an ID of 1. The next attribute is the channel. You can have up to 4 channels, numbered 0-3. Remember to set the number of channels in the IDE when creating the HMI file. If you do not assign enough channels, the command will not give an error, but you will not see the data. Below I use the variable xArrayCounter to step through all the data collected. I do not have a stand-alone statement to decrement the counter variable. Instead, I decrement the variable in the same command used to add to the waveform.

while(xArrayCounter>0){
  // NOTE : display actual collected data
  Serial2.print("add 1,0," + String(xArray[xArrayCounter--]) + endChar);
}

Later in the video, I added code to create intermediate steps between the collected values. The difference between the data points and divide that by 4. I use that value to create a smoother graph. There is an error in the video where I divide by four, which makes three new data points instead of four. This is better explained in the video. I will correct this in the following video. What? Did he admit an error? Humble, skilled, and willing to admit errors. I am truly that skilled.

Please download the code and have it open and ready while watching the video. If you have questions, ask in the comments below, and I will update this blog. Thanks for watching.