forked from pz4kybsvg/Conception
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
4.9 KiB
119 lines
4.9 KiB
#include "drake/systems/primitives/discrete_time_delay.h"
|
|
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "drake/common/default_scalars.h"
|
|
|
|
namespace drake {
|
|
namespace systems {
|
|
|
|
template <typename T>
|
|
DiscreteTimeDelay<T>::DiscreteTimeDelay(
|
|
double update_sec, int delay_timesteps, int vector_size,
|
|
std::unique_ptr<const AbstractValue> abstract_model_value)
|
|
: LeafSystem<T>(SystemTypeTag<DiscreteTimeDelay>()),
|
|
update_sec_(update_sec),
|
|
// Delay buffer must be one element longer to properly delay signal
|
|
delay_buffer_size_(delay_timesteps + 1),
|
|
vector_size_(vector_size),
|
|
abstract_model_value_(std::move(abstract_model_value)) {
|
|
if (!is_abstract()) {
|
|
DRAKE_DEMAND(vector_size >= 0);
|
|
// TODO(mpetersen94): remove the size parameter from the constructor
|
|
// once #3109 supporting automatic sizes is resolved.
|
|
BasicVector<T> model_value(vector_size);
|
|
this->DeclareVectorInputPort("u", model_value);
|
|
this->DeclareVectorOutputPort("delayed_u", model_value,
|
|
&DiscreteTimeDelay::CopyDelayedVector,
|
|
{this->xd_ticket()});
|
|
this->DeclareDiscreteState(vector_size_ * delay_buffer_size_);
|
|
this->DeclarePeriodicDiscreteUpdateEvent(
|
|
update_sec_, 0., &DiscreteTimeDelay::SaveInputVectorToBuffer);
|
|
} else {
|
|
DRAKE_DEMAND(vector_size < 0);
|
|
// TODO(mpetersen94): Remove value parameter from the constructor once
|
|
// the equivalent of #3109 for abstract values is also resolved.
|
|
this->DeclareAbstractInputPort("u", *abstract_model_value_);
|
|
this->DeclareAbstractOutputPort("delayed_u",
|
|
[this]() { return abstract_model_value_->Clone(); },
|
|
[this](const Context<T>& context, AbstractValue* out) {
|
|
this->CopyDelayedAbstractValue(context, out);
|
|
},
|
|
{this->xa_ticket()});
|
|
for (int ii = 0; ii < delay_buffer_size_; ++ii) {
|
|
this->DeclareAbstractState(*abstract_model_value_);
|
|
}
|
|
// This state keeps track of the index of the oldest value in the buffer.
|
|
// It is at abstract state index `delay_buffer_size_`.
|
|
this->DeclareAbstractState(Value<int>(0));
|
|
this->DeclarePeriodicUnrestrictedUpdateEvent(
|
|
update_sec_, 0., &DiscreteTimeDelay::SaveInputAbstractValueToBuffer);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
template <typename U>
|
|
DiscreteTimeDelay<T>::DiscreteTimeDelay(const DiscreteTimeDelay<U>& other)
|
|
: DiscreteTimeDelay(
|
|
other.update_sec_, other.delay_buffer_size_ - 1, other.vector_size_,
|
|
other.is_abstract() ? other.abstract_model_value_->Clone()
|
|
: nullptr) {}
|
|
|
|
template <typename T>
|
|
void DiscreteTimeDelay<T>::CopyDelayedVector(
|
|
const Context<T>& context, BasicVector<T>* output) const {
|
|
DRAKE_ASSERT(!is_abstract());
|
|
const BasicVector<T>& state_value = context.get_discrete_state(0);
|
|
output->SetFromVector(state_value.get_value().head(vector_size_));
|
|
}
|
|
|
|
template <typename T>
|
|
void DiscreteTimeDelay<T>::SaveInputVectorToBuffer(
|
|
const Context<T>& context, DiscreteValues<T>* discrete_state) const {
|
|
DRAKE_ASSERT(!is_abstract());
|
|
// Copies the current state of the delay buffer from the context to the
|
|
// discrete state, sliding the buffer forward one step, dropping the oldest
|
|
// value and adding the value on the input port to the end of the buffer.
|
|
// TODO(mpetersen94): consider revising to avoid possibly expensive buffer
|
|
// copy operation.
|
|
const auto& input = this->get_input_port().Eval(context);
|
|
Eigen::VectorBlock<VectorX<T>> updated_state_value =
|
|
discrete_state->get_mutable_value(0);
|
|
const VectorX<T>& old_state_value = context.get_discrete_state(0).value();
|
|
updated_state_value.head((delay_buffer_size_ - 1) * vector_size_) =
|
|
old_state_value.tail((delay_buffer_size_ - 1) * vector_size_);
|
|
updated_state_value.tail(vector_size_) = input;
|
|
}
|
|
|
|
template <typename T>
|
|
void DiscreteTimeDelay<T>::CopyDelayedAbstractValue(
|
|
const Context<T>& context, AbstractValue* output) const {
|
|
DRAKE_ASSERT(is_abstract());
|
|
const int& oldest_index =
|
|
context.template get_abstract_state<int>(delay_buffer_size_);
|
|
const AbstractValue& state_value =
|
|
context.get_abstract_state().get_value(oldest_index);
|
|
output->SetFrom(state_value);
|
|
}
|
|
|
|
template <typename T>
|
|
void DiscreteTimeDelay<T>::SaveInputAbstractValueToBuffer(
|
|
const Context<T>& context, State<T>* state) const {
|
|
DRAKE_ASSERT(is_abstract());
|
|
const auto& input =
|
|
this->get_input_port().template Eval<AbstractValue>(context);
|
|
int& oldest_index =
|
|
state->template get_mutable_abstract_state<int>(delay_buffer_size_);
|
|
AbstractValue& state_value =
|
|
state->get_mutable_abstract_state().get_mutable_value(oldest_index);
|
|
state_value.SetFrom(input);
|
|
oldest_index = (oldest_index + 1) % delay_buffer_size_;
|
|
}
|
|
|
|
} // namespace systems
|
|
} // namespace drake
|
|
|
|
DRAKE_DEFINE_CLASS_TEMPLATE_INSTANTIATIONS_ON_DEFAULT_SCALARS(
|
|
class ::drake::systems::DiscreteTimeDelay)
|