Motor Ramp to a Variable that Changes

**Full sketch added to files.

Equipment:

MEGA 2560
SyRen50 Motor Controller
12V, 30A switching power supply for motor
12V, 3000mA wall wart for Arduino
12VDC motor
Incremental encoder
Generic LCD

What I want to do:

Control a maximum motor speed as determined by the difference in position. Current position is registered by an incremental encoder and desired position is varied by a simple pushbutton counter for the moment. Both positions read correct in the LCD and Serial.print when troubleshooting. I am trying to make the motor ramp up to the motor setpoint if its current speed is less and ramp down the setpoint if its current speed is more. If the positions are equal, I want the motor to stop. Essentially, I am looking for proportional control; the farther from the target position, the faster I want the motor to go towards it.

This is going to control a telescope dome so all the 360° math relates to the azimuth of the dome and a lot of the math shown is to keep everything scaled to a positive 360° no matter which direction the encoder is running.

I am setting the motor setpoint (mtrMax) in mtrSpeedMax () and instructing the motor to run at those speeds in the second half of mtrRun() after the auto manual condition has been checked (needs to see a 1). You'll see a manual motor operation section in first half of the later function (condition autoMan == 0) and that operates just fine ramping to and from a maximum value as determined in the first half of mtrSpeedMax()

What is happening:

The motor seems to ramp up ok but once it reaches the maximum of 80, it holds that value and will not ramp down. I do not understand why, clearly I am not satisfying some condition but the logic seems simple enough I can't find the error I've injected.

I had to delete the various sections of code and notes to get under 9000 characters so if you suspect something is missing that is causing the problem, I can post other sections in the comments.

My code is over 9000 characters so it won't let me post in its entirety. I've posted what I believe to be the pertinent sections (I am very aware that I could be wrong) so if something else needs to be looked at I can post more in the comments.

void differentialPosition() {

  //////***math to sort smallest of angle differences***///////
  if ((tgtPos - azi) > 0) {
    angleDiff1 = abs(tgtPos - azi - 360);
  }
  else {
    angleDiff1 = tgtPos - azi;
  }

  if (azi > tgtPos) {
    angleDiff2 = azi - tgtPos;
  }
  else {
    angleDiff2 = tgtPos - azi;
  }

  if (angleDiff2 > 180) {
    smallestAngle = 360 - angleDiff2;
  }
  else {
    smallestAngle = angleDiff2;
  }

void mtrSpeedMax() {
  if (autoMan == 0) { // If in manual mode
    mtrMax = 100;
  }
  if (autoMan == 1) { // If in auto mode  ***Add conditions for differential speed***
    if (smallestAngle > 0 && smallestAngle < 5) {
      mtrMax = 15;
    }
    if (smallestAngle >= 5 && smallestAngle < 20) {
      mtrMax = 20;
    }
    if (smallestAngle >= 20 && smallestAngle < 90) {
      mtrMax = 60;
    }
    if (smallestAngle >= 90 && smallestAngle < 180) {
      mtrMax = 80;
    }
    if (azi % 360 == tgtPos % 360) {
      mtrMax = 0;
    }
  }
}

void mtrRun () {
  //Default lights to off
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);

  //Declare variables for encoder millis() math
  static unsigned long lastAccelTime = 0;
  static unsigned long lastDecelTime = 0;
  unsigned long currentTime = millis();

  if (autoMan == 0) { //Manual mode **works fine
    //CCW Button ramp motor up if high ramp to max if nigh, ramp down to 0 if low, ramp to zero if both pressed
    if (digitalRead(BUTTON1) == HIGH && digitalRead(BUTTON2) == LOW && power >= 0)
    {
      digitalWrite(LED1, HIGH);
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power <= mtrMax) {
          power ++;
          SR.motor(power);
        }
      }
    }

    if (power > 0 && digitalRead(BUTTON1) == LOW || power > 0 && digitalRead(BUTTON1) == HIGH && digitalRead(BUTTON2) == HIGH || power > 0 && digitalRead(BUTTON1) == LOW && digitalRead(BUTTON2) == HIGH )
    {
      if (currentTime - lastDecelTime > decel) {
        lastDecelTime = currentTime;
        power = power / 1.01;
        SR.motor(power);
      }
    }

    // CW Button ramp motor down to max negative if high, ramp up to 0 if low, ramp to 0 if both pressed
    if (digitalRead(BUTTON2) == HIGH && digitalRead(BUTTON1) == LOW && power <= 0) //ramp up in positive direction with B1 pressed
    { //but return speed to zero if conflicting inputs
      digitalWrite(LED2, HIGH);

      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power >= -mtrMax) {
          power --;
          SR.motor(power);
        }
      }
    }

    if (power < 0 && digitalRead(BUTTON2) == LOW || power < 0 && digitalRead(BUTTON1) == HIGH && digitalRead(BUTTON2) == HIGH || power < 0 && digitalRead(BUTTON2) == LOW && digitalRead(BUTTON2) == HIGH)
    {
      if (currentTime - lastDecelTime > decel) {
        lastDecelTime = currentTime;
        power = power / 1.01;
        SR.motor(power);
      }

    }
  }

  if (autoMan == 1) { //automatic mode **does not work
    if (mtrdirection == -1) {

      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power < mtrMax && power >= 0) {
          power ++;
          SR.motor(power);
        }
      }
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power > mtrMax && power > 0) {
          power = power / 1.01;
          SR.motor(power);
        }
      }
    }

    if (mtrdirection == 1) {

      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power > -mtrMax && power <= 0) {
          power --;
          SR.motor(power);
        }
      }
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power < -mtrMax && power < 0) {
          power = power / 1.01;
          SR.motor(power);
        }
      }
    }
  }
}

SabertoothArduinoLibraries.zip (382 KB)

Motor_Test_2_Ramp_Real_with_LCD_Sep_Voids.ino (12.2 KB)

This code

  if (autoMan == 1) { //automatic mode **does not work
    if (mtrdirection == -1) {

      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power < mtrMax && power >= 0) {
          power ++;
          SR.motor(power);
        }
      }
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        if (power > mtrMax && power > 0) {
          power = power / 1.01;
          SR.motor(power);
        }
      }
    }
  //...

can't work. If the first currentTime - lastAccelTime comparison is true, the second one will never be true since you are resetting lastAccelTime. This means your 'power' will never go down.

not sure if blh64's comment is the cause of the problem

suggest you add serial prints to debug: print tgtPos, azi and mtrdirection

gcjr:
not sure if blh64's comment is the cause of the problem

suggest you add serial prints to debug: print tgtPos, azi and mtrdirection

It wasn't. That bit of code works fine.
I got it sorted last night. There were several problems but the biggest was that for 'motordirection' there were 3 possible conditions but I only accounted for 2 in mtrRun(). Instead of further complicating mtrRun(), I decided to multiply the mtrMax value by the 'motordirection' value which greatly simplified the mtrRun() programming. Snips below:

  mtrdirectionTemp = ((tgtPos - azi + 540) % 360) - 180;
  if (azi % 360 == tgtPos % 360) {
    mtrdirection = 0;
  }
  if (mtrdirectionTemp < 0) {
    mtrdirection = -1;
  }
  if (mtrdirectionTemp > 0) {
    mtrdirection = 1;
  }

void mtrSpeedMax() {
  if (autoMan == 0) { // If in manual mode
    mtrMax = 100;
  }
  if (autoMan == 1) { // If in auto mode  ***Add conditions for differential speed***
    if (smallestAngle > 0 && smallestAngle < 5) {
      mtrMax = 15*mtrdirection;
    }
    if (smallestAngle >= 5 && smallestAngle < 20) {
      mtrMax = 20*mtrdirection;
    }
    if (smallestAngle >= 20 && smallestAngle < 90) {
      mtrMax = 60*mtrdirection;
    }
    if (smallestAngle >= 90 && smallestAngle < 180) {
      mtrMax = 80*mtrdirection;
    }
    
    if (azi % 360 == tgtPos % 360) {
      mtrMax = 0;
    }
  }
}


  if (autoMan == 1) { //automatic mode **does not work
    if (power < mtrMax && power >=0) {
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        power ++;
        SR.motor(power);
      }
    }

    if (power > mtrMax && power >0) {
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        power = power / 1.01;
        SR.motor(power);
      }
    }

    if (power > mtrMax && power <=0) {
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        power --;
        SR.motor(power);
      }
    }
    if (power < mtrMax && power <0) {
      if (currentTime - lastAccelTime > accel) {
        lastAccelTime = currentTime;
        power = power / 1.01;
        SR.motor(power);
      }
    }
  }

The above (with all the other code not shown of course) behaves exactly as intended.

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