1 |
|
|
// |
2 |
|
|
// Copyright (c) 2014 CNRS |
3 |
|
|
// Authors: Mylene Campana |
4 |
|
|
// |
5 |
|
|
// This file is part of hpp-core |
6 |
|
|
// hpp-core is free software: you can redistribute it |
7 |
|
|
// and/or modify it under the terms of the GNU Lesser General Public |
8 |
|
|
// License as published by the Free Software Foundation, either version |
9 |
|
|
// 3 of the License, or (at your option) any later version. |
10 |
|
|
// |
11 |
|
|
// hpp-core is distributed in the hope that it will be |
12 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
13 |
|
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 |
|
|
// General Lesser Public License for more details. You should have |
15 |
|
|
// received a copy of the GNU Lesser General Public License along with |
16 |
|
|
// hpp-core If not, see |
17 |
|
|
// <http://www.gnu.org/licenses/>. |
18 |
|
|
|
19 |
|
|
#include <hpp/core/config-projector.hh> |
20 |
|
|
#include <hpp/core/straight-path.hh> |
21 |
|
|
#include <hpp/pinocchio/configuration.hh> |
22 |
|
|
#include <hpp/pinocchio/device.hh> |
23 |
|
|
#include <hpp/pinocchio/joint.hh> |
24 |
|
|
#include <hpp/rbprm/planner/parabola-path.hh> |
25 |
|
|
#include <hpp/util/debug.hh> |
26 |
|
|
|
27 |
|
|
namespace hpp { |
28 |
|
|
namespace rbprm { |
29 |
|
|
using core::interval_t; |
30 |
|
|
using core::size_type; |
31 |
|
|
using core::value_type; |
32 |
|
|
using core::vector_t; |
33 |
|
|
using pinocchio::displayConfig; |
34 |
|
|
|
35 |
|
|
ParabolaPath::ParabolaPath(const core::DevicePtr_t& device, |
36 |
|
|
core::ConfigurationIn_t init, |
37 |
|
|
core::ConfigurationIn_t end, value_type length, |
38 |
|
|
vector_t coefs) |
39 |
|
|
: parent_t(interval_t(0, length), device->configSize(), |
40 |
|
|
device->numberDof()), |
41 |
|
|
V0_(vector_t(3)), |
42 |
|
|
Vimp_(vector_t(3)), |
43 |
|
|
device_(device), |
44 |
|
|
initial_(init), |
45 |
|
|
end_(end), |
46 |
|
|
coefficients_(vector_t(coefs.size())), |
47 |
|
|
length_(length) |
48 |
|
|
|
49 |
|
|
{ |
50 |
|
|
assert(device); |
51 |
|
|
coefficients(coefs); |
52 |
|
|
initialROMnames_.reserve(10); |
53 |
|
|
endROMnames_.reserve(10); |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
ParabolaPath::ParabolaPath(const core::DevicePtr_t& device, |
57 |
|
|
core::ConfigurationIn_t init, |
58 |
|
|
core::ConfigurationIn_t end, value_type length, |
59 |
|
|
vector_t coefs, vector_t V0, vector_t Vimp, |
60 |
|
|
std::vector<std::string> initialROMnames, |
61 |
|
|
std::vector<std::string> endROMnames) |
62 |
|
|
: parent_t(interval_t(0, length), device->configSize(), |
63 |
|
|
device->numberDof()), |
64 |
|
|
V0_(V0), |
65 |
|
|
Vimp_(Vimp), |
66 |
|
|
initialROMnames_(initialROMnames), |
67 |
|
|
endROMnames_(endROMnames), |
68 |
|
|
device_(device), |
69 |
|
|
initial_(init), |
70 |
|
|
end_(end), |
71 |
|
|
coefficients_(vector_t(coefs.size())), |
72 |
|
|
length_(length) { |
73 |
|
|
assert(device); |
74 |
|
|
coefficients(coefs); |
75 |
|
|
hppDout(info, "V0_= " << V0_.transpose() << " Vimp_= " << Vimp_.transpose()); |
76 |
|
|
hppDout(info, "initialROMnames size= " << initialROMnames_.size()); |
77 |
|
|
} |
78 |
|
|
|
79 |
|
|
ParabolaPath::ParabolaPath(const ParabolaPath& path) |
80 |
|
|
: parent_t(path), |
81 |
|
|
V0_(path.V0_), |
82 |
|
|
Vimp_(path.Vimp_), |
83 |
|
|
initialROMnames_(path.initialROMnames_), |
84 |
|
|
endROMnames_(path.endROMnames_), |
85 |
|
|
device_(path.device_), |
86 |
|
|
initial_(path.initial_), |
87 |
|
|
end_(path.end_), |
88 |
|
|
coefficients_(path.coefficients_), |
89 |
|
|
length_(path.length_) { |
90 |
|
|
hppDout(info, "V0_= " << V0_.transpose() << " Vimp_= " << Vimp_.transpose()); |
91 |
|
|
hppDout(info, "initialROMnames size= " << initialROMnames_.size()); |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
bool ParabolaPath::impl_compute(core::ConfigurationOut_t result, |
95 |
|
|
value_type param) const { |
96 |
|
|
if (param == 0 || initial_(0) == end_(0)) { |
97 |
|
|
result = initial_; |
98 |
|
|
return true; |
99 |
|
|
} |
100 |
|
|
if (param >= length_) { |
101 |
|
|
result = end_; |
102 |
|
|
return true; |
103 |
|
|
} |
104 |
|
|
|
105 |
|
|
const size_type nbConfig = device_->configSize(); |
106 |
|
|
const size_type ecsDim = device_->extraConfigSpace().dimension(); |
107 |
|
|
// param = x_theta |
108 |
|
|
const value_type u = param / length_; |
109 |
|
|
const value_type theta = coefficients_(3); |
110 |
|
|
/* const value_type x_theta_max = - 0.5 * |
111 |
|
|
coefficients_ (1) / coefficients_ (0); |
112 |
|
|
const value_type x_theta_initial = cos(theta)*initial_ (0) + |
113 |
|
|
sin(theta)*initial_ (1); |
114 |
|
|
const value_type x_theta_end = cos(theta)*end_ (0) + |
115 |
|
|
sin(theta)*end_ (1); |
116 |
|
|
const bool tanThetaNotDefined = (theta < M_PI/2 + 1e-2 && theta > M_PI/2 - |
117 |
|
|
1e-2) || (theta > -M_PI/2 - 1e-2 && theta < -M_PI/2 + 1e-2); |
118 |
|
|
*/ |
119 |
|
|
result(0) = initial_(0) + u * length_ * cos(theta); |
120 |
|
|
result(1) = initial_(1) + u * length_ * sin(theta); |
121 |
|
|
const value_type x_theta = cos(theta) * result(0) + sin(theta) * result(1); |
122 |
|
|
result(2) = coefficients_(0) * x_theta * x_theta + |
123 |
|
|
coefficients_(1) * x_theta + coefficients_(2); |
124 |
|
|
|
125 |
|
|
pinocchio::interpolate(device_, initial_, end_, u, result); |
126 |
|
|
/* Quaternions interpolation */ |
127 |
|
|
/*const core::JointPtr_t SO3joint = device_->getJointByName |
128 |
|
|
("base_joint_SO3"); const std::size_t rank = SO3joint->rankInConfiguration (); |
129 |
|
|
const core::size_type dimSO3 = SO3joint->configSize (); |
130 |
|
|
SO3joint->configuration ()->interpolate |
131 |
|
|
(initial_, end_, u, rank, result); |
132 |
|
|
|
133 |
|
|
// if robot-trunk has internal DoF (except freeflyer ones) |
134 |
|
|
// then linear interpolation on them |
135 |
|
|
const std::size_t freeflyerDim = 3 + dimSO3; |
136 |
|
|
const bool hasInternalDof = nbConfig > ecsDim + freeflyerDim; |
137 |
|
|
if (hasInternalDof) { |
138 |
|
|
for (core::size_type i = freeflyerDim; i<nbConfig-ecsDim; i++) { |
139 |
|
|
result (i) = (1 - u) * initial_ (i) + u * end_ (i); |
140 |
|
|
} |
141 |
|
|
}*/ |
142 |
|
|
|
143 |
|
|
/* Set to zero extra-configs (only on path, not on extremities */ |
144 |
|
|
const std::size_t indexECS = nbConfig - ecsDim; |
145 |
|
|
for (size_type i = 0; i < ecsDim; i++) result(indexECS + i) = 0; |
146 |
|
|
return true; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
core::PathPtr_t ParabolaPath::extract(const interval_t& subInterval) const { |
150 |
|
|
hppDout(error, "path extract is not recommended on parabola path"); |
151 |
|
|
bool success; |
152 |
|
|
core::Configuration_t q1((*this)(subInterval.first, success)); // straight |
153 |
|
|
core::Configuration_t q2((*this)(subInterval.second, success)); // straight |
154 |
|
|
ParabolaPathPtr_t result = rbprm::ParabolaPath::create( |
155 |
|
|
device_, q1, q2, computeLength(q1, q2), coefficients_, V0_, Vimp_, |
156 |
|
|
initialROMnames_, endROMnames_); |
157 |
|
|
hppDout(info, "initialROMnames size= " << (*result).initialROMnames_.size()); |
158 |
|
|
return result; |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
core::PathPtr_t ParabolaPath::reverse() const { |
162 |
|
|
hppDout(notice, " ~ reverse path parabola !!!!!!!!!!!!!!!!!!!!!!"); |
163 |
|
|
bool success; |
164 |
|
|
core::Configuration_t q1((*this)(length_, success)); |
165 |
|
|
core::Configuration_t q2((*this)(0, success)); |
166 |
|
|
ParabolaPathPtr_t result = |
167 |
|
|
ParabolaPath::create(device_, q1, q2, length_, coefficients_, Vimp_, V0_, |
168 |
|
|
endROMnames_, initialROMnames_); |
169 |
|
|
hppDout(info, "V0_= " << V0_.transpose() << " Vimp_= " << Vimp_.transpose()); |
170 |
|
|
hppDout(info, "result V0_= " << (*result).V0_.transpose() << " result Vimp_= " |
171 |
|
|
<< (*result).Vimp_.transpose()); |
172 |
|
|
hppDout(info, |
173 |
|
|
"path->initialROMnames size= " << (*result).initialROMnames_.size()); |
174 |
|
|
hppDout(info, |
175 |
|
|
"this->initialROMnames size= " << (*this).initialROMnames_.size()); |
176 |
|
|
hppDout(info, "result->initialROMnames size= " |
177 |
|
|
<< (*result).initialROMnames_.size()); |
178 |
|
|
return result; |
179 |
|
|
} |
180 |
|
|
|
181 |
|
|
core::DevicePtr_t ParabolaPath::device() const { return device_; } |
182 |
|
|
|
183 |
|
|
/* value_type ParabolaPath::computeLength |
184 |
|
|
(const core::ConfigurationIn_t q1, const core::ConfigurationIn_t q2) const { |
185 |
|
|
const int N = 6; // number -1 of interval sub-divisions |
186 |
|
|
// for N = 4, computation error ~= 1e-5. |
187 |
|
|
// for N = 20, computation error ~= 1e-11. |
188 |
|
|
value_type length = 0; |
189 |
|
|
const value_type theta = coefficients_ (3); |
190 |
|
|
value_type x1 = cos(theta) * q1 (0) + sin(theta) * q1 (1); // x_theta_0 |
191 |
|
|
value_type x2 = cos(theta) * q2 (0) + sin(theta) * q2 (1); // x_theta_imp |
192 |
|
|
hppDout(notice,"xTheta0 = "<<x1 << " , "<<coefficients_[6]<<" xThetaImp = |
193 |
|
|
"<<x2); |
194 |
|
|
|
195 |
|
|
// Define integration bounds |
196 |
|
|
if (x1 > x2) { // re-order integration bounds |
197 |
|
|
const value_type xtmp = x1; |
198 |
|
|
x1 = x2; |
199 |
|
|
x2 = xtmp; |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
const value_type dx = (x2 - x1) / N; // integration step size |
203 |
|
|
for (int i=0; i<N; i++) { |
204 |
|
|
length += dx*( 0.166666667*lengthFunction (x1 + i*dx) |
205 |
|
|
+ 0.666666667*lengthFunction (x1 + (i+0.5)*dx ) |
206 |
|
|
+ 0.166666667*lengthFunction (x1 + (i+1)*dx )); |
207 |
|
|
// apparently, 1/6 and 2/3 are not recognized as floats ... |
208 |
|
|
} |
209 |
|
|
hppDout (notice, "length = " << length); |
210 |
|
|
return length; |
211 |
|
|
}*/ |
212 |
|
|
|
213 |
|
|
// test (pierre) : |
214 |
|
|
value_type ParabolaPath::computeLength(const core::ConfigurationIn_t q1, |
215 |
|
|
const core::ConfigurationIn_t q2) const { |
216 |
|
|
const value_type theta = coefficients_(3); |
217 |
|
|
const value_type X = q2[0] - q1[0]; |
218 |
|
|
const value_type Y = q2[1] - q1[1]; |
219 |
|
|
; |
220 |
|
|
// theta = coef[3] |
221 |
|
|
const value_type X_theta = X * cos(theta) + Y * sin(theta); |
222 |
|
|
return X_theta; |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
// Function equivalent to sqrt( 1 + f'(x)^2 ) |
226 |
|
|
value_type ParabolaPath::lengthFunction(const value_type x) const { |
227 |
|
|
const value_type y = |
228 |
|
|
sqrt(1 + (2 * coefficients_(0) * x + coefficients_(1)) * |
229 |
|
|
(2 * coefficients_(0) * x + coefficients_(1))); |
230 |
|
|
return y; |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
vector_t ParabolaPath::evaluateVelocity(const value_type t) const { |
234 |
|
|
vector_t vel(3); |
235 |
|
|
bool success; |
236 |
|
|
const value_type theta = coefficients_(3); |
237 |
|
|
const value_type alpha = coefficients_(4); |
238 |
|
|
const value_type x_theta_0_dot = coefficients_(5); |
239 |
|
|
const value_type inv_x_theta_0_dot_sq = 1 / (x_theta_0_dot * x_theta_0_dot); |
240 |
|
|
const value_type x_theta_0 = coefficients_(6); |
241 |
|
|
const core::Configuration_t q = (*this)(t, success); |
242 |
|
|
const value_type x_theta = q[0] * cos(theta) + q[1] * sin(theta); |
243 |
|
|
vel[0] = x_theta_0_dot * cos(theta); |
244 |
|
|
vel[1] = x_theta_0_dot * sin(theta); |
245 |
|
|
vel[2] = x_theta_0_dot * |
246 |
|
|
(-9.81 * (x_theta - x_theta_0) * inv_x_theta_0_dot_sq + tan(alpha)); |
247 |
|
|
return vel; |
248 |
|
|
} |
249 |
|
|
|
250 |
|
|
} // namespace rbprm |
251 |
|
|
} // namespace hpp |