| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| |
|
| | #include <memory>
|
| |
|
| | #include "kdl_cp/path_line.hpp"
|
| | #include "kdl_cp/path_roundedcomposite.hpp"
|
| | #include "kdl_cp/rotational_interpolation_sa.hpp"
|
| | #include "kdl_cp/trajectory_composite.hpp"
|
| | #include "kdl_cp/trajectory_segment.hpp"
|
| | #include "kdl_cp/utilities/error.h"
|
| | #include "kdl_cp/velocityprofile_trap.hpp"
|
| |
|
| | #include <Base/Exception.h>
|
| | #include <Base/Reader.h>
|
| | #include <Base/Writer.h>
|
| |
|
| | #include "RobotAlgos.h"
|
| | #include "Trajectory.h"
|
| |
|
| |
|
| | using namespace Robot;
|
| | using namespace Base;
|
| |
|
| |
|
| | TYPESYSTEM_SOURCE(Robot::Trajectory, Base::Persistence)
|
| |
|
| | Trajectory::Trajectory() = default;
|
| |
|
| | Trajectory::Trajectory(const Trajectory& Trac)
|
| | : vpcWaypoints(Trac.vpcWaypoints.size())
|
| | , pcTrajectory(nullptr)
|
| | {
|
| | operator=(Trac);
|
| | }
|
| |
|
| | Trajectory::~Trajectory()
|
| | {
|
| | for (auto it : vpcWaypoints) {
|
| | delete it;
|
| | }
|
| | delete pcTrajectory;
|
| | }
|
| |
|
| | Trajectory& Trajectory::operator=(const Trajectory& Trac)
|
| | {
|
| | if (this == &Trac) {
|
| | return *this;
|
| | }
|
| |
|
| | for (auto it : vpcWaypoints) {
|
| | delete it;
|
| | }
|
| | vpcWaypoints.clear();
|
| | vpcWaypoints.resize(Trac.vpcWaypoints.size());
|
| |
|
| | int i = 0;
|
| | for (std::vector<Waypoint*>::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)));
|
| | }
|
| | return {};
|
| | }
|
| |
|
| | 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()
|
| | {
|
| | if (vpcWaypoints.empty()) {
|
| | return;
|
| | }
|
| |
|
| |
|
| | if (pcTrajectory) {
|
| | delete (pcTrajectory);
|
| | }
|
| | pcTrajectory = new KDL::Trajectory_Composite();
|
| |
|
| |
|
| | std::unique_ptr<KDL::Trajectory_Segment> pcTrak;
|
| | std::unique_ptr<KDL::VelocityProfile> pcVelPrf;
|
| | std::unique_ptr<KDL::Path_RoundedComposite> pcRoundComp;
|
| | KDL::Frame Last;
|
| |
|
| | try {
|
| |
|
| | bool first = true;
|
| |
|
| | for (std::vector<Waypoint*>::const_iterator it = vpcWaypoints.begin();
|
| | it != vpcWaypoints.end();
|
| | ++it) {
|
| | if (first) {
|
| | Last = toFrame((*it)->EndPos);
|
| | first = false;
|
| | }
|
| | else {
|
| |
|
| | switch ((*it)->Type) {
|
| | case Waypoint::LINE:
|
| | case Waypoint::PTP: {
|
| | KDL::Frame Next = toFrame((*it)->EndPos);
|
| |
|
| | bool Cont = (*it)->Cont && !(it == --vpcWaypoints.end());
|
| |
|
| | if (Cont && !pcRoundComp) {
|
| | pcRoundComp = std::make_unique<KDL::Path_RoundedComposite>(
|
| | 3,
|
| | 3,
|
| | new KDL::RotationalInterpolation_SingleAxis()
|
| | );
|
| |
|
| | pcVelPrf = std::make_unique<KDL::VelocityProfile_Trap>(
|
| | (*it)->Velocity,
|
| | (*it)->Acceleration
|
| | );
|
| | pcRoundComp->Add(Last);
|
| | pcRoundComp->Add(Next);
|
| |
|
| |
|
| | }
|
| | else if (Cont && pcRoundComp) {
|
| | pcRoundComp->Add(Next);
|
| |
|
| | }
|
| | else if (!Cont && pcRoundComp) {
|
| |
|
| | pcRoundComp->Add(Next);
|
| | pcRoundComp->Finish();
|
| | pcVelPrf->SetProfile(0, pcRoundComp->PathLength());
|
| | pcTrak = std::make_unique<KDL::Trajectory_Segment>(
|
| | pcRoundComp.release(),
|
| | pcVelPrf.release()
|
| | );
|
| |
|
| |
|
| | }
|
| | else if (!Cont && !pcRoundComp) {
|
| | KDL::Path* pcPath;
|
| | pcPath = new KDL::Path_Line(
|
| | Last,
|
| | Next,
|
| | new KDL::RotationalInterpolation_SingleAxis(),
|
| | 1.0,
|
| | true
|
| | );
|
| |
|
| | pcVelPrf = std::make_unique<KDL::VelocityProfile_Trap>(
|
| | (*it)->Velocity,
|
| | (*it)->Acceleration
|
| | );
|
| | pcVelPrf->SetProfile(0, pcPath->PathLength());
|
| | pcTrak = std::make_unique<KDL::Trajectory_Segment>(
|
| | pcPath,
|
| | pcVelPrf.release()
|
| | );
|
| | }
|
| | Last = Next;
|
| | break;
|
| | }
|
| | case Waypoint::WAIT:
|
| | break;
|
| | default:
|
| | break;
|
| | }
|
| |
|
| |
|
| | 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 CleanName = Name;
|
| | if (!CleanName.empty() && CleanName[0] >= 48 && CleanName[0] <= 57) {
|
| | CleanName[0] = '_';
|
| | }
|
| |
|
| | for (char& it : CleanName) {
|
| | if (!((it >= 48 && it <= 57) ||
|
| | (it >= 65 && it <= 90) ||
|
| | (it >= 97 && it <= 122))) {
|
| | it = '_';
|
| | }
|
| | }
|
| |
|
| |
|
| | std::vector<Robot::Waypoint*>::const_iterator it;
|
| | for (it = vpcWaypoints.begin(); it != vpcWaypoints.end(); ++it) {
|
| | if ((*it)->Name == CleanName) {
|
| | break;
|
| | }
|
| | }
|
| |
|
| | if (it == vpcWaypoints.end()) {
|
| |
|
| | return CleanName;
|
| | }
|
| | else {
|
| |
|
| | int nSuff = 0;
|
| | for (it = vpcWaypoints.begin(); it != vpcWaypoints.end(); ++it) {
|
| | const std::string& ObjName = (*it)->Name;
|
| | if (ObjName.substr(0, CleanName.length()) == CleanName) {
|
| | std::string clSuffix(ObjName.substr(CleanName.length()));
|
| | if (!clSuffix.empty()) {
|
| | std::string::size_type nPos = clSuffix.find_first_not_of("0123456789");
|
| | if (nPos == std::string::npos) {
|
| | nSuff = std::max<int>(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() const
|
| | {
|
| | return 0;
|
| | }
|
| |
|
| | void Trajectory::Save(Writer& writer) const
|
| | {
|
| | writer.Stream() << writer.ind() << "<Trajectory count=\"" << getSize() << "\">" << std::endl;
|
| | writer.incInd();
|
| | for (unsigned int i = 0; i < getSize(); i++) {
|
| | vpcWaypoints[i]->Save(writer);
|
| | }
|
| | writer.decInd();
|
| | writer.Stream() << writer.ind() << "</Trajectory>" << std::endl;
|
| | }
|
| |
|
| | void Trajectory::Restore(XMLReader& reader)
|
| | {
|
| | vpcWaypoints.clear();
|
| |
|
| | reader.readElement("Trajectory");
|
| |
|
| | int count = reader.getAttribute<long>("count");
|
| | vpcWaypoints.resize(count);
|
| |
|
| | for (int i = 0; i < count; i++) {
|
| | Waypoint* tmp = new Waypoint();
|
| | tmp->Restore(reader);
|
| | vpcWaypoints[i] = tmp;
|
| | }
|
| | generateTrajectory();
|
| | }
|
| |
|