tutorials/tut05_opspace_and_parameters.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 The Board of Trustees of The Leland Stanford Junior University. All rights reserved.
00003  *
00004  * Author: Roland Philippsen
00005  *         http://cs.stanford.edu/group/manips/
00006  *
00007  * This program is free software: you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation, either version 3 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this program.  If not, see
00019  * <http://www.gnu.org/licenses/>
00020  */
00021 
00059 #include "tutsim.hpp"
00060 #include <opspace/task_library.hpp>
00061 #include <jspace/test/sai_util.hpp>
00062 #include <boost/shared_ptr.hpp>
00063 #include <FL/fl_draw.H>
00064 #include <err.h>
00065 
00066 
00067 namespace tut05 {
00068   
00069   using namespace jspace;
00070 
00071   class PTask : public opspace::Task {
00072   public:
00073     PTask()
00074       : opspace::Task("tut05::PTask"),
00075   initialized_(false)
00076     {
00077       declareParameter("goalpos", &goalpos_);
00078       declareParameter("goalvel", &goalvel_);
00079     }
00080     
00081     void updateStateAndJacobian(Model const & model)
00082     {
00083       jspace::Transform ee_transform;
00084       model.computeGlobalFrame(model.getNode(3), // hardcoded end-effector ID = 3
00085              0, 0, -1, // hardcoded ctrl point 1m down along Z axis
00086              ee_transform);
00087       actual_ = ee_transform.translation().block(1, 0, 2, 1); // extract 2D point (y, z)
00088       Matrix Jfull;
00089       model.computeJacobian(model.getNode(3),
00090           ee_transform.translation(),
00091           Jfull);
00092       jacobian_ = Jfull.block(1, 0, 2, Jfull.cols()); // extract the Y and Z rows
00093       curvel_ = jacobian_ * model.getState().velocity_;
00094     }
00095     
00096     virtual jspace::Status init(jspace::Model const & model)
00097     {
00099       // Initialize our PD parameters.
00100       
00101       kp_ = 32.0;
00102       kd_ = 8.0;
00103       
00105       // The Jacobian becomes important now, because we are going to
00106       // use it to compute the mapping from operational space force to
00107       // joint torques. For real applications, it would furthermore be
00108       // used to determine the nullspace of the operational point
00109       // motion (but not in this tutorial where we simply let the
00110       // robot "flop around" in the task nullspace).
00111       
00112       updateStateAndJacobian(model);
00113       
00115       // Initialize our goal to the current state.
00116       
00117       goalpos_ = actual_;
00118       goalvel_ = jspace::Vector::Zero(2);
00119       
00121       // No initialization problems to report: the default constructor
00122       // of jspace::Status yields an instance that signifies success.
00123       
00124       initialized_ = true;
00125       jspace::Status ok;
00126       return ok;
00127     }
00128     
00129     
00130     virtual jspace::Status update(jspace::Model const & model)
00131     {
00133       // Lazy init...
00134       
00135       if ( ! initialized_ ) {
00136   init(model);
00137       }
00138       
00140       // Update the state and Jacobian of our task.
00141       
00142       updateStateAndJacobian(model);
00143       
00145       // Compute PD control forces (in task space). Later, in the
00146       // control loop, our Jacobian will be used to map them to
00147       // joint-space.  Inertial and gravity compensation happens
00148       // there, too. In effect, an operational space task only worries
00149       // about desired accelerations within its own task space.
00150       
00151       command_ = kp_ * (goalpos_ - actual_) + kd_ * (goalvel_ - curvel_);
00152       
00153       jspace::Status ok;
00154       return ok;
00155     }
00156 
00157     bool initialized_;    
00158     double kp_, kd_;
00159     jspace::Vector curvel_;
00160     jspace::Vector goalpos_, goalvel_;
00161     
00162     // Make these two protected fields publicly available for easier
00163     // info messages.
00164     opspace::Task::actual_;
00165     opspace::Task::jacobian_;
00166   };
00167   
00168 }
00169 
00170 
00171 static std::string model_filename(TUTROB_XML_PATH_STR);
00172 static boost::shared_ptr<jspace::Model> model;
00173 static tut05::PTask ptask;
00174 static opspace::Parameter * goalpos;
00175 static opspace::Parameter * goalvel;
00176 static size_t mode;
00177 
00178 
00179 static bool servo_cb(size_t toggle_count,
00180          double wall_time_ms,
00181          double sim_time_ms,
00182          jspace::State & state,
00183          jspace::Vector & command)
00184 {
00185   mode = toggle_count % 4;
00186   static size_t prevmode(42);
00187   
00188   if (0 == mode) {
00189     
00191     // Re-initialize simulator
00192     
00193     for (int ii(0); ii < state.position_.rows(); ++ii) {
00194       static double const amplitude(0.5 * M_PI);
00195       double const omega(1.0 + 0.1 * ii);
00196       double const phase(omega * 1e-3 * wall_time_ms);
00197       state.position_[ii] =         amplitude * sin(phase);
00198       state.velocity_[ii] = omega * amplitude * cos(phase);
00199     }
00200     prevmode = mode;
00201     return false;
00202     
00203   }
00204   
00206   // Update the model to reflect the current robot state.
00207   
00208   model->update(state);
00209   
00210   if (0 == prevmode) {
00211     jspace::Status const st(ptask.init(*model));
00212     if ( ! st) {
00213       errx(EXIT_FAILURE, "ptask.init() failed: %s", st.errstr.c_str());
00214     }
00215   }
00216   
00217   static jspace::Vector pos(2), vel(2);
00218   static double const ox(0.2);
00219   static double const oy(0.37);
00220   static double const amp(2.5);
00221   double const px(ox * 1e-3 * wall_time_ms);
00222   double const py(oy * 1e-3 * wall_time_ms);
00223   pos <<      amp * sin(px),      amp * sin(py);
00224   vel << ox * amp * cos(px), oy * amp * cos(py);
00225   if ( ! goalpos->set(pos)) {
00226     errx(EXIT_FAILURE, "failed to set end-effector goal position");
00227   }
00228   if ( ! goalvel->set(vel)) {
00229     errx(EXIT_FAILURE, "failed to set end-effector goal velocity");
00230   }
00231   
00232   ptask.update(*model);
00233   
00235   // The end-effector position task computes a desired acceleration in
00236   // Cartesian space. In order to send it to the joints as desired
00237   // torques, this needs to be translated from operational space to
00238   // joint space. In the opspace library, this is the job of
00239   // opspace::Controller::computeCommand(). However, that needs a bit
00240   // of extra infrastructure, so here we simply hardcode the
00241   // fundamental equation without any frosting...
00242   
00243   jspace::Matrix aa;
00244   model->getMassInertia(aa);
00245   jspace::Vector gg;
00246   model->getGravity(gg);
00247   jspace::Vector cc;
00248   model->getCoriolisCentrifugal(cc);
00249   
00250   char const * mode_desc;
00251   switch (mode) {
00252   case 1:
00253     mode_desc = "no compensation\n";
00254     command = ptask.getJacobian().transpose() * ptask.getCommand();
00255     break;
00256   case 2:
00257     mode_desc = "only gravity compensation\n";
00258     command = ptask.getJacobian().transpose() * ptask.getCommand() + gg;
00259     break;
00260   default:
00261     mode_desc = "full compensation\n";
00262     command = aa * ptask.getJacobian().transpose() * ptask.getCommand() + gg + cc;
00263   }
00264   
00265   static size_t iteration(0);
00266   if (0 == (iteration % 100)) {
00267     std::cerr << "**************************************************\n"
00268         << mode_desc;
00269     jspace::pretty_print(state.position_, std::cerr, "  jpos", "    ");
00270     jspace::pretty_print(state.velocity_, std::cerr, "  jvel", "    ");
00271     jspace::pretty_print(ptask.actual_, std::cerr, "  ppos", "    ");
00272     jspace::pretty_print(ptask.curvel_, std::cerr, "  pvel", "    ");
00273     jspace::pretty_print(ptask.goalpos_, std::cerr, "  goalpos", "    ");
00274     jspace::pretty_print(ptask.goalvel_, std::cerr, "  goalvel", "    ");
00275     jspace::pretty_print(ptask.jacobian_, std::cerr, "  Jacobian", "    ");
00276     jspace::pretty_print(command, std::cerr, "  command", "    ");
00277   }
00278   ++iteration;
00279   
00280   prevmode = mode;
00281   return true;
00282 }
00283 
00284 
00285 static void draw_cb(double x0, double y0, double scale)
00286 {
00287   if (0 != mode) {
00288     
00290     // On a side-note: we plot the YZ plane, X is sticking out of the
00291     // screen (but the robot is planar anyway). However, the
00292     // tut05::PTask's planar operational space already takes that into
00293     // account.
00294     
00295     fl_color(255, 100, 100);
00296     fl_line_style(FL_SOLID, 1, 0);
00297     
00298     double const gx(goalpos->getVector()->x());
00299     double const gy(goalpos->getVector()->y());
00300     int const rr(ceil(0.15 * scale));
00301     int const dd(2 * rr);
00302     fl_arc(int(x0 + gx * scale) - rr, int(y0 - gy * scale) - rr, dd, dd, 0.0, 360.0);
00303     
00304     double const vx(goalvel->getVector()->x());
00305     double const vy(goalvel->getVector()->y());
00306     double const px(gx + vx * 0.1);
00307     double const py(gy + vy * 0.1);
00308     fl_line(x0 + (gx + 0.2) * scale, y0 - gy * scale,
00309       x0 + (gx - 0.2) * scale, y0 - gy * scale);
00310     fl_line(x0 + gx * scale, y0 - (gy + 0.2) * scale,
00311       x0 + gx * scale, y0 - (gy - 0.2) * scale);
00312     fl_color(255, 255, 100);
00313     fl_line(x0 + gx * scale, y0 - gy * scale,
00314       x0 + px * scale, y0 - py * scale);
00315   }
00316 }
00317 
00318 
00319 int main(int argc, char ** argv)
00320 {
00321   try {
00322     model.reset(jspace::test::parse_sai_xml_file(model_filename, true));
00323     goalpos = ptask.lookupParameter("goalpos", opspace::PARAMETER_TYPE_VECTOR);
00324     if ( ! goalpos) {
00325       errx(EXIT_FAILURE, "failed to find appropriate goalpos parameter");
00326     }
00327     goalvel = ptask.lookupParameter("goalvel", opspace::PARAMETER_TYPE_VECTOR);
00328     if ( ! goalvel) {
00329       errx(EXIT_FAILURE, "failed to find appropriate goalvel parameter");
00330     }
00331   }
00332   catch (std::runtime_error const & ee) {
00333     errx(EXIT_FAILURE, "%s", ee.what());
00334   }
00335   tutsim::set_draw_cb(draw_cb);
00336   return tutsim::run(servo_cb);
00337 }

Generated on Fri Aug 26 01:31:18 2011 for Stanford Whole-Body Control Framework by  doxygen 1.5.4