Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PostureEngine.cc

Go to the documentation of this file.
00001 #include "PostureEngine.h"
00002 #include "Shared/WorldState.h"
00003 #include "Motion/IKSolver.h"
00004 #include "Shared/Config.h"
00005 #include "Shared/string_util.h"
00006 #include <stdio.h>
00007 #include <iostream>
00008 #include <regex.h>
00009 #include <map>
00010 #include <memory>
00011 
00012 using namespace std;
00013 
00014 PostureEngine::~PostureEngine() {}
00015 
00016 void PostureEngine::takeSnapshot() {
00017   takeSnapshot(*WorldState::getCurrent());
00018 }
00019 
00020 void PostureEngine::takeSnapshot(const WorldState& st) {
00021   for(unsigned int i=0; i<NumOutputs; i++)
00022     cmds[i].value=st.outputs[i];
00023 }
00024 
00025 void PostureEngine::setWeights(float w, unsigned int lowjoint, unsigned int highjoint) {
00026   for(unsigned int i=lowjoint; i<highjoint; i++)
00027     cmds[i].weight=w;
00028 }
00029 
00030 void PostureEngine::clear() {
00031   for(unsigned int i=0; i<NumOutputs; i++)
00032     cmds[i].unset();
00033 }
00034 
00035 PostureEngine& PostureEngine::setOverlay(const PostureEngine& pe) {
00036   for(unsigned int i=0; i<NumOutputs; i++)
00037     if(pe.cmds[i].weight>0)
00038       cmds[i]=pe.cmds[i];
00039   return *this;
00040 }
00041 PostureEngine PostureEngine::createOverlay(const PostureEngine& pe) const {
00042   PostureEngine tmp(*this);
00043   return tmp.setOverlay(pe);
00044 }
00045 PostureEngine& PostureEngine::setUnderlay(const PostureEngine& pe) {
00046   for(unsigned int i=0; i<NumOutputs; i++)
00047     if(cmds[i].weight<=0)
00048       cmds[i]=pe.cmds[i];
00049   return *this;
00050 }
00051 PostureEngine PostureEngine::createUnderlay(const PostureEngine& pe) const {
00052   PostureEngine tmp(*this);
00053   return tmp.setUnderlay(pe);
00054 }
00055 /*! joints being averaged with unused joints have their weights averaged, but not their values (so an output can crossfade properly)\n
00056  *  @param pe the other PostureEngine
00057  *  @param w amount to weight towards @a pe
00058  *  - if @a w < .001, nothing is done
00059  *  - if @a w > .999, a straight copy of @a pe occurs (sets joints to unused properly at end of fade)
00060  *  - .001 and .999 is used instead of 0 and 1 to allow for slight addition errors in a loop (if
00061  *    using repeated additions of a delta value instead of repeated divisions)
00062  *  @return @c *this, stores results into this */
00063 PostureEngine& PostureEngine::setAverage(const PostureEngine& pe, float w) {
00064   if(w<0.001)
00065     return *this;
00066   if(w>0.999)
00067     return (*this=pe);
00068   float wp=1-w;
00069   for(unsigned int i=0; i<NumOutputs; i++)
00070     if(cmds[i].weight>0) {
00071       if(pe.cmds[i].weight>0)
00072         cmds[i].set(cmds[i].value*wp+pe.cmds[i].value*w,cmds[i].weight*wp+pe.cmds[i].weight*w);
00073       else
00074         cmds[i].weight*=wp;
00075     } else
00076       cmds[i].set(pe.cmds[i].value,pe.cmds[i].weight*w);
00077   return *this;
00078 }
00079 /*! joints being averaged with weight<=0 have their weights averaged, but not their values (so an output can crossfade properly)\n
00080  *  @param pe the other PostureEngine
00081  *  @param w amount to weight towards @a pe
00082  *  - if @a w < .001, nothing is done
00083  *  - if @a w > .999, a straight copy of @a pe occurs (sets joints to unused properly at end of fade)
00084  *  - .001 and .999 is used instead of 0 and 1 to allow for slight addition errors in a loop (if
00085  *    using repeated additions of a delta value instead of repeated divisions)
00086  *  @return a new posture containing the results */
00087 PostureEngine PostureEngine::createAverage(const PostureEngine& pe, float w) const {
00088   PostureEngine tmp(*this);
00089   return tmp.setAverage(pe,w);
00090 }
00091 PostureEngine& PostureEngine::setCombine(const PostureEngine& pe) {
00092   for(unsigned int i=0; i<NumOutputs; i++) {
00093     float total=cmds[i].weight+pe.cmds[i].weight;
00094     cmds[i].set((cmds[i].value*cmds[i].weight+pe.cmds[i].value*pe.cmds[i].weight)/total,total);
00095   }
00096   return *this;
00097 }
00098 PostureEngine PostureEngine::createCombine(const PostureEngine& pe) const {
00099   PostureEngine tmp(*this);
00100   return tmp.setCombine(pe);
00101 }
00102 
00103 float PostureEngine::diff(const PostureEngine& pe) const {
00104   float ans=0;
00105   for(unsigned int i=0; i<NumOutputs; i++)
00106     if(cmds[i].weight>0 && pe.cmds[i].weight>0) {
00107       float dif=cmds[i].value-pe.cmds[i].value;
00108       ans+=dif*dif;
00109     }
00110   return ans;
00111 }
00112 
00113 float PostureEngine::avgdiff(const PostureEngine& pe) const {
00114   float ans=0;
00115   unsigned int cnt=0;
00116   for(unsigned int i=0; i<NumOutputs; i++)
00117     if(cmds[i].weight>0 && pe.cmds[i].weight>0) {
00118       float dif=cmds[i].value-pe.cmds[i].value;
00119       ans+=dif*dif;
00120       cnt++;
00121     }
00122   return ans/cnt;
00123 }
00124 
00125 float PostureEngine::maxdiff(const PostureEngine& pe) const {
00126   float max=0;
00127   for(unsigned int i=0; i<NumOutputs; i++)
00128     if(cmds[i].weight>0 && pe.cmds[i].weight>0) {
00129       float dif=cmds[i].value-pe.cmds[i].value;
00130       if(dif>max)
00131         max=dif;
00132     }
00133   return max;
00134 }
00135 
00136 void PostureEngine::setSaveFormat(bool condensed, WorldState* ws) {
00137   saveFormatCondensed=condensed;
00138   saveSensors=ws;
00139 }
00140 
00141 unsigned int PostureEngine::getBinSize() const {
00142   unsigned int written=11; //accounts for initial #POS\n and final #END\n, plus 1
00143   const unsigned int len=0;
00144   char buf[len];
00145   if(saveFormatCondensed) {
00146 #ifndef PLATFORM_APERIOS
00147     written+=snprintf(buf,len,"condensed %s\n",RobotName);
00148 #else
00149     written+=snprintf(buf,len,"condensed %s\n",RobotName.c_str());
00150 #endif
00151     if(saveSensors!=NULL)
00152       written+=snprintf(buf,len,"meta-info = %u %u\n",saveSensors->lastSensorUpdateTime,saveSensors->frameNumber);
00153     bool weightsAllEqual=true;
00154     float weightsVal=cmds[0].weight;
00155     for(unsigned int i=1; i<NumOutputs && weightsAllEqual; i++)
00156       weightsAllEqual=(cmds[i].weight==weightsVal);
00157     if(!weightsAllEqual || weightsVal!=0) { //if they're all 0, skip outputs and weights
00158       written+=snprintf(buf,len,"outputs =");
00159       for(unsigned int i=0; i<NumOutputs; i++) {
00160         written+=snprintf(buf,len," %g",cmds[i].value);
00161       }
00162       if(!weightsAllEqual || weightsVal!=1) { //if they're all 1, skip weights
00163         written+=snprintf(buf,len,"\nweights =");
00164         for(unsigned int i=0; i<NumOutputs; i++) {
00165           written+=snprintf(buf,len," %g",cmds[i].weight);
00166         }
00167       }
00168       written+=snprintf(buf,len,"\n");
00169     }
00170     if(saveSensors!=NULL) {
00171       written+=snprintf(buf,len,"buttons =");
00172       for(unsigned int i=0; i<NumButtons; i++) {
00173         written+=snprintf(buf,len," %g",saveSensors->buttons[i]);
00174       }
00175       written+=snprintf(buf,len,"\nsensors =");
00176       for(unsigned int i=0; i<NumSensors; i++) {
00177         written+=snprintf(buf,len," %g",saveSensors->sensors[i]);
00178       }
00179       written+=snprintf(buf,len,"\npidduties =");
00180       for(unsigned int i=0; i<NumPIDJoints; i++) {
00181         written+=snprintf(buf,len," %g",saveSensors->pidduties[i]);
00182       }
00183       written+=snprintf(buf,len,"\n");
00184     }   
00185   } else {
00186     if(saveSensors!=NULL)
00187       written+=snprintf(buf,len,"<meta-info>\n  timestamp\t%u\n  framenumber\t%u\n</meta-info>\n",saveSensors->lastSensorUpdateTime,saveSensors->frameNumber);
00188     for(unsigned int i=0; i<NumOutputs; i++)
00189       if(cmds[i].weight>0) {
00190         if(cmds[i].weight==1)
00191           written+=snprintf(buf,len,"%s\t% .4f\n",outputNames[i],cmds[i].value);
00192         else
00193           written+=snprintf(buf,len,"%s\t% .4f\t% .4f\n",outputNames[i],cmds[i].value,cmds[i].weight);
00194       }
00195     if(saveSensors!=NULL) {
00196       written+=snprintf(buf,len,"<buttons>\n");
00197       for(unsigned int i=0; i<NumButtons; i++) {
00198         written+=snprintf(buf,len,"  %s\t% .4f\t\n",buttonNames[i],saveSensors->buttons[i]);
00199       }
00200       written+=snprintf(buf,len,"</buttons><sensors>\n");
00201       for(unsigned int i=0; i<NumSensors; i++) {
00202         written+=snprintf(buf,len,"  %s\t% .4f\t\n",sensorNames[i],saveSensors->sensors[i]);
00203       }
00204       written+=snprintf(buf,len,"</sensors><pidduties>\n");
00205       for(unsigned int i=0; i<NumPIDJoints; i++) {
00206         written+=snprintf(buf,len,"  %s\t% .4f\t\n",outputNames[i],saveSensors->pidduties[i]);
00207       }
00208       written+=snprintf(buf,len,"</pidduties>\n");
00209     }
00210   }
00211   return written;
00212 }
00213 
00214 unsigned int PostureEngine::loadBuffer(const char buf[], unsigned int len, const char* filename) {
00215   unsigned int origlen=len;
00216   clear();
00217   if(buf==NULL || len==0) {
00218     cerr << "*** ERROR: PostureEngine::loadBuffer(" << static_cast<const void*>(buf) << ',' << len << ")" << endl;
00219     return 0;
00220   }
00221   if(strncmp("#POS",buf,4)!=0) {
00222     // we don't want to display an error here because we may be only testing file type,
00223     // so it's up to the caller to decide if it's necessarily an error if the file isn't
00224     // a posture
00225     //std::cout << "ERROR PostureEngine load corrupted - expected #POS header" << std::endl;
00226     return 0;
00227   }
00228   saveFormatCondensed=false;
00229   const Capabilities* caps = &capabilities;
00230   unsigned int linenum=0;
00231   bool filtered=false; // true if in a specialization section for a different model
00232   section_t curSection=SECTION_OUTPUTS;
00233   map<string,section_t> sectionMap;
00234   sectionMap["meta-info"]=SECTION_METAINFO;
00235   sectionMap["outputs"]=SECTION_OUTPUTS;
00236   sectionMap["buttons"]=SECTION_BUTTONS;
00237   sectionMap["sensors"]=SECTION_SENSORS;
00238   sectionMap["pidduties"]=SECTION_PIDDUTIES;
00239   
00240   
00241   while(len<=origlen && len>0) {
00242     // extract a line from the buffer (line endings could be \r, \n, or \r\n )
00243     string line;
00244     for(unsigned int lineend=0; lineend<len; ++lineend) {
00245       bool isreturn = (buf[lineend]=='\r');
00246       bool isnewline = (buf[lineend]=='\n');
00247       bool iseof = (lineend+1==len);
00248       if(isreturn || isnewline || iseof) {
00249         line.assign(buf,(iseof && !isreturn && !isnewline) ? lineend+1 : lineend);
00250         ++linenum;
00251         ++lineend;
00252         buf+=lineend;
00253         len-=lineend;
00254         if(len==0) // end of buffer, don't check for \n
00255           break;
00256         if(isreturn && buf[0]=='\n') { // indicates an \r\n
00257           ++buf;
00258           --len;
00259         }
00260         break;
00261       }
00262     }
00263     
00264     // strip comment
00265     string::size_type commentPos = line.find('#');
00266     if(commentPos!=string::npos) {
00267       if(line.substr(commentPos)=="#END")
00268         return origlen-len;
00269       line = line.substr(0,commentPos);
00270     }
00271     
00272     // tokenize
00273     // whitespace and '=' are used as delimiters
00274     vector<string> words;
00275     for(unsigned int i=0; i<line.size(); ++i) {
00276       if(isspace(line[i]) || line[i]=='=')
00277         continue;
00278       unsigned int j=i+1;
00279       while(j<line.size() && !isspace(line[j]) && line[j]!='=')
00280         ++j;
00281       words.push_back(line.substr(i,j-i));
00282       i=j;
00283     }
00284     if(words.size()==0)
00285       continue;
00286     
00287     // debugging output
00288     /*cout << "LINE " << linenum << endl;
00289     for(unsigned int i=0; i<words.size(); ++i)
00290       cout << '\t' << words[i] << endl;*/
00291     
00292     // process the line!
00293     if(!loadLine(linenum,filename,sectionMap,words,curSection,caps,filtered))
00294       return 0;
00295     
00296   } // end of process-line loop 'while'
00297     
00298   // shouldn't get here, proper file ends with '#END', which will trigger a 'return' within the loop
00299   std::cout << "*** WARNING PostureEngine load missing #END" << std::endl;
00300   return origlen-len;
00301 }
00302 
00303 bool PostureEngine::loadLine(unsigned int linenum, const char* filename, const std::map<std::string,section_t>& sectionMap, std::vector<std::string>& words, section_t& curSection, const Capabilities*& caps, bool& filtered) {
00304   if(words[0]=="specialize") {
00305     if(words.size()>2)
00306       cerr << "*** Warning line " << linenum << ", extra arguments to 'specialize'" << endl;
00307     filtered = false;
00308     if(words.size()>1) try {
00309       filtered = !string_util::reMatch(RobotName,words[1],REG_EXTENDED);
00310     } catch(const std::string& err) {
00311       cerr << "*** ERROR line " << linenum << ", bad regular expression: " << err << endl;
00312       return false;
00313     }
00314     
00315   } else if(words[0]=="condensed") {
00316     if(words.size()>2)
00317       cerr << "*** Warning line " << linenum << ", extra arguments to 'condensed'" << endl;
00318     if(words.size()==1) {
00319       cerr << "*** ERROR line " << linenum << ", missing model name for 'condensed'" << endl;
00320       return false;
00321     } else {
00322       caps = getCapabilities(words[1]);
00323       if(caps==NULL) {
00324         cerr << "*** ERROR line " << linenum << ", unknown model for 'condensed': " << words[1] << endl;
00325         return false;
00326       }
00327       saveFormatCondensed=true;
00328     }
00329     
00330   } else if(words[0]=="verbose") {
00331     if(words.size()>1)
00332       cerr << "*** Warning line " << linenum << ", extra arguments to 'verbose'" << endl;
00333     saveFormatCondensed=false;
00334     
00335   } else if(words[0][0]=='<' && words[0][words[0].size()-1]=='>') {
00336     if(words.size()>1)
00337       cerr << "*** Warning line " << linenum << ", extra arguments to section tag (this isn't a real XML format, tag must be on line by itself)" << endl;
00338     bool isend = (words[0][1]=='/');
00339     const string name = words[0].substr((isend?2:1), words[0].size()-(isend?3:2));
00340     map<string,section_t>::const_iterator it = sectionMap.find(name);
00341     if(it==sectionMap.end()) {
00342       cerr << "*** ERROR line " << linenum << ", unknown section '" << name << "'" << endl;
00343       return false;
00344     }
00345     section_t section = it->second;
00346     if(isend) {
00347       if(curSection!=section)
00348         cerr << "*** Warning line " << linenum << ", mismatched close tag " << name << endl;
00349       curSection=SECTION_OUTPUTS;
00350     } else {
00351       if(curSection!=SECTION_OUTPUTS)
00352         cerr << "*** Warning line " << linenum << " (" << words[0] << "), nested tags not supported, or missing close tag" << endl;
00353       curSection=section;
00354     }
00355     
00356   } else if(filtered) {
00357     // no-op
00358     
00359   } else {
00360     // either a section name (condensed form) or an output/button/sensor name (verbose form)
00361     map<string,section_t>::const_iterator it = sectionMap.find(words[0]);
00362     if(it==sectionMap.end()) {
00363       // not an entry in sectionMap...
00364       if(words[0]=="weights") { // weights is a "condensed-only" section, handled a little specially since it's not in sectionMap...
00365         if(caps==&capabilities) {
00366           // we're using the "native" target... make things a bit quicker
00367           for(unsigned int i=1; i<words.size(); ++i)
00368             cmds[i-1].weight = (float)atof(words[i].c_str());
00369         } else {
00370           // we're using another target, map to the host
00371           for(unsigned int i=1; i<words.size(); ++i) {
00372             const char * name = caps->getOutputName(i-1);
00373             unsigned int off = capabilities.findOutputOffset(name);
00374             if(off==-1U) {
00375               cerr << "*** Warning line " << linenum;
00376               if (filename)
00377                 cerr << " of " << filename;
00378               cerr << ", output '" << name << "' from robot " << caps->getRobotName() << " cannot be mapped to host " << RobotName << endl;
00379             } else {
00380               cmds[off].weight = (float)atof(words[i].c_str());
00381             }
00382           }
00383         }
00384       } else {
00385         // line is not a section declaration -- is it an 'verbose' output/sensor/button/etc. name within the current section??
00386         if(words.size()<2) {
00387           cerr << "*** ERROR line " << linenum;
00388           if (filename)
00389             cerr << " of " << filename;
00390           cerr << ", no value supplied for " << words[0] << endl;
00391           return false;
00392         }
00393         switch(curSection) {
00394           case SECTION_METAINFO: {
00395             if(words[0]=="timestamp") {
00396               if(loadSensors!=NULL)
00397                 loadSensors->timestamp = atoi(words[1].c_str());
00398             } else if(words[0]=="framenumber") {
00399               if(loadSensors!=NULL)
00400                 loadSensors->frameNumber = atoi(words[1].c_str());
00401             } else {
00402               cerr << "*** Warning line " << linenum;
00403               if (filename)
00404                 cerr << " of " << filename;
00405               cerr << ", '" << words[0] << "' is not a valid meta-info" << endl;
00406             }
00407           } break;
00408           case SECTION_OUTPUTS: {
00409             stripTildes(words[0]);
00410             unsigned int off = capabilities.findOutputOffset(words[0].c_str()), loff=-1U;
00411             if(off==-1U) {
00412               // try again with L/R prefixes
00413               loff = capabilities.findOutputOffset(('L'+words[0]).c_str());
00414               if(loff!=-1U)
00415                 off = capabilities.findOutputOffset(('R'+words[0]).c_str());
00416             }
00417             if(off==-1U) {
00418               cerr << "*** Warning line " << linenum;
00419               if (filename)
00420                 cerr << " of " << filename;
00421               cerr << ", '" << words[0] << "' is not a valid output on this model (" << RobotName << ")" << endl;
00422             } else {
00423               float value = (float)atof(words[1].c_str());
00424               float weight=1;
00425               if(words.size()>2)
00426                 weight = (float)atof(words[2].c_str());
00427               cmds[off].set(value,weight);
00428               if(loff!=-1U)
00429                 cmds[loff].set(value,weight);
00430             }
00431           } break;
00432           case SECTION_BUTTONS: {
00433             unsigned int off = capabilities.findButtonOffset(words[0].c_str());
00434             if(off==-1U) {
00435               cerr << "*** Warning line " << linenum;
00436               if (filename)
00437                 cerr << " of " << filename;
00438               cerr << ", '" << words[0] << "' is not a valid button on this model (" << RobotName << ")" << endl;
00439             } else if(loadSensors!=NULL) {
00440               loadSensors->buttons[off] = (float)atof(words[1].c_str());
00441             }
00442           } break;
00443           case SECTION_SENSORS: {
00444             unsigned int off = capabilities.findSensorOffset(words[0].c_str());
00445             if(off==-1U) {
00446               cerr << "*** Warning line " << linenum;
00447               if (filename)
00448                 cerr << " of " << filename;
00449               cerr << ", '" << words[0] << "' is not a valid sensor on this model (" << RobotName << ")" << endl;
00450             } else if(loadSensors!=NULL) {
00451               loadSensors->sensors[off] = (float)atof(words[1].c_str());
00452             }
00453           } break;
00454           case SECTION_PIDDUTIES: {
00455             stripTildes(words[0]);
00456             unsigned int off = capabilities.findOutputOffset(words[0].c_str());
00457             if(off==-1U) {
00458               cerr << "*** Warning line " << linenum;
00459               if (filename)
00460                 cerr << " of " << filename;
00461               cerr << ", '" << words[0] << "' is not a valid output on this model (" << RobotName << ")" << endl;
00462             } else if(off<PIDJointOffset || off>=PIDJointOffset+NumPIDJoints) {
00463               cerr << "*** Warning line " << linenum;
00464               if (filename)
00465                 cerr << " of " << filename;
00466               cerr << ", output '" << words[0] << "' from robot " << caps->getRobotName() << " does not map to a PID joint on the local host " << RobotName << endl;
00467             } else if(loadSensors!=NULL) {
00468               loadSensors->pidduties[off-PIDJointOffset] = (float)atof(words[1].c_str());
00469             }
00470           } break;
00471         } // end of section 'switch'
00472       } // end of condensed 'weight' section vs. verbose entry 'else'
00473       
00474     } else {
00475       // is a section name (aka condensed entry)
00476       switch(it->second) {
00477         case SECTION_METAINFO: {
00478           if(loadSensors==NULL)
00479             break;
00480           if(words.size()>1)
00481             loadSensors->timestamp = atoi(words[1].c_str());
00482           if(words.size()>1)
00483             loadSensors->frameNumber = atoi(words[2].c_str());
00484         } break;
00485         case SECTION_OUTPUTS: {
00486           unsigned int size=words.size();
00487           if(size-1!=caps->getNumOutputs()) {
00488             cerr << "*** ERROR line " << linenum;
00489             if (filename)
00490               cerr << " of " << filename;
00491             cerr << ", " << caps->getRobotName() << " expected " << caps->getNumOutputs() << " values, got " << (size-1) << endl;
00492             return 0;
00493           }
00494           if(caps==&capabilities) {
00495             // we're using the "native" target... make things a bit quicker
00496             for(unsigned int i=1; i<size; ++i)
00497               cmds[i-1].set((float)atof(words[i].c_str()));
00498           } else {
00499             // we're using another target, map to the host
00500             for(unsigned int i=1; i<size; ++i) {
00501               const char * name = caps->getOutputName(i-1);
00502               unsigned int off = capabilities.findOutputOffset(name);
00503               if(off==-1U) {
00504                 cerr << "*** Warning line " << linenum;
00505                 if (filename)
00506                   cerr << " of " << filename;
00507                 cerr << ", output '" << name << "' from robot " << caps->getRobotName() << " cannot be mapped to host " << RobotName << endl;
00508               } else {
00509                 cmds[off].set((float)atof(words[i].c_str()));
00510               }
00511             }
00512           }
00513         } break;
00514         case SECTION_BUTTONS: {
00515           if(loadSensors==NULL)
00516             break;
00517           unsigned int size=words.size();
00518           if(size-1!=caps->getNumButtons()) {
00519             cerr << "*** ERROR line " << linenum;
00520             if (filename)
00521               cerr << " of " << filename;
00522             cerr << ", " << caps->getRobotName() << " expected " << caps->getNumButtons() << " values, got " << (size-1) << endl;
00523             return 0;
00524           }
00525           if(caps==&capabilities) {
00526             // we're using the "native" target... make things a bit quicker
00527             for(unsigned int i=1; i<size; ++i)
00528               loadSensors->buttons[i-1] = (float)atof(words[i].c_str());
00529           } else {
00530             // we're using another target, map to the host
00531             for(unsigned int i=1; i<size; ++i) {
00532               const char * name = caps->getButtonName(i-1);
00533               unsigned int off = capabilities.findButtonOffset(name);
00534               if(off==-1U) {
00535                 cerr << "*** Warning line " << linenum;
00536                 if (filename)
00537                   cerr << " of " << filename;
00538                 cerr << ", button '" << name << "' from robot " << caps->getRobotName() << " cannot be mapped to host " << RobotName << endl;
00539               } else {
00540                 loadSensors->buttons[off] = (float)atof(words[i].c_str());
00541               }
00542             }
00543           }
00544         } break;
00545         case SECTION_SENSORS: {
00546           if(loadSensors==NULL)
00547             break;
00548           unsigned int size=words.size();
00549           if(size-1!=caps->getNumSensors()) {
00550             cerr << "*** ERROR line " << linenum;
00551             if (filename)
00552               cerr << " of " << filename;
00553             cerr << ", " << caps->getRobotName() << " expected " << caps->getNumSensors() << " values, got " << (size-1) << endl;
00554             return 0;
00555           }
00556           if(caps==&capabilities) {
00557             // we're using the "native" target... make things a bit quicker
00558             for(unsigned int i=1; i<size; ++i)
00559               loadSensors->sensors[i-1] = (float)atof(words[i].c_str());
00560           } else {
00561             // we're using another target, map to the host
00562             for(unsigned int i=1; i<size; ++i) {
00563               const char * name = caps->getSensorName(i-1);
00564               unsigned int off = capabilities.findSensorOffset(name);
00565               if(off==-1U) {
00566                 cerr << "*** Warning line " << linenum;
00567                 if (filename)
00568                   cerr << " of " << filename;
00569                 cerr << ", sensor '" << name << "' from robot " << caps->getRobotName() << " cannot be mapped to host " << RobotName << endl;
00570               } else {
00571                 loadSensors->sensors[off] = (float)atof(words[i].c_str());
00572               }
00573             }
00574           }
00575         } break;
00576         case SECTION_PIDDUTIES: {
00577           if(loadSensors==NULL)
00578             break;
00579           unsigned int size=words.size();
00580           if(size-1!=caps->getNumPIDJoints()) {
00581             cerr << "*** ERROR line " << linenum;
00582             if (filename)
00583               cerr << " of " << filename;
00584             cerr << ", " << caps->getRobotName() << " expected " << caps->getNumPIDJoints() << " values, got " << (size-1) << endl;
00585             return 0;
00586           }
00587           if(caps==&capabilities) {
00588             for(unsigned int i=1; i<size; ++i)
00589               loadSensors->pidduties[i-1] = (float)atof(words[i].c_str());
00590           } else {
00591             // we're using another target, map to the host
00592             unsigned int pidoff = caps->getPIDJointOffset();
00593             for(unsigned int i=1; i<size; ++i) {
00594               const char * name = caps->getOutputName(pidoff+i-1);
00595               unsigned int off = capabilities.findOutputOffset(name);
00596               if(off==-1U) {
00597                 cerr << "*** Warning line " << linenum;
00598                 if (filename)
00599                   cerr << " of " << filename;
00600                 cerr << ", output '" << name << "' from robot " << caps->getRobotName() << " cannot be mapped to host " << RobotName << endl;
00601               } else if(off<PIDJointOffset || off>=PIDJointOffset+NumPIDJoints) {
00602                 cerr << "*** Warning line " << linenum;
00603                 if (filename)
00604                   cerr << " of " << filename;
00605                 cerr << ", output '" << name << "' from robot " << caps->getRobotName()
00606                      << " does not map to a PID joint on the local host " << RobotName << endl;
00607               } else {
00608                 loadSensors->pidduties[off-PIDJointOffset] = (float)atof(words[i].c_str());
00609               }
00610             }
00611           }
00612         } break;
00613       } // end of section name 'switch'
00614     } // end of section name found 'else'
00615   } // end of not-a-keyword 'else'
00616   return true;
00617 }
00618       
00619 //Why do i need a cast to const char**??? It doesn't work without, should be automatic... grrrr
00620 unsigned int PostureEngine::saveBuffer(char buf[], unsigned int len) const {
00621   unsigned int origlen=len;
00622   int written=snprintf(buf,len,"#POS\n");
00623   if(!checkInc(written,buf,len,"*** ERROR PostureEngine save failed on header\n")) return 0;
00624   if(saveFormatCondensed) {
00625 #ifndef PLATFORM_APERIOS
00626     written=snprintf(buf,len,"condensed %s\n",RobotName);
00627 #else
00628     written=snprintf(buf,len,"condensed %s\n",RobotName.c_str());
00629 #endif
00630     if(!checkInc(written,buf,len,"*** ERROR PostureEngine save condensed header failed\n")) return 0;
00631     if(saveSensors!=NULL) {
00632       written=snprintf(buf,len,"meta-info = %u %u\n",saveSensors->lastSensorUpdateTime,saveSensors->frameNumber);
00633       if(!checkInc(written,buf,len,"*** ERROR PostureEngine save pidduty failed\n")) return 0;
00634     }
00635     bool weightsAllEqual=true;
00636     float weightsVal=cmds[0].weight;
00637     for(unsigned int i=1; i<NumOutputs && weightsAllEqual; i++)
00638       weightsAllEqual=(cmds[i].weight==weightsVal);
00639     if(!weightsAllEqual || weightsVal!=0) { //if they're all 0, skip outputs and weights
00640       written=snprintf(buf,len,"outputs =");
00641       if(!checkInc(written,buf,len,"*** ERROR PostureEngine save outputs header failed\n")) return 0;
00642       for(unsigned int i=0; i<NumOutputs; i++) {
00643         written=snprintf(buf,len," %g",cmds[i].value);
00644         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save output failed\n")) return 0;
00645       }
00646       if(!weightsAllEqual || weightsVal!=1) { //if they're all 1, skip weights
00647         written=snprintf(buf,len,"\nweights =");
00648         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save weights header failed\n")) return 0;
00649         for(unsigned int i=0; i<NumOutputs; i++) {
00650           written=snprintf(buf,len," %g",cmds[i].weight);
00651           if(!checkInc(written,buf,len,"*** ERROR PostureEngine save weight failed\n")) return 0;
00652         }
00653       }
00654       written=snprintf(buf,len,"\n");
00655       if(!checkInc(written,buf,len,"*** ERROR PostureEngine save final newline failed\n")) return 0;
00656     }
00657     if(saveSensors!=NULL) {
00658       written=snprintf(buf,len,"buttons =");
00659       if(!checkInc(written,buf,len,"*** ERROR PostureEngine save buttons header failed\n")) return 0;
00660       for(unsigned int i=0; i<NumButtons; i++) {
00661         written=snprintf(buf,len," %g",saveSensors->buttons[i]);
00662         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save button failed\n")) return 0;
00663       }
00664       written=snprintf(buf,len,"\nsensors =");
00665       if(!checkInc(written,buf,len,"*** ERROR PostureEngine save sensors header failed\n")) return 0;
00666       for(unsigned int i=0; i<NumSensors; i++) {
00667         written=snprintf(buf,len," %g",saveSensors->sensors[i]);
00668         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save sensor failed\n")) return 0;
00669       }
00670       written=snprintf(buf,len,"\npidduties =");
00671       if(!checkInc(written,buf,len,"*** ERROR PostureEngine save pidduties header failed\n")) return 0;
00672       for(unsigned int i=0; i<NumPIDJoints; i++) {
00673         written=snprintf(buf,len," %g",saveSensors->pidduties[i]);
00674         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save pidduty failed\n")) return 0;
00675       }
00676       written=snprintf(buf,len,"\n");
00677       if(!checkInc(written,buf,len,"*** ERROR PostureEngine save final newline failed\n")) return 0;
00678     }   
00679   } else {
00680     if(saveSensors!=NULL) {
00681       written=snprintf(buf,len,"<meta-info>\n  timestamp\t%u\n  framenumber\t%u\n</meta-info>\n",saveSensors->lastSensorUpdateTime,saveSensors->frameNumber);
00682       if(!checkInc(written,buf,len,"*** ERROR PostureEngine sensor begin save failed\n")) return 0;
00683     }
00684     for(unsigned int i=0; i<NumOutputs; i++) {
00685       if(cmds[i].weight>0) {
00686         if(cmds[i].weight==1)
00687           written=snprintf(buf,len,"%s\t% .4f\n",outputNames[i],cmds[i].value);
00688         else
00689           written=snprintf(buf,len,"%s\t% .4f\t% .4f\n",outputNames[i],cmds[i].value,cmds[i].weight);
00690         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save failed\n")) return 0;
00691       }
00692     }
00693     if(saveSensors!=NULL) {
00694       written=snprintf(buf,len,"<buttons>\n");
00695       if(!checkInc(written,buf,len,"*** ERROR PostureEngine sensor begin save failed\n")) return 0;
00696       for(unsigned int i=0; i<NumButtons; i++) {
00697         written=snprintf(buf,len,"  %s\t% .4f\t\n",buttonNames[i],saveSensors->buttons[i]);
00698         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save button failed\n")) return 0;
00699       }
00700       written=snprintf(buf,len,"</buttons><sensors>\n");
00701       if(!checkInc(written,buf,len,"*** ERROR PostureEngine sensor end save failed\n")) return 0;
00702       for(unsigned int i=0; i<NumSensors; i++) {
00703         written=snprintf(buf,len,"  %s\t% .4f\t\n",sensorNames[i],saveSensors->sensors[i]);
00704         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save sensor failed\n")) return 0;
00705       }
00706       written=snprintf(buf,len,"</sensors><pidduties>\n");
00707       if(!checkInc(written,buf,len,"*** ERROR PostureEngine sensor end save failed\n")) return 0;
00708       for(unsigned int i=0; i<NumPIDJoints; i++) {
00709         written=snprintf(buf,len,"  %s\t% .4f\t\n",outputNames[i],saveSensors->pidduties[i]);
00710         if(!checkInc(written,buf,len,"*** ERROR PostureEngine save pidduties failed\n")) return 0;
00711       }
00712       written=snprintf(buf,len,"</pidduties>\n");
00713       if(!checkInc(written,buf,len,"*** ERROR PostureEngine sensor end save failed\n")) return 0;
00714     }
00715   }
00716   written=snprintf(buf,len,"#END\n");
00717   if(!checkInc(written,buf,len,"*** ERROR PostureEngine save failed on #END\n")) return 0;
00718   return origlen-len;
00719 }
00720         
00721 unsigned int PostureEngine::loadFile(const char filename[]) {
00722   return LoadSave::loadFile(config->motion.makePath(filename).c_str());
00723 }
00724 unsigned int PostureEngine::saveFile(const char filename[]) const {
00725   return LoadSave::saveFile(config->motion.makePath(filename).c_str());
00726 }
00727 
00728 bool
00729 PostureEngine::solveLinkPosition(const fmat::SubVector<3,const float>& Pobj, unsigned int link, const fmat::SubVector<3,const float>& Plink) {
00730   if(jointMaps[link]==NULL)
00731     return false;
00732   update();
00733   IKSolver& solver = jointMaps[link]->getIK();
00734   bool conv = solver.solve(Plink,*jointMaps[link],IKSolver::Point(Pobj));
00735   KinematicJoint * kj = jointMaps[link];
00736   while(kj!=NULL) {
00737     if(kj->outputOffset<NumOutputs)
00738       setOutputCmd(kj->outputOffset, kj->getQ());
00739     kj = kj->getParent();
00740   }
00741   return conv;
00742 }
00743 
00744 bool
00745 PostureEngine::solveLinkVector(const fmat::SubVector<3,const float>& Pobj, unsigned int link, const fmat::SubVector<3,const float>& Plink) {
00746   solveLinkPosition(Pobj,link,Plink);
00747   //This method is an approximation, not entirely precise or fast as it could be
00748   //Something to work on some more down the road! :)
00749   //(this method is shared with HeadPointerMC::lookAtPoint(x,y,z))
00750   fmat::Column<3> poE=baseToLink(link)*Pobj;
00751   float plE_len=Plink.sumSq();
00752   float obj_comp_link=fmat::dotProduct(Plink,poE)/plE_len;
00753   if(obj_comp_link<plE_len)
00754     obj_comp_link=obj_comp_link*.975f; //.975 is a bit of fudge - accounts for joints moving Plink when adjusting
00755   else
00756     obj_comp_link=obj_comp_link/.975f; //.975 is a bit of fudge - accounts for joints moving Plink when adjusting
00757   fmat::Column<3> obj_proj_link(Plink*obj_comp_link);
00758   return solveLinkPosition(Pobj,link,obj_proj_link);
00759 }
00760 
00761 bool
00762 PostureEngine::solveLinkOrientation(const fmat::Quaternion& oriTgt, unsigned int link, const fmat::Quaternion& oriOffset) {
00763   if(jointMaps[link]==NULL)
00764     return false;
00765   update();
00766   IKSolver& solver = jointMaps[link]->getIK();
00767   bool conv = solver.solve(oriOffset,*jointMaps[link],IKSolver::Rotation(oriTgt));
00768   KinematicJoint * kj = jointMaps[link];
00769   while(kj!=NULL) {
00770     if(kj->outputOffset<NumOutputs)
00771       setOutputCmd(kj->outputOffset, kj->getQ());
00772     kj = kj->getParent();
00773   }
00774   return conv;
00775 }
00776 
00777 bool
00778 PostureEngine::solveLink(const fmat::SubVector<3,const float>& posTgt, const fmat::Quaternion& oriTgt, unsigned int link, const fmat::SubVector<3,const float>& posOffset, const fmat::Quaternion& oriOffset) {
00779   if(jointMaps[link]==NULL)
00780     return false;
00781   update();
00782   IKSolver& solver = jointMaps[link]->getIK();
00783   bool conv = solver.solve(posOffset,oriOffset,*jointMaps[link],IKSolver::Point(posTgt),1,IKSolver::Rotation(oriTgt),1);
00784   KinematicJoint * kj = jointMaps[link];
00785   while(kj!=NULL) {
00786     if(kj->outputOffset<NumOutputs)
00787       setOutputCmd(kj->outputOffset, kj->getQ());
00788     kj = kj->getParent();
00789   }
00790   return conv;
00791 }
00792 
00793 
00794 void
00795 PostureEngine::update() const {
00796   for(unsigned int j=0; j<NumOutputs; j++) {
00797     if(jointMaps[j]!=NULL)
00798       jointMaps[j]->setQ(getOutputCmd(j).value);
00799   }
00800 }
00801 
00802 /*! @file
00803  * @brief Implements PostureEngine, a base class for managing the values and weights of all the outputs
00804  * @author ejt (Creator)
00805  */
00806 

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