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.
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
get_control_output (without underscore) of the abstract
controller will be called by the simulator and the hardware control loop during
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.
init_ method will be called before the execution and
be used to reset parameters inside the controller.
save_ is used to store
controller parameters to be able retrace the controller properties after
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
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
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
The controller internally logs the total controller torque in
friciton compensation torque in
u_fric_hist, the gravity compensation torque
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 , ,