Go Down

Topic: [Solved] Control a motor with acceleration and variable speed, no delays (Read 898 times) previous topic - next topic

aj88keys

I am building a power supply/throttle for a model tram layout, and I want to use my Uno R3 to not only power the train but also to run accessories (eg, traffic lights, crossing signals, etc) that rely on timing. My hope is to eventually have everything automated, with sensors to detect where the tram is on the layout so that it can stop at stations, trigger crossing lights, etc.
I want to have some amount of "momentum" on the train so that it runs more realistically, but I have so far only managed to figure out how to do it using delays, which will end up messing up traffic lights and detection when those get implemented. Is there a way that I can implement acceleration without using delay?

Here is the code I am currently using, It does exactly what I want it to, but will cause problems if I try to add any more features:
Code: [Select]

int sensVal = 0; //Value read from pot
int val = 0; //Desired speed value
int spd = 0; //Actual speed to run train
int accel = 150; // Speed to accelerate, lower numbers are faster
int decel = 60; //Speed to decelerate, lower numbers are faster
int outPin = 10; //Motor control pin

void setup() {
 //set inputs and outputs:
 pinMode(outPin, OUTPUT);
 pinMode(0, INPUT);
 
 setPwmFrequency(10,1); //set a higher, inaudible PWM frequency on pins 9 and 10
 
 Serial.begin(9600);
 
 //Leave voltage at 0 while pot is low, reset button can thus be used as emergency stop:
 analogWrite(outPin, 0);
 while (sensVal < 100) {
   sensVal = analogRead(0);
 }
}

void loop() {
 sensVal = analogRead(0); //get value from pot
 sensVal = map(sensVal, 0, 1023, 0, 140); //map to PWM range
 sensVal = constrain(sensVal, 0, 255); //allows for pot range tweaking
 
 //stops powering the motor below stall
 if (sensVal < 20) {
   val = 0;
   }
 else val = sensVal;
 
 Serial.println(sensVal); //debugging
 Serial.println(val);     //""
 Serial.println(spd);     //""
 
 // ****Acceleration****
 if (spd < val) {
   analogWrite(outPin, spd);
   //Serial.println(spd);
   delay(accel);
   spd++;
 }
 else if (spd > val) {
   analogWrite(outPin, spd);
   //Serial.println(spd);
   delay(decel);
   spd = spd / 1.01;
 }
 
}

//-------------------------------------------------------------------------------------

void setPwmFrequency(int pin, int divisor) {
 byte mode;
 if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
   switch(divisor) {
     case 1: mode = 0x01; break;
     case 8: mode = 0x02; break;
     case 64: mode = 0x03; break;
     case 256: mode = 0x04; break;
     case 1024: mode = 0x05; break;
     default: return;
   }
   if(pin == 5 || pin == 6) {
     TCCR0B = TCCR0B & 0b11111000 | mode;
   } else {
     TCCR1B = TCCR1B & 0b11111000 | mode;
   }
 } else if(pin == 3 || pin == 11) {
   switch(divisor) {
     case 1: mode = 0x01; break;
     case 8: mode = 0x02; break;
     case 32: mode = 0x03; break;
     case 64: mode = 0x04; break;
     case 128: mode = 0x05; break;
     case 256: mode = 0x06; break;
     case 1024: mode = 0x7; break;
     default: return;
   }
   TCCR2B = TCCR2B & 0b11111000 | mode;
 }
}

The setPwmFrequency() function was taken from the arduino playground, I am using it so I can eliminate the squeal that was driving me nuts (now its driving my dog nuts :smiley-mr-green:)

johnwasser

To eliminate the delays, use something like this in loop:
Code: [Select]

   static unsigned long lastAccelTime = 0;
   static unsigned long lastDecelTime = 0;

   unsigned long currentTime = millis();

  // ****Acceleration****
  if (currentTime - lastAccelTime > accel) {
    lastAccelTime = currentTime;
    if (spd < val) {
      spd++;
      analogWrite(outPin, spd);
    }
  }

  // ****Deceleration****
  if (currentTime - lastDecelTime > decel) {
    lastDecelTime = currentTime;
    if (spd > val) {
      spd = spd / 1.01;
      analogWrite(outPin, spd);
    }
  }
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

aj88keys

Wow, that was a whole lot easier than I expected! I have spent a lot of time trying to figure out how to use that currentTime - lastTime format and just couldn't get it until now. I will definitely be using that more often!

Go Up