blob: d6040d11eca6072085e47c3a8b0f6de61e680254 [file] [log] [blame]
from frc971.control_loops.python import angular_system
from frc971.control_loops.python import control_loop
from frc971.control_loops.python import controls
from aos.util.trapezoid_profile import TrapezoidProfile
import numpy
from matplotlib import pylab
import gflags
import glog
CatapultParams = angular_system.AngularSystemParams
# TODO(austin): This is mostly the same as angular_system. Can we either wrap an angular_system or assign it?
class Catapult(angular_system.AngularSystem):
def __init__(self, params, name="Catapult"):
super(Catapult, self).__init__(params, name)
# Signal that we have a single cycle output delay to compensate for in
# our observer.
self.delayed_u = True
self.InitializeState()
class IntegralCatapult(angular_system.IntegralAngularSystem):
def __init__(self, params, name="IntegralCatapult"):
super(IntegralCatapult, self).__init__(params, name=name)
# Signal that we have a single cycle output delay to compensate for in
# our observer.
self.delayed_u = True
self.InitializeState()
def MaxSpeed(params, U, final_position):
"""Runs the catapult plant with an initial condition and goal.
Args:
catapult: Catapult object to use.
goal: goal state.
iterations: Number of timesteps to run the model for.
controller_catapult: Catapult object to get K from, or None if we should
use catapult.
observer_catapult: Catapult object to use for the observer, or None if we
should use the actual state.
"""
# Various lists for graphing things.
catapult = Catapult(params, params.name)
controller_catapult = IntegralCatapult(params, params.name)
observer_catapult = IntegralCatapult(params, params.name)
vbat = 12.0
while True:
X_hat = catapult.X
if catapult.X[0, 0] > final_position:
return catapult.X[1, 0] * params.radius
if observer_catapult is not None:
X_hat = observer_catapult.X_hat
U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat)
if observer_catapult is not None:
observer_catapult.Y = catapult.Y
observer_catapult.CorrectObserver(U)
applied_U = U.copy()
catapult.Update(applied_U)
if observer_catapult is not None:
observer_catapult.PredictObserver(U)
def PlotShot(params, U, final_position):
"""Runs the catapult plant with an initial condition and goal.
Args:
catapult: Catapult object to use.
goal: goal state.
iterations: Number of timesteps to run the model for.
controller_catapult: Catapult object to get K from, or None if we should
use catapult.
observer_catapult: Catapult object to use for the observer, or None if we
should use the actual state.
"""
# Various lists for graphing things.
t = []
x = []
x_hat = []
v = []
w_hat = []
v_hat = []
a = []
u = []
offset = []
catapult = Catapult(params, params.name)
controller_catapult = IntegralCatapult(params, params.name)
observer_catapult = IntegralCatapult(params, params.name)
vbat = 12.0
if t:
initial_t = t[-1] + catapult.dt
else:
initial_t = 0
for i in range(10000):
X_hat = catapult.X
if catapult.X[0, 0] > final_position:
break
if observer_catapult is not None:
X_hat = observer_catapult.X_hat
x_hat.append(observer_catapult.X_hat[0, 0])
w_hat.append(observer_catapult.X_hat[1, 0])
v_hat.append(observer_catapult.X_hat[1, 0] * params.radius)
U[0, 0] = numpy.clip(U[0, 0], -vbat, vbat)
x.append(catapult.X[0, 0])
if v:
last_v = v[-1]
else:
last_v = 0
v.append(catapult.X[1, 0])
a.append((v[-1] - last_v) / catapult.dt)
if observer_catapult is not None:
observer_catapult.Y = catapult.Y
observer_catapult.CorrectObserver(U)
offset.append(observer_catapult.X_hat[2, 0])
catapult.Update(U)
if observer_catapult is not None:
observer_catapult.PredictObserver(U)
t.append(initial_t + i * catapult.dt)
u.append(U[0, 0])
pylab.subplot(3, 1, 1)
pylab.plot(t, v, label='v')
pylab.plot(t, x_hat, label='x_hat')
pylab.plot(t, v, label='v')
pylab.plot(t, v_hat, label='v_hat')
pylab.plot(t, w_hat, label='w_hat')
pylab.legend()
pylab.subplot(3, 1, 2)
pylab.plot(t, u, label='u')
pylab.plot(t, offset, label='voltage_offset')
pylab.legend()
pylab.subplot(3, 1, 3)
pylab.plot(t, a, label='a')
pylab.legend()
pylab.show()
RunTest = angular_system.RunTest
def PlotStep(params, R, plant_params=None):
"""Plots a step move to the goal.
Args:
params: CatapultParams for the controller and observer
plant_params: CatapultParams for the plant. Defaults to params if
plant_params is None.
R: numpy.matrix(2, 1), the goal"""
plant = Catapult(plant_params or params, params.name)
controller = IntegralCatapult(params, params.name)
observer = IntegralCatapult(params, params.name)
# Test moving the system.
initial_X = numpy.matrix([[0.0], [0.0]])
augmented_R = numpy.matrix(numpy.zeros((3, 1)))
augmented_R[0:2, :] = R
RunTest(plant,
end_goal=augmented_R,
controller=controller,
observer=observer,
duration=2.0,
use_profile=False,
kick_time=1.0,
kick_magnitude=0.0)
def PlotKick(params, R, plant_params=None):
"""Plots a step motion with a kick at 1.0 seconds.
Args:
params: CatapultParams for the controller and observer
plant_params: CatapultParams for the plant. Defaults to params if
plant_params is None.
R: numpy.matrix(2, 1), the goal"""
plant = Catapult(plant_params or params, params.name)
controller = IntegralCatapult(params, params.name)
observer = IntegralCatapult(params, params.name)
# Test moving the system.
initial_X = numpy.matrix([[0.0], [0.0]])
augmented_R = numpy.matrix(numpy.zeros((3, 1)))
augmented_R[0:2, :] = R
RunTest(plant,
end_goal=augmented_R,
controller=controller,
observer=observer,
duration=2.0,
use_profile=False,
kick_time=1.0,
kick_magnitude=2.0)
def PlotMotion(params,
R,
max_velocity=10.0,
max_acceleration=70.0,
plant_params=None):
"""Plots a trapezoidal motion.
Args:
params: CatapultParams for the controller and observer
plant_params: CatapultParams for the plant. Defaults to params if
plant_params is None.
R: numpy.matrix(2, 1), the goal,
max_velocity: float, The max velocity of the profile.
max_acceleration: float, The max acceleration of the profile.
"""
plant = Catapult(plant_params or params, params.name)
controller = IntegralCatapult(params, params.name)
observer = IntegralCatapult(params, params.name)
# Test moving the system.
initial_X = numpy.matrix([[0.0], [0.0]])
augmented_R = numpy.matrix(numpy.zeros((3, 1)))
augmented_R[0:2, :] = R
RunTest(plant,
end_goal=augmented_R,
controller=controller,
observer=observer,
duration=2.0,
use_profile=True,
max_velocity=max_velocity,
max_acceleration=max_acceleration)
def WriteCatapult(params, plant_files, controller_files, year_namespaces):
"""Writes out the constants for a catapult to a file.
Args:
params: list of CatapultParams or CatapultParams, the
parameters defining the system.
plant_files: list of strings, the cc and h files for the plant.
controller_files: list of strings, the cc and h files for the integral
controller.
year_namespaces: list of strings, the namespace list to use.
"""
# Write the generated constants out to a file.
catapults = []
integral_catapults = []
if type(params) is list:
name = params[0].name
for index, param in enumerate(params):
catapults.append(Catapult(param, param.name + str(index)))
integral_catapults.append(
IntegralCatapult(param, 'Integral' + param.name + str(index)))
else:
name = params.name
catapults.append(Catapult(params, params.name))
integral_catapults.append(
IntegralCatapult(params, 'Integral' + params.name))
loop_writer = control_loop.ControlLoopWriter(name,
catapults,
namespaces=year_namespaces)
loop_writer.AddConstant(
control_loop.Constant('kOutputRatio', '%f', catapults[0].G))
loop_writer.AddConstant(
control_loop.Constant('kFreeSpeed', '%f',
catapults[0].motor.free_speed))
loop_writer.Write(plant_files[0], plant_files[1])
integral_loop_writer = control_loop.ControlLoopWriter(
'Integral' + name, integral_catapults, namespaces=year_namespaces)
integral_loop_writer.Write(controller_files[0], controller_files[1])