- 3.0.2 core module.
ControlSimulator.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
8 #include <atomic>
9 #include <chrono>
10 #include <thread>
11 #include <memory>
12 
13 #include <ct/core/types/Time.h>
17 
18 namespace ct {
19 namespace core {
20 
22 
28 template <class CONTROLLED_SYSTEM>
30 {
31 public:
32  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
33 
34  static const size_t STATE_DIM = CONTROLLED_SYSTEM::STATE_DIM;
35  static const size_t CONTROL_DIM = CONTROLLED_SYSTEM::CONTROL_DIM;
36 
37  using SCALAR = typename CONTROLLED_SYSTEM::SCALAR;
38 
40  ControlSimulator() = default;
43  Time control_dt,
44  const StateVector<STATE_DIM>& x0,
45  std::shared_ptr<CONTROLLED_SYSTEM> controlled_system,
46  bool verbose = false)
47  : sim_dt_(sim_dt), control_dt_(control_dt), x0_(x0), system_(controlled_system), stop_(false), verbose_(verbose)
48  {
49  system_->getController(controller_);
50  if (sim_dt_ <= 0 || control_dt_ <= 0)
51  throw std::runtime_error("Step sizes must be positive.");
52  if (sim_dt_ > control_dt_)
53  throw std::runtime_error("Simulation step must be smaller than the control step.");
54  }
55 
58  : sim_dt_(arg.sim_dt_), control_dt_(arg.control_dt_), x0_(arg.x0_), stop_(arg.stop_)
59  {
60  if (!arg.system_)
61  return;
62  system_ = std::shared_ptr<Controller<STATE_DIM, CONTROL_DIM, SCALAR>>(arg.system_->clone());
63  if (arg.controller_)
64  {
65  controller_ = std::shared_ptr<Controller<STATE_DIM, CONTROL_DIM, SCALAR>>(arg.controller_->clone());
66  system_->setController(controller_);
67  }
68  }
69 
71  virtual ~ControlSimulator() { finish(); };
73  virtual void finishSystemIteration(Time sim_time) {}
75  virtual void prepareControllerIteration(Time sim_time) {}
77  virtual void finishControllerIteration(Time sim_time) {}
79  void simulate(Time duration, const IntegrationType& intType = IntegrationType::EULERCT)
80  {
81  stop_ = false;
82  sim_start_time_ = std::chrono::high_resolution_clock::now();
83  x_ = x0_;
84  sys_thread_ = std::thread(&ControlSimulator::simulateSystem, this, duration, std::ref(intType));
85  control_thread_ = std::thread(&ControlSimulator::simulateController, this, duration);
86  }
87 
89  void finish()
90  {
91  if (sys_thread_.joinable())
92  sys_thread_.join();
93  if (control_thread_.joinable())
94  control_thread_.join();
95  }
96 
98  void stop() { stop_ = true; }
99 protected:
101  virtual void simulateSystem(Time duration, const IntegrationType& intType = IntegrationType::EULERCT)
102  {
103  try
104  {
105  Integrator<STATE_DIM> integrator(system_, intType);
106  StateVector<STATE_DIM> temp_x = x_;
107  // In case an integer number of steps cannot be performed
108  const double residue = control_dt_ / sim_dt_ - int(control_dt_ / sim_dt_);
109  auto wall_time = sim_start_time_;
110  Time sim_time = std::chrono::duration<double>(wall_time - sim_start_time_).count();
111 
112  while (std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - sim_start_time_).count() <
113  duration &&
114  !stop_)
115  {
116  integrator.integrate_n_steps(temp_x, sim_time, int(control_dt_ / sim_dt_), sim_dt_);
117  if (residue > 1e-6)
118  integrator.integrate_n_steps(temp_x, sim_time + int(control_dt_ / sim_dt_) * sim_dt_, 1, residue);
119 
120  if (std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - wall_time).count() >=
121  control_dt_)
122  {
123  if (verbose_)
124  std::cerr << "Simulation running too slow. Please increase the step size!" << std::endl;
125  }
126  else
127  std::this_thread::sleep_until(wall_time + std::chrono::duration<double>(control_dt_));
128 
129  wall_time += std::chrono::duration_cast<std::chrono::system_clock::duration>(
130  std::chrono::duration<double>(control_dt_));
131 
132  state_mtx_.lock();
133  x_ = temp_x;
134  state_mtx_.unlock();
135 
136  sim_time = std::chrono::duration<double>(wall_time - sim_start_time_).count();
137  finishSystemIteration(sim_time);
138  }
139  } catch (std::exception& e)
140  {
141  std::cout << e.what() << std::endl;
142  throw(std::runtime_error("Control Simulator failed."));
143  }
144  }
145 
147  virtual void simulateController(Time duration)
148  {
149  try
150  {
151  Time sim_time;
152  while (std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - sim_start_time_).count() <
153  duration &&
154  !stop_)
155  {
156  sim_time =
157  std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - sim_start_time_).count();
158  prepareControllerIteration(sim_time);
159 
160  sim_time =
161  std::chrono::duration<double>(std::chrono::high_resolution_clock::now() - sim_start_time_).count();
162  finishControllerIteration(sim_time);
163  }
164  } catch (std::exception& e)
165  {
166  std::cout << e.what() << std::endl;
167  throw(std::runtime_error("Control Simulator failed."));
168  }
169  }
170 
173  std::shared_ptr<CONTROLLED_SYSTEM> system_;
174  std::shared_ptr<Controller<STATE_DIM, CONTROL_DIM, SCALAR>> controller_;
175  std::chrono::time_point<std::chrono::high_resolution_clock> sim_start_time_;
178  std::thread sys_thread_;
179  std::thread control_thread_;
180  std::mutex state_mtx_;
181  std::mutex control_mtx_;
182  std::atomic<bool> stop_;
183  bool verbose_;
184 };
185 
186 } // namespace core
187 } // namespace ct
void stop()
stops the simulation
Definition: ControlSimulator.h:98
void integrate_n_steps(StateVector< STATE_DIM, SCALAR > &state, const SCALAR &startTime, size_t numSteps, SCALAR dt, StateVectorArray< STATE_DIM, SCALAR > &stateTrajectory, tpl::TimeArray< SCALAR > &timeTrajectory)
Equidistant integration based on number of time steps and step length.
Definition: Integrator-impl.h:50
virtual void prepareControllerIteration(Time sim_time)
During controller update, this method does processing before the state measurement arrives...
Definition: ControlSimulator.h:75
StateVector< STATE_DIM > x0_
Definition: ControlSimulator.h:176
std::shared_ptr< CONTROLLED_SYSTEM > system_
Definition: ControlSimulator.h:173
void simulate(Time duration, const IntegrationType &intType=IntegrationType::EULERCT)
spawns the two threads in a nonblocking way
Definition: ControlSimulator.h:79
ControlSimulator(Time sim_dt, Time control_dt, const StateVector< STATE_DIM > &x0, std::shared_ptr< CONTROLLED_SYSTEM > controlled_system, bool verbose=false)
constructor
Definition: ControlSimulator.h:42
std::atomic< bool > stop_
Definition: ControlSimulator.h:182
typename CONTROLLED_SYSTEM::SCALAR SCALAR
Definition: ControlSimulator.h:37
virtual ~ControlSimulator()
destructor
Definition: ControlSimulator.h:71
std::shared_ptr< Controller< STATE_DIM, CONTROL_DIM, SCALAR > > controller_
Definition: ControlSimulator.h:174
static EIGEN_MAKE_ALIGNED_OPERATOR_NEW const size_t STATE_DIM
Definition: ControlSimulator.h:34
std::mutex control_mtx_
Definition: ControlSimulator.h:181
A class for simulating controlled systems in a general way.
Definition: ControlSimulator.h:29
virtual void finishSystemIteration(Time sim_time)
Gets called after the integrator step.
Definition: ControlSimulator.h:73
virtual void simulateController(Time duration)
run by the thread that updates the controller
Definition: ControlSimulator.h:147
std::thread sys_thread_
Definition: ControlSimulator.h:178
std::thread control_thread_
Definition: ControlSimulator.h:179
Time sim_dt_
Definition: ControlSimulator.h:171
Standard Integrator.
Definition: Integrator.h:62
Definition: Integrator.h:39
const bool verbose
Definition: JacobianCGTest.h:19
static const size_t CONTROL_DIM
Definition: ControlSimulator.h:35
ControlSimulator(const ControlSimulator &arg)
copy constructor
Definition: ControlSimulator.h:57
ControlSimulator()=default
default constructor
virtual void finishControllerIteration(Time sim_time)
During controller update, this method does processing once the state measurement arrives.
Definition: ControlSimulator.h:77
Time control_dt_
Definition: ControlSimulator.h:172
std::chrono::time_point< std::chrono::high_resolution_clock > sim_start_time_
Definition: ControlSimulator.h:175
bool verbose_
Definition: ControlSimulator.h:183
virtual void simulateSystem(Time duration, const IntegrationType &intType=IntegrationType::EULERCT)
run by the thread that simulates the system
Definition: ControlSimulator.h:101
StateVector< STATE_DIM > x_
Definition: ControlSimulator.h:177
std::mutex state_mtx_
Definition: ControlSimulator.h:180
double Time
Definition: Time.h:11
IntegrationType
The available integration types.
Definition: Integrator.h:30
void finish()
waits for the simulation threads to finish
Definition: ControlSimulator.h:89