tutorials/tutsim.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 
00022 #include "tutsim.hpp"
00023 
00024 #include <jspace/test/sai_brep_parser.hpp>
00025 #include <jspace/test/sai_brep.hpp>
00026 
00027 #include <tao/dynamics/taoNode.h>
00028 #include <tao/dynamics/taoJoint.h>
00029 #include <tao/dynamics/taoDynamics.h>
00030 #include <tao/dynamics/taoVar.h>
00031 #include <tao/matrix/TaoDeMath.h>
00032 #include <tao/matrix/TaoDeQuaternion.h>
00033 #include <tao/matrix/TaoDeFrame.h>
00034 
00035 #include <boost/shared_ptr.hpp>
00036 
00037 #include <FL/Fl.H>
00038 #include <FL/Fl_Double_Window.H>
00039 #include <FL/Fl_Button.H>
00040 #include <FL/fl_draw.H>
00041 
00042 #include <err.h>
00043 #include <sys/time.h>
00044 
00045 
00046 static char const * robot_filename(TUTROB_XML_PATH_STR);
00047 static double gfx_rate_hz(20.0);
00048 static double servo_rate_hz(400.0);
00049 static double sim_rate_hz(1600.0);
00050 static int win_width(300);
00051 static int win_height(200);
00052 static char const * win_title("Stanford WBC Tutorial");
00053 static boost::shared_ptr<jspace::tao_tree_info_s> sim_tree;
00054 static boost::shared_ptr<jspace::tao_tree_info_s> scratch_tree;
00055 static int id1(-1);
00056 static int id2(-1);
00057 static int id3(-1);
00058 static int id4(-1);
00059 static jspace::State state;
00060 static size_t ndof;
00061 static size_t toggle_count(0);
00062 static double servo_dt_ms;
00063 static bool paused(false);
00064 
00065 
00066 static bool (*servo_cb)(size_t toggle_count,
00067       double wall_time_ms,
00068       double sim_time_ms,
00069       jspace::State & state,
00070       jspace::Vector & command);
00071 
00072 static void (*draw_cb)(double x0, double y0, double scale) = 0;
00073 
00074 
00075 namespace {
00076   
00077   
00078   class Simulator : public Fl_Widget {
00079   public:
00080     Simulator(int xx, int yy, int width, int height, const char * label = 0);
00081     virtual ~Simulator();
00082     
00083     virtual void draw();
00084     
00085     void tick();
00086     static void timer_cb(void * param);
00087   };
00088   
00089   
00090   class Window : public Fl_Double_Window {
00091   public:
00092     Window(int width, int height, const char * title);
00093     
00094     virtual void resize(int x, int y, int w, int h);
00095     
00096     Simulator * simulator;
00097     Fl_Button * toggle;
00098     Fl_Button * pause;
00099     Fl_Button * quit;
00100     
00101     static void cb_toggle(Fl_Widget * widget, void * param);
00102     static void cb_pause(Fl_Widget * widget, void * param);
00103     static void cb_quit(Fl_Widget * widget, void * param);
00104   };
00105   
00106   
00107   static void write_state_to_tree(jspace::Vector const * jpos,
00108           jspace::Vector const * jvel,
00109           jspace::tao_tree_info_s & tree)
00110   {
00111     for (size_t ii(0); ii < ndof; ++ii) {
00112       taoJoint * joint(tree.info[ii].joint);
00113       int const kk(tree.info[ii].id);
00114       if (jpos) {
00115   joint->setQ(&(jpos->coeff(kk)));
00116       }
00117       if (jvel) {
00118   joint->setDQ(&(jvel->coeff(kk)));
00119       }
00120       joint->zeroDDQ();
00121       joint->zeroTau();
00122     }
00123     taoDynamics::updateTransformation(tree.root);
00124   }
00125   
00126   
00127   static void write_state_to_tree(jspace::tao_tree_info_s & tree)
00128   {
00129     write_state_to_tree(&(state.position_), &(state.velocity_), tree);
00130   }
00131   
00132   
00133   static void read_state_from_tree(jspace::tao_tree_info_s const & tree,
00134            jspace::Vector * jpos,
00135            jspace::Vector * jvel,
00136            jspace::Vector * jfrc)
00137   {
00138     for (size_t ii(0); ii < ndof; ++ii) {
00139       taoJoint const * joint(tree.info[ii].joint);
00140       int const kk(tree.info[ii].id);
00141       if (jpos) {
00142   joint->getQ(&(jpos->coeffRef(kk)));
00143       }
00144       if (jvel) {
00145   joint->getDQ(&(jvel->coeffRef(kk)));
00146       }
00147       if (jfrc) {
00148   joint->getTau(&(jfrc->coeffRef(kk)));
00149       }
00150     }
00151   }
00152   
00153   
00154   static void read_state_from_tree(jspace::tao_tree_info_s const & tree)
00155   {
00156     read_state_from_tree(tree, &(state.position_), &(state.velocity_), &(state.force_));
00157   }
00158   
00159   
00160   Simulator::
00161   Simulator(int xx, int yy, int width, int height, const char * label)
00162     : Fl_Widget(xx, yy, width, height, label)
00163   {
00164     Fl::add_timeout(0.1, timer_cb, this);
00165   }
00166   
00167   
00168   Simulator::
00169   ~Simulator()
00170   {
00171     Fl::remove_timeout(timer_cb, this);
00172   }
00173   
00174   
00175   static taoDNode * find_node(jspace::tao_tree_info_s & tree, std::string const & name)
00176   {
00177     for (size_t ii(0); ii < ndof; ++ii) {
00178       if (name == tree.info[ii].link_name) {
00179   return  tree.info[ii].node;
00180       }
00181     }
00182     errx(EXIT_FAILURE, "node `%s' not found", name.c_str());
00183   }
00184   
00185   
00186   static void raw_draw_tree(jspace::tao_tree_info_s & tree, double x0, double y0, double scale)
00187   {
00188     if (0 > id1) {
00189       id1 = find_node(*sim_tree, "link1")->getID();
00190       id2 = find_node(*sim_tree, "link2")->getID();
00191       id3 = find_node(*sim_tree, "link3")->getID();
00192       id4 = find_node(*sim_tree, "link4")->getID();
00193     }
00194     
00195     fl_line(x0 + (tree.info[id1].node->frameGlobal()->translation()[1] * scale),
00196       y0 - (tree.info[id1].node->frameGlobal()->translation()[2] * scale),
00197       x0 + (tree.info[id2].node->frameGlobal()->translation()[1] * scale),
00198       y0 - (tree.info[id2].node->frameGlobal()->translation()[2] * scale));
00199     fl_line(x0 + (tree.info[id2].node->frameGlobal()->translation()[1] * scale),
00200       y0 - (tree.info[id2].node->frameGlobal()->translation()[2] * scale),
00201       x0 + (tree.info[id3].node->frameGlobal()->translation()[1] * scale),
00202       y0 - (tree.info[id3].node->frameGlobal()->translation()[2] * scale));
00203     fl_line(x0 + (tree.info[id3].node->frameGlobal()->translation()[1] * scale),
00204       y0 - (tree.info[id3].node->frameGlobal()->translation()[2] * scale),
00205       x0 + (tree.info[id4].node->frameGlobal()->translation()[1] * scale),
00206       y0 - (tree.info[id4].node->frameGlobal()->translation()[2] * scale));
00207     deFrame locframe;
00208     locframe.translation()[2] = -1.0;
00209     deFrame globframe;
00210     globframe.multiply(*(tree.info[id4].node->frameGlobal()), locframe);
00211     fl_line(x0 + (tree.info[id4].node->frameGlobal()->translation()[1] * scale),
00212       y0 - (tree.info[id4].node->frameGlobal()->translation()[2] * scale),
00213       x0 + (globframe.translation()[1] * scale),
00214       y0 - (globframe.translation()[2] * scale));
00215   }
00216   
00217   
00218   static void raw_draw_com(jspace::tao_tree_info_s & tree, double x0, double y0, double scale)
00219   {
00220     if ( ! id1) {
00221       id1 = find_node(*sim_tree, "link1")->getID();
00222       id2 = find_node(*sim_tree, "link2")->getID();
00223       id3 = find_node(*sim_tree, "link3")->getID();
00224       id4 = find_node(*sim_tree, "link4")->getID();
00225     }
00226     
00227     deVector3 globpoint;
00228     globpoint.multiply(*(tree.info[id1].node->frameGlobal()), *(tree.info[id1].node->center()));
00229     fl_point(x0 + (globpoint[1] * scale), y0 - (globpoint[2] * scale));
00230     globpoint.multiply(*(tree.info[id2].node->frameGlobal()), *(tree.info[id2].node->center()));
00231     fl_point(x0 + (globpoint[1] * scale), y0 - (globpoint[2] * scale));
00232     globpoint.multiply(*(tree.info[id3].node->frameGlobal()), *(tree.info[id3].node->center()));
00233     fl_point(x0 + (globpoint[1] * scale), y0 - (globpoint[2] * scale));
00234     globpoint.multiply(*(tree.info[id4].node->frameGlobal()), *(tree.info[id4].node->center()));
00235     fl_point(x0 + (globpoint[1] * scale), y0 - (globpoint[2] * scale));
00236   }
00237   
00238   
00239   void Simulator::
00240   draw()
00241   {
00242     double scale;
00243     if (w() > h()) {
00244       scale = h() / 9.0;
00245     }
00246     else {
00247       scale = w() / 9.0;
00248     }
00249     double const x0(w() / 2.0);
00250     double const y0(h() / 2.0);
00251     
00252     fl_color(FL_BLACK);
00253     fl_rectf(x(), y(), w(), h());
00254     
00255     fl_color(FL_WHITE);
00256     fl_line_style(FL_SOLID, 3, 0);
00257     raw_draw_tree(*sim_tree, x0, y0, scale);
00258     
00259     fl_color(FL_GREEN);
00260     raw_draw_com(*sim_tree, x0, y0, scale);
00261     
00262     if (draw_cb) {
00263       draw_cb(x0, y0, scale);
00264     }
00265     
00266     fl_line_style(0);   // back to default
00267   }
00268   
00269   
00270   void Simulator::
00271   tick()
00272   {
00273     static struct timeval wall_time_start;
00274     static size_t sim_nsteps(0);
00275     static double wall_time_ms, sim_time_ms, sim_dt;
00276     static double gfx_dt_ms, gfx_next_ms;
00277     
00278     if (sim_nsteps == 0) {  // lazy init
00279       if (0 != gettimeofday(&wall_time_start, 0)) {
00280   errx(EXIT_FAILURE, "gettimofday failed");
00281       }
00282       wall_time_ms = 0;
00283       sim_time_ms = 0;
00284       servo_dt_ms = 1e3 / servo_rate_hz;
00285       if (sim_rate_hz <= servo_rate_hz) {
00286   sim_rate_hz = servo_rate_hz;
00287   sim_nsteps = 1;
00288       }
00289       else {
00290   sim_nsteps = llrint(ceil(sim_rate_hz / servo_rate_hz));
00291   sim_rate_hz = sim_nsteps * servo_rate_hz;
00292       }
00293       sim_dt = 1.0 / sim_rate_hz;
00294       gfx_dt_ms = 1e3 / gfx_rate_hz;
00295       gfx_next_ms = -1;
00296     }
00297     else {
00298       struct timeval now;
00299       if (0 != gettimeofday(&now, 0)) {
00300   errx(EXIT_FAILURE, "gettimofday failed");
00301       }
00302       wall_time_ms = 1e3 * (now.tv_sec - wall_time_start.tv_sec)
00303   + 1e-3 * (now.tv_usec - wall_time_start.tv_usec);
00304       sim_time_ms += servo_dt_ms;
00305     }
00306     
00307     jspace::Vector command;
00308     read_state_from_tree(*sim_tree);
00309     if ( ! servo_cb(toggle_count, wall_time_ms, sim_time_ms, state, command)) {
00310       write_state_to_tree(*sim_tree);
00311     }
00312     else {
00313       if (command.rows() != ndof) {
00314   errx(EXIT_FAILURE, "invalid command dimension %d (should be %zu)", command.rows(), ndof);
00315       }
00316       jspace::Vector ddq(ndof);
00317       for (size_t ii(0); ii < sim_nsteps; ++ii) {
00318   static deVector3 earth_gravity(0.0, 0.0, -9.81);
00319   for (size_t kk(0); kk < ndof; ++kk) {
00320     // is this necessary each kk?
00321     sim_tree->info[kk].joint->setTau(&(command.coeffRef(sim_tree->info[kk].id)));
00322   }
00323   taoDynamics::fwdDynamics(sim_tree->root, &earth_gravity);
00324   for (size_t kk(0); kk < ndof; ++kk) {
00325     sim_tree->info[kk].joint->getDDQ(&(ddq.coeffRef(sim_tree->info[kk].id)));
00326   }
00330   state.velocity_ += sim_dt * ddq;
00331   state.position_ += sim_dt * state.velocity_;
00332   write_state_to_tree(*sim_tree);
00333       }
00334     }
00335     
00336     if (wall_time_ms >= gfx_next_ms) {
00337       redraw();      
00338       gfx_next_ms += gfx_dt_ms;
00339     }
00340   }
00341   
00342   
00343   void Simulator::
00344   timer_cb(void * param)
00345   {
00346     if ( ! paused) {
00347       reinterpret_cast<Simulator*>(param)->tick();
00348     }
00349     Fl::repeat_timeout(1e-3 * servo_dt_ms, // gets initialized within tick()
00350            timer_cb,
00351            param);
00352   }
00353   
00354   
00355   Window::
00356   Window(int width, int height, const char * title)
00357     : Fl_Double_Window(width, height, title)
00358   {
00359     Fl::visual(FL_DOUBLE|FL_INDEX);
00360     begin();
00361     simulator = new Simulator(0, 0, width, height - 40);
00362     toggle = new Fl_Button(5, height - 35, 100, 30, "&Toggle");
00363     toggle->callback(cb_toggle);
00364     pause = new Fl_Button(width / 2 - 50, height - 35, 100, 30, "&Pause");
00365     pause->callback(cb_pause);
00366     quit = new Fl_Button(width - 105, height - 35, 100, 30, "&Quit");
00367     quit->callback(cb_quit, this);
00368     end();
00369     resizable(this);
00370     show();
00371   }
00372   
00373   
00374   void Window::
00375   resize(int x, int y, int w, int h)
00376   {
00377     Fl_Double_Window::resize(x, y, w, h);
00378     simulator->resize(0, 0, w, h - 40);
00379     toggle->resize(5, h-35, 100, 30);
00380     pause->resize(w/2-50, h-35, 100, 30);
00381     quit->resize(w-105, h-35, 100, 30);
00382   }
00383   
00384   
00385   void Window::
00386   cb_toggle(Fl_Widget * widget, void * param)
00387   {
00388     ++toggle_count;
00389   }
00390   
00391   
00392   void Window::
00393   cb_pause(Fl_Widget * widget, void * param)
00394   {
00395     if (paused) {
00396       paused = false;
00397     }
00398     else {
00399       paused = true;
00400     }
00401   }
00402   
00403   
00404   void Window::
00405   cb_quit(Fl_Widget * widget, void * param)
00406   {
00407     reinterpret_cast<Window*>(param)->hide();
00408   }
00409   
00410 }
00411 
00412 
00413 void tutsim::
00414 set_robot_filename(char const * _robot_filename)
00415 {
00416   robot_filename = _robot_filename;
00417 }
00418 
00419 
00420 void tutsim::
00421 set_rates(double _gfx_rate_hz,
00422     double _servo_rate_hz,
00423     double _sim_rate_hz)
00424 {
00425   gfx_rate_hz = _gfx_rate_hz;
00426   servo_rate_hz = _servo_rate_hz;
00427   sim_rate_hz = _sim_rate_hz;
00428 }
00429 
00430 
00431 void tutsim::
00432 set_window_params(int width, int height, char const * title)
00433 {
00434   win_width = width;
00435   win_height = height;
00436   win_title = title;
00437 }
00438 
00439 
00440 void tutsim::
00441 draw_robot(jspace::Vector const & jpos, int width,
00442      unsigned char red, unsigned char green, unsigned char blue,
00443      double x0, double y0, double scale)
00444 {
00445   write_state_to_tree(&jpos, 0, *scratch_tree);
00446   fl_color(red, green, blue);
00447   fl_line_style(FL_SOLID, width, 0);
00448   raw_draw_tree(*scratch_tree, x0, y0, scale);
00449   fl_line_style(0);   // back to default
00450 }
00451 
00452 
00453 void tutsim::
00454 draw_delta_jpos(jspace::Vector const & jpos, int width,
00455     unsigned char red, unsigned char green, unsigned char blue,
00456     double x0, double y0, double scale)
00457 {
00458   if (0 > id1) {
00459     id1 = find_node(*sim_tree, "link1")->getID();
00460     id2 = find_node(*sim_tree, "link2")->getID();
00461     id3 = find_node(*sim_tree, "link3")->getID();
00462     id4 = find_node(*sim_tree, "link4")->getID();
00463   }
00464   
00465   jspace::Vector scratchpos(sim_tree->info.size());
00466   read_state_from_tree(*sim_tree, &scratchpos, 0, 0);
00467   
00468   fl_color(red, green, blue);
00469   fl_line_style(FL_SOLID, width, 0);
00470   
00471   scratchpos[id4] = jpos[id4];
00472   write_state_to_tree(&scratchpos, 0, *scratch_tree);
00473   deFrame locframe;
00474   locframe.translation()[2] = -1.0;
00475   deFrame globframe;
00476   globframe.multiply(*(scratch_tree->info[id4].node->frameGlobal()), locframe);
00477   fl_line(x0 + (scratch_tree->info[id4].node->frameGlobal()->translation()[1] * scale),
00478     y0 - (scratch_tree->info[id4].node->frameGlobal()->translation()[2] * scale),
00479     x0 + (globframe.translation()[1] * scale),
00480     y0 - (globframe.translation()[2] * scale));
00481   
00482   scratchpos[id3] = jpos[id3];
00483   write_state_to_tree(&scratchpos, 0, *scratch_tree);
00484   fl_line(x0 + (scratch_tree->info[id3].node->frameGlobal()->translation()[1] * scale),
00485     y0 - (scratch_tree->info[id3].node->frameGlobal()->translation()[2] * scale),
00486     x0 + (scratch_tree->info[id4].node->frameGlobal()->translation()[1] * scale),
00487     y0 - (scratch_tree->info[id4].node->frameGlobal()->translation()[2] * scale));
00488   
00489   scratchpos[id2] = jpos[id2];
00490   write_state_to_tree(&scratchpos, 0, *scratch_tree);
00491   fl_line(x0 + (scratch_tree->info[id2].node->frameGlobal()->translation()[1] * scale),
00492     y0 - (scratch_tree->info[id2].node->frameGlobal()->translation()[2] * scale),
00493     x0 + (scratch_tree->info[id3].node->frameGlobal()->translation()[1] * scale),
00494     y0 - (scratch_tree->info[id3].node->frameGlobal()->translation()[2] * scale));
00495   
00496   scratchpos[id1] = jpos[id1];
00497   write_state_to_tree(&scratchpos, 0, *scratch_tree);
00498   fl_line(x0 + (scratch_tree->info[id1].node->frameGlobal()->translation()[1] * scale),
00499     y0 - (scratch_tree->info[id1].node->frameGlobal()->translation()[2] * scale),
00500     x0 + (scratch_tree->info[id2].node->frameGlobal()->translation()[1] * scale),
00501     y0 - (scratch_tree->info[id2].node->frameGlobal()->translation()[2] * scale));
00502 
00503   fl_line_style(0);   // back to default
00504 }
00505 
00506 
00507 void tutsim::
00508 set_draw_cb(void (*_draw_cb)(double x0, double y0, double scale))
00509 {
00510   draw_cb = _draw_cb;
00511 }
00512 
00513 
00514 int tutsim::
00515 run(bool (*_servo_cb)(size_t toggle_count,
00516           double wall_time_ms,
00517           double sim_time_ms,
00518           jspace::State & state,
00519           jspace::Vector & command))
00520 {
00521   if (gfx_rate_hz <= 0.0) {
00522     errx(EXIT_FAILURE, "invalid gfx_rate_hz %g (must be > 0)", gfx_rate_hz);
00523   }
00524   if (servo_rate_hz <= 0.0) {
00525     errx(EXIT_FAILURE, "invalid servo_rate_hz %g (must be > 0)", servo_rate_hz);
00526   }
00527   
00528   try {
00529     jspace::test::BRParser brp;
00530     boost::shared_ptr<jspace::test::BranchingRepresentation> brep(brp.parse(robot_filename));
00531     sim_tree.reset(brep->createTreeInfo());
00532     brep.reset(brp.parse(robot_filename));
00533     scratch_tree.reset(brep->createTreeInfo());
00534   }
00535   catch (std::runtime_error const & ee) {
00536     errx(EXIT_FAILURE, "%s", ee.what());
00537   }
00538   
00539   servo_cb = _servo_cb;
00540   ndof = sim_tree->info.size();
00541   state.init(ndof, ndof, ndof);
00542   write_state_to_tree(*sim_tree);
00543   
00544   Window win(win_width, win_height, win_title);
00545   return Fl::run();
00546 }

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