Homepage Demos Overview Downloads Tutorials Reference
Credits

WorldModel2.cc

Go to the documentation of this file.
00001 /*
00002  * Tekkotsu framework class for the Second Generation World Model.
00003  * This class is the glue that connects all of the representations in
00004  * the 2GWM with the rest of Tekkotsu. It implements EventListener so it
00005  * can receive motion and video events; it maintains a queue of actions
00006  * that the AIBO can elect to perform to improve the certainty of the
00007  * world representations; and it also has access functions that allow
00008  * other code to get at the contents of the world model.
00009  *
00010  * This code checks for the definition of WANT_GLOBAL_MAP. If WANT_GLOBAL_MAP
00011  * is enabled, then global mapping functionality (FastSLAM, the global height
00012  * map) is compiled in. If not, these parts are omitted.
00013  */
00014 
00015 // include me
00016 #include "WorldModel2.h"
00017 
00018 // include STL, Tekkotsu, and other basics
00019 #include <cmath>
00020 #include <vector>
00021 #include <deque>
00022 #include "Events/EventRouter.h"
00023 #include "Events/VisionEvent.h"
00024 #include "Events/LocomotionEvent.h"
00025 #include "Shared/WorldState.h"
00026 #include "Vision/Vision.h"
00027 #include "Wireless/Wireless.h"
00028 #include "Shared/Config.h"
00029 
00030 // include WorldModel2 particulars
00031 #include "FastSLAM/afsMain.h"
00032 #include "Maps/almMain.h"
00033 #include "Maps/agmMain.h"
00034 #include "Maps/almStructures.h"
00035 // needed for AFS_NUM_LANDMARKS, AFS_NUM_PARTICLES
00036 #include "FastSLAM/Configuration.h"
00037 // needed for afsParticle
00038 #include "FastSLAM/afsParticle.h"
00039 // needed for pinhole camera model parameters
00040 #include "Maps/Configuration.h"
00041 // Standing robot parameters. TODO--replace with motion model
00042 #include "Poses.h"
00043 
00044 // Timing to time our moves
00045 #include "Shared/get_time.h"
00046 
00047 // use perl;
00048 #define UNLESS(item)  if(!( (item) ))
00049 
00050 // debugging?
00051 //#define DEBUG_WM2
00052 
00053 // Timer SIDs
00054 #define TIMER_SID_GPA 0 // sid for ground plane assumption timer
00055 #define TIMER_SID_SRL 1 // sid for serializer
00056 
00057 using namespace std;
00058 
00059 
00060   // Start everything out with WorldMap2 resource lock flag (see
00061   // WorldModel2.h) unlocked
00062 bool WorldModel2::locked = false;
00063 
00064   // Constructor. The constructor must initialize all of the world model
00065   // representations
00066 WorldModel2::WorldModel2()
00067       // We start with no kludges enabled. This is known to all my "homies"
00068       // as "keeping it real".
00069   : kludges(0),
00070       // NOTE: moving is true because we don't know our state on initialization
00071     moving(true),
00072       // Set all enabled sensing mechanisms to false
00073     enabledIR(false), enabledGPA(false),
00074       // Set current velocities and travel time start to 0.
00075       // NOTE: 0 is a special value for movingSince--see WorldModel2.h
00076     dx(0.0), dy(0.0), da(0.0), movingSince(0),
00077       // Initialize sockets for outbound communication. Note strikingly
00078       // unintelligent outbound buffer sizes--this could lead to
00079       // problems if we ever get great big maps.
00080       // We're also assuming that the space used by cells in the maps is equal
00081       // to or greater than the amount of room you need to transmit cell data
00082       // over the ether.
00083     sockDM(wireless->socket(SocketNS::SOCK_STREAM, 1024,
00084           DM_CELL_COUNT*sizeof(dm_cell))),
00085     sockHM(wireless->socket(SocketNS::SOCK_STREAM, 1024,
00086           HM_CELL_COUNT*sizeof(hm_cell)))
00087 #ifdef WANT_GLOBAL_MAP
00088     ,
00089     sockGM(wireless->socket(SocketNS::SOCK_STREAM, 1024,
00090           GM_CELL_COUNT*sizeof(hm_cell))),
00091     sockFS(wireless->socket(SocketNS::SOCK_STREAM, 1024,
00092     AFS_NUM_PARTICLES*sizeof(afsPose) + sizeof(afsParticle))),
00093     enabledMarkers(false),
00094     fs_updates()
00095 #endif
00096 {
00097     // Make sure the world model resources aren't owned by someone else.
00098   if(locked) return; // TODO: throw an exception?
00099     // OK, claim the resources for ourselves
00100   locked = true;
00101 
00102 #ifdef WANT_GLOBAL_MAP
00103     // Clear sensor processing checklist flags (see WorldModel2.h)
00104   for(int i=0; i<AFS_NUM_LANDMARKS; ++i) haveSeenMarker[i] = false;
00105 #endif
00106 
00107     // Start listening on output ports
00108   wireless->listen(sockDM->sock, config->worldmodel2.dm_port);
00109   wireless->listen(sockHM->sock, config->worldmodel2.hm_port);
00110 #ifdef WANT_GLOBAL_MAP
00111   wireless->listen(sockGM->sock, config->worldmodel2.gm_port);
00112   wireless->listen(sockFS->sock, config->worldmodel2.fs_port);
00113 #endif
00114 
00115     // We just set the world model to the start state.
00116   resetWorldModel();
00117 
00118     // Subscribe to locomotion events
00119   erouter->addListener(this,EventBase::locomotionEGID);
00120 
00121     // Turn on serialization timer
00122   erouter->addTimer(this, TIMER_SID_SRL, SRLdelay, true);
00123 }
00124 
00125   // Destructor
00126 WorldModel2::~WorldModel2()
00127 {
00128     // Cancel subscriptions to various events--also turns off timers
00129   disableIR();
00130   disableGPA();
00131 #ifdef WANT_GLOBAL_MAP
00132   disableMarkers();
00133 #endif
00134   erouter->forgetListener(this);
00135 
00136     // Close sockets
00137   wireless->close(sockDM);
00138   wireless->close(sockHM);
00139 #ifdef WANT_GLOBAL_MAP
00140   wireless->close(sockGM);
00141   wireless->close(sockFS);
00142 #endif
00143 
00144     // Free the resources up for someone else
00145   locked = false;
00146 }
00147 
00148 
00149 
00150   // Enable or disable certain sensing mechanisms.
00151   // infrared
00152 void WorldModel2::enableIR()
00153 {
00154     // Subscribe to sensor updates so that we can know what the IR sees
00155   erouter->addListener(this, EventBase::sensorEGID, SensorSourceID::UpdatedSID);
00156   enabledIR = true;
00157 }
00158 void WorldModel2::disableIR()
00159 {
00160     // Cancel subscription to sensor updates--we don't need them for IR anymore
00161   erouter->removeListener(this, EventBase::sensorEGID,
00162         SensorSourceID::UpdatedSID);
00163   enabledIR = false;
00164 }
00165 
00166   // Ground plane assumption. The GPA uses timer events to tell it to check
00167   // periodically for the head to be in the right position to do GPA.
00168   // Thus, after we've enabled GPA, we need to see if we're not moving
00169   // and if so, turn on the GPA timer
00170 void WorldModel2::enableGPA()
00171 {
00172     // turn on GPA timer if we're not moving
00173     // note: checks for indicator value of 0 of movingSince
00174     // Timer SID 0 is for
00175   if(movingSince && !moving)
00176     erouter->addTimer(this, TIMER_SID_GPA, GPAdelay, true);
00177 
00178   enabledGPA = true;
00179 }
00180 void WorldModel2::disableGPA()
00181 {
00182     // turn off the GPA timer if it's running
00183   erouter->removeTimer(this, TIMER_SID_GPA);
00184 
00185   enabledGPA = false;
00186 }
00187 
00188 
00189 // Enable a kludge. See the definition of the WM2Kludge namespace
00190 // to find out what they are
00191 void WorldModel2::enableKludge(unsigned int kludge)
00192 {
00193   kludges |= kludge;
00194 }
00195 
00196 // Disable a kludge
00197 void WorldModel2::disableKludge(unsigned int kludge)
00198 {
00199   kludges &= ~kludge;
00200 }
00201 
00202 
00203 #ifdef WANT_GLOBAL_MAP
00204   // Marker events--for FastSLAM
00205 void WorldModel2::enableMarkers()
00206 {
00207   // We even listen to them if we're not moving
00208   // note: also checks for indicator value of 0 of movingSince
00209   if(movingSince && !moving)
00210     erouter->addListener(this,EventBase::visionEGID, VisionEventNS::MarkersSID);
00211   enabledMarkers = true;
00212 }
00213 void WorldModel2::disableMarkers()
00214 {
00215     // Marker vision events go off
00216   vision->disableEvents(VisionEventNS::MarkersSID);
00217   erouter->removeListener(this, EventBase::visionEGID,
00218         VisionEventNS::MarkersSID);
00219   enabledMarkers = false;
00220 }
00221 #endif
00222 
00223 
00224 
00225   // Resets the world model to the start state
00226 void WorldModel2::resetWorldModel()
00227 {
00228     // Reset egocentric maps
00229   ALM::init();
00230 #ifdef WANT_GLOBAL_MAP
00231     // Reset global maps
00232   AGM::init();
00233     // Reset FastSLAM global localizer
00234   afsInit();
00235 #endif
00236 }
00237 
00238 #ifdef WANT_GLOBAL_MAP
00239   // Specify the position of a landmark (for FastSLAM)
00240   // just a wrapper function, really.
00241 void WorldModel2::setLandmark(int landmark,
00242             double x, double y, double covariance)
00243 {
00244   afsSetLandmark(landmark, x, y, covariance);
00245 }
00246 
00247   // Distribute FastSLAM particles randomly (uniformly) throughout
00248   // a bounding box.
00249   // just a wrapper function, really.
00250   // lx = left x, ty = top y, rx = right x, bottom y = by
00251 void WorldModel2::fsDistribute(double lx, double ty, double rx, double by)
00252 {
00253   afsDistribute(lx, ty, rx, by);
00254 }
00255 #endif
00256 
00257   // Process vision and motion events
00258 void WorldModel2::processEvent(const EventBase& event)
00259 {
00260     // Find out what sort of event we have here and act accordingly
00261   switch(event.getGeneratorID()) {
00262     // process sensor data, specifically IR
00263   case EventBase::sensorEGID: processSensors(); break;
00264 #ifdef WANT_GLOBAL_MAP
00265     // process vision data, specifically markers
00266   case EventBase::visionEGID: processVision(event); break;
00267 #endif
00268     // process locomotion data
00269   case EventBase::locomotionEGID: processLocomotion(event); break;
00270     // either it's time to try and process ground data or it's time to
00271     // serialize our data
00272   case EventBase::timerEGID:
00273    if(event.getSourceID() == TIMER_SID_GPA) processGround();
00274     else if(event.getSourceID() == TIMER_SID_SRL) serialize();
00275     break;
00276     // dunno what this is, then
00277   default:
00278     cerr << "warning: WorldModel2 receved unrequested event" << endl;
00279   }
00280 }
00281 
00282   // Get suggestions about what to look at next
00283 void WorldModel2::getRequests(MRvector &requests)
00284 {
00285   ALM::genRequests(requests);
00286 #ifdef WANT_GLOBAL_MAP
00287   AGM::genRequests(requests);
00288 #endif
00289 }
00290 
00291 
00292   // Access methods for the spherical depth map. See WorldModel2.h for
00293   // extensive documentation.
00294 void WorldModel2::pickDMData(dmPicker &p, float *dest)
00295 {
00296   // Get DM data
00297   dm_cell *DMp = ALM::getDM();
00298   for(int i=0; i<DM_CELL_COUNT; ++i) dest[i] = p(DMp[i]);
00299 }
00300 dm_cell *WorldModel2::invadeDMData(void) { return ALM::getDM(); }
00301 
00302   // Access methods for the horizontal height map. See WorldModel2.h for
00303   // extensive documentation.
00304 void WorldModel2::pickHMData(hmPicker &p, float *dest)
00305 {
00306   // Get HM data
00307   hm_cell *HMp = ALM::getHM();
00308   for(int i=0; i<HM_CELL_COUNT; ++i) dest[i] = p(HMp[i]);
00309 }
00310 hm_cell *WorldModel2::invadeHMData(void) { return ALM::getHM(); }
00311 
00312 #ifdef WANT_GLOBAL_MAP
00313   // Access methods for the horizontal height map. See WorldModel2.h for
00314   // extensive documentation.
00315 void WorldModel2::pickGMData(hmPicker &p, float *dest)
00316 {
00317   // Get HM data
00318   /*
00319   hm_cell *GMp = ALM::getGM();
00320   for(int i=0; i<GM_CELL_COUNT; ++i) dest[i] = p(GMp[i]);
00321   */
00322 }
00323 hm_cell *WorldModel2::invadeGMData(void) { return NULL; } //return ALM::getGM(); }
00324 #endif
00325 
00326 
00327   // process sensors, specifically IRs
00328 void WorldModel2::processSensors()
00329 {
00330   // We should never be called if enabledIR is off, but here's a test anyway
00331   UNLESS(enabledIR) {
00332     cerr << "warning: WorldModel2 handling IR event w/o authorization" << endl;
00333     return;
00334   }
00335   // just abort if the AIBO isn't standing erect--we can't do math on the
00336   // IR stuff then. In the future, we'll have inverse kinematics that
00337   // take care of this for us.
00338 //UNCOMMENT THIS IN REAL LIFE
00339   //if(!aiboIsErect()) return;
00340 
00341   // OK, AIBO is in the right position. Go ahead and integrate its sensor data
00342   double depth    = state->sensors[IRDistOffset];
00343   double azimuth  = state->outputs[HeadOffset+PanOffset];
00344   double altitude = state->outputs[HeadOffset+TiltOffset];
00345 
00346   ALM::registerDepth(depth, altitude, azimuth, kludges);
00347 }
00348 
00349 #ifdef WANT_GLOBAL_MAP
00350   // process vision events
00351 void WorldModel2::processVision(const EventBase& event)
00352 {
00353   // These variables are part of the same mechanism that tracks image size
00354   // (and hence depth of the "film plane" in our pinhole camera model)
00355   // used in Maps/almMain.cc
00356   static int curr_img_width = 0;
00357   static float cam_depth_wpix = 0;
00358   static float ciw_2 = 0; // curr_img_width / 2
00359 
00360   // We should never be called if enabledMarkers is off, but here's a test
00361   UNLESS(enabledMarkers) {
00362     cerr << "warning: WorldModel2 handling markers w/o authorization" << endl;
00363     return;
00364   }
00365   // just abort if the AIBO isn't standing erect--we can't do math on the
00366   // vision stuff then. In the future, we'll have inverse kinematics that
00367   // take care of this for us.
00368 //UNCOMMENT THIS IN REAL LIFE
00369   //UNLESS(aiboIsErect()) return;
00370 
00371   // Likewise if the AIBO's head is tilted or rolled. We'll improve this
00372   // later.
00373 //UNCOMMENT THIS IN REAL LIFE
00374   //UNLESS(aiboIsLevelHeaded()) return;
00375 
00376   // Make sure this is a marker event
00377   UNLESS((event.getTypeID() == EventBase::statusETID) &&
00378    (event.getSourceID() == VisionEventNS::MarkersSID)) return;
00379 
00380   // Glean the data
00381   float x = static_cast<const VisionEvent*>(&event)->getCenterX();
00382   int whichMarker = static_cast<const VisionEvent*>(&event)->getProperty();
00383 
00384   // just in case things go crazy
00385   if((whichMarker < 0) || (whichMarker >= AFS_NUM_LANDMARKS)) return;
00386 
00387   // find out the degree offset of the landmark. As in the ground plane
00388   // assumption code, I'm assuming a pinhole camera model. The constants
00389   // used in the following code are drawn from Maps/Configuration.h
00390 
00391   //if(haveSeenMarker[whichMarker]) return; // seen this marker before? quit.
00392 
00393   // The first thing we have to do is see whether the image size has
00394   // changed and alter our own camera model measurements accordingly
00395   if(vision->width != curr_img_width) {
00396     curr_img_width = vision->width;
00397     ciw_2 = ((float)curr_img_width) / 2.0;
00398 
00399     // See almMain.cc method ALM::registerGround for details on this
00400     // computation.
00401     cam_depth_wpix = ((double) ciw_2)*tan(AIBO_CAM_H_FOV/2);
00402   }
00403 
00404   // Now we can find the degree offset of the landmark within the image
00405   float theta = atan2(ciw_2-x, cam_depth_wpix);
00406 
00407   // Let's ignore camera measurements that aren't relatively near to our
00408   // center of vision. Constant is in WorldModel2.h
00409   if(theta*theta > maxMarkerAngle*maxMarkerAngle) return;
00410 
00411   // We add that to our head pan angle to get the actual relative angle
00412   theta += state->outputs[HeadOffset+PanOffset];
00413 
00414   // Now we pass on the creamy data freshness to FastSLAM
00415   afsMeasurement(whichMarker, theta);
00416 
00417 #ifdef DEBUG_WM2
00418   // Print out observation details.
00419   cout << "  OBS: " << whichMarker << " at " << theta
00420        << "\t (" << theta*180/M_PI << ")" << endl;
00421 #endif
00422 
00423   // Now we've officially seen this marker.
00424   haveSeenMarker[whichMarker] = true;
00425 }
00426 #endif
00427 
00428   // process locomotion events--movements
00429 void WorldModel2::processLocomotion(const EventBase& event)
00430 {
00431   long currTime = get_time(); // get the current time
00432 
00433   // See if we know where we've been last. Update our representations' ideas
00434   // of our position given our past trajectory accordingly
00435   if(movingSince) {
00436     long timeDiff = currTime - movingSince;
00437     // Only translate maps, FastSLAM particles if we've been moving
00438     if(moving) {
00439       ALM::move(dx, dy, da, timeDiff);
00440 #ifdef WANT_GLOBAL_MAP
00441       // Add this motion to the list of things for FastSLAM to process. If
00442       // the LazyFastSLAM kludge is on, it won't happen until the AIBO has
00443       // come to a complete stop.
00444       //afsMotion(dx, dy, da, timeDiff);
00445       FastSLAM_update fsu;
00446       fsu.type = FastSLAM_update::MOTION;
00447       fsu.dx = dx;
00448       fsu.dy = dy;
00449       fsu.da = da;
00450       fsu.time = timeDiff;
00451       fs_updates.push_back(fsu);
00452 #endif
00453     }
00454   }
00455 
00456   // Update start time for new trajectory
00457   movingSince = currTime;
00458 
00459   // Update dx,dy,da with new trajectory info
00460   dx = static_cast<const LocomotionEvent*>(&event)->x;
00461   dy = static_cast<const LocomotionEvent*>(&event)->y;
00462   da = static_cast<const LocomotionEvent*>(&event)->a;
00463 
00464   // See if we're moving
00465   // Note use of movingSince test.
00466   if(movingSince && (dx == 0.0) && (dy == 0.0) && (da == 0.0)) moving = false;
00467   else moving = true;
00468 
00469     // Things to do if we've started moving
00470   if(moving) {
00471       // Turn off the GPA timer so that we don't try to do GPA on the move
00472       // If we did do GPA successfully, this will already have happened.
00473     if(enabledGPA) erouter->removeTimer(this);
00474 #ifdef WANT_GLOBAL_MAP
00475       // Turn off marker events for FastSLAM
00476       // We don't seem to be able to request only markers
00477     if(enabledMarkers) erouter->removeListener(this, EventBase::visionEGID);//,
00478                  //VisionEventNS::MarkersSID);
00479 #endif
00480       // Turn off IR ranging
00481     if(enabledIR) erouter->removeListener(this, EventBase::sensorEGID,
00482             SensorSourceID::UpdatedSID);
00483   }
00484     // Things to do if we've stopped
00485   else {
00486       // Turn on GPA timer to trigger GPA if the pose is right
00487     if(enabledGPA) erouter->addTimer(this, 0, GPAdelay, true);
00488 #ifdef WANT_GLOBAL_MAP
00489       // Turn on marker events for FastSLAM
00490       // We don't seem to be able to request only markers
00491     if(enabledMarkers) erouter->addListener(this, EventBase::visionEGID);//,
00492               //VisionEventNS::MarkersSID);
00493 #endif
00494     if(enabledIR) erouter->addListener(this, EventBase::sensorEGID,
00495                SensorSourceID::UpdatedSID);
00496   }
00497 
00498 #ifdef WANT_GLOBAL_MAP
00499   // Clear sensor processing checklist flags, and see if we've seen any
00500   // landmarks. If we've seen more than a small number, then let's do
00501   // a FastSLAM resample.
00502   int numMarkersSeen = 0;
00503   for(int i=0; i<AFS_NUM_LANDMARKS; ++i)
00504     if(haveSeenMarker[i]) {
00505       ++numMarkersSeen;
00506       haveSeenMarker[i] = false;
00507     }
00508   //if(numMarkersSeen >= minMarkersForFastSLAM) afsResample();
00509   if(numMarkersSeen >= minMarkersForFastSLAM) {
00510     FastSLAM_update fsu;
00511     fsu.type = FastSLAM_update::LANDMARK;
00512     fsu.dx = fsu.dy = fsu.da = 0;
00513     fsu.time = 0;
00514     fs_updates.push_back(fsu);
00515   }
00516 
00517 
00518   // If we're moving and we have the LazyFastSLAM kludge enabled, then we
00519   // stop here.
00520   if(moving && (kludges & WM2Kludge::LazyFastSLAM)) return;
00521   // Either we're stopped or LazyFastSLAM is off. Process away.
00522   while(!fs_updates.empty()) {
00523     FastSLAM_update fsu = fs_updates.front();
00524 
00525     // Is this a resampling update or a motion update? Act accordingly.
00526     if(fsu.type == FastSLAM_update::MOTION) {
00527 #ifdef DEBUG_WM2
00528       cout << "MOTION RESAMPLE <" << fsu.dx << ',' << fsu.dy << ',' << fsu.da
00529      << ' ' << fsu.time << ">... " << flush;
00530 #endif
00531       afsMotion(fsu.dx, fsu.dy, fsu.da, fsu.time);
00532 #ifdef DEBUG_WM2
00533       cout << "done." << endl;
00534       afsWhatsUp(NULL);
00535 #endif
00536     }
00537     else if(fsu.type == FastSLAM_update::LANDMARK) {
00538 #ifdef DEBUG_WM2
00539       cout << "LANDMARK RESAMPLE... " << flush;
00540 #endif
00541       afsResample();
00542 #ifdef DEBUG_WM2
00543       cout << "done." << endl;
00544       afsWhatsUp(NULL);
00545 #endif
00546     }
00547 
00548     // Next!
00549     fs_updates.pop_front();
00550   }
00551 #endif
00552 }
00553 
00554   // Try to do ground plane assumption
00555 void WorldModel2::processGround()
00556 {
00557   // We should never be called if enabledGPA is off, but here's a test anyway
00558   UNLESS(enabledGPA) {
00559     cerr << "warning: WorldModel2 doing GPA w/o authorization" << endl;
00560     return;
00561   }
00562   // Make sure AIBO is standing erect AND facing dead ahead
00563   UNLESS(aiboIsErect() && aiboStaresDeadAhead()) return;
00564 
00565   // Delete the ground plane assumption timer
00566   erouter->removeTimer(this);
00567 
00568   // Go ahead and do the ground plane assumption
00569   ALM::registerGround();
00570 }
00571 
00572 #ifdef WANT_GLOBAL_MAP
00573   // Gets the current best FastSLAM map and places its contents in p
00574 void WorldModel2::getFastSLAMMap(afsParticle &p)
00575 {
00576   afsParticle *best = afsWhatsUp(NULL);
00577 
00578   p = *best;
00579 }
00580 #endif
00581 
00582   // Perform serialization -- send data down the line, if needed.
00583 void WorldModel2::serialize()
00584 {
00585   char *buf;
00586 
00587   // Encode depth map data
00588   buf = (char *)sockDM->getWriteBuffer(DM_CELL_COUNT*sizeof(dm_cell));
00589   if(buf) {
00590     dm_cell *DMp = ALM::getDM();
00591 
00592     for(int i=0; i<DM_CELL_COUNT; ++i) {
00593       dm_cell *cel = &DMp[i];
00594       encode(&buf, cel->depth);
00595       encode(&buf, cel->confidence);
00596       encode(&buf, cel->color);
00597     }
00598     sockDM->write(DM_CELL_COUNT*(sizeof(float)*2 + sizeof(colortype)));
00599   }
00600 
00601   // Encode height map data
00602   buf = (char *)sockHM->getWriteBuffer(HM_CELL_COUNT*sizeof(hm_cell));
00603   if(buf) {
00604     hm_cell *HMp = ALM::getHM();
00605 
00606     for(int i=0; i<HM_CELL_COUNT; ++i) {
00607       hm_cell *cel = &HMp[i];
00608       encode(&buf, cel->height);
00609       encode(&buf, cel->trav);
00610       encode(&buf, cel->confidence);
00611       encode(&buf, cel->color);
00612     }
00613     // colortype is defined in Maps/almStructures.h
00614     sockHM->write(HM_CELL_COUNT*(sizeof(float)*3 + sizeof(colortype)));
00615   }
00616 
00617 #ifdef WANT_GLOBAL_MAP
00618   // Encode global map data
00619   buf = (char *)sockGM->getWriteBuffer(GM_CELL_COUNT*sizeof(hm_cell));
00620   if(buf) {
00621     hm_cell *GMp = AGM::getGM();
00622 
00623     for(int i=0; i<GM_CELL_COUNT; ++i) {
00624       hm_cell *cel = &GMp[i];
00625       encode(&buf, cel->height);
00626       encode(&buf, cel->trav);
00627       encode(&buf, cel->confidence);
00628       encode(&buf, cel->color);
00629     }
00630     // colortype is defined in Maps/almStructures.h
00631     sockGM->write(GM_CELL_COUNT*(sizeof(float)*3 + sizeof(colortype)));
00632   }
00633 
00634   // Encode FastSLAM map and location data
00635   buf = (char *)sockFS->getWriteBuffer(AFS_NUM_PARTICLES*sizeof(afsPose) +
00636                sizeof(afsParticle));
00637   if(buf) {
00638     // Insert the locations of all the particles
00639     afsParticle *Particles = afsInvadeFSData(); // Routine not for general use!
00640     for(int i=0; i<AFS_NUM_PARTICLES; ++i) {
00641       encode(&buf, (float) Particles[i].pose.x);
00642       encode(&buf, (float) Particles[i].pose.y);
00643       encode(&buf, (float) Particles[i].pose.theta);
00644     }
00645 
00646     // Send information about the best particle
00647     afsParticle *p = afsWhatsUp(NULL);
00648 
00649     encode(&buf, (float) p->pose.x);
00650     encode(&buf, (float) p->pose.y);
00651     encode(&buf, (float) p->pose.theta);
00652     for(int i=0; i<AFS_NUM_LANDMARKS; ++i) {
00653       afsLandmarkLoc *l = &p->landmarks[i];
00654 
00655       // Just use HUGE_VAL to indicate uninitialized landmarks. The code
00656       // at the other end will detect these unreasonable values and act
00657       // accordingly
00658       if(l->state == PRIMING) {
00659   encode(&buf, (float) HUGE_VAL);
00660   encode(&buf, (float) HUGE_VAL);
00661   encode(&buf, (float) HUGE_VAL);
00662   encode(&buf, (float) HUGE_VAL);
00663   encode(&buf, (float) HUGE_VAL);
00664       }
00665       else {  // state == PRIMED
00666   encode(&buf, (float) l->mean.x);
00667   encode(&buf, (float) l->mean.y);
00668   encode(&buf, (float) l->variance.x);
00669   encode(&buf, (float) l->variance.xy);
00670   encode(&buf, (float) l->variance.y);
00671       }
00672     }
00673     sockFS->write(AFS_NUM_PARTICLES*(3*sizeof(float)) +
00674       (3*sizeof(float)) + AFS_NUM_LANDMARKS*(5*sizeof(float)));
00675   }
00676 #endif
00677 }
00678 
00679   // Determine whether Aibo is in an erect stature, allowing us to do
00680   // measurements. TODO: replace with a real motion model
00681 bool aiboIsErect()
00682 {
00683   double diff;
00684 
00685   diff = SP_LFR_JOINT - state->outputs[LFrLegOffset+RotatorOffset];
00686   if(diff*diff > SP_TOLERANCE) return false;
00687   diff = SP_LFR_SHLDR - state->outputs[LFrLegOffset+ElevatorOffset];
00688   if(diff*diff > SP_TOLERANCE) return false;
00689   diff = SP_LFR_KNEE  - state->outputs[LFrLegOffset+KneeOffset];
00690   if(diff*diff > SP_TOLERANCE) return false;
00691 
00692   diff = SP_RFR_JOINT - state->outputs[RFrLegOffset+RotatorOffset];
00693   if(diff*diff > SP_TOLERANCE) return false;
00694   diff = SP_RFR_SHLDR - state->outputs[RFrLegOffset+ElevatorOffset];
00695   if(diff*diff > SP_TOLERANCE) return false;
00696   diff = SP_RFR_KNEE  - state->outputs[RFrLegOffset+KneeOffset];
00697   if(diff*diff > SP_TOLERANCE) return false;
00698 
00699   diff = SP_LFR_JOINT - state->outputs[LBkLegOffset+RotatorOffset];
00700   if(diff*diff > SP_TOLERANCE) return false;
00701   diff = SP_LFR_SHLDR - state->outputs[LBkLegOffset+ElevatorOffset];
00702   if(diff*diff > SP_TOLERANCE) return false;
00703   diff = SP_LFR_KNEE  - state->outputs[LBkLegOffset+KneeOffset];
00704   if(diff*diff > SP_TOLERANCE) return false;
00705 
00706   diff = SP_RFR_JOINT - state->outputs[RBkLegOffset+RotatorOffset];
00707   if(diff*diff > SP_TOLERANCE) return false;
00708   diff = SP_RFR_SHLDR - state->outputs[RBkLegOffset+ElevatorOffset];
00709   if(diff*diff > SP_TOLERANCE) return false;
00710   diff = SP_RFR_KNEE  - state->outputs[RBkLegOffset+KneeOffset];
00711   if(diff*diff > SP_TOLERANCE) return false;
00712 
00713   return true;
00714 }
00715 
00716   // Determine whether Aibo is looking dead ahead. Needed for ground plane
00717   // assumption, for the moment.
00718 bool aiboStaresDeadAhead()
00719 {
00720   double diff;
00721 
00722   diff = DA_TILT - state->outputs[HeadOffset+TiltOffset];
00723   if(diff*diff > DA_TOLERANCE) return false;
00724   diff = DA_PAN  - state->outputs[HeadOffset+PanOffset];
00725   if(diff*diff > DA_TOLERANCE) return false;
00726   diff = DA_ROLL - state->outputs[HeadOffset+RollOffset];
00727   if(diff*diff > DA_TOLERANCE) return false;
00728 
00729   return true;
00730 }
00731 
00732   // Determine whether Aibo is keeping its head level (i.e. no tilt or roll).
00733   // Needed for FastSLAM at the moment
00734 bool aiboIsLevelHeaded()
00735 {
00736   double diff;
00737 
00738   diff = DA_TILT - state->outputs[HeadOffset+TiltOffset];
00739   if(diff*diff > DA_TOLERANCE) return false;
00740   diff = DA_ROLL - state->outputs[HeadOffset+RollOffset];
00741   if(diff*diff > DA_TOLERANCE) return false;
00742 
00743   return true;
00744 }

Tekkotsu v1.5
Generated Fri Oct 10 15:52:00 2003 by Doxygen 1.3.4