Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding another kinodynamic timer #443

Merged
merged 27 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
* Added flags to WorldStateSaver to specify what to save: [#339](https://github.com/personalrobotics/aikido/pull/339)
* Changed interface for TrajectoryPostProcessor: [#341](https://github.com/personalrobotics/aikido/pull/341)
* Planning calls with InverseKinematicsSampleable constraints explicitly set MetaSkeleton to solve IK with: [#379](https://github.com/personalrobotics/aikido/pull/379)
* Add a kinodynamic timer that generates a time-optimal smooth trajectory without completely stopping at each waypoint: [#443](https://github.com/personalrobotics/aikido/pull/443)
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Added ~


* Robot

Expand Down
36 changes: 36 additions & 0 deletions cmake/FindEIGEN3.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (c) 2011-2018, The DART development contributors
# All rights reserved.
#
# The list of contributors can be found at:
# https://github.com/dartsim/dart/blob/master/LICENSE
#
# This file is provided under the "BSD-style" License

# Find Eigen
#
# This sets the following variables:
# EIGEN3_FOUND
# EIGEN3_INCLUDE_DIRS
# EIGEN3_VERSION

find_package(PkgConfig QUIET)

# Check to see if pkgconfig is installed.
pkg_check_modules(PC_EIGEN3 eigen3 QUIET)

# Include directories
find_path(EIGEN3_INCLUDE_DIRS
NAMES Eigen/Core
PATHS "${CMAKE_INSTALL_PREFIX}/include"
PATH_SUFFIXES eigen3 eigen)

# Version
set(EIGEN3_VERSION ${PC_EIGEN3_VERSION})

# Set (NAME)_FOUND if all the variables and the version are satisfied.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(EIGEN3
FAIL_MESSAGE DEFAULT_MSG
REQUIRED_VARS EIGEN3_INCLUDE_DIRS
VERSION_VAR EIGEN3_VERSION)

139 changes: 139 additions & 0 deletions include/aikido/planner/kinodynamic/KinodynamicTimer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#ifndef AIKIDO_PLANNER_KINODYNAMIC_KINODYNAMICTIMER_HPP_
#define AIKIDO_PLANNER_KINODYNAMIC_KINODYNAMICTIMER_HPP_

#include <Eigen/Dense>
#include "aikido/planner/TrajectoryPostProcessor.hpp"
#include "aikido/trajectory/Interpolated.hpp"
#include "aikido/trajectory/Spline.hpp"

namespace aikido {
namespace planner {
namespace kinodynamic {

/// Computes the time-optimal timing of a trajectory consisting of a sequence
/// Geodesic interpolations between states under velocity and acceleration
/// bounds. The output is a parabolic spline, encoded in cubic polynomials.
/// It firstly preprocesses a non-differentiable path to a differentiable one
/// by adding circular blends; and then \b exactly follows the preprocessed
/// path.
///
/// The output trajectory consists of a sequence of trapezoidal velocity
/// profiles that implement bang-bang control. This function curently only
/// supports \c RealVector, \c SO2, and compound state spaces of those types.
/// Additionally, this function requires that \c inputTrajectory to be
/// interpolated using a \c GeodesicInterpolator.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does the input trajectory need to have been interpolated using GeodesicInterpolator? Why the explicit mention? Just curious. Any sequence of waypoints should be fine right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this is necessary. The interpolation implies the shape of a path given a sequence of waypoints. If you choose a different interpolator, the shape of a path will be different (length might also be changed). The timing algorithm works on the assumption of the geodesic interpolation.

///
/// \param[in] inputTrajectory input piecewise Geodesic trajectory
/// \param[in] maxVelocity maximum velocity for each dimension
/// \param[in] maxAcceleration maximum acceleration for each dimension
/// \param[in] maxDeviation maximum deviation from a waypoint in doing circular
/// blending around the waypoint
/// \param[in] timeStep time step in following the path
/// \return time optimal trajectory that satisfies acceleration constraints
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: mention velocity constraints too? 🤔

std::unique_ptr<aikido::trajectory::Spline> computeKinodynamicTiming(
const aikido::trajectory::Interpolated& inputTrajectory,
const Eigen::VectorXd& maxVelocity,
const Eigen::VectorXd& maxAcceleration,
double maxDeviation = 1e-2,
double timeStep = 0.1);

/// Computes the time-optimal timing of a spline trajectory under velocity
/// and acceleration bounds. The output is another parabolic spline, encoded
/// in cubic polynomials. In retiming, the input trajectory is used as a
/// piecewise Geodesic trajectory (only the geometry of the input trajectory
/// is considered; and the velocity information is ignored. It firstly
/// preprocesses a non-differentiable path to a differentiable one by adding
/// circular blends; and then \b exactly follows the preprocessed path.
///
/// The output trajectory consists of a sequence of trapezoidal velocity
/// profiles that implement bang-bang control. This function curently only
/// supports \c RealVector, \c SO2, and compound state spaces of those types.
/// Additionally, this function requires that \c inputTrajectory to be
/// a spline (only the geometry of the trajectory is considered in retiming).
///
/// \param[in] inputTrajectory input piecewise Geodesic trajectory
/// \param[in] maxVelocity maximum velocity for each dimension
/// \param[in] maxAcceleration maximum acceleration for each dimension
/// \param[in] maxDeviation maximum deviation from a waypoint in doing circular
/// blending around the waypoint
/// \param[in] timeStep time step in following the path
/// \return time optimal trajectory that satisfies acceleration constraints
std::unique_ptr<aikido::trajectory::Spline> computeKinodynamicTiming(
const aikido::trajectory::Spline& inputTrajectory,
const Eigen::VectorXd& maxVelocity,
const Eigen::VectorXd& maxAcceleration,
double maxDeviation = 1e-2,
double timeStep = 0.1);

/// Class for performing time-optimal trajectory retiming following subject to
/// velocity and acceleration limits.
class KinodynamicTimer : public aikido::planner::TrajectoryPostProcessor
{
public:
/// \param[in] velocityLimits Maximum velocity for each dimension.
/// \param[in] accelerationLimits Maximum acceleration for each dimension.
/// \param[in] maxDeviation Maximum deviation in circular blending
/// \param[in] timeStep Time step in following the path
KinodynamicTimer(
const Eigen::VectorXd& velocityLimits,
const Eigen::VectorXd& accelerationLimits,
double maxDeviation,
double timeStep);

/// Performs parabolic retiming on an input trajectory.
/// \copydoc TrajectoryPostProcessor::postprocess
std::unique_ptr<aikido::trajectory::Spline> postprocess(
const aikido::trajectory::Interpolated& inputTraj,
const aikido::common::RNG& rng,
const aikido::constraint::TestablePtr& constraint = nullptr) override;

/// Performs parabolic retiming on an input *spline* trajectory.
/// \copydoc TrajectoryPostProcessor::postprocess
std::unique_ptr<aikido::trajectory::Spline> postprocess(
const aikido::trajectory::Spline& inputTraj,
const aikido::common::RNG& rng,
const aikido::constraint::TestablePtr& constraint = nullptr) override;

/// Returns the velocity limits of the dimensions
const Eigen::VectorXd& getVelocityLimits() const;
Copy link
Contributor

Choose a reason for hiding this comment

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

Are all these getters and setters useful? I'm not sure if they're necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the getters are useful. For example, when we want to validate whether a timed trajectory violates the limits but only have the access to the timer handle. I prefer to keep the setters as well. It provides a way of adjusting timer parameters without reconstructing a new timer object.


/// Returns the acceleration limits of the dimensions
const Eigen::VectorXd& getAccelerationLimits() const;

/// Sets the velocity limits of the dimensions
void setVelocityLimits(const Eigen::VectorXd& velocityLimits);

/// Sets the acceleration limits of the dimensions
void setAccelerationLimits(const Eigen::VectorXd& accelerationLimits);

/// Returns the time step in following a path
double getTimeStep() const;

/// Sets the time step in following a path
void setTimeStep(double timeStep);

/// Returns the max deviation of circular blending
double getMaxDeviation() const;

/// Sets the max deviation of circular blending
void setMaxDeviation(double maxDeviation);

private:
/// Set to the value of \c velocityLimits.
Eigen::VectorXd mVelocityLimits;

/// Set to the value of \c accelerationLimits.
Eigen::VectorXd mAccelerationLimits;

/// Set to the value of \c maxDeviation
double mMaxDeviation;

/// Set to the value of \c timeStep
double mTimeStep;
};

} // namespace kinodynamic
} // namespace planner
} // namespace aikido

#endif // ifndef AIKIDO_PLANNER_KINODYNAMIC_KINODYNAMICTIMER_HPP_
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Aikido targets are marked as [target_name].

add_subdirectory("external/hauser_parabolic_smoother")
add_subdirectory("external/optimal_time_path_following")

add_subdirectory("common") # boost, dart
add_subdirectory("io") # [common], boost, dart, tinyxml2, yaml-cpp
Expand Down
18 changes: 18 additions & 0 deletions src/external/optimal_time_path_following/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
find_package(EIGEN3 REQUIRED)

add_library("${PROJECT_NAME}_external_optimaltimepathfollowing" STATIC
Path.cpp
Trajectory.cpp
)

target_include_directories("${PROJECT_NAME}_external_optimaltimepathfollowing"
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}"
${EIGEN3_INCLUDE_DIRS}
)
set_target_properties("${PROJECT_NAME}_external_optimaltimepathfollowing"
PROPERTIES POSITION_INDEPENDENT_CODE TRUE
)
target_compile_options("${PROJECT_NAME}_external_optimaltimepathfollowing"
PUBLIC ${AIKIDO_CXX_STANDARD_FLAGS}
PRIVATE -w
)
Loading