00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
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 ;
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),
00080 itsSubLength(1.5),
00081 itsSubRadius(0.2),
00082 itsSubWeight(30),
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
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
00131 dWorldSetContactMaxCorrectingVel (world,0.1);
00132
00133 dWorldSetContactSurfaceLayer(world, 0.001);
00134
00135
00136 makeSub();
00137
00138
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
00150
00151
00152 dBodySetPosition(itsSubBody,0,0.2*5,1.94);
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
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
00228 vp->dsSetColor(0,0,0);
00229
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
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
00253
00254 if (frame++ > 5)
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
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;
00327 itsPitch = asin(-R[8]);
00328 itsYaw = atan2(R[4], R[0]);
00329
00330 if (itsYaw < 0) itsYaw += M_PI*2;
00331
00332
00333
00334
00335 }
00336
00337 void SubSim::simLoop()
00338 {
00339
00340
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
00347 applyHydrodynamicForces(0.5);
00348
00349
00350
00351
00352 const dReal *bodyPos = dBodyGetPosition(itsSubBody);
00353 const dReal *bodyR = dBodyGetRotation(itsSubBody);
00354
00355 updateSensors(bodyPos, bodyR);
00356
00357 dSpaceCollide (space,this,&nearCallback);
00358
00359 dWorldStep(world,0.1);
00360
00361 dJointGroupEmpty (contactgroup);
00362
00363 if (itsShowWorld)
00364 {
00365 itsWorldDisp->drawImage(flipVertic(getFrame(0)));
00366 }
00367 }
00368
00369
00370
00371
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
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;
00402 dBodyAddTorque(itsSubBody, temp * R[0], temp * R[4], temp * R[8]);
00403
00404 temp = -ny * viscosity;
00405 dBodyAddTorque(itsSubBody, temp * R[1], temp * R[5], temp * R[9]);
00406
00407 temp = -nz * viscosity;
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:
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;
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;
00445 cam_hpr[1] = -90;
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
00488
00489
00490