simulated_plant.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement
4  *
5  * Copyright (c) 2020,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  *
22  * Authors: Christoph Rösmann
23  *********************************************************************/
24 
26 #include <corbo-core/console.h>
29 #include <memory>
30 
31 namespace corbo {
32 
34 {
35  // default integrator
36  setIntegrator(std::make_shared<IntegratorExplicitEuler>());
37 }
38 
40 {
41  setSystemDynamics(dynamics); // this also sets the initial state
43 
44  // default integrator
45  setIntegrator(std::make_shared<IntegratorExplicitEuler>());
46 }
47 
49 {
50  if (!_output) return 0;
51  if (_output->getOutputDimension() == property::INHERITED)
52  {
53  if (_dynamics) return _dynamics->getStateDimension();
54  return 0;
55  }
56 
57  return _output->getOutputDimension();
58 }
59 
60 /*
61 bool SimulatedPlant::control(const ControlVector& u, const Duration& dt, const Time& t, SignalTargetInterface* signal_target)
62 {
63  if (!_dynamics || !_output || !_integrator) return false;
64 
65  StateVector next_state(_current_state.rows());
66 
67  // disturb input if desired
68  ControlVector u_disturbed(u.rows());
69  if (_input_disturbance)
70  _input_disturbance->disturb(t, u, u_disturbed);
71  else
72  u_disturbed = u;
73 
74  if (_dynamics->isContinuousTime())
75  {
76  // _integrator->integrate(_current_state, u, dt.toSec(), *_dynamics, next_state);
77  _integrator->solveIVPWithInnerDt(_current_state, u_disturbed, dt.toSec(), *_dynamics, next_state);
78  }
79  else
80  {
81  _dynamics->dynamics(_current_state, u_disturbed, next_state);
82  }
83  _current_state = next_state;
84 
85  if (signal_target) signal_target->sendMeasurement("plant/state", t.toSec(), _current_state);
86 
87  return true;
88 }
89 */
90 
91 bool SimulatedPlant::control(const TimeSeries::ConstPtr& u_sequence, const TimeSeries::ConstPtr& x_sequence, const Duration& dt, const Time& t,
92  SignalTargetInterface* signal_target, const std::string& ns)
93 {
94  if (!_dynamics || !_output || !_integrator) return false;
95 
96  StateVector next_state(_current_state.rows());
98 
99  if (u_sequence->getTimeDimension() < 1)
100  {
101  PRINT_ERROR_NAMED("u_sequence is empty.");
102  return false;
103  }
104 
105  u = u_sequence->getValuesMap(0); // Get most recent control vector
106 
107  // disturb input if desired
108  ControlVector u_disturbed(u.rows());
109  if (_input_disturbance)
110  _input_disturbance->disturb(t, u, u_disturbed);
111  else
112  u_disturbed = u;
113 
114  // we might have deadtimes so use buffer
115  std::vector<std::pair<double, ControlVector>> delayed_u_seq;
116 
118 
119  _time_value_buffer.appendValues(t.toSec(), u_disturbed);
120  _time_value_buffer.getValues(t.toSec() - _dynamics->getDeadTime(), dt.toSec(), delayed_u_seq);
121 
122  double cur_t = t.toSec();
123  for (int i = 0; i < delayed_u_seq.size(); ++i)
124  {
125  double cur_dt = delayed_u_seq[i].first;
126 
127  if (_dynamics->isContinuousTime())
128  {
129  // _integrator->integrate(_current_state, u, dt.toSec(), *_dynamics, next_state);
130  _integrator->solveIVP(_current_state, delayed_u_seq[i].second, cur_dt, *_dynamics, next_state);
131  }
132  else
133  {
134  // TODO(roesmann): we need to check how discrete states behave with the deadtime simulator!!!
135  PRINT_WARNING_COND(_dynamics->getDeadTime() > 0, "Discrete-time systems with deadtime not yet tested/fully implemented...");
136  _dynamics->dynamics(_current_state, delayed_u_seq[i].second, next_state);
137  }
138  _current_state = next_state;
139 
140  // disturb state if desired
142 
143  cur_t += cur_dt;
144 
145  if (signal_target) signal_target->sendMeasurement(ns + "plant/state", cur_t, _current_state); // TODO(roesmann): check time stamp!
146  }
147  return true;
148 }
149 
150 bool SimulatedPlant::output(OutputVector& output, const Time& t, SignalTargetInterface* /*signal_target*/, const std::string& /*ns*/)
151 {
152  if (!_output) return false;
153 
154  _output->output(_current_state, output);
155 
156  // disturb output if desired
158 
159  return true;
160 }
161 
163 {
164  _dynamics = dynamics;
165  // Set initial state and control (important: we set the dimensions here as well!)
166  setInitialState(StateVector::Zero(dynamics->getStateDimension()));
167  _current_control = ControlVector::Zero(dynamics->getInputDimension());
168 }
169 
171 
173 
175 
177 
179 
180 bool SimulatedPlant::setInitialState(const StateVector& x_init)
181 {
182  if (x_init.rows() != _dynamics->getStateDimension())
183  {
184  // PRINT_ERROR("SimulatedPlant::setInitialState(): dimension mismatch between x_init and _dynamics->getStateDimension()");
185  return false;
186  }
187  _current_state = x_init;
189  return true;
190 }
191 
192 void SimulatedPlant::getAvailableSignals(SignalTargetInterface& signal_target, const std::string& ns) const
193 {
194  if (_dynamics) signal_target.registerMeasurement(ns + "plant/state", _dynamics->getStateDimension());
195 }
196 
198 {
201 
202  if (_dynamics) _dynamics->reset();
203  if (_output) _output->reset();
207 
208  _current_control.setZero();
209 }
210 
211 #ifdef MESSAGE_SUPPORT
212 void SimulatedPlant::toMessage(messages::SimulatedPlant& message) const
213 {
214  if (_dynamics) _dynamics->toMessage(*message.mutable_system_dynamics());
215  if (_output) _output->toMessage(*message.mutable_output_function());
216  if (_integrator) _integrator->toMessage(*message.mutable_integrator());
217 
218  if (_input_disturbance) _input_disturbance->toMessage(*message.mutable_input_disturbance());
219  if (_output_disturbance) _output_disturbance->toMessage(*message.mutable_output_disturbance());
220  if (_state_disturbance) _state_disturbance->toMessage(*message.mutable_state_disturbance());
221 
222  message.mutable_x0()->Resize(_current_state.rows(), 0);
223  Eigen::Map<StateVector>(message.mutable_x0()->mutable_data(), _current_state.rows()) = _current_state;
224 }
225 
226 void SimulatedPlant::fromMessage(const corbo::messages::SimulatedPlant& message, std::stringstream* issues)
227 {
228  _dynamics.reset();
229  _current_state.resize(0);
230  _current_control.resize(0);
231  _output.reset();
232  _integrator.reset();
233 
234  // system dynamics
235  if (message.has_system_dynamics())
236  {
237  // construct object
238  std::string type;
239  util::get_oneof_field_type_expand_isolated(message.system_dynamics(), "system_dynamics", type, false, 1);
241  // import parameters
242  if (dynamics)
243  {
244  StateVector x0;
245  dynamics->fromMessage(message.system_dynamics(), issues);
246  setSystemDynamics(dynamics);
247  }
248  else if (issues)
249  {
250  *issues << "SimulatedPlant: No system dynamics specified.\n";
251  return;
252  }
253  }
254 
255  // output function
256  if (message.has_output_function())
257  {
258  // construct object
259  std::string type;
260  util::get_oneof_field_type_expand_isolated(message.output_function(), "output_function", type, false, 1);
262  // import parameters
263  if (output)
264  {
265  output->fromMessage(message.output_function(), issues);
267  }
268  }
269 
270  // integrator
271  if (message.has_integrator())
272  {
273  // construct object
274  std::string type;
275  util::get_oneof_field_type(message.integrator(), "explicit_integrator", type, false);
276  NumericalIntegratorExplicitInterface::Ptr integrator = create_from_factory<NumericalIntegratorExplicitInterface>(type);
277  // import parameters
278  if (integrator)
279  {
280  integrator->fromMessage(message.integrator(), issues);
281  setIntegrator(integrator);
282  }
283  }
284 
285  // start state
286  if (message.x0_size() > 0 && _dynamics)
287  {
288  int dim = message.x0_size();
289  Eigen::VectorXd x0(dim);
290  for (int i = 0; i < dim; ++i) x0[i] = message.x0(i);
291  if (!setInitialState(x0))
292  {
293  *issues << "Size of state x0 (" << dim << ") does not comply with system dynamics dimension (" << _dynamics->getStateDimension()
294  << ").\n";
295  }
296  }
297  else if (issues)
298  *issues << "SimulatedPlant: dimension of x0 must be larger then zero.\n";
299 
300  // input disturbance
301  if (message.has_input_disturbance() && !message.input_disturbance().has_no_disturbance())
302  {
303  // construct object
304  std::string type;
305  util::get_oneof_field_type(message.input_disturbance(), "disturbance", type, false);
306  DisturbanceInterface::Ptr disturbance = create_from_factory<DisturbanceInterface>(type);
307  // import parameters
308  if (disturbance)
309  {
310  disturbance->fromMessage(message.input_disturbance(), issues);
311  if (!disturbance->checkParameters(getInputDimension(), issues)) return;
312  setInputDisturbance(disturbance);
313  }
314  }
315 
316  // output disturbance
317  if (message.has_output_disturbance() && !message.output_disturbance().has_no_disturbance())
318  {
319  // construct object
320  std::string type;
321  util::get_oneof_field_type(message.output_disturbance(), "disturbance", type, false);
322  DisturbanceInterface::Ptr disturbance = create_from_factory<DisturbanceInterface>(type);
323  // import parameters
324  if (disturbance)
325  {
326  disturbance->fromMessage(message.output_disturbance(), issues);
327  if (!disturbance->checkParameters(getOutputDimension(), issues)) return;
328  setOutputDisturbance(disturbance);
329  }
330  }
331 
332  // state disturbance
333  if (message.has_state_disturbance() && !message.state_disturbance().has_no_disturbance())
334  {
335  // construct object
336  std::string type;
337  util::get_oneof_field_type(message.state_disturbance(), "disturbance", type, false);
338  DisturbanceInterface::Ptr disturbance = create_from_factory<DisturbanceInterface>(type);
339  // import parameters
340  if (disturbance)
341  {
342  disturbance->fromMessage(message.state_disturbance(), issues);
343  if (!disturbance->checkParameters(_dynamics->getStateDimension(), issues)) return;
344  setStateDisturbance(disturbance);
345  }
346  else if (issues)
347  {
348  *issues << "SimulatedPlant: Cannot set state disturbance model.\n";
349  }
350  }
351 }
352 #endif
353 
354 } // namespace corbo
corbo::SimulatedPlant::reset
void reset() override
Definition: simulated_plant.cpp:219
corbo::SimulatedPlant::setOutputFunction
void setOutputFunction(SystemOutputInterface::Ptr output)
Set the output function of the simulated plant.
Definition: simulated_plant.cpp:192
corbo::SimulatedPlant::getInputDimension
int getInputDimension() const override
Return the plant input dimension (u)
Definition: simulated_plant.h:113
corbo::SignalTargetInterface
Interface class for signal targets.
Definition: signal_target_interface.h:84
PRINT_ERROR_NAMED
#define PRINT_ERROR_NAMED(msg)
Definition: console.h:260
corbo::SimulatedPlant::control
bool control(const TimeSeries::ConstPtr &u_sequence, const TimeSeries::ConstPtr &x_sequence, const Duration &dt, const Time &t, SignalTargetInterface *signal_target=nullptr, const std::string &ns="") override
Send commands to plant.
Definition: simulated_plant.cpp:113
corbo
Definition: communication/include/corbo-communication/utilities.h:37
corbo::NumericalIntegratorExplicitInterface::Ptr
std::shared_ptr< NumericalIntegratorExplicitInterface > Ptr
Definition: integrator_interface.h:205
corbo::TimeValueBuffer::getValues
void getValues(double ts, double dt, std::vector< std::pair< double, Eigen::VectorXd >> &useq_out)
Compute the delayed values.
Definition: time_value_buffer.cpp:52
corbo::TimeValueBuffer::setInitialValue
void setInitialValue(const Eigen::Ref< const Eigen::VectorXd > &uinit)
Specify initial value.
Definition: time_value_buffer.h:123
corbo::SimulatedPlant::_state_disturbance
DisturbanceInterface::Ptr _state_disturbance
Definition: simulated_plant.h:176
corbo::SimulatedPlant::_output
SystemOutputInterface::Ptr _output
Definition: simulated_plant.h:170
corbo::TimeSeries::ConstPtr
std::shared_ptr< const TimeSeries > ConstPtr
Definition: time_series.h:109
corbo::TimeValueBuffer::appendValues
void appendValues(double t, const Eigen::Ref< const Eigen::VectorXd > &u)
Definition: time_value_buffer.cpp:111
corbo::SimulatedPlant::_current_state
StateVector _current_state
Definition: simulated_plant.h:181
corbo::SimulatedPlant::_integrator
NumericalIntegratorExplicitInterface::Ptr _integrator
Definition: simulated_plant.h:172
corbo::TimeValueBuffer::reset
void reset()
Reset internal buffer.
Definition: time_value_buffer.h:128
console.h
corbo::TimeValueBuffer::isEmpty
bool isEmpty() const
Definition: time_value_buffer.h:125
corbo::PlantInterface::StateVector
Eigen::VectorXd StateVector
Definition: plant_interface.h:103
corbo::PlantInterface::ControlVector
Eigen::VectorXd ControlVector
Definition: plant_interface.h:102
corbo::SimulatedPlant::setSystemDynamics
void setSystemDynamics(SystemDynamicsInterface::Ptr dynamics)
Set the system dynamics of the simulated plant.
Definition: simulated_plant.cpp:184
corbo::SimulatedPlant::setIntegrator
void setIntegrator(NumericalIntegratorExplicitInterface::Ptr integrator)
Set a numerical integrator for continuous-time dynamics.
Definition: simulated_plant.cpp:194
corbo::SimulatedPlant::setStateDisturbance
void setStateDisturbance(DisturbanceInterface::Ptr disturbance)
Set plant state disturbance model.
Definition: simulated_plant.cpp:200
corbo::Factory::instance
static Factory & instance()
< Retrieve static instance of the factory
Definition: factory.h:116
corbo::DisturbanceInterface::Ptr
std::shared_ptr< DisturbanceInterface > Ptr
Definition: disturbance_interface.h:87
corbo::SignalTargetInterface::sendMeasurement
virtual void sendMeasurement(Measurement::ConstPtr measurement)=0
Send a measurement to the target.
corbo::Time::toSec
double toSec() const
Cast time stamp to seconds.
Definition: time.h:303
corbo::Duration
Representation of time durations.
Definition: time.h:128
PRINT_WARNING_COND
#define PRINT_WARNING_COND(cond, msg)
Print msg-stream only if cond == true.
Definition: console.h:159
corbo::property::INHERITED
constexpr const int INHERITED
Inherit property.
Definition: core/include/corbo-core/types.h:84
corbo::SignalTargetInterface::registerMeasurement
virtual void registerMeasurement(const std::string &unique_name, int value_dimension, const std::vector< std::string > &value_labels={}, bool zero_order_hold=false)=0
Register a measurement type at current target.
corbo::SimulatedPlant::_dynamics
SystemDynamicsInterface::Ptr _dynamics
Definition: simulated_plant.h:169
corbo::SimulatedPlant::_initial_state
StateVector _initial_state
Definition: simulated_plant.h:180
corbo::SimulatedPlant::_output_disturbance
DisturbanceInterface::Ptr _output_disturbance
Definition: simulated_plant.h:175
corbo::SystemDynamicsInterface::Ptr
std::shared_ptr< SystemDynamicsInterface > Ptr
Definition: system_dynamics_interface.h:91
corbo::SimulatedPlant::_input_disturbance
DisturbanceInterface::Ptr _input_disturbance
Definition: simulated_plant.h:174
Eigen::Map
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:94
corbo::SimulatedPlant::getAvailableSignals
void getAvailableSignals(SignalTargetInterface &signal_target, const std::string &ns="") const override
Retrieve available signals from the plant.
Definition: simulated_plant.cpp:214
corbo::SimulatedPlant::output
bool output(OutputVector &output, const Time &t, SignalTargetInterface *signal_target=nullptr, const std::string &ns="") override
Retrieve current plant output (measurements)
Definition: simulated_plant.cpp:172
corbo::SimulatedPlant::_time_value_buffer
TimeValueBuffer _time_value_buffer
Definition: simulated_plant.h:178
utilities.h
corbo::Factory::create
std::shared_ptr< Derived > create(const std::string &name, bool print_error=true) const
Create a shared instance of the desired object.
Definition: factory.h:137
corbo::Duration::toSec
double toSec() const
Return duration in seconds.
Definition: time.h:160
corbo::SimulatedPlant::getOutputDimension
int getOutputDimension() const override
Return the plant output dimension (y)
Definition: simulated_plant.cpp:70
corbo::Time
Representation of time stamps.
Definition: time.h:273
corbo::SimulatedPlant::setInputDisturbance
void setInputDisturbance(DisturbanceInterface::Ptr disturbance)
Set plant input disturbance model.
Definition: simulated_plant.cpp:196
corbo::SimulatedPlant::_current_control
ControlVector _current_control
Definition: simulated_plant.h:182
corbo::SimulatedPlant::SimulatedPlant
SimulatedPlant()
Default constructor.
Definition: simulated_plant.cpp:55
simulated_plant.h
corbo::SystemOutputInterface::Ptr
std::shared_ptr< SystemOutputInterface > Ptr
Definition: output_function_interface.h:109
explicit_integrators.h
corbo::SimulatedPlant::setOutputDisturbance
void setOutputDisturbance(DisturbanceInterface::Ptr disturbance)
Set plant output disturbance model.
Definition: simulated_plant.cpp:198
corbo::SimulatedPlant::setInitialState
bool setInitialState(const StateVector &x_init)
Specify an initial state x0 [SystemDynamicsInterface::getStateDimension() x 1].
Definition: simulated_plant.cpp:202
corbo::SimulatedPlant::StateVector
Eigen::VectorXd StateVector
Definition: simulated_plant.h:103


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Wed Mar 2 2022 00:06:14