Difficulty coding for motor control

I’m a novice learning on the fly and I’ve been reading as much as my brain can absorb but I’m completely flummoxed. I’m trying to control a conveyor’s position by moving a pulley, based on and average value from an analog sensor. My first headache involved “negative” values of an unknown origin that were mucking up my control comparisons but I reluctantly used absolute values and some floats to get rid of that. My control values are nice and stable now but I cant get the conditional outputs for the stepper motor to work. It always executes the “else if” part of the logic, regardless of the relationship between the process value and the set-point, so the motor only goes one direction. I’m probably doing something remedially stupid but I can’t find it. I’ve attached the code. Admittedly, I’m a little lazy with annotations but it should be pretty straightforward. I’d appreciate any guidance that I can get but please try to contain the impulses to heap abuse: I’m already feeling plenty stupid.

Thanks,

conveyor.txt (2.44 KB)

#include <Stepper.h>

const int ppr = 100; // pulses per revolution
const int numReadings = 50;
const float setpoint = 2.2500;
Stepper myStepper(ppr, 4, 5, 6, 7);


int readings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average
int inputPin = A8;
int sensorValue = analogRead(A8);

float averageVoltage = average * (5.000 / 1023.00);
unsigned long previousMillis1 = 0;
long interval1 = 500;
unsigned long previousMillis2 = 0;
long interval2 = 48000;


void setup() {
  // initialize serial communication with computer:
  Serial.begin(9600);
  myStepper.setSpeed(60);
  // initialize all the readings to 0:
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis1 > interval1) {
    previousMillis1 = currentMillis;
  }
  if (previousMillis1 == currentMillis) {

    // subtract the last reading:
    total = total - readings[readIndex];
    // read from the sensor:
    readings[readIndex] = analogRead(A8);
    // add the reading to the total:
    total = total + readings[readIndex];
    // advance to the next position in the array:
    readIndex = readIndex + 1;

    // if we're at the end of the array...
    if (readIndex >= numReadings) {
      // ...wrap around to the beginning:
      readIndex = 0;
    }

    // calculate the average:
    average = total / numReadings;
    // send it to the computer as ASCII digits
    float averageVoltage = (abs(average) * (5.000 / 1023.000));

    Serial.print(" Setpoint = ");
    Serial.print(setpoint);
    Serial.print("   Process Value = ");
    Serial.println( averageVoltage);
  }
  if ((currentMillis - previousMillis2 >= interval2) && (averageVoltage >= setpoint)) {
    previousMillis2 = currentMillis;

    Serial.println(" control right ");
    Serial.println(" control right ");
    Serial.println(" control right ");

    myStepper.step(-ppr);
  }
  else if ((currentMillis - previousMillis2 >= interval2) && (setpoint >= averageVoltage)) {
    previousMillis2 = currentMillis;

    Serial.println(" control left ");
    Serial.println(" control left ");
    Serial.println(" control left ");

    myStepper.step(ppr);

  }
}

Your problem with negative numbers is caused by the fact that the maximum value of an integer is 32,767. When the total exceeds that, the processor doesn't detect the overflow, and instead interprets the number as negative. You can get around this by using an unsigned integer, which has a maximum value of 65,535, or using long instead of integer.

Another possible problem, you are pre-loading all 50 readings in the array with 0, so the first 50 times you calculate the average your result will be low, because you are averaging for 50 samples when you actually haven't taken 50 samples yet. You might try reading the sensor in setup and pre-loading the array with that value for all the samples, that would get a bit closer to correct for the first few readings.

edit: Also, if you do change the way you initialize the array, because of the way you are keeping a running total, the variable "total" will need to be initialize to the sum of the initial array elements. (in the case of using the current reading of the sensor, total would be 50 * sensor reading).

Took me a while to see this one, but you declared the variable averageVoltage once at the top of the code, and again within the loop inside of an IF statement. The second declaration, which is your actual calculation of the average, is a local variable that is only visible inside the IF statement, so once you leave it and continue on in the code, you are using the original declaration of averageVoltage from the beginning of the code, which is a constant value of 0 because average at that time was 0.

...
float averageVoltage = average * (5.000 / 1023.00);
...


void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis1 > interval1) {
    previousMillis1 = currentMillis;
  }
  if (previousMillis1 == currentMillis) {

    ....
    float averageVoltage = (abs(average) * (5.000 / 1023.000));

   ...
  }
  
}

Thanks a ton, that was the bug. I'll double back to tackle the float value stuff later. For now, it's good just to watch the machine run (instead of endlessly whacking the big read "oh ####" button).

Thanks again.