Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
42f87ed
A new funciton, calculateDerivativesFromVelocity()
AndyZe Apr 22, 2020
911102f
Fix sign of delta_v to backwardLimitComp()
AndyZe Apr 22, 2020
f50224d
Fix the streaming test/example
AndyZe Apr 27, 2020
0cfe557
Fix the skipping of some elements in downSample()
AndyZe Apr 22, 2020
c974284
Add a new single-joint oscillation test
AndyZe May 4, 2020
1e7c9f0
It works! Probably could be implemented more efficiently
AndyZe May 4, 2020
a6e8b58
Delete commented block of code from previous implementation
AndyZe May 5, 2020
93a7566
Set up if-condition to skip splines, if necessary
AndyZe May 6, 2020
bd03348
Fix the crash in OscillatingUR5Test
AndyZe May 6, 2020
b9ee3dd
All tests pass except DurationExtension
AndyZe May 6, 2020
6ba0ce1
Always use minimum possible duration for each joint
AndyZe Jun 29, 2020
d2d06d8
Add the if/else fix in backwardLimitComp (PR 57)
AndyZe Jun 29, 2020
c60e557
Add an example that should be able to execute faster
AndyZe Jun 30, 2020
0ec5fa3
It works!
AndyZe Jun 30, 2020
0ea5a96
Restore original kinematic limits. DownSample actually worked fine
AndyZe Jun 30, 2020
2c916dd
position_tolerance can be a bit bigger
AndyZe Jun 30, 2020
dd0d065
Remove debug statements, add hints if failure on first waypoint
AndyZe Jun 30, 2020
d709306
Revert changes to three_dof_examples.cpp
AndyZe Jun 30, 2020
68d623c
Small fixup to streaming_example.cpp for readability
AndyZe Jun 30, 2020
b63e02c
Reset desired_duration_ in reset() function, too.
AndyZe Jul 5, 2020
c8d4928
Delete extra loop in clipVector()
AndyZe Jul 5, 2020
a7c0c57
Change three_dof_examples to something that needs debugging
AndyZe Jul 5, 2020
440ee3f
Fix spline interpolation
AndyZe Jul 6, 2020
ca03c4e
Convert simple_example to a good failure case
AndyZe Jul 10, 2020
400656c
Derivative calculations in the middle of LimitComp often caused limit…
AndyZe Jul 10, 2020
921f627
Better estimates for desired durations
AndyZe Jul 10, 2020
15f1dc2
Clang format
AndyZe Jul 13, 2020
afa724e
Increase position_tolerance to help pass the first waypoint
AndyZe Aug 22, 2020
f44e3bc
Add checks on Timestep to every relevant unit test
AndyZe Aug 22, 2020
4939981
Add arg for whether upsampling occurred
AndyZe Aug 23, 2020
f880a2f
Slightly tweak test conditions for tests that seem to be working well
AndyZe Aug 23, 2020
e967c3b
Fix the allocation of waypoints.elapsed_times, only 2 tests fail now
AndyZe Aug 23, 2020
26a6cc9
Remove a few commented lines
AndyZe Aug 23, 2020
e01a912
Fix a typo in LimitCompensation test conditions
AndyZe Aug 23, 2020
19791d1
Initialize index_last_successful_
AndyZe Sep 13, 2020
9929cc2
Tweak simple_example.cpp for better accuracy
AndyZe Sep 13, 2020
a0ad0a9
Rebase, clang format, clang tidy
zultron Sep 20, 2020
43724a1
single_joint_generator: Remove trailing `_` from function parameter …
zultron Sep 23, 2020
0fc6930
Zultron/tracksuite refactor pt1 (#62)
zultron Oct 5, 2020
d3cf022
Don't need a warning for failure to comp at first waypoint
AndyZe Oct 22, 2020
060dab4
Print warning if results directory doesn't exist
AndyZe Oct 22, 2020
479e734
Fix small rebase mistake
AndyZe Oct 22, 2020
a28a7d4
Clang format
AndyZe Oct 22, 2020
4b4f3f3
Add comment about duration extension constant
AndyZe Oct 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed .catkin_tools/CATKIN_IGNORE
Empty file.
13 changes: 0 additions & 13 deletions .catkin_tools/README

This file was deleted.

1 change: 0 additions & 1 deletion .catkin_tools/VERSION

This file was deleted.

Empty file.
2 changes: 1 addition & 1 deletion .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: true
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@
.DS_Store

# SSH Keys (used for Docker)
id_rsa
id_rsa

# Catkin tools
/.catkin-tools/

54 changes: 54 additions & 0 deletions include/trackjoint/configuration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*********************************************************************
* Copyright (c) 2019, PickNik Consulting
* All rights reserved.
*
* Unauthorized copying of this file, via any medium is strictly prohibited
* Proprietary and confidential
*********************************************************************/

/* Author: John Morris
Desc: Trajectory generator configuration.
*/

#pragma once

#include "trackjoint/limits.h"

namespace trackjoint
{
/**
* \brief Trajectory generator configuration.
*/
struct Configuration
{
Configuration(double timestep, double max_duration, const Limits& limits, const double position_tolerance,
bool use_streaming_mode)
: timestep(timestep)
, max_duration(max_duration)
, limits(limits)
, position_tolerance(position_tolerance)
, use_streaming_mode(use_streaming_mode)
{
}

Configuration()
{
}

double timestep;
double max_duration;
Limits limits;
double position_tolerance;
// If streaming mode is enabled, trajectories are clipped at
// kNumWaypointsThreshold so the algorithm runs very quickly.
//
// Streaming mode is intended for realtime streaming applications.
//
// There could be even fewer waypoints than that if the goal is very
// close or the algorithm only finds a few waypoints successfully.
//
// In streaming mode, trajectory duration is not extended until it
// successfully reaches the goal.
bool use_streaming_mode;
};
} // namespace trackjoint
33 changes: 19 additions & 14 deletions include/trackjoint/error_codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,28 @@ enum ErrorCodeEnum
LIMIT_NOT_POSITIVE = 6,
GOAL_POSITION_MISMATCH = 7,
FAILURE_TO_GENERATE_SINGLE_WAYPOINT = 8,
LESS_THAN_TEN_TIMESTEPS_FOR_STREAMING_MODE = 9
LESS_THAN_TEN_TIMESTEPS_FOR_STREAMING_MODE = 9,
OBJECT_NOT_RESET = 10,
};

/**
* \brief Use this map to look up human-readable strings for each error code
*/
const std::unordered_map<uint, std::string> ERROR_CODE_MAP(
{ { NO_ERROR, "No error, trajectory generation was successful" },
{ DESIRED_DURATION_TOO_SHORT, "Desired duration is too short, cannot have less than one timestep in a "
"trajectory" },
{ MAX_DURATION_EXCEEDED, "Max duration was exceeded" },
{ VELOCITY_EXCEEDS_LIMIT, "A velocity input exceeds the velocity limit" },
{ ACCEL_EXCEEDS_LIMIT, "An acceleration input exceeds the acceleration limit" },
{ MAX_DURATION_LESS_THAN_DESIRED_DURATION, "max_duration should not be less than desired_duration" },
{ LIMIT_NOT_POSITIVE, "Vel/accel/jerk limits should be greater than zero" },
{ GOAL_POSITION_MISMATCH, "Mismatch between the final position and the goal position" },
{ FAILURE_TO_GENERATE_SINGLE_WAYPOINT, "Failed to generate even a single new waypoint" },
{ LESS_THAN_TEN_TIMESTEPS_FOR_STREAMING_MODE, "In streaming mode, desired duration should be at least 10 "
"timesteps" } });
const std::unordered_map<uint, std::string> ERROR_CODE_MAP({
{ NO_ERROR, "No error, trajectory generation was successful" },
{ DESIRED_DURATION_TOO_SHORT,
"Desired duration is too short, cannot have less than one timestep in a "
"trajectory" },
{ MAX_DURATION_EXCEEDED, "Max duration was exceeded" },
{ VELOCITY_EXCEEDS_LIMIT, "A velocity input exceeds the velocity limit" },
{ ACCEL_EXCEEDS_LIMIT, "An acceleration input exceeds the acceleration limit" },
{ MAX_DURATION_LESS_THAN_DESIRED_DURATION, "max_duration should not be less than desired_duration" },
{ LIMIT_NOT_POSITIVE, "Vel/accel/jerk limits should be greater than zero" },
{ GOAL_POSITION_MISMATCH, "Mismatch between the final position and the goal position" },
{ FAILURE_TO_GENERATE_SINGLE_WAYPOINT, "Failed to generate even a single new waypoint" },
{ LESS_THAN_TEN_TIMESTEPS_FOR_STREAMING_MODE,
"In streaming mode, desired duration should be at least 10 timesteps" },
{ OBJECT_NOT_RESET, "Must call reset() before generating trajectory" },

});
} // end namespace trackjoint
77 changes: 43 additions & 34 deletions include/trackjoint/single_joint_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,72 @@

#pragma once

#include <cmath> // copysign
#include <cmath> // copysign
#include <unsupported/Eigen/Splines> // Spline-fitting is used to extend trajectory duration
#include "trackjoint/error_codes.h"
#include "trackjoint/joint_trajectory.h"
#include "trackjoint/kinematic_state.h"
#include "trackjoint/configuration.h"
#include "trackjoint/limits.h"
#include "trackjoint/utilities.h"

namespace trackjoint
{
typedef Eigen::Spline<double, 1, 2> Spline1D;
typedef Eigen::SplineFitting<Spline1D> SplineFitting1D;

class SingleJointGenerator
{
public:
/** \brief Constructor
*
* input num_waypoints_threshold minimum/maximum number of waypoints for full trajectory/streaming modes, respectively
* input max_num_waypoints_trajectory_mode to maintain determinism, return an error if more than this many waypoints
* is required
*/
SingleJointGenerator(size_t num_waypoints_threshold, size_t max_num_waypoints_trajectory_mode);

/** \brief reset data members and prepare to generate a new trajectory
*
* input configuration A `Configuration` object
* input current_joint_states vector of the initial kinematic states for each degree of freedom
* input goal_joint_states vector of the target kinematic states for each degree of freedom
* input desired_num_waypoints nominal number of waypoints, calculated from user-supplied duration and timestep
* input timestep_was_upsampled If upsampling happened (we are working with very few waypoints), do not adjust
* timestep
*
*/
void reset(const Configuration& configuration, const KinematicState& current_joint_state,
const KinematicState& goal_joint_state, size_t desired_num_waypoints, bool timestep_was_upsampled);

/** \brief reset data members and prepare to generate a new trajectory
*
* input timestep desired time between waypoints
* input desired_duration total desired duration of the trajectory
* input max_duration allow the trajectory to be extended up to this limit. Error if that cannot be done.
* input current_joint_states vector of the initial kinematic states for each degree of freedom
* input goal_joint_states vector of the target kinematic states for each degree of freedom
* input limits vector of kinematic limits for each degree of freedom
* input desired_num_waypoints nominal number of waypoints, calculated from user-supplied duration and timestep
* input num_waypoints_threshold minimum/maximum number of waypoints for full trajectory/streaming modes, respectively
* input max_num_waypoints_trajectory_mode to maintain determinism, return an error if more than this many waypoints
* is required
* input position_tolerance tolerance for how close the final trajectory should follow a smooth interpolation.
* Should be set lower than the accuracy requirements for your task
* input use_streaming_mode set to true for fast streaming applications. Returns a maximum of num_waypoints_threshold
* waypoints.
* waypoints.
* input timestep_was_upsampled If upsampling happened (we are working with very few waypoints), do not adjust
* timestep
*
*/
SingleJointGenerator(double timestep, double desired_duration, double max_duration,
const KinematicState& current_joint_state, const KinematicState& goal_joint_state,
const Limits& limits, size_t desired_num_waypoints, size_t num_waypoints_threshold,
size_t max_num_waypoints_trajectory_mode, const double position_tolerance,
bool use_streaming_mode);

/** \brief reset data members and prepare to generate a new trajectory */
void reset(double timestep, double desired_duration, double max_duration, const KinematicState& current_joint_state,
void reset(double timestep, double max_duration, const KinematicState& current_joint_state,
const KinematicState& goal_joint_state, const Limits& limits, size_t desired_num_waypoints,
const double position_tolerance, bool use_streaming_mode);
const double position_tolerance, bool use_streaming_mode, bool timestep_was_upsampled);

/** \brief Generate a jerk-limited trajectory for this joint
*
* return a TrackJoint status code
*/
ErrorCodeEnum generateTrajectory();

/** \brief Calculate a trajectory once duration is known. Similar to generateTrajectory minus predictTimeToReach().
*
* return a TrackJoint status code
*/
ErrorCodeEnum extendTrajectoryDuration();
/** \brief Extend a trajectory to a new duration. Magnitudes of vel/accel/jerk will be decreased. */
void extendTrajectoryDuration();

/** \brief Get the generated trajectory
*
Expand Down Expand Up @@ -105,7 +120,7 @@ class SingleJointGenerator

/** \brief Start looking back through a velocity vector to calculate for an
* excess velocity at limited_index. */
bool backwardLimitCompensation(size_t limited_index, double* excess_velocity);
bool backwardLimitCompensation(size_t limited_index, double excess_velocity);

@nbbrooks nbbrooks Sep 21, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still needs to be a ptr otherwise any leftover excess_velocity computed in the function gets discarded

@AndyZe AndyZe Oct 22, 2020

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, check this out...

      successful_compensation = backwardLimitCompensation(index, -delta_v);
      if (!successful_compensation)
      {
        position_error = position_error + delta_v * configuration_.timestep;

So we keep the full delta_v if !successful_compensation. If compensation is successful, it's assumed that delta_v is zero. The logic seems good either way, to me.


/** \brief This uses backwardLimitCompensation() but it starts from a position
* vector */
Expand All @@ -115,26 +130,20 @@ class SingleJointGenerator
ErrorCodeEnum predictTimeToReach();

/** \brief Calculate vel/accel/jerk from position */
void calculateDerivatives();
void calculateDerivativesFromPosition();

/** \brief Calculate accel/jerk from velocity */
void calculateDerivativesFromVelocity();

const size_t kNumWaypointsThreshold, kMaxNumWaypointsFullTrajectory;

double timestep_;
double desired_duration_, max_duration_;
Configuration configuration_;
double desired_duration_;
KinematicState current_joint_state_;
KinematicState goal_joint_state_;
Limits limits_;
double position_tolerance_;
Eigen::VectorXd nominal_times_;
JointTrajectory waypoints_;
size_t index_last_successful_;

// If streaming mode is enabled, trajectories are clipped at kNumWaypointsThreshold so the algorithm runs very
// quickly.
// streaming mode is intended for realtime streaming applications.
// There could be even fewer waypoints than that if the goal is very close or the algorithm only finds a few waypoints
// successfully.
// In streaming mode, trajectory duration is not extended until it successfully reaches the goal.
bool use_streaming_mode_;
bool is_reset_;
}; // end class SingleJointGenerator
} // namespace trackjoint
9 changes: 5 additions & 4 deletions include/trackjoint/trajectory_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "trackjoint/utilities.h"

// C++
#include <boost/filesystem.hpp>
#include <Eigen/Geometry>
#include <memory> // shared_ptr
#include <vector>
Expand Down Expand Up @@ -78,7 +79,7 @@ class TrajectoryGenerator
* input limits vector of kinematic limits for each degree of freedom
* input nominal_timestep the user-requested time between waypoints
* returna TrackJoint status code
*/
*/
ErrorCodeEnum inputChecking(const std::vector<KinematicState>& current_joint_states,
const std::vector<KinematicState>& goal_joint_states, const std::vector<Limits>& limits,
double nominal_timestep);
Expand All @@ -87,7 +88,7 @@ class TrajectoryGenerator
/** \brief Ensure limits are obeyed before outputting.
*
* input trajectory the calculated trajectories for n joints
*/
*/
void clipVectorsForOutput(std::vector<JointTrajectory>* trajectory);

/** \brief upsample if num. waypoints would be short. Helps with accuracy. */
Expand All @@ -100,15 +101,15 @@ class TrajectoryGenerator
* input velocity_vector a vector of velocities
* input acceleration_vector a vector of accelerations
* input jerk_vector a vector of jerks
*/
*/
void downSample(Eigen::VectorXd* time_vector, Eigen::VectorXd* position_vector, Eigen::VectorXd* velocity_vector,
Eigen::VectorXd* acceleration_vector, Eigen::VectorXd* jerk_vector);

/** \brief Synchronize all trajectories with the one of longest duration.
*
* input output_trajectories the calculated trajectories for n joints
* returna TrackJoint status code
*/
*/
ErrorCodeEnum synchronizeTrajComponents(std::vector<JointTrajectory>* output_trajectories);

// TODO(andyz): set this back to a small number when done testing
Expand Down
2 changes: 1 addition & 1 deletion include/trackjoint/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Eigen::VectorXd DiscreteDifferentiation(const Eigen::VectorXd& input_vector, dou
* input joint the index of a joint
* input output_trajectories the calculated trajectories for n joints
* input desired_duration the user-requested duration of the trajectory
*/
*/
void PrintJointTrajectory(const std::size_t joint, const std::vector<JointTrajectory>& output_trajectories,
const double desired_duration);

Expand Down
33 changes: 20 additions & 13 deletions src/simple_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,46 +21,53 @@ int main(int argc, char** argv)
// This example is for just one degree of freedom
constexpr int num_dof = 1;
// Timestep. Units don't matter as long as they're consistent
constexpr double timestep = 0.0075;
// Total desired trajectory duration
constexpr double desired_duration = 0.028322;
constexpr double timestep = 0.001;
// TrackJoint is allowed to extend the trajectory up to this duration, if a solution at kDesiredDuration can't be
// found
constexpr double max_duration = 10;
constexpr double max_duration = 5;
// streaming mode returns just a few waypoints but executes very quickly. We won't use it here -- we'll calculate
// the whole trajectory at once.
constexpr bool use_streaming_mode = false;
// Optional logging of TrackJoint output
const std::string output_path_base = "/home/" + std::string(getenv("USER")) + "/trackjoint_data/output_joint";
const std::string output_path_base =
"/home/" + std::string(getenv("USER")) + "/Downloads/trackjoint_data/output_joint";

std::vector<trackjoint::KinematicState> current_joint_states(1);
trackjoint::KinematicState joint_state;
joint_state.position = 0.00596041;
joint_state.velocity = -0.176232;
joint_state.acceleration = -3.06289;
joint_state.position = 1.16431;
joint_state.velocity = 2.66465;
joint_state.acceleration = 0;
// This is the initial state of the joint
current_joint_states[0] = joint_state;

std::vector<trackjoint::KinematicState> goal_joint_states(1);
joint_state.position = -0.00121542;
joint_state.velocity = -0.289615;
joint_state.acceleration = -2.88021;
joint_state.position = 1.40264;
joint_state.velocity = 2.88556;
joint_state.acceleration = 0.0615633;
goal_joint_states[0] = joint_state;

trackjoint::Limits single_joint_limits;
// Typically, jerk limit >> acceleration limit > velocity limit
single_joint_limits.velocity_limit = 3.15;
single_joint_limits.acceleration_limit = 5;
single_joint_limits.jerk_limit = 5000;
single_joint_limits.jerk_limit = 100;
std::vector<trackjoint::Limits> limits(1, single_joint_limits);

// Estimate trajectory duration
// This is the fastest possible trajectory execution time, assuming the robot starts at full velocity.
double desired_duration =
fabs(goal_joint_states[0].position - current_joint_states[0].position) / single_joint_limits.velocity_limit;
std::cout << "Desired duration: " << desired_duration << std::endl;

// This descibes how far TrackJoint can deviate from a smooth, interpolated polynomial.
// It is used for calculations internally. It should be set to a smaller number than your task requires.
const double position_tolerance = 1e-6;
const double position_tolerance = 0.0001;

// Instantiate a trajectory generation object
trackjoint::TrajectoryGenerator traj_gen(num_dof, timestep, desired_duration, max_duration, current_joint_states,
goal_joint_states, limits, position_tolerance, use_streaming_mode);
traj_gen.reset(timestep, desired_duration, max_duration, current_joint_states, goal_joint_states, limits,
position_tolerance, use_streaming_mode);
// This vector holds the trajectories for each DOF
std::vector<trackjoint::JointTrajectory> output_trajectories(num_dof);
// Optionally, check user input for common errors, like current velocities being less than velocity limits
Expand Down
Loading