Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wpimath] fully discretized ElevatorFF and ArmFF #7024

Merged
merged 74 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
22c63dd
discretized calculate overloads in Elevator FF
narmstro2020 Sep 2, 2024
8df1e01
initial simple and elevator cleanup/disc
narmstro2020 Sep 2, 2024
0c9df14
added mutable measure for calculated output
narmstro2020 Sep 2, 2024
b47b679
fix to arm structs
narmstro2020 Sep 2, 2024
6cb02a9
SimpleMotorFF C++ first draft
narmstro2020 Sep 3, 2024
3e6a303
formatting fixes
narmstro2020 Sep 3, 2024
8232f6d
ElevatorFF C++ first draft
narmstro2020 Sep 3, 2024
8c8eb58
minor comment out fix
narmstro2020 Sep 3, 2024
d7ba075
Formatting fixes
github-actions[bot] Sep 3, 2024
f7c33d7
Arm first draft C++
narmstro2020 Sep 3, 2024
782e335
Formatting fixes
github-actions[bot] Sep 3, 2024
4e0d048
removed deprecated tests
narmstro2020 Sep 3, 2024
162e977
fixed armFFTest
narmstro2020 Sep 3, 2024
b043a2e
more fixes to ArmFFTests
narmstro2020 Sep 3, 2024
6831552
modification to controller.proto
narmstro2020 Sep 3, 2024
6adb65c
revert controller.java
narmstro2020 Sep 3, 2024
07dc5e2
tiny formatting issue
narmstro2020 Sep 3, 2024
7dfd21a
Regenerate pregenerated files
github-actions[bot] Sep 3, 2024
aee2ac7
fixed some more documentaiton
narmstro2020 Sep 3, 2024
8467501
Merge branch 'FFCalculates' of https://github.com/narmstro2020/allwpi…
narmstro2020 Sep 3, 2024
e5c321a
fixed a doc issue
narmstro2020 Sep 3, 2024
157ee4b
fixed method for arm
narmstro2020 Sep 3, 2024
78bcbf0
empty commit
narmstro2020 Sep 3, 2024
fe3743b
revert ArmFeedforward method back
narmstro2020 Sep 4, 2024
57648cd
Formatting fixes
github-actions[bot] Sep 4, 2024
053af7f
doc fix
narmstro2020 Sep 4, 2024
6966028
fixed recursive mistake
narmstro2020 Sep 4, 2024
f5a9b29
use continuous equation for single velocity overload
narmstro2020 Sep 4, 2024
219a976
Formatting fixes
github-actions[bot] Sep 4, 2024
87cab16
Merge branch 'main' into FFCalculates
narmstro2020 Sep 7, 2024
5056bd0
fixed based of new Units API
narmstro2020 Sep 7, 2024
51cf78e
unwrapped constant in Frisbeebot example
narmstro2020 Sep 13, 2024
fedb57d
empty
narmstro2020 Sep 13, 2024
a35f8e4
java doc cleanup for Arm
narmstro2020 Sep 13, 2024
faae22a
removal of duplicate code in ArmFeedforward.cpp
narmstro2020 Sep 13, 2024
23627fb
doc fix and duplication fix
narmstro2020 Sep 13, 2024
bab93d6
variable fix
narmstro2020 Sep 13, 2024
0529b7d
Formatting fixes
github-actions[bot] Sep 13, 2024
5043a23
Update wpilibcExamples/src/main/cpp/examples/SysId/include/Constants.h
narmstro2020 Sep 13, 2024
edb85cc
Update wpilibcExamples/src/main/cpp/examples/RapidReactCommandBot/inc…
narmstro2020 Sep 13, 2024
a71696f
Update wpimath/src/main/native/include/frc/controller/ElevatorFeedfor…
narmstro2020 Sep 13, 2024
dda16c5
Update wpimath/src/main/java/edu/wpi/first/math/controller/ElevatorFe…
narmstro2020 Sep 13, 2024
8ce86ee
Update wpimath/src/main/native/include/frc/controller/ArmFeedforward.h
narmstro2020 Sep 13, 2024
8e74de6
fix variable reassignment
narmstro2020 Sep 13, 2024
0075619
Formatting fixes
github-actions[bot] Sep 13, 2024
48d2ea8
fixed comment formatting
narmstro2020 Sep 13, 2024
4a3f773
comment formatting fix.
narmstro2020 Sep 13, 2024
6e8b2b7
another fix to comments.
narmstro2020 Sep 13, 2024
d75021b
more formatting fixes.
narmstro2020 Sep 13, 2024
6e81ff7
added 1 space to math indents
narmstro2020 Sep 13, 2024
e76cd03
Formatting fixes
github-actions[bot] Sep 13, 2024
972882b
put comment back in
narmstro2020 Sep 13, 2024
da3cce7
rearrangement
narmstro2020 Sep 13, 2024
d3360f1
Formatting fixes
github-actions[bot] Sep 13, 2024
abf3d60
Update wpimath/src/main/java/edu/wpi/first/math/controller/ElevatorFe…
narmstro2020 Sep 13, 2024
ff91176
Update wpimath/src/main/java/edu/wpi/first/math/controller/ArmFeedfor…
narmstro2020 Sep 13, 2024
097ea4b
cleaning up math derivation comments
narmstro2020 Sep 14, 2024
bc9ddf4
Formatting fixes
github-actions[bot] Sep 14, 2024
9692d52
fix missing periods
narmstro2020 Sep 14, 2024
89f1c71
Merge branch 'FFCalculates' of https://github.com/narmstro2020/allwpi…
narmstro2020 Sep 14, 2024
a726b8b
derivation moved to algorithms.md
narmstro2020 Sep 14, 2024
52443ac
Formatting fixes
github-actions[bot] Sep 14, 2024
50b3cb7
Merge branch 'wpilibsuite:main' into FFCalculates
narmstro2020 Sep 21, 2024
07087b6
Merge branch 'wpilibsuite:main' into FFCalculates
narmstro2020 Sep 29, 2024
9bc9366
added continuous control comment
narmstro2020 Sep 30, 2024
b3fdf03
Merge branch 'FFCalculates' of https://github.com/narmstro2020/allwpi…
narmstro2020 Sep 30, 2024
e1e1dfd
Formatting fixes
github-actions[bot] Sep 30, 2024
894d42c
added 1 comment for feedback on derivation comment
narmstro2020 Sep 30, 2024
9f1a970
Merge branch 'FFCalculates' of https://github.com/narmstro2020/allwpi…
narmstro2020 Sep 30, 2024
1ab61f3
derivation comments complete
narmstro2020 Sep 30, 2024
5620c57
Formatting fixes
github-actions[bot] Sep 30, 2024
c4e95f1
added derivation comment
narmstro2020 Sep 30, 2024
ddc4c22
Merge branch 'FFCalculates' of https://github.com/narmstro2020/allwpi…
narmstro2020 Sep 30, 2024
3b4d8c3
Formatting fixes
github-actions[bot] Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void Elevator::ReachGoal(units::meter_t goal) {
auto pidOutput = m_controller.Calculate(m_encoder.GetDistance(),
m_setpoint.position / 1_m);
auto feedforwardOutput =
m_feedforward.Calculate(m_setpoint.velocity, next.velocity, 20_ms);
m_feedforward.Calculate(m_setpoint.velocity, next.velocity);

m_motor.SetVoltage(units::volt_t{pidOutput} + feedforwardOutput);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <numbers>

#include <units/angle.h>
#include <units/angular_velocity.h>
#include <units/time.h>
#include <units/voltage.h>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ class ShooterSubsystem : public frc2::PIDSubsystem {
frc::PWMSparkMax m_shooterMotor;
frc::PWMSparkMax m_feederMotor;
frc::Encoder m_shooterEncoder;
frc::SimpleMotorFeedforward<units::turns> m_shooterFeedforward;
frc::SimpleMotorFeedforward<units::radians> m_shooterFeedforward;
};
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Shooter : public frc2::SubsystemBase {
frc::Encoder m_shooterEncoder{ShooterConstants::kEncoderPorts[0],
ShooterConstants::kEncoderPorts[1],
ShooterConstants::kEncoderReversed};
frc::SimpleMotorFeedforward<units::turns> m_shooterFeedforward{
frc::SimpleMotorFeedforward<units::radians> m_shooterFeedforward{
ShooterConstants::kS, ShooterConstants::kV};
frc::PIDController m_shooterFeedback{ShooterConstants::kP, 0.0, 0.0};
};
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ inline constexpr units::turns_per_second_t kShooterTolerance = 50_tps;
inline constexpr double kP = 1.0;

inline constexpr units::volt_t kS = 0.05_V;
inline constexpr kv_unit_t kV = (12_V) / kShooterFreeSpeed;
inline constexpr kv_unit_t kV = 12_V / kShooterFreeSpeed;
inline constexpr ka_unit_t kA = 0_V * 1_s * 1_s / 1_tr;

inline constexpr double kFeederSpeed = 0.5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ class Shooter : public frc2::SubsystemBase {
},
this}};
frc::PIDController m_shooterFeedback{constants::shooter::kP, 0, 0};
frc::SimpleMotorFeedforward<units::turns> m_shooterFeedforward{
frc::SimpleMotorFeedforward<units::radians> m_shooterFeedforward{
constants::shooter::kS, constants::shooter::kV, constants::shooter::kA};
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

package edu.wpi.first.wpilibj.examples.armbot.subsystems;

import static edu.wpi.first.units.Units.Radians;
import static edu.wpi.first.units.Units.RadiansPerSecond;
import static edu.wpi.first.units.Units.Volts;

import edu.wpi.first.math.controller.ArmFeedforward;
import edu.wpi.first.math.controller.ProfiledPIDController;
import edu.wpi.first.math.trajectory.TrapezoidProfile;
Expand Down Expand Up @@ -41,7 +45,10 @@ public ArmSubsystem() {
@Override
public void useOutput(double output, TrapezoidProfile.State setpoint) {
// Calculate the feedforward from the sepoint
double feedforward = m_feedforward.calculate(setpoint.position, setpoint.velocity);
double feedforward =
m_feedforward
.calculate(Radians.of(setpoint.position), RadiansPerSecond.of(setpoint.velocity))
.in(Volts);
// Add the feedforward to the PID output to get the motor output
m_motor.setVoltage(output + feedforward);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

package edu.wpi.first.wpilibj.examples.armbotoffboard.subsystems;

import static edu.wpi.first.units.Units.Radians;
import static edu.wpi.first.units.Units.RadiansPerSecond;
import static edu.wpi.first.units.Units.Volts;

import edu.wpi.first.math.controller.ArmFeedforward;
import edu.wpi.first.math.trajectory.TrapezoidProfile;
import edu.wpi.first.wpilibj.examples.armbotoffboard.Constants.ArmConstants;
Expand Down Expand Up @@ -33,7 +37,10 @@ public ArmSubsystem() {
@Override
public void useState(TrapezoidProfile.State setpoint) {
// Calculate the feedforward from the sepoint
double feedforward = m_feedforward.calculate(setpoint.position, setpoint.velocity);
double feedforward =
m_feedforward
.calculate(Radians.of(setpoint.position), RadiansPerSecond.of(setpoint.velocity))
.in(Volts);
// Add the feedforward to the PID output to get the motor output
m_motor.setSetpoint(
ExampleSmartMotorController.PIDMode.kPosition, setpoint.position, feedforward / 12.0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

package edu.wpi.first.wpilibj.examples.elevatorexponentialsimulation.subsystems;

import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.Volts;

import edu.wpi.first.math.controller.ElevatorFeedforward;
import edu.wpi.first.math.controller.PIDController;
import edu.wpi.first.math.system.plant.DCMotor;
Expand Down Expand Up @@ -110,7 +113,10 @@ public void reachGoal(double goal) {

// With the setpoint value we run PID control like normal
double pidOutput = m_pidController.calculate(m_encoder.getDistance(), m_setpoint.position);
double feedforwardOutput = m_feedforward.calculate(m_setpoint.velocity, next.velocity, 0.020);
double feedforwardOutput =
m_feedforward
.calculate(MetersPerSecond.of(m_setpoint.velocity), MetersPerSecond.of(next.velocity))
.in(Volts);

m_motor.setVoltage(pidOutput + feedforwardOutput);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

package edu.wpi.first.wpilibj.examples.elevatorprofiledpid;

import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.Volts;

import edu.wpi.first.math.controller.ElevatorFeedforward;
import edu.wpi.first.math.controller.ProfiledPIDController;
import edu.wpi.first.math.trajectory.TrapezoidProfile;
Expand Down Expand Up @@ -51,6 +54,8 @@ public void teleopPeriodic() {
// Run controller and update motor output
m_motor.setVoltage(
m_controller.calculate(m_encoder.getDistance())
+ m_feedforward.calculate(m_controller.getSetpoint().velocity));
+ m_feedforward
.calculate(MetersPerSecond.of(m_controller.getSetpoint().velocity))
.in(Volts));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

package edu.wpi.first.wpilibj.examples.elevatorsimulation.subsystems;

import static edu.wpi.first.units.Units.MetersPerSecond;
import static edu.wpi.first.units.Units.Volts;

import edu.wpi.first.math.controller.ElevatorFeedforward;
import edu.wpi.first.math.controller.ProfiledPIDController;
import edu.wpi.first.math.system.plant.DCMotor;
Expand Down Expand Up @@ -101,7 +104,8 @@ public void reachGoal(double goal) {

// With the setpoint value we run PID control like normal
double pidOutput = m_controller.calculate(m_encoder.getDistance());
double feedforwardOutput = m_feedforward.calculate(m_controller.getSetpoint().velocity);
double feedforwardOutput =
m_feedforward.calculate(MetersPerSecond.of(m_controller.getSetpoint().velocity)).in(Volts);
m_motor.setVoltage(pidOutput + feedforwardOutput);
}

Expand Down
214 changes: 214 additions & 0 deletions wpimath/algorithms.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,219 @@
# Algorithms

## Simple motor feedforward

### Derivation

For a simple DC motor with the model

```
dx/dt = −kᵥ/kₐ x + 1/kₐ u - kₛ/kₐ sgn(x),
```

where

```
A = −kᵥ/kₐ
B = 1/kₐ
c = -kₛ/kₐ sgn(x)
A_d = eᴬᵀ
B_d = A⁻¹(eᴬᵀ - I)B
dx/dt = Ax + Bu + c
```

Discretize the affine model.

```
dx/dt = Ax + Bu + c
dx/dt = Ax + B(u + B⁺c)
xₖ₊₁ = eᴬᵀxₖ + A⁻¹(eᴬᵀ - I)B(uₖ + B⁺cₖ)
xₖ₊₁ = A_d xₖ + B_d (uₖ + B⁺cₖ)
xₖ₊₁ = A_d xₖ + B_d uₖ + B_d B⁺cₖ
```

Solve for uₖ.

```
B_d uₖ = xₖ₊₁ − A_d xₖ − B_d B⁺cₖ
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ − B_d B⁺cₖ)
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) − B⁺cₖ
```

Substitute in B assuming sgn(x) is a constant for the duration of the step.

```
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) − kₐ(-(kₛ/kₐ sgn(x)))
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) + kₐ(kₛ/kₐ sgn(x))
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) + kₛ sgn(x)
```

Simplify the model when kₐ = 0.

Simplify A.

```
A = −kᵥ/kₐ
```

As kₐ approaches zero, A approaches -∞.

```
A = −∞
```

Simplify A_d.

```
A_d = eᴬᵀ
A_d = exp(−∞)
A_d = 0
```

Simplify B_d.

```
B_d = A⁻¹(eᴬᵀ - I)B
B_d = A⁻¹((0) - I)B
B_d = A⁻¹(-I)B
B_d = -A⁻¹B
B_d = -(−kᵥ/kₐ)⁻¹(1/kₐ)
B_d = (kᵥ/kₐ)⁻¹(1/kₐ)
B_d = kₐ/kᵥ(1/kₐ)
B_d = 1/kᵥ
```

Substitute these into the feedforward equation.

```
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) + kₛ sgn(x)
uₖ = (1/kᵥ)⁺(xₖ₊₁ − (0) xₖ) + kₛ sgn(x)
uₖ = (1/kᵥ)⁺(xₖ₊₁) + kₛ sgn(x)
uₖ = kᵥxₖ₊₁ + kₛ sgn(x)
uₖ = kₛ sgn(x) + kᵥxₖ₊₁
```

Simplify the model when ka ≠ 0

```
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ)
```

where

```
A = −kᵥ/kₐ
B = 1/kₐ
A_d = eᴬᵀ
B_d = A⁻¹(eᴬᵀ - I)B
```

## Elevator feedforward

### Derivation

For an elevator with the model

```
dx/dt = −kᵥ/kₐ x + 1/kₐ u - kg/kₐ - kₛ/kₐ sgn(x)
```

where

```
A = −kᵥ/kₐ
B = 1/kₐ
c = -(kg/kₐ + kₛ/kₐ sgn(x))
A_d = eᴬᵀ
B_d = A⁻¹(eᴬᵀ - I)B
dx/dt = Ax + Bu + c
```

Discretize the affine model.

```
dx/dt = Ax + Bu + c
dx/dt = Ax + B(u + B⁺c)
xₖ₊₁ = eᴬᵀxₖ + A⁻¹(eᴬᵀ - I)B(uₖ + B⁺cₖ)
xₖ₊₁ = A_d xₖ + B_d (uₖ + B⁺cₖ)
xₖ₊₁ = A_d xₖ + B_d uₖ + B_d B⁺cₖ
```

Solve for uₖ.

```
B_d uₖ = xₖ₊₁ − A_d xₖ − B_d B⁺cₖ
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ − B_d B⁺cₖ)
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) − B⁺cₖ
```

Substitute in B assuming sgn(x) is a constant for the duration of the step.

```
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) − kₐ(-(kg/kₐ + kₛ/kₐ sgn(x)))
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) + kₐ(kg/kₐ + kₛ/kₐ sgn(x))
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) + kg + kₛ sgn(x)
```

Simplify the model when kₐ = 0.

Simplify A.

```
A = −kᵥ/kₐ
```

As kₐ approaches zero, A approaches -∞.

```
A = −∞
```

Simplify A_d.

```
A_d = eᴬᵀ
A_d = exp(−∞)
A_d = 0
```

Simplify B_d.

```
B_d = A⁻¹(eᴬᵀ - I)B
B_d = A⁻¹((0) - I)B
B_d = A⁻¹(-I)B
B_d = -A⁻¹B
B_d = -(−kᵥ/kₐ)⁻¹(1/kₐ)
B_d = (kᵥ/kₐ)⁻¹(1/kₐ)
B_d = kₐ/kᵥ(1/kₐ)
B_d = 1/kᵥ
```

Substitute these into the feedforward equation.

```
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ) + kg + kₛ sgn(x)
uₖ = (1/kᵥ)⁺(xₖ₊₁ − (0) xₖ) + kg + kₛ sgn(x)
uₖ = (1/kᵥ)⁺(xₖ₊₁) + kg + kₛ sgn(x)
uₖ = kᵥxₖ₊₁ + kg + kₛ sgn(x)
uₖ = kₛ sgn(x) + kg + kᵥxₖ₊₁
```

Simplify the model when ka ≠ 0

```
uₖ = B_d⁺(xₖ₊₁ − A_d xₖ)
```

where

```
A = −kᵥ/kₐ
B = 1/kₐ
A_d = eᴬᵀ
B_d = A⁻¹(eᴬᵀ - I)B
```

## Closed form Kalman gain for continuous Kalman filter with A = 0 and C = I

### Derivation
Expand Down
Loading
Loading