00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <opspace/task_library.hpp>
00027 #include <opspace/TypeIOTGCursor.hpp>
00028
00029 using jspace::pretty_print;
00030
00031 namespace opspace {
00032
00033
00034 PDTask::
00035 PDTask(std::string const & name,
00036 saturation_policy_t saturation_policy)
00037 : Task(name),
00038 saturation_policy_(saturation_policy),
00039 initialized_(false)
00040 {
00041 declareParameter("goalpos", &goalpos_);
00042 declareParameter("goalvel", &goalvel_);
00043 declareParameter("errpos", &errpos_);
00044 declareParameter("errvel", &errvel_);
00045 declareParameter("kp", &kp_, PARAMETER_FLAG_NOLOG);
00046 declareParameter("kd", &kd_, PARAMETER_FLAG_NOLOG);
00047 declareParameter("maxvel", &maxvel_, PARAMETER_FLAG_NOLOG);
00048 }
00049
00050
00051 Status PDTask::
00052 check(Vector const * param, Vector const & value) const
00053 {
00054 if ((param == &errpos_) || (param == &errvel_)) {
00055 return Status(false, "error signals are read-only");
00056 }
00057 if ((param == &kp_) || (param == &kd_) || (param == &maxvel_)) {
00058 if (SATURATION_NORM == saturation_policy_) {
00059 if (1 != value.rows()) {
00060 return Status(false, "SATURATION_NORM requires one-dimensional gains and limits");
00061 }
00062 }
00063 for (size_t ii(0); ii < value.rows(); ++ii) {
00064 if (0 > value[ii]) {
00065 return Status(false, "gains and limits must be >= 0");
00066 }
00067 }
00068 }
00069 if (initialized_) {
00070 if (SATURATION_NORM != saturation_policy_) {
00071 if ((param == &kp_) || (param == &kd_) || (param == &maxvel_)) {
00072 if (goalpos_.rows() != value.rows()) {
00073 return Status(false, "invalid dimension");
00074 }
00075 }
00076 }
00077 if ((param == &goalpos_) || (param == &goalvel_)) {
00078 if (goalpos_.rows() != value.rows()) {
00079 return Status(false, "invalid dimension");
00080 }
00081 }
00082 }
00083 return Status();
00084 }
00085
00086
00087 Status PDTask::
00088 initPDTask(Vector const & initpos)
00089 {
00090 int const ndim(initpos.rows());
00091
00092 if (SATURATION_NORM == saturation_policy_) {
00093 if (1 != kp_.rows()) {
00094 return Status(false, "kp must be one-dimensional for SATURATION_NORM policy");
00095 }
00096 if (1 != kd_.rows()) {
00097 return Status(false, "kd must be one-dimensional for SATURATION_NORM policy");
00098 }
00099 if (1 != maxvel_.rows()) {
00100 return Status(false, "maxvel must be one-dimensional for SATURATION_NORM policy");
00101 }
00102 }
00103 else {
00104 if (ndim != kp_.rows()) {
00105 if ((ndim != 1) && (1 == kp_.rows())) {
00106 kp_ = kp_[0] * Vector::Ones(ndim);
00107 }
00108 else {
00109 return Status(false, "invalid kp dimension");
00110 }
00111 }
00112 if (ndim != kd_.rows()) {
00113 if ((ndim != 1) && (1 == kd_.rows())) {
00114 kd_ = kd_[0] * Vector::Ones(ndim);
00115 }
00116 else {
00117 return Status(false, "invalid kd dimension");
00118 }
00119 }
00120 if (ndim != maxvel_.rows()) {
00121 if ((ndim != 1) && (1 == maxvel_.rows())) {
00122 maxvel_ = maxvel_[0] * Vector::Ones(ndim);
00123 }
00124 else {
00125 return Status(false, "invalid maxvel dimension");
00126 }
00127 }
00128 }
00129
00130 goalpos_ = initpos;
00131 goalvel_ = Vector::Zero(ndim);
00132 errpos_ = Vector::Zero(ndim);
00133 errvel_ = Vector::Zero(ndim);
00134 initialized_ = true;
00135
00136 Status ok;
00137 return ok;
00138 }
00139
00140
00141 Status PDTask::
00142 computePDCommand(Vector const & curpos,
00143 Vector const & curvel,
00144 Vector & command)
00145 {
00146 Status st;
00147 if ( ! initialized_) {
00148 st.ok = false;
00149 st.errstr = "not initialized";
00150 return st;
00151 }
00152
00153 errpos_ = goalpos_ - curpos;
00154 errvel_ = goalvel_ - curvel;
00155
00156 if (SATURATION_NORM == saturation_policy_) {
00157 command = kp_[0] * errpos_;
00158 if ((maxvel_[0] > 1e-4) && (kd_[0] > 1e-4)) {
00159 double const sat(command.norm() / maxvel_[0] / kd_[0]);
00160 if (sat > 1.0) {
00161 command /= sat;
00162 }
00163 }
00164 command += kd_[0] * errvel_;
00165 return st;
00166 }
00167
00168 command = kp_.cwise() * errpos_;
00169
00170 if (SATURATION_COMPONENT_WISE == saturation_policy_) {
00171 for (int ii(0); ii < command.rows(); ++ii) {
00172 if ((maxvel_[ii] > 1e-4) && (kd_[ii] > 1e-4)) {
00173 double const sat(fabs((command[ii] / maxvel_[ii]) / kd_[ii]));
00174 if (sat > 1.0) {
00175 command[ii] /= sat;
00176 }
00177 }
00178 }
00179 }
00180
00181 else if (SATURATION_MAX_COMPONENT == saturation_policy_) {
00182 double saturation(0.0);
00183 for (int ii(0); ii < command.rows(); ++ii) {
00184 if ((maxvel_[ii] > 1e-4) && (kd_[ii] > 1e-4)) {
00185 double const sat(fabs((command[ii] / maxvel_[ii]) / kd_[ii]));
00186 if (sat > saturation) {
00187 saturation = sat;
00188 }
00189 }
00190 }
00191 if (saturation > 1.0) {
00192 command /= saturation;
00193 }
00194 }
00195
00196
00197
00198
00199
00200 command += kd_.cwise() * errvel_;
00201
00202 return st;
00203 }
00204
00205
00206 DraftPIDTask::
00207 DraftPIDTask(std::string const & name)
00208 : PDTask(name, PDTask::SATURATION_COMPONENT_WISE),
00209 dt_seconds_(-1)
00210 {
00211 declareParameter("dt_seconds", &dt_seconds_, PARAMETER_FLAG_NOLOG);
00212 declareParameter("ki", &ki_, PARAMETER_FLAG_NOLOG);
00213 declareParameter("errsum", &errsum_);
00214 declareParameter("limitpos", &limitpos_, PARAMETER_FLAG_NOLOG);
00215 declareParameter("limitvel", &limitvel_, PARAMETER_FLAG_NOLOG);
00216 declareParameter("triggerpos", &triggerpos_);
00217 }
00218
00219
00220 Status DraftPIDTask::
00221 check(double const * param, double value) const
00222 {
00223 if (param == &dt_seconds_) {
00224 if (0 >= value) {
00225 return Status(false, "dt_seconds must be > 0");
00226 }
00227 }
00228 return Status();
00229 }
00230
00231
00232 Status DraftPIDTask::
00233 check(Vector const * param, Vector const & value) const
00234 {
00235 if (param == &triggerpos_) {
00236 return Status(false, "triggerpos is read-only");
00237 }
00238 if (param == &errsum_) {
00239 return Status(false, "errsum is read-only");
00240 }
00241 if ((param == &ki_) || (param == &limitpos_) || (param == &limitvel_)) {
00242 for (size_t ii(0); ii < value.rows(); ++ii) {
00243 if (0 > value[ii]) {
00244 return Status(false, "gains and limits must be >= 0");
00245 }
00246 }
00247 if (initialized_) {
00248 if (goalpos_.rows() != value.rows()) {
00249 return Status(false, "invalid dimension");
00250 }
00251 }
00252 }
00253 return Status();
00254 }
00255
00256
00257 Status DraftPIDTask::
00258 initDraftPIDTask(Vector const & initpos)
00259 {
00260 Status st(initPDTask(initpos));
00261 if ( ! st) {
00262 return st;
00263 }
00264
00265 if (0 >= dt_seconds_) {
00266 return Status(false, "dt_seconds_ must be > 0");
00267 }
00268 for (size_t ii(0); ii < ki_.rows(); ++ii) {
00269 if (0 > ki_[ii]) {
00270 return Status(false, "ki must be >= 0");
00271 }
00272 }
00273 for (size_t ii(0); ii < limitpos_.rows(); ++ii) {
00274 if (0 > limitpos_[ii]) {
00275 return Status(false, "limitpos must be >= 0");
00276 }
00277 }
00278 for (size_t ii(0); ii < limitvel_.rows(); ++ii) {
00279 if (0 > limitvel_[ii]) {
00280 return Status(false, "limitvel must be >= 0");
00281 }
00282 }
00283
00284 int const ndim(initpos.rows());
00285 if (ndim != ki_.rows()) {
00286 if ((ndim != 1) && (1 == ki_.rows())) {
00287 ki_ = ki_[0] * Vector::Ones(ndim);
00288 }
00289 else {
00290 return Status(false, "invalid ki dimension");
00291 }
00292 }
00293 if (ndim != limitpos_.rows()) {
00294 if ((ndim != 1) && (1 == limitpos_.rows())) {
00295 limitpos_ = limitpos_[0] * Vector::Ones(ndim);
00296 }
00297 else {
00298 return Status(false, "invalid limitpos dimension");
00299 }
00300 }
00301 if (ndim != limitvel_.rows()) {
00302 if ((ndim != 1) && (1 == limitvel_.rows())) {
00303 limitvel_ = limitvel_[0] * Vector::Ones(ndim);
00304 }
00305 else {
00306 return Status(false, "invalid limitvel dimension");
00307 }
00308 }
00309
00310 errsum_ = Vector::Zero(ndim);
00311 triggerpos_ = - 1.0 * Vector::Ones(ndim);
00312
00313 return st;
00314 }
00315
00316
00317 Status DraftPIDTask::
00318 computeDraftPIDCommand(Vector const & curpos,
00319 Vector const & curvel,
00320 Vector & command)
00321 {
00322 Status st(computePDCommand(curpos, curvel, command));
00323 if ( ! st) {
00324 return st;
00325 }
00326
00327
00328
00329
00330 for (int ii(0); ii < triggerpos_.rows(); ++ii) {
00331 if (triggerpos_[ii] > 0) {
00332
00333 if (fabs(errpos_[ii]) > triggerpos_[ii]) {
00334
00335 triggerpos_[ii] = -1;
00336 }
00337 else if (fabs(errvel_[ii]) > 2.0 * limitvel_[ii]) {
00338
00339 triggerpos_[ii] = -1;
00340 }
00341
00342 }
00343 else {
00344
00345 if ((fabs(errpos_[ii]) < limitpos_[ii])
00346 && (fabs(errvel_[ii]) < limitvel_[ii])) {
00347
00348 triggerpos_[ii] = 2.0 * fabs(errpos_[ii]);
00349 errsum_[ii] = 0;
00350 }
00351 }
00352 }
00353
00354
00355 for (int ii(0); ii < triggerpos_.rows(); ++ii) {
00356 if (triggerpos_[ii] > 0) {
00357 errsum_[ii] += errpos_[ii] * dt_seconds_;
00358 command[ii] += ki_[ii] * errsum_[ii];
00359 }
00360 }
00361
00362 return st;
00363 }
00364
00365
00366 Status DraftPIDTask::
00367 init(Model const & model)
00368 {
00369 jacobian_ = Matrix::Identity(model.getNDOF(), model.getNDOF());
00370 actual_ = model.getState().position_;
00371 return initDraftPIDTask(model.getState().position_);
00372 }
00373
00374
00375 Status DraftPIDTask::
00376 update(Model const & model)
00377 {
00378 actual_ = model.getState().position_;
00379 return computeDraftPIDCommand(actual_,
00380 model.getState().velocity_,
00381 command_);
00382 }
00383
00384
00385 void DraftPIDTask::
00386 dbg(std::ostream & os,
00387 std::string const & title,
00388 std::string const & prefix) const
00389 {
00390 if ( ! title.empty()) {
00391 os << title << "\n";
00392 }
00393 os << prefix << "draft PID task: `" << instance_name_ << "'\n";
00394 pretty_print(errpos_, os, prefix + " errpos", prefix + " ");
00395 pretty_print(triggerpos_, os, prefix + " triggerpos", prefix + " ");
00396 pretty_print(ki_, os, prefix + " ki", prefix + " ");
00397 pretty_print(errsum_, os, prefix + " errsum", prefix + " ");
00398 }
00399
00400
00401
00402 CartPosTask::
00403 CartPosTask(std::string const & name)
00404 : PDTask(name, PDTask::SATURATION_NORM),
00405 end_effector_name_(""),
00406 control_point_(Vector::Zero(3)),
00407 end_effector_node_(0)
00408 {
00409 declareParameter("end_effector", &end_effector_name_, PARAMETER_FLAG_NOLOG);
00410 declareParameter("control_point", &control_point_, PARAMETER_FLAG_NOLOG);
00411 }
00412
00413
00414 Status CartPosTask::
00415 init(Model const & model)
00416 {
00417 if (end_effector_name_.empty()) {
00418 return Status(false, "no end_effector");
00419 }
00420 if (3 != control_point_.rows()) {
00421 return Status(false, "control_point must have 3 dimensions");
00422 }
00423 end_effector_node_ = updateActual(model);
00424 if ( ! end_effector_node_) {
00425 return Status(false, "invalid end_effector");
00426 }
00427 return initPDTask(actual_);
00428 }
00429
00430
00431 Status CartPosTask::
00432 update(Model const & model)
00433 {
00434 end_effector_node_ = updateActual(model);
00435 if ( ! end_effector_node_) {
00436 return Status(false, "invalid end_effector");
00437 }
00438
00439 Matrix Jfull;
00440 if ( ! model.computeJacobian(end_effector_node_, actual_[0], actual_[1], actual_[2], Jfull)) {
00441 return Status(false, "failed to compute Jacobian (unsupported joint type?)");
00442 }
00443 jacobian_ = Jfull.block(0, 0, 3, Jfull.cols());
00444
00445 return computePDCommand(actual_,
00446 jacobian_ * model.getState().velocity_,
00447 command_);
00448 }
00449
00450
00451 Status CartPosTask::
00452 check(std::string const * param, std::string const & value) const
00453 {
00454 if (param == &end_effector_name_) {
00455 end_effector_node_ = 0;
00456 }
00457 Status ok;
00458 return ok;
00459 }
00460
00461
00462 taoDNode const * CartPosTask::
00463 updateActual(Model const & model)
00464 {
00465 if ( ! end_effector_node_) {
00466 end_effector_node_ = model.getNodeByName(end_effector_name_);
00467 }
00468 if (end_effector_node_) {
00469 jspace::Transform ee_transform;
00470 model.computeGlobalFrame(end_effector_node_,
00471 control_point_[0],
00472 control_point_[1],
00473 control_point_[2],
00474 ee_transform);
00475 actual_ = ee_transform.translation();
00476 }
00477 return end_effector_node_;
00478 }
00479
00480
00481 JPosTask::
00482 JPosTask(std::string const & name)
00483 : PDTask(name, PDTask::SATURATION_COMPONENT_WISE)
00484 {
00485 }
00486
00487
00488 Status JPosTask::
00489 init(Model const & model)
00490 {
00491 jacobian_ = Matrix::Identity(model.getNDOF(), model.getNDOF());
00492 actual_ = model.getState().position_;
00493 return initPDTask(model.getState().position_);
00494 }
00495
00496
00497 Status JPosTask::
00498 update(Model const & model)
00499 {
00500 actual_ = model.getState().position_;
00501 return computePDCommand(actual_,
00502 model.getState().velocity_,
00503 command_);
00504 }
00505
00506
00507 SelectedJointPostureTask::
00508 SelectedJointPostureTask(std::string const & name)
00509 : Task(name),
00510 kp_(100.0),
00511 kd_(20.0),
00512 initialized_(false)
00513 {
00514 declareParameter("selection", &selection_, PARAMETER_FLAG_NOLOG);
00515 declareParameter("kp", &kp_, PARAMETER_FLAG_NOLOG);
00516 declareParameter("kd", &kd_, PARAMETER_FLAG_NOLOG);
00517 }
00518
00519
00520 Status SelectedJointPostureTask::
00521 init(Model const & model)
00522 {
00523 size_t const ndof(model.getNDOF());
00524 active_joints_.clear();
00525 for (size_t ii(0); ii < selection_.rows(); ++ii) {
00526 if (ii >= ndof) {
00527 break;
00528 }
00529 if (selection_[ii] > 0.5) {
00530 active_joints_.push_back(ii);
00531 }
00532 }
00533 if (active_joints_.empty()) {
00534 return Status(false, "no active joints");
00535 }
00536 size_t const ndim(active_joints_.size());
00537 actual_ = Vector::Zero(ndim);
00538 command_ = Vector::Zero(ndim);
00539 jacobian_ = Matrix::Zero(ndim, ndof);
00540 for (size_t ii(0); ii < ndim; ++ii) {
00541 actual_[ii] = model.getState().position_[active_joints_[ii]];
00542 jacobian_.coeffRef(ii, active_joints_[ii]) = 1.0;
00543 }
00544 initialized_ = true;
00545 Status ok;
00546 return ok;
00547 }
00548
00549
00550 Status SelectedJointPostureTask::
00551 update(Model const & model)
00552 {
00553 Status st;
00554 if ( ! initialized_) {
00555 st.ok = false;
00556 st.errstr = "not initialized";
00557 return st;
00558 }
00559 Vector vel(actual_.rows());
00560 for (size_t ii(0); ii < active_joints_.size(); ++ii) {
00561 actual_[ii] = model.getState().position_[active_joints_[ii]];
00562 vel[ii] = model.getState().velocity_[active_joints_[ii]];
00563 }
00564 command_ = -kp_ * actual_ - kd_ * vel;
00565 return st;
00566 }
00567
00568
00569 Status SelectedJointPostureTask::
00570 check(double const * param, double value) const
00571 {
00572 Status st;
00573 if (((&kp_ == param) && (value < 0)) || ((&kd_ == param) && (value < 0))) {
00574 st.ok = false;
00575 st.errstr = "gains must be >= 0";
00576 }
00577 return st;
00578 }
00579
00580
00581 Status SelectedJointPostureTask::
00582 check(Vector const * param, Vector const & value) const
00583 {
00584 Status st;
00585 if ((&selection_ == param) && (value.rows() == 0)) {
00586 st.ok = false;
00587 st.errstr = "selection must not be empty";
00588 }
00589 return st;
00590 }
00591
00592
00593 TrajectoryTask::
00594 TrajectoryTask(std::string const & name, saturation_policy_t saturation_policy)
00595 : PDTask(name, saturation_policy),
00596 cursor_(0),
00597 dt_seconds_(-1)
00598 {
00599 declareParameter("dt_seconds", &dt_seconds_, PARAMETER_FLAG_NOLOG);
00600 declareParameter("trjgoal", &trjgoal_);
00601 declareParameter("maxacc", &maxacc_, PARAMETER_FLAG_NOLOG);
00602 }
00603
00604
00605 TrajectoryTask::
00606 ~TrajectoryTask()
00607 {
00608 delete cursor_;
00609 }
00610
00611
00612 Status TrajectoryTask::
00613 initTrajectoryTask(Vector const & initpos)
00614 {
00615 Status st(initPDTask(initpos));
00616 if ( ! st) {
00617 return st;
00618 }
00619
00620 if (0 > dt_seconds_) {
00621 st.ok = false;
00622 st.errstr = "you did not (correctly) set dt_seconds";
00623 return st;
00624 }
00625
00626 int const ndim(initpos.rows());
00627 if (ndim != maxacc_.rows()) {
00628 if ((ndim != 1) && (1 == maxacc_.rows())) {
00629 maxacc_ = maxacc_[0] * Vector::Ones(ndim);
00630 }
00631 else {
00632 return Status(false, "invalid maxacc dimension");
00633 }
00634 }
00635
00636 if (cursor_) {
00637 if (cursor_->dt_seconds_ != dt_seconds_) {
00638 delete cursor_;
00639 cursor_ = 0;
00640 }
00641 }
00642 if ( ! cursor_) {
00643 cursor_ = new TypeIOTGCursor(ndim, dt_seconds_);
00644 }
00645
00646 trjgoal_ = initpos;
00647 cursor_->position() = initpos;
00648 cursor_->velocity() = Vector::Zero(ndim);
00649
00650 if (SATURATION_NORM == saturation_policy_) {
00651 qh_maxvel_ = maxvel_[0] * Vector::Ones(ndim);
00652 }
00653 else {
00654 qh_maxvel_ = maxvel_;
00655 }
00656
00657 return st;
00658 }
00659
00660
00661 Status TrajectoryTask::
00662 computeTrajectoryCommand(Vector const & curpos,
00663 Vector const & curvel,
00664 Vector & command)
00665 {
00666 if ( ! cursor_) {
00667 return Status(false, "not initialized");
00668 }
00669
00670 int const trjstatus(cursor_->next(qh_maxvel_, maxacc_, trjgoal_));
00671 if (0 > trjstatus) {
00672 std::ostringstream msg;
00673 msg << "trajectory generation error code "
00674 << trjstatus << ": " << otg_errstr(trjstatus);
00675 return Status(false, msg.str());
00676 }
00677
00678 goalpos_ = cursor_->position();
00679 goalvel_ = cursor_->velocity();
00680
00681 return computePDCommand(curpos, curvel, command);
00682 }
00683
00684
00685 Status TrajectoryTask::
00686 check(double const * param, double value) const
00687 {
00688 if ((param == &dt_seconds_) && (0 >= value)) {
00689 return Status(false, "dt_seconds must be > 0");
00690 }
00691 return Status();
00692 }
00693
00694
00695 Status TrajectoryTask::
00696 check(Vector const * param, Vector const & value) const
00697 {
00698 Status st(PDTask::check(param, value));
00699 if ( ! st) {
00700 return st;
00701 }
00702
00703 if ( ! cursor_) {
00704 return st;
00705 }
00706
00707 if (param == &trjgoal_) {
00708 if (cursor_->ndof_ != value.rows()) {
00709 return Status(false, "invalid goal dimension");
00710 }
00711 }
00712
00713 if (param == &maxacc_) {
00714 if (cursor_->ndof_ != value.rows()) {
00715 return Status(false, "invalid maxacc dimension");
00716 }
00717 for (size_t ii(0); ii < value.rows(); ++ii) {
00718 if (0 > value[ii]) {
00719 return Status(false, "maxacc must be >= 0");
00720 }
00721 }
00722 }
00723
00724 if (param == &maxvel_) {
00725 if (SATURATION_NORM == saturation_policy_) {
00726 qh_maxvel_ = value[0] * Vector::Ones(cursor_->ndof_);
00727 }
00728 else {
00729 qh_maxvel_ = value;
00730 }
00731 }
00732
00733 return st;
00734 }
00735
00736
00737 void TrajectoryTask::
00738 dbg(std::ostream & os,
00739 std::string const & title,
00740 std::string const & prefix) const
00741 {
00742 if ( ! title.empty()) {
00743 os << title << "\n";
00744 }
00745 os << prefix << "trajectory task: `" << instance_name_ << "'\n";
00746 if ( ! cursor_) {
00747 os << prefix << " NOT INITIALIZED\n";
00748 }
00749 else {
00750 pretty_print(actual_, os, prefix + " actual", prefix + " ");
00751 pretty_print(cursor_->position(), os, prefix + " carrot", prefix + " ");
00752 pretty_print(trjgoal_, os, prefix + " trjgoal", prefix + " ");
00753 }
00754 }
00755
00756
00757 CartPosTrjTask::
00758 CartPosTrjTask(std::string const & name)
00759 : TrajectoryTask(name, PDTask::SATURATION_NORM),
00760 end_effector_id_(-1),
00761 control_point_(Vector::Zero(3))
00762 {
00763 declareParameter("end_effector_id", &end_effector_id_, PARAMETER_FLAG_NOLOG);
00764 declareParameter("control_point", &control_point_, PARAMETER_FLAG_NOLOG);
00765 }
00766
00767
00768 Status CartPosTrjTask::
00769 init(Model const & model)
00770 {
00771 if (0 > end_effector_id_) {
00772 return Status(false, "you did not (correctly) set end_effector_id");
00773 }
00774 if (3 != control_point_.rows()) {
00775 return Status(false, "control_point needs to be three dimensional");
00776 }
00777 if (0 == updateActual(model)) {
00778 return Status(false, "updateActual() failed, did you specify a valid end_effector_id?");
00779 }
00780 return initTrajectoryTask(actual_);
00781 }
00782
00783
00784 Status CartPosTrjTask::
00785 update(Model const & model)
00786 {
00787 taoDNode const * ee_node(updateActual(model));
00788 if (0 == ee_node) {
00789 return Status(false, "updateActual() failed, did you specify a valid end_effector_id?");
00790 }
00791
00792 Matrix Jfull;
00793 if ( ! model.computeJacobian(ee_node, actual_[0], actual_[1], actual_[2], Jfull)) {
00794 return Status(false, "failed to compute Jacobian (unsupported joint type?)");
00795 }
00796 jacobian_ = Jfull.block(0, 0, 3, Jfull.cols());
00797
00798 return computeTrajectoryCommand(actual_,
00799 jacobian_ * model.getState().velocity_,
00800 command_);
00801 }
00802
00803
00804 taoDNode const * CartPosTrjTask::
00805 updateActual(Model const & model)
00806 {
00807 taoDNode * ee_node(model.getNode(end_effector_id_));
00808 if (ee_node) {
00809 jspace::Transform ee_transform;
00810 model.computeGlobalFrame(ee_node,
00811 control_point_[0],
00812 control_point_[1],
00813 control_point_[2],
00814 ee_transform);
00815 actual_ = ee_transform.translation();
00816 }
00817 return ee_node;
00818 }
00819
00820
00821 JPosTrjTask::
00822 JPosTrjTask(std::string const & name)
00823 : TrajectoryTask(name, PDTask::SATURATION_COMPONENT_WISE)
00824 {
00825 }
00826
00827
00828 Status JPosTrjTask::
00829 init(Model const & model)
00830 {
00831 jacobian_ = Matrix::Identity(model.getNDOF(), model.getNDOF());
00832 actual_ = model.getState().position_;
00833 return initTrajectoryTask(model.getState().position_);
00834 }
00835
00836
00837 Status JPosTrjTask::
00838 update(Model const & model)
00839 {
00840 actual_ = model.getState().position_;
00841 return computeTrajectoryCommand(actual_, model.getState().velocity_, command_);
00842 }
00843
00844
00845 void JPosTrjTask::
00846 quickSetup(double dt_seconds, double kp, double kd, double maxvel, double maxacc)
00847 {
00848 dt_seconds_ = dt_seconds;
00849 kp_ = kp * Vector::Ones(1);
00850 kd_ = kd * Vector::Ones(1);
00851 maxvel_ = maxvel * Vector::Ones(1);
00852 maxacc_ = maxacc * Vector::Ones(1);
00853 }
00854
00855
00856 JointLimitTask::
00857 JointLimitTask(std::string const & name)
00858 : Task(name),
00859 dt_seconds_(-1)
00860 {
00861 declareParameter("dt_seconds", &dt_seconds_, PARAMETER_FLAG_NOLOG);
00862 declareParameter("upper_stop_deg", &upper_stop_deg_, PARAMETER_FLAG_NOLOG);
00863 declareParameter("upper_trigger_deg", &upper_trigger_deg_, PARAMETER_FLAG_NOLOG);
00864 declareParameter("lower_stop_deg", &lower_stop_deg_, PARAMETER_FLAG_NOLOG);
00865 declareParameter("lower_trigger_deg", &lower_trigger_deg_, PARAMETER_FLAG_NOLOG);
00866 declareParameter("kp", &kp_, PARAMETER_FLAG_NOLOG);
00867 declareParameter("kd", &kd_, PARAMETER_FLAG_NOLOG);
00868 declareParameter("maxvel", &maxvel_, PARAMETER_FLAG_NOLOG);
00869 declareParameter("maxacc", &maxacc_, PARAMETER_FLAG_NOLOG);
00870 }
00871
00872
00873 JointLimitTask::
00874 ~JointLimitTask()
00875 {
00876 for (size_t ii(0); ii < cursor_.size(); ++ii) {
00877 delete cursor_[ii];
00878 }
00879 }
00880
00881
00882 Status JointLimitTask::
00883 check(Vector const * param, Vector const & value) const
00884 {
00885 if ((param == &kp_) || (param == &kd_) || (param == &maxvel_) || (param == &maxacc_)) {
00886 for (size_t ii(0); ii < value.rows(); ++ii) {
00887 if (0 > value[ii]) {
00888 return Status(false, "gains and limits must be >= 0");
00889 }
00890 }
00891 }
00892 if ( ! cursor_.empty()) {
00893 if ((param == &kp_) || (param == &kd_) || (param == &maxvel_) || (param == &maxacc_)) {
00894 if (cursor_.size() != value.rows()) {
00895 return Status(false, "invalid dimension");
00896 }
00897 }
00898 }
00899 return Status();
00900 }
00901
00902
00903 Status JointLimitTask::
00904 check(double const * param, double const & value) const
00905 {
00906 if ((param == &dt_seconds_) && (0 >= value)) {
00907 return Status(false, "dt_seconds must be > 0");
00908 }
00909 return Status();
00910 }
00911
00912
00913 Status JointLimitTask::
00914 init(Model const & model)
00915 {
00916 if (dt_seconds_ <= 0) {
00917 return Status(false, "dt_seconds must be positive");
00918 }
00919 size_t const ndof(model.getNDOF());
00920 if (upper_stop_deg_.rows() != ndof) {
00921 return Status(false, "upper_stop dimension mismatch");
00922 }
00923 if (upper_trigger_deg_.rows() != ndof) {
00924 return Status(false, "upper_trigger dimension mismatch");
00925 }
00926 if (lower_stop_deg_.rows() != ndof) {
00927 return Status(false, "lower_stop dimension mismatch");
00928 }
00929 if (lower_trigger_deg_.rows() != ndof) {
00930 return Status(false, "lower_trigger dimension mismatch");
00931 }
00932 if (maxvel_.rows() != ndof) {
00933 return Status(false, "maxvel dimension mismatch");
00934 }
00935 if (maxacc_.rows() != ndof) {
00936 return Status(false, "maxacc dimension mismatch");
00937 }
00938 if (kp_.rows() != ndof) {
00939 return Status(false, "kp dimension mismatch");
00940 }
00941 if (kd_.rows() != ndof) {
00942 return Status(false, "kd dimension mismatch");
00943 }
00944
00945 upper_stop_ = M_PI * upper_stop_deg_ / 180.0;
00946 upper_trigger_ = M_PI * upper_trigger_deg_ / 180.0;
00947 lower_stop_ = M_PI * lower_stop_deg_ / 180.0;
00948 lower_trigger_ = M_PI * lower_trigger_deg_ / 180.0;
00949
00950 cursor_.assign(ndof, 0);
00951 goal_ = Vector::Zero(ndof);
00952 jacobian_.resize(0, 0);
00953
00954
00955 updateState(model);
00956
00957 Status ok;
00958 return ok;
00959 }
00960
00961
00962 Status JointLimitTask::
00963 update(Model const & model)
00964 {
00965 if (dt_seconds_ <= 0) {
00966 return Status(false, "not initialized");
00967 }
00968
00969 updateState(model);
00970 command_.resize(jacobian_.rows());
00971 size_t task_index(0);
00972
00973 for (size_t joint_index(0); joint_index < cursor_.size(); ++joint_index) {
00974 if (cursor_[joint_index]) {
00975 if (0 > cursor_[joint_index]->next(maxvel_[joint_index], maxacc_[joint_index], goal_[joint_index])) {
00976 return Status(false, "trajectory generation error");
00977 }
00978 double com(kp_[joint_index] * (cursor_[joint_index]->position()[0] - actual_[task_index]));
00979 if ((maxvel_[joint_index] > 1e-4) && (kd_[joint_index] > 1e-4)) {
00980 double const sat(fabs((com / maxvel_[joint_index]) / kd_[joint_index]));
00981 if (sat > 1.0) {
00982 com /= sat;
00983 }
00984 }
00985 command_[task_index]
00986 = com
00987 + kd_[joint_index] * (cursor_[joint_index]->velocity()[0] - model.getState().velocity_[joint_index]);
00988 ++task_index;
00989 }
00990 }
00991
00992 Status ok;
00993 return ok;
00994 }
00995
00996
00997 void JointLimitTask::
00998 updateState(Model const & model)
00999 {
01000 size_t const ndof(model.getNDOF());
01001 Vector const & jpos(model.getState().position_);
01002 bool dimension_changed(false);
01003 size_t task_dimension(0);
01004
01005 for (size_t ii(0); ii < ndof; ++ii) {
01006 if (cursor_[ii]) {
01007 ++task_dimension;
01008 }
01009 else {
01010 if (jpos[ii] > upper_trigger_[ii]) {
01011 ++task_dimension;
01012 dimension_changed = true;
01013 cursor_[ii] = new TypeIOTGCursor(1, dt_seconds_);
01014 cursor_[ii]->position()[0] = jpos[ii];
01015 cursor_[ii]->velocity()[0] = model.getState().velocity_[ii];
01016 goal_[ii] = upper_stop_[ii];
01017 }
01018 else if (jpos[ii] < lower_trigger_[ii]) {
01019 ++task_dimension;
01020 dimension_changed = true;
01021 cursor_[ii] = new TypeIOTGCursor(1, dt_seconds_);
01022 cursor_[ii]->position()[0] = jpos[ii];
01023 cursor_[ii]->velocity()[0] = model.getState().velocity_[ii];
01024 goal_[ii] = lower_stop_[ii];
01025 }
01026 }
01027 }
01028
01029 if (dimension_changed) {
01030 jacobian_ = Matrix::Zero(task_dimension, ndof);
01031 size_t task_index(0);
01032 for (size_t joint_index(0); joint_index < ndof; ++joint_index) {
01033 if (cursor_[joint_index]) {
01034 jacobian_.coeffRef(task_index, joint_index) = 1.0;
01035 ++task_index;
01036 }
01037 }
01038 }
01039
01040 actual_.resize(task_dimension);
01041 size_t task_index(0);
01042 for (size_t joint_index(0); joint_index < ndof; ++joint_index) {
01043 if (cursor_[joint_index]) {
01044 actual_[task_index] = jpos[joint_index];
01045 ++task_index;
01046 }
01047 }
01048 }
01049
01050
01051 void JointLimitTask::
01052 dbg(std::ostream & os,
01053 std::string const & title,
01054 std::string const & prefix) const
01055 {
01056 if ( ! title.empty()) {
01057 os << title << "\n";
01058 }
01059 os << prefix << "joint limit task: `" << instance_name_ << "'\n";
01060 if (cursor_.empty()) {
01061 os << prefix << " NOT INITIALIZED\n";
01062 }
01063 pretty_print(actual_, os, prefix + " actual", prefix + " ");
01064 pretty_print(goal_, os, prefix + " goal", prefix + " ");
01065 pretty_print(jacobian_, os, prefix + " jacobian", prefix + " ");
01066 }
01067
01068
01069 OrientationTask::
01070 OrientationTask(std::string const & name)
01071 : Task(name),
01072 end_effector_id_(-1),
01073 kp_(50),
01074 kd_(5),
01075 maxvel_(0.5)
01076 {
01077 declareParameter("end_effector_id", &end_effector_id_, PARAMETER_FLAG_NOLOG);
01078 declareParameter("kp", &kp_, PARAMETER_FLAG_NOLOG);
01079 declareParameter("kd", &kd_, PARAMETER_FLAG_NOLOG);
01080 declareParameter("maxvel", &maxvel_, PARAMETER_FLAG_NOLOG);
01081 declareParameter("eepos", &eepos_);
01082 }
01083
01084
01085 Status OrientationTask::
01086 init(Model const & model)
01087 {
01088 if (0 > end_effector_id_) {
01089 return Status(false, "I need an end effector ID please");
01090 }
01091 if ( ! updateActual(model)) {
01092 return Status(false, "invalid end effector ID or failure to compute Jacobian");
01093 }
01094 goal_x_ = actual_x_;
01095 goal_y_ = actual_y_;
01096 goal_z_ = actual_z_;
01097 Status ok;
01098 return ok;
01099 }
01100
01101
01102 taoDNode const * OrientationTask::
01103 updateActual(Model const & model)
01104 {
01105 taoDNode * ee_node(model.getNode(end_effector_id_));
01106 if ( ! ee_node) {
01107 return 0;
01108 }
01109
01110 jspace::Transform ee_transform;
01111 model.computeGlobalFrame(ee_node, Vector::Zero(3), ee_transform);
01112 Matrix Jfull;
01113 eepos_ = ee_transform.translation();
01114 if ( ! model.computeJacobian(ee_node,
01115 eepos_[0],
01116 eepos_[1],
01117 eepos_[2],
01118 Jfull)) {
01119 return 0;
01120 }
01121
01122 jacobian_ = Jfull.block(3, 0, 3, Jfull.cols());
01123
01124 actual_x_ = ee_transform.linear().block(0, 0, 3, 1);
01125 actual_y_ = ee_transform.linear().block(0, 1, 3, 1);
01126 actual_z_ = ee_transform.linear().block(0, 2, 3, 1);
01127
01128 actual_.resize(9);
01129 actual_.block(0, 0, 3, 1) = actual_x_;
01130 actual_.block(3, 0, 3, 1) = actual_y_;
01131 actual_.block(6, 0, 3, 1) = actual_z_;
01132
01133 velocity_ = jacobian_ * model.getState().velocity_;
01134
01135 return ee_node;
01136 }
01137
01138
01139 Status OrientationTask::
01140 update(Model const & model)
01141 {
01142 if ( ! updateActual(model)) {
01143 return Status(false, "invalid end effector ID");
01144 }
01145 delta_ = actual_x_.cross(goal_x_) + actual_y_.cross(goal_y_) + actual_z_.cross(goal_z_);
01146 delta_ *= -0.5;
01147
01148 command_ = -delta_ * kp_;
01149 if ((maxvel_ > 1e-4) && (kd_ > 1e-4)) {
01150 double const sat(fabs((command_.norm() / maxvel_) / kd_));
01151 if (sat > 1.0) {
01152 command_ /= sat;
01153 }
01154 }
01155
01156 command_ -= velocity_ * kd_;
01157
01158 Status ok;
01159 return ok;
01160 }
01161
01162
01163 void OrientationTask::
01164 dbg(std::ostream & os,
01165 std::string const & title,
01166 std::string const & prefix) const
01167 {
01168 if ( ! title.empty()) {
01169 os << title << "\n";
01170 }
01171 os << prefix << "orientation task: `" << instance_name_ << "'\n";
01172 pretty_print(velocity_, os, prefix + " velocity", prefix + " ");
01173 pretty_print(goal_x_, os, prefix + " goal_x", prefix + " ");
01174 pretty_print(goal_y_, os, prefix + " goal_y", prefix + " ");
01175 pretty_print(goal_z_, os, prefix + " goal_z", prefix + " ");
01176 Vector foo(3);
01177 foo << goal_x_.norm(), goal_y_.norm(), goal_z_.norm();
01178 pretty_print(foo, os, prefix + " length of goal unit vectors", prefix + " ");
01179 pretty_print(actual_x_, os, prefix + " actual_x", prefix + " ");
01180 pretty_print(actual_y_, os, prefix + " actual_y", prefix + " ");
01181 pretty_print(actual_z_, os, prefix + " actual_z", prefix + " ");
01182 foo << actual_x_.norm(), actual_y_.norm(), actual_z_.norm();
01183 pretty_print(foo, os, prefix + " length of actual unit vectors", prefix + " ");
01184 pretty_print(delta_, os, prefix + " delta", prefix + " ");
01185 pretty_print(command_, os, prefix + " command", prefix + " ");
01186 }
01187
01188 }