Variable Not Updating

My group and I are finishing up our engineering capstone project in which we created and automated control system for a ball valve on a reaction turbine. We have programmed a stepper motor as our actuator and a LIDAR sensor to provide system feedback to the Arduino. We have also programmed 2 push buttons to allow user input and an LCD module to display the system data. However, the data from the sensor does not seem to be updating in a reasonable time which cause instability of the actuator since it works based on the data received by the sensor. We have conducted tests with different codes and have concluded that it is most likely a problem with our code as our system works fine with different code. Does anyone know what the issue could be? The code is posted below:

//LIBRARIES-----------------------------------------------------------------------------------------------------------------------------------------------------------


//Sensor:
#include <SoftwareSerial.h> //Library for Sensor.
#include <LiquidCrystal_I2C.h> //Library for LCD.


//Intializations------------------------------------------------------------------------------------------------------------------------------------------------------


//LCD:
LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD address to 0x27 for a 16 chars and 2 line display.
//SDA (Yellow Wire) is Pin A4.
//SCL (Purple Wire) is Pin A5.


//Sensor:
SoftwareSerial Serial1(2,3); //Defines the pins used for the LIDAR sensor.
//SCL(or TXD) (Green Wire) is Pin 2.
//SDA(or RXD) (White Wire) is Pin 3.


int dist; // Initializes "dist" variable as integer.
int check; // Initializes "check" variable as integer.
int uart[9]; //Initializes "uart" protocol for sensor.
int j; //Initializes counter variable "j" for sensor as an integer.
float setPoint = 1; //Initializes "setPoint" value as a float.
float realPoint = 0; //Initializes "realPoint" value as a float.
const int HEADER = 0x59; //Initializes "HEADER" variable for sensor as an integer.


//Stepper Motor:
int i = 0; //Initializes counter variable "i" for stepper motor as an integer.


//Buttons:
const float  Up_buttonPin   = 6; // Initializes button on the right as the "UP" button.
const float  Down_buttonPin = 7; // Initializes button on the right as the "UP" button.
float buttonPushCounter = 0; //Counter for the number of button presses.
float up_buttonState = 0; //Current state of the up button.
float up_lastButtonState = 0; //Previous state of the up button.
float down_buttonState = 0; //Current state of the up button.
float down_lastButtonState = 0; //Previous state of the up button.
bool bPress = false; //Initializes boolean statement determining the state of the buttons.




//SETUP--------------------------------------------------------------------------------------------------------------------------------------------------------------


void setup() {
  
 //LCD and Printing:
 Serial.begin(115200); // Initialize serial communication with computer at 115200 baud:
 Serial1.begin(115200); // Initialize serial communication with computer at 115200 baud:  
 lcd.init();  // Initialize the LCD.
 lcd.backlight();  // Initialize the backlight.


 //Buttons:
 pinMode( Up_buttonPin , INPUT_PULLUP); 
 pinMode( Down_buttonPin , INPUT_PULLUP);
}


//UP BUTTON-----------------------------------------------------------------------------------------------------------------------------------------------------------


void checkUp()
{
  up_buttonState = digitalRead(Up_buttonPin); 
  if (up_buttonState != up_lastButtonState) { //Compare the buttonState to its previous state.
    if (up_buttonState == LOW) { // If the state has changed, increment the counter.
        bPress = true;
      //If the current state is HIGH then the button went from off to on:
     buttonPushCounter = buttonPushCounter + 0.2; //Increase the number of the counter by 0.2 each button press.
    } else { 
      //If the current state is LOW then the button went from on to off:
    }
   delay(10); //Delay a little bit to avoid bouncing.
  }
  up_lastButtonState = up_buttonState; //Save the current state as the last state, for next time through the loop.
}


//DOWN BUTTON-----------------------------------------------------------------------------------------------------------------------------------------------------------


void checkDown()
{
  down_buttonState = digitalRead(Down_buttonPin); 
  if (down_buttonState != down_lastButtonState) { //Compare the buttonState to its previous state.
    if (down_buttonState == LOW) { //If the state has changed, increment the counter.
        bPress = true;
      //If the current state is HIGH then the button went from off to on:
      buttonPushCounter = buttonPushCounter - 0.2; //Increase the number of the counter by 0.2 each button press.
    } else {
      //If the current state is LOW then the button went from on to off:
    }
    delay(10); // Delay a little bit to avoid bouncing.
  }
  down_lastButtonState = down_buttonState; //Save the current state as the last state, for next time through the loop.
}


//LOOP-------------------------------------------------------------------------------------------------------------------------------------------------------------------


void loop() {


 //Buttons:
 checkUp(); //Implements up button code into the loop.
 checkDown(); //Implements down button code into the loop.


 if( bPress){ // If stament for when either button is pressed.
   bPress = false;
   setPoint = setPoint + buttonPushCounter; //Adds or subtracts 0.2 from Set Point value based on which button is pressed.
   }
   
 //Sensor:
  if (Serial1.available())
   {
     if(Serial1.read()==HEADER)
     {
        uart[0]=HEADER;
        if(Serial1.read()==HEADER)
        {
         uart[1]=HEADER;
        }
        for(j=2;j<9;j++)
        {
         uart[j]=Serial1.read();
        }
        check=uart[0]+uart[1]+uart[2]+uart[3]+uart[4]+uart[5]+uart[6]+uart[7];
       
        if (uart[8]==(check&0xff)) 
        {
         dist=uart[2]+uart[3]*256;
         delayMicroseconds(25);
        }
     }
   }
 //LCD and Printing:
 Serial.print("Set MAF="); //Displays Set Point MAF in kg/s.
 Serial.print(setPoint);
 Serial.print('\t');


 Serial.print("Real MAF="); //Displays Real Point MAF in kg/s
 Serial.print(-0.305*(dist)+12.2);
 Serial.print('\t');


 Serial.print("Error="); //Displays Error between Set Point and Real Point
 Serial.print(setPoint-realPoint);
 Serial.print('\t');
 delay(25); //Delay to slow down serial monitor.
        
 lcd.setCursor(1, 0); // Sets the cursor at the beginning of the first line on display.
 lcd.print("Set MAF: ");  // Print a message to the LCD.
 lcd.print(setPoint);  // Print a message to the LCD.
 lcd.setCursor(0, 1); // Sets the cursor at the beginning of the second line on display.
 lcd.print("Real MAF: ");  // Print a message to the LCD.
 lcd.print(realPoint, 1);  // Print a message to the LCD.




 //Stepper Motor:
 realPoint = -0.305*(dist)+12.15; //Equation to convert sensor data (cm) to mass air flow rate data (kg/s) and sets it as the real point for calculation.


 /* The following if and for statements are used to control the motor based on the set point. The statements drive the motor towards the set point by trying 
 to get the error between the set point and real point lower than +/-0.2 kg/s.
 */ 
 
 if (setPoint-realPoint >= 0.2){
   digitalWrite(4, HIGH);
     for (i = 0; i <= 2; i++)
      {
      digitalWrite(5,HIGH);
      digitalWrite(5,LOW);
      delayMicroseconds(60);
      }
 }
  else if (setPoint-realPoint <= -0.2){
   digitalWrite(4, LOW);
     for (i = 0; i <= 2; i++)
      {
      digitalWrite(5,HIGH);
      digitalWrite(5,LOW);
      delayMicroseconds(60);
      }  
  }
}

I think your sensor serial read has problems.

Can you explain (or better yet, attach or link to the datasheet for) the sensor or device that's generating the serial data?

Does it send two headers as the first two bytes of the message?

This is not helping matters at all. delay(25); //Delay to slow down serial monitor.

-jim lee

You check if there is something (at least 1 byte) waiting in the serial buffer but you read many

 if (Serial1.available())
   {
     if(Serial1.read()==HEADER)
     {
        uart[0]=HEADER;
        if(Serial1.read()==HEADER)
        {
         uart[1]=HEADER;
        }
        for(j=2;j<9;j++)
        {
         uart[j]=Serial1.read();
        }

so you might read stuff that has not arrived yet...

I would suggest to study Serial Input Basics to handle this

Note that 115200 might be too fast for reliable Communication with SofttwareSerial. Using a hardware serial port would be better (any arduino MEGA available?)

(Float for pins number is not the best type... use const byte)

Re: Variable Not Updating
Too many of your variables are not doing what they should, like counting integers, or recording just 2 states ... instead, they're just "floating".

You can try a state-machine approach to receiving your serial messages; pop in, process any characters waiting and then pop out. When you've received the whole complete message and it checks out then you actually do something.

The attached compiles but isn't tested. It's a modification of your existing code so if there are deficiencies elsewhere in the code it doesn't address those.

sketch_dec17b.ino (9.28 KB)

You may wish to review your comments before submission.
You have comments that variables are "initialized" when in fact you've left the initialisation up to crt0.
Also, both serial ports do not connect to the computer (I assume).

On the whole, I'd say you've over-commented the obvious stuff, and under-commented the not-so obvious stuff.

const float Up_buttonPin = 6; This will lose you marks.

It is a serious mistake to use "float" for these variables, although the code might conceivably work. Choose the appropriate variable type for the intended action.

float buttonPushCounter = 0; //Counter for the number of button presses.
float up_buttonState = 0; //Current state of the up button.
float up_lastButtonState = 0; //Previous state of the up button.
float down_buttonState = 0; //Current state of the up button.
float down_lastButtonState = 0; //Previous state of the up button.

You might find it helpful to check out some of my tutorials on multi-tasking in arduino which has a stepper motor controlled by user input as an example and on using Serial Txt I/0 in the Real World which covers getting commands and printing debug messages without delaying the rest of your loop code.
Those tutorials also cover using a loopTimer to see how fast/slow your code is running.
You might fine the LCD a bit slow.

To debounce your switch inputs look at
https://www.forward.com.au/pfod/ArduinoProgramming/DebouncedSwitch/DebouncedSwitch.html

The reason why float is a real bad variable-type for "natural" numbers is that floats aren't exact.

It's possible. Floating point numbers are represented in an exponential notation (a*2^n), where some bits represent a (the significand), and some bits represent n (the exponent).
You can't uniquely represent all the integers in the range of a floating point value, due to the so-called pigeonhole principle. For example, 32-bit floats go up to over 10^38, but on 32 bits you can only represent 2^32 values - that means some integers will have the same representation.
Now, what happens when you try to, for example, do the following:

x = 10^38 - (10^38 - 1)

You should get 1, but you probably won't, because 10^38 and 10^38-1 are so close to each other that the computer has to represent them the same way. So, your 1.0f will usually be 1, but if this 1 is a result of calculation, it might not be.

here

are some examples

so for now and forwever for defining constats that shall represent "natural" numbers like 1,2,3,4,5....
use byte, int, long.

IO-pins are definitly "natural" full numbers 1, 2, 3, 4
and not 1,00001 etc.

//Buttons:[color=#222222][/color]
const byte Up_buttonPin   = 6; // Initializes button on the right as the "UP" button.[color=#222222][/color]
const byte  Down_buttonPin = 7; // Initializes button on the right as the "UP" button.[color=#222222][/color]
int buttonPushCounter = 0; //Counter for the number of button presses.[color=#222222][/color]
byte up_buttonState = 0; //Current state of the up button.[color=#222222][/color]
byte up_lastButtonState = 0; //Previous state of the up button.[color=#222222][/color]
byte down_buttonState = 0; //Current state of the up button.[color=#222222][/color]
byte down_lastButtonState = 0; //Previous state of the up button.

Your code uses some hardcoded numbers like here

 if (setPoint-realPoint >= 0.2){
   digitalWrite(4, HIGH);
     for (i = 0; i <= 2; i++)
      {
      digitalWrite(5,HIGH);
      digitalWrite(5,LOW);
      delayMicroseconds(60);
      }
 }
  else if (setPoint-realPoint <= -0.2){
   digitalWrite(4, LOW);
     for (i = 0; i <= 2; i++)
      {
      digitalWrite(5,HIGH);
      digitalWrite(5,LOW);
      delayMicroseconds(60);
      }  
  }
}

to make it easier to maintain and less error-prone you should use constants for IO-pins
if you use constants there is only one place to change the number and all places where the number should be changed are changed.

and using self-explaining names make it easier to understand the code

const byte Dir_Pin  = 4;
const byte Step_Pin = 5;

You should read the datasheet of the stepper-driver how long the minimum-pulse-length for step-pulses must be for reliable detection of the step-pulses. Usually in the range of 5 microseconds

 if (setPoint-realPoint >= 0.2){
   digitalWrite(Dir_Pin, HIGH);
   
     for (i = 0; i <= 2; i++)
     {
        digitalWrite(Step_Pin,HIGH);
        // are you sure that the pulse to the stepper-driver is long enough with just low high right after each other?
        // I guess there should be a delay of 10 microseconds just to make sure the pulse is long enough for reliable detection
        delayMicroseconds(10);
        digitalWrite(Step_Pin,LOW);
        delayMicroseconds(50); //same time over all delayMicroseconds(60);
     }
 }
  else if (setPoint-realPoint <= -0.2){
   digitalWrite(Dir_Pin, LOW);
     for (i = 0; i <= 2; i++)
     {
        digitalWrite(Step_Pin,HIGH);
        // are you sure that the pulse to the stepper-driver is long enough with just low high right after each other?
        // I guess there should be a delay of 10 microseconds just to make sure the pulse is long enough for reliable detection
        delayMicroseconds(10);
        digitalWrite(Step_Pin,LOW);
        delayMicroseconds(50); //same time over all delayMicroseconds(60);
     }  
  }

and you should test your whole system real thoroughly for all kinds of errors.
too high volume-flow
no volume-flow at all
LIDAR-sensor mis-aligned
levers dis-adjusted
etc. etc. etc.
right now your code assumes everything runs always within secure borders.

best regards Stefan

Can you please explain in detail how the feedback of the lidar-sensor is working?
You have a ball valve that is turned by the stepper-motor. Good choice for adjusting the valve-position in small steps.

But how dos the feedback work? A LIDAR-sensor measures distance through measuring Time of Flight (ToF)
How does measuring a distance relate to the volumen-flow-rate ?

best regards Stefan