Crocoddyl
floating-base-thrusters.hpp
1 // BSD 3-Clause License
3 //
4 // Copyright (C) 2014-2024, Heriot-Watt University
5 // Copyright note valid unless otherwise stated in individual files.
6 // All rights reserved.
8 
9 #ifndef CROCODDYL_MULTIBODY_ACTUATIONS_PROPELLERS_HPP_
10 #define CROCODDYL_MULTIBODY_ACTUATIONS_PROPELLERS_HPP_
11 
12 #include <pinocchio/multibody/fwd.hpp>
13 #include <pinocchio/spatial/se3.hpp>
14 #include <vector>
15 
16 #include "crocoddyl/core/actuation-base.hpp"
17 #include "crocoddyl/core/utils/exception.hpp"
18 #include "crocoddyl/multibody/states/multibody.hpp"
19 
20 namespace crocoddyl {
21 
22 enum ThrusterType { CW = 0, CCW };
23 
24 template <typename _Scalar>
25 struct ThrusterTpl {
26  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
27 
28  typedef _Scalar Scalar;
29  typedef pinocchio::SE3Tpl<Scalar> SE3;
31 
42  ThrusterTpl(const SE3& pose, const Scalar ctorque,
43  const ThrusterType type = CW,
44  const Scalar min_thrust = Scalar(0.),
45  const Scalar max_thrust = std::numeric_limits<Scalar>::infinity())
46  : pose(pose),
48  type(type),
51 
62  ThrusterTpl(const Scalar ctorque, const ThrusterType type = CW,
63  const Scalar min_thrust = Scalar(0.),
64  const Scalar max_thrust = std::numeric_limits<Scalar>::infinity())
65  : pose(SE3::Identity()),
67  type(type),
70  ThrusterTpl(const ThrusterTpl<Scalar>& clone)
71  : pose(clone.pose),
72  ctorque(clone.ctorque),
73  type(clone.type),
74  min_thrust(clone.min_thrust),
75  max_thrust(clone.max_thrust) {}
76 
77  ThrusterTpl& operator=(const ThrusterTpl<Scalar>& other) {
78  if (this != &other) {
79  pose = other.pose;
80  ctorque = other.ctorque;
81  type = other.type;
82  min_thrust = other.min_thrust;
83  max_thrust = other.max_thrust;
84  }
85  return *this;
86  }
87 
88  template <typename OtherScalar>
89  bool operator==(const ThrusterTpl<OtherScalar>& other) const {
90  return (pose == other.pose && ctorque == other.ctorque &&
91  type == other.type && min_thrust == other.min_thrust &&
92  max_thrust == other.max_thrust);
93  }
94 
95  friend std::ostream& operator<<(std::ostream& os,
96  const ThrusterTpl<Scalar>& X) {
97  os << " pose:" << std::endl
98  << X.pose << " ctorque: " << X.ctorque << std::endl
99  << " type: " << X.type << std::endl
100  << "min_thrust: " << X.min_thrust << std::endl
101  << "max_thrust: " << X.max_thrust << std::endl;
102  return os;
103  }
104 
105  SE3 pose;
106  Scalar ctorque;
107  ThrusterType type;
109  Scalar min_thrust;
110  Scalar max_thrust;
111 };
112 
131 template <typename _Scalar>
133  : public ActuationModelAbstractTpl<_Scalar> {
134  public:
135  typedef _Scalar Scalar;
141  typedef typename MathBase::Vector3s Vector3s;
142  typedef typename MathBase::VectorXs VectorXs;
143  typedef typename MathBase::MatrixXs MatrixXs;
144 
152  ActuationModelFloatingBaseThrustersTpl(std::shared_ptr<StateMultibody> state,
153  const std::vector<Thruster>& thrusters)
154  : Base(state,
155  state->get_nv() -
156  state->get_pinocchio()
157  ->joints[(
158  state->get_pinocchio()->existJointName("root_joint")
159  ? state->get_pinocchio()->getJointId("root_joint")
160  : 0)]
161  .nv() +
162  thrusters.size()),
163  thrusters_(thrusters),
164  n_thrusters_(thrusters.size()),
165  W_thrust_(state_->get_nv(), nu_),
166  update_data_(true) {
167  if (!state->get_pinocchio()->existJointName("root_joint")) {
168  throw_pretty(
169  "Invalid argument: "
170  << "the first joint has to be a root one (e.g., free-flyer joint)");
171  }
172  // Update the joint actuation part
173  W_thrust_.setZero();
174  if (nu_ > n_thrusters_) {
175  W_thrust_.bottomRightCorner(nu_ - n_thrusters_, nu_ - n_thrusters_)
176  .diagonal()
177  .setOnes();
178  }
179  // Update the floating base actuation part
181  }
183 
192  virtual void calc(const std::shared_ptr<Data>& data,
193  const Eigen::Ref<const VectorXs>&,
194  const Eigen::Ref<const VectorXs>& u) {
195  if (static_cast<std::size_t>(u.size()) != nu_) {
196  throw_pretty(
197  "Invalid argument: " << "u has wrong dimension (it should be " +
198  std::to_string(nu_) + ")");
199  }
200  if (update_data_) {
201  updateData(data);
202  }
203  data->tau.noalias() = data->dtau_du * u;
204  }
205 
214 #ifndef NDEBUG
215  virtual void calcDiff(const std::shared_ptr<Data>& data,
216  const Eigen::Ref<const VectorXs>&,
217  const Eigen::Ref<const VectorXs>&) {
218 #else
219  virtual void calcDiff(const std::shared_ptr<Data>&,
220  const Eigen::Ref<const VectorXs>&,
221  const Eigen::Ref<const VectorXs>&) {
222 #endif
223  // The derivatives has constant values which were set in createData.
224  assert_pretty(MatrixXs(data->dtau_du).isApprox(W_thrust_),
225  "dtau_du has wrong value");
226  }
227 
228  virtual void commands(const std::shared_ptr<Data>& data,
229  const Eigen::Ref<const VectorXs>&,
230  const Eigen::Ref<const VectorXs>& tau) {
231  data->u.noalias() = data->Mtau * tau;
232  }
233 
234 #ifndef NDEBUG
235  virtual void torqueTransform(const std::shared_ptr<Data>& data,
236  const Eigen::Ref<const VectorXs>&,
237  const Eigen::Ref<const VectorXs>&) {
238 #else
239  virtual void torqueTransform(const std::shared_ptr<Data>&,
240  const Eigen::Ref<const VectorXs>&,
241  const Eigen::Ref<const VectorXs>&) {
242 #endif
243  // The torque transform has constant values which were set in createData.
244  assert_pretty(MatrixXs(data->Mtau).isApprox(Mtau_), "Mtau has wrong value");
245  }
246 
252  virtual std::shared_ptr<Data> createData() {
253  std::shared_ptr<Data> data =
254  std::allocate_shared<Data>(Eigen::aligned_allocator<Data>(), this);
255  updateData(data);
256  return data;
257  }
258 
262  const std::vector<Thruster>& get_thrusters() const { return thrusters_; }
263 
267  std::size_t get_nthrusters() const { return n_thrusters_; }
268 
277  void set_thrusters(const std::vector<Thruster>& thrusters) {
278  if (static_cast<std::size_t>(thrusters.size()) != n_thrusters_) {
279  throw_pretty("Invalid argument: "
280  << "the number of thrusters is wrong (it should be " +
281  std::to_string(n_thrusters_) + ")");
282  }
283  thrusters_ = thrusters;
284  // Update the mapping matrix from thrusters thrust to body force/moments
285  for (std::size_t i = 0; i < n_thrusters_; ++i) {
286  const Thruster& p = thrusters_[i];
287  const Vector3s& f_z = p.pose.rotation() * Vector3s::UnitZ();
288  W_thrust_.template topRows<3>().col(i) += f_z;
289  W_thrust_.template middleRows<3>(3).col(i).noalias() +=
290  p.pose.translation().cross(f_z);
291  switch (p.type) {
292  case CW:
293  W_thrust_.template middleRows<3>(3).col(i) += p.ctorque * f_z;
294  break;
295  case CCW:
296  W_thrust_.template middleRows<3>(3).col(i) -= p.ctorque * f_z;
297  break;
298  }
299  }
300  // Compute the torque transform matrix from generalized torques to joint
301  // torque inputs
302  Mtau_ = pseudoInverse(MatrixXs(W_thrust_));
303  S_.noalias() = W_thrust_ * Mtau_;
304  update_data_ = true;
305  }
306 
307  const MatrixXs& get_Wthrust() const { return W_thrust_; }
308 
309  const MatrixXs& get_S() const { return S_; }
310 
311  void print(std::ostream& os) const {
312  os << "ActuationModelFloatingBaseThrusters {nu=" << nu_
313  << ", nthrusters=" << n_thrusters_ << ", thrusters=" << std::endl;
314  for (std::size_t i = 0; i < n_thrusters_; ++i) {
315  os << std::to_string(i) << ": " << thrusters_[i];
316  }
317  os << "}";
318  }
319 
320  protected:
321  std::vector<Thruster> thrusters_;
322  std::size_t n_thrusters_;
323  MatrixXs W_thrust_;
324  MatrixXs Mtau_;
326  MatrixXs S_;
327 
328  bool update_data_;
329  using Base::nu_;
330  using Base::state_;
331 
332  private:
333  void updateData(const std::shared_ptr<Data>& data) {
334  data->dtau_du = W_thrust_;
335  data->Mtau = Mtau_;
336  const std::size_t nv = state_->get_nv();
337  for (std::size_t k = 0; k < nv; ++k) {
338  if (fabs(S_(k, k)) < std::numeric_limits<Scalar>::epsilon()) {
339  data->tau_set[k] = false;
340  } else {
341  data->tau_set[k] = true;
342  }
343  }
344  update_data_ = false;
345  }
346 };
347 
348 } // namespace crocoddyl
349 
350 #endif // CROCODDYL_MULTIBODY_ACTUATIONS_PROPELLERS_HPP_
Abstract class for the actuation-mapping model.
std::shared_ptr< StateAbstract > state_
Model of the state.
std::size_t nu_
Dimension of joint torque inputs.
Actuation models for floating base systems actuated with thrusters.
virtual std::shared_ptr< Data > createData()
Create the floating base thruster actuation data.
MatrixXs S_
Selection matrix for under-actuation part.
std::shared_ptr< StateAbstract > state_
Model of the state.
const std::vector< Thruster > & get_thrusters() const
Return the vector of thrusters.
virtual void commands(const std::shared_ptr< Data > &data, const Eigen::Ref< const VectorXs > &, const Eigen::Ref< const VectorXs > &tau)
Compute the joint torque input from the generalized torques.
virtual void calcDiff(const std::shared_ptr< Data > &data, const Eigen::Ref< const VectorXs > &, const Eigen::Ref< const VectorXs > &)
Compute the Jacobians of the floating base thruster actuation function.
virtual void calc(const std::shared_ptr< Data > &data, const Eigen::Ref< const VectorXs > &, const Eigen::Ref< const VectorXs > &u)
Compute the actuation signal and actuation set from its thrust and joint torque inputs .
ActuationModelFloatingBaseThrustersTpl(std::shared_ptr< StateMultibody > state, const std::vector< Thruster > &thrusters)
Initialize the floating base actuation model equipped with thrusters.
std::vector< Thruster > thrusters_
Vector of thrusters.
std::size_t nu_
Dimension of joint torque inputs.
std::size_t get_nthrusters() const
Return the number of thrusters.
MatrixXs W_thrust_
Matrix from thrusters thrusts to body wrench.
void print(std::ostream &os) const
Print relevant information of the residual model.
virtual void torqueTransform(const std::shared_ptr< Data > &data, const Eigen::Ref< const VectorXs > &, const Eigen::Ref< const VectorXs > &)
Compute the torque transform from generalized torques to joint torque inputs.
void set_thrusters(const std::vector< Thruster > &thrusters)
Modify the vector of thrusters.
State multibody representation.
Definition: multibody.hpp:35
Scalar min_thrust
Minimum thrust.
ThrusterTpl(const SE3 &pose, const Scalar ctorque, const ThrusterType type=CW, const Scalar min_thrust=Scalar(0.), const Scalar max_thrust=std::numeric_limits< Scalar >::infinity())
Initialize the thruster in a give pose from the root joint.
Scalar max_thrust
Minimum thrust.
ThrusterTpl(const Scalar ctorque, const ThrusterType type=CW, const Scalar min_thrust=Scalar(0.), const Scalar max_thrust=std::numeric_limits< Scalar >::infinity())
Initialize the thruster in a pose in the origin of the root joint.
Scalar ctorque
Coefficient of generated torque per thrust.