View Full Version : Controlling Motors More Accurately
Glueeater
17-03-2008, 06:37
Sorry for the many questions,
Does the SetMotor function accept fractional speeds (ie 127.1 127.5?) ? If not, is there anyway to control them more accurate (different commands?)
Kingofl337
17-03-2008, 09:58
No, unfortunately PWM's can only be controlled in whole numbers.
Glueeater
17-03-2008, 20:24
Would there be a way to control a digital servo with the digital outpot ports? Even with RobotC, I cannot control the PulseOut to the motor?
I'm basically looking for a way to force this hobby servo running on Vex with an optical shaft encoder to run at a constant velocity. I've looked into PIDs but can't figure out how to make it work with my setup.
Kingofl337
18-03-2008, 13:05
The master processor controls the motor outputs and IFI controls the source for that.
Glueeater
19-03-2008, 20:36
I have sorted the problem out somewhat. Is there a way to limit a range of numbers? Such as:
If (rps < trps)
speed = speed + 1
elseif (rps > trps)
speed = speed - 1
elseif (rps == trps)
speed = speed
I want to keep it only in forward motion so the values must be restricted to 127 to 255. Thank you!
Glueeater
26-03-2008, 06:46
Anybody have feedback on this?
Mark McLeod
26-03-2008, 10:26
What you want to do is certainly possible and there are, as usual, several ways of accomplishing velocity control.
Your biggest issue is limiting how often/fast to update your speed.
Motor updates on Vex/EasyC occur in the background at 54 times per second, but the EasyC code runs much, much faster than this. So if you just dropped in the code you proposed (with the addition of a 125-255 limit check) then your speed would immediately count up to the max 255, then when you pass your target rps it would run immediately right back down to 127. Effectively, the motor would only see stop or full speed.
You'll need to learn to use a timer set to run at 54 Hz to limit how often you update "speed."
Oscillation past the target rps point might be an issue and you'll need to add a limit check to avoid both overflow/wrap-around and reverse speed, e.g.,
unsigned char speed=127; // You can pick a better/faster start value that matches the speed you're trying to hit
if (speed < 127) speed = 127;
if(speed > 254) speed = 254;
If your servo will just be running free, then your code should work, if slowly.
However, if the servo will have varying loads put on it then you might need a little more sophistication in how you adjust speed.
Glueeater
26-03-2008, 17:31
Hmm. I don't think I follow?
Right now I have the aforementioned code running within a for loop..
float speed
int trps
-snip-
for enco == 0; enco < distance; enco = GetEncoder(1)
StartTimer(1)
-snip-
time = GetTimer(1)
rps = enco / time
If (rps <= 127)
speed = speed + .5
elseif (rps < trps)
speed = speed + 1
elseif (rps > trps)
speed = speed - 1
elseif (rps == trps)
speed = speed
The first If limits it to only go "forward." I think my main question now is if there is a way to more accurately control the speed than by integers. I think you referred to it overcompensating which is what I think it's doing, is there a way to solve that?
I start at a speed close to the target and it will vary around it, that should work, no?
By the way, I am not varying loads or anything. The servo will just run continously at its target speed.
Mark McLeod
26-03-2008, 22:51
Integers are how the servo is controlled, so no there is no other way using EasyC. SetMotor(speed) will be looking for an unsigned char variable rather than a floating point value. Adam's answer still holds :)
Using MPLAB and C directly there are methods to increase the accuracy of the controlling integers, but discrete integers are always how the motors are controlled. That's because they are digital controls rather than analog.
Giving "speed" a starting value close to what you know it should be will help. That may avoid having speed go too high or too low, but without a check that'll be a risk.
The way you wrote your code example seems to indicate you want to drive for a specific distance at a constant velocity. Is my interpretation correct?
In your code example "for" loops aren't used in that way.
You'd use a "while" loop to do what you want.
Also, rps in your calculation needs an extra factor for the encoder equivalent of one revolution of your motor before it becomes revolutions per second.
rps isn't in terms of the the motor command values of 127 to 255, it's in terms of some velocity, so (rps < 127) doesn't do what you want in keeping the speed value from adding up to more than 255 or less than 127 eventually. It might coincidentally work out that 127 is a valid "distance per second," but that doesn't sound like what you want.
// Initialize stuff
StartTimer(1)
enco = 0;
// Drive the motor
while (enco < distance)
{
enco = GetEncoder(1);
make speed adjustments
}
You're going to see overcompensation, because you aren't accounting for how often the value set by the SetMotor() command is actually sent to the motor.
It is not sent to the motor whenever SetMotor is called. SetMotor only stores the value for later pickup by the master processor which doesn't check very often. For instance,
for (speed=127; speed <255; speed ++)
{
SetMotor (speed);
}
will step through the values 127 to 255 so fast that the master processor will probably only pickup the SetMotor value once and so see only one of the many values SetMotor sets.
We're competing tomorrow, so I won't be replying for awhile.
Someone else will probably help out if you post more questions.
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.