nimm2.cpp

Example for the creation of a simulated robot with transform object and infrared sensors (lpzrobots/ode_robots/robots/nimm2.cpp).

00001 /***************************************************************************
00002  *   Copyright (C) 2005 by Robot Group Leipzig                             *
00003  *    martius@informatik.uni-leipzig.de                                    *
00004  *    fhesse@informatik.uni-leipzig.de                                     *
00005  *    der@informatik.uni-leipzig.de                                        *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  *                                                                         *
00022  *   $Log: nimm2.cpp,v $
00023  *   Revision 1.21.4.17  2006/03/31 12:12:41  fhesse
00024  *   documentation improved
00025  *
00026  *   Revision 1.21.4.16  2006/02/01 18:33:39  martius
00027  *   use Axis type for Joint axis. very important, since otherwise Vec3 * pose is not the right direction vector anymore
00028  *
00029  *   Revision 1.21.4.15  2006/01/31 15:40:23  martius
00030  *   irRange configurable
00031  *   even higher friction and body is allways on th ground
00032  *
00033  *   Revision 1.21.4.14  2006/01/26 18:37:20  martius
00034  *   *** empty log message ***
00035  *
00036  *   Revision 1.21.4.13  2006/01/18 16:46:24  martius
00037  *   enabled coloring via osgHandle
00038  *
00039  *   Revision 1.21.4.12  2006/01/17 17:02:19  martius
00040  *   faster, stronger, more friction
00041  *
00042  *   Revision 1.21.4.11  2006/01/13 12:25:44  martius
00043  *   typo in setmotors
00044  *
00045  *   Revision 1.21.4.10  2006/01/11 18:21:48  martius
00046  *   bumpers are moving
00047  *   wheel texture is okay
00048  *
00049  *   Revision 1.21.4.9  2006/01/10 17:16:22  martius
00050  *   sensorbank cleared on destroy
00051  *
00052  *   Revision 1.21.4.8  2005/12/29 16:47:40  martius
00053  *   joint has getPosition
00054  *
00055  *   Revision 1.21.4.7  2005/12/15 17:04:08  martius
00056  *   Primitives are not longer inherited from OSGPrimitive, moreover
00057  *   they aggregate them.
00058  *   Joint have better getter and setter
00059  *
00060  *   Revision 1.21.4.6  2005/12/14 15:37:09  martius
00061  *   robots are working with osg
00062  *
00063  *   Revision 1.21.4.5  2005/12/13 18:11:39  martius
00064  *   still trying to port robots
00065  *
00066  *   Revision 1.21.4.4  2005/12/06 17:38:17  martius
00067  *   *** empty log message ***
00068  *
00069  *   Revision 1.21.4.3  2005/11/16 11:26:52  martius
00070  *   moved to selforg
00071  *
00072  *   Revision 1.21.4.2  2005/11/15 12:29:26  martius
00073  *   new selforg structure and OdeAgent, OdeRobot ...
00074  *
00075  *   Revision 1.21.4.1  2005/11/14 17:37:17  martius
00076  *   moved to selforg
00077  *
00078  *   Revision 1.21  2005/11/08 11:35:56  martius
00079  *   removed check for sensorbank because rays are disabled now
00080  *
00081  *   Revision 1.20  2005/11/04 14:43:27  martius
00082  *   added GPL
00083  *
00084  *                                                                 *
00085  ***************************************************************************/
00086 
00087 #include <ode/ode.h>
00088 #include <assert.h>
00089 #include <osg/Matrix>
00090 
00091 #include "nimm2.h"
00092 #include "irsensor.h"
00093 
00094 using namespace osg;
00095 
00096 namespace lpzrobots {
00097 
00098   // constructor:
00099   // - give handle for ODE and OSG stuff, and default configuration
00100   Nimm2::Nimm2(const OdeHandle& odehandle, const OsgHandle& osgHandle, 
00101                const Nimm2Conf& conf = getDefaultConf()):
00102     // calling OdeRobots construtor with name of the actual robot
00103     OdeRobot(odehandle, osgHandle, "Nimm2"), conf(conf) { 
00104 
00105     // robot not created up to now
00106     created=false;
00107   
00108     // Nimm2 color ;-)
00109     // this->osgHandle.color = Color(2, 156/255.0, 0, 1.0f);
00110     // can be set in main.cpp of simulation
00111 
00112     // maximal used force is calculated from the force and size given in the configuration
00113     max_force   = conf.force*conf.size*conf.size;
00114 
00115     height=conf.size;
00116 
00117     width=conf.size/2;  // radius of body
00118     radius=conf.size/4; // +conf.size/600;  //radius of wheels
00119     wheelthickness=conf.size/20; // thickness of the wheels (if wheels used, no spheres)
00120     cmass=4*conf.size;    // mass of body
00121     wmass=conf.size/5.0;  // mass of wheels
00122     if(conf.singleMotor){ //-> one dimensional robot
00123       sensorno=1; 
00124       motorno=1;  
00125     } else { // -> both wheels actuated independently
00126       sensorno=2; 
00127       motorno=2;  
00128     }
00129 
00130     if (conf.cigarMode){
00131       length=conf.size*2.0;    // long body
00132       wheeloffset= -length/4;  // wheels at the end of the cylinder, and the opposite endas the bumper
00133       number_bumpers=2;        // if wheels not at center only one bumper
00134       cmass=4*conf.size;
00135       max_force   = 2*conf.force*conf.size*conf.size;
00136     }
00137     else{
00138       length=conf.size/2;     // short body 
00139       wheeloffset=0.0;        // wheels at center of body
00140       number_bumpers=2;       // if wheels at center 2 bumpers (one at each end)
00141     }
00142     
00143     // increase sensornumber by 2 if front infrared sensors are used
00144     sensorno+= conf.irFront * 2;
00145   };
00146 
00147 
00148   /** sets actual motorcommands
00149       @param motors motors scaled to [-1,1] 
00150       @param motornumber length of the motor array
00151   */
00152   void Nimm2::setMotors(const motor* motors, int motornumber){
00153     assert(created);
00154     assert(motornumber == motorno);
00155     if(conf.singleMotor){ // set the same motorcommand to both wheels
00156       joint[0]->setParam(dParamVel2, motors[0]*conf.speed); // set velocity      
00157       joint[0]->setParam(dParamFMax2,max_force);            // set maximal force
00158       joint[1]->setParam(dParamVel2, motors[0]*conf.speed);       
00159       joint[1]->setParam(dParamFMax2,max_force);    
00160     } else {
00161       for (int i=0; i<2; i++){ // set different motorcommands to the wheels
00162         joint[i]->setParam(dParamVel2, motors[i]*conf.speed);       
00163         joint[i]->setParam(dParamFMax2,max_force);
00164       }
00165     }
00166   };
00167 
00168   /** returns actual sensorvalues
00169       @param sensors sensors scaled to [-1,1] (more or less)
00170       @param sensornumber length of the sensor array
00171       @return number of actually written sensors
00172   */
00173   int Nimm2::getSensors(sensor* sensors, int sensornumber){
00174     assert(created);
00175   
00176     // choose sensornumber according to number of motors
00177     // - one motorcommand -> one sensorvalue
00178     // - motors indepently controlled -> two sensorvalues
00179     int len = conf.singleMotor ? 1 : 2;
00180     for (int i=0; i<len; i++){
00181       sensors[i]=joint[i]->getPosition2Rate();  // readout wheel velocity
00182       sensors[i]/=conf.speed;  //scaling
00183     }
00184     // ask sensorbank for sensor values (from infrared sensors)
00185     //  sensor+len is the starting point in the sensors array
00186     len += irSensorBank.get(sensors+len, sensornumber-len);
00187     return len;
00188   };
00189 
00190 
00191   void Nimm2::place(const Matrix& pose){
00192     // the position of the robot is the center of the body (without wheels)
00193     // to set the vehicle on the ground when the z component of the position is 0
00194     // width*0.6 is added (without this the wheels and half of the robot will be in the ground)    
00195     Matrix p2;
00196     p2 = pose * Matrix::translate(Vec3(0, 0, width*0.6)); 
00197     create(p2);
00198     
00199   };
00200 
00201   /** returns a vector with the positions of all segments of the robot
00202       @param poslist vector of positions (of all robot segments) 
00203       @return length of the list
00204   */
00205   int Nimm2::getSegmentsPosition(vector<Position> &poslist){
00206     assert(created);
00207     for (int i=0; i<3; i++){
00208       poslist.push_back(Position(dBodyGetPosition(object[i]->getBody())));
00209     }   
00210     return 3;
00211   };  
00212 
00213   /**
00214    * updates the osg notes and sensorbank
00215    */
00216   void Nimm2::update(){
00217     assert(created); // robot must exist
00218   
00219     for (int i=0; i<3; i++) { // update objects
00220       object[i]->update();
00221     }
00222     for (int i=0; i < 2; i++) { // update joints
00223       joint[i]->update(); 
00224     }
00225     if (conf.bumper){ // if bumper used update transform objects
00226       for (int i=0; i<number_bumpers; i++){
00227         bumper[i].trans->update();
00228       }
00229     }
00230 
00231     // update sensorbank with infrared sensors
00232     irSensorBank.update();  
00233   }
00234 
00235 
00236   void Nimm2::mycallback(void *data, dGeomID o1, dGeomID o2){
00237     // Nimm2* me = (Nimm2*)data;  
00238     // o1 and o2 are member of the space
00239 
00240     // we ignore the collisions
00241   }
00242 
00243   bool Nimm2::collisionCallback(void *data, dGeomID o1, dGeomID o2){
00244     //checks if one of the collision objects is part of the robot
00245     assert(created);
00246     bool colwithme = false;  
00247     if( o1 == (dGeomID)odeHandle.space || o2 == (dGeomID)odeHandle.space ){
00248       if(o1 == (dGeomID)odeHandle.space) irSensorBank.sense(o2);
00249       if(o2 == (dGeomID)odeHandle.space) irSensorBank.sense(o1);
00250 
00251       bool colwithbody;  
00252       int i,n;  
00253       const int N = 10;
00254       dContact contact[N];
00255       //    n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
00256       n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
00257       for (i=0; i<n; i++){
00258         colwithme = true; // there is at least one collision with some part of the robot (not sensors)
00259         colwithbody = false;
00260         if( contact[i].geom.g1 == object[0]->getGeom() || contact[i].geom.g2 == object[0]->getGeom() ||
00261             ( bumper[0].trans && bumper[1].trans) && (
00262             contact[i].geom.g1 == bumper[0].trans->getGeom() || 
00263             contact[i].geom.g2 == bumper[0].trans->getGeom() ||
00264             contact[i].geom.g1 == bumper[1].trans->getGeom() || 
00265             contact[i].geom.g2 == bumper[1].trans->getGeom()) ){
00266         
00267           colwithbody = true;
00268         }
00269         contact[i].surface.mode = dContactSlip1 | dContactSlip2 |
00270           dContactSoftERP | dContactSoftCFM | dContactApprox1;
00271         // one could try to make the body sliping along its axis by using 
00272         //  sin(alpha), cos(alpha) for sliping params (only for body collisions)
00273         contact[i].surface.slip1 = 0.005; // sliping in x
00274         contact[i].surface.slip2 = 0.005; // sliping in y
00275         if(colwithbody){
00276           contact[i].surface.mu = 0.1; // small friction of smooth body
00277           contact[i].surface.soft_erp = 0.5;
00278           contact[i].surface.soft_cfm = 0.005;
00279         }else{
00280           contact[i].surface.mu = 5.0; //large friction
00281           contact[i].surface.soft_erp = 0.5;
00282           contact[i].surface.soft_cfm = 0.001;
00283         }
00284         dJointID c = dJointCreateContact( odeHandle.world, odeHandle.jointGroup, &contact[i]);
00285         dJointAttach ( c , dGeomGetBody(contact[i].geom.g1) , dGeomGetBody(contact[i].geom.g2));
00286       }        
00287     }
00288     return colwithme;
00289   }
00290 
00291   void Nimm2::doInternalStuff(const GlobalData& globalData){
00292     // dSpaceCollide(car_space, this, mycallback); // checks collisions in the car_space only (not needed)
00293     irSensorBank.reset(); // reset sensorbank (infrared sensors)
00294   }
00295 
00296   /** creates vehicle at desired position 
00297       @param pos struct Position with desired position
00298   */
00299   void Nimm2::create(const Matrix& pose){
00300     if (created) {
00301       destroy();
00302     }
00303 
00304     // create vehicle space and add it to the top level space
00305     // robot will be inserted in the vehicle space
00306     odeHandle.space = dSimpleSpaceCreate (parentspace);
00307   
00308     // create body
00309     // - create cylinder for main body (with radius and length)
00310     // - init cylinder with odehandle, mass and osghandle
00311     // - rotate and place body (here by 90° around the y-axis)
00312     // - set texture for cylinder
00313     // - put it into object[0]
00314     Capsule* cap = new Capsule(width/2, length);
00315     cap->init(odeHandle, cmass, osgHandle);    
00316     cap->setPose(Matrix::rotate(M_PI/2, 0, 1, 0) * pose);
00317     cap->getOSGPrimitive()->setTexture("Images/wood.rgb");
00318     object[0]=cap;
00319 
00320     // create bumper if required
00321     // - create cylinder with radius and length
00322     // - position bumper relative to main body 
00323     //  (using transform object "glues" it together without using joints, see ODE documentation)
00324     // - init cylinder with odehandle, mass and osghandle
00325     if (conf.bumper){    
00326       for (int i=0; i<number_bumpers; i++){
00327         bumper[i].bump = new Capsule(width/4, 2*radius+width/2);      
00328         bumper[i].trans = new Transform(object[0], bumper[i].bump, 
00329                                         Matrix::rotate(M_PI/2.0, Vec3(1, 0, 0)) * 
00330                                         Matrix::translate(0, 0, i==0 ? -(length/2) : (length/2)));
00331         bumper[i].trans->init(odeHandle, 0, osgHandle); 
00332       }
00333     }
00334 
00335     // create wheel bodies
00336     OsgHandle osgHandleWheels(osgHandle);    // new osghandle with color for wheels
00337     osgHandleWheels.color = Color(1.0,1.0,1.0); 
00338     for (int i=1; i<3; i++) {
00339       if(conf.sphereWheels) { // for spherical wheels
00340         Sphere* wheel = new Sphere(radius);      // create spheres
00341         wheel->init(odeHandle, wmass, osgHandleWheels); // init with odehandle, mass, and osghandle
00342       
00343         wheel->setPose(Matrix::rotate(M_PI/2.0, 1, 0, 0) * 
00344                        Matrix::translate(wheeloffset, (i==2 ? -1 : 1) * (width*0.5+wheelthickness), 0) *
00345                        pose); // place wheels
00346         wheel->getOSGPrimitive()->setTexture("Images/tire.rgb"); // set texture for wheels
00347         object[i] = wheel;
00348       }else{ // for "normal" wheels
00349         //       Cylinder* wheel = new Cylinder(radius);      
00350         //       wheel->init(odeHandle, wmass, osgHandleWheels);
00351       
00352         //       wheel->setPose(Matrix::rotate(M_PI/2.0, Vec3(1,0,0)) * 
00353         //                   Matrix::translate(wheeloffset, (i==2 ? -1 : 1) * (width*0.5+wheelthickness), 0)*
00354         //                   pose);
00355         //       object[i] = wheel;
00356       }
00357     }
00358   
00359     // set joints between wheels and body (see ODE documentation)
00360     // - create joint
00361     // - init joint
00362     // - set stop parameters
00363     for (int i=0; i<2; i++) {
00364       joint[i] = new Hinge2Joint(object[0], object[i+1], object[i+1]->getPosition(), 
00365                                  Axis(0, 0, 1)*pose, Axis(0, -1, 0)*pose);
00366       joint[i]->init(odeHandle, osgHandleWheels, true, 2.01 * radius);
00367       // set stops to make sure wheels always stay in alignment
00368       joint[i]->setParam(dParamLoStop,0);
00369       joint[i]->setParam(dParamHiStop,0);
00370     }
00371 
00372     // initialize sensorbank (for use of infrared sensors)
00373     irSensorBank.init(odeHandle, osgHandle);
00374 
00375     if (conf.irFront){ // add front infrared sensors to sensorbank if required
00376       for(int i=-1; i<2; i+=2){
00377         IRSensor* sensor = new IRSensor();
00378         irSensorBank.registerSensor(sensor, object[0], 
00379                                     Matrix::rotate(i*M_PI/10, Vec3(0,0,1)) * 
00380                                     Matrix::translate(0,i*width/10,length/2 + width/2 - width/60 ), 
00381                                     conf.irRange, RaySensor::drawAll);
00382       }
00383     }
00384     // TODO Back , Side sensors
00385 
00386     created=true;
00387   }; 
00388 
00389 
00390   /** destroys vehicle and space
00391    */
00392   void Nimm2::destroy(){
00393     if (created){
00394       for (int i=0; i<3; i++){
00395         if(object[i]) delete object[i];
00396       }
00397       for (int i=0; i<2; i++){
00398         if(joint[i]) delete joint[i];
00399       }
00400       for (int i=0; i<2; i++){
00401         if(bumper[i].bump) delete bumper[i].bump;
00402         if(bumper[i].trans) delete bumper[i].trans;
00403       }
00404       irSensorBank.clear();
00405       dSpaceDestroy(odeHandle.space);
00406     }
00407     created=false;
00408   }
00409 
00410 }
00411 

Generated on Tue Apr 4 19:05:03 2006 for Robotsystem from Robot Group Leipzig by  doxygen 1.4.5