00001 /*!@file BeoSub/SubSim.C Sub Simulator */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // // See http://iLab.usc.edu for information about this project. // 00006 // //////////////////////////////////////////////////////////////////// // 00007 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00008 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00009 // in Visual Environments, and Applications'' by Christof Koch and // 00010 // Laurent Itti, California Institute of Technology, 2001 (patent // 00011 // pending; application number 09/912,225 filed July 23, 2001; see // 00012 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00013 // //////////////////////////////////////////////////////////////////// // 00014 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00015 // // 00016 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00017 // redistribute it and/or modify it under the terms of the GNU General // 00018 // Public License as published by the Free Software Foundation; either // 00019 // version 2 of the License, or (at your option) any later version. // 00020 // // 00021 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00022 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00023 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00024 // PURPOSE. See the GNU General Public License for more details. // 00025 // // 00026 // You should have received a copy of the GNU General Public License // 00027 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00028 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00029 // Boston, MA 02111-1307 USA. // 00030 // //////////////////////////////////////////////////////////////////// // 00031 // 00032 // Primary maintainer for this file: Lior Elazary <elazary@usc.edu> 00033 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/BeoSub/SubSim.C $ 00034 // $Id: SubSim.C 11565 2009-08-09 02:14:40Z rand $ 00035 // 00036 00037 #include "BeoSub/SubSim.H" 00038 #include "Component/OptionManager.H" 00039 #include "Util/MathFunctions.H" 00040 #include "Util/Assert.H" 00041 #include "rutz/compat_snprintf.h" 00042 #include "Image/MatrixOps.H" 00043 #include <stdio.h> 00044 #include <stdlib.h> 00045 #include <signal.h> 00046 00047 00048 namespace { 00049 00050 void nearCallback (void *data, dGeomID o1, dGeomID o2){ 00051 SubSim *subSim = (SubSim *)data; 00052 const int MaxContacts = 10; 00053 00054 //create a contact joint to simulate collisions 00055 dContact contact[MaxContacts]; 00056 int nContacts = dCollide (o1,o2,MaxContacts, 00057 &contact[0].geom,sizeof(dContact)); 00058 for (int i=0; i<nContacts; i++) { 00059 contact[i].surface.mode = dContactSoftCFM ; //| dContactBounce; // | dContactSoftCFM; 00060 contact[i].surface.mu = 0.5; 00061 contact[i].surface.mu2 = 0.5; 00062 contact[i].surface.bounce = 0.01; 00063 contact[i].surface.bounce_vel = 0.01; 00064 contact[i].surface.soft_cfm = 0.001; 00065 00066 dJointID c = dJointCreateContact (subSim->getWorld(), 00067 subSim->getContactgroup(),&contact[i]); 00068 dJointAttach (c, 00069 dGeomGetBody(contact[i].geom.g1), 00070 dGeomGetBody(contact[i].geom.g2)); 00071 } 00072 } 00073 } 00074 00075 // ###################################################################### 00076 SubSim::SubSim(OptionManager& mgr, const std::string& descrName, 00077 const std::string& tagName, bool showWorld) : 00078 ModelComponent(mgr, descrName, tagName), 00079 itsWaterLevel(4.57), //15 feet of water 00080 itsSubLength(1.5), //the length of sub in meters 00081 itsSubRadius(0.2), //the radius of the sub in meters 00082 itsSubWeight(30), // the weight of the sub in kg 00083 vp(new ViewPort("SubSim")), 00084 itsPanTruster(0), 00085 itsTiltTruster(0), 00086 itsForwardTruster(0), 00087 itsUpTruster(0), 00088 itsXPos(0), 00089 itsYPos(0), 00090 itsDepth(0), 00091 itsRoll(0), 00092 itsPitch(0), 00093 itsYaw(0), 00094 itsWorldView(true), 00095 itsShowWorld(showWorld), 00096 itsWorldDisp(NULL) 00097 { 00098 vp->isSubSim = true; 00099 00100 if (itsShowWorld) 00101 { 00102 itsWorldDisp = new XWinManaged(vp->getDims(), -1, -1, "World View"); 00103 } 00104 00105 pthread_mutex_init(&itsDispLock, NULL); 00106 00107 } 00108 00109 SubSim::~SubSim() 00110 { 00111 dSpaceDestroy(space); 00112 dWorldDestroy(world); 00113 00114 delete vp; 00115 delete itsWorldDisp; 00116 pthread_mutex_destroy(&itsDispLock); 00117 } 00118 00119 void SubSim::start2() 00120 { 00121 // setDrawStuff(); 00122 world = dWorldCreate(); 00123 space = dHashSpaceCreate(0); 00124 contactgroup = dJointGroupCreate(0); 00125 ground = dCreatePlane(space, 0, 0, 1, 0); 00126 dWorldSetGravity(world,0,0,0); 00127 00128 dWorldSetCFM (world,1e-6); 00129 dWorldSetERP (world,1); 00130 //dWorldSetAutoDisableFlag (world,1); 00131 dWorldSetContactMaxCorrectingVel (world,0.1); 00132 //set the contact penetration 00133 dWorldSetContactSurfaceLayer(world, 0.001); 00134 00135 00136 makeSub(); 00137 00138 //set the viewpoint 00139 double xyz[3] = {0 , -3.0, 15}; 00140 double hpr[3] = {90.0,-45,0.0}; 00141 vp->dsSetViewpoint (xyz,hpr); 00142 00143 } 00144 00145 void SubSim::makeSub() 00146 { 00147 dMass mass; 00148 itsSubBody = dBodyCreate(world); 00149 //pos[0] = 0; pos[1] = 1.0*5; pos[2] = 1.80; 00150 00151 // dBodySetPosition(itsSubBody,1.85,4.91*5,3.04); //Sub is 10 feet underwater 00152 dBodySetPosition(itsSubBody,0,0.2*5,1.94); //Sub is 10 feet underwater 00153 00154 dMatrix3 R; 00155 dRFromAxisAndAngle (R,1,0,0,-M_PI/2); 00156 dBodySetRotation(itsSubBody, R); 00157 dMassSetZero(&mass); 00158 dMassSetCappedCylinderTotal(&mass,itsSubWeight,3,itsSubRadius,itsSubLength); 00159 dMassRotate(&mass, R); 00160 dBodySetMass(itsSubBody,&mass); 00161 itsSubGeom = dCreateCCylinder(space, itsSubRadius, itsSubLength); 00162 dGeomSetRotation(itsSubGeom, R); 00163 dGeomSetBody(itsSubGeom, itsSubBody); 00164 } 00165 00166 void SubSim::drawSub() 00167 { 00168 //double r, length; 00169 dReal r, length; 00170 00171 dGeomCCylinderGetParams(itsSubGeom,&r,&length); 00172 00173 vp->dsSetColor(1,1,0); 00174 vp->dsDrawCappedCylinder( 00175 dBodyGetPosition(itsSubBody), 00176 dBodyGetRotation(itsSubBody), 00177 length, 00178 r); 00179 00180 } 00181 00182 void SubSim::drawArena() 00183 { 00184 00185 double pos[3]; 00186 00187 pos[0] = 0; pos[1] = 1.0*5; pos[2] = 2.80; 00188 drawGate(pos); 00189 00190 pos[0] = 0.16*5; pos[1] = 3.8*5; pos[2] = 1.83; 00191 drawBuoy(pos); 00192 00193 pos[0] = 0.66*5; pos[1] = 4.33*5; pos[2] = 0.6; 00194 drawPipeline(0, pos); 00195 00196 pos[0] = 1.16*5; pos[1] = 4.66*5; pos[2] = 0.6; 00197 drawBin(0, pos); 00198 00199 pos[0] = 1.75*5; pos[1] = 4.91*5; pos[2] = 0.6; 00200 drawPipeline(M_PI/4, pos); 00201 00202 pos[0] = 2.33*5; pos[1] = 5.41*5; pos[2] = 0.6; 00203 drawPipeline(0, pos); 00204 00205 pos[0] = 3.0*5; pos[1] = 5.25*5; pos[2] = 0.6; 00206 drawPipeline(-M_PI/4, pos); 00207 00208 pos[0] = 3.5*5; pos[1] = 4.083*5; pos[2] = 0.6; 00209 drawBin(M_PI/2, pos); 00210 00211 pos[0] = 3.5*5; pos[1] = 4.083*5; pos[2] = 1.83; 00212 drawBuoy(pos); 00213 00214 pos[0] = 3.83*5; pos[1] = 4.33*5; pos[2] = 0.6; 00215 drawPipeline(-M_PI/4, pos); 00216 00217 00218 pos[0] = 4.75*5; pos[1] = 3.5*5; pos[2] = 0.6; 00219 drawPinger(pos); 00220 } 00221 00222 00223 void SubSim::drawGate(const double *gatePos) 00224 { 00225 double pos[3]; 00226 double R[12]; 00227 //Gate 00228 vp->dsSetColor(0,0,0); 00229 //Top 00230 pos[0] = gatePos[0]; pos[1] = gatePos[1]; pos[2] = gatePos[2]; 00231 00232 dRFromAxisAndAngle (R,0,1,0,-M_PI/2); 00233 vp->dsDrawCappedCylinder(pos, R, 3.05f, 0.1f); 00234 00235 //side 00236 dRSetIdentity(R); 00237 pos[0] = gatePos[0]-(3.05/2); pos[1] = gatePos[1]; pos[2] = gatePos[2]/2; 00238 vp->dsDrawCappedCylinder(pos, R, 1.83, 0.1); 00239 00240 pos[0] = gatePos[0]+(3.05/2); pos[1] = gatePos[1]; pos[2] = gatePos[2]/2; 00241 vp->dsDrawCappedCylinder(pos, R, 1.83, 0.1); 00242 } 00243 00244 00245 void SubSim::drawBuoy(const double *bouyPos) 00246 { 00247 static int frame = 0; 00248 static bool bouyOn = false; 00249 double pos[3]; 00250 double R[12]; 00251 00252 //start Buoy 00253 //flash buoy 00254 if (frame++ > 5) //this sets the frame rate 00255 { 00256 bouyOn = !bouyOn; 00257 frame = 0; 00258 } 00259 00260 if (bouyOn) 00261 vp->dsSetColor(1,0,0); 00262 else 00263 vp->dsSetColor(0.5,0,0); 00264 pos[0] = bouyPos[0]; pos[1] = bouyPos[1]; pos[2] = bouyPos[2]; 00265 dRSetIdentity(R); 00266 vp->dsDrawSphere(pos, R, 0.20); 00267 double pos1[3]; 00268 vp->dsSetColor(0,0,0); 00269 pos1[0] = pos[0]; pos1[1] = pos[1]; pos1[2] = 0; 00270 vp->dsDrawLine(pos, pos1); 00271 00272 } 00273 00274 void SubSim::drawPipeline(const double ori, const double *pipePos) 00275 { 00276 00277 double sides[3] = {1.2, 0.15, 0.1}; 00278 double R[12]; 00279 00280 dRFromAxisAndAngle (R,0,0,1,ori); 00281 00282 vp->dsSetColor(1,0.5,0); 00283 00284 vp->dsDrawBox(pipePos, R, sides); 00285 } 00286 00287 void SubSim::drawBin(const double ori, const double *binPos) 00288 { 00289 00290 double sides[3]; 00291 double R[12]; 00292 00293 dRFromAxisAndAngle (R,0,0,1,ori); 00294 00295 vp->dsSetColor(1,1,1); 00296 sides[0] = 0.6; sides[1] = 0.8; sides[2] = 0.1; 00297 vp->dsDrawBox(binPos, R, sides); 00298 00299 vp->dsSetColor(0,0,0); 00300 sides[0] = 0.3; sides[1] = 0.6; sides[2] = 0.15; 00301 vp->dsDrawBox(binPos, R, sides); 00302 } 00303 00304 void SubSim::drawPinger(const double *pingerPos) 00305 { 00306 double pos[3]; 00307 double R[12]; 00308 00309 vp->dsSetColor(1,1,1); 00310 pos[0] = pingerPos[0]; pos[1] = pingerPos[1]; pos[1] = pingerPos[2] + 1.2/2; 00311 vp->dsDrawCappedCylinder(pos, R, 1.2, 0.1); 00312 00313 } 00314 00315 00316 void SubSim::handleWinEvents(XEvent& event) 00317 { 00318 } 00319 00320 //void SubSim::updateSensors(const double *pos, const double *R) 00321 void SubSim::updateSensors(const dReal *pos, const dReal *R) 00322 { 00323 itsXPos = pos[0]; 00324 itsYPos = pos[1]; 00325 itsDepth = pos[2]; 00326 itsRoll = atan2(R[9], R[10]) + M_PI/2; //phi correct for initial rotation 00327 itsPitch = asin(-R[8]); //theta 00328 itsYaw = atan2(R[4], R[0]); //greek Y 00329 00330 if (itsYaw < 0) itsYaw += M_PI*2; 00331 // LINFO("(%f,%f) Depth %f, roll %f pitch %f yaw %f", 00332 // itsXPos, itsYPos, itsDepth, 00333 // itsRoll, itsPitch, itsYaw); 00334 00335 } 00336 00337 void SubSim::simLoop() 00338 { 00339 00340 //set the trusters 00341 dBodyAddRelForceAtRelPos(itsSubBody,0,itsUpTruster,0, 0,0,0); 00342 dBodyAddRelTorque(itsSubBody,itsTiltTruster, 0, 0); 00343 dBodyAddRelTorque(itsSubBody,0, itsPanTruster, 0); 00344 dBodyAddRelForceAtRelPos(itsSubBody,0,0,itsForwardTruster, 0,0,0); 00345 00346 //Apply a viscosity water force 00347 applyHydrodynamicForces(0.5); 00348 00349 //Folow the sub with the camera 00350 // const double *bodyPos = dBodyGetPosition(itsSubBody); 00351 //const double *bodyR = dBodyGetRotation(itsSubBody); 00352 const dReal *bodyPos = dBodyGetPosition(itsSubBody); 00353 const dReal *bodyR = dBodyGetRotation(itsSubBody); 00354 00355 updateSensors(bodyPos, bodyR); 00356 00357 dSpaceCollide (space,this,&nearCallback); //check for collisions 00358 00359 dWorldStep(world,0.1); 00360 00361 dJointGroupEmpty (contactgroup); //delete the contact joints 00362 00363 if (itsShowWorld) 00364 { 00365 itsWorldDisp->drawImage(flipVertic(getFrame(0))); 00366 } 00367 } 00368 00369 00370 //! Calculate the water forces on the object 00371 // Obtained from http://ode.org/pipermail/ode/2005-January/014929.html 00372 void SubSim::applyHydrodynamicForces(dReal viscosity) 00373 { 00374 const dReal *lvel = dBodyGetLinearVel(itsSubBody); 00375 const dReal *avel = dBodyGetAngularVel(itsSubBody); 00376 const dReal *R = dBodyGetRotation(itsSubBody); 00377 00378 00379 //Should be the area of the sub 00380 dReal AreaX = 10; 00381 dReal AreaY = 10; 00382 dReal AreaZ = 10; 00383 00384 dReal nx = (R[0] * lvel[0] + R[4] * lvel[1] + R[8] * lvel[2]) * AreaX; 00385 dReal ny = (R[1] * lvel[0] + R[5] * lvel[1] + R[9] * lvel[2]) * AreaY; 00386 dReal nz = (R[2] * lvel[0] + R[6] * lvel[1] + R[10] * lvel[2]) * AreaZ; 00387 00388 dReal temp = -nx * viscosity; 00389 dBodyAddForce(itsSubBody, temp * R[0], temp * R[4], temp * R[8]); 00390 00391 temp = -ny * viscosity; 00392 dBodyAddForce(itsSubBody, temp * R[1], temp * R[5], temp * R[9]); 00393 00394 temp =-nz * viscosity; 00395 dBodyAddForce(itsSubBody, temp * R[2], temp * R[6], temp * R[10]); 00396 00397 nx = (R[0] * avel[0] + R[4] * avel[1] + R[8] * avel[2]) * AreaZ; 00398 ny = (R[1] * avel[0] + R[5] * avel[1] + R[9] * avel[2]) * AreaX; 00399 nz = (R[2] * avel[0] + R[6] * avel[1] + R[10] * avel[2]) * AreaY; 00400 00401 temp = -nx * viscosity; // * 500; //seems to strong 00402 dBodyAddTorque(itsSubBody, temp * R[0], temp * R[4], temp * R[8]); 00403 00404 temp = -ny * viscosity; // * 500; 00405 dBodyAddTorque(itsSubBody, temp * R[1], temp * R[5], temp * R[9]); 00406 00407 temp = -nz * viscosity; // * 500; 00408 dBodyAddTorque(itsSubBody, temp * R[2], temp * R[6], temp * R[10]); 00409 00410 } 00411 00412 Image<PixRGB<byte> > SubSim::getFrame(int camera) 00413 { 00414 const dReal *bodyPos = dBodyGetPosition(itsSubBody); 00415 const dReal *bodyR = dBodyGetRotation(itsSubBody); 00416 00417 double cam_xyz[3], cam_hpr[3] = {0.0,0.0,0.0}; 00418 00419 switch (camera) 00420 { 00421 case 0: //world camera 00422 cam_xyz[0] = bodyPos[0]; 00423 cam_xyz[1] = bodyPos[1]-5; 00424 cam_xyz[2] = 10; 00425 00426 cam_hpr[0] = 90.0; 00427 cam_hpr[1] = -45.0; 00428 cam_hpr[2] = 0.0; 00429 00430 break; 00431 case 1: 00432 cam_xyz[0] = bodyPos[0]; 00433 cam_xyz[1] = bodyPos[1]; 00434 cam_xyz[2] = bodyPos[2]; 00435 00436 cam_hpr[0] = (atan2(bodyR[4], bodyR[0])*180/M_PI) + 90; //yaw 00437 00438 break; 00439 case 2: 00440 cam_xyz[0] = bodyPos[0]; 00441 cam_xyz[1] = bodyPos[1]; 00442 cam_xyz[2] = bodyPos[2]; 00443 00444 cam_hpr[0] = (atan2(bodyR[4], bodyR[0])*180/M_PI) + 90; //yaw 00445 cam_hpr[1] = -90; //yaw 00446 00447 00448 break; 00449 } 00450 pthread_mutex_lock(&itsDispLock); 00451 if (camera != -1) 00452 vp->dsSetViewpoint (cam_xyz,cam_hpr); 00453 vp->initFrame(); 00454 drawSub(); 00455 drawArena(); 00456 vp->updateFrame(); 00457 pthread_mutex_unlock(&itsDispLock); 00458 00459 00460 return vp->getFrame(); 00461 00462 } 00463 00464 void SubSim::getSensors(float &xPos, float &yPos, float &depth, 00465 float &roll, float &pitch, float &yaw) 00466 { 00467 00468 xPos = itsXPos; 00469 yPos = itsYPos; 00470 depth = itsDepth; 00471 roll = itsRoll; 00472 pitch = itsPitch; 00473 yaw = itsYaw; 00474 00475 } 00476 00477 void SubSim::setTrusters(float panTruster, float tiltTruster, float forwardTruster, float upTruster) 00478 { 00479 00480 itsPanTruster = panTruster; 00481 itsTiltTruster = tiltTruster; 00482 itsForwardTruster = forwardTruster; 00483 itsUpTruster = upTruster; 00484 } 00485 00486 // ###################################################################### 00487 /* So things look consistent in everyone's emacs... */ 00488 /* Local Variables: */ 00489 /* indent-tabs-mode: nil */ 00490 /* End: */