Parameter value gets changed after it is called

Hi there. First post...
First of all - thank you to all of you who share your time and expertise - MUCH appreciated.

I'm using an Arduino Grand Central M4 to control and measure the performance of a pendulum clock. I have some experience with coding, but not on Arduinos or to control hardware.

I have the code running, but want to add validation to the beam breaks that are detected by the photo sensor to filter out the occasional spurious beam break signal.

The time between the last beam break and the current one is held in testSwingTime_u. That then gets tested to see if it is within a small tolerance of the expected value. If not then the beam break gets ignored as being a false break.

The problem that I'm having is that the value of testSwingTime_u passed to the validation function
validateBeamBreak(testSwingTime_u, isLeftSwing);
IS NOT what the function then sees and uses
void validateBeamBreak(unsigned long validationTime_u, bool currentSwingIsLeft) {
I've marked it with "[####]" in the example output.

There's a bunch of other code associated with the LCD screen, data logging, GPS, etc that I have removed to simplify things, but the problem remains.

I've got other issues to sort as well - it gets stuck on checking right swings only and it always thinks its on the first, right swing - but I can sort those out myself (probably!) but I'm stuck on this change of the parameter value.

The code is attached together with sample output. I hope I have managed to comply with the guidelines for posting, apologies if I haven't.

Many, many thanks to anyone who can assist.

#include <SPI.h>
//#include <SD.h>
#include <SdFat.h>
#include <Wire.h>
#include <Adafruit_MS8607.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_MotorShield.h>
#include <RTClib.h>                 // For RTC functionality
#include <Adafruit_RGBLCDShield.h>  //Adafruit RGB LCD Shield library v1.2.2
#include <Adafruit_GPS.h>

// Objects
Adafruit_MS8607 ms8607;
//Adafruit_GPS GPS(&GPSSerial);  // Connect to the GPS on the hardware port
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *EMagnet1Left = AFMS.getMotor(1);
Adafruit_DCMotor *EMagnet2Right = AFMS.getMotor(2);
//Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
SdFat SD;
File logfile;

// hardware settings
const byte chipSelect = SDCARD_SS_PIN;  //pin for interaction with SD card
const byte photoSensorPin = 4;
const byte leftImpulseLED = 5;
const byte rightImpulseLED = 6;
const int flashDuration_ms = 0;

//run time settings
const int pulseLength_ms = 40;  // 12 is about the minimum
const int pulseInterval_s = 3;
const int logInterval_s = 6;
const int settlingTime_m = 1;      //settling time in minutes
const int runRateInterval_s = 12;  //use a multiple of the impulse cycle duration (=2 x pulseInterval_s)
const float swingTolerance = 0.004;

// elapsed time variables
float elapsedTime_s;
int elapsedDays_d;
int elapsedHours_h;
int elapsedMinutes_m;
float elapsedSeconds_s;

//timing variables
//GPS variables
unsigned long gpsDate = 0;
unsigned long gpsTime = 0;
unsigned long clockTime = 0;
unsigned long breakTime_u;
unsigned long runStartTime_u = 0;

//single swing variables
unsigned long singleSwingStartTime_u = 0;
unsigned long singleSwingEndTime_u = 0;
unsigned long singleSwingTime_u;

//window swing variables (logging window)
unsigned long windowStartTime_u = 0;
unsigned long windowEndTime_u = 0;
unsigned long windowTime_u = 0;

//amplitude variables
unsigned long amplitudeStartTime_u = 0;
unsigned long amplitudeEndTime_u = 0;
unsigned long amplitudeTime_u = 0;
unsigned long amplitudeSum_u = 0;
bool amplitudeMeasurementStarted = false;
bool beamUnbroken = false;

//run rate variables
unsigned long runRateStart_u = 0;
unsigned long runRateEnd_u = 0;
unsigned long runRate_u = 0;

// Left and right swing tracking variables
bool isLeftSwing = true;  //start from the left; after the first beam break, it's on a right swing
float lastLeftSwingTime_u = 0;
float lastRightSwingTime_u = 0;
float previousLeftSwingTime_u = 0;
float previousRightSwingTime_u = 0;

// beat error variables
float leftSwingTimes_u[10];   //array size needs to be greater than pulseInterval
float rightSwingTimes_u[10];  //array size needs to be greater than pulseInterval
int leftSwingIndex = 0;
int rightSwingIndex = 0;
float beatTimeLeft_u = 0;
float beatTimeRight_u = 0;
float beatError_u = 0;

//validation variables
bool validationActive = false;
bool breakIsValid = true;
unsigned long testSwingTime_u = 0;
bool lastPinState = LOW;
bool currentPinState = LOW;

//misc variables
int filenameHundreds;
int filenameTens;
int displayNum = 0;
unsigned long breakCount = 0;
int pulseBreakCount = 0;
volatile bool beamBroken = false;
bool pulseLeft = false;

void setup() {
  // connect at 115200 so we can read the GPS fast enough and echo without
  // dropping chars also spit it out
  Serial.begin(115200);
  /*while (!Serial) {
    ;  // wait for serial port to connect. Needed for native USB port only
  }*/
  delay(2000);
  Serial.println();
  Serial.println(F("### Starting setup ###"));

  //initializeLCD();
  pinMode(photoSensorPin, INPUT_PULLUP);  // Initialize optical sensor with interrupt
  attachInterrupt(digitalPinToInterrupt(photoSensorPin), beamBreak, FALLING);
  pinMode(leftImpulseLED, OUTPUT);
  pinMode(rightImpulseLED, OUTPUT);
  Serial.println(F("  Optical sensor             - initialized"));

  //initialize_MS8607_PHT();
  initializeMotorShield();
  Serial.println(F("### System initialized.  Ready for LEFT start ###"));
  Serial.println();
}

void loop() {
  if (beamBroken) {  //check if it is a valid break; only happens on the first pass through loop() after a beam break
    beamBroken = false;

    checkBreakIsValid();

    //Serial.println();
    Serial.print("check#2:          breakTime_u=");
    Serial.print(breakTime_u);
    Serial.print("   singleSwingEndTime_u=");
    Serial.print(singleSwingEndTime_u);
    Serial.print("   singleSwingStartTime_u=");
    Serial.print(singleSwingStartTime_u);
    Serial.print("   testSwingTime_u=");
    Serial.println(testSwingTime_u);
  }

  if (breakIsValid) {  //it is in the "blocked" phase, marked by amplitudeMeasurementStarted = true;
    beamUnbroken = false;
    breakCount++;
    amplitudeMeasurementStarted = true;

    Serial.print("chk3: validation: breakTime_u=");
    Serial.print(breakTime_u);
    Serial.print("   singleSwingEndTime_u=");
    Serial.print(singleSwingEndTime_u);
    Serial.print("   singleSwingStartTime_u=");
    Serial.print(singleSwingStartTime_u);
    Serial.print("   testSwingTime_u=");
    Serial.println(testSwingTime_u);

    singleSwingStartTime_u = singleSwingEndTime_u;
    singleSwingEndTime_u = breakTime_u;
    amplitudeStartTime_u = breakTime_u;

    Serial.print("chk4: validation: breakTime_u=");
    Serial.print(breakTime_u);
    Serial.print("   singleSwingEndTime_u=");
    Serial.print(singleSwingEndTime_u);
    Serial.print("   singleSwingStartTime_u=");
    Serial.print(singleSwingStartTime_u);
    Serial.print("   testSwingTime_u=");
    Serial.println(testSwingTime_u);

    if (breakCount == 1) {  //first beam break of the run - do some initializing
      runStartTime_u = breakTime_u;
      singleSwingEndTime_u = breakTime_u;
      windowStartTime_u = breakTime_u;
    }
  }

  if (amplitudeMeasurementStarted) {  // valid break and in the "blocked" period between break and unbreak
    // watch for the end of the blocked period
    lastPinState = currentPinState;
    currentPinState = digitalRead(photoSensorPin);

    if ((lastPinState == LOW) && (currentPinState == HIGH)) {  //reached the end of the "blocked" phase
      amplitudeEndTime_u = micros();
      beamUnbroken = true;
      amplitudeMeasurementStarted = false;
    }  //end of         if ((lastPinState == LOW) && (currentPinState == HIGH)) {  //reached the end of the "blocked" phase

    if (beamUnbroken == true) {  //only happens on the first pass through loop() after beam unbreak
      beamUnbroken = false;
      beamBroken = false;

      pulseElectromagnets();

      if (singleSwingEndTime_u > singleSwingStartTime_u) {  // calculate singleSwingTime_u
        singleSwingTime_u = singleSwingEndTime_u - singleSwingStartTime_u;
      } else {
        singleSwingTime_u = int(float(singleSwingEndTime_u) + 4294967295UL - float(singleSwingStartTime_u));
      }

      Serial.print("check#5:        ");
      Serial.print("  breakTime_u=");
      Serial.print(breakTime_u);
      Serial.print("  singleSwingEndTime_u=");
      Serial.print(singleSwingEndTime_u);
      Serial.print("  singleSwingStartTime_u=");
      Serial.print(singleSwingStartTime_u);
      Serial.print("  singleSwingTime_u=");
      Serial.print(singleSwingTime_u);

      if (isLeftSwing) {  // Track left swing durations
        // Store the previous left swing time before updating
        if (lastLeftSwingTime_u > 0) {
          previousLeftSwingTime_u = lastLeftSwingTime_u;
        }
        lastLeftSwingTime_u = singleSwingTime_u;
      } else {  // Track right swing durations
        // Store the previous right swing time before updating
        if (lastRightSwingTime_u > 0) {
          previousRightSwingTime_u = lastRightSwingTime_u;
        }
        lastRightSwingTime_u = singleSwingTime_u;
      }

      isLeftSwing = !isLeftSwing;
    }  //end of        if (beamUnbroken == true) {       //only happens on the first pass through loop() after beam unbreak
  }    // end of       if (amplitudeMeasurementStarted) {  // valid break and in the "blocked" period between break and unbreak

  if (!validationActive && ((micros() - runStartTime_u) >= 10000000UL)) {  // Enable validation 10 seconds after first beam break
    validationActive = true;
    Serial.println(F("*** Beam break validation activated ***"));
  }

  amplitudeMeasurementStarted = false;
  breakIsValid = false;
}  // end of void loop()

void beamBreak() {
  breakTime_u = micros();
  beamBroken = true;
}

void checkBreakIsValid() {
  if (validationActive) {
    testSwingTime_u = breakTime_u - singleSwingEndTime_u;  //current beam break minus previous swing end

    Serial.println();
    Serial.print("check#1:          breakTime_u=");
    Serial.print(breakTime_u);
    Serial.print("   singleSwingEndTime_u=");
    Serial.print(singleSwingEndTime_u);
    Serial.print("   singleSwingStartTime_u=");
    Serial.print(singleSwingStartTime_u);
    Serial.print("   testSwingTime_u=");
    Serial.println(testSwingTime_u);
    validateBeamBreak(testSwingTime_u, isLeftSwing);
  } else {
    breakIsValid = true;
  }
}

void validateBeamBreak(unsigned long validationTime_u, bool currentSwingIsLeft) {
  Serial.print(F("  in VBB:      validationTime_u="));
  Serial.println(validationTime_u, 6);
  breakIsValid = true;  //start with true; change to false if invalid

  if (currentSwingIsLeft) {
    float leftTolerance_u = previousLeftSwingTime_u * swingTolerance;
    Serial.print(F("  check6Left: validationTime_u="));
    Serial.print(validationTime_u, 6);

    // CLAUDE FIX: Only validate if we have a previous left swing time to compare against
    if (previousLeftSwingTime_u > 0) {
      if ((validationTime_u < (previousLeftSwingTime_u - leftTolerance_u)) || (validationTime_u > (previousLeftSwingTime_u + leftTolerance_u))) {
        breakIsValid = false;
        Serial.print(F("  Left swing rejected: "));
      } else {
        Serial.print(F("  Left swing OK: "));
      }

      Serial.print(F("validationTime_u="));
      Serial.print(validationTime_u, 6);
      Serial.print(F(", expected="));
      Serial.print(previousLeftSwingTime_u, 6);
      Serial.print(F(", difference="));
      Serial.print((validationTime_u - previousLeftSwingTime_u) / previousLeftSwingTime_u * 100, 2);
      Serial.println(F("%"));
    } else {
      // No previous left swing time available, accept the swing
      Serial.print(F("  Left swing OK (no previous): "));
      Serial.print(F("validationTime_u="));
      Serial.print(validationTime_u, 6);
      Serial.println(F(", expected=N/A (first left swing)"));
    }
  } else {
    float rightTolerance_u = previousRightSwingTime_u * swingTolerance;
    Serial.print(F("  check6Right: validationTime_u="));
    Serial.print(validationTime_u, 6);

    if (previousRightSwingTime_u > 0) {
      if (validationTime_u < (previousRightSwingTime_u - rightTolerance_u) || validationTime_u > (previousRightSwingTime_u + rightTolerance_u)) {
        breakIsValid = false;
        Serial.print(F("  Right swing rejected: "));
      } else {
        Serial.print(F("  Right swing OK: "));
      }

      Serial.print(F("validationTime_u="));
      Serial.print(validationTime_u, 6);
      Serial.print(F(", expected="));
      Serial.print(previousRightSwingTime_u, 6);
      Serial.print(F(", difference="));
      Serial.print((validationTime_u - previousRightSwingTime_u) / previousRightSwingTime_u * 100, 2);
      Serial.println(F("%"));
    } else {
      // No previous right swing time available, accept the swing
      Serial.print(F("  Right swing OK (no previous): "));
      Serial.print(F("validationTime_u="));
      Serial.print(validationTime_u, 6);
      Serial.println(F(", expected=N/A (first right swing)"));
    }
  }
}

void pulseElectromagnets() {
  pulseBreakCount++;

  // Handle electromagnet pulses
  if (pulseBreakCount == pulseInterval_s) {
    if (pulseLeft == true) {
      impulse_1_left();
    } else {
      impulse_2_right();
    }
    pulseLeft = !pulseLeft;
    pulseBreakCount = 0;
  }
}  //end of pulseElectromagnets()

// Electromagnet functions
void impulse_1_left() {
  digitalWrite(leftImpulseLED, HIGH);
  EMagnet1Left->run(FORWARD);
  EMagnet1Left->setSpeed(255);
  delay(pulseLength_ms * 1.5);
  EMagnet1Left->run(RELEASE);
  delay(flashDuration_ms);
  digitalWrite(leftImpulseLED, LOW);
}

void impulse_2_right() {
  digitalWrite(rightImpulseLED, HIGH);
  EMagnet2Right->run(FORWARD);
  EMagnet2Right->setSpeed(255);
  delay(pulseLength_ms / 1.6);
  EMagnet2Right->run(RELEASE);
  delay(flashDuration_ms);
  digitalWrite(rightImpulseLED, LOW);
}

void initializeMotorShield() {
  Serial.print("  Initializing Motor Shield");
  if (!AFMS.begin()) {
    Serial.println(F("  - Could not find Motor Shield"));
  } else {
    Serial.println(F("  - Motor Shield initialized successfully"));
  }
  EMagnet1Left->setSpeed(255);
  EMagnet1Left->run(FORWARD);
  EMagnet1Left->run(RELEASE);

  EMagnet2Right->setSpeed(255);
  EMagnet2Right->run(FORWARD);
  EMagnet2Right->run(RELEASE);
}

#########################################
EXAMPLE OUTPUT (partial)
#########################################
*** Beam break validation activated ***

check#1: breakTime_u=12005499 singleSwingEndTime_u=11005106 singleSwingStartTime_u=10005547 testSwingTime_u=1000393 [####]
in VBB: validationTime_u=33235241 [####]
check6Right: validationTime_u=33235241 Right swing OK (no previous): validationTime_u=33235241, expected=N/A (first right swing)
check#2: breakTime_u=12005499 singleSwingEndTime_u=11005106 singleSwingStartTime_u=10005547 testSwingTime_u=1000393
chk3: validation: breakTime_u=12005499 singleSwingEndTime_u=11005106 singleSwingStartTime_u=10005547 testSwingTime_u=1000393
chk4: validation: breakTime_u=12005499 singleSwingEndTime_u=12005499 singleSwingStartTime_u=11005106 testSwingTime_u=1000393

Could you explain why you are printing validationTime_u in base 6 notation?

1000393 base 10 is 33235241 base 6.

1 Like

Wonderful, wonderful, wonderful!!!
Because I didn't know!!
I thought that would print 6 decimal places (which it obviously isn't, but I didn't put 2 and 2 together to make 100 :slight_smile: )

Now that that is cleared up, I can get on with the other bugs/problems.

Thank you SO much for your help.

validationTime_u is an integer type, not a floating point type. Why would you want to print digits after the decimal place? They're always going to be zero.

Indeed they are.
I think that, originally, I had divided it by 1000000 to turn microseconds into seconds, printed with 6 decimal places. When I took out the "/1000000", I didn't take out the ", 6"
With the assistance of your previous answer, I now have that beam break validation working - so one more step forward. Thanks again.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.