GCC Code Coverage Report


Directory: ./
File: src/qp-static-stability.cc
Date: 2025-05-05 12:19:30
Exec Total Coverage
Lines: 0 111 0.0%
Branches: 0 290 0.0%

Line Branch Exec Source
1 // Copyright (c) 2015, Joseph Mirabel
2 // Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3 //
4
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // 1. Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 // DAMAGE.
28
29 #include "hpp/constraints/qp-static-stability.hh"
30
31 #include <hpp/pinocchio/device.hh>
32 #include <hpp/pinocchio/joint.hh>
33 #include <limits>
34
35 #include "hpp/constraints/tools.hh"
36
37 namespace hpp {
38 namespace constraints {
39 namespace {
40 std::size_t forceDatasToNbContacts(
41 const std::vector<ConvexShapeContact::ForceData>& fds) {
42 std::size_t nb = 0;
43 for (std::vector<ConvexShapeContact::ForceData>::const_iterator it =
44 fds.begin();
45 it != fds.end(); ++it)
46 nb += it->points.size();
47 return nb;
48 }
49 } // namespace
50
51 const Eigen::Matrix<value_type, 6, 1> QPStaticStability::Gravity =
52 (Eigen::Matrix<value_type, 6, 1>() << 0, 0, -1, 0, 0, 0).finished();
53 const Eigen::Matrix<value_type, 6, 1> QPStaticStability::MinusGravity =
54 (Eigen::Matrix<value_type, 6, 1>() << 0, 0, +1, 0, 0, 0).finished();
55
56 QPStaticStability::QPStaticStability(const std::string& name,
57 const DevicePtr_t& robot,
58 const Contacts_t& contacts,
59 const CenterOfMassComputationPtr_t& com)
60 : DifferentiableFunction(robot->configSize(), robot->numberDof(),
61 LiegroupSpace::R1(), name),
62 Zeros(new qpOASES::real_t[contacts.size()]),
63 nWSR(40),
64 robot_(robot),
65 nbContacts_(contacts.size()),
66 com_(com),
67 H_(nbContacts_, nbContacts_),
68 G_(nbContacts_),
69 qp_((qpOASES::int_t)nbContacts_, qpOASES::HST_SEMIDEF),
70 phi_(Eigen::Matrix<value_type, 6, Eigen::Dynamic>::Zero(6, nbContacts_),
71 Eigen::Matrix<value_type, 6, Eigen::Dynamic>::Zero(
72 6, nbContacts_ * robot->numberDof())),
73 primal_(vector_t::Zero(nbContacts_)),
74 dual_(vector_t::Zero(nbContacts_)) {
75 VectorMap_t zeros(Zeros, nbContacts_);
76 zeros.setZero();
77
78 qpOASES::Options options;
79 qp_.setOptions(options);
80
81 qp_.setPrintLevel(qpOASES::PL_NONE);
82 phi_.setSize(2, nbContacts_);
83 Traits<PointCom>::Ptr_t OG = PointCom::create(com);
84 for (std::size_t i = 0; i < contacts.size(); ++i) {
85 Traits<PointInJoint>::Ptr_t OP2 = PointInJoint::create(
86 contacts[i].joint, contacts[i].point, robot->numberDof());
87 Traits<VectorInJoint>::Ptr_t n2 = VectorInJoint::create(
88 contacts[i].joint, contacts[i].normal, robot->numberDof());
89
90 phi_(0, i) = n2;
91 phi_(1, i) = (OG - OP2) ^ n2;
92 }
93 }
94
95 QPStaticStability::QPStaticStability(const std::string& name,
96 const DevicePtr_t& robot,
97 const std::vector<ForceData>& contacts,
98 const CenterOfMassComputationPtr_t& com)
99 : DifferentiableFunction(robot->configSize(), robot->numberDof(), 1, name),
100 Zeros(new qpOASES::real_t[forceDatasToNbContacts(contacts)]),
101 nWSR(40),
102 robot_(robot),
103 nbContacts_(forceDatasToNbContacts(contacts)),
104 com_(com),
105 H_(nbContacts_, nbContacts_),
106 G_(nbContacts_),
107 qp_((qpOASES::int_t)nbContacts_, qpOASES::HST_SEMIDEF),
108 phi_(Eigen::Matrix<value_type, 6, Eigen::Dynamic>::Zero(6, nbContacts_),
109 Eigen::Matrix<value_type, 6, Eigen::Dynamic>::Zero(
110 6, nbContacts_ * robot->numberDof())),
111 primal_(vector_t::Zero(nbContacts_)),
112 dual_(vector_t::Zero(nbContacts_)) {
113 VectorMap_t zeros(Zeros, nbContacts_);
114 zeros.setZero();
115
116 qpOASES::Options options;
117 qp_.setOptions(options);
118
119 qp_.setPrintLevel(qpOASES::PL_NONE);
120 phi_.setSize(2, nbContacts_);
121 Traits<PointCom>::Ptr_t OG = PointCom::create(com);
122 std::size_t col = 0;
123 for (std::size_t i = 0; i < contacts.size(); ++i) {
124 Traits<VectorInJoint>::Ptr_t n = VectorInJoint::create(
125 contacts[i].joint, contacts[i].normal, robot->numberDof());
126 for (std::size_t j = 0; j < contacts[i].points.size(); ++j) {
127 Traits<PointInJoint>::Ptr_t OP = PointInJoint::create(
128 contacts[i].joint, contacts[i].points[j], robot->numberDof());
129
130 phi_(0, col) = n;
131 phi_(1, col) = (OG - OP) ^ n;
132 col++;
133 }
134 }
135 }
136
137 QPStaticStabilityPtr_t QPStaticStability::create(
138 const std::string& name, const DevicePtr_t& robot,
139 const Contacts_t& contacts, const CenterOfMassComputationPtr_t& com) {
140 return QPStaticStabilityPtr_t(
141 new QPStaticStability(name, robot, contacts, com));
142 }
143
144 QPStaticStabilityPtr_t QPStaticStability::create(
145 const std::string& name, const DevicePtr_t& robot,
146 const std::vector<ForceData>& contacts,
147 const CenterOfMassComputationPtr_t& com) {
148 return QPStaticStabilityPtr_t(
149 new QPStaticStability(name, robot, contacts, com));
150 }
151
152 QPStaticStabilityPtr_t QPStaticStability::create(
153 const DevicePtr_t& robot, const Contacts_t& contacts,
154 const CenterOfMassComputationPtr_t& com) {
155 return create("QPStaticStability", robot, contacts, com);
156 }
157
158 void QPStaticStability::impl_compute(LiegroupElementRef result,
159 ConfigurationIn_t argument) const {
160 robot_->currentConfiguration(argument);
161 robot_->computeForwardKinematics(pinocchio::JOINT_POSITION);
162
163 phi_.invalidate();
164 phi_.computeValue(argument);
165 // phi_.computeSVD (argument);
166
167 qpOASES::returnValue ret = solveQP(result.vector());
168 if (ret != qpOASES::SUCCESSFUL_RETURN) {
169 hppDout(error, "QP could not be solved. Error is " << ret);
170 }
171 if (!checkQPSol()) {
172 hppDout(error, "QP solution does not satisfies the constraints");
173 }
174 }
175
176 void QPStaticStability::impl_jacobian(matrixOut_t jacobian,
177 ConfigurationIn_t argument) const {
178 robot_->currentConfiguration(argument);
179 robot_->computeForwardKinematics(pinocchio::JOINT_POSITION |
180 pinocchio::JACOBIAN);
181
182 phi_.invalidate();
183 // phi_.computeSVD (argument);
184 phi_.computeJacobian(argument);
185
186 vector_t res(1);
187 qpOASES::returnValue ret = solveQP(res);
188 if (ret != qpOASES::SUCCESSFUL_RETURN) {
189 hppDout(error, "QP could not be solved. Error is " << ret);
190 }
191 if (!checkQPSol()) {
192 hppDout(error, "QP solution does not satisfies the constraints");
193 }
194 if (!checkStrictComplementarity()) {
195 hppDout(error,
196 "Strict complementary slackness does not hold. "
197 "Jacobian WILL be wrong.");
198 }
199
200 // TODO preallocate this.
201 matrix_t JT_phi_F(nbContacts_, robot_->numberDof());
202 matrix_t J_F(6, robot_->numberDof());
203 phi_.jacobianTransposeTimes(argument, phi_.value() * primal_, JT_phi_F);
204 phi_.jacobianTimes(argument, primal_, J_F);
205
206 jacobian = 0.5 * primal_.transpose() * JT_phi_F +
207 (0.5 * phi_.value() * primal_ + Gravity).transpose() * J_F;
208 }
209
210 inline qpOASES::returnValue QPStaticStability::solveQP(
211 vectorOut_t result) const {
212 // TODO: Use the SVD to solve a smaller quadratic problem
213 // Try to find a positive solution
214 using qpOASES::SUCCESSFUL_RETURN;
215
216 H_ = phi_.value().transpose() * phi_.value();
217 G_ = phi_.value().transpose() * Gravity;
218
219 qpOASES::int_t nwsr = nWSR;
220 qp_.reset();
221 qp_.setHessianType(qpOASES::HST_SEMIDEF);
222 qpOASES::returnValue ret;
223 ret = qp_.init(H_.data(), G_.data(), Zeros, 0, nwsr, 0);
224 qp_.getPrimalSolution(primal_.data());
225 qp_.getDualSolution(dual_.data());
226 result[0] = 2 * qp_.getObjVal() + MinusGravity.squaredNorm();
227 return ret;
228 }
229
230 bool QPStaticStability::checkQPSol() const {
231 return (primal_.array() >= -1e-8).all();
232 }
233
234 bool QPStaticStability::checkStrictComplementarity() const {
235 qpOASES::real_t eps = qp_.getOptions().boundTolerance;
236 return ((primal_.array() > eps && dual_.cwiseAbs().array() <= eps) ||
237 (dual_.array() > eps && primal_.cwiseAbs().array() <= eps))
238 .all();
239 }
240 } // namespace constraints
241 } // namespace hpp
242