In this example we'll use the asc::History class to create a simple controller for a spring-mass-damper system.
Control.h
#pragma once #include "ascent/history/History.h" #include "ascent/Link.h" class Control : public asc::Module { public: double x{}, xd{}, xdd{}; // We are going to control a simple mass-spring-damper system: x'' + 2*zeta*wn*x' + wn*wn*x = f/m double x_target{}; // Desired x value double f{}; // force applied double m = 1.0; // mass double wn = sqrt(40); // Hz double zeta = 0.7; asc::History error; // History of the error. double Kp{}; // Proportional gain double Ki{}; // Integral gain double Kd{}; // Derivative gain Control(size_t sim); protected: void update(); void postcalc(); };
Control.cpp
#include "Control.h" Control::Control(size_t sim) : asc::Module(sim), error(sim) { addIntegrator(x, xd); addIntegrator(xd, xdd); #define ascNS Control ascVar(x) ascVar(x_target) } void Control::update() { xdd = -2.0*zeta*wn*xd - wn*wn*x + f / m; // This may seem simpler than the Spring-Damper example, but it is far less flexible. } void Control::postcalc() { error.push_back(x_target - x); f = Kp*error.back() + Ki * error.integral() + Kd*error.derivative(); }
Initializing and Running
Main.cpp
Setup tracking, run the simulation, and generate output file.
#include "Control.h" int main() { Control control(0); control.name<Control>("control"); control.Kp = 300.0; control.Ki = 300.0; control.Kd = 10.0; control.x_target = 1.0; control.track("t"); control.track("x"); control.track("x_target"); control.run(0.01, 1.0); control.outputTrack(); return 0; }
Generated File
control.csv
t,control x,control x_target 0,0.000000,1.000000 0.01,0.000000,1.000000 0.02,0.014562,1.000000 0.03,0.055761,1.000000 0.04,0.118031,1.000000 0.05,0.195357,1.000000 continued...