00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <robot/ManipulatorJointTrajectory>
00026
00027 #include <sstream>
00028
00029 #include <base/Math>
00030 #include <base/Externalizer>
00031 #include <base/Serializer>
00032 #include <base/externalization_error>
00033
00034
00035 using robot::ManipulatorJointTrajectory;
00036
00037 using base::Vector;
00038 using base::vectorRange;
00039 using base::Range;
00040 using base::Time;
00041 using base::Serializer;
00042 using base::Externalizer;
00043 using base::externalization_error;
00044 using base::XS;
00045 using base::dom::DOMNode;
00046 using base::dom::DOMElement;
00047
00048
00049 ManipulatorJointTrajectory::ManipulatorJointTrajectory(Int numJoints, AngularUnits units)
00050 : angUnits(units)
00051 {
00052 const Int dof = numJoints;
00053 qs.resize(2);
00054 qs[0].reset( zeroVector(dof) );
00055 qs[1].reset( zeroVector(dof) );
00056
00057 times.resize(2);
00058 times[0] = 0;
00059 times[1] = 1;
00060
00061 computeSis(dof);
00062 }
00063
00064
00065 ManipulatorJointTrajectory::ManipulatorJointTrajectory(const ManipulatorJointTrajectory& t)
00066 : qs(t.qs), times(t.times), si(t.si), angUnits(t.angUnits)
00067 {
00068 }
00069
00070
00071 ManipulatorJointTrajectory::ManipulatorJointTrajectory(const Vector& sq, const Time& st,
00072 const Vector& eq, const Time& et,
00073 AngularUnits units)
00074 : angUnits(units)
00075 {
00076 Int dof = sq.size();
00077 Assert( dof > 0 );
00078
00079 qs.resize(2);
00080 qs[0].reset(sq);
00081 qs[1].reset(eq);
00082
00083 times.resize(2);
00084 times[0] = st;
00085 times[1] = et;
00086
00087 computeSis(dof);
00088 }
00089
00090
00091 ManipulatorJointTrajectory::ManipulatorJointTrajectory(const array<Vector>& qs,
00092 const array<Time>& times,
00093 bool deltas, AngularUnits units)
00094 : angUnits(units)
00095 {
00096 init(qs, times, deltas);
00097 }
00098
00099
00100 void ManipulatorJointTrajectory::convertComponentUnits(array<Int> components, AngularUnits units)
00101 {
00102 if (getAngularUnits() == units) return;
00103
00104 const Int dof = qs[0].size();
00105 for(Int i=0; i<qs.size(); i++) {
00106 for(Int ci=0; ci<components.size(); ci++) {
00107 Int c(components[ci]);
00108 if (c<dof) {
00109 qs[i][c] = (units==Radians)?Math::degToRad(qs[i][c]):Math::radToDeg(qs[i][c]);
00110 }
00111 else
00112 throw std::invalid_argument(Exception("component index out of range"));
00113 }
00114 }
00115 }
00116
00117
00118 void ManipulatorJointTrajectory::setNumJoints(Int numJoints, bool truncateInitial)
00119 {
00120 Int currsize = qs[0].size();
00121
00122 if (numJoints < currsize) {
00123 for(Int i=0; i<qs.size(); i++) {
00124 Vector nq( numJoints );
00125 if (!truncateInitial)
00126 nq = vectorRange(qs[i], Range(0, numJoints) );
00127 else
00128 nq = vectorRange(qs[i], Range(currsize-numJoints, currsize));
00129 qs[i].reset(nq);
00130 }
00131 }
00132 else if (numJoints > currsize) {
00133 const Int currentNum = qs[0].size();
00134 for(Int i=0; i<qs.size(); i++) {
00135 Vector nq( zeroVector(numJoints) );
00136 vectorRange(nq, Range(0, currentNum)) = qs[i];
00137 qs[i].reset(nq);
00138 }
00139 }
00140
00141 }
00142
00143
00144
00145 Vector ManipulatorJointTrajectory::q(const Time& t) const
00146 {
00147 Real s = gets(t);
00148 Int i = findIndex(s);
00149 if (Math::equals(s,si[i]))
00150 return qs[i];
00151
00152 Vector v( qs[i+1] - qs[i] );
00153 Real ts( si[i+1] - si[i] );
00154
00155 Real ds = s-si[i];
00156 Vector dv( (ds/ts)*v );
00157
00158 return qs[i] + dv;
00159 }
00160
00161
00162 Time ManipulatorJointTrajectory::time(Real s) const
00163 {
00164 Math::bound<Real>(s,0,1);
00165 return Time( times[0].seconds() + ( (times[times.size()-1] - times[0]).seconds() * s ) );
00166 }
00167
00168
00169 void ManipulatorJointTrajectory::shiftTime(const Time& dt)
00170 {
00171 for(Int i=0; i<times.size(); i++)
00172 times[i] += dt;
00173 }
00174
00175
00176 void ManipulatorJointTrajectory::scaleTime(Real s)
00177 {
00178 for(Int i=0; i<times.size(); i++)
00179 times[i] *= s;
00180 }
00181
00182
00183 Real ManipulatorJointTrajectory::gets(const Time& t) const
00184 {
00185 const Time& st(times[0]);
00186 const Time& et(times[times.size()-1]);
00187 Time bt(t);
00188 Math::bound<Time>(bt,st,et);
00189 return (bt-st).seconds() / (et-st).seconds();
00190 }
00191
00192 void ManipulatorJointTrajectory::serialize(Serializer& s)
00193 {
00194 s(qs,"qs");
00195 s(times,"times");
00196 s(si,"si");
00197 }
00198
00199
00200 bool ManipulatorJointTrajectory::formatSupported(String format, Real version, ExternalizationType type) const
00201 {
00202 return (format == "txt") && (version==1.0)
00203 || (format == "xml") && (version==1.0);
00204 }
00205
00206
00207 void ManipulatorJointTrajectory::externalize(Externalizer& e, String format, Real version)
00208 {
00209 if (format=="") format = String("xml");
00210
00211 if (!formatSupported(format,version,e.ioType()))
00212 throw std::invalid_argument(Exception(String("format ")+format+" "+base::realToString(version)+" unsupported"));
00213
00214 if (format == "txt") {
00215
00216 if (e.isInput()) {
00217 array<Vector> qs;
00218 array<Time> times;
00219 bool first = true;
00220 bool deltas = false;
00221
00222 while (e.moreInput()) {
00223
00224 String line(e.readLine());
00225 if (line.empty()) break;
00226 while (line[0] == '#') line = e.readLine();
00227
00228 if (first) {
00229 if (!( (line.substr(0,8) == "absolute") || (line.substr(0,8) == "relative")))
00230 throw std::invalid_argument(Exception(String("joint waypoint text file must indicate 'absolute' or 'relative'")));
00231
00232 deltas = (line.substr(0,8) == String("relative"));
00233 first = false;
00234 }
00235 else {
00236
00237 Int spaces=0;
00238 for(Int i=0; i<line.size(); i++)
00239 if (line[i]==' ') {
00240 spaces++;
00241 while ( (i<line.size()-1) && (line[i]==' ')) i++;
00242 }
00243 if (line[0]==' ') spaces--;
00244
00245 std::istringstream iss(line);
00246 iss.setf(std::ios_base::skipws | std::ios_base::dec);
00247
00248 const Int dof = spaces + 1 - 1;
00249
00250 Vector q(dof);
00251
00252 for(Int i=0; i<dof; i++)
00253 iss >> q[i];
00254
00255 Real t;
00256 iss >> t;
00257
00258 qs.push_back(q);
00259
00260 times.push_back(Time(t));
00261 }
00262 }
00263
00264 if (first)
00265 throw std::invalid_argument(Exception(String("joint waypoint text file contains no data.")));
00266
00267 if (qs.size() < 2)
00268 throw std::invalid_argument(Exception(String("joint waypoint text file must contain at least 2 'waypoint' vectors")));
00269
00270 init(qs,times,deltas);
00271
00272 }
00273 else {
00274 std::ostringstream out;
00275
00276
00277 out << "# Joint waypoint trajectory [joint positions & times (at-end)]" << std::endl;
00278 out << "# the following line should be 'absolute' for absolute qi's & t values or 'relative' if the vectors represent inter-waypoint deltas dqi's & dt" << std::endl;
00279 out << "absolute" << std::endl;
00280 out << "# q0 q1 ... qn t" << std::endl;
00281 std::ostream::fmtflags savedFlags = out.setf(std::ios_base::dec | std::ios_base::right);
00282 Int savedPrec = out.precision(10);
00283 Int savedWidth = out.width(13);
00284 const Int dof=qs[0].size();
00285
00286
00287 #define setflags \
00288 out.setf(std::ios_base::dec | std::ios_base::right); \
00289 out.precision(10); \
00290 out.width(13);
00291
00292 setflags;
00293 for(Int i=0; i<qs.size(); i++) {
00294 Vector q(qs[i]);
00295 Time t(times[i]);
00296
00297 for(Int e=0; e<dof; e++)
00298 out << q[e] << " "; setflags;
00299
00300 out << t.seconds(); setflags;
00301 out << std::endl;
00302
00303 }
00304
00305 out.setf(savedFlags);
00306 out.precision(savedPrec);
00307 out.width(savedWidth);
00308
00309 e.writeString(out.str());
00310 }
00311
00312 } else if (format == "xml") {
00313
00314 if (e.isOutput()) {
00315
00316 DOMElement* trajElem = e.createElement("jointtrajectory");
00317
00318 e.setElementAttribute(trajElem,"pointtype","absolute");
00319 e.setElementAttribute(trajElem,"angunit", (angUnits==Radians)?String("rad"):String("deg"));
00320
00321 e.appendComment(trajElem, "space separated joint parameter values and time (secs) at end");
00322
00323 const Int dof=qs[0].size();
00324
00325 for(Int i=0; i<qs.size(); i++) {
00326 Vector v(dof + 1);
00327 vectorRange(v, Range(0,dof)) = qs[i];
00328 v[dof] = times[i].seconds();
00329
00330 e.appendText( trajElem, e.toString(v) );
00331 e.appendBreak( trajElem );
00332 }
00333
00334 e.appendElement(trajElem);
00335
00336 }
00337 else {
00338
00339 DOMNode* context = e.context();
00340
00341 DOMElement* trajElem = e.getFirstElement(context, "jointtrajectory");
00342
00343 bool absolute = ( e.getDefaultedElementAttribute(trajElem, "pointtype", "absolute") == "absolute" );
00344 angUnits = ( e.getDefaultedElementAttribute(trajElem, "angunit", "rad") == "deg" )?Degrees:Radians;
00345
00346 array<Vector> qs;
00347 array<Time> times;
00348
00349 String trajText = e.getContainedText(trajElem,true);
00350 array<String> trajLines = e.splitIntoLines(trajText);
00351
00352 if (trajLines.size() < 2)
00353 throw externalization_error(Exception("trajectory must contain at least two points"));
00354
00355 Int dof;
00356 for(Int i=0; i<trajLines.size(); i++) {
00357
00358 array<String> elts = e.splitAtDelimiter(trajLines[i], ' ');
00359 if (elts.size() < 2)
00360 throw externalization_error(Exception("trajectory point with no joints encountered"));
00361 else {
00362 if (i==0)
00363 dof=elts.size()-1;
00364 else
00365 if (elts.size()-1 != dof)
00366 throw externalization_error(Exception("trajectory point of incorrect dimension encountered"));
00367 }
00368
00369 Vector v( e.stringsToReals(elts) );
00370
00371 qs.push_back( Vector( vectorRange(v, Range(0, v.size()-1)) ) );
00372 times.push_back( Time(v[v.size()-1]) );
00373 }
00374
00375 e.removeElement(trajElem);
00376
00377 init(qs,times,!absolute);
00378
00379 }
00380
00381
00382 }
00383
00384 }
00385
00386
00387
00388 void ManipulatorJointTrajectory::init(const array<base::Vector>& qs, const array<base::Time>& times, bool deltas)
00389 {
00390 Assert(qs.size() > 0);
00391 Assert(qs.size() == times.size());
00392 Int dof=qs[0].size();
00393
00394 if (!deltas) {
00395 this->qs=qs;
00396 this->times = times;
00397 #ifdef DEBUG
00398
00399 for(Int i=0; i<qs.size(); i++) {
00400 Assert(qs[i].size() == dof);
00401 }
00402 #endif
00403 }
00404 else {
00405
00406 array<Vector> aqs(qs.size()+1);
00407 aqs[0].reset( zeroVector(dof) );
00408 for(Int i=0; i<qs.size(); i++) {
00409 Assert(qs[i].size() == dof);
00410 aqs[i+1].reset( aqs[i]+qs[i] );
00411 }
00412
00413 array<Time> atimes(times.size()+1);
00414 atimes[0] = 0;
00415 for(Int i=0; i<times.size(); i++)
00416 atimes[i+1] = atimes[i]+times[i];
00417
00418 this->qs = aqs;
00419 this->times = atimes;
00420 }
00421
00422 computeSis(dof);
00423 }
00424
00425
00426 void ManipulatorJointTrajectory::computeSis(Int dof)
00427 {
00428
00429 if (qs.size() == 0) { qs.at(0) = qs.at(1) = Vector(dof); }
00430 if (times.size() == 0) { times.at(0) = 0; times.at(1) = 1; }
00431
00432
00433 Real T = (times[times.size()-1] - times[0]).seconds();
00434 Int i = 1;
00435 si.resize(qs.size());
00436 si[0] = 0;
00437 while (i<qs.size()) {
00438 if (times[i-1] > times[i])
00439 throw std::invalid_argument(Exception("times must be monotonically increasing"));
00440 si[i] = (times[i] - times[0]).seconds() / T;
00441 i++;
00442 }
00443 }
00444
00445
00446 Int ManipulatorJointTrajectory::findIndex(Real s) const
00447 {
00448 Int i;
00449 for(i=0; i<si.size(); i++)
00450 if (si[i] > s) break;
00451 return i-1;
00452 }