6 #include <dynamic-graph/factory.h>
8 #include <sot/core/debug.hh>
11 #include <tsid/utils/stop-watch.hpp>
16 namespace dg = ::dynamicgraph;
18 using namespace dg::command;
20 using namespace Eigen;
22 using namespace tsid::math;
23 using namespace tsid::tasks;
24 using namespace dg::sot;
26 #define PROFILE_DQ_DES_COMPUTATION "Admittance control computation"
28 #define REF_FORCE_SIGNALS m_fRightFootRefSIN << m_fLeftFootRefSIN
30 #define FORCE_SIGNALS \
31 m_fRightFootSIN << m_fLeftFootSIN << m_fRightFootFilteredSIN \
32 << m_fLeftFootFilteredSIN
34 #define GAIN_SIGNALS \
35 m_kp_forceSIN << m_ki_forceSIN << m_kp_velSIN << m_ki_velSIN \
36 << m_force_integral_saturationSIN \
37 << m_force_integral_deadzoneSIN
38 #define STATE_SIGNALS m_encodersSIN << m_jointsVelocitiesSIN
40 #define INPUT_SIGNALS \
41 STATE_SIGNALS << REF_FORCE_SIGNALS << FORCE_SIGNALS << GAIN_SIGNALS \
42 << m_controlledJointsSIN << m_dampingSIN
44 #define DES_VEL_SIGNALS \
45 m_vDesRightFootSOUT << m_vDesLeftFootSOUT //<< m_fRightHandErrorSOUT <<
47 #define OUTPUT_SIGNALS m_uSOUT << m_dqDesSOUT << DES_VEL_SIGNALS
53 typedef Eigen::Matrix<double, 3, 1>
Vector3;
54 typedef Eigen::Matrix<double, 6, 1>
Vector6;
57 "AdmittanceController");
65 CONSTRUCT_SIGNAL_IN(jointsVelocities,
dynamicgraph::Vector),
70 CONSTRUCT_SIGNAL_IN(force_integral_saturation,
dynamicgraph::Vector),
71 CONSTRUCT_SIGNAL_IN(force_integral_deadzone,
dynamicgraph::Vector),
72 CONSTRUCT_SIGNAL_IN(fRightFootRef,
dynamicgraph::Vector),
76 CONSTRUCT_SIGNAL_IN(fRightFootFiltered,
dynamicgraph::Vector),
77 CONSTRUCT_SIGNAL_IN(fLeftFootFiltered,
dynamicgraph::Vector),
78 CONSTRUCT_SIGNAL_IN(controlledJoints,
dynamicgraph::Vector),
89 CONSTRUCT_SIGNAL_OUT(vDesRightFoot,
dynamicgraph::Vector,
90 m_fRightFootSIN << m_fRightFootFilteredSIN
94 m_fLeftFootSIN << m_fLeftFootFilteredSIN
104 m_initSucceeded(false),
105 m_useJacobianTranspose(true) {
113 "getUseJacobianTranspose",
115 docDirectGetter(
"If true it uses the Jacobian "
116 "transpose, otherwise the pseudoinverse",
119 "setUseJacobianTranspose",
121 docDirectSetter(
"If true it uses the Jacobian "
122 "transpose, otherwise the pseudoinverse",
126 docCommandVoid2(
"Initialize the entity.",
127 "Time period in seconds (double)",
128 "Robot name (string)")));
132 if (dt <= 0.0)
return SEND_MSG(
"Timestep must be positive", MSG_TYPE_ERROR);
133 if (!m_encodersSIN.isPlugged())
134 return SEND_MSG(
"Init failed: signal encoders is not plugged",
136 if (!m_jointsVelocitiesSIN.isPlugged())
137 return SEND_MSG(
"Init failed: signal jointsVelocities is not plugged",
139 if (!m_controlledJointsSIN.isPlugged())
140 return SEND_MSG(
"Init failed: signal controlledJoints is not plugged",
147 std::string localName(robotRef);
148 if (isNameInRobotUtil(localName))
152 "You should have an entity controller manager initialized before",
156 vector<string> package_dirs;
158 new robots::RobotWrapper(
m_robot_util->m_urdf_filename, package_dirs,
159 pinocchio::JointModelFreeFlyer());
181 }
catch (
const std::exception& e) {
182 std::cout << e.what();
184 "Init failed: Could load URDF :" +
m_robot_util->m_urdf_filename,
194 if (!m_initSucceeded) {
195 SEND_WARNING_STREAM_MSG(
"Cannot compute signal u before initialization!");
199 const Vector& dqDes = m_dqDesSOUT(iter);
200 const Vector& q = m_encodersSIN(iter);
201 const Vector& dq = m_jointsVelocitiesSIN(iter);
202 const Vector& kp = m_kp_velSIN(iter);
203 const Vector& ki = m_ki_velSIN(iter);
211 m_dq_fd = (q - m_qPrev) / m_dt;
214 m_dqErrIntegral += m_dt * ki.cwiseProduct(dqDes - m_dq_fd);
215 s = kp.cwiseProduct(dqDes - dq) + m_dqErrIntegral;
221 if (!m_initSucceeded) {
222 SEND_WARNING_STREAM_MSG(
223 "Cannot compute signal dqDes before initialization!");
229 const dg::sot::Vector6d v_des_LF = m_vDesLeftFootSOUT(iter);
230 const dg::sot::Vector6d v_des_RF = m_vDesRightFootSOUT(iter);
231 const Vector& q_sot = m_encodersSIN(iter);
237 assert(q_sot.size() == m_nj &&
"Unexpected size of signal encoder");
240 m_robot_util->joints_sot_to_urdf(q_sot, m_q_urdf.tail(m_nj));
241 m_robot->computeAllTerms(*m_data, m_q_urdf, m_v_urdf);
242 m_robot->frameJacobianLocal(*m_data, m_frame_id_rf, m_J_RF);
243 m_robot->frameJacobianLocal(*m_data, m_frame_id_lf, m_J_LF);
253 if (m_useJacobianTranspose) {
254 m_dq_des_urdf = m_J_RF.rightCols(m_nj).transpose() * v_des_RF;
255 m_dq_des_urdf += m_J_LF.rightCols(m_nj).transpose() * v_des_LF;
257 m_J_RF_QR.compute(m_J_RF.rightCols(m_nj));
258 m_J_LF_QR.compute(m_J_LF.rightCols(m_nj));
260 m_dq_des_urdf = m_J_RF_QR.solve(v_des_RF);
261 m_dq_des_urdf += m_J_LF_QR.solve(v_des_LF);
264 if (s.size() != m_nj) s.resize(m_nj);
266 m_robot_util->joints_urdf_to_sot(m_dq_des_urdf, s);
274 if (!m_initSucceeded) {
275 SEND_MSG(
"Cannot compute signal vDesRightFoot before initialization!",
276 MSG_TYPE_WARNING_STREAM);
279 const Vector6& f = m_fRightFootSIN(iter);
280 const Vector6& f_filt = m_fRightFootFilteredSIN(iter);
281 const Vector6& fRef = m_fRightFootRefSIN(iter);
282 const Vector6d& kp = m_kp_forceSIN(iter);
283 const Vector6d& ki = m_ki_forceSIN(iter);
284 const Vector6d& f_sat = m_force_integral_saturationSIN(iter);
285 const Vector6d& dz = m_force_integral_deadzoneSIN(iter);
287 dg::sot::Vector6d err = fRef - f;
288 dg::sot::Vector6d err_filt = fRef - f_filt;
289 dg::sot::Vector6d v_des = -kp.cwiseProduct(err_filt);
291 for (
int i = 0; i < 6; i++) {
293 m_v_RF_int(i) -= m_dt * ki(i) * (err(i) - dz(i));
294 else if (err(i) < -dz(i))
295 m_v_RF_int(i) -= m_dt * ki(i) * (err(i) + dz(i));
299 bool saturating =
false;
300 for (
int i = 0; i < 6; i++) {
301 if (m_v_RF_int(i) > f_sat(i)) {
303 m_v_RF_int(i) = f_sat(i);
304 }
else if (m_v_RF_int(i) < -f_sat(i)) {
306 m_v_RF_int(i) = -f_sat(i);
310 SEND_INFO_STREAM_MSG(
"Saturate m_v_RF_int integral: " +
311 toString(m_v_RF_int.transpose()));
312 s = v_des + m_v_RF_int;
317 if (!m_initSucceeded) {
318 SEND_MSG(
"Cannot compute signal vDesLeftFoot before initialization!",
319 MSG_TYPE_WARNING_STREAM);
322 const Vector6& f = m_fLeftFootSIN(iter);
323 const Vector6& f_filt = m_fLeftFootFilteredSIN(iter);
324 const Vector6& fRef = m_fLeftFootRefSIN(iter);
325 const Vector6d& kp = m_kp_forceSIN(iter);
326 const Vector6d& ki = m_ki_forceSIN(iter);
327 const Vector6d& f_sat = m_force_integral_saturationSIN(iter);
328 const Vector6d& dz = m_force_integral_deadzoneSIN(iter);
330 dg::sot::Vector6d err = fRef - f;
331 dg::sot::Vector6d err_filt = fRef - f_filt;
332 dg::sot::Vector6d v_des = -kp.cwiseProduct(err_filt);
334 for (
int i = 0; i < 6; i++) {
336 m_v_LF_int(i) -= m_dt * ki(i) * (err(i) - dz(i));
337 else if (err(i) < -dz(i))
338 m_v_LF_int(i) -= m_dt * ki(i) * (err(i) + dz(i));
342 bool saturating =
false;
343 for (
int i = 0; i < 6; i++) {
344 if (m_v_LF_int(i) > f_sat(i)) {
346 m_v_LF_int(i) = f_sat(i);
347 }
else if (m_v_LF_int(i) < -f_sat(i)) {
349 m_v_LF_int(i) = -f_sat(i);
353 SEND_INFO_STREAM_MSG(
"Saturate m_v_LF_int integral: " +
354 toString(m_v_LF_int.transpose()));
355 s = v_des + m_v_LF_int;
411 os <<
"AdmittanceController " << getName();
413 getProfiler().report_all(3, os);
414 }
catch (ExceptionSignal e) {
421 eigen_assert(A.computeU() && A.computeV() &&
422 "svdSolveWithDamping() requires both unitaries U and V to be "
423 "computed (thin unitaries suffice).");
424 assert(A.rows() == b.size());
427 VectorXd tmp(A.cols());
428 int nzsv =
static_cast<int>(A.nonzeroSingularValues());
429 tmp.noalias() = A.matrixU().leftCols(nzsv).adjoint() * b;
431 double sv, d2 = damping * damping;
432 for (
int i = 0; i < nzsv; i++) {
433 sv = A.singularValues()(i);
434 tmp(i) *= sv / (sv * sv + d2);
437 VectorXd res = A.matrixV().leftCols(nzsv) * tmp;