Program Listing for File trajectory.h
↰ Return to documentation for file (/tmp/ws/src/robot_controllers/robot_controllers/include/robot_controllers/trajectory.h
)
/*********************************************************************
* Software License Agreement (BSD License)
*
* Copyright (c) 2014-2015, Fetch Robotics Inc.
* Copyright (c) 2013, Unbounded Robotics Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Unbounded Robotics nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/
// Author: Michael Ferguson
#ifndef ROBOT_CONTROLLERS__TRAJECTORY_H_
#define ROBOT_CONTROLLERS__TRAJECTORY_H_
#include <iomanip>
#include <string>
#include <vector>
#include "rclcpp/rclcpp.hpp"
#include "angles/angles.h"
#include "trajectory_msgs/msg/joint_trajectory.hpp"
#include "robot_controllers_interface/utils.h"
namespace robot_controllers
{
struct TrajectoryPoint
{
std::vector<double> q;
std::vector<double> qd;
std::vector<double> qdd;
double time;
};
struct Trajectory
{
std::vector<TrajectoryPoint> points;
size_t size() const
{
return points.size();
}
};
inline bool trajectoryFromMsg(const trajectory_msgs::msg::JointTrajectory& message,
const std::vector<std::string> joints,
const rclcpp::Time now,
Trajectory* trajectory)
{
// Find mapping of joint names into message joint names
std::vector<int> mapping(joints.size(), -1);
for (size_t j = 0; j < joints.size(); ++j)
{
for (size_t i = 0; i < message.joint_names.size(); ++i)
{
if (joints[j] == message.joint_names[i])
{
mapping[j] = i;
break;
}
}
if (mapping[j] == -1)
{
return false;
}
}
// Make sure trajectory is empty
trajectory->points.clear();
double start_time = robot_controllers_interface::msg_to_sec(message.header.stamp);
if (start_time == 0.0)
start_time = robot_controllers_interface::to_sec(now);
// Fill in Trajectory
for (size_t p = 0; p < message.points.size(); ++p)
{
TrajectoryPoint point;
for (size_t j = 0; j < joints.size(); ++j)
{
point.q.push_back(message.points[p].positions[mapping[j]]);
if (message.points[p].velocities.size() == message.points[p].positions.size())
point.qd.push_back(message.points[p].velocities[mapping[j]]);
if (message.points[p].accelerations.size() == message.points[p].positions.size())
point.qdd.push_back(message.points[p].accelerations[mapping[j]]);
}
point.time = start_time +
robot_controllers_interface::msg_to_sec(message.points[p].time_from_start);
trajectory->points.push_back(point);
}
// Parsed this
return true;
}
inline bool spliceTrajectories(const Trajectory& t1,
const Trajectory& t2,
const double time,
Trajectory * t)
{
// Need at least one point in t1 for the following code to work
if (t1.size() == 0)
{
return false;
}
// Need at least one point in t2 for the following code to work
if (t2.size() == 0)
{
*t = t1;
return true;
}
// Check sizes
size_t num_joints = t1.points[0].q.size();
bool has_velocities = (t1.points[0].qd.size() == num_joints) &&
(t2.points[0].qd.size() == num_joints);
bool has_accelerations = (t1.points[0].qdd.size() == num_joints) &&
(t2.points[0].qdd.size() == num_joints);
// Just to be sure
t->points.clear();
// When does t2 start?
double start_t2 = t2.points[0].time;
// Find points in t1 after time, but before start_t2
for (size_t p = 0; p < t1.size(); ++p)
{
if (t1.points[p].time >= time && t1.points[p].time < start_t2)
{
if (t1.points[p].time > time && t->size() == 0)
{
/* This is first point in trajectory, and is after our
start time, see if we can add one point in front of it */
if (p > 0)
t->points.push_back(t1.points[p-1]);
}
t->points.push_back(t1.points[p]);
}
}
// Add points from t2
for (size_t p = 0; p < t2.size(); ++p)
{
if (t2.points[p].time >= time)
{
if (t2.points[p].time > time && t->size() == 0)
{
/* This is first point in trajectory, and is after our
start time, see if we can add one point in front of it */
if (p > 0)
t->points.push_back(t2.points[p-1]);
else if (t1.size() > 0)
t->points.push_back(t1.points[t1.size()-1]);
}
t->points.push_back(t2.points[p]);
}
}
if (!has_accelerations)
{
// Remove any accelerations in output trajectory
for (size_t i = 0; i < t->points.size(); i++)
{
t->points[i].qdd.clear();
}
}
if (!has_velocities)
{
// Remove any velocities in output trajectory
for (size_t i = 0; i < t->points.size(); i++)
{
t->points[i].qd.clear();
}
}
return true;
}
inline void rosPrintTrajectory(rclcpp::Node::SharedPtr node, Trajectory& t)
{
RCLCPP_INFO_STREAM(node->get_logger(), "Trajectory with " << t.size() << " points:");
for (size_t p = 0; p < t.size(); ++p)
{
RCLCPP_INFO_STREAM(node->get_logger(), " Point " << p <<
" at " << std::setprecision (15) << t.points[p].time);
for (size_t j = 0; j < t.points[p].q.size(); ++j)
{
if (t.points[p].qdd.size() == t.points[p].q.size())
{
RCLCPP_INFO_STREAM(node->get_logger(), " " << std::setprecision (5) <<
t.points[p].q[j] << ", " << std::setprecision (5) <<
t.points[p].qd[j] << ", " << std::setprecision (5) <<
t.points[p].qdd[j]);
}
else if(t.points[p].q.size() == t.points[p].q.size())
{
RCLCPP_INFO_STREAM(node->get_logger(), " " << std::setprecision (5) <<
t.points[p].q[j] << ", " << std::setprecision (5) <<
t.points[p].qd[j]);
}
else
{
RCLCPP_INFO_STREAM(node->get_logger(), " " << std::setprecision (5) <<
t.points[p].q[j]);
}
}
}
}
inline bool windupTrajectory(std::vector<bool> continuous,
Trajectory& trajectory)
{
for (size_t p = 0; p < trajectory.size(); p++)
{
if (continuous.size() != trajectory.points[p].q.size())
{
// Size does not match
return false;
}
for (size_t j = 0; j < continuous.size(); j++)
{
if (continuous[j])
{
if (p > 0)
{
// Unwind by taking shortest path from previous point
double shortest = angles::shortest_angular_distance(trajectory.points[p-1].q[j],
trajectory.points[p].q[j]);
trajectory.points[p].q[j] = trajectory.points[p-1].q[j] + shortest;
}
else
{
// Start between -PI and PI
trajectory.points[p].q[j] = angles::normalize_angle(trajectory.points[p].q[j]);
}
}
}
}
return true;
}
inline bool unwindTrajectoryPoint(std::vector<bool> continuous,
TrajectoryPoint& p)
{
if (continuous.size() != p.q.size())
{
return false;
}
for (size_t j = 0; j < continuous.size(); j++)
{
if (continuous[j])
{
p.q[j] = angles::normalize_angle(p.q[j]);
}
}
return true;
}
class TrajectorySampler
{
public:
TrajectorySampler() {}
virtual ~TrajectorySampler() {}
virtual TrajectoryPoint sample(double time) = 0;
virtual double end_time() = 0;
virtual Trajectory getTrajectory() = 0;
private:
// You no copy...
TrajectorySampler(const TrajectorySampler&);
TrajectorySampler& operator=(const TrajectorySampler&);
};
} // namespace robot_controllers
#endif // ROBOT_CONTROLLERS__TRAJECTORY_H_