Hi!
For the project I am making I need a DC motor to start and stop smoothly when switching directions. At the end, I plan on using 4 MCUs to each swing its own bell (there will be 4 bells), but they will swing in sequence 1234 1234 1234 and the timing must be accurate enough so that they will not get out of order in under 5 minutes (at least) - they will all have the same program, the same swing time, but the motor speeds could differ because they will not all be the same weight and motors will have to do harder/lighter jobs depending on the bell and also swinging angles will be different. I am having a lot of trouble writing soft pull function that will do the job with as small error as possible. So far I have this:
void pwmSmoothPull(int dutyCycleStart, int dutyCycleEnd, int motorPinPWM, int speedChangeTime)
{
/* Enables the motor to change duty cycle slowly to avoid sudden strong pulls and stops. */
int deltaDutyCycleSigned = dutyCycleEnd - dutyCycleStart;
int deltaDutyCycle = abs(deltaDutyCycleSigned); // How many steps to make to reach desired duty cycle.
double speedChangeTimeStepDec = ((double) speedChangeTime / deltaDutyCycle) * 1000; // How much time to wait per step (in microseconds).
int speedChangeTimeStepInt = (int) speedChangeTimeStepDec; // How much time per step (in microseconds) as integer (for delay function).
double speedChangeTimeStepRemainder = speedChangeTimeStepDec - speedChangeTimeStepInt; // The decimal part of time step (lost in integer rounding).
int speedChangeTimeRemainder = (int) (speedChangeTimeStepRemainder * deltaDutyCycle); // The time not waited due to integer rounding.
int dutyCycleCurrent;
// CASE: Speedup.
if (deltaDutyCycleSigned >= 0)
{
dutyCycleCurrent = dutyCycleStart + 1;
while (dutyCycleCurrent <= dutyCycleEnd)
{
analogWrite(motorPinPWM, dutyCycleCurrent);
dutyCycleCurrent++;
delayMicroseconds(speedChangeTimeStepInt);
}
// CASE: Slowdown.
} else
{
dutyCycleCurrent = dutyCycleStart - 1;
while (dutyCycleCurrent >= dutyCycleEnd)
{
analogWrite(motorPinPWM, dutyCycleCurrent);
dutyCycleCurrent--;
delayMicroseconds(speedChangeTimeStepInt);
}
}
delayMicroseconds(speedChangeTimeRemainder); // To make this function last as close as possible to the time given in speedChangeTime, we need to wait the time that was lost in integer rounding (even though we are not changing speed anymore).
}
This function will be called each time the motor will have to reverse, so that can means at a rate of roughly 400 ms (+ the time of the function * 2 = around 600 ms of total swing time). The problem is, when I measure the time taken by it, it varies, from 2.6 msec off to 4 msec off or even 20 msec off, all of those values are the time waited too much, not too little (of course the error depends on the distance between two pwm duty cycles it was given - at this time I use from 0 to 155 and vice versa, but with different h-bridge it might be smaller, ie from 0 to 70 or so) and I cannot even plot a function from it - when I used 0-100 pwm I got 520ms, when I used 0-120 I got 504ms, when I used 0-140 I got 504.1ms, when I used 0-160 I got 520ms again - there doesn't seem to be any logic behind. That is far to much for my application as if bell swings for example 100 times per minute that means A LOT of error. Now I might have done this the wrong way, or perhaps there is a solution with timers. I would really appreciate anyone looking at this and helping me if possible or suggest a new approach as I am new in this field. Thank you very much!