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