#include "drake/systems/sensors/accelerometer.h" #include "drake/multibody/math/spatial_algebra.h" namespace drake { namespace systems { namespace sensors { using math::RigidTransform; using math::RotationMatrix; using multibody::SpatialAcceleration; using multibody::SpatialVelocity; template Accelerometer::Accelerometer(const multibody::Body& body, const RigidTransform& X_BS, const Eigen::Vector3d& gravity_vector) : Accelerometer(body.index(), X_BS, gravity_vector) {} template Accelerometer::Accelerometer(const multibody::BodyIndex& body_index, const RigidTransform& X_BS, const Eigen::Vector3d& gravity_vector) : LeafSystem(SystemTypeTag{}), body_index_(body_index), X_BS_(X_BS), gravity_vector_(gravity_vector) { // Declare measurement output port. measurement_output_port_ = &this->DeclareVectorOutputPort( "measurement", 3, &Accelerometer::CalcOutput); body_poses_input_port_ = &this->DeclareAbstractInputPort( "body_poses", Value>>()); body_velocities_input_port_ = &this->DeclareAbstractInputPort( "body_spatial_velocities", Value>>()); body_accelerations_input_port_ = &this->DeclareAbstractInputPort( "body_spatial_accelerations", Value>>()); } template void Accelerometer::CalcOutput(const Context& context, BasicVector* output) const { const auto& X_WB = get_body_poses_input_port().template Eval>>( context)[body_index_]; const auto& V_WB = get_body_velocities_input_port() .template Eval>>(context)[body_index_]; const auto& A_WB = get_body_accelerations_input_port() .template Eval>>( context)[body_index_]; // Kinematic term expressed in world coordinates unless specified // Sensor frame position and orientation. const RotationMatrix& R_WB = X_WB.rotation(); // Express sensor position in world coordinates const Vector3& p_BS_W = R_WB * X_BS_.translation().template cast(); const RotationMatrix& R_BS = X_BS_.rotation().template cast(); // Acceleration of the accelerometer expressed in world coordinates const auto A_WS = A_WB.Shift(p_BS_W, V_WB.rotational()); // Rotation from world to accelerometer const auto R_SW = R_BS.inverse() * R_WB.inverse(); // Rotate to local frame and return output->SetFromVector(R_SW * (A_WS.translational() - gravity_vector_)); } template const Accelerometer& Accelerometer::AddToDiagram( const multibody::Body& body, const RigidTransform& X_BS, const Eigen::Vector3d& gravity_vector, const multibody::MultibodyPlant& plant, DiagramBuilder* builder) { const auto& accelerometer = *builder->template AddSystem>( body, X_BS, gravity_vector); builder->Connect(plant.get_body_poses_output_port(), accelerometer.get_body_poses_input_port()); builder->Connect(plant.get_body_spatial_velocities_output_port(), accelerometer.get_body_velocities_input_port()); builder->Connect(plant.get_body_spatial_accelerations_output_port(), accelerometer.get_body_accelerations_input_port()); return accelerometer; } template template Accelerometer::Accelerometer(const Accelerometer& other) : Accelerometer(other.body_index(), other.pose(), other.gravity_vector()) {} DRAKE_DEFINE_CLASS_TEMPLATE_INSTANTIATIONS_ON_DEFAULT_SCALARS( class ::drake::systems::sensors::Accelerometer) } // namespace sensors } // namespace systems } // namespace drake