/*************************************************************************** * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include #endif #include #include #include #include "kdl_cp/chain.hpp" #include "kdl_cp/path_line.hpp" #include "kdl_cp/path_roundedcomposite.hpp" #include "kdl_cp/trajectory_composite.hpp" #include "kdl_cp/rotational_interpolation_sa.hpp" #include "kdl_cp/velocityprofile_trap.hpp" #include "kdl_cp/trajectory_segment.hpp" #include "kdl_cp/path_roundedcomposite.hpp" #include "kdl_cp/utilities/error.h" #include "Trajectory.h" #include "RobotAlgos.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846 /* pi */ #endif #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 /* pi/2 */ #endif using namespace Robot; using namespace Base; //using namespace KDL; TYPESYSTEM_SOURCE(Robot::Trajectory , Base::Persistence); Trajectory::Trajectory() :pcTrajectory(0) { } Trajectory::Trajectory(const Trajectory& Trac) :vpcWaypoints(Trac.vpcWaypoints.size()),pcTrajectory(0) { operator=(Trac); } Trajectory::~Trajectory() { for(std::vector::iterator it = vpcWaypoints.begin();it!=vpcWaypoints.end();++it) delete ( *it ); delete pcTrajectory; } Trajectory &Trajectory::operator=(const Trajectory& Trac) { for(std::vector::iterator it = vpcWaypoints.begin();it!=vpcWaypoints.end();++it) delete ( *it ); vpcWaypoints.clear(); vpcWaypoints.resize(Trac.vpcWaypoints.size()); int i=0; for (std::vector::const_iterator it=Trac.vpcWaypoints.begin();it!=Trac.vpcWaypoints.end();++it,i++) vpcWaypoints[i] = new Waypoint(**it); generateTrajectory(); return *this; } double Trajectory::getLength(int n) const { if(pcTrajectory) if(n<0) return pcTrajectory->GetPath()->PathLength(); else return pcTrajectory->Get(n)->GetPath()->PathLength(); else return 0; } double Trajectory::getDuration(int n) const { if(pcTrajectory) if(n<0) return pcTrajectory->Duration(); else return pcTrajectory->Get(n)->Duration(); else return 0; } Placement Trajectory::getPosition(double time)const { if(pcTrajectory) return Placement(toPlacement(pcTrajectory->Pos(time))); else return Placement(); } double Trajectory::getVelocity(double time)const { if(pcTrajectory){ KDL::Vector vec = pcTrajectory->Vel(time).vel; Base::Vector3d vec2(vec[0],vec[1],vec[2]); return vec2.Length(); }else return 0; } void Trajectory::deleteLast(unsigned int n) { for(unsigned int i=0;i<=n;i++){ delete(*vpcWaypoints.rbegin()); vpcWaypoints.pop_back(); } } void Trajectory::generateTrajectory(void) { if (vpcWaypoints.size()==0) return; // delete the old and create a new one if (pcTrajectory) delete (pcTrajectory); pcTrajectory = new KDL::Trajectory_Composite(); // pointer to the pieces while iterating std::unique_ptr pcTrak; std::unique_ptr pcVelPrf; std::unique_ptr pcRoundComp; KDL::Frame Last; try { // handle the first waypoint special bool first=true; for (std::vector::const_iterator it = vpcWaypoints.begin();it!=vpcWaypoints.end();++it) { if (first) { Last = toFrame((*it)->EndPos); first = false; } else { // destinct the type of movement switch((*it)->Type){ case Waypoint::LINE: case Waypoint::PTP:{ KDL::Frame Next = toFrame((*it)->EndPos); // continues the movement until no continus waypoint or the end bool Cont = (*it)->Cont && !(it==--vpcWaypoints.end()); // start of a continue block if (Cont && !pcRoundComp) { pcRoundComp.reset(new KDL::Path_RoundedComposite(3, 3, new KDL::RotationalInterpolation_SingleAxis())); // the velocity of the first waypoint is used pcVelPrf.reset(new KDL::VelocityProfile_Trap((*it)->Velocity,(*it)->Accelaration)); pcRoundComp->Add(Last); pcRoundComp->Add(Next); // continue a continues block } else if (Cont && pcRoundComp) { pcRoundComp->Add(Next); // end a continuous block } else if (Cont==false && pcRoundComp) { // add the last one pcRoundComp->Add(Next); pcRoundComp->Finish(); pcVelPrf->SetProfile(0,pcRoundComp->PathLength()); pcTrak.reset(new KDL::Trajectory_Segment(pcRoundComp.release(),pcVelPrf.release())); // normal block } else if (Cont==false && !pcRoundComp){ KDL::Path* pcPath; pcPath = new KDL::Path_Line(Last, Next, new KDL::RotationalInterpolation_SingleAxis(), 1.0, true ); pcVelPrf.reset(new KDL::VelocityProfile_Trap((*it)->Velocity,(*it)->Accelaration)); pcVelPrf->SetProfile(0,pcPath->PathLength()); pcTrak.reset(new KDL::Trajectory_Segment(pcPath,pcVelPrf.release())); } Last = Next; break;} case Waypoint::WAIT: break; default: break; } // add the segment if no continuous block is running if (!pcRoundComp && pcTrak) pcTrajectory->Add(pcTrak.release()); } } } catch (KDL::Error &e) { throw Base::RuntimeError(e.Description()); } } std::string Trajectory::getUniqueWaypointName(const char *Name) const { if (!Name || *Name == '\0') return std::string(); // check for first character whether it's a digit std::string CleanName = Name; if (!CleanName.empty() && CleanName[0] >= 48 && CleanName[0] <= 57) CleanName[0] = '_'; // strip illegal chars for (std::string::iterator it = CleanName.begin(); it != CleanName.end(); ++it) { if (!((*it>=48 && *it<=57) || // number (*it>=65 && *it<=90) || // uppercase letter (*it>=97 && *it<=122))) // lowercase letter *it = '_'; // it's neither number nor letter } // name in use? std::vector::const_iterator it; for(it = vpcWaypoints.begin();it!=vpcWaypoints.end();++it) if((*it)->Name == CleanName) break; if (it == vpcWaypoints.end()) { // if not, name is OK return CleanName; } else { // find highest suffix int nSuff = 0; for(it = vpcWaypoints.begin();it!=vpcWaypoints.end();++it) { const std::string &ObjName = (*it)->Name; if (ObjName.substr(0, CleanName.length()) == CleanName) { // same prefix std::string clSuffix(ObjName.substr(CleanName.length())); if (clSuffix.size() > 0) { std::string::size_type nPos = clSuffix.find_first_not_of("0123456789"); if (nPos==std::string::npos) nSuff = std::max(nSuff, std::atol(clSuffix.c_str())); } } } std::stringstream str; str << CleanName << (nSuff + 1); return str.str(); } } void Trajectory::addWaypoint(const Waypoint &WPnt) { std::string UniqueName = getUniqueWaypointName(WPnt.Name.c_str()); Waypoint *tmp = new Waypoint(WPnt); tmp->Name = UniqueName; vpcWaypoints.push_back(tmp); } unsigned int Trajectory::getMemSize (void) const { return 0; } void Trajectory::Save (Writer &writer) const { writer.Stream() << writer.ind() << "" << std::endl; writer.incInd(); for(unsigned int i = 0;iSave(writer); writer.decInd(); writer.Stream() << writer.ind() << "" << std::endl ; } void Trajectory::Restore(XMLReader &reader) { vpcWaypoints.clear(); // read my element reader.readElement("Trajectory"); // get the value of my Attribute int count = reader.getAttributeAsInteger("count"); vpcWaypoints.resize(count); for (int i = 0; i < count; i++) { Waypoint *tmp = new Waypoint(); tmp->Restore(reader); vpcWaypoints[i] = tmp; } generateTrajectory(); }