What is the Point of the Acceleration Feed-Forward?

So I have been looking into basic motion profiling. I have watched this video a couple times an am a bit confused by the slide at 39:46.

It claims to be “Better” feedforward control because it also factors in acceleration.


SetMotorSpeed(Kv * setpoint.vel + Ka * setpoint.acc)

The first term (Kv * setpoint.vel) makes a lot of sense. Set the motor to run at your desired velocity based on your current time following the profile. I’m on board here.

My question is what does the acceleration term actually do? To me, it seems like it just throws things off.

Consider a trapezoidal profile. We have 3 states: accelerating, cruising and decelerating. During acceleration, Ka * setpoint.acc would increase motor speed to be higher than the desired velocity. During cruising, it would not contribute. During deceleration, it would decrease motor speed to be lower than the desired velocity. Doesn’t this just mess things up?

My understanding is that is it is extra “oomph” to make the robot more responsive when accelerating and to counter inertia when decelerating quickly.

Takes the load off of the PID loop a little bit, as the error when accelerating is almost always lag, and the error when decelerating is almost always due to inertia.

The point of any feedforward is to make a better “guess” at the actual control signal required to make your motor do what you want it to.

Without getting into the nitty-gritty control theory, basically: because the robot has inertia, accelerating takes more voltage than running at a constant speed. The acceleration feedforward term attempts to account for this, so that your feedback loop doesn’t have to.

Edit: I apologize for having to re-write this entire section, but apparently my brain does not function after 10PM (which is when I originally added it) - hopefully no one was mislead for the couple hours during which it was wrong.

To gain some intuition for why this works, consider the way a brushed DC motor works: torque (which causes acceleration) is proportional to current. Current, as you might remember, is proportional to voltage (V=IR). Now the voltage across a DC motor can be broken into two parts: voltage due to internal resistance of the motor, and voltage due to “back-EMF.” The former is, as noted, proportional to the current across the motor. The latter is proportional to the velocity of the motor. The applied voltage must equal the sum of the two. If we imagine that we have a frictionless motor, the torque required to maintain any speed is zero, and thus the voltage required to simply go at a given velocity is proportional to that velocity - we merely need to apply voltage equal to the back-EMF, which is proportional to velocity (in actuality, motors are obviously not frictionless, which is why the current draw at free speed is not zero). This is accounted for by our velocity feedforward. However, if we want the motor to accelerate, then we need to add some amount of voltage on top of that which compensates for the back-EMF, such that this additional voltage, when divided by the internal resistance of the motor (V/R = I), yields the correct current to generate the torque we need. This is what the acceleration feedforward estimates.

This is really programming to the motor performance curve. Once the motor is spinning, it functions as a generator, creating an emf (voltage) which (in normal operation) is in the opposite direction of the applied voltage. The remaining voltage generates torque, which is used to counter friction and accelerate. I have gotten fair performance out of using this form of feed forward with no feedback with some non-competition systems in experimentation.

This isn’t exactly how it is used here because it seems that the feed forward is using desired (setpoint) speed rather than measured speed, but the effects should be roughly the same.

Thanks for the responses everyone. Learned a bit about how brushed DC motors work from this which has been fun.

Now that I understand the motive for the acceleration term. I am curious to know good ways to go about finding Ka.

Kv = 1 / max_velocity
(where max_velocity is measured by running at your robot at max voltage until it stops accelerating makes sense to me)

This might lead one to suspect
Ka = 1 / max_acceleration

But the issue, as you pointed out, is that max_acceleration varies with the speed of the robot. That is to say, I can accelerate much faster at rest than I can when I am running a 90% velocity. How can I determine the max_acceleration for any given velocity? Perhaps I could run the robot at max voltage and track the velocity and acceleration at all points in time and the create a map from velocity to acceleration. Assuming no slippage (big assumption) this should give me the max_acceleration for any velocity. But then there is the whole deceleration thing. I can probably decelerate faster than I can accelerate. How can I track that? My head hurts. Can anyone shed some light on this?

I could also ignore the fact that max_acceleration changes with velocity and just pick the max_acceleration at rest (the maximum max_acceleration :rolleyes: ) causing the acceleration term to under compensate. Then, the feedback controller would just pick up the slack. Have people found an approach like this to be sufficient for their FRC needs?

This would be correct, if “max acceleration” corresponded to “the acceleration of the motor at rest when full voltage is applied,” or, in simpler terms, the acceleration corresponding to the stall torque.

The reason you lose the ability to accelerate at higher speeds is that the back-EMF from the motor (i.e., the thing accounted for by your velocity feedforward) “saps” your available voltage. That is, if your motor is already spinning at half of max speed, then half of your available battery voltage is already being used to counteract the resulting back-EMF, and you only have the remaining half available to provide torque (and accelerate the robot) - thus, your available torque at 50% of free speed is 50% of stall torque. If you’re running at max speed, well, you can’t accelerate at all (at least in the direction of motion) because applying full battery voltage merely cancels the back-EMF.

But the “torque per voltage” never changes (the original wording of my post was unclear/wrong about this, which is why I had to modify it a whole bunch of times - late night posting ftl). That is determined by the internal resistance of the motor. So, increasing applied voltage by a fixed amount will always increase the torque by a corresponding amount.

On a related note, I really wish that the Talon SRXs would allow for acceleration feedforward in motion profiling mode.

Because torque and my robots acceleration are proportional (correct me if I am wrong on this, but that makes sense to me), could I then use what your saying to calculate max_acceleration as a function of current_velocity as follows:

max_acceleration(current_velocity) = from_rest_max_acceleration * (current_velocity / max_velocity)

where from_rest_max_acceleration is the acceleration my robot has running at full voltage from rest. Again, assuming no slippage.

I have a followup question. How do you determine/tune Ka?

This is a correct calculation of “max acceleration” (at least in the direction of current motion), but as it happens you do not need to bother with it for figuring out the scaling of Ka, which depends only on the stall torque acceleration.

Remember the form of our feedforward:

Kv * setpoint.vel + Ka*setpoint.acc

If the motor is behaving as we expect it to (and we neglect frictional losses), the first term (Kv * setpoint.vel) will output the voltage required to counteract the back-EMF. The second term (Ka * setpoint.acc), we want to output the voltage required to yield a torque that will cause the robot to accelerate at setpoint.acc. Regardless of the speed we’re moving, the voltage required to produce a given torque is the same, even though the “max torque” (or “max acceleration”) is different, because the difference in “max torque” is only due to the decrease in the available battery voltage after taking into account the back-EMF.

So, regardless of the speed we’re currently traveling, if we want to accelerate at 50% of max acceleration, we would need to add an additional 50% of the maximum battery voltage to our current output. The scaling of Ka is the same. Of course, if we’re traveling over 50% of max speed, then this is not actually possible, because that would be greater than our “max acceleration” (as you have calculated it) at that speed - this is because we’d have less than 50% of max battery voltage available after subtracting off the back-EMF, however, not because a given increase in voltage would cause a smaller acceleration.

So if we want to follow a simple Trapezoidal Motion Profile, one where we accelerate at a constant rate, cruise, then decelerate at a constant rate, it is important to do the math to choose an <acceleration, cruise_velocity> pair that is physically achievable.

This check should be as simple as compute the max_acceleration(cruise_velocity) from the function I posted above (all other velocities in the profile are less than the cruise_velocity so this should result in the lowest max_acceleration). Compare this to the acceleration chosen in the profile. If the profile’s acceleration is less than max_acceleration(cruise_velocity), then we should be able to follow the profile correctly. If not, we won’t have enough voltage to continue accelerating at the same rate. Does that make sense?

Yes. But I usually run another check of approximate Kv and Ka gains before tuning profile with the robot. Kv * desired velocity + Ka * constant acceleration rate should be less than full throttle. You need room for Kd * distance error to work when the feedback loop is added.

Using Kv of 1/max velocity is a good place to start. So if you are trying to cruise at 70% of max velocity, then the output to the motor during the cruise section of the curve will be 0.7. You only have 0.3 throttle to add the acceleration component plus any error correction for distance.

Bottom line, your cruise velocity picked will set the ceiling on your other terms. Make sure you understand your real robot characteristics instead of basing cruise and acceleration on theoretical calculations.

Good luck with your experiments!

David

As noted by the poster above, this is correct. Note, however, that “max acceleration” as you calculated it is only valid in the direction of current motion. If you are moving at max speed and wish to decelerate, then you actually have a “max acceleration” of twice the acceleration corresponding to stall torque, because the back-EMF would actually add to the applied voltage.

They do :slight_smile:

(In profile mode, but not in motion magic mode). In profile mode, the “velocity” you supply with each trajectory point is just multiplied by the feedforward gain and added to the output; there is no requirement that the velocities integrate correctly to obtain the position of the next point. So you can tune your feedforward velocity gain as usual, then pass in a velocity setpoint that is actually (desired_velocity + desired_acceleration * ka / kv).

Well, that’s quite a clever little hack, and should be easy for us to implement. Thanks!

Edit: Out of curiosity, I was wondering if you could share your experience with Ka tuning - in particular, how close would you say the theoretical “guess” of (total stall torque of the two main drive shafts)*(wheel radius)/(robot mass), perhaps adjusted by some fudge factor for efficiency (80%?), tends to be to the actual “max acceleration” value? What technique do you recommend using for empirical measurement, if theoretical values prove inadequate?

So, this weekend we implemented acceleration feedforward for our motion-profiling, using the workaround suggested.

We initially guessed at a value for Ka by calculating the “maximum” acceleration at stall-torque assuming no wheel slip and a perfect voltage source, multiplied by .8 to account for frictional losses.

For our practice bot, this came out to approximately 100 feet per second squared (~110lb robot, 6 CIMs, 6.1:1 gearing, 2’’ wheel radius](http://www.wolframalpha.com/input/?i=21.3+inlb++6.1++6+%2F+(2+inches++110+lbm)+in+ft%2Fs%5E2)).

(Our “fudged” velocity values were then calculated as desired velocity + desired acceleration * maximum velocity / maximum acceleration, which is equivalent to the formula provided by Jared Russel if Kv = 1/max velocity and Ka = 1/max acceleration).

This number seems ridiculously large in terms of realistic robot accelerations, and it is - the assumptions of “no wheel slip” and “perfect voltage source” are lousy assumptions that do not hold in all situations.

That said, we are careful to limit our max acceleration to a value below that which would slip the wheels, and we use the “nominal closed loop voltage” option on the Talon SRXs to account for dropping battery voltage, which should account for the latter (so long as we do not actually command un-achievable accelerations).

So, we were marginally confident that our calculated “theoretical” value would be somewhat close to the “actual” value.

As it happens, this was not the case - we found that the “maximum acceleration” that yielded a reasonable Ka was around 15 feet per second squared - far lower than the theoretically-calculated value of 100.

Perhaps someone with experience in this could shed some insight into why this is the case? I’m at a loss for why there’s such a huge discrepancy between the calculated value and the value that actually works in practice, *especially *since we are using the Talon’s nominal battery voltage compensation.

I’ve never worried too much with max acceleration. I try to use a value within reason such as 0 to 10fps in 0.5 seconds - 20ft/sec^2.

I haven’t performed a max acceleration calculation on a robot, but 3 G’s seems a bit stout to control.

David

The robot will obviously never actually achieve a 3g acceleration, due to either wheel slip or internal resistance of the battery (robot acceleration is effectively limited to the coefficient of friction of the wheels times the acceleration of gravity, assuming the motors can actually achieve that on the FRC battery).

However, wheel slip pretty clearly shouldn’t factor into the determination of Ka (we’re not slipping the wheels with the profiles we run), and the voltage effect should be compensated for by the nominal battery voltage feature of the Talon SRX.

Admittedly, we are running two of the three motors per gearbox in slave mode - it may be possible that the nominal battery voltage feature is only functioning for the master on each side of the drive? But, if that’s the case, how would we enable it on the slave motors, given that they’re not in a closed-loop mode?

The only two things that come to mind that could have caused the discrepancy between the theoretical and practical values are:

  1. a failure of the nominal battery voltage feature
  2. friction

However, as best I could figure, effect 1 could only at worst account for less than a factor of two error (if battery voltage is below 6A, the system would be browning out). I don’t know how big effect 2 is, but even imagining a factor of 2 contribution from effect 1 (which is already unrealistically big) I can’t imagine it causing an error this big. It’s baffling.

Edit: I suppose it’s also remotely possible that some our of motors simply weren’t running, though we saw no other evidence of this…