Skip to content

Commit ed1cb0e

Browse files
committed
fixes after rebase
1 parent cb6e8e2 commit ed1cb0e

File tree

10 files changed

+105
-42
lines changed

10 files changed

+105
-42
lines changed

.bazelrc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,3 @@ build --action_env=LD_LIBRARY_PATH=
5252
build --python_path=python3
5353

5454
build --define=WITH_GUROBI=ON
55-
56-
build --local_resources=cpu=8

core/BUILD.bazel

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ filegroup(
2929
],
3030
)
3131

32+
cc_library(
33+
name = "logging",
34+
hdrs = ["common/logging_utils.hpp"],
35+
)
36+
3237
cc_library(
3338
name = "c3",
3439
srcs = [
@@ -49,11 +54,15 @@ cc_library(
4954
"c3_qp.h",
5055
"c3_plus.h",
5156
],
57+
data = [
58+
":default_solver_options",
59+
],
5260
copts = ["-fopenmp"],
5361
linkopts = ["-fopenmp"],
5462
deps = [
5563
":lcs",
5664
":options",
65+
":logging",
5766
"@drake//:drake_shared_library",
5867
] + select({
5968
"//tools:with_gurobi": ["@gurobi//:gurobi_cxx"],

core/c3.cc

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <drake/common/find_runfiles.h>
88
#include <omp.h>
99

10+
#include "common/logging_utils.hpp"
1011
#include "lcs.h"
1112
#include "solver_options_io.h"
1213

@@ -90,7 +91,6 @@ C3::C3(const LCS& lcs, const CostMatrices& costs,
9091
w_sol_ = std::make_unique<std::vector<VectorXd>>();
9192
delta_sol_ = std::make_unique<std::vector<VectorXd>>();
9293
for (int i = 0; i < N_; ++i) {
93-
z_sol_->push_back(Eigen::VectorXd::Zero(n_z_));
9494
x_sol_->push_back(Eigen::VectorXd::Zero(n_x_));
9595
lambda_sol_->push_back(Eigen::VectorXd::Zero(n_lambda_));
9696
u_sol_->push_back(Eigen::VectorXd::Zero(n_u_));
@@ -269,6 +269,7 @@ const std::vector<drake::solvers::QuadraticCost*>& C3::GetTargetCost() {
269269
}
270270

271271
void C3::Solve(const VectorXd& x0) {
272+
drake::log()->debug("C3::Solve called");
272273
auto start = std::chrono::high_resolution_clock::now();
273274
// Set the initial state constraint
274275
if (initial_state_constraint_) {
@@ -319,6 +320,8 @@ void C3::Solve(const VectorXd& x0) {
319320
std::vector<VectorXd> w(N_, VectorXd::Zero(n_z_));
320321
vector<MatrixXd> G = cost_matrices_.G;
321322

323+
drake::log()->debug("C3::Solve starting ADMM iterations.");
324+
322325
for (int iter = 0; iter < options_.admm_iter; iter++) {
323326
ADMMStep(x0, &delta, &w, &G, iter);
324327
}
@@ -328,12 +331,14 @@ void C3::Solve(const VectorXd& x0) {
328331
WD.at(i) = delta.at(i) - w.at(i);
329332
}
330333

334+
drake::log()->debug("C3::Solve final SolveQP step.");
331335
*z_fin_ = SolveQP(x0, G, WD, options_.admm_iter, true);
332336

333337
*w_sol_ = w;
334338
*delta_sol_ = delta;
335339

336340
if (!options_.end_on_qp_step) {
341+
drake::log()->debug("C3::Solve compute a half step.");
337342
*z_sol_ = delta;
338343
z_sol_->at(0).segment(0, n_x_) = x0;
339344
x_sol_->at(0) = x0;
@@ -357,6 +362,7 @@ void C3::Solve(const VectorXd& x0) {
357362
solve_time_ =
358363
std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() /
359364
1e6;
365+
drake::log()->debug("C3::Solve completed in {} seconds.", solve_time_);
360366
}
361367

362368
void C3::ADMMStep(const VectorXd& x0, vector<VectorXd>* delta,
@@ -368,13 +374,15 @@ void C3::ADMMStep(const VectorXd& x0, vector<VectorXd>* delta,
368374
WD.at(i) = delta->at(i) - w->at(i);
369375
}
370376

377+
drake::log()->debug("C3::ADMMStep SolveQP step.");
371378
vector<VectorXd> z = SolveQP(x0, *G, WD, admm_iteration, false);
372379

373380
vector<VectorXd> ZW(N_, VectorXd::Zero(n_z_));
374381
for (int i = 0; i < N_; ++i) {
375382
ZW[i] = w->at(i) + z[i];
376383
}
377384

385+
drake::log()->debug("C3::ADMMStep SolveProjection step.");
378386
if (cost_matrices_.U[0].isZero(0)) {
379387
*delta = SolveProjection(*G, ZW, admm_iteration);
380388
} else {
@@ -419,10 +427,17 @@ void C3::StoreQPResults(const MathematicalProgramResult& result,
419427
z_sol_->at(i).segment(0, n_x_) = result.GetSolution(x_[i]);
420428
z_sol_->at(i).segment(n_x_, n_lambda_) = result.GetSolution(lambda_[i]);
421429
z_sol_->at(i).segment(n_x_ + n_lambda_, n_u_) = result.GetSolution(u_[i]);
430+
431+
drake::log()->trace(
432+
"C3::StoreQPResults storing solution for time step {}: "
433+
"lambda = {}",
434+
i, EigenToString(lambda_sol_->at(i).transpose()));
422435
}
423436

424437
if (!warm_start_)
425438
return; // No warm start, so no need to update warm start parameters
439+
440+
drake::log()->trace("C3::StoreQPResults storing warm start values.");
426441
for (int i = 0; i < N_ + 1; ++i) {
427442
if (i < N_) {
428443
warm_start_x_[admm_iteration][i] = result.GetSolution(x_[i]);
@@ -436,6 +451,7 @@ void C3::StoreQPResults(const MathematicalProgramResult& result,
436451
vector<VectorXd> C3::SolveQP(const VectorXd& x0, const vector<MatrixXd>& G,
437452
const vector<VectorXd>& WD, int admm_iteration,
438453
bool is_final_solve) {
454+
drake::log()->trace("C3::SolveQP Adding augmented costs(G).");
439455
// Add or update augmented costs
440456
if (augmented_costs_.size() == 0) {
441457
for (int i = 0; i < N_; ++i)
@@ -452,16 +468,17 @@ vector<VectorXd> C3::SolveQP(const VectorXd& x0, const vector<MatrixXd>& G,
452468

453469
SetInitialGuessQP(x0, admm_iteration);
454470

471+
drake::log()->trace("C3::SolveQP calling solver.");
455472
try {
456473
MathematicalProgramResult result = osqp_.Solve(prog_);
474+
if (!result.is_success()) {
475+
drake::log()->warn("C3::SolveQP failed to solve the QP with status: {}",
476+
result.get_solution_result());
477+
}
478+
StoreQPResults(result, admm_iteration, is_final_solve);
457479
} catch (const std::exception& e) {
458480
drake::log()->error("C3::SolveQP failed with exception: {}", e.what());
459481
}
460-
if (!result.is_success()) {
461-
drake::log()->warn("C3::SolveQP failed to solve the QP with status: {}",
462-
result.get_solution_result());
463-
}
464-
StoreQPResults(result, admm_iteration, is_final_solve);
465482

466483
return *z_sol_;
467484
}
@@ -477,8 +494,11 @@ vector<VectorXd> C3::SolveProjection(const vector<MatrixXd>& U,
477494
omp_set_schedule(omp_sched_static, 0);
478495
}
479496

497+
// clang-format off
480498
#pragma omp parallel for num_threads( \
481499
options_.num_threads) if (use_parallelization_in_projection_)
500+
// clang-format on
501+
482502
for (int i = 0; i < N_; ++i) {
483503
if (warm_start_) {
484504
if (i == N_ - 1) {

core/c3_options.h

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ struct C3Options {
6767
std::vector<double> g_lambda_t;
6868
std::vector<double> g_lambda;
6969
std::vector<double> g_u;
70+
std::vector<double> g_eta_vector;
7071
std::optional<std::vector<double>> g_eta_slack;
7172
std::optional<std::vector<double>> g_eta_n;
7273
std::optional<std::vector<double>> g_eta_t;
@@ -79,6 +80,7 @@ struct C3Options {
7980
std::vector<double> u_lambda_t;
8081
std::vector<double> u_lambda;
8182
std::vector<double> u_u;
83+
std::vector<double> u_eta_vector;
8284
std::optional<std::vector<double>> u_eta_slack;
8385
std::optional<std::vector<double>> u_eta_n;
8486
std::optional<std::vector<double>> u_eta_t;
@@ -139,16 +141,14 @@ struct C3Options {
139141
}
140142
g_vector.insert(g_vector.end(), g_lambda.begin(), g_lambda.end());
141143
g_vector.insert(g_vector.end(), g_u.begin(), g_u.end());
142-
if (g_eta != std::nullopt || g_eta_slack != std::nullopt) {
143-
if (g_eta == std::nullopt || g_eta->empty()) {
144-
g_vector.insert(g_vector.end(), g_eta_slack->begin(),
145-
g_eta_slack->end());
146-
g_vector.insert(g_vector.end(), g_eta_n->begin(), g_eta_n->end());
147-
g_vector.insert(g_vector.end(), g_eta_t->begin(), g_eta_t->end());
148-
} else {
149-
g_vector.insert(g_vector.end(), g_eta->begin(), g_eta->end());
150-
}
144+
g_eta_vector = g_eta.value_or(std::vector<double>());
145+
if (g_eta_vector.empty() && g_eta_slack.has_value()) {
146+
g_eta_vector.insert(g_eta_vector.end(), g_eta_slack->begin(),
147+
g_eta_slack->end());
148+
g_eta_vector.insert(g_eta_vector.end(), g_eta_n->begin(), g_eta_n->end());
149+
g_eta_vector.insert(g_eta_vector.end(), g_eta_t->begin(), g_eta_t->end());
151150
}
151+
g_vector.insert(g_vector.end(), g_eta_vector.begin(), g_eta_vector.end());
152152

153153
u_vector = std::vector<double>();
154154
u_vector.insert(u_vector.end(), u_x.begin(), u_x.end());
@@ -159,16 +159,14 @@ struct C3Options {
159159
}
160160
u_vector.insert(u_vector.end(), u_lambda.begin(), u_lambda.end());
161161
u_vector.insert(u_vector.end(), u_u.begin(), u_u.end());
162-
if (u_eta != std::nullopt || u_eta_slack != std::nullopt) {
163-
if (u_eta == std::nullopt || u_eta->empty()) {
164-
g_vector.insert(g_vector.end(), u_eta_slack->begin(),
165-
u_eta_slack->end());
166-
g_vector.insert(g_vector.end(), u_eta_n->begin(), u_eta_n->end());
167-
g_vector.insert(g_vector.end(), u_eta_t->begin(), u_eta_t->end());
168-
} else {
169-
g_vector.insert(g_vector.end(), u_eta->begin(), u_eta->end());
170-
}
162+
u_eta_vector = u_eta.value_or(std::vector<double>());
163+
if (u_eta_vector.empty() && u_eta_slack.has_value()) {
164+
u_eta_vector.insert(u_eta_vector.end(), u_eta_slack->begin(),
165+
u_eta_slack->end());
166+
u_eta_vector.insert(u_eta_vector.end(), u_eta_n->begin(), u_eta_n->end());
167+
u_eta_vector.insert(u_eta_vector.end(), u_eta_t->begin(), u_eta_t->end());
171168
}
169+
u_vector.insert(u_vector.end(), u_eta_vector.begin(), u_eta_vector.end());
172170

173171
Eigen::VectorXd q = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(
174172
this->q_vector.data(), this->q_vector.size());
@@ -179,8 +177,6 @@ struct C3Options {
179177
Eigen::VectorXd u = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned>(
180178
this->u_vector.data(), this->u_vector.size());
181179

182-
DRAKE_DEMAND(g.size() == u.size());
183-
184180
Q = w_Q * q.asDiagonal();
185181
R = w_R * r.asDiagonal();
186182
G = w_G * g.asDiagonal();

core/c3_plus.cc

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
#include <Eigen/Dense>
66

77
#include "c3_options.h"
8+
#include "common/logging_utils.hpp"
89
#include "lcs.h"
910

11+
#include "drake/common/text_logging.h"
12+
1013
namespace c3 {
1114

1215
using Eigen::MatrixXd;
@@ -19,6 +22,16 @@ C3Plus::C3Plus(const LCS& lcs, const CostMatrices& costs,
1922
const vector<VectorXd>& xdesired, const C3Options& options)
2023
: C3(lcs, costs, xdesired, options,
2124
lcs.num_states() + 2 * lcs.num_lambdas() + lcs.num_inputs()) {
25+
if (warm_start_) {
26+
warm_start_eta_.resize(options_.admm_iter + 1);
27+
for (int iter = 0; iter < options_.admm_iter + 1; ++iter) {
28+
warm_start_eta_[iter].resize(N_);
29+
for (int i = 0; i < N_; ++i) {
30+
warm_start_eta_[iter][i] = VectorXd::Zero(n_lambda_);
31+
}
32+
}
33+
}
34+
2235
// Initialize eta as optimization variables
2336
eta_ = vector<drake::solvers::VectorXDecisionVariable>();
2437
eta_sol_ = std::make_unique<std::vector<VectorXd>>();
@@ -40,10 +53,7 @@ C3Plus::C3Plus(const LCS& lcs, const CostMatrices& costs,
4053
EtaLinEq.block(0, n_x_ + n_lambda_, n_lambda_, n_u_) = lcs_.H().at(i);
4154

4255
eta_constraints_[i] =
43-
prog_
44-
.AddLinearEqualityConstraint(
45-
EtaLinEq, -lcs_.c().at(i),
46-
{x_.at(i), lambda_.at(i), u_.at(i), eta_.at(i)})
56+
prog_.AddLinearEqualityConstraint(EtaLinEq, -lcs_.c().at(i), z_.at(i))
4757
.evaluator()
4858
.get();
4959
}
@@ -81,16 +91,23 @@ void C3Plus::SetInitialGuessQP(const Eigen::VectorXd& x0, int admm_iteration) {
8191
void C3Plus::StoreQPResults(const MathematicalProgramResult& result,
8292
int admm_iteration, bool is_final_solve) {
8393
C3::StoreQPResults(result, admm_iteration, is_final_solve);
94+
drake::log()->trace("C3Plus::StoreQPResults storing eta results.");
8495
for (int i = 0; i < N_; i++) {
8596
if (is_final_solve) {
8697
eta_sol_->at(i) = result.GetSolution(eta_[i]);
8798
}
8899
z_sol_->at(i).segment(n_x_ + n_lambda_ + n_u_, n_lambda_) =
89100
result.GetSolution(eta_[i]);
101+
drake::log()->trace(
102+
"C3Plus::StoreQPResults storing solution for time step {}: "
103+
"eta = {}",
104+
i, EigenToString(eta_sol_->at(i).transpose()));
90105
}
91106

92107
if (!warm_start_)
93108
return; // No warm start, so no need to update warm start parameters
109+
110+
drake::log()->trace("C3Plus::StoreQPResults storing warm start eta.");
94111
for (int i = 0; i < N_; ++i) {
95112
warm_start_eta_[admm_iteration][i] = result.GetSolution(eta_[i]);
96113
}
@@ -120,6 +137,12 @@ VectorXd C3Plus::SolveSingleProjection(const MatrixXd& U,
120137
VectorXd lambda_c = delta_c.segment(n_x_, n_lambda_);
121138
VectorXd eta_c = delta_c.segment(n_x_ + n_lambda_ + n_u_, n_lambda_);
122139

140+
drake::log()->trace(
141+
"C3Plus::SolveSingleProjection ADMM iteration {}: pre-projection "
142+
"lambda = {}, eta = {}",
143+
admm_iteration, EigenToString(lambda_c.transpose()),
144+
EigenToString(eta_c.transpose()));
145+
123146
// Set the smaller of lambda and eta to zero
124147
Eigen::Array<bool, Eigen::Dynamic, 1> eta_larger =
125148
eta_c.array() * w_eta_vec.array().sqrt() >

core/common/logging_utils.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <sstream>
2+
#include <string>
3+
4+
#include <Eigen/Dense>
5+
6+
/**
7+
* Converts an Eigen matrix to a string representation.
8+
* This function is useful for logging or debugging purposes.
9+
*
10+
* @tparam Derived The type of the Eigen matrix.
11+
* @param mat The Eigen matrix to convert.
12+
* @return A string representation of the matrix.
13+
*/
14+
template <typename Derived>
15+
std::string EigenToString(const Eigen::MatrixBase<Derived>& mat) {
16+
std::stringstream ss;
17+
ss << mat;
18+
return ss.str();
19+
}

multibody/geom_geom_collider.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,11 @@ GeomGeomCollider<T>::CalcForceBasisInWorldFrame(
280280
const auto query_result = GetGeometryQueryResult(context);
281281
if (num_friction_directions < 1) {
282282
// Planar contact: basis is constructed from the contact and planar normals.
283-
return ComputePlanarForceBasis(-query_result.signed_distance_pair.nhat_BA_W,
284-
planar_normal);
283+
return ComputePlanarForceBasis(-query_result.nhat_BA_W, planar_normal);
285284
} else {
286285
// 3D contact: build polytope basis and rotate using contact normal.
287286
auto R_WC = drake::math::RotationMatrix<T>::MakeFromOneVector(
288-
-query_result.signed_distance_pair.nhat_BA_W, 0);
287+
-query_result.nhat_BA_W, 0);
289288
return ComputePolytopeForceBasis(num_friction_directions) *
290289
R_WC.matrix().transpose();
291290
}

multibody/lcs_factory.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,9 @@ std::vector<LCSContactDescription> LCSFactory::GetContactDescriptions() {
420420
contact_descriptions.at(i).witness_point_A ==
421421
normal_contact_descriptions.at(normal_index).witness_point_A);
422422
contact_descriptions.at(i).force_basis =
423-
contact_descriptions.at(i).force_basis +
424-
mu_[normal_index] *
425-
normal_contact_descriptions.at(normal_index).force_basis;
423+
mu_[normal_index] * contact_descriptions.at(i).force_basis +
424+
normal_contact_descriptions.at(normal_index).force_basis;
425+
contact_descriptions.at(i).force_basis.normalize();
426426
}
427427
}
428428

systems/c3_controller.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ C3Controller::C3Controller(
111111
.get_index();
112112
c3_intermediates_port_ =
113113
this->DeclareAbstractOutputPort(
114-
"intermediates",
115-
C3Output::C3Intermediates(n_x_, n_lambda_, n_u_, N_),
114+
"intermediates", C3Output::C3Intermediates(c3_->GetZSize(), N_),
116115
&C3Controller::OutputC3Intermediates)
117116
.get_index();
118117

systems/c3_controller_options.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ struct C3ControllerOptions {
8282
DRAKE_DEMAND(static_cast<int>(c3_options.u_lambda.size()) ==
8383
expected_lambda_size);
8484
if (projection_type == "C3+") {
85-
DRAKE_DEMAND(static_cast<int>(c3_options.g_eta->size()) ==
85+
DRAKE_DEMAND(static_cast<int>(c3_options.g_eta_vector.size()) ==
8686
expected_lambda_size);
87-
DRAKE_DEMAND(static_cast<int>(c3_options.u_eta->size()) ==
87+
DRAKE_DEMAND(static_cast<int>(c3_options.u_eta_vector.size()) ==
8888
expected_lambda_size);
8989
}
9090
}

0 commit comments

Comments
 (0)