We are looking for a method of limiting acceleration to prevent the Robot from tipping itself over during robot operation. We are looking some form of rate limiting function. What is the best way to accomplish this.
Generally, the best option is to ensure that you’re never moving a substantial distance while your robot’s center-of-mass is high enough to cause stability issues. If the center of mass of your robot is always high enough to cause stability issues, you have a significant problem and should consider some fundamental design changes.
However, if you do want to provide some extra safety in code (this is not a replacement for following the above advice!), you may find this helpful. Be aware that you’ll need to instantiate one component per value you wish to ramp. You also will probably have to modify the clock call, which is unique to our framework.
If you use Talon SRX or Victor SPX motor controllers, you can set the open loop ramp rate to limit the max acceleration and deceleration.
“The Talon SRX can be set to honor a ramp rate to prevent instantaneous changes in output. This ramp rate is in effect regardless of which mode is selected (PercentOutput, Follower, or closed-loop).” Talon SRX Software Reference Manual, section 6
talon.configOpenloopRamp(secondsFromNeutralToFull, timeoutMs);
secondsFromNeutralToFull sets the number of seconds from 0.0 to 1.0, while timeoutMs sets the number of milliseconds to wait when setting this config (this is persistent between power cycles) before giving up.
Currently what we are doing is taking the value to a power less then 1 to reduce the acceleration. Is this an effective way or is there a better way?
//limits accleration in certain drive functions
public class DifferentialDriveLimiter extends DifferentialDrive {
public DifferentialDriveLimiter(SpeedController leftMotor, SpeedController rightMotor) {
super(leftMotor, rightMotor);
}
public static final double RATE_LIMITER = 3/5;
public void arcadeDriveLimiter(double throttle, double turn) {
throttle = Math.copySign(Math.pow(throttle, RATE_LIMITER), throttle);
turn = Math.copySign(Math.pow(turn, RATE_LIMITER), turn);
super.arcadeDrive(throttle, turn);
}
public void tankDriveLimiter(double leftSpeed, double rightSpeed) {
leftSpeed = Math.copySign(Math.pow(leftSpeed, RATE_LIMITER), leftSpeed);
rightSpeed = Math.copySign(Math.pow(rightSpeed, RATE_LIMITER), rightSpeed);
super.tankDrive(leftSpeed, rightSpeed);
}
}
I strongly advise against doing this if you are in any control mode other than PercentOutput (open-loop) - output ramps tend interact very badly with control loop behavior.
This is unlikely to be effective. If you want to limit the rate, you need to limit the rate. The math you do here does nothing of the sort. To demonstrate:
Let our unprocessed throttle value at time t be denoted by f(t). The treatment above yields a processed throttle of f(t)^(3/5). Applying the chain rule, we see that the rate of change of f(t)^(3/5) is ((3/5)f(t)^(-2/5))*f’(t), where f’(t) is the rate of change of the throttle at time t. Clearly, no meaningful limiting has occurred here - in fact, the implementation may make the problem worse, as the factor of (3/5)f(t)^(-2/5) is greater than 1 for a substantial portion of the range of f(t), and even tends to infinity(!) at a throttle value of 0.
This won’t decrease the acceleration if your driver slams the stick all the way forward. This only helps if the driver is actively trying to slowly accelerate.
That’s why I specified “open loop control”. Setting talon.configOpenloopRamp shouldn’t affect closed loop behavior (if you use the SRX’s built-in closed loop control).
**
Rate limiting is very easy to do.
Just use a slew rate limiter on your joystick, like this.
Here’s an old article by Eric VanWyk.**
I want to point out to readers that Oblarg is referring to closed loop control methods here and not open loop (percent output). Using the open loop voltage ramping config on the talons is a great way to do this and many teams already use it to limit the current spikes in their drive train. We plan to adjust the open loop configuration dynamically based on the height the elevator is at at any given time.
Also… If you limit the slew rate of the joystick, it doesn’t affect closed stability does it? You’re just limit the rate of change of the setpoint.
Has anyone tried a more active anti-tipping method? Some of our programmers were talking about using IMU data to detect when the robot starts to tip and automatically changing drivetrain output to counteract.
I’m not sure if our code would be able to react fast enough to prevent the tip, and am not sure how we’d differentiate the start of a full tip from driving over the cable trays.
You’re talking about using an adder on the joystick value to set the setpoint of a closed loop on the drivetrain/subsystem?
That’s basically what we’re doing for the manual control of our elevator. It’s run on a position based closed loop controller and we change the position based on an adder looking at the joystick.
If your setpoint is velocity, then a setpoint slew limit is an acceleration limit, provided your loop can track the setpoint well. An output ramp is not really a clean acceleration limit, either, since the rate of change of the voltage supplied to the motor does not itself directly correspond to acceleration. Output ramps tend to interact in nasty/unpredictable ways with control loops, while setpoint ramps do not; I therefore always recommend setpoint ramping. Of course, in open loop control the two are (usually) the same.
We did this in 2015. It was pretty effective. The only issue is if you rely on this you’re basically taking control from your drivers for periods of time that it is tipping. It’s more for an emergency situation than your first point of defense. At least that was what we used it for.
If the drivers need hard limits on straight line acceleration, what about turning acceleration? Is simple damping of the inputs sufficient?
Sounds interesting, so I went looking
public void arcadeDrive(double throttle, double turn) {
if (imu.getRoll() > 8.5) {
robotDrive.arcadeDrive(0.5, 0);
} else if (imu.getRoll() < -8.5) {
robotDrive.arcadeDrive(-0.5, 0);
} else {
robotDrive.arcadeDrive(throttle, turn);
}
}
Straightforward for the forward/back case, but what if your bigger worry is tipping to the left or right? Do you think a brief spin into the fall might help? Not yet sure we have a problem at the moment (or is that with the moment), but have been thinking about this.
We didn’t see any issues with that that year because of the lower speeds of the game. This year it could very much be an issue.
limit the rate of change of the joystick output command. click the “like this” link in this post to see some pseudo code.
That’s basically what we’re doing for the manual control of our elevator. It’s run on a position based closed loop controller and we change the position based on an adder looking at the joystick.
joystick command rate limiting can can used whether you’re commanding position or speed, and regardless of whether your control scheme is closed or open loop.
It just limits the rate at which the driver can change the setpoint… which is good enough in many cases.
Yeah that’s basically what we’re doing. I hadn’t thought about using it to change the setpoint of a velocity controller, that’s cool.
Here is the pseudo code of how we do it.
change = joystick * limit
setpoint = setpoint + change
if setpoint > max
setpoint = max
else if setpoint < min
setpoint = min
send setpoint to controller
Something’s wrong with the above.
If the joystick is 0, the setpoint never changes.