using millis() to set actuator speed based on time elapsed

Hello,

Thanks to the advice of folks here, I've been trying to use the millis() function, but I'm having difficulty. I have an actuator that I want to raise quickly at first and have the speed slow as 1 second passes. However, when the program gets to the step where the actuator is supposed to come up, it instead just goes nowhere (the code does compile and upload). Here's what I have so far for setup:

byte Speed = 0; // Intialize Varaible for the speed of the motor (0-255);
int RPWM = 9;  //connect Arduino pin 9 to motor driver pin RaisePWM
int LPWM = 6;  //connect Arduino pin 6 to motor driver pin LowerPWM
unsigned long interval=1000; // the time we want to wait for the soft-stop arm retraction

And then the actual code to raise the actuator is below. I start a timer with millis and use a do loop to keep overwriting the speed until the value returned by millis() reaches the value of "interval" that I set above.

  //Retract actuator arm with soft stop
  analogWrite(LPWM, 0);
  unsigned long startMillis = millis(); // start the millisecond timer and set T0 (startMillis)
  do {
    unsigned long slowSpeed = 255 * (sqrt(1000.0 - (millis() - startMillis))/1000.0); // An equation to drop the speed as the time increases
    int intSpeed = int(slowSpeed); //convert the result from long to integer
    analogWrite(RPWM, intSpeed); //set the speed based on the timer
  } while (millis() - startMillis <= interval); // loop until the timer reaches the specified duration
  putstring_nl("Up Tim Duncan!");

Previously, I was just using this code to retract the actuator at a constant speed and it worked fine, so I know the actuator is alright:

  // Retract actuator arm
  analogWrite(LPWM, 0);
  analogWrite(RPWM, Speed);
  delay(1000); // 1 Seconds

All I'm trying to do is replace "Speed" in the example above with a variable based on time. Putting in a few values for millis() illustrates how the speed should drop over time:
millis = 20ms, slowSpeed = 252 (max speed is 255)
millis = 250ms, slowSpeed = 220.8
millis = 900ms, slowSpeed = 80.6
So I feel pretty confident about the math, I just think I have a programming issue. Can anyone see what I'm doing wrong?

thanks.

There is a minimum PWM value below which the actuator won't move. What is that value?
How long does it take for the actuator to move from full extend to full retract?

Hello and thanks for the response. That's a good question, I've tested it down to 20 and it will still move, but I don't know the exact value. Also, at full speed and no weight load, the full distance traveled takes a little more than 0.5 seconds.

I'm not so sure how I would debug that do loop i showed, but the value into the PWN should be well above 20 for the bulk of it.

Can anyone suggest a way to debug this, maybe I can get it on my own?

" I have an actuator that I want to raise quickly at first and have the speed slow as 1 second passes."

Calculate start speed..

255 * (sqrt(1000.0 - (millis() - startMillis))/1000.0)

255 * (sqrt(1000.0 - (0))/1000.0)

255 * (sqrt(1000.0))/1000.0)

255 * (31.62))/1000.0)

255 * .03162

8.06

After one second.. Lest say 2 seconds for ease of math..

255 * (sqrt(1000.0 - (millis() - startMillis))/1000.0)

255 * (sqrt(1000.0 - (2000))/1000.0)

255 * (sqrt(-1000.0))/1000.0)

255 * NAN / 1000.0 = NAN

What do you actually want for max & min speed values?

-jim lee

Here's something you can use to check your speeds. Just put in START_SPEED & CRUIS_SPEED and it'll print out the values. You can tweak the times as well..

#include <timeObj.h>    
#include <mapper.h> 

#define SOFT_START_MS   1000.0
#define TOTAL_MS        3000.0
#define START_SPEED     255
#define CRUISE_SPEED    20


timeObj  speedTimer(SOFT_START_MS);                // This tells the amount of time to do the speed ramp.
timeObj  totalTimer(TOTAL_MS);                     // This sets how long we will run the move for.
mapper   speedMap(1,0,START_SPEED,CRUISE_SPEED);   // This ramps the speed from START_SPEED to CRUISE_SPEED during the ramp time.

void setup() {
   
   Serial.begin(57600);                                // Start up serial.
   
   Serial.println("Starting move");
}



// And the old loop() function..
void loop() {
   
   if (totalTimer.ding()) {                                    // If we've run out of time..
      Serial.println("Move complete");                         // Note we're done.
      while(1);                                                // Lock here forever
   } else {                                                    // Else, move is going on..
      speedTimer.ding();                                       // Check the timer state.
      Serial.println(speedMap.map(speedTimer.getFraction()));  // Print out the speed we are set to.
   }
}

You will need to instal LC_baseTools from the library manager to compile this.

Good luck

-jim lee

jimLee:
" I have an actuator that I want to raise quickly at first and have the speed slow as 1 second passes."

Calculate start speed..

255 * (sqrt(1000.0 - (millis() - startMillis))/1000.0)

255 * (sqrt(1000.0 - (0))/1000.0)

255 * (sqrt(1000.0))/1000.0)

255 * (31.62))/1000.0)

255 * .03162

8.06

After one second.. Lest say 2 seconds for ease of math..

255 * (sqrt(1000.0 - (millis() - startMillis))/1000.0)

255 * (sqrt(1000.0 - (2000))/1000.0)

255 * (sqrt(-1000.0))/1000.0)

255 * NAN / 1000.0 = NAN

What do you actually want for max & min speed values?

-jim lee

Well it seems I had some parenthesis problems. The idea was to start at 255, which it seems i can get to by rearranging them like this:
255 * sqrt((1000.0 - (millis() - startMillis))/1000.0)

255 * sqrt((1000.0 - (0))/1000.0)

255 * sqrt((1000.0)/1000.0)

255 * sqrt(1)

255 * 1

255

Thank you very much for the help (I was pretty convinced I had the above part right, so I kept overlooking it!) and for the tips on debug. I'll give these things a shot.

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