Controller Class
The controller class is central the this library as it has connections to many other components. To ensure compatibility with all components, controllers should always inherit from the abstract_controller class. The abstract controller class can optionally do logging, state filtering, friction compensation and gravity compensation.
Class Methods
Every specific controller, inheriting from the abstract controller class has to implement a
controller.get_control_output_(self, x, t)
method, which should return an array-like object with shape=(2,) representing
the torques to be sent to the motors. The get_control_output_
or more
precisely the get_control_output
(without underscore) of the abstract
controller will be called by the simulator and the hardware control loop during
hardware experiments.
In addition to this function controllers can optionally have the methods
controller.set_parameters(self, ...)
controller.set_goal(self, goal)
controller.init_(self)
controller.reset_(self)
controller.save_(self, save_dir)
controller.get_forecast(self)
controller.get_init_trajectory(self)
set_parameter
can be used to set controller specific parameters and
set_goal
can be used to set the goal and maybe compute internal controller
properties which depend on the goal.
The init_
method will be called before the execution and reset_
can
be used to reset parameters inside the controller. save_
is used to store
controller parameters to be able retrace the controller properties after
execution. get_forecast
can be implemented in predictive controllers to
return the predicted trajectory and get_init_trajectory
can return the
initialy planned trajectory of the controller (e.g. the trajectory a controller
is supposed to stabilize). If the latter two trajectory returning methods are
implemented these trajectories can ba plotted in the animation funciton of the
simulator.
Logging, Filtering and Compensation
The abstract controller class has methods implemented for logging, state filtering and friction/gravity compensation.
To use the state filtering one has to call set_filter_args
method with the
desired filter parameters. The filter is then initialized during the
controller.init
and incoming state measurements are filtered before being
parsed to the get_control_output_
method. By default no filtering is used.
Friction compensation can be turned on by calling set_friction_compensation
with the desired friction parameters. Gravity compensation is activated with
set_gravity_compensation
with a plant object as parameter. Note that gravity
can only be fully compensated on the fully actuated double pendulum. Friction
and gravity compensation torques are both added to the torque returned by the
get_control_output_
method.
The controller internally logs the total controller torque in u_hist
, the
friciton compensation torque in u_fric_hist
, the gravity compensation torque
in u_grav_hist
, the state history in x_hist
and the filtered states in
xfilt_hist
and they can be accesses via the controller object.
Writing your own controller
If you want to write your own controller you may want to use the template below.
The only method that is strictly necessary and has to be implemented is the
get_control_output
method. The other methods are optional.
from double_pendulum.controller.abstract_controller import AbstractController
class ControllerTemplate(AbstractController):
"""Controller Template"""
def __init__(self):
super().__init__()
def set_parameters(self):
"""
Set controller parameters. Optional.
Can be overwritten by actual controller.
"""
pass
def set_goal(self, x):
"""
Set the desired state for the controller. Optional.
Can be overwritten by actual controller.
Parameters
----------
x : array_like, shape=(4,), dtype=float,
state of the double pendulum,
order=[angle1, angle2, velocity1, velocity2],
units=[rad, rad, rad/s, rad/s]
"""
self.goal = x
def init_(self):
"""
Initialize the controller. Optional.
Can be overwritten by actual controller.
Initialize function which will always be called before using the
controller.
"""
pass
def reset_(self):
"""
Reset the Controller. Optional
Can be overwritten by actual controller.
Function to reset parameters inside the controller.
"""
pass
def get_control_output_(self, x, t=None):
"""
The function to compute the control input for the double pendulum's
actuator(s).
Supposed to be overwritten by actual controllers. The API of this
method should not be changed. Unused inputs/outputs can be set to None.
Parameters
----------
x : array_like, shape=(4,), dtype=float,
state of the double pendulum,
order=[angle1, angle2, velocity1, velocity2],
units=[rad, rad, rad/s, rad/s]
t : float, optional
time, unit=[s]
(Default value=None)
Returns
-------
array_like
shape=(2,), dtype=float
actuation input/motor torque,
order=[u1, u2],
units=[Nm]
"""
u = [0.0, 0.0]
return u
def save_(self, save_dir):
"""
Save controller parameters. Optional
Can be overwritten by actual controller.
Parameters
----------
save_dir : string or path object
directory where the parameters will be saved
"""
pass
def get_forecast(self):
"""
Get a forecast trajectory as planned by the controller. Optional.
Can be overwritten by actual controller.
Returns
-------
list
Time array
list
X array
list
U array
"""
return [], [], []
def get_init_trajectory(self):
"""
Get an initial (reference) trajectory used by the controller. Optional.
Can be overwritten by actual controller.
Returns
-------
list
Time array
list
X array
list
U array
"""
return [], [], []