Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MotionManager.cc

Go to the documentation of this file.
00001 #include "MotionManager.h"
00002 #include "MotionCommand.h"
00003 #include "Events/EventRouter.h"
00004 #include "Shared/StackTrace.h"
00005 #include "Shared/ProjectInterface.h"
00006 #include "Shared/debuget.h"
00007 #include "Shared/WorldState.h"
00008 #include "IPC/SharedObject.h"
00009 
00010 #ifndef PLATFORM_APERIOS
00011 #  include "IPC/MessageQueue.h"
00012 #  include "IPC/MessageReceiver.h"
00013 #  include "Shared/ProjectInterface.h"
00014 #endif
00015 
00016 #include "Shared/ERS210Info.h"
00017 #include "Shared/ERS220Info.h"
00018 #include "Shared/ERS7Info.h"
00019 #include "Shared/Config.h"
00020 
00021 #include <list>
00022 
00023 MotionManager * motman=NULL;
00024 int MotionManager::_MMaccID[ProcessID::NumProcesses];
00025 EventTranslator* MotionManager::etrans=NULL;
00026 
00027 const float MotionManager::kIgnoredPriority    =-1;
00028 const float MotionManager::kBackgroundPriority = 0;
00029 const float MotionManager::kLowPriority        = 5;
00030 const float MotionManager::kStdPriority        = 10;
00031 const float MotionManager::kHighPriority       = 50;
00032 const float MotionManager::kEmergencyPriority  = 100;
00033 
00034 using namespace std;
00035 
00036 //! just for convenience
00037 typedef unsigned int uint;
00038 
00039 MotionManager::MotionManager()
00040 : pidchanges(),cmdlist(),cur_cmd(invalid_MC_ID),MMlock(),numAcc(0)
00041 {
00042   for(uint x=0; x<NumOutputs; x++)
00043     cmdSums[x]=0;
00044 }
00045 
00046 #ifdef PLATFORM_APERIOS
00047 
00048 void
00049 MotionManager::InitAccess(OSubject* subj) {
00050   if(numAcc==MAX_ACCESS) {
00051     printf("*** ERROR *** attempted to register more accessors with MotionManager than allowed by MAX_ACCESS\n");
00052     return;
00053   }
00054   _MMaccID[ProcessID::getID()]=numAcc++;
00055   //  cout << "ID is now " << getAccID() << " of " << numAcc << endl;
00056   MMlock.lock(getAccID());
00057   //  accRegs[accID].init();
00058   subjs[getAccID()]=subj;
00059   if(cmdlist.size()>0) //Shouldn't happen - busy wait in addMotion
00060     cout << "*** WARNING *** MOTIONS ADDED BEFORE ALL INITACCESSED" << endl;
00061   MMlock.unlock();
00062 }
00063 
00064 #else //now PLATFORM_LOCAL
00065 
00066 void
00067 MotionManager::InitAccess(MessageQueueBase& mcbufq, Resource& behaviorLock) {
00068   if(numAcc==MAX_ACCESS) {
00069     printf("*** ERROR *** attempted to register more accessors with MotionManager than allowed by MAX_ACCESS\n");
00070     return;
00071   }
00072   _MMaccID[ProcessID::getID()]=numAcc++;
00073   //  cout << "ID is now " << getAccID() << " of " << numAcc << endl;
00074   MMlock.lock(getAccID());
00075   subjs[getAccID()]=&mcbufq;
00076   mcrecvs[getAccID()]=new MessageReceiver(*subjs[getAccID()],receivedMsg);
00077   procLocks[getAccID()]=&behaviorLock;
00078   if(cmdlist.size()>0) //Shouldn't happen - busy wait in doAddMotion
00079     cout << "*** WARNING *** MOTIONS ADDED BEFORE ALL INITACCESSED" << endl;
00080   MMlock.unlock();
00081 }
00082 
00083 #endif //PLATFORM-specific initialization
00084 
00085 void
00086 MotionManager::RemoveAccess() {
00087 #ifndef PLATFORM_APERIOS
00088   //kill the message receiver before we get the motion manager lock
00089   // that way if there's a message pending, it can be processed instead of deadlocking
00090   mcrecvs[getAccID()]->finish();
00091   delete mcrecvs[getAccID()];
00092   mcrecvs[getAccID()]=NULL;
00093 #endif
00094   
00095   func_begin();
00096   for(MC_ID mc_id=cmdlist.begin(); mc_id!=cmdlist.end(); mc_id=cmdlist.next(mc_id)) {
00097     if(cmdlist[mc_id].rcr[getAccID()]!=NULL) {
00098       MotionCommand* mc=checkoutMotion(mc_id,true);
00099       int found=0;
00100       for(unsigned int i=0; i<numAcc; i++) {
00101         if(cmdlist[mc_id].rcr[i]!=NULL) {
00102           found++;
00103         }
00104       }
00105       cout << "Warning: " << ProcessID::getIDStr() << " dropping motion command " << mc_id << " of type " << typeid(*mc).name() << ", was active at shutdown " << (mc->getAutoPrune()?"(was set for autoprune)":"(leaked?)") << '\n';
00106       cout << "         Motion command " << mc_id << " was created from:" << endl;
00107       stacktrace::displayStackTrace(cmdlist[mc_id].trace);
00108 #ifdef PLATFORM_APERIOS
00109       int refs=1;
00110 #else
00111       int refs=cmdlist[mc_id].rcr[getAccID()]->NumberOfLocalReference();
00112 #endif
00113       if(refs>1)
00114         cout << "Warning: " << ProcessID::getIDStr() << " still had " <<  refs-1 << " references to motion command " << mc_id << " as it was being dropped (these are now invalid)" << endl;
00115       for(int i=0; i<refs; ++i)
00116         cmdlist[mc_id].rcr[getAccID()]->RemoveReference();
00117       cmdlist[mc_id].rcr[getAccID()]=NULL;
00118       if(found==1) {
00119         MC_ID p=cmdlist.prev(mc_id);
00120         push_free(mc_id); //don't check in -- lock destructor will release the lock as the entry is destructed
00121         mc_id=p;
00122       } else {
00123         checkinMotion(mc_id);
00124       }
00125     }
00126   }
00127   func_end();
00128 }
00129 
00130 
00131 MotionManager::~MotionManager() {
00132   if(!cmdlist.empty()) {
00133     func_begin();
00134     cout << "WARNING: MotionManager destruction with MotionCommands still attached." << endl;
00135     while(!cmdlist.empty()) {
00136       MC_ID mc_id=cmdlist.begin();
00137       for(unsigned int i=0; i<numAcc; i++)
00138         if(cmdlist[mc_id].rcr[i]!=NULL)
00139           cout << "MC " << mc_id << " was still referenced by InitAccess caller #" << getAccID() << endl;
00140       push_free(mc_id);
00141     }
00142     func_end();
00143   }
00144 }
00145 
00146 
00147 void
00148 MotionManager::motionReport() const {
00149   func_begin();
00150   std::cout << cmdlist.size() << " live motion commands\n";
00151   for(MC_ID mc_id=cmdlist.begin(); mc_id!=cmdlist.end(); mc_id=cmdlist.next(mc_id)) {
00152     MotionCommand* mc=checkoutMotion(mc_id,true);
00153     std::cout << "MC_ID " << mc_id << " type " << typeid(*mc).name() << " priority " << cmdlist[mc_id].priority << '\n';
00154     std::cout << "Created by:" << std::endl;
00155     stacktrace::displayStackTrace(cmdlist[mc_id].trace);
00156     checkinMotion(mc_id);
00157   }
00158   std::cout << "\nOutput Usage: (MCID @ value [* weight])\n";
00159   bool any=false;
00160   for(unsigned int i=0; i<NumOutputs; ++i) {
00161     bool first=true;
00162     for(unsigned int j=cmdstates[i].begin(); j!=cmdstates[i].end(); j=cmdstates[i].next(j)) {
00163       if(cmdstates[i][j].frames[NumFrames-1].weight > 0) {
00164         if(first) {
00165           std::cout << "   " << outputNames[i] << ':';
00166           first=false;
00167           any=true;
00168         }
00169         std::cout << " (" << cmdstates[i][j].mcid << " @ " << cmdstates[i][j].frames[NumFrames-1].value;
00170         if(cmdstates[i][j].frames[NumFrames-1].weight!=1)
00171           std::cout << " * " << cmdstates[i][j].frames[NumFrames-1].weight;
00172         std::cout << ")";
00173       }
00174     }
00175     if(!first)
00176       std::cout << '\n';
00177   }
00178   if(!any)
00179     std::cout << "   [No outputs in use]" << std::endl;
00180   func_end();
00181 }
00182 
00183 
00184 void
00185 MotionManager::setOutput(const MotionCommand* caller, unsigned int output, const OutputCmd& cmd) {
00186   if(output >= NumOutputs)
00187     return;
00188   if(cmd.weight<=0)
00189     return;
00190 
00191   if(caller==NULL || caller->getID()!=cur_cmd)
00192     func_begin();
00193   if(cur_cmd==invalid_MC_ID) {
00194     cmdSums[output]=cmd.value;
00195   } else if(getPriority(cur_cmd)>=kBackgroundPriority) {
00196     cmdstatelist_t& curstatelist=cmdstates[output];
00197     cmdstatelist_t::index_t ent=curstatelist.begin();
00198     if(ent==curstatelist.end() || curstatelist[ent].mcid!=cur_cmd)
00199       curstatelist.push_front(OutputState(output,getPriority(cur_cmd),cur_cmd,cmd));
00200     else
00201       for(unsigned int i=0; i<NumFrames; i++)
00202         curstatelist[ent].frames[i]=cmd;
00203   }
00204   if(caller==NULL || caller->getID()!=cur_cmd)
00205     func_end();
00206 }
00207 
00208 void
00209 MotionManager::setOutput(const MotionCommand* caller, unsigned int output, const OutputCmd& cmd, unsigned int frame) {
00210   if(output >= NumOutputs)
00211     return;
00212   if(cmd.weight<=0)
00213     return;
00214 
00215   if(caller==NULL || caller->getID()!=cur_cmd)
00216     func_begin();
00217   if(cur_cmd==invalid_MC_ID) {
00218     cmdSums[output]=cmd.value;
00219   } else if(getPriority(cur_cmd)>=kBackgroundPriority) {
00220     cmdstatelist_t& curstatelist=cmdstates[output];
00221     cmdstatelist_t::index_t ent=curstatelist.begin();
00222     if(ent==curstatelist.end() || curstatelist[ent].mcid!=cur_cmd)
00223       curstatelist.push_front(OutputState(output,getPriority(cur_cmd),cur_cmd,cmd,frame));
00224     else
00225       curstatelist[ent].frames[frame]=cmd;
00226   }
00227   if(caller==NULL || caller->getID()!=cur_cmd)
00228     func_end();
00229 }
00230 
00231 void 
00232 MotionManager::setOutput(const MotionCommand* caller, unsigned int output, const OutputCmd ocmds[NumFrames]) {
00233   if(output >= NumOutputs)
00234     return;
00235   unsigned int hasWeight=NumFrames;
00236   for(unsigned int i=NumFrames-1; i!=-1U; i--)
00237     if(ocmds[i].weight>0) {
00238       hasWeight=i;
00239       break;
00240     }
00241   if(hasWeight==NumFrames)
00242     return;
00243   
00244 
00245   if(caller==NULL || caller->getID()!=cur_cmd)
00246     func_begin();
00247   if(cur_cmd==invalid_MC_ID) {
00248     cmdSums[output]=ocmds[hasWeight].value;
00249   } else if(getPriority(cur_cmd)>=kBackgroundPriority) {
00250     cmdstatelist_t& curstatelist=cmdstates[output];
00251     cmdstatelist_t::index_t ent=curstatelist.begin();
00252     if(ent==curstatelist.end() || curstatelist[ent].mcid!=cur_cmd)
00253       curstatelist.push_front(OutputState(output,getPriority(cur_cmd),cur_cmd,ocmds));
00254     else
00255       for(unsigned int i=0; i<NumFrames; i++)
00256         curstatelist[ent].frames[i]=ocmds[i];
00257   }
00258   if(caller==NULL || caller->getID()!=cur_cmd)
00259     func_end();
00260 }
00261 
00262 void
00263 MotionManager::setOutput(const MotionCommand* caller, unsigned int output, const OutputPID& pid) {
00264   if(output >= NumOutputs)
00265     return;
00266 
00267   if(caller==NULL || caller->getID()!=cur_cmd)
00268     func_begin();
00269   if(cur_cmd==invalid_MC_ID) {
00270     setPID(output,pid.pid);
00271   } else if(getPriority(cur_cmd)>=kBackgroundPriority) {
00272     cmdstatelist_t& curstatelist=cmdstates[output];
00273     cmdstatelist_t::index_t ent=curstatelist.begin();
00274     if(ent==curstatelist.end() || curstatelist[ent].mcid!=cur_cmd)
00275       curstatelist.push_front(OutputState(output,getPriority(cur_cmd),cur_cmd,pid));
00276     else
00277       curstatelist[ent].pid=pid;
00278   }
00279   if(caller==NULL || caller->getID()!=cur_cmd)
00280     func_end();
00281 }
00282 
00283 void
00284 MotionManager::setOutput(const MotionCommand* caller, unsigned int output, const OutputCmd& cmd, const OutputPID& pid) {
00285   if(output >= NumOutputs)
00286     return;
00287 
00288   if(caller==NULL || caller->getID()!=cur_cmd)
00289     func_begin();
00290   if(cur_cmd==invalid_MC_ID) {
00291     if(cmd.weight>0)
00292       cmdSums[output]=cmd.value;
00293     setPID(output,pid.pid);
00294   } else if(getPriority(cur_cmd)>=kBackgroundPriority) {
00295     cmdstatelist_t& curstatelist=cmdstates[output];
00296     cmdstatelist_t::index_t ent=curstatelist.begin();
00297     if(ent==curstatelist.end() || curstatelist[ent].mcid!=cur_cmd)
00298       curstatelist.push_front(OutputState(output,getPriority(cur_cmd),cur_cmd,cmd,pid));
00299     else {
00300       for(unsigned int i=0; i<NumFrames; i++)
00301         curstatelist[ent].frames[i]=cmd;
00302       curstatelist[ent].pid=pid;
00303     }
00304   }
00305   if(caller==NULL || caller->getID()!=cur_cmd)
00306     func_end();
00307 }
00308 
00309 void
00310 MotionManager::setOutput(const MotionCommand* caller, unsigned int output, const OutputCmd ocmds[NumFrames], const OutputPID& pid) {
00311   if(output >= NumOutputs)
00312     return;
00313 
00314   if(caller==NULL || caller->getID()!=cur_cmd)
00315     func_begin();
00316   if(cur_cmd==invalid_MC_ID) {
00317     if(ocmds[NumFrames-1].weight>0)
00318       cmdSums[output]=ocmds[NumFrames-1].value;
00319     setPID(output,pid.pid);
00320   } else if(getPriority(cur_cmd)>=kBackgroundPriority) {
00321     cmdstatelist_t& curstatelist=cmdstates[output];
00322     cmdstatelist_t::index_t ent=curstatelist.begin();
00323     if(ent==curstatelist.end() || curstatelist[ent].mcid!=cur_cmd)
00324       curstatelist.push_front(OutputState(output,getPriority(cur_cmd),cur_cmd,ocmds,pid));
00325     else {
00326       for(unsigned int i=0; i<NumFrames; i++)
00327         curstatelist[ent].frames[i]=ocmds[i];
00328       curstatelist[ent].pid=pid;
00329     }
00330   }
00331   if(caller==NULL || caller->getID()!=cur_cmd)
00332     func_end();
00333 }
00334 
00335 /*! What's worse? A plethora of functions which are only called, and only useful at one place,
00336  *  or a big massive function which doesn't pollute the namespace?  This is the latter, for
00337  *  better or worse. */
00338 void
00339 MotionManager::getOutputs(float outputs[][NumOutputs]) {
00340   //  if(begin(id)!=end())
00341   //if(state && state->buttons[LFrPawOffset]) cout << "getAngles..." << flush;
00342   if(state==NULL) {
00343     // we haven't gotten the WorldState memory region from Main yet, just set LEDs to a wierd pattern and leave
00344     for(uint f=0;f<NumFrames;f++)
00345       for(uint i=0; i<NumOutputs; i++)
00346         outputs[f][i]=0;
00347     for(uint f=0;f<NumFrames;f++)
00348       for(uint l=0; l<NumLEDs; l++)
00349         outputs[f][l]=l/(NumLEDs-1.0f);
00350     //  if(begin(id)!=end())
00351     //if(state && state->buttons[LFrPawOffset]) cout << "getangles-nostate-done..." << flush;
00352     return;
00353   }
00354   func_begin();
00355   //  if(begin(id)!=end())
00356   //  cout << id << "..." << flush;
00357   //cout << "CHECKOUT..." << flush;
00358   for(uint output=0; output<NumOutputs; output++)
00359     cmdstates[output].clear();
00360 
00361   // for each PID joint which is set to 0 power, set the background
00362   // position value to current sensed value this prevents jerking back
00363   // to the previous position when joint(s) are moved during 0 power,
00364   // and then power is turned back on. (power here is in the 0 pid
00365   // sense, the joints are still receiving power from the system -
00366   // that's a separate system call)
00367   // Note that we wouldn't want to do this all the time, because
00368   // miscalibration between the sensed position and target position
00369   // will cause joints to drift to the extremities of motion, in some
00370   // cases, very quickly, and in worse cases, colliding with other
00371   // joints
00372   for(uint output=0; output<NumPIDJoints; output++)
00373     if(state->pids[output][0]==0 && state->pids[output][1]==0 && state->pids[output][2]==0)
00374       cmdSums[output]=state->outputs[output];
00375 
00376   //std::cout << "UPDATE..." << std::flush;
00377   std::list<MC_ID> unlocked;
00378   for(MC_ID mcNum=begin(); mcNum!=end(); mcNum=next(mcNum)) // check out all the MotionCommands (only one at a time tho)
00379     if(cmdlist[mcNum].lastAccessor!=(accID_t)-1)
00380       unlocked.push_back(mcNum);
00381   unsigned int lastProcessed=get_time();
00382   while(unlocked.size()>0) { // keep cycling through all the locks we didn't get
00383     for(std::list<MC_ID>::iterator it=unlocked.begin(); it!=unlocked.end(); ) {
00384       MotionCommand* mc=checkoutMotion(*it,false);
00385       if(mc==NULL)
00386         it++; //we didn't get a lock, skip it (we'll keep looping until we get it)
00387       else {
00388         // we got a lock
00389         cur_cmd=*it;
00390         bool prune=true;
00391         try {
00392           prune=mc->shouldPrune();
00393         } catch(const std::exception& ex) {
00394           ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand prune test, will prune",&ex);
00395         } catch(...) {
00396           ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand prune test, will prune",NULL);
00397         }
00398         if(prune) {
00399           // cout << "Removing expired " << *it << " (autoprune)" << endl;
00400           checkinMotion(*it); // release lock, done with motion (don't need to (and shouldn't) keep lock through the removeMotion())
00401           //only the last process to receive the remove notification actually does the remove, and
00402           //wouldn't be able to undo the thread portion of the lock made in this process
00403           //so we have to take off our own lock here first.
00404           removeMotion(*it);
00405         } else {
00406           try {
00407             if ( cmdlist[mc->getID()].priority >= kBackgroundPriority )
00408               mc->updateOutputs(); // the MotionCommand should make calls to setOutput from within here
00409           } catch(const std::exception& ex) {
00410             ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand updateOutputs",&ex);
00411           } catch(...) {
00412             ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand updateOutputs",NULL);
00413           }
00414           checkinMotion(*it); // release lock, done with motion
00415         }
00416         cur_cmd=invalid_MC_ID;
00417         // remove id from list of unprocessed motioncommands
00418         std::list<MC_ID>::iterator rem=it++;
00419         unlocked.erase(rem);
00420         lastProcessed=get_time();
00421       }
00422     }
00423     if(get_time()-lastProcessed>FrameTime*NumFrames/2)
00424       break;
00425   }
00426   /* Kill annoying warning for now.  -- DST
00427   if(unlocked.size()>0) {
00428     cerr << "Warning: MotionManager was unable to obtain a lock on MCs: ";
00429     for(std::list<MC_ID>::iterator it=unlocked.begin(); it!=unlocked.end(); it++)
00430       cerr << *it << ' ';
00431     cerr << endl;
00432     cerr << (unlocked.size()>1?"They":"It") << " may have been left locked by a Behavior while it was busy." << endl;
00433     cerr << "Try reducing the scope of your MMAccessor or call checkinMotion sooner." << endl;
00434   }
00435   */
00436 
00437   // sort the list of requested outputs based on priority
00438   // (insertion sort, data structure is linked list)
00439   for(uint output=0; output<NumOutputs; output++) {
00440     cmdstatelist_t& curstatelist=cmdstates[output];
00441     for(cmdstatelist_t::index_t bit=curstatelist.begin(); bit!=curstatelist.end(); bit=curstatelist.next(bit)) {
00442       MC_ID high_ent=bit;
00443       float high_p=cmdlist[curstatelist[high_ent].mcid].priority;
00444       for(cmdstatelist_t::index_t cit=curstatelist.next(bit); cit!=curstatelist.end(); cit=curstatelist.next(cit)) {
00445         float curp=cmdlist[curstatelist[cit].mcid].priority;
00446         if(curp>high_p) {
00447           high_p=curp;
00448           high_ent=cit;
00449         }
00450       }
00451       curstatelist.swap(bit,high_ent);
00452       /*if(curstatelist.countf()!=curstatelist.countb() || curstatelist.countf()!=curstatelist.size()) {
00453         cout << "LOST ONE! " << bit << ' ' << high_ent << endl;
00454         cout << curstatelist.countf() << ' ' << curstatelist.countb() << ' ' << curstatelist.size() << endl;
00455         }*/
00456       bit=high_ent;
00457     }
00458   }
00459 
00460   // now we've got, for each output, a list of requested values sorted by priority
00461   // summarize each output
00462   for(uint frame=0; frame<NumFrames; frame++) {
00463     for(uint output=0; output<NumOutputs; output++) {
00464       cmdstatelist_t& curstatelist=cmdstates[output];
00465       float alpha=1;
00466       OutputCmd sumcmd;
00467       /*if(curstatelist.size()>1) {
00468         cout << get_time() << "." << frame << " " << outputNames[output] << ": ";
00469         for(cmdstatelist_t::index_t ent=curstatelist.begin(); ent!=curstatelist.end(); ent=curstatelist.next(ent))
00470           cout << "  (" << curstatelist[ent].frames[frame].value <<',' << curstatelist[ent].frames[frame].weight << ',' << curstatelist[ent].priority << ')';
00471         cout << endl;
00472       }*/
00473       cmdstatelist_t::index_t ent=curstatelist.begin();
00474       while(ent!=curstatelist.end() && alpha>0) {
00475         OutputCmd curcmd;
00476         float curp=curstatelist[ent].priority;
00477         float curalpha=1; // curalpha is cumulative product of leftovers (weights between 0 and 1)
00478         for(;ent!=curstatelist.end() && curstatelist[ent].priority==curp; ent=curstatelist.next(ent)) {
00479           //weighted average within priority level
00480           float curweight=curstatelist[ent].frames[frame].weight;
00481           ASSERT(curweight>=0,"negative output weights are illegal, MC_ID="<<curstatelist[ent].mcid<<" joint="<<outputNames[output]<<" frame="<<frame<<" weight="<<curweight);
00482           if(curweight<0) //negative weights are illegal
00483             curweight=0;
00484           curcmd.value+=curstatelist[ent].frames[frame].value*curweight;
00485           curcmd.weight+=curweight;
00486           if(curweight<1)
00487             curalpha*=(1-curweight);
00488           else
00489             curalpha=0;
00490         }
00491         if(curcmd.weight>0) {
00492           //weighted average of priority levels
00493           sumcmd.value+=curcmd.value/curcmd.weight*alpha*(1-curalpha);
00494           sumcmd.weight+=alpha*(1-curalpha);
00495           alpha*=curalpha;
00496         }
00497       }
00498 
00499       //if(curstatelist.size()>1)
00500       //  cout << "   -> " << sumcmd.value/sumcmd.weight << ',' << sumcmd.weight << " @ " << alpha << endl;
00501       if(sumcmd.weight>0) {
00502         sumcmd.value/=sumcmd.weight;
00503         outputs[frame][output]=sumcmd.value;
00504       } else //if zero weight, hold last value
00505         sumcmd.value=outputs[frame][output]=cmdSums[output];
00506       if(frame==NumFrames-1)
00507         cmds[output]=sumcmd;
00508     }
00509   }
00510   
00511   for(uint output=0; output<NumOutputs; output++)
00512     cmdSums[output]=outputs[NumFrames-1][output];
00513 
00514   for (uint frame_idx = 0; frame_idx < NumFrames; frame_idx++) {
00515     for(uint output=PIDJointOffset; output<PIDJointOffset+NumPIDJoints; output++)
00516       outputs[frame_idx][output] = (outputs[frame_idx][output] + config->motion.calibration_offset[output-PIDJointOffset])
00517         * config->motion.calibration_scale[output-PIDJointOffset];
00518   }
00519       
00520         
00521   // now summarize each output's PID values (for those which use PID control)
00522   for(uint output=PIDJointOffset; output<PIDJointOffset+NumPIDJoints; output++) {
00523     cmdstatelist_t& curstatelist=cmdstates[output];
00524     float alpha=1;
00525     float sumpid[3];
00526     for(uint i=0; i<3; i++)
00527       sumpid[i]=0;
00528     float sumweight=0;
00529     cmdstatelist_t::index_t ent=curstatelist.begin();
00530     while(ent!=curstatelist.end() && alpha>0) {
00531       float tmppid[3];
00532       for(uint i=0; i<3; i++)
00533         tmppid[i]=0;
00534       float tmpweight=0;
00535       float curp=curstatelist[ent].priority;
00536       float curalpha=1; // curalpha is multiplicative sum of leftovers (weights between 0 and 1)
00537       for(;ent!=curstatelist.end() && curstatelist[ent].priority==curp; ent=curstatelist.next(ent)) {
00538         //weighted average within priority level
00539         float curweight=curstatelist[ent].pid.weight;
00540         ASSERT(curweight>=0,"negative PID weights are illegal")
00541         if(curweight<0) //negative weights are illegal
00542           curweight=0;
00543         for(uint i=0; i<3; i++)
00544           tmppid[i]+=curstatelist[ent].pid.pid[i]*curweight;
00545         tmpweight+=curweight;
00546         if(curweight<1)
00547           curalpha*=(1-curweight);
00548         else
00549           curalpha=0;
00550       }
00551       if(tmpweight>0) {
00552         //weighted average of priority levels
00553         for(uint i=0; i<3; i++)
00554           sumpid[i]+=tmppid[i]/tmpweight*(1-curalpha);
00555         sumweight+=(1-curalpha);
00556         alpha*=curalpha;
00557       }
00558     }
00559     if(sumweight>0) {
00560       for(uint i=0; i<3; i++)
00561         sumpid[i]/=sumweight;
00562       setPID(output,sumpid);
00563     }
00564   }
00565 
00566   func_end();
00567   //  if(begin(id)!=end())
00568   //if(state && state->buttons[LFrPawOffset]) cout << "getAngles-done." << flush;
00569 }
00570 
00571 /*! This function handles the conversion from the Tekkotsu format (one
00572  *  regular IEEE float per parameter, to the OPEN-R format (which
00573  *  takes a specialized, reduced precision floating point number) This
00574  *  is all documented in PIDMC as well.
00575  *
00576  *  In order to send Tekkotsu's PIDs to the system, they are converted
00577  *  to the gain/shift format.  On the ERS-2xx, we could dynamically
00578  *  choose shift values to allow more precision in setting values.
00579  *
00580  *  With the ERS-7, all shifts are shared, so they must be set to a
00581  *  common set of values, defined by WorldState::DefaultPIDShifts.
00582  *  This limits the range of gains which can then be set.
00583  *
00584  *  Due to the mysterious warning which would occur with the 2xx,
00585  *  (AGRMSDriver::SetGain() : 0x0A IS USED FOR GAIN SHIFT VALUE.)  and
00586  *  since this seems to be the way things are going, all models now,
00587  *  by default, use global shift values (which can vary from model to
00588  *  model, just global for each model)
00589  *
00590  *  You can revert to the dynamic shift selection by commenting-in
00591  *  the noted code section below.
00592  *
00593  *  A final note: the OPENR::SetJointGain function seems to be
00594  *  a rather costly function call.  You should probably try to avoid
00595  *  setting PIDs at too high a frequency.
00596  */
00597 #ifdef PLATFORM_APERIOS
00598 bool
00599 MotionManager::updatePIDs(OPrimitiveID primIDs[NumOutputs]) {
00600   //cout << "updatePIDs " << endl;
00601   bool dirty=!pidchanges.empty();
00602   while(!pidchanges.empty()) {
00603     float gain[3];
00604     word shift[3];
00605     
00606     //if you want to enforce the default shifts:
00607     for(uint i=0; i<3; i++) {
00608       shift[i]=DefaultPIDShifts[i];
00609       gain[i]=pidchanges.front().pids[i]*(1<<(0x10-shift[i]));
00610     }
00611     
00612     //if you want to allow shifts to move for better precision:
00613     // this is OK on 2xx, although it occasionally produces warnings like:
00614     // AGRMSDriver::SetGain() : 0x0A IS USED FOR GAIN SHIFT VALUE.
00615     // It still seems to work fine though.
00616     // HOWEVER, the ERS-7 is a different story.  Apparently ( https://openr.aibo.com/cgi-bin/openr/e_regi/im_trbbs.cgi?uid=general&df=bbs.dat&prm=TAN&pg=1&no=0893#0893 )
00617     // all joints share the same shift, and so there must be one
00618     // global setting enforced.  If this is the way things are heading,
00619     // might as well just have everyone use the first method instead.
00620     // but here's the more dynamic way just for posterity:
00621     /*
00622     for(uint i=0; i<3; i++) {
00623       gain[i]=pidchanges.front().pids[i]*2;
00624       shift[i]=0xF;
00625       while(shift[i]!=2 && (gain[i]!=(word)gain[i] || gain[i]<=1) && gain[i]<0x20) {
00626         gain[i]*=2;
00627         shift[i]--;
00628       }
00629     }
00630      */
00631     
00632     //some debugging output (pick your favorite joint - i was having trouble with the ERS-7 nod joint in particular)
00633     //if(pidchanges.front().joint==HeadOffset+NodOffset)
00634     //cout << (word)gain[0] << ' ' << shift[0] << "   " << (word)gain[1] << ' ' << shift[1] << "   " << (word)gain[2] << ' ' << shift[2] << endl;
00635     //cout << gain[0] << ' ' << shift[0] << "   " << gain[1] << ' ' << shift[1] << "   " << gain[2] << ' ' << shift[2] << endl;
00636     
00637     OPENR::SetJointGain(primIDs[pidchanges.front().joint],(word)gain[0],(word)gain[1],(word)gain[2],shift[0],shift[1],shift[2]);
00638     for(uint i=0; i<3; i++)
00639       state->pids[pidchanges.front().joint][i]=pidchanges.front().pids[i];
00640     pidchanges.pop_front();
00641   }
00642   return dirty;
00643 }
00644 #else
00645 bool
00646 MotionManager::updatePIDs(std::vector<std::pair<unsigned int, float[3]> >& pids) {
00647   //cout << "updatePIDs " << endl;
00648   bool dirty=!pidchanges.empty();
00649   std::pair<unsigned int, float[3]> entry;
00650   while(!pidchanges.empty()) {
00651     entry.first=pidchanges.front().joint;
00652     for(uint i=0; i<3; i++)
00653       state->pids[entry.first][i] = entry.second[i] = pidchanges.front().pids[i];
00654     pids.push_back(entry);
00655     pidchanges.pop_front();
00656   }
00657   return dirty;
00658 }
00659 #endif //PLATFORM_APERIOS or PLATFORM_LOCAL
00660 
00661 #ifdef PLATFORM_APERIOS
00662 void
00663 MotionManager::receivedMsg(const ONotifyEvent& event) {
00664   //  cout << "receivedMsg..." << flush;
00665   func_begin();
00666   //  cout << id << "..." << flush;
00667   //cout << "Received at " << get_time() << endl;
00668   for(int x=0; x<event.NumOfData(); x++)
00669     processMsg(event.RCData(x));
00670   //  cout << "receivedMsg-done" << endl;
00671   func_end();
00672 }
00673 #else //PLATFORM_LOCAL
00674 bool
00675 MotionManager::receivedMsg(RCRegion* msg) {
00676   try {
00677     Thread::NoCancelScope nc;
00678     MarkScope l(*motman->procLocks[getAccID()]);
00679     /*MotionManagerMsg * mminfo = reinterpret_cast<MotionManagerMsg*>(msg->Base());
00680     if(mminfo->creatorPID==ProcessID::getID())
00681       return true; //don't process echos*/
00682     motman->processMsg(msg);
00683   } catch(const std::exception& ex) {
00684     if(!ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionManagerMsg processing (MotionManager::receivedMsg)",&ex))
00685       throw;
00686   } catch(...) {
00687     if(!ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionManagerMsg processing (MotionManager::receivedMsg)",NULL))
00688       throw;
00689   }
00690   return true;
00691 }
00692 #endif //PLATFORM_APERIOS or PLATFORM_LOCAL
00693 
00694 void
00695 MotionManager::processMsg(RCRegion * rcr) {
00696   //cout << "processMsg..." << flush;
00697   if(rcr==NULL) {
00698     cout << "WARNING: MotionManager::processMsg was given a NULL region" << endl;
00699     return;
00700   }
00701   MotionManagerMsg * mminfo = reinterpret_cast<MotionManagerMsg*>(rcr->Base());
00702 #ifndef PLATFORM_APERIOS
00703   if(mminfo->creatorPID==ProcessID::getID())
00704     return; // don't process echos
00705 #endif
00706 
00707   func_begin();
00708   const accID_t MYACCID = getAccID();
00709   //cout << ProcessID::getIDStr() << "..." << flush;
00710   MC_ID mc_id=mminfo->mc_id;
00711   switch(mminfo->type) {
00712     case MotionManagerMsg::addMotion: {
00713       if(mc_id==invalid_MC_ID) { // || cmdlist[mc_id].lastAccessor==(accID_t)-1
00714         cout << "WARNING: MotionManager::processMsg addMotion for invalid_MC_ID motion" << endl;
00715         func_end();
00716         return;
00717       }
00718       if(cmdlist[mc_id].rcr[MYACCID]!=NULL) {
00719         cerr << "WARNING: MotionManager::processMsg addMotion for motion which was already added!" << endl;
00720       } else {
00721         //cout << "receiveMotion()NOW: rcr->NumberOfReference()==" << rcr->NumberOfReference() << endl;
00722         cmdlist[mc_id].rcr[MYACCID]=rcr;
00723         //cout << "receiveMotion(): rcr->NumberOfReference()==" << rcr->NumberOfReference() << endl;
00724         rcr->AddReference();
00725         //should be able to do a nice dynamic cast instead of a static one
00726         // but it gives NULL for some reason - i blame having to do the fork trick
00727         //cout << "Adding mc_id=="<< mc_id << " (and dynamic_cast is still " << dynamic_cast<MotionCommand*>(mminfo) << ")" << endl;
00728         cmdlist[mc_id].baseaddrs[MYACCID]=static_cast<MotionCommand*>(mminfo);
00729       }
00730       if(ProcessID::getID()==ProcessID::MotionProcess && cmdlist[mc_id].lastAccessor!=(accID_t)-1) {
00731         checkoutMotion(mc_id,true);
00732         try {
00733           cmdlist[mc_id].baseaddrs[MYACCID]->start();
00734         } catch(const std::exception& ex) {
00735           ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand::start()",&ex);
00736         } catch(...) {
00737           ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand::start()",NULL);
00738         }
00739         checkinMotion(mc_id);
00740       }
00741     } break;
00742     case MotionManagerMsg::deleteMotion: {
00743       //cout << "deleteMotion(): cmdlist[mc_id].rcr[MYACCID]->NumberOfReference()==" << cmdlist[mc_id].rcr[MYACCID]->NumberOfReference() << endl;
00744       //cout << "deleting mc_id=="<<mc_id << "..." << flush;
00745       ASSERT(cmdlist[mc_id].lastAccessor==(accID_t)-1,"delete motion message for motion command not marked for deletion");
00746       if(cmdlist[mc_id].rcr[MYACCID]==NULL) {
00747         cout << "WARNING: MotionManager attempted to delete a NULL motion! mc_id="<<mc_id<<" process=" << ProcessID::getIDStr() << endl;
00748         stacktrace::displayCurrentStackTrace();
00749       } else {
00750         cmdlist[mc_id].lock.lock(MYACCID);
00751         unsigned int found=0;
00752         for(unsigned int i=0; i<numAcc; i++) {
00753           if(cmdlist[mc_id].rcr[i]!=NULL) {
00754             found++;
00755           }
00756         }
00757         ASSERT(found>0,"WARNING: MotionManager::processMsg underflow");
00758         if(found==1 && mc_id==cmdlist[mc_id].baseaddrs[MYACCID]->mc_id) // now removing last reference, and no in-flight re-add under new ID
00759           cmdlist[mc_id].baseaddrs[MYACCID]->clearID();
00760         cmdlist[mc_id].rcr[MYACCID]->RemoveReference();
00761         cmdlist[mc_id].rcr[MYACCID]=NULL;
00762         cmdlist[mc_id].baseaddrs[MYACCID]=NULL;
00763         if(found==1) {
00764           push_free(mc_id); //don't unlock -- lock destructor will release the lock as the entry is destructed
00765         } else {
00766           cmdlist[mc_id].lock.unlock();
00767         }
00768         if(ProcessID::getID()==ProcessID::MainProcess) {
00769           try {
00770             erouter->postEvent(EventBase::motmanEGID,mc_id,EventBase::deactivateETID,0);
00771           } catch(const std::exception& ex) {
00772             ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during event posting",&ex);
00773           } catch(...) {
00774             ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during event posting",NULL);
00775           }
00776         }
00777       }
00778       //cout << "deleteMotion()NOW: cmdlist[mc_id].rcr[MYACCID]->NumberOfReference()==" << cmdlist[mc_id].rcr[MYACCID]->NumberOfReference() << endl;
00779     } break;
00780     default:
00781       printf("*** WARNING *** unknown MotionManager msg type received\n");
00782   }
00783   //cout << "processMsg-done" << endl;
00784   func_end();
00785 }
00786 
00787 
00788 /*! We have made this function protected because it's more readable if you
00789 *  call addPrunableMotion() or addPersistentMotion() instead... we decided
00790 *  requiring people to pass a true/false arguement wouldn't make it clear
00791 *  what that true/false was controlling. */
00792 MotionManager::MC_ID 
00793 MotionManager::doAddMotion(const SharedObjectBase& sm, bool autoprune, float priority) {
00794   MotionCommand * mc = dynamic_cast<MotionCommand*>(static_cast<MotionManagerMsg*>(sm.data()));
00795   if(mc==NULL) {
00796     cout << "MotionManager::addMotion() - SharedObject does not seem to hold a MotionCommand" << endl;
00797     return invalid_MC_ID;
00798   }
00799   mc->setAutoPrune(autoprune);
00800   //cout << "addMotion...";
00801   while(numAcc<MAX_ACCESS-1) { std::cout << "WAIT" << std::flush; } //Wait for everyone to register
00802   func_begin();
00803   const accID_t MYACCID = getAccID();
00804   //cout << cmdlist.size() << " exist..." << endl;
00805   //  cout << id << "..." << flush;
00806   for(MC_ID it=cmdlist.begin(); it!=cmdlist.end(); it=cmdlist.next(it)) {
00807     if(cmdlist[it].baseaddrs[MYACCID]==mc) {
00808       cerr << "Warning: adding motion command at " << mc << ", is already running in motion manager as MC_ID " << it << endl;
00809       return func_end(it);
00810     }
00811   }
00812   MC_ID mc_id = pop_free();
00813   //cout << sm.getRegion()->ID().key << " holds " << mc_id << endl;
00814   if(mc_id==cmdlist.end()) {
00815     cout << "MotionManager::addMotion() - Out of room, could not add" << endl;
00816     return func_end(cmdlist.end());
00817   }
00818   //cout << "setAdd(" << mc_id << ")" << endl;
00819   mc->setAdd(mc_id);
00820   cmdlist[mc_id].baseaddrs[MYACCID]=mc;
00821   cmdlist[mc_id].rcr[MYACCID]=sm.getRegion();
00822   //cout << "addMotion(): sm.getRegion()->NumberOfReference()==" << sm.getRegion()->NumberOfReference() << endl;
00823   cmdlist[mc_id].rcr[MYACCID]->AddReference();
00824   //cout << "addMotion()NOW: sm.getRegion()->NumberOfReference()==" << sm.getRegion()->NumberOfReference() << endl;
00825   cmdlist[mc_id].lastAccessor=MYACCID;
00826   cmdlist[mc_id].priority=priority;
00827   try {
00828     erouter->postEvent(EventBase::motmanEGID,mc_id,EventBase::activateETID,0);
00829   } catch(const std::exception& ex) {
00830     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during event posting",&ex);
00831   } catch(...) {
00832     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during event posting",NULL);
00833   }
00834   
00835   // only send remove message if there is still a reference
00836   // otherwise, the previous add message is probably still in transit, and we cleared the mc_id, so it will be ignored
00837 #ifdef PLATFORM_APERIOS
00838   OStatus err;
00839   /*{
00840    unsigned int i=0;
00841    for(ObserverConstIterator it=subjs[MYACCID]->begin();it!=subjs[MYACCID]->end();it++) {
00842    cout << "RemainBuffer("<<i++<<")==" << subjs[MYACCID]->RemainBuffer(*it) << endl;
00843    }
00844    ASSERT((int)i==subjs[MYACCID]->NumberOfObservers(),"did I miss an observer?");
00845    }*/
00846   //cout << "Sent at " << get_time() << flush;
00847   err=subjs[MYACCID]->SetData(sm.getRegion());
00848   ASSERT(err==oSUCCESS,"*** ERROR MotionManager: SetData returned " << err);
00849   //cout << "addMotion()afterSetData: sm.getRegion()->NumberOfReference()==" << sm.getRegion()->NumberOfReference() << endl;
00850   err=subjs[MYACCID]->NotifyObservers();
00851   ASSERT(err==oSUCCESS,"*** ERROR MotionManager: NotifyObservers returned " << err);
00852 #else //PLATFORM_LOCAL
00853   try {
00854     subjs[MYACCID]->sendMessage(sm.getRegion());
00855   } catch(const std::exception& ex) {
00856     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during message sending",&ex);
00857   } catch(...) {
00858     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during message sending",NULL);
00859   }
00860 #endif //PLATFORM check for IPC stuff
00861   //  cout << "addMotion-done" << endl;
00862   //cout << " - " << get_time() << endl;
00863   return func_end(mc_id);
00864 }
00865 
00866 MotionCommand *
00867 MotionManager::checkoutMotion(MC_ID mcid,bool block) const {
00868   //cout << "checkout..." << flush;
00869   if(mcid>=MAX_MOTIONS || mcid==invalid_MC_ID) {
00870     cout << "*** ERROR *** " << ProcessID::getIDStr() << " tried to access invalid mcid " << mcid << endl;
00871     stacktrace::displayCurrentStackTrace();
00872     return NULL;
00873   }
00874   if(cmdlist[mcid].lastAccessor==(accID_t)-1) { // test both before and after the block
00875     cout << "*** WARNING *** " << ProcessID::getIDStr() << " tried to access dead mcid " << mcid << endl;
00876     stacktrace::displayCurrentStackTrace();
00877     return NULL;
00878   }
00879   // block would lock up if the motion is dead in the simulator (left in a locked state)
00880   if(block)
00881     cmdlist[mcid].lock.lock(getAccID());
00882   else
00883     if(!cmdlist[mcid].lock.try_lock(getAccID()))
00884       return NULL;
00885   if(cmdlist[mcid].lastAccessor==(accID_t)-1) { // test both before and after the block
00886     cout << "*** WARNING *** " << ProcessID::getIDStr() << " tried to access mcid as it was removed " << mcid << endl;
00887     stacktrace::displayCurrentStackTrace();
00888     cmdlist[mcid].lock.unlock();
00889     return NULL;
00890   }
00891   //cout << "locked..." << endl;
00892   //cout << "checkout-done..." << flush;
00893   return convertMotion(mcid);
00894 }
00895 
00896 MotionCommand *
00897 MotionManager::convertMotion(MC_ID mc) const {
00898   const accID_t MYACCID = getAccID();
00899   MotionCommand * base = cmdlist[mc].baseaddrs[MYACCID];
00900   //  cout << "base=" << base << "..." << flush;
00901   if(cmdlist[mc].lastAccessor!=MYACCID) {
00902     //cout << "converting from " << MCRegistrar::getRaw(base) << "..." << flush;
00903     //cout << "prev=" << accRegs[cmdlist[mcid].lastAccessor].getReg(base) << "..." << flush;
00904     //    accRegs[id].convert(base);
00905     //cout << "to=" << MCRegistrar::getRaw(base) << ", " << accRegs[cmdlist[mcid].lastAccessor].getReg(base) << endl;
00906     cmdlist[mc].lastAccessor=MYACCID;
00907   }
00908   base->setTranslator(etrans);
00909 #ifdef PLATFORM_APERIOS
00910   base->setWorldState(state);
00911 #endif
00912   return base;
00913 }
00914 
00915 void
00916 MotionManager::checkinMotion(MC_ID mcid) const {
00917   if(mcid>=MAX_MOTIONS || mcid==invalid_MC_ID) {
00918     cout << "*** ERROR *** " << ProcessID::getIDStr() << " tried to checkin invalid mcid " << mcid << endl;
00919     stacktrace::displayCurrentStackTrace();
00920     return;
00921   }
00922   const accID_t MYACCID = getAccID();
00923   if(cmdlist[mcid].lock.get_lock_level()==1 && cmdlist[mcid].rcr[MYACCID]!=NULL) { //about to release last lock (and region hasn't been removed)
00924     MotionCommand * base = cmdlist[mcid].baseaddrs[MYACCID];
00925     base->setTranslator(NULL);
00926 #ifdef PLATFORM_APERIOS
00927     base->setWorldState(NULL);
00928 #endif
00929   }
00930   cmdlist[mcid].lock.unlock();
00931 }
00932 
00933 void
00934 MotionManager::removeMotion(MC_ID mcid) {
00935   if(mcid>=MAX_MOTIONS || mcid==invalid_MC_ID)
00936     return;
00937   func_begin();
00938   const accID_t MYACCID = getAccID();
00939   if(cmdlist[mcid].lastAccessor==(accID_t)-1) {
00940     cout << "WARNING: removeMotion called for a motion which has already been removed mc_id="<<mcid<<" process=" << ProcessID::getIDStr() << endl;
00941     stacktrace::displayCurrentStackTrace();
00942     func_end();
00943     return;
00944   }
00945   if(cmdlist[mcid].rcr[MYACCID]==NULL) { 
00946     cout << "WARNING: removeMotion called for a NULL motion! mc_id="<<mcid<<" process=" << ProcessID::getIDStr() << endl;
00947     stacktrace::displayCurrentStackTrace();
00948     func_end();
00949     return;
00950   }
00951   cmdlist[mcid].lock.lock(MYACCID);
00952   MotionCommand * mc=checkoutMotion(mcid,true);
00953   try {
00954     mc->stop();
00955   } catch(const std::exception& ex) {
00956     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand::stop()",&ex);
00957   } catch(...) {
00958     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during MotionCommand::stop()",NULL);
00959   }
00960   checkinMotion(mcid);
00961   cmdlist[mcid].lastAccessor=(accID_t)-1;
00962   cmdlist[mcid].rcr[MYACCID]->RemoveReference();
00963   cmdlist[mcid].rcr[MYACCID]=NULL;
00964   cmdlist[mcid].baseaddrs[MYACCID]=NULL;
00965   cmdlist[mcid].lock.unlock();
00966   if(ProcessID::getID()==ProcessID::MainProcess) {
00967     try {
00968       erouter->postEvent(EventBase::motmanEGID,mcid,EventBase::deactivateETID,0);
00969     } catch(const std::exception& ex) {
00970       ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during event posting",&ex);
00971     } catch(...) {
00972       ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during event posting",NULL);
00973     }
00974   }
00975 #ifdef PLATFORM_APERIOS
00976   MotionManagerMsg dmsg;
00977   dmsg.setDelete(mcid);
00978   //cout << "Remove at " << get_time() << flush;
00979   subjs[MYACCID]->SetData(&dmsg,sizeof(dmsg));
00980   subjs[MYACCID]->NotifyObservers();
00981 #else //PLATFORM_LOCAL
00982   // local will "echo" the message, so we'll do the actual remove when we get the echo
00983   SharedObject<MotionManagerMsg> dmsg;
00984   dmsg->setDelete(mcid);
00985   //cout << "Remove at " << get_time() << flush;
00986   try {
00987     subjs[MYACCID]->sendMessage(dmsg.getRegion());
00988   } catch(const std::exception& ex) {
00989     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during message sending",&ex);
00990   } catch(...) {
00991     ProjectInterface::uncaughtException(__FILE__,__LINE__,"Occurred during message sending",NULL);
00992   }
00993 #endif //PLATFORM check for IPC stuff
00994   func_end();
00995 }
00996 
00997 
00998 /*! Note that we don't actually set the PIDs in the system here, we just queue them up.
00999  *  PID changes seem to be an expensive operation, so may only want to clear the queue
01000  *  at some reduced rate (although that's not actually currently being done, it just
01001  *  could be) */
01002 void
01003 MotionManager::setPID(unsigned int joint, const float pids[3]) {
01004   func_begin();
01005 
01006   //see if there's already an update for this joint
01007   for(uint u = pidchanges.begin(); u!=pidchanges.end(); u=pidchanges.next(u)) {
01008     if(pidchanges[u].joint==joint) { //found it
01009       for(uint i=0; i<3; i++) {
01010         pidchanges[u].pids[i]=pids[i];
01011         if(pids[i]!=state->pids[joint][i]) { //see if we're setting back to current PID
01012           for(i++; i<3; i++) //we aren't, copy over the rest
01013             pidchanges[u].pids[i]=pids[i];
01014           func_end();
01015           return;
01016         }
01017       }
01018       //if it didn't return within the loop, no difference was found from current state
01019       //so just delete the update
01020       pidchanges.erase(u);
01021       func_end();
01022       return;
01023     }
01024   }
01025 
01026   //if we completed the for loop, we didn't find an update for the joint
01027   for(uint i=0; i<3; i++) //check to see if it's different from the current
01028     if(pids[i]!=state->pids[joint][i]) {
01029       PIDUpdate update(joint,pids); //it is different, insert a new update
01030       pidchanges.push_back(update);
01031       // or for debugging:
01032       //ListMemBuf<PIDUpdate,NumPIDJoints>::index_t it=pidchanges.push_back(update);
01033       //ASSERT(it!=pidchanges.end(),"MotionManager ran out of pidchanges entries!");
01034       break;
01035     }
01036   func_end();
01037 }
01038 
01039 
01040 MotionManager::MC_ID
01041 MotionManager::skip_ahead(MC_ID mcid) const {
01042   // this is in case a new motion has been added, but the current
01043   // process hasn't received its own copy yet, so should skip over them
01044   while(mcid!=cmdlist.end() && cmdlist[mcid].rcr[getAccID()]==NULL)
01045     mcid=cmdlist.next(mcid);
01046   return mcid;
01047 }
01048 
01049 MotionManager::OutputState::OutputState()
01050   : priority(0),mcid(MotionManager::invalid_MC_ID), pid()
01051 {}
01052 MotionManager::OutputState::OutputState(unsigned int out, float pri, MC_ID mc, const OutputCmd cmds[NumFrames])
01053   : priority(pri),mcid(mc), pid(DefaultPIDs[out])
01054 {
01055   for(unsigned int i=0; i<NumFrames; i++)
01056     frames[i]=cmds[i];
01057 }
01058 MotionManager::OutputState::OutputState(unsigned int out, float pri, MC_ID mc, const OutputCmd& cmd)
01059   : priority(pri),mcid(mc), pid(DefaultPIDs[out])
01060 {
01061   for(unsigned int i=0; i<NumFrames; i++)
01062     frames[i]=cmd;
01063 }
01064 MotionManager::OutputState::OutputState(unsigned int out, float pri, MC_ID mc, const OutputCmd& cmd, unsigned int frame)
01065   : priority(pri),mcid(mc), pid(DefaultPIDs[out])
01066 {
01067   frames[frame]=cmd;
01068 }
01069 MotionManager::OutputState::OutputState(unsigned int /*out*/, float pri, MC_ID mc, const OutputPID& p)
01070   : priority(pri),mcid(mc), pid(p)
01071 {}
01072 MotionManager::OutputState::OutputState(unsigned int /*out*/, float pri, MC_ID mc, const OutputCmd cmds[NumFrames], const OutputPID& p)
01073   : priority(pri),mcid(mc), pid(p)
01074 {
01075   for(unsigned int i=0; i<NumFrames; i++)
01076     frames[i]=cmds[i];
01077 }
01078 MotionManager::OutputState::OutputState(unsigned int /*out*/, float pri, MC_ID mc, const OutputCmd& cmd, const OutputPID& p)
01079   : priority(pri),mcid(mc), pid(p)
01080 {
01081   for(unsigned int i=0; i<NumFrames; i++)
01082     frames[i]=cmd;
01083 }
01084 
01085 
01086 /*! @file
01087  * @brief Implements MotionManager, simplifies sharing of MotionCommand's and provides mutual exclusion to their access
01088  * @author ejt (Creator)
01089  */
01090 
01091 
01092 /*
01093     for(uint f=0;f<NumFrames;f++)
01094       for(uint i=0; i<NumOutputs; i++)
01095         outputs[f][i]=0;
01096     const uint cyctime=128;
01097     uint ot=get_time()+3*cyctime;
01098     for(uint f=0;f<NumFrames;f++) {
01099       uint t=ot+f*FrameTime;
01100       outputs[f][TopBrLEDOffset]=(t/(double)cyctime-t/cyctime)*.75+.25;
01101       t-=cyctime;
01102       outputs[f][TopLLEDOffset]=(t/(double)cyctime-t/cyctime)*.75+.25;
01103       outputs[f][TopRLEDOffset]=(t/(double)cyctime-t/cyctime)*.75+.25;
01104       t-=cyctime;
01105       outputs[f][MidLLEDOffset]=(t/(double)cyctime-t/cyctime)*.75+.25;
01106       outputs[f][MidRLEDOffset]=(t/(double)cyctime-t/cyctime)*.75+.25;
01107       t-=cyctime;
01108       outputs[f][BotLLEDOffset]=(t/(double)cyctime-t/cyctime)*.75+.25;
01109       outputs[f][BotRLEDOffset]=(t/(double)cyctime-t/cyctime)*.75+.25;
01110     }
01111 */
01112 
01113   /*  for(uint output=TlRedLEDOffset-1; output<LEDOffset+NumLEDs-1; output++) {
01114     cmdstatelist_t& curstatelist=cmdstates[output];
01115     cout << "Out " << output << ": ";
01116     for(cmdstatelist_t::index_t bit=curstatelist.begin(); bit!=curstatelist.end(); bit=curstatelist.next(bit))
01117       cout << '('<<curstatelist[bit].mcid<<','<<cmdlist[curstatelist[bit].mcid].priority<<','<<curstatelist[bit].frames[0].value<<','<<curstatelist[bit].frames[0].weight<<") ";
01118     cout << endl;
01119     }*/
01120 
01121 
01122   /*  cout << get_time() << ' ' << size() << endl;
01123   for(uint output=TlRedLEDOffset; output<LEDOffset+NumLEDs-1; output++) {
01124     cmdstatelist_t& curstatelist=cmdstates[output];
01125     cout << "Out " << output << ": ";
01126     for(cmdstatelist_t::index_t bit=curstatelist.begin(); bit!=curstatelist.end(); bit=curstatelist.next(bit))
01127       cout << '('<<curstatelist[bit].mcid<<','<<cmdlist[curstatelist[bit].mcid].priority<<','<<curstatelist[bit].frames[0].value<<','<<curstatelist[bit].frames[0].weight<<") ";
01128     cout << endl;
01129   }
01130   */

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:45 2016 by Doxygen 1.6.3