Skip to content

Commit

Permalink
added velocity interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars Berscheid committed Feb 22, 2021
1 parent 4755cff commit e029558
Show file tree
Hide file tree
Showing 20 changed files with 856 additions and 449 deletions.
6 changes: 4 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ endif()

add_library(ruckig SHARED
src/brake.cpp
src/step1.cpp
src/step2.cpp
src/position1.cpp
src/position2.cpp
src/velocity1.cpp
src/velocity2.cpp
)
target_compile_features(ruckig PUBLIC cxx_std_17)
target_include_directories(ruckig PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ Vector max_jerk;
std::optional<Vector> min_velocity; // If not given, the negative maximum velocity will be used.
std::optional<Vector> min_acceleration; // If not given, the negative maximum acceleration will be used.

Interface interface; // Default is the regular position interface
Synchronization synchronization; // Synchronization behavior of multiple DoFs
std::array<bool, DOFs> enabled; // Initialized to true
std::optional<double> minimum_duration;
Expand Down
18 changes: 9 additions & 9 deletions include/ruckig/alternative/reflexxes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ class Reflexxes {
}
}

switch (input.type) {
case InputParameter<DOFs>::Type::Position: {
switch (input.interface) {
case InputParameter<DOFs>::Interface::Position: {
if (input.minimum_duration) {
input_parameters->SetMinimumSynchronizationTime(input.minimum_duration.value());
}
Expand All @@ -70,7 +70,7 @@ class Reflexxes {
input_parameters->SetMaxAccelerationVector(input.max_acceleration.data());
input_parameters->SetMaxJerkVector(input.max_jerk.data());
} break;
case InputParameter<DOFs>::Type::Velocity: {
case InputParameter<DOFs>::Interface::Velocity: {
if (input.minimum_duration) {
input_vel_parameters->SetMinimumSynchronizationTime(input.minimum_duration.value());
}
Expand All @@ -88,8 +88,8 @@ class Reflexxes {

auto start = std::chrono::high_resolution_clock::now();

switch (input.type) {
case InputParameter<DOFs>::Type::Position: {
switch (input.interface) {
case InputParameter<DOFs>::Interface::Position: {
result_value = rml->RMLPosition(*input_parameters, output_parameters.get(), flags);

for (size_t dof = 0; dof < DOFs; ++dof) {
Expand All @@ -100,7 +100,7 @@ class Reflexxes {
output.trajectory.duration = output_parameters->GetSynchronizationTime();
output.new_calculation = output_parameters->WasACompleteComputationPerformedDuringTheLastCycle();
} break;
case InputParameter<DOFs>::Type::Velocity: {
case InputParameter<DOFs>::Interface::Velocity: {
result_value = rml->RMLVelocity(*input_vel_parameters, output_vel_parameters.get(), vel_flags);

for (size_t dof = 0; dof < DOFs; ++dof) {
Expand All @@ -125,8 +125,8 @@ class Reflexxes {
}

void at_time(double time, OutputParameter<DOFs>& output) {
switch (current_input.type) {
case InputParameter<DOFs>::Type::Position: {
switch (current_input.interface) {
case InputParameter<DOFs>::Interface::Position: {
rml->RMLPositionAtAGivenSampleTime(time, output_parameters.get());

for (size_t dof = 0; dof < DOFs; dof += 1) {
Expand All @@ -135,7 +135,7 @@ class Reflexxes {
output.new_acceleration[dof] = output_parameters->NewAccelerationVector->VecData[dof];
}
} break;
case InputParameter<DOFs>::Type::Velocity: {
case InputParameter<DOFs>::Interface::Velocity: {
rml->RMLVelocityAtAGivenSampleTime(time, output_vel_parameters.get());

for (size_t dof = 0; dof < DOFs; dof += 1) {
Expand Down
97 changes: 97 additions & 0 deletions include/ruckig/block.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#pragma once

#include <limits>
#include <optional>

#include <ruckig/profile.hpp>


namespace ruckig {

//! Which times are possible for synchronization?
struct Block {
struct Interval {
double left, right; // [s]
Profile profile; // Profile corresponding to right (end) time

explicit Interval(double left, double right, const Profile& profile): left(left), right(right), profile(profile) { };
};

Profile p_min; // Save min profile so that it doesn't need to be recalculated in Step2
double t_min; // [s]

// Max. 2 intervals can be blocked: called a and b with corresponding profiles, order does not matter
std::optional<Interval> a, b;

explicit Block() { }
explicit Block(const Profile& p_min): p_min(p_min), t_min(p_min.t_sum[6] + p_min.t_brake.value_or(0.0)) { }

bool is_blocked(double t) const {
return (t < t_min) || (a && a->left < t && t < a->right) || (b && b->left < t && t < b->right);
}

inline static void add_interval(std::optional<Block::Interval>& interval, const Profile& left, const Profile& right) {
const double left_duration = left.t_sum[6] + left.t_brake.value_or(0.0);
const double right_duraction = right.t_sum[6] + right.t_brake.value_or(0.0);
if (left_duration < right_duraction) {
interval = Block::Interval(left_duration, right_duraction, right);
} else {
interval = Block::Interval(right_duraction, left_duration, left);
}
}

template<size_t N>
static bool calculate_block(Block& block, const std::array<Profile, N>& valid_profiles, const size_t valid_profile_counter) {
// if (valid_profile_counter > 0)
// {
// std::cout << "---\n " << valid_profile_counter << std::endl;
// for (size_t i = 0; i < valid_profile_counter; ++i) {
// std::cout << valid_profiles[i].t_sum[6] << " " << valid_profiles[i].to_string() << std::endl;
// }
// }

if (
(valid_profile_counter == 1)
|| (valid_profile_counter == 2 && std::abs(valid_profiles[0].t_sum[6] - valid_profiles[1].t_sum[6]) < std::numeric_limits<double>::epsilon())
) {
block = Block(valid_profiles[0]);
return true;

} else if (valid_profile_counter % 2 == 0) {
return false;
}

// Find index of fastest profile
auto idx_min_it = std::min_element(valid_profiles.cbegin(), valid_profiles.cbegin() + valid_profile_counter, [](auto& a, auto& b) { return a.t_sum[6] + a.t_brake.value_or(0.0) < b.t_sum[6] + b.t_brake.value_or(0.0); });
size_t idx_min = std::distance(valid_profiles.cbegin(), idx_min_it);

block = Block(valid_profiles[idx_min]);

if (valid_profile_counter == 3) {
size_t idx_else_1 = (idx_min + 1) % 3;
size_t idx_else_2 = (idx_min + 2) % 3;

Block::add_interval(block.a, valid_profiles[idx_else_1], valid_profiles[idx_else_2]);
return true;

} else if (valid_profile_counter == 5) {
size_t idx_else_1 = (idx_min + 1) % 5;
size_t idx_else_2 = (idx_min + 2) % 5;
size_t idx_else_3 = (idx_min + 3) % 5;
size_t idx_else_4 = (idx_min + 4) % 5;

if (valid_profiles[idx_else_1].direction == valid_profiles[idx_else_2].direction) {
Block::add_interval(block.a, valid_profiles[idx_else_1], valid_profiles[idx_else_2]);
Block::add_interval(block.b, valid_profiles[idx_else_3], valid_profiles[idx_else_4]);
} else {
Block::add_interval(block.a, valid_profiles[idx_else_1], valid_profiles[idx_else_4]);
Block::add_interval(block.b, valid_profiles[idx_else_2], valid_profiles[idx_else_3]);
}
return true;
}

return false;
}
};

} // namespace ruckig
20 changes: 20 additions & 0 deletions include/ruckig/brake.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <array>


namespace ruckig {

//! Calculates (pre-) trajectory to get current state below the limits
class Brake {
static constexpr double eps {2e-14};

static void acceleration_brake(double v0, double a0, double vMax, double vMin, double aMax, double aMin, double jMax, std::array<double, 2>& t_brake, std::array<double, 2>& j_brake);
static void velocity_brake(double v0, double a0, double vMax, double vMin, double aMax, double aMin, double jMax, std::array<double, 2>& t_brake, std::array<double, 2>& j_brake);

public:
static void get_position_brake_trajectory(double v0, double a0, double vMax, double vMin, double aMax, double aMin, double jMax, std::array<double, 2>& t_brake, std::array<double, 2>& j_brake);
static void get_velocity_brake_trajectory(double a0, double aMax, double aMin, double jMax, std::array<double, 2>& t_brake, std::array<double, 2>& j_brake);
};

} // namespace ruckig
6 changes: 3 additions & 3 deletions include/ruckig/parameter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ class InputParameter {
using Vector = std::array<double, DOFs>;
static constexpr size_t degrees_of_freedom {DOFs};

enum class Type {
enum class Interface {
Position,
Velocity,
} type {Type::Position};
} interface {Interface::Position};

enum class Synchronization {
Time,
Expand Down Expand Up @@ -78,7 +78,7 @@ class InputParameter {
|| minimum_duration != rhs.minimum_duration
|| min_velocity != rhs.min_velocity
|| min_acceleration != rhs.min_acceleration
|| type != rhs.type
|| interface != rhs.interface
|| synchronization != rhs.synchronization
);
}
Expand Down
73 changes: 9 additions & 64 deletions include/ruckig/steps.hpp → include/ruckig/position.hpp
Original file line number Diff line number Diff line change
@@ -1,55 +1,16 @@
#pragma once

#include <array>
#include <limits>
#include <optional>

#include <ruckig/trajectory.hpp>


namespace ruckig {

//! Which times are possible for synchronization?
struct Block {
struct Interval {
double left, right; // [s]
Profile profile; // Profile corresponding to right (end) time

explicit Interval(double left, double right, const Profile& profile): left(left), right(right), profile(profile) { };
};

Profile p_min; // Save min profile so that it doesn't need to be recalculated in Step2
double t_min; // [s]

// Max. 2 intervals can be blocked: called a and b with corresponding profiles, order does not matter
std::optional<Interval> a, b;

explicit Block() { }
explicit Block(const Profile& p_min): p_min(p_min), t_min(p_min.t_sum[6] + p_min.t_brake.value_or(0.0)) { }

bool is_blocked(double t) const {
return (t < t_min) || (a && a->left < t && t < a->right) || (b && b->left < t && t < b->right);
}
};


//! Calculates (pre-) trajectory to get current state below the limits
class Brake {
static constexpr double eps {2e-14};

static void acceleration_brake(double v0, double a0, double vMax, double vMin, double aMax, double aMin, double jMax, std::array<double, 2>& t_brake, std::array<double, 2>& j_brake);
static void velocity_brake(double v0, double a0, double vMax, double vMin, double aMax, double aMin, double jMax, std::array<double, 2>& t_brake, std::array<double, 2>& j_brake);

public:
static void get_brake_trajectory(double v0, double a0, double vMax, double vMin, double aMax, double aMin, double jMax, std::array<double, 2>& t_brake, std::array<double, 2>& j_brake);
};


//! Mathematical equations for Step 1: Extremal profiles
class Step1 {
using Limits = Profile::Limits;
using JerkSigns = Profile::JerkSigns;
using Limits = Profile::Limits;
using JerkSigns = Profile::JerkSigns;

//! Mathematical equations for Step 1 in position interface: Extremal profiles
class Position1 {
double p0, v0, a0;
double pf, vf, af;
double vMax, vMin, aMax, aMin, jMax;
Expand Down Expand Up @@ -91,33 +52,17 @@ class Step1 {
++valid_profile_counter;
}

inline void add_interval(std::optional<Block::Interval>& interval, size_t left, size_t right) const {
const double left_duration = valid_profiles[left].t_sum[6] + valid_profiles[left].t_brake.value_or(0.0);
const double right_duraction = valid_profiles[right].t_sum[6] + valid_profiles[right].t_brake.value_or(0.0);
if (left_duration < right_duraction) {
interval = Block::Interval(left_duration, right_duraction, valid_profiles[right]);
} else {
interval = Block::Interval(right_duraction, left_duration, valid_profiles[left]);
}
}

bool calculate_block(Block& block) const;

public:
explicit Step1(double p0, double v0, double a0, double pf, double vf, double af, double vMax, double vMin, double aMax, double aMin, double jMax);
explicit Position1(double p0, double v0, double a0, double pf, double vf, double af, double vMax, double vMin, double aMax, double aMin, double jMax);

bool get_profile(const Profile& input, Block& block);
};


//! Mathematical equations for Step 2: Time synchronization
class Step2 {
using Limits = Profile::Limits;
using JerkSigns = Profile::JerkSigns;

double tf;
//! Mathematical equations for Step 2 in position interface: Time synchronization
class Position2 {
double p0, v0, a0;
double pf, vf, af;
double tf, pf, vf, af;
double vMax, vMin, aMax, aMin, jMax;

// Pre-calculated expressions
Expand Down Expand Up @@ -152,7 +97,7 @@ class Step2 {
}

public:
explicit Step2(double tf, double p0, double v0, double a0, double pf, double vf, double af, double vMax, double vMin, double aMax, double aMin, double jMax);
explicit Position2(double tf, double p0, double v0, double a0, double pf, double vf, double af, double vMax, double vMin, double aMax, double aMin, double jMax);

bool get_profile(Profile& profile);
};
Expand Down
Loading

0 comments on commit e029558

Please sign in to comment.