worldsim/src/phymarxbot.cpp

00001 /********************************************************************************
00002  *  WorldSim -- library for robot simulations                                   *
00003  *  Copyright (C) 2012-2013                                                     *
00004  *  Gianluca Massera <emmegian@yahoo.it>                                        *
00005  *  Fabrizio Papi <erkito87@gmail.com>                                          *
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 Free Software                 *
00019  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00020  ********************************************************************************/
00021 
00022 #include "phymarxbot.h"
00023 #include "phybox.h"
00024 #include "phycylinder.h"
00025 #include "phyfixed.h"
00026 #include "phyballandsocket.h"
00027 #include "physphere.h"
00028 #include "physuspension.h"
00029 #include "phycompoundobject.h"
00030 #include "phycone.h"
00031 #include "mathutils.h"
00032 
00033 namespace farsa {
00034 
00035 PhyMarXbot::PhyMarXbot( World* w, QString name, const wMatrix& basetm ) : WObject( w, name, basetm, false ) {
00036     // --- reference frame
00037     //  X
00038     //  ^
00039     //  |       ------
00040     //  | ______|____|_________
00041     //  | |_|_| track |_|_|_|_|
00042     //  |  -------------------
00043     //  |  |   battery       |
00044     //  |  -------------------
00045     //  | |_|_| track |_|_|_|_|
00046     //  |       |    |
00047     //  |       ------
00048     //  |
00049     //   ---------------------> Y
00050     
00051     //measures and masses in MKS
00052     // --- chassis containing the battery
00053     real basex = 0.034f, basey = 0.143f, basez = 0.048f, basem = 0.4f;
00054     // --- cylinder body supporting infrared and other modules and turrets
00055     real bodyr = 0.085f, bodyh = 0.0055f, bodym = 0.02f;
00056     // --- inner part of the continous tracks (where the rubber tracks move on)
00057     real axledistance = 0.104f, trackradius = 0.022f, trackheight = 0.0295f,trackm = 0.05f;
00058     // --- the height of the treads on tracks and wheels
00059     real treaddepth = 0.004f;
00060     // --- external wheels (the radius is excluding the tread height)
00061     real wheelr = 0.027f, wheelh = 0.0215f, wheelm = 0.02f;
00062     // --- height of the attachment ring
00063     real attachringh = 0.0285f, attachringm = 0.08f;
00064     // --- module with 12 RGB LEDs
00065     real ledsh = 0.010f, ledsradius = 0.080f, ledsm = 0.03f;
00066 
00067     // --- create a material for marXbot
00068     w->materials().createMaterial( "marXbotMaterial" );
00069     w->materials().setProperties( "marXbotMaterial", "default", 0.0f, 0.0f, 0.01f, 0.01f, true );
00070     w->materials().createMaterial( "marXbotTire" );
00071     w->materials().setProperties( "marXbotTire", "default", 1.2f, 0.9f, 0.01f, 0.01f, true );
00072 
00073     // --- create the body of the base of the marxbot
00074     QVector<PhyObject*> objs;
00075     wMatrix tm = wMatrix::identity();
00076     // battery container
00077     PhyObject* obj = new PhyBox( basex, basey, basez, w );
00078     tm.w_pos[2] = basez/2.0f + 0.015f;
00079     obj->setMass( basem );
00080     obj->setMatrix( tm );
00081     objs << obj;
00082     // cylinder body
00083     obj = new PhyCylinder( bodyr, bodyh, w );
00084     obj->setMass( bodym );
00085     tm = wMatrix::yaw( toRad(90.0f) );
00086     tm.w_pos[2] = 0.015f + basez + bodyh/2.0f;
00087     obj->setMatrix( tm );
00088     objs << obj;
00089     // right track
00090     obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
00091     tm = wMatrix::identity();
00092     tm.w_pos[0] = (basex + trackheight)/2.0f;
00093     tm.w_pos[2] = trackradius + treaddepth;
00094     obj->setMass( trackm );
00095     obj->setMatrix( tm );
00096     objs << obj;
00097     obj = new PhyCylinder( trackradius, trackheight, w );
00098     obj->setMass( wheelm );
00099     tm.w_pos[1] = axledistance/2.0;
00100     obj->setMatrix( tm );
00101     objs << obj;
00102     obj = new PhyCylinder( trackradius, trackheight, w );
00103     obj->setMass( wheelm );
00104     tm.w_pos[1] = -axledistance/2.0;
00105     obj->setMatrix( tm );
00106     objs << obj;
00107     // left track
00108     obj = new PhyBox( trackheight, axledistance, trackradius*2.0f, w );
00109     tm = wMatrix::identity();
00110     tm.w_pos[0] = -(basex + trackheight)/2.0f;
00111     tm.w_pos[2] = trackradius + treaddepth;
00112     obj->setMass( trackm );
00113     obj->setMatrix( tm );
00114     objs << obj;
00115     obj = new PhyCylinder( trackradius, trackheight, w );
00116     obj->setMass( wheelm );
00117     tm.w_pos[1] = axledistance/2.0;
00118     obj->setMatrix( tm );
00119     objs << obj;
00120     obj = new PhyCylinder( trackradius, trackheight, w );
00121     obj->setMass( wheelm );
00122     tm.w_pos[1] = -axledistance/2.0;
00123     obj->setMatrix( tm );
00124     objs << obj;
00125     // merge all togheter
00126     base = new PhyCompoundObject( objs, w );
00127     base->setMaterial("marXbotMaterial");
00128     base->setOwner( this, false );
00129     base->setMatrix( basetm );
00130     
00131     // --- create the two external wheels
00132     //     they are motorized and they move the robot
00133     //     and create four spheres for supporting the tracks
00134     // NOTE: the tracks are not simulated, they are just rigid bodies and
00135     //       the four sphere move freely in order to approximate the real movement
00136     // --- position of wheels and their IDs in the vector
00137     //          +-----+
00138     //       |3||     ||2|
00139     //     |1|  |     |  |0|
00140     //       |5||     ||4|
00141     //          +-----+
00142     //  --------------------> X
00143     // arrays of X and Y offsets for calculate the positions
00144     double xoffs[6] = { 1, -1,  1, -1,  1, -1 };
00145     double yoffs[6] = { 0,  0,  1,  1, -1, -1 };
00146     PhyObject* awheel;
00147     PhyJoint* joint;
00148     for( int i=0; i<6; i++ ) {
00149         // --- relative to base
00150         wMatrix wtm = wMatrix::identity();
00151         wtm.w_pos = wVector(
00152             xoffs[i] * (basex + trackheight)/2.0f + (yoffs[i]==0 ? xoffs[i]*(trackheight/2.0+wheelh/2.0f+0.006f) : 0.0f),
00153             yoffs[i] * (axledistance/2.0f),
00154             0.0f );
00155         if ( i<2 ) {
00156             // the two motorized wheels
00157             wtm.w_pos[2] = wheelr;
00158             awheel = new PhyCylinder( wheelr, wheelh, w );
00159         } else {
00160             // the four sphere supporting the track
00161             wtm.w_pos[2] = treaddepth;
00162             awheel = new PhySphere( treaddepth, w );
00163         }
00164         wheelstm.append( wtm );
00165         awheel->setMass( wheelm );
00166         awheel->setColor( Qt::blue );
00167         awheel->setMaterial( "marXbotTire" );
00168         awheel->setOwner( this, false );
00169         awheel->setMatrix( wtm * basetm );
00170         wheels.append( awheel );
00171         
00172         //--- create the joints
00173         if ( i<2 ) {
00174             // the two motorized wheels
00175             joint = new PhySuspension(
00176                 base->matrix().x_ax, // rotation axis
00177                 wheels[i]->matrix().w_pos,
00178                 base->matrix().z_ax, // suspension 'vertical' axis
00179                 base, wheels[i] );
00180             joint->dofs()[0]->disableLimits();
00181         } else {
00182             // the four sphere supporting the track
00183             joint = new PhyBallAndSocket(
00184                 wheels[i]->matrix().w_pos,
00185                 base, wheels[i] );
00186         }
00187         joint->setOwner( this, false );
00188         joint->updateJointInfo();
00189         wheelJoints.append( joint );
00190     }
00191 
00192     // create the motor controller
00193     QVector<PhyDOF*> motors;
00194     motors << wheelJoints[0]->dofs()[0] << wheelJoints[1]->dofs()[0];
00195     wheelsCtrl = new WheelMotorController( motors, w );
00196     wheelsCtrl->setOwner( this, false );
00197 #ifdef __GNUC__
00198     #warning QUI DECIDERE PER LE VELOCITÀ MASSIME E MINIME DELLE RUOTE
00199 #endif
00200     wheelsCtrl->setSpeedLimits( -10.0, -10.0, 10.0, 10.0 );
00201 
00202     // --- create the attachment module with the 12 RGB LEDs part
00203     objs.clear();
00204     obj = new PhyCone( bodyr, attachringh+0.010f, w );
00205     obj->setMass( attachringm );
00206     tm = wMatrix::identity();
00207     tm.w_pos[0] = 0.005f;
00208     obj->setMatrix( tm );
00209     objs << obj;
00210     obj = new PhyCone( bodyr, attachringh+0.010f, w );
00211     obj->setMass( attachringm );
00212     tm = wMatrix::roll( toRad(180.0f) );
00213     tm.w_pos[0] = -0.005f;
00214     obj->setMatrix( tm );
00215     objs << obj;
00216     obj = new PhyCylinder( ledsradius, ledsh, w );
00217     obj->setMass( ledsm );
00218     obj->setTexture( "marXbot_12leds" );
00219     obj->setUseColorTextureOfOwner( false );
00220     tm.w_pos[0] = attachringh/2.0f + ledsh/2.0f + 0.0015f;
00221     obj->setMatrix( tm );
00222     objs << obj;
00223     // merge all toghether
00224     attachring = new PhyCompoundObject( objs, w );
00225     attachring->setMaterial("marXbotMaterial");
00226     attachring->setOwner( this, false );
00227     attachring->setUseColorTextureOfOwner( false );
00228     attachringtm = wMatrix::yaw( toRad(-90.0f) );
00229     attachringtm.w_pos[2] = 0.015f + basez + bodyh + attachringh/2.0f + 0.0015f;
00230     attachring->setMatrix( attachringtm * basetm );
00231     // --- create the joint for sensing the force
00232     forcesensor = new PhyFixed( base, attachring, w );
00233     forcesensor->setOwner( this, false );
00234 
00235     // Creating the proximity IR sensors
00236     QVector<SingleIR> sensors;
00237 
00238 #ifdef __GNUC__
00239     #warning QUI DECIDERE PER I RANGE/APERTURE E LE POSIZIONI (SPECIE PER I GROUND). INOLTRE IL CENTRO DI MASSA DEL ROBOT È SUL TAVOLO, SOTTO LA BASE: NON È TROPPO BASSO?
00240 #endif
00241     // Adding the sensors. The marxbot has 24 proximity infrared sensors
00242     for (unsigned int i = 0; i < 24; i++) {
00243         const double curAngle = double(i) * (360.0 / 24.0) + ((360.0 / 24.0) / 2.0);
00244         const double radius = bodyr;
00245 
00246         wMatrix mtr = wMatrix::yaw(deg2rad(curAngle + 90.0)) * wMatrix::pitch(deg2rad(90.0f));
00247         mtr.w_pos.x = radius * cos(deg2rad(curAngle));
00248         mtr.w_pos.y = radius * sin(deg2rad(curAngle));
00249         mtr.w_pos.z = 0.015f + basez + bodyh/2.0f;
00250 
00251         sensors.append(SingleIR(base, mtr, 0.02, 0.1, 10.0, 5));
00252     }
00253     proximityIR = new SimulatedIRProximitySensorController(world(), sensors);
00254 
00255     // Now creating the ground IR sensors below the battery pack
00256     sensors.clear();
00257     wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
00258     const double distFromBorder = 0.003;
00259 
00260     // Adding the sensors. The marxbot has 4 ground infrared sensors below the battery pack
00261     mtr.w_pos = wVector(basex / 2.0f - distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
00262     sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
00263     mtr.w_pos = wVector(basex / 2.0f - distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
00264     sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
00265     mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, basey / 2.0f - distFromBorder, 0.015f);
00266     sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
00267     mtr.w_pos = wVector(-basex / 2.0f + distFromBorder, -basey / 2.0f + distFromBorder, 0.015f);
00268     sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
00269     groundBottomIR = new SimulatedIRGroundSensorController(world(), sensors);
00270 
00271     // Creating the ground IR sensors below the base
00272     sensors.clear();
00273 
00274     // Adding the sensors. The marxbot has 8 ground infrared sensors below the base
00275     for (unsigned int i = 0; i < 8; i++) {
00276         const double curAngle = double(i) * (360.0 / 8.0);
00277         const double radius = bodyr - 0.003;
00278 
00279         wMatrix mtr = wMatrix::yaw(deg2rad(180.0));
00280         mtr.w_pos.x = radius * cos(deg2rad(curAngle));
00281         mtr.w_pos.y = radius * sin(deg2rad(curAngle));
00282         mtr.w_pos.z = 0.015f + basez;
00283 
00284         sensors.append(SingleIR(base, mtr, 0.0, mtr.w_pos.z + 0.005, 0.0, 1));
00285     }
00286     groundAroundIR = new SimulatedIRGroundSensorController(world(), sensors);
00287     
00288     w->pushObject( this );
00289 }
00290 
00291 PhyMarXbot::~PhyMarXbot() {
00292     foreach( PhyJoint* susp, wheelJoints ) {
00293         delete susp;
00294     }
00295     foreach( PhyObject* w, wheels ) {
00296         delete w;
00297     }
00298     delete wheelsCtrl;
00299     delete forcesensor;
00300     delete attachring;
00301     delete base;
00302     delete proximityIR;
00303 }
00304 
00305 void PhyMarXbot::preUpdate()
00306 {
00307     // Updating motors
00308     if (wheelsCtrl->isEnabled()) {
00309         wheelsCtrl->update();
00310     }
00311 }
00312 
00313 void PhyMarXbot::postUpdate()
00314 {
00315     // Updating sensors
00316     if (proximityIR->isEnabled()) {
00317         proximityIR->update();
00318     }
00319     if (groundBottomIR->isEnabled()) {
00320         groundBottomIR->update();
00321     }
00322     if (groundAroundIR->isEnabled()) {
00323         groundAroundIR->update();
00324     }
00325 }
00326 
00327 void PhyMarXbot::setProximityIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
00328 {
00329     proximityIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
00330 }
00331 
00332 void PhyMarXbot::setGroundBottomIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
00333 {
00334     groundBottomIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
00335 }
00336 
00337 void PhyMarXbot::setGroundAroundIRSensorsGraphicalProperties(bool drawSensor, bool drawRay, bool drawRealRay)
00338 {
00339     groundAroundIR->setGraphicalProperties(drawSensor, drawRay, drawRealRay);
00340 }
00341 
00342 void PhyMarXbot::changedMatrix() {
00343     wMatrix tm = matrix();
00344     base->setMatrix( tm );
00345     for( int i=0; i<wheels.size(); i++ ) {
00346         wheels[i]->setMatrix( wheelstm[i] * tm );
00347     }
00348     foreach( PhyJoint* ajoint, wheelJoints ) {
00349         ajoint->updateJointInfo();
00350     }
00351     attachring->setMatrix( attachringtm * tm );
00352     forcesensor->updateJointInfo();
00353 }
00354 
00355 } // end namespace farsa