#include "drake/systems/sensors/rotary_encoders.h" #include #include #include #include #include #include "drake/common/default_scalars.h" #include "drake/common/eigen_types.h" #include "drake/common/unused.h" #include "drake/systems/framework/basic_vector.h" namespace drake { namespace systems { namespace sensors { namespace { // Return a vector of the given size, with result[i] == i. std::vector vector_iota(int size) { std::vector result(size); std::iota(std::begin(result), std::end(result), 0); return result; } } // namespace template RotaryEncoders::RotaryEncoders(const std::vector& ticks_per_revolution) : RotaryEncoders( ticks_per_revolution.size() /* input_port_size */, vector_iota(ticks_per_revolution.size()) /* input_vector_indices */, ticks_per_revolution) {} template RotaryEncoders::RotaryEncoders(int input_port_size, const std::vector& input_vector_indices) : RotaryEncoders(input_port_size, input_vector_indices, std::vector() /* ticks_per_revolution */) {} template RotaryEncoders::RotaryEncoders(int input_port_size, const std::vector& input_vector_indices, const std::vector& ticks_per_revolution) : VectorSystem( SystemTypeTag{}, input_port_size, input_vector_indices.size() /* output_port_size */), num_encoders_(input_vector_indices.size()), indices_(input_vector_indices), ticks_per_revolution_(ticks_per_revolution) { DRAKE_DEMAND(input_port_size >= 0); DRAKE_ASSERT(*std::min_element(indices_.begin(), indices_.end()) >= 0); DRAKE_ASSERT(*std::max_element(indices_.begin(), indices_.end()) < input_port_size); DRAKE_DEMAND(ticks_per_revolution_.empty() || indices_.size() == ticks_per_revolution_.size()); DRAKE_ASSERT(ticks_per_revolution_.empty() || *std::min_element(ticks_per_revolution_.begin(), ticks_per_revolution_.end()) >= 0); // This vector is numeric parameter 0. this->DeclareNumericParameter( BasicVector(VectorX::Zero(num_encoders_))); } template template RotaryEncoders::RotaryEncoders(const RotaryEncoders& other) : RotaryEncoders(other.get_input_port().size(), other.indices_, other.ticks_per_revolution_) {} template void RotaryEncoders::DoCalcVectorOutput( const Context& context, const Eigen::VectorBlock>& input, const Eigen::VectorBlock>& state, Eigen::VectorBlock>* output) const { unused(state); const VectorX& calibration_offsets = context.get_numeric_parameter(0).value(); DRAKE_ASSERT(calibration_offsets.size() == num_encoders_); // Loop through the outputs. Eigen::VectorBlock>& y = *output; for (int i = 0; i < num_encoders_; i++) { const int index = indices_.empty() ? i : indices_[i]; // Calibration. y(i) = input(index) - calibration_offsets(i); // Quantization. if (!ticks_per_revolution_.empty()) { using std::floor; const T ticks_per_radian = ticks_per_revolution_[i] / (2.0 * M_PI); y(i) = floor(y(i) * ticks_per_radian) / ticks_per_radian; } } } template void RotaryEncoders::set_calibration_offsets( Context* context, const Eigen::Ref>& calibration_offsets) const { DRAKE_DEMAND(calibration_offsets.rows() == num_encoders_); context->get_mutable_numeric_parameter(0).set_value(calibration_offsets); } template const VectorX& RotaryEncoders::get_calibration_offsets( const Context& context) const { return context.get_numeric_parameter(0).value(); } } // namespace sensors } // namespace systems } // namespace drake DRAKE_DEFINE_CLASS_TEMPLATE_INSTANTIATIONS_ON_DEFAULT_SCALARS( class ::drake::systems::sensors::RotaryEncoders)