Skip to content

Commit 38c9eb3

Browse files
authored
Merge pull request #1213 from cmastalli/topic/propellers
2 parents 616a2cb + fd0787e commit 38c9eb3

18 files changed

+697
-88
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## [Unreleased]
88

9+
* Introduced floating base thruster actuation model in https://github.com/loco-3d/crocoddyl/pull/1213
10+
* Fixed quadruped and biped examples in https://github.com/loco-3d/crocoddyl/pull/1208
11+
* Fixed terminal computation in Python models in https://github.com/loco-3d/crocoddyl/pull/1204
912
* Fixed handling of unbounded values for `ActivationBounds` in https://github.com/loco-3d/crocoddyl/pull/1191
1013

1114
## [2.0.2] - 2023-12-07
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// BSD 3-Clause License
3+
//
4+
// Copyright (C) 2024-2024, Heriot-Watt University
5+
// Copyright note valid unless otherwise stated in individual files.
6+
// All rights reserved.
7+
///////////////////////////////////////////////////////////////////////////////
8+
9+
#include "crocoddyl/multibody/actuations/floating-base-thrusters.hpp"
10+
#include "python/crocoddyl/multibody/multibody.hpp"
11+
#include "python/crocoddyl/utils/copyable.hpp"
12+
#include "python/crocoddyl/utils/printable.hpp"
13+
#include "python/crocoddyl/utils/vector-converter.hpp"
14+
15+
namespace crocoddyl {
16+
17+
namespace python {
18+
19+
void exposeActuationFloatingBaseThruster() {
20+
bp::enum_<ThrusterType>("ThrusterType")
21+
.value("CW", CW)
22+
.value("CCW", CCW)
23+
.export_values();
24+
25+
bp::class_<Thruster>(
26+
"Thruster", "Model for thrusters",
27+
bp::init<pinocchio::SE3, double,
28+
bp::optional<ThrusterType, double, double>>(
29+
bp::args("self", "M", "ctorque", "type", "min_thrust", "max_thrust"),
30+
"Initialize the thruster in a give pose from the root joint.\n\n"
31+
":param M: pose from root joint\n"
32+
":param ctorque: coefficient of generated torque per thrust\n"
33+
":param type: type of thruster (clockwise or counterclockwise, "
34+
"default clockwise)\n"
35+
":param min_thrust: minimum thrust (default 0.)\n"
36+
":param max_thrust: maximum thrust (default np.inf)"))
37+
.def(bp::init<double, bp::optional<ThrusterType, double, double>>(
38+
bp::args("self", "ctorque", "type", "min_thrust", "max_thrust"),
39+
"Initialize the thruster in a give pose from the root joint.\n\n"
40+
":param ctorque: coefficient of generated torque per thrust\n"
41+
":param type: type of thruster (clockwise or counterclockwise, "
42+
"default clockwise)\n"
43+
":param min_thrust: minimum thrust (default 0.)\n"
44+
":param max_thrust: maximum thrust (default np.inf)"))
45+
.def_readwrite("pose", &Thruster::pose,
46+
"thruster pose (traslation, rotation)")
47+
.def_readwrite("ctorque", &Thruster::ctorque,
48+
"coefficient of generated torque per thrust")
49+
.def_readwrite("type", &Thruster::type,
50+
"type of thruster (clockwise or counterclockwise)")
51+
.def_readwrite("min_thrust", &Thruster::min_thrust, "minimum thrust")
52+
.def_readwrite("max_thrust", &Thruster::min_thrust, "maximum thrust")
53+
.def(PrintableVisitor<Thruster>())
54+
.def(CopyableVisitor<Thruster>());
55+
56+
StdVectorPythonVisitor<std::vector<Thruster>, true>::expose(
57+
"StdVec_Thruster");
58+
59+
bp::register_ptr_to_python<
60+
boost::shared_ptr<crocoddyl::ActuationModelFloatingBaseThrusters>>();
61+
62+
bp::class_<ActuationModelFloatingBaseThrusters,
63+
bp::bases<ActuationModelAbstract>>(
64+
"ActuationModelFloatingBaseThrusters",
65+
"Actuation models for floating base systems actuated with thrusters "
66+
"(e.g. aerial "
67+
"manipulators).",
68+
bp::init<boost::shared_ptr<StateMultibody>, std::vector<Thruster>>(
69+
bp::args("self", "state", "thrusters"),
70+
"Initialize the floating base actuation model equipped with "
71+
"thrusters.\n\n"
72+
":param state: state of multibody system\n"
73+
":param thrusters: vector of thrusters"))
74+
.def<void (ActuationModelFloatingBaseThrusters::*)(
75+
const boost::shared_ptr<ActuationDataAbstract>&,
76+
const Eigen::Ref<const Eigen::VectorXd>&,
77+
const Eigen::Ref<const Eigen::VectorXd>&)>(
78+
"calc", &ActuationModelFloatingBaseThrusters::calc,
79+
bp::args("self", "data", "x", "u"),
80+
"Compute the actuation signal and actuation set from the thrust\n"
81+
"forces and joint torque inputs u.\n\n"
82+
":param data: floating base thrusters actuation data\n"
83+
":param x: state point (dim. state.nx)\n"
84+
":param u: joint torque input (dim. nu)")
85+
.def("calcDiff", &ActuationModelFloatingBaseThrusters::calcDiff,
86+
bp::args("self", "data", "x", "u"),
87+
"Compute the derivatives of the actuation model.\n\n"
88+
"It computes the partial derivatives of the thruster actuation. It\n"
89+
"assumes that calc has been run first. The reason is that the\n"
90+
"derivatives are constant and defined in createData. The Hessian\n"
91+
"is constant, so we don't write again this value.\n"
92+
":param data: floating base thrusters actuation data\n"
93+
":param x: state point (dim. state.nx)\n"
94+
":param u: joint torque input (dim. nu)")
95+
.def("commands", &ActuationModelFloatingBaseThrusters::commands,
96+
bp::args("self", "data", "x", "tau"),
97+
"Compute the thrust and joint torque commands from the generalized "
98+
"torques.\n\n"
99+
"It stores the results in data.u.\n"
100+
":param data: actuation data\n"
101+
":param x: state point (dim. state.nx)\n"
102+
":param tau: generalized torques (dim state.nv)")
103+
.def("torqueTransform",
104+
&ActuationModelFloatingBaseThrusters::torqueTransform,
105+
bp::args("self", "data", "x", "tau"),
106+
"Compute the torque transform from generalized torques to thrust "
107+
"and joint torque inputs.\n\n"
108+
"It stores the results in data.Mtau.\n"
109+
":param data: floating base thrusters actuation data\n"
110+
":param x: state point (dim. state.nx)\n"
111+
":param tau: generalized torques (dim state.nv)")
112+
.def("createData", &ActuationModelFloatingBaseThrusters::createData,
113+
bp::args("self"),
114+
"Create the floating base thrusters actuation data.")
115+
.add_property(
116+
"thrusters",
117+
bp::make_function(&ActuationModelFloatingBaseThrusters::get_thrusters,
118+
bp::return_value_policy<bp::return_by_value>()),
119+
bp::make_function(
120+
&ActuationModelFloatingBaseThrusters::set_thrusters),
121+
"vector of thrusters")
122+
.add_property("nthrusters",
123+
bp::make_function(
124+
&ActuationModelFloatingBaseThrusters::get_nthrusters),
125+
"number of thrusters")
126+
.add_property(
127+
"Wthrust",
128+
bp::make_function(&ActuationModelFloatingBaseThrusters::get_Wthrust,
129+
bp::return_value_policy<bp::return_by_value>()),
130+
"matrix mapping from thrusts to thruster wrenches")
131+
.add_property(
132+
"S",
133+
bp::make_function(&ActuationModelFloatingBaseThrusters::get_S,
134+
bp::return_value_policy<bp::return_by_value>()),
135+
"selection matrix for under-actuation part")
136+
.def(PrintableVisitor<ActuationModelFloatingBaseThrusters>())
137+
.def(CopyableVisitor<ActuationModelFloatingBaseThrusters>());
138+
}
139+
140+
} // namespace python
141+
} // namespace crocoddyl

bindings/python/crocoddyl/multibody/multibody.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
///////////////////////////////////////////////////////////////////////////////
22
// BSD 3-Clause License
33
//
4-
// Copyright (C) 2019-2023, University of Edinburgh, Heriot-Watt University
4+
// Copyright (C) 2019-2024, University of Edinburgh, Heriot-Watt University
55
// Copyright note valid unless otherwise stated in individual files.
66
// All rights reserved.
77
///////////////////////////////////////////////////////////////////////////////
@@ -18,6 +18,7 @@ void exposeMultibody() {
1818
exposeStateMultibody();
1919
exposeActuationFloatingBase();
2020
exposeActuationFull();
21+
exposeActuationFloatingBaseThruster();
2122
exposeActuationModelMultiCopterBase();
2223
exposeForceAbstract();
2324
exposeContactAbstract();

bindings/python/crocoddyl/multibody/multibody.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
///////////////////////////////////////////////////////////////////////////////
22
// BSD 3-Clause License
33
//
4-
// Copyright (C) 2019-2023, LAAS-CNRS, University of Edinburgh
4+
// Copyright (C) 2019-2024, LAAS-CNRS, University of Edinburgh
55
// Heriot-Watt University
66
// Copyright note valid unless otherwise stated in individual files.
77
// All rights reserved.
@@ -23,6 +23,7 @@ void exposeCoPSupport();
2323
void exposeStateMultibody();
2424
void exposeActuationFloatingBase();
2525
void exposeActuationFull();
26+
void exposeActuationFloatingBaseThruster();
2627
void exposeActuationModelMultiCopterBase();
2728
void exposeForceAbstract();
2829
void exposeContactAbstract();
@@ -62,7 +63,6 @@ void exposeContact3D();
6263
void exposeContact6D();
6364
void exposeImpulse3D();
6465
void exposeImpulse6D();
65-
6666
void exposeMultibody();
6767

6868
} // namespace python

examples/quadrotor_fwddyn.py

+23-11
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,29 @@
2222
state = crocoddyl.StateMultibody(robot_model)
2323

2424
d_cog, cf, cm, u_lim, l_lim = 0.1525, 6.6e-5, 1e-6, 5.0, 0.1
25-
tau_f = np.array(
26-
[
27-
[0.0, 0.0, 0.0, 0.0],
28-
[0.0, 0.0, 0.0, 0.0],
29-
[1.0, 1.0, 1.0, 1.0],
30-
[0.0, d_cog, 0.0, -d_cog],
31-
[-d_cog, 0.0, d_cog, 0.0],
32-
[-cm / cf, cm / cf, -cm / cf, cm / cf],
33-
]
34-
)
35-
actuation = crocoddyl.ActuationModelMultiCopterBase(state, tau_f)
25+
ps = [
26+
crocoddyl.Thruster(
27+
pinocchio.SE3(np.eye(3), np.array([d_cog, 0, 0])),
28+
cm / cf,
29+
crocoddyl.ThrusterType.CCW,
30+
),
31+
crocoddyl.Thruster(
32+
pinocchio.SE3(np.eye(3), np.array([0, d_cog, 0])),
33+
cm / cf,
34+
crocoddyl.ThrusterType.CW,
35+
),
36+
crocoddyl.Thruster(
37+
pinocchio.SE3(np.eye(3), np.array([-d_cog, 0, 0])),
38+
cm / cf,
39+
crocoddyl.ThrusterType.CCW,
40+
),
41+
crocoddyl.Thruster(
42+
pinocchio.SE3(np.eye(3), np.array([0, -d_cog, 0])),
43+
cm / cf,
44+
crocoddyl.ThrusterType.CW,
45+
),
46+
]
47+
actuation = crocoddyl.ActuationModelFloatingBaseThrusters(state, ps)
3648

3749
nu = actuation.nu
3850
runningCostModel = crocoddyl.CostModelSum(state, nu)

examples/quadrotor_invdyn.py

+23-11
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,29 @@
2222
state = crocoddyl.StateMultibody(robot_model)
2323

2424
d_cog, cf, cm, u_lim, l_lim = 0.1525, 6.6e-5, 1e-6, 5.0, 0.1
25-
tau_f = np.array(
26-
[
27-
[0.0, 0.0, 0.0, 0.0],
28-
[0.0, 0.0, 0.0, 0.0],
29-
[1.0, 1.0, 1.0, 1.0],
30-
[0.0, d_cog, 0.0, -d_cog],
31-
[-d_cog, 0.0, d_cog, 0.0],
32-
[-cm / cf, cm / cf, -cm / cf, cm / cf],
33-
]
34-
)
35-
actuation = crocoddyl.ActuationModelMultiCopterBase(state, tau_f)
25+
ps = [
26+
crocoddyl.Thruster(
27+
pinocchio.SE3(np.eye(3), np.array([d_cog, 0, 0])),
28+
cm / cf,
29+
crocoddyl.ThrusterType.CCW,
30+
),
31+
crocoddyl.Thruster(
32+
pinocchio.SE3(np.eye(3), np.array([0, d_cog, 0])),
33+
cm / cf,
34+
crocoddyl.ThrusterType.CW,
35+
),
36+
crocoddyl.Thruster(
37+
pinocchio.SE3(np.eye(3), np.array([-d_cog, 0, 0])),
38+
cm / cf,
39+
crocoddyl.ThrusterType.CCW,
40+
),
41+
crocoddyl.Thruster(
42+
pinocchio.SE3(np.eye(3), np.array([0, -d_cog, 0])),
43+
cm / cf,
44+
crocoddyl.ThrusterType.CW,
45+
),
46+
]
47+
actuation = crocoddyl.ActuationModelFloatingBaseThrusters(state, ps)
3648

3749
nu = state.nv
3850
runningCostModel = crocoddyl.CostModelSum(state, nu)

examples/quadrotor_ubound.py

+23-11
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,29 @@
2222
state = crocoddyl.StateMultibody(robot_model)
2323

2424
d_cog, cf, cm, u_lim, l_lim = 0.1525, 6.6e-5, 1e-6, 5.0, 0.1
25-
tau_f = np.array(
26-
[
27-
[0.0, 0.0, 0.0, 0.0],
28-
[0.0, 0.0, 0.0, 0.0],
29-
[1.0, 1.0, 1.0, 1.0],
30-
[0.0, d_cog, 0.0, -d_cog],
31-
[-d_cog, 0.0, d_cog, 0.0],
32-
[-cm / cf, cm / cf, -cm / cf, cm / cf],
33-
]
34-
)
35-
actuation = crocoddyl.ActuationModelMultiCopterBase(state, tau_f)
25+
ps = [
26+
crocoddyl.Thruster(
27+
pinocchio.SE3(np.eye(3), np.array([d_cog, 0, 0])),
28+
cm / cf,
29+
crocoddyl.ThrusterType.CCW,
30+
),
31+
crocoddyl.Thruster(
32+
pinocchio.SE3(np.eye(3), np.array([0, d_cog, 0])),
33+
cm / cf,
34+
crocoddyl.ThrusterType.CW,
35+
),
36+
crocoddyl.Thruster(
37+
pinocchio.SE3(np.eye(3), np.array([-d_cog, 0, 0])),
38+
cm / cf,
39+
crocoddyl.ThrusterType.CCW,
40+
),
41+
crocoddyl.Thruster(
42+
pinocchio.SE3(np.eye(3), np.array([0, -d_cog, 0])),
43+
cm / cf,
44+
crocoddyl.ThrusterType.CW,
45+
),
46+
]
47+
actuation = crocoddyl.ActuationModelFloatingBaseThrusters(state, ps)
3648

3749
nu = actuation.nu
3850
runningCostModel = crocoddyl.CostModelSum(state, nu)

include/crocoddyl/core/numdiff/actuation.hpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
///////////////////////////////////////////////////////////////////////////////
22
// BSD 3-Clause License
33
//
4-
// Copyright (C) 2019-2023, University of Edinburgh, LAAS-CNRS
4+
// Copyright (C) 2019-2024, University of Edinburgh, LAAS-CNRS
55
// Heriot-Watt University
66
// Copyright note valid unless otherwise stated in individual files.
77
// All rights reserved.
@@ -90,6 +90,13 @@ class ActuationModelNumDiffTpl : public ActuationModelAbstractTpl<_Scalar> {
9090
const Eigen::Ref<const VectorXs>& x,
9191
const Eigen::Ref<const VectorXs>& tau);
9292

93+
/**
94+
* @brief @copydoc Base::torqueTransform()
95+
*/
96+
virtual void torqueTransform(
97+
const boost::shared_ptr<ActuationDataAbstract>& data,
98+
const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u);
99+
93100
/**
94101
* @brief @copydoc Base::createData()
95102
*/

include/crocoddyl/core/numdiff/actuation.hxx

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
///////////////////////////////////////////////////////////////////////////////
22
// BSD 3-Clause License
33
//
4-
// Copyright (C) 2019-2023, University of Edinburgh, LAAS-CNRS
4+
// Copyright (C) 2019-2024, University of Edinburgh, LAAS-CNRS
55
// Copyright note valid unless otherwise stated in individual files.
66
// All rights reserved.
77
///////////////////////////////////////////////////////////////////////////////
@@ -138,9 +138,27 @@ void ActuationModelNumDiffTpl<Scalar>::commands(
138138
std::to_string(model_->get_state()->get_nv()) + ")");
139139
}
140140
Data* d = static_cast<Data*>(data.get());
141+
model_->commands(d->data_0, x, tau);
142+
data->u = d->data_0->u;
143+
}
141144

142-
model_->torqueTransform(d->data_x[0], x, tau);
143-
data->u.noalias() = d->data_x[0]->Mtau * tau;
145+
template <typename Scalar>
146+
void ActuationModelNumDiffTpl<Scalar>::torqueTransform(
147+
const boost::shared_ptr<ActuationDataAbstract>& data,
148+
const Eigen::Ref<const VectorXs>& x, const Eigen::Ref<const VectorXs>& u) {
149+
if (static_cast<std::size_t>(x.size()) != model_->get_state()->get_nx()) {
150+
throw_pretty("Invalid argument: "
151+
<< "x has wrong dimension (it should be " +
152+
std::to_string(model_->get_state()->get_nx()) + ")");
153+
}
154+
if (static_cast<std::size_t>(u.size()) != nu_) {
155+
throw_pretty("Invalid argument: "
156+
<< "u has wrong dimension (it should be " +
157+
std::to_string(nu_) + ")");
158+
}
159+
Data* d = static_cast<Data*>(data.get());
160+
model_->torqueTransform(d->data_0, x, u);
161+
d->Mtau = d->data_0->Mtau;
144162
}
145163

146164
template <typename Scalar>

0 commit comments

Comments
 (0)