SeaBee3Simulator.C

Go to the documentation of this file.
00001 /*!@file Robots/SeaBeeIII/SeaBee3Simulator.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.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Randolph Voorhies <voorhies at usc dot edu>
00034 
00035 #include "Robots/SeaBeeIII/SeaBee3Simulator.H"
00036 #include "Component/OptionManager.H"
00037 #include "Util/MathFunctions.H"
00038 #include "Util/Assert.H"
00039 #include "rutz/compat_snprintf.h"
00040 #include "Image/MatrixOps.H"
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <signal.h>
00044 
00045 
00046 namespace {
00047 
00048   void nearCallback (void *data, dGeomID o1, dGeomID o2){
00049     SeaBee3Simulator *subSim = (SeaBee3Simulator *)data;
00050     const int MaxContacts = 10;
00051 
00052     //create a contact joint to simulate collisions
00053     dContact contact[MaxContacts];
00054     int nContacts = dCollide (o1,o2,MaxContacts,
00055         &contact[0].geom,sizeof(dContact));
00056     for (int i=0; i<nContacts; i++) {
00057       contact[i].surface.mode = dContactSoftCFM ; //| dContactBounce; // | dContactSoftCFM;
00058       contact[i].surface.mu = 0.5;
00059       contact[i].surface.mu2 = 0.5;
00060       contact[i].surface.bounce = 0.01;
00061       contact[i].surface.bounce_vel = 0.01;
00062       contact[i].surface.soft_cfm = 0.001;
00063 
00064       dJointID c = dJointCreateContact (subSim->getWorld(),
00065           subSim->getContactgroup(),&contact[i]);
00066       dJointAttach (c,
00067           dGeomGetBody(contact[i].geom.g1),
00068           dGeomGetBody(contact[i].geom.g2));
00069     }
00070   }
00071 }
00072 
00073 // ######################################################################
00074 SeaBee3Simulator::SeaBee3Simulator(OptionManager& mgr, const std::string& descrName,
00075     const std::string& tagName) :
00076   RobotBrainComponent(mgr, descrName, tagName),
00077   itsPoolDepth(4.5),
00078   itsPoolLength(70),
00079   itsPoolWidth(20),
00080   itsWaterLevel(4.57), //15 feet of water
00081   itsSubLength(1.5), //the length of sub in meters
00082   itsSubRadius(0.2), //the radius of the sub in meters
00083   itsSubWeight(20), // the weight of the sub in kg
00084   vp(new ViewPort("SeaBee3Simulator", "sea_floor.ppm", "sky.ppm", true, true)),
00085   itsWorldView(true),
00086   itsShowWorld(true),
00087   itsWorldDisp(NULL),
00088   itsCameraUpdateTime(.0333333),
00089   itsBeeStemUpdateTime(.1),
00090   itsSimXPos(0),
00091   itsSimYPos(0),
00092   itsSimDepth(0),
00093   itsSimRoll(0),
00094   itsSimPitch(0),
00095   itsSimYaw(0),
00096   itsPIDsEnabled(false),
00097   itsDepthPID(new PID<float>(0,0,0,0,100)),
00098   itsHeadingPID(new PID<Angle>(0,0,0,0,100))
00099 {
00100   dInitODE();
00101 
00102   Initialized = false;
00103 
00104   //  vp->isSubSim = true;
00105 
00106   itsWorldDisp = new XWinManaged(vp->getDims(), -1, -1, "World View");
00107 
00108   pthread_mutex_init(&itsDispLock, NULL);
00109 
00110   world = dWorldCreate();
00111   space = dHashSpaceCreate(0);
00112   contactgroup = dJointGroupCreate(0);
00113   ground = dCreatePlane(space, 0, 0, 1, 0);
00114 
00115   //Initialize the world's gravity
00116   dWorldSetGravity(world,0,0,-9.81);
00117 
00118   dWorldSetCFM (world,1e-6);
00119   dWorldSetERP (world,1);
00120   //dWorldSetAutoDisableFlag (world,1);
00121   dWorldSetContactMaxCorrectingVel (world,0.1);
00122   //set the contact penetration
00123   dWorldSetContactSurfaceLayer(world, 0.001);
00124 
00125   makeSub();
00126 
00127   //set the viewpoint
00128   double xyz[3] = {0 , -3.0, 15};
00129   double hpr[3] = {90.0,-45,0.0};
00130   vp->dsSetViewpoint (xyz,hpr);
00131 
00132   arenaWallTexture    = new Texture("etc/textures/sea_floor.ppm");
00133   waterSurfaceTexture = new Texture("etc/textures/water.ppm");
00134 
00135   itsJSValues.resize(8);
00136   itsButValues.resize(20);
00137 
00138   // init trigger values
00139   itsJSValues[4] = -100;
00140   itsJSValues[5] = -100;
00141 }
00142 
00143 SeaBee3Simulator::~SeaBee3Simulator()
00144 {
00145   dSpaceDestroy(space);
00146   dWorldDestroy(world);
00147 
00148   delete vp;
00149   delete itsWorldDisp;
00150   pthread_mutex_destroy(&itsDispLock);
00151 }
00152 
00153 void SeaBee3Simulator::registerTopics()
00154 {
00155   registerPublisher("RetinaMessageTopic");
00156   registerPublisher("BeeStemMessageTopic");
00157   registerSubscription("XBox360RemoteControlMessageTopic");
00158   registerSubscription("BeeStemConfigTopic");
00159 
00160 }
00161 
00162 void SeaBee3Simulator::makeSub()
00163 {
00164   dMass mass;
00165   itsSubBody = dBodyCreate(world);
00166   //pos[0] = 0; pos[1] = 1.0*5; pos[2] = 1.80;
00167 
00168   //dBodySetPosition(itsSubBody,10,5,1.94); //Sub is 10 feet underwater
00169 
00170   //Initialize the position of the submarine to (10, 5) and just below the surface
00171   dBodySetPosition(itsSubBody,10,5,itsPoolDepth-.1);
00172 
00173   //Turn the submarine towards the long end of the pool
00174   dMatrix3 R;
00175   dRFromAxisAndAngle (R,1,0,0,-M_PI/2);
00176   dBodySetRotation(itsSubBody, R);
00177 
00178   //Set the submarine's mass and geometry
00179   dMassSetZero(&mass);
00180   dMassSetCappedCylinderTotal(&mass,itsSubWeight,3,itsSubRadius,itsSubLength);
00181   dMassRotate(&mass, R);
00182   dBodySetMass(itsSubBody,&mass);
00183   itsSubGeom = dCreateCCylinder(space, itsSubRadius, itsSubLength);
00184   dGeomSetRotation(itsSubGeom, R);
00185   dGeomSetBody(itsSubGeom, itsSubBody);
00186 }
00187 
00188 void SeaBee3Simulator::drawSub()
00189 {
00190   dReal r, length;
00191 
00192   dGeomCCylinderGetParams(itsSubGeom,&r,&length);
00193 
00194   vp->dsSetColor(1,1,0);
00195   vp->dsDrawCappedCylinder(
00196       dBodyGetPosition(itsSubBody),
00197       dBodyGetRotation(itsSubBody),
00198       length,
00199       r);
00200 }
00201 
00202 void SeaBee3Simulator::drawArena()
00203 {
00204   double pos[3];
00205 
00206   drawWaterSurface();
00207   drawPool();
00208 
00209   pos[0] = 10; pos[1] = 10; pos[2] = 2.80;
00210   drawGate(pos);
00211 
00212   pos[0] = 11; pos[1] = 17; pos[2] = 1.83;
00213   drawBuoy(pos);
00214 
00215   pos[0] = 10; pos[1] = 20; pos[2] = 0.6;
00216   drawPipeline(M_PI/2.0, pos);
00217 
00218   pos[0] = 10; pos[1] = 25; pos[2] = 0.6;
00219   drawBin(0, pos);
00220 
00221   pos[0] = 10; pos[1] = 27; pos[2] = 0.6;
00222   drawPipeline(M_PI/4.0, pos);
00223 
00224   pos[0] = 12; pos[1] = 29; pos[2] = 0.6;
00225   drawPipeline(M_PI/2.0, pos);
00226 
00227   pos[0] = 12; pos[1] = 32; pos[2] = 0.6;
00228   drawPipeline(-M_PI/4, pos);
00229 
00230   pos[0] = 8; pos[1] = 37; pos[2] = 0.6;
00231   drawBin(M_PI/2, pos);
00232 
00233   pos[0] = 8; pos[1] = 37; pos[2] = 1.83;
00234   drawBuoy(pos);
00235 
00236 //  pos[0] = 60; pos[1] = 4.33*5; pos[2] = 0.6;
00237 //  drawPipeline(-M_PI/4, pos);
00238 //
00239 //  pos[0] = 70; pos[1] = 3.5*5; pos[2] = 0.6;
00240 //  drawPinger(pos);
00241 }
00242 
00243 
00244 void SeaBee3Simulator::drawGate(const double *gatePos)
00245 {
00246   double gateHeight = 3.0; //The length of the gate's side tubes
00247 
00248   double pos[3];
00249   double R[12];
00250 
00251   //Gate Color
00252   vp->dsSetColor(0,0,0);
00253 
00254   //Top
00255   pos[0] = gatePos[0]; pos[1] = gatePos[1]; pos[2] = gatePos[2];
00256   dRFromAxisAndAngle (R,0,1,0,-M_PI/2);
00257   vp->dsDrawCappedCylinder(pos, R, 3.05f, 0.1f);
00258 
00259   //Sides
00260   dRSetIdentity(R);
00261   pos[0] = gatePos[0]-(3.05/2); pos[1] = gatePos[1]; pos[2] = gatePos[2] - gateHeight/2;
00262   vp->dsDrawCappedCylinder(pos, R, gateHeight, 0.1);
00263 
00264   pos[0] = gatePos[0]+(3.05/2); pos[1] = gatePos[1]; pos[2] = gatePos[2] - gateHeight/2;
00265   vp->dsDrawCappedCylinder(pos, R, gateHeight, 0.1);
00266 }
00267 
00268 
00269 void SeaBee3Simulator::drawBuoy(const double *bouyPos)
00270 {
00271   static int frame = 0;
00272   static bool bouyOn = false;
00273   double pos[3];
00274   double R[12];
00275 
00276   //start Buoy
00277   //flash buoy
00278   if (frame++ > 5) //this sets the frame rate
00279   {
00280     bouyOn = !bouyOn;
00281     frame = 0;
00282   }
00283 
00284   if (bouyOn)
00285     vp->dsSetColor(1,0,0);
00286   else
00287     vp->dsSetColor(0.5,0,0);
00288   pos[0] = bouyPos[0]; pos[1] = bouyPos[1]; pos[2] = bouyPos[2];
00289   dRSetIdentity(R);
00290   vp->dsDrawSphere(pos, R, 0.20);
00291   double pos1[3];
00292   vp->dsSetColor(0,0,0);
00293   pos1[0] = pos[0]; pos1[1] = pos[1]; pos1[2] = 0;
00294   vp->dsDrawLine(pos, pos1);
00295 }
00296 
00297 void SeaBee3Simulator::drawWaterSurface()
00298 {
00299   //I haven't the slightest clue why this doesn't work.
00300   static double texOff=0.0f;
00301   texOff += 0.1f;
00302 
00303   //Set the water surface texture
00304   glEnable (GL_TEXTURE_2D);
00305 
00306   glBindTexture(GL_TEXTURE_2D, waterSurfaceTexture->getName());
00307 
00308   //Draw the bottom water surface
00309   glBegin(GL_QUADS);
00310   {
00311     glNormal3f(0,0,-1);
00312     glTexCoord2f(0.0f,  0.0f+texOff); glVertex3f( -5.0f,             -5.0f,              itsPoolDepth);
00313     glTexCoord2f(1.0f,  0.0f+texOff); glVertex3f( itsPoolWidth+5.0f, -5.0f,              itsPoolDepth);
00314     glTexCoord2f(1.0f,  1.0f+texOff); glVertex3f( itsPoolWidth+5.0f, itsPoolLength+5.0f, itsPoolDepth);
00315     glTexCoord2f(0.0f,  1.0f+texOff); glVertex3f( -5.0f,             itsPoolLength+5.0f, itsPoolDepth);
00316 
00317     //Draw the top water surface
00318     glNormal3f(0,0,1);
00319     glTexCoord2f(0.0f,  0.0f+texOff); glVertex3f( -5.0f,             -5.0f,              itsPoolDepth);
00320     glTexCoord2f(0.0f,  1.0f+texOff); glVertex3f( -5.0f,             itsPoolLength+5.0f, itsPoolDepth);
00321     glTexCoord2f(1.0f,  1.0f+texOff); glVertex3f( itsPoolWidth+5.0f, itsPoolLength+5.0f, itsPoolDepth);
00322     glTexCoord2f(1.0f,  0.0f+texOff); glVertex3f( itsPoolWidth+5.0f, -5.0f,              itsPoolDepth);
00323   }
00324   glEnd();
00325 
00326   if(texOff > 1.0f) texOff = 0.0f;
00327 }
00328 void SeaBee3Simulator::drawPool()
00329 {
00330   double pos[3];
00331   double R[12];
00332   double sides[3];
00333 
00334   double WallAngle = M_PI/8;
00335 
00336   double WallHeight = itsPoolDepth / cos(WallAngle);
00337 
00338   //Draw far wall
00339   pos[0] = itsPoolWidth/2.0; pos[1] = itsPoolLength; pos[2] = itsPoolDepth/2;
00340   dRFromAxisAndAngle(R, 1,0,0,-WallAngle);
00341   sides[0] = itsPoolWidth*1.5; sides[1] = 0.5; sides[2] = WallHeight;
00342   vp->dsSetTexture(ViewPort::OTHER,arenaWallTexture);
00343   vp->dsDrawBox(pos, R, sides);
00344 
00345   //Draw back wall
00346   pos[0] = itsPoolWidth/2.0; pos[1] = 0; pos[2] = itsPoolDepth/2;
00347   dRFromAxisAndAngle(R, 1,0,0,WallAngle);
00348   sides[0] = itsPoolWidth*1.5; sides[1] = 0.5; sides[2] = WallHeight;
00349   vp->dsSetTexture(ViewPort::OTHER,arenaWallTexture);
00350   vp->dsDrawBox(pos, R, sides);
00351 
00352   //Draw right wall
00353   pos[0] = itsPoolWidth; pos[1] = itsPoolLength/2.0; pos[2] = itsPoolDepth/2;
00354   dRFromAxisAndAngle(R, 0,1,0,WallAngle);
00355   sides[0] = 0.5; sides[1] = itsPoolLength*1.5; sides[2] = WallHeight;
00356   vp->dsSetTexture(ViewPort::OTHER,arenaWallTexture);
00357   vp->dsDrawBox(pos, R, sides);
00358 
00359   //Draw left wall
00360   pos[0] = 0; pos[1] = itsPoolLength/2.0; pos[2] = itsPoolDepth/2;
00361   dRFromAxisAndAngle(R, 0,1,0,-WallAngle);
00362   sides[0] = 0.5; sides[1] = itsPoolLength*1.5; sides[2] = WallHeight;
00363   vp->dsSetTexture(ViewPort::OTHER,arenaWallTexture);
00364   vp->dsDrawBox(pos, R, sides);
00365 }
00366 
00367 void SeaBee3Simulator::drawPipeline(const double ori, const double *pipePos)
00368 {
00369 
00370   double sides[3] = {1.2, 0.15, 0.1};
00371   double R[12];
00372 
00373   dRFromAxisAndAngle (R,0,0,1,ori);
00374 
00375   vp->dsSetColor(1,0.5,0);
00376 
00377   vp->dsDrawBox(pipePos, R, sides);
00378 }
00379 
00380 void SeaBee3Simulator::drawBin(const double ori, const double *binPos)
00381 {
00382 
00383   double sides[3];
00384   double R[12];
00385 
00386   dRFromAxisAndAngle (R,0,0,1,ori);
00387 
00388   vp->dsSetColor(1,1,1);
00389   sides[0] = 0.6; sides[1] = 0.8; sides[2] = 0.1;
00390   vp->dsDrawBox(binPos, R, sides);
00391 
00392   vp->dsSetColor(0,0,0);
00393   sides[0] = 0.3; sides[1] = 0.6; sides[2] = 0.15;
00394   vp->dsDrawBox(binPos, R, sides);
00395 }
00396 
00397 void SeaBee3Simulator::drawPinger(const double *pingerPos)
00398 {
00399   double pos[3];
00400   double R[12];
00401 
00402   vp->dsSetColor(1,1,1);
00403   pos[0] = pingerPos[0]; pos[1] = pingerPos[1]; pos[1] = pingerPos[2] + 1.2/2;
00404   vp->dsDrawCappedCylinder(pos, R, 1.2, 0.1);
00405 
00406 }
00407 
00408 
00409 void SeaBee3Simulator::handleWinEvents(XEvent& event)
00410 {}
00411 
00412 void SeaBee3Simulator::updateSensors(const dReal *pos, const dReal *R)
00413 {
00414   itsSimXPos  = pos[0];
00415   itsSimYPos  = pos[1];
00416   itsSimDepth = 2000 - pos[2] * 100             + randomDoubleFromNormal(3.0);
00417   itsSimRoll  = atan2(R[9], R[10]) + M_PI/2+ randomDoubleFromNormal(5.0); //phi correct for initial rotation
00418   itsSimPitch = asin(-R[8])        + randomDoubleFromNormal(5.0);         //theta
00419   itsSimYaw   = atan2(R[4], R[0]) * 180.0/M_PI  + randomDoubleFromNormal(2.0);         //greek Y
00420 
00421   if (itsSimYaw < 0) itsSimYaw += 360;
00422 
00423 
00424   if(itsCameraTimer.getSecs() > itsCameraUpdateTime)
00425   {
00426     //Grab an image from the forward camera, and publish it as a Retina message
00427     Image<PixRGB<byte> > fwdCameraImage = flipVertic(getFrame(1));
00428 
00429     RobotSimEvents::RetinaMessagePtr fwdRetMsg = new RobotSimEvents::RetinaMessage;
00430     fwdRetMsg->img = Image2Ice(fwdCameraImage);
00431     fwdRetMsg->cameraID = "DwnCamera";
00432 
00433     this->publish("RetinaMessageTopic", fwdRetMsg);
00434 
00435     //Grab an image from the downward camera, and publish it as a Retina message
00436     Image<PixRGB<byte> > dwnCameraImage = flipVertic(getFrame(2));
00437 
00438     RobotSimEvents::RetinaMessagePtr dwnRetMsg = new RobotSimEvents::RetinaMessage;
00439     dwnRetMsg->img = Image2Ice(dwnCameraImage);
00440     dwnRetMsg->cameraID = "FwdCamera";
00441 
00442     this->publish("RetinaMessageTopic", dwnRetMsg);
00443 
00444     itsCameraTimer.reset();
00445   }
00446 
00447   if(itsBeeStemTimer.getSecs() > itsBeeStemUpdateTime)
00448   {
00449     //Create the BeeStem message, and publish it
00450     RobotSimEvents::BeeStemMessagePtr BeeStemMsg = new RobotSimEvents::BeeStemMessage;
00451     BeeStemMsg->accelX           = 0;
00452     BeeStemMsg->accelY           = 0;
00453     BeeStemMsg->accelZ           = 0;
00454     BeeStemMsg->compassHeading   = itsSimYaw;
00455     BeeStemMsg->compassPitch     = itsSimRoll;
00456     BeeStemMsg->compassRoll      = itsSimPitch;
00457     BeeStemMsg->internalPressure = 3000 + randomDoubleFromNormal(3.0);
00458     BeeStemMsg->externalPressure = itsSimDepth;
00459     BeeStemMsg->desiredHeading   = itsDesiredHeading;
00460     BeeStemMsg->desiredDepth     = itsDesiredDepth;
00461     BeeStemMsg->desiredSpeed     = itsDesiredSpeed;
00462     BeeStemMsg->headingK         = itsHeadingK;
00463     BeeStemMsg->headingP         = itsHeadingP;
00464     BeeStemMsg->headingD         = itsHeadingD;
00465     BeeStemMsg->headingI         = itsHeadingI;
00466     BeeStemMsg->headingOutput    = itsHeadingOutput;
00467     BeeStemMsg->depthK           = itsDepthK;
00468     BeeStemMsg->depthP           = itsDepthP;
00469     BeeStemMsg->depthD           = itsDepthD;
00470     BeeStemMsg->depthI           = itsDepthI;
00471     BeeStemMsg->depthOutput      = itsDepthOutput;
00472     BeeStemMsg->killSwitch       = 1;
00473     BeeStemMsg->thruster1        = itsForwardLeftThrusterVal;
00474     BeeStemMsg->thruster2        = itsForwardRightThrusterVal;
00475     BeeStemMsg->thruster3        = itsFrontStrafeThrusterVal;
00476     BeeStemMsg->thruster4        = itsBackStrafeThrusterVal;
00477     BeeStemMsg->thruster5        = itsLeftVertThrusterVal;
00478     BeeStemMsg->thruster6        = itsRightVertThrusterVal;
00479 
00480     this->publish("BeeStemMessageTopic", BeeStemMsg);
00481     itsBeeStemTimer.reset();
00482   }
00483 }
00484 
00485 
00486 void SeaBee3Simulator::evolve() {usleep(10000000);}
00487 
00488 
00489 void SeaBee3Simulator::updateMessage(const RobotSimEvents::EventMessagePtr& eMsg,
00490     const Ice::Current&)
00491 {
00492   // Get an XBox360RemoteControl Message
00493   if(eMsg->ice_isA("::RobotSimEvents::JoyStickControlMessage"))
00494   {
00495     RobotSimEvents::JoyStickControlMessagePtr msg = RobotSimEvents::JoyStickControlMessagePtr::dynamicCast(eMsg);
00496 
00497     itsJSMutex.lock();
00498     if(msg->axis >= 0)
00499       itsJSValues[msg->axis] = msg->axisVal;
00500     if(msg->button >= 0)
00501       itsButValues[msg->button] = msg->butVal;
00502     itsJSMutex.unlock();
00503   }
00504   // Get a BeeStemConfig Message
00505   else if(eMsg->ice_isA("::RobotSimEvents::BeeStemConfigMessage"))
00506   {
00507     RobotSimEvents::BeeStemConfigMessagePtr msg = RobotSimEvents::BeeStemConfigMessagePtr::dynamicCast(eMsg);
00508 
00509 
00510     if(msg->enablePID == 1)
00511     { //Our message contains an instruction to turn on/off the PID
00512 
00513       itsStemMutex.lock();
00514       {
00515         if(msg->enableVal == 1)
00516           itsPIDsEnabled = true;
00517         else
00518           itsPIDsEnabled = false;
00519 
00520         LINFO("PIDEnable=%d", itsPIDsEnabled);
00521       }
00522       itsStemMutex.unlock();
00523 
00524     }
00525     else if(msg->updateHeadingPID == 0 && msg->updateDepthPID == 0)
00526     {
00527 
00528       itsStemMutex.lock();
00529       {
00530         LINFO("Update Pose: %d\n",msg->updateDesiredValue);
00531         if(msg->updateDesiredValue == 1)
00532           itsTargetHeading = msg->desiredHeading;
00533         else if(msg->updateDesiredValue == 2)
00534           itsTargetDepth = msg->desiredDepth;
00535         else if(msg->updateDesiredValue == 3)
00536           itsTargetSpeed = msg->desiredSpeed;
00537       }
00538       itsStemMutex.unlock();
00539 
00540     }
00541     else if(msg->updateDepthPID == 1)
00542     {
00543 
00544       itsStemMutex.lock();
00545       {
00546         itsDepthPID->setPIDPgain(float(msg->depthP) / float(msg->depthK));
00547         itsDepthPID->setPIDIgain(float(msg->depthI) / float(msg->depthK));
00548         itsDepthPID->setPIDDgain(float(msg->depthD) / float(msg->depthK));
00549       }
00550       itsStemMutex.unlock();
00551 
00552     }
00553     else if(msg->updateHeadingPID == 1)
00554     {
00555 
00556       itsStemMutex.lock();
00557       {
00558         itsHeadingPID->setPIDPgain(float(msg->headingP) / float(msg->headingK));
00559         itsHeadingPID->setPIDIgain(float(msg->headingI) / float(msg->headingK));
00560         itsHeadingPID->setPIDDgain(float(msg->headingD) / float(msg->headingK));
00561       }
00562       itsStemMutex.unlock();
00563 
00564     }
00565   }
00566 }
00567 
00568 void SeaBee3Simulator::simLoop()
00569 {
00570   //Add the appropriate forces from the motors
00571   dBodyAddRelForceAtRelPos(itsSubBody,
00572       0,0, itsForwardLeftThrusterVal/10.0,  //Force Vector
00573       -.25, 0, 0);                     //Force Position
00574 
00575   dBodyAddRelForceAtRelPos(itsSubBody,
00576       0,0, itsForwardRightThrusterVal/10.0, //Force Vector
00577       +.25, 0, 0);                     //Force Position
00578 
00579   dBodyAddRelForceAtRelPos(itsSubBody,
00580       itsFrontStrafeThrusterVal/10.0, 0,0,  //Force Vector
00581       0, 0, +.5);                      //Force Position
00582 
00583   dBodyAddRelForceAtRelPos(itsSubBody,
00584       itsBackStrafeThrusterVal/10.0, 0,0,   //Force Vector
00585       0, 0, -.5);                      //Force Position
00586 
00587   dBodyAddRelForceAtRelPos(itsSubBody,
00588       0, itsLeftVertThrusterVal/10.0, 0,    //Force Vector
00589       -.25, 0, 0);                     //Force Position
00590 
00591   dBodyAddRelForceAtRelPos(itsSubBody,
00592       0, itsRightVertThrusterVal/10.0, 0,   //Force Vector
00593       +.25, 0, 0);                     //Force Position
00594 
00595   //Apply a viscosity water force
00596   applyHydrodynamicForces(.2);
00597 
00598   //Update the PID controllers if necessary
00599   updateControllers();
00600 
00601   //Folow the sub with the camera
00602   //  const double *bodyPos = dBodyGetPosition(itsSubBody);
00603   //const double *bodyR = dBodyGetRotation(itsSubBody);
00604   const dReal *bodyPos = dBodyGetPosition(itsSubBody);
00605   const dReal *bodyR = dBodyGetRotation(itsSubBody);
00606 
00607   updateSensors(bodyPos, bodyR);
00608 
00609   dSpaceCollide (space,this,&nearCallback); //check for collisions
00610 
00611   dWorldStep(world,0.1);
00612 
00613   dJointGroupEmpty (contactgroup); //delete the contact joints
00614 
00615   itsWorldDisp->drawImage(flipVertic(getFrame(0)));
00616 }
00617 
00618 
00619 
00620 void SeaBee3Simulator::updateControllers()
00621 {
00622   if(itsPIDsEnabled)
00623     {
00624       float DepthCommand = itsDepthPID->update(itsTargetDepth, itsSimDepth)*100;
00625       itsLeftVertThrusterVal = DepthCommand;
00626       itsRightVertThrusterVal = DepthCommand;
00627       itsDepthOutput = DepthCommand;
00628 
00629       Angle currHeadingAngle(itsSimYaw);
00630       Angle desHeadingAngle(itsTargetHeading);
00631 
00632       float HeadingCommand = (itsHeadingPID->update(desHeadingAngle, currHeadingAngle)).getRadians() * (180.0/M_PI)*100.0;
00633       itsForwardLeftThrusterVal  = -HeadingCommand;
00634       itsForwardRightThrusterVal = HeadingCommand;
00635       itsHeadingOutput = HeadingCommand;
00636     }
00637   else
00638     {
00639       itsJSMutex.lock();
00640       int rightVal = itsJSValues[1]*-1;
00641       int leftVal = itsJSValues[1]*-1;
00642 
00643       int depthVal = int((float(itsJSValues[5]) + 100.0)/2.0 - (float(itsJSValues[4]) + 100.0)/2.0);
00644 
00645       int depthValRight = depthVal;
00646       int depthValLeft = depthVal;
00647 
00648       int frontVal = itsJSValues[2] + itsJSValues[0];
00649       int backVal = itsJSValues[2]*-1 + itsJSValues[0];
00650 
00651       if(itsButValues[5])
00652         {
00653           depthValRight = 75;
00654           depthValLeft = -75;
00655         }
00656       else if(itsButValues[4])
00657         {
00658           depthValRight = -75;
00659           depthValLeft = 75;
00660         }
00661 
00662 
00663       //itsStem->setThruster(FWD_RIGHT_THRUSTER, rightVal);
00664       //itsStem->setThruster(FWD_LEFT_THRUSTER, leftVal);
00665       itsForwardRightThrusterVal = rightVal;
00666       itsForwardLeftThrusterVal = leftVal;
00667 
00668       //itsStem->setThruster(DEPTH_RIGHT_THRUSTER, depthValRight);
00669       //  itsStem->setThruster(DEPTH_LEFT_THRUSTER, depthValLeft);
00670 
00671       itsLeftVertThrusterVal = depthValLeft;
00672       itsRightVertThrusterVal = depthValRight;
00673 
00674       //itsStem->setThruster(STRAFE_FRONT_THRUSTER, frontVal);
00675       //itsStem->setThruster(STRAFE_BACK_THRUSTER, backVal);
00676       itsFrontStrafeThrusterVal = frontVal;
00677       itsBackStrafeThrusterVal = backVal;
00678       itsJSMutex.unlock();
00679     }
00680 }
00681 
00682 
00683 //! Calculate the water forces on the object
00684 // Obtained from http://ode.org/pipermail/ode/2005-January/014929.html
00685 void SeaBee3Simulator::applyHydrodynamicForces(dReal viscosity)
00686 {
00687   const dReal *lvel = dBodyGetLinearVel(itsSubBody);
00688   const dReal *avel = dBodyGetAngularVel(itsSubBody);
00689   const dReal *R = dBodyGetRotation(itsSubBody);
00690 
00691   //Should be the area of the sub
00692   dReal AreaX = 10;
00693   dReal AreaY = 10;
00694   dReal AreaZ = 10;
00695 
00696   dReal nx = (R[0] * lvel[0] + R[4] * lvel[1] + R[8] * lvel[2]) *  AreaX;
00697   dReal ny = (R[1] * lvel[0] + R[5] * lvel[1] + R[9] * lvel[2]) * AreaY;
00698   dReal nz = (R[2] * lvel[0] + R[6] * lvel[1] + R[10] * lvel[2]) * AreaZ;
00699 
00700   dReal temp = -nx * viscosity;
00701   dBodyAddForce(itsSubBody, temp * R[0], temp * R[4], temp * R[8]);
00702 
00703   temp = -ny * viscosity;
00704   dBodyAddForce(itsSubBody, temp * R[1], temp * R[5], temp * R[9]);
00705 
00706   temp =-nz * viscosity;
00707   dBodyAddForce(itsSubBody, temp * R[2], temp * R[6], temp * R[10]);
00708 
00709   nx = (R[0] * avel[0] + R[4] * avel[1] + R[8] * avel[2]) * AreaZ;
00710   ny = (R[1] * avel[0] + R[5] * avel[1] + R[9] * avel[2]) * AreaX;
00711   nz = (R[2] * avel[0] + R[6] * avel[1] + R[10] * avel[2]) * AreaY;
00712 
00713   temp = -nx * viscosity; // * 500; //seems to strong
00714   dBodyAddTorque(itsSubBody, temp * R[0], temp * R[4], temp * R[8]);
00715 
00716   temp = -ny * viscosity; // * 500;
00717   dBodyAddTorque(itsSubBody, temp * R[1], temp * R[5], temp * R[9]);
00718 
00719   temp = -nz * viscosity; // * 500;
00720   dBodyAddTorque(itsSubBody, temp * R[2], temp * R[6], temp * R[10]);
00721 
00722 
00723   const dReal *bodyPos = dBodyGetPosition(itsSubBody);
00724 //  LINFO("DEPTH: %f, PoolDepth: %f", bodyPos[2], itsPoolDepth);
00725 
00726   dMass *subMass = new dMass();
00727   dBodyGetMass(itsSubBody, subMass);
00728 
00729   double TotalBuoyancy = 9.86;
00730 
00731   //Apply buoyancy forces as a piecewise linear function
00732   if(bodyPos[2] <= itsPoolDepth)
00733   {
00734     //The sub is totally in the water, so apply all of the buoyancy
00735     //dBodyAddForce(itsSubBody, 0,0, subMass->mass * TotalBuoyancy);
00736 
00737     dBodyAddForceAtRelPos(itsSubBody,0,0,subMass->mass * TotalBuoyancy,
00738                           0,-0.01,0);
00739   }
00740   else if(bodyPos[2] <= itsPoolDepth + itsSubRadius)
00741   {
00742     //The sub is partially out of the water, so apply only a fraction of the
00743     //total buoyancy
00744  //    dBodyAddForce(itsSubBody, 0, 0,
00745 //         subMass->mass *
00746 //         (TotalBuoyancy *
00747 //          (1 - (bodyPos[2] - itsPoolDepth)/(itsSubRadius) )
00748 //         ));
00749 
00750     dBodyAddForceAtRelPos(itsSubBody,0,0,subMass->mass *
00751                           (TotalBuoyancy *
00752                            (1 - (bodyPos[2] - itsPoolDepth)/(itsSubRadius))),
00753                           0,-0.01,0);
00754   }
00755 
00756 
00757 }
00758 
00759 Image<PixRGB<byte> > SeaBee3Simulator::getFrame(int camera)
00760 {
00761   const dReal *bodyPos = dBodyGetPosition(itsSubBody);
00762   const dReal *bodyR = dBodyGetRotation(itsSubBody);
00763 
00764   double cam_xyz[3], cam_hpr[3] = {0.0,0.0,0.0};
00765 
00766   double roll= (atan2(bodyR[9], bodyR[10]) + M_PI/2.0) * 180.0/M_PI;
00767   double pitch = asin(-bodyR[8]) * 180.0/M_PI;
00768   double yaw = atan2(bodyR[4], bodyR[0]) * 180.0/M_PI;
00769 
00770   switch (camera)
00771   {
00772     case 0: //world camera
00773       cam_xyz[0] = bodyPos[0];
00774       cam_xyz[1] =  bodyPos[1]-5;
00775       cam_xyz[2] =  10;
00776 
00777       cam_hpr[0]   = 90.0;
00778       cam_hpr[1]   = -45.0;
00779       cam_hpr[2]   = 0.0;
00780 
00781       break;
00782     case 1:
00783       cam_xyz[0] = bodyPos[0];
00784       cam_xyz[1] = bodyPos[1];
00785       cam_xyz[2] = bodyPos[2];
00786 
00787       cam_hpr[0]   = yaw + 90;
00788       cam_hpr[1]   = pitch;
00789       cam_hpr[2]   = roll;
00790 
00791       break;
00792     case 2:
00793       cam_xyz[0] = bodyPos[0];
00794       cam_xyz[1] = bodyPos[1];
00795       cam_xyz[2] = bodyPos[2];
00796 
00797       cam_hpr[0]   = yaw + 90;
00798       cam_hpr[1]   = pitch - 90;
00799       cam_hpr[2]   = roll;
00800 
00801       break;
00802   }
00803   pthread_mutex_lock(&itsDispLock);
00804   if (camera != -1)
00805     vp->dsSetViewpoint (cam_xyz,cam_hpr);
00806   vp->initFrame();
00807   drawSub();
00808   drawArena();
00809   vp->updateFrame();
00810   pthread_mutex_unlock(&itsDispLock);
00811 
00812 
00813   return vp->getFrame();
00814 }
00815 
00816 void SeaBee3Simulator::getSensors(float &xPos, float &yPos, float &depth,
00817     float &roll, float &pitch, float &yaw)
00818 {
00819 
00820   xPos = itsSimXPos;
00821   yPos = itsSimYPos;
00822   depth = itsSimDepth;
00823   roll = itsSimRoll;
00824   pitch = itsSimPitch;
00825   yaw = itsSimYaw;
00826 
00827 }
00828 
00829 void SeaBee3Simulator::setThrusters(double forwardLeftThruster, double forwardRightThruster,
00830     double verticalLeftThruster, double verticalRightThruster,
00831     double forwardStrafeThruster, double  backStrafeThruster)
00832 {
00833 
00834   itsForwardLeftThrusterVal    = forwardLeftThruster;
00835   itsForwardRightThrusterVal   = forwardRightThruster;
00836   itsFrontStrafeThrusterVal    = forwardStrafeThruster;
00837   itsBackStrafeThrusterVal     = backStrafeThruster;
00838   itsLeftVertThrusterVal       = verticalLeftThruster;
00839   itsRightVertThrusterVal      = verticalRightThruster;
00840 }
00841 
Generated on Sun May 8 08:41:38 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3