-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathinverse_dynamics_qp.h
More file actions
341 lines (294 loc) · 11.1 KB
/
Copy pathinverse_dynamics_qp.h
File metadata and controls
341 lines (294 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
#pragma once
#include "multibody/kinematic/kinematic_evaluator_set.h"
#include "multibody/kinematic/world_point_evaluator.h"
#include "drake/multibody/plant/multibody_plant.h"
#include "drake/solvers/mathematical_program.h"
namespace dairlib {
namespace systems {
namespace controllers {
using CostMap =
std::unordered_map<std::string,
std::shared_ptr<drake::solvers::QuadraticCost>>;
using FrictionConeMap =
std::unordered_map<std::string,
std::shared_ptr<drake::solvers::LinearConstraint>>;
using ContactMap = std::unordered_map<
std::string, std::unique_ptr<const multibody::WorldPointEvaluator<double>>>;
/*!
* Wrapper class for handling kinematics and dynamics for a quadratic program
* which computes dynamically consistent accelerations, inputs,
* and constraint forces (including contacts) which minimize some combined
* cost on these variables.
*
* Designed to be used as a back-end for operational space control, but
* applicable to other model-based instantaneous QP controllers.
*
* Constructs a QP of the form
*
* minimize C₁(v̇) + C₂(u), C₃(λₕ) + C₄(λ_c) + C₄(λₑ)
* subject to Jₕv̇ + J̇ₕ = 0
* J_cv̇ + J̇_c = 0
* Mv̇ + c = Bu + Jₕᵀλₕ + J_cᵀλ_c + Jₑᵀλₑ
* λ_c ∈ FrictionCone
*
* Where
*
* Cᵢ are arbitrary user-defined convex quadratic costs,
* v̇ are generalized accelerations,
* u are actuation efforts,
* λₕ are constraint forces for general holonomic constraints such linkages,
* λ_c are constraint forces for contact constraints
* λₑ are external forces, such as contact forces, which do not constrain the
* robot's motion (like force on the end effector of a robot arm)
*
*/
class InverseDynamicsQp {
public:
InverseDynamicsQp(const drake::multibody::MultibodyPlant<double>& plant,
drake::systems::Context<double>* context);
/*!
* @brief Adds the set of holonomic constraints given by eval to the QP.
*/
void AddHolonomicConstraint(
std::unique_ptr<const multibody::KinematicEvaluatorSet<double>> eval);
/*!
* Adds a contact constraint
* @param name name of the contact constraint
* @param eval WorldPointEvaluator describing the contact point
* @param friction_coefficient friction coefficient of the friction cone for
* the associated contact force
*/
void AddContactConstraint(
const std::string& name,
std::unique_ptr<const multibody::WorldPointEvaluator<double>> eval,
double friction_coefficient);
/*!
* Adds an external force to the dynamics.
*
* Note: By default, no constraints are imposed on the external forces. If
* external forces are declared without corresponding constraints/costs
* from the upstream controller, then unexpected behavior may occur.
* (i.e. Unconstrained forces effectively act as input variables.)
*
* @param name name of the external force
* @param eval WorldPointEvaluator for the associated jacobian
*/
void AddExternalForce(
const std::string& name,
std::unique_ptr<const multibody::WorldPointEvaluator<double>> eval);
/*!
* Adds the quadratic cost 1/2 xᵀQx + bᵀx to the underlying QP
*
* Must be called AFTER build
*
* @param name name of the cost (must be unique)
* @param Q PSD cost hessian
* @param b linear term
* @param vars decision variables representing x
*/
void AddQuadraticCost(const std::string& name, const Eigen::MatrixXd& Q,
const Eigen::VectorXd& b,
const drake::solvers::VectorXDecisionVariable& vars);
/*!
* See above
*/
void AddQuadraticCost(const std::string& name, const Eigen::MatrixXd& Q,
const Eigen::VectorXd& b,
const drake::solvers::VariableRefList& vars);
/*!
* Builds the underlying QP
*/
void Build();
/*!
* @return the total dimension of the (stacked) contact forces.
* This is greater than or equal to the number of active rows in the
* contact constraint (see kinematic_evaluator.h).
*/
[[nodiscard]] int nc() const { return nc_; }
/*!
* @return the total dimension of the holonomic constraint forces.
* Equal to the number of rows in the holonomic constraint.
*/
[[nodiscard]] int nh() const { return nh_; }
/*!
* @return the total dimension of the external forces.
* This is equal to the number of rows in the external force constraint.
*/
[[nodiscard]] int ne() const { return ne_; }
/*!
* @return the total number of active rows in the contact constraint for all
* contacts. Potentially less than nc() to avoid redundant constraints.
*/
[[nodiscard]] int nc_active() const { return nc_active_; }
/*
* N.B. To avoid overhead in the OSC loop, we don't check the if the QP is
* built before these are called, but the decision variables are empty
* until then!
*/
[[nodiscard]] const drake::solvers::VectorXDecisionVariable& dv() const {
return dv_;
}
[[nodiscard]] const drake::solvers::VectorXDecisionVariable& u() const {
return u_;
}
[[nodiscard]] const drake::solvers::VectorXDecisionVariable& lambda_h()
const {
return lambda_h_;
}
[[nodiscard]] const drake::solvers::VectorXDecisionVariable& lambda_c()
const {
return lambda_c_;
}
[[nodiscard]] const drake::solvers::VectorXDecisionVariable& lambda_e()
const {
return lambda_e_;
}
[[nodiscard]] const drake::solvers::VectorXDecisionVariable& epsilon() const {
return epsilon_;
}
/*!
* @return a const-reference to the underlying MathematicalProgram
*/
[[nodiscard]] const drake::solvers::MathematicalProgram& get_prog() const {
return prog_;
}
/*!
* @return a mutable reference to the underlying MathematicalProgram
*/
[[nodiscard]] drake::solvers::MathematicalProgram& get_mutable_prog() {
return prog_;
}
/*!
* @brief gets a const reference WorldPointEvaluator for the contact with
* the given name
*/
[[nodiscard]] const multibody::WorldPointEvaluator<double>&
get_contact_evaluator(const std::string& name) const {
return *contact_constraint_evaluators_.at(name);
}
/*!
* @brief gets a const reference to the KinematicEvaluatorSet associated
* with the holonomic constraints
*/
[[nodiscard]] const multibody::KinematicEvaluatorSet<double>&
get_holonomic_evaluators() const {
return *holonomic_constraints_;
}
/*!
* @brief updates the coefficients of the cost with the given name to
* 1/2 xᵀQx + bᵀx + c
*/
void UpdateCost(const std::string& name, const Eigen::MatrixXd& Q,
const Eigen::VectorXd& b, double c = 0) {
all_costs_.at(name)->UpdateCoefficients(Q, b, c, true);
};
/*!
* updates the dynamics and contact constraints to reflect a given
* state and contact configuration.
* @param x the robot state [q, v]
* @param active_contact_constraints the names of all contact constraints
* currently in contact
* @param active_external_forces the names of all the external forces
* currently being applied
*/
void UpdateDynamics(
const Eigen::VectorXd& x,
const std::vector<std::string>& active_contact_constraints,
const std::vector<std::string>& active_external_forces);
/*!
* @brief gets the drake QuadraticCost evaluator associated with a given cost
*/
[[nodiscard]] const drake::solvers::QuadraticCost& get_cost_evaluator(
const std::string& name) const {
return *all_costs_.at(name);
}
/*!
* @brief checks if this QP has a cost with the given name
*/
bool has_cost_named(const std::string& name) {
return all_costs_.count(name) > 0;
}
/*!
* @brief utility functions to enable/disable gravity compensation
*/
void DisableGravityCompensation() { with_gravity_compensation_ = false; }
void EnableGravityCompensation() { with_gravity_compensation_ = true; }
bool HasGravityCompensation() { return with_gravity_compensation_; }
/*!
* @brief utility functions to enable/disable input constraints
*/
void DisableInputConstraints() { with_input_constraints_ = false; }
void EnableInputConstraints() { with_input_constraints_ = true; }
bool HasInputConstraints() { return with_input_constraints_; }
/*!
* @brief utility functions to enable/disable acceleration constraints
*/
void DisableAccelerationConstraints() {
with_acceleration_constraints_ = false;
}
void EnableAccelerationConstraints() {
with_acceleration_constraints_ = true;
}
bool HasAccelerationConstraints() { return with_acceleration_constraints_; }
private:
// Multibody Dynamics
const drake::multibody::MultibodyPlant<double>& plant_;
drake::systems::Context<double>* context_;
// Holonomic constraints are bilateral constraints that are always active
std::unique_ptr<const multibody::KinematicEvaluatorSet<double>>
holonomic_constraints_ = nullptr;
// Contact constraints are unilateral constraints with an associated
// contact force which obeys the friction cone
ContactMap contact_constraint_evaluators_{};
std::unordered_map<std::string, int> lambda_c_start_;
std::unordered_map<std::string, int> Jc_active_start_;
std::unordered_map<std::string, double> mu_map_;
// External forces are reaction forces we want to "track," but which do not
// constrain the robot's motion
std::unordered_map<
std::string, std::unique_ptr<const multibody::KinematicEvaluator<double>>>
external_force_evaluators_{};
std::unordered_map<std::string, std::pair<int, int>> lambda_e_start_and_size_;
// Size of position, velocity, and input of the plant
int nq_;
int nv_;
int nu_;
// Size of constraints and external forces
int nh_ = 0;
int ne_ = 0;
int nc_ = 0;
int nc_active_ = 0;
// Mathematical Program
drake::solvers::MathematicalProgram prog_;
// Decision Variables
drake::solvers::VectorXDecisionVariable u_{};
drake::solvers::VectorXDecisionVariable dv_{};
drake::solvers::VectorXDecisionVariable lambda_h_{};
drake::solvers::VectorXDecisionVariable lambda_c_{};
drake::solvers::VectorXDecisionVariable lambda_e_{};
drake::solvers::VectorXDecisionVariable epsilon_{};
// Costs
CostMap all_costs_;
// Friction Cone Constraints
FrictionConeMap lambda_c_friction_cone_;
FrictionConeMap lambda_e_friction_cone_;
// Dynamics
std::shared_ptr<drake::solvers::LinearEqualityConstraint> dynamics_c_;
std::shared_ptr<drake::solvers::LinearEqualityConstraint> holonomic_c_;
std::shared_ptr<drake::solvers::LinearEqualityConstraint> contact_c_;
// input limits
std::shared_ptr<drake::solvers::BoundingBoxConstraint> input_limit_c_;
// acceleration limits
std::shared_ptr<drake::solvers::BoundingBoxConstraint> acceleration_limit_c_;
// Bookkeeping
bool built_ = false;
// Flag to indicate if gravity compensation is enabled. Default is true.
bool with_gravity_compensation_ = true;
// Flag to indicate if input constraints are enabled. Default is true.
bool with_input_constraints_ = true;
// Flag to indicate if acceleration constraints are enabled. Default is false.
bool with_acceleration_constraints_ = false;
};
} // namespace controllers
} // namespace systems
} // namespace dairlib