Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
f32e747
add hook to ParallelContainerBase to customize state propagation
v4hn Aug 18, 2021
8719b1c
Implement state-wise Fallbacks
v4hn Aug 19, 2021
3d5cecd
fallback generator can run a single job per compute call
v4hn Sep 2, 2021
aa733fc
simplify onNewFailure
v4hn Sep 2, 2021
5a9cfc5
cleanup: get rid of superfluous parameter
v4hn Sep 2, 2021
9a583ab
run only one compute step per call
v4hn Sep 3, 2021
22809c0
order external states
v4hn Sep 10, 2021
887da5b
fix fallbacks logic
v4hn Sep 14, 2021
b6ac5b0
add demo illustrating useful fallbacks behavior
v4hn Sep 15, 2021
6301169
Fix pruning
rhaschke Sep 16, 2021
7235e56
enable successful test for connect-fallbacks
v4hn Sep 22, 2021
23f32d7
restructure fallbacks logic
v4hn Sep 20, 2021
e2ad662
Fallbacks: rename Incoming to Pending
v4hn Sep 23, 2021
c37cf6e
Handle updates on external states
rhaschke Sep 16, 2021
478b60c
enable core test for fallbacks behavior
v4hn Sep 23, 2021
6a80425
use switch for enum
v4hn Sep 23, 2021
2d53f1b
fix logic for pop in fallbacks states
v4hn Sep 23, 2021
c6c6d50
cleanup failed() reference
v4hn Sep 23, 2021
42cf67e
fallbacks: include current state in pending
v4hn Sep 24, 2021
66e141d
Fix printChildrenInterfaces()
rhaschke Nov 15, 2021
011e4be
Add more pruning tests
rhaschke Nov 18, 2021
c617e33
Disable failing tests
rhaschke Nov 19, 2021
718170a
Always skip pruning if there exist alternative enabled solutions
rhaschke Nov 19, 2021
97c2130
Improve readability
rhaschke Nov 19, 2021
1ddf7dd
Never remove pending CONNECT pairs
rhaschke Nov 19, 2021
4170a1c
Drop unused and misleading Direction enums
rhaschke Nov 19, 2021
29d1e44
Rework updatePriority() functions
rhaschke Nov 19, 2021
06ae5dd
Fix hasPendingOpposites()
rhaschke Nov 19, 2021
52dc494
Fix test Pruning.NoPruningIfAlternativesExist
rhaschke Nov 19, 2021
1dda3d1
Switch order of function declarations
rhaschke Nov 19, 2021
3c4ef68
Rename Interface::Status FAILED -> ARMED
rhaschke Nov 20, 2021
ab9af6a
Recursively re-enable states when matching an ARMED state
rhaschke Nov 20, 2021
ffb8598
Recursively prune new CONNECT state if there is no enabled opposite
rhaschke Nov 20, 2021
9d37495
Recombine both variants of Interface::updatePriority()
rhaschke Nov 21, 2021
3648db4
Never overwrite ARMED with PRUNED
rhaschke Nov 21, 2021
a31e52d
Propagate status across Connecting gap
rhaschke Nov 21, 2021
fdd5ff8
templatize: pullInterface(dir) -> pullInterface<dir>()
rhaschke Nov 21, 2021
a48b932
Distinguish STATUS and PRIORITY updates in notify() callbacks
rhaschke Nov 21, 2021
aef9916
Propagate either STATUS or PRIORITY updates into a container
rhaschke Nov 21, 2021
e5ec9b3
Remove main() from test_fallback.cpp
rhaschke Nov 22, 2021
13208f0
Improve readability
rhaschke Nov 22, 2021
3d9f654
Reduce code duplication
rhaschke Nov 22, 2021
0bd89f2
Simplify debug output functions
rhaschke Nov 22, 2021
a912f10
Use Interface::Direction enum as index to pending_states_
rhaschke Nov 22, 2021
0df470c
Fix clang-specific warnings
rhaschke Nov 22, 2021
c4b2004
Merge PR #309: fix pruning
rhaschke Nov 22, 2021
f22778c
Enable Fallbacks pruning test (failing)
rhaschke Nov 22, 2021
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
8 changes: 5 additions & 3 deletions core/include/moveit/task_constructor/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class Alternatives : public ParallelContainerBase
void onNewSolution(const SolutionBase& s) override;
};

class FallbacksPrivate;
/** Plan for different alternatives in sequence.
*
* Try to find feasible solutions using first child. Only if this fails,
Expand All @@ -158,16 +159,17 @@ class Alternatives : public ParallelContainerBase
*/
class Fallbacks : public ParallelContainerBase
{
mutable Stage* active_child_ = nullptr;

public:
Fallbacks(const std::string& name = "fallbacks") : ParallelContainerBase(name) {}
PRIVATE_CLASS(Fallbacks);
Fallbacks(const std::string& name = "fallbacks");

void reset() override;
void init(const moveit::core::RobotModelConstPtr& robot_model) override;
bool canCompute() const override;
void compute() override;

protected:
Fallbacks(FallbacksPrivate* impl);
void onNewSolution(const SolutionBase& s) override;
};

Expand Down
95 changes: 88 additions & 7 deletions core/include/moveit/task_constructor/container_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ namespace task_constructor {
class ContainerBasePrivate : public StagePrivate
{
friend class ContainerBase;
friend class ConnectingPrivate; // needs to call protected setStatus()
friend void swap(StagePrivate*& lhs, StagePrivate*& rhs);

public:
Expand Down Expand Up @@ -131,7 +132,7 @@ class ContainerBasePrivate : public StagePrivate
inline const auto& externalToInternalMap() const { return internal_external_.by<EXTERNAL>(); }

/// called by a (direct) child when a solution failed
void onNewFailure(const Stage& child, const InterfaceState* from, const InterfaceState* to);
virtual void onNewFailure(const Stage& child, const InterfaceState* from, const InterfaceState* to);

protected:
ContainerBasePrivate(ContainerBase* me, const std::string& name);
Expand All @@ -148,13 +149,21 @@ class ContainerBasePrivate : public StagePrivate
child->setNextStarts(allowed ? pending_forward_ : InterfacePtr());
}

/// Set ENABLED / PRUNED status of the solution tree starting from s into given direction
/// Set ENABLED/PRUNED status of a solution branch starting from target into the given direction
template <Interface::Direction dir>
void setStatus(const InterfaceState* s, InterfaceState::Status status);
void setStatus(const Stage* creator, const InterfaceState* source, const InterfaceState* target,
InterfaceState::Status status);
/// non-template version
void setStatus(Interface::Direction dir, const Stage* creator, const InterfaceState* source,
const InterfaceState* target, InterfaceState::Status status);

/// copy external_state to a child's interface and remember the link in internal_external map
template <Interface::Direction>
void copyState(Interface::iterator external, const InterfacePtr& target, bool updated);
void copyState(Interface::iterator external, const InterfacePtr& target, Interface::UpdateFlags updated);
/// non-template version
void copyState(Interface::Direction dir, Interface::iterator external, const InterfacePtr& target,
Interface::UpdateFlags updated);

/// lift solution from internal to external level
void liftSolution(const SolutionBasePtr& solution, const InterfaceState* internal_from,
const InterfaceState* internal_to);
Expand Down Expand Up @@ -227,13 +236,85 @@ class ParallelContainerBasePrivate : public ContainerBasePrivate
protected:
void validateInterfaces(const StagePrivate& child, InterfaceFlags& external, bool first = false) const;

private:
/// callback for new externally received states
/// notify callback for new states received on external interfaces
template <typename Interface::Direction>
void onNewExternalState(Interface::iterator external, bool updated);
void propagateStateToChildren(Interface::iterator external, Interface::UpdateFlags updated);

private:
// override for custom behavior on received interface states
virtual void initializeExternalInterfaces();
};
PIMPL_FUNCTIONS(ParallelContainerBase)

class FallbacksPrivate : public ParallelContainerBasePrivate
{
friend class Fallbacks;

struct ExternalState
{
ExternalState() = default;
ExternalState(Interface::iterator state, container_type::const_iterator child)
: external_state(state), stage(child) {}

Interface::iterator external_state;
container_type::const_iterator stage;

inline bool operator<(const ExternalState& other) const { return *external_state < *other.external_state; }
};

struct PendingStates
{
std::pair<ExternalState, Interface::Direction> pop();
inline void push(const ExternalState& job, Interface::Direction dir);
inline bool empty() const { return pending_states_[0].empty() && pending_states_[1].empty(); }

/// get pending states queue for a given direction
template <Interface::Direction dir>
inline ordered<ExternalState>& queue() {
static_assert(static_cast<size_t>(dir) < 2, "Expecting dir = FORWARD | BACKWARD");
return pending_states_[dir];
}

inline auto& current() { return current_; }

ordered<ExternalState> pending_states_[2]; ///< separate queues for start / end states
Interface::Direction current_queue_ = Interface::FORWARD; ///< which queue to check on next pop
struct
{
bool valid = false;
ExternalState state;
Interface::Direction dir = Interface::FORWARD;
} current_;

} pending_;

friend std::ostream& operator<<(std::ostream& os, const FallbacksPrivate::PendingStates& pending);

public:
FallbacksPrivate(Fallbacks* me, const std::string& name);

protected:
inline void computeGenerate();
void computeFromExternal();

bool seekToNextPending();

container_type::const_iterator current_generator_;
bool seekToNextGenerator();

private:
void initializeExternalInterfaces() override;
template <typename Interface::Direction>
void onNewExternalState(Interface::iterator external, Interface::UpdateFlags updated);
void onNewFailure(const Stage& child, const InterfaceState* from, const InterfaceState* to) override;

void advanceCurrentStateToNextChild();
// print pending states for debugging
void printPending(const char* comment = "pending: ") const;
};
PIMPL_FUNCTIONS(Fallbacks)
std::ostream& operator<<(std::ostream& os, const FallbacksPrivate::PendingStates& pending);

class WrapperBasePrivate : public ParallelContainerBasePrivate
{
friend class WrapperBase;
Expand Down
52 changes: 28 additions & 24 deletions core/include/moveit/task_constructor/stage_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,11 @@ class StagePrivate
inline InterfaceConstPtr prevEnds() const { return prev_ends_.lock(); }
inline InterfaceConstPtr nextStarts() const { return next_starts_.lock(); }

/// direction-based access to pull/push interfaces
inline InterfacePtr& pullInterface(Interface::Direction dir) { return dir == Interface::FORWARD ? starts_ : ends_; }
inline InterfacePtr pushInterface(Interface::Direction dir) {
return dir == Interface::FORWARD ? next_starts_.lock() : prev_ends_.lock();
}
inline InterfaceConstPtr pullInterface(Interface::Direction dir) const {
return dir == Interface::FORWARD ? starts_ : ends_;
}
inline InterfaceConstPtr pushInterface(Interface::Direction dir) const {
return dir == Interface::FORWARD ? next_starts_.lock() : prev_ends_.lock();
}
/// direction-based access to pull interface
template <Interface::Direction dir>
inline InterfacePtr pullInterface();
/// non-template version
inline InterfacePtr pullInterface(Interface::Direction dir);

/// set parent of stage
/// enforce only one parent exists
Expand Down Expand Up @@ -204,6 +198,19 @@ class StagePrivate
PIMPL_FUNCTIONS(Stage)
std::ostream& operator<<(std::ostream& os, const StagePrivate& stage);

template <>
inline InterfacePtr StagePrivate::pullInterface<Interface::FORWARD>() {
return starts_;
}
template <>
inline InterfacePtr StagePrivate::pullInterface<Interface::BACKWARD>() {
return ends_;
}
inline InterfacePtr StagePrivate::pullInterface(Interface::Direction dir) {
return dir == Interface::Direction::FORWARD ? pullInterface<Interface::Direction::FORWARD>() :
pullInterface<Interface::Direction::BACKWARD>();
}

template <>
inline void StagePrivate::send<Interface::FORWARD>(const InterfaceState& start, InterfaceState&& end,
const SolutionBasePtr& solution) {
Expand Down Expand Up @@ -310,18 +317,15 @@ class ConnectingPrivate : public ComputeBasePrivate
}
static inline bool less(const InterfaceState::Priority& lhsA, const InterfaceState::Priority& lhsB,
const InterfaceState::Priority& rhsA, const InterfaceState::Priority& rhsB) {
unsigned char lhs = (lhsA.enabled() << 1) | lhsB.enabled(); // combine bits into two-digit binary number
unsigned char rhs = (rhsA.enabled() << 1) | rhsB.enabled();
bool lhs = lhsA.enabled() && lhsB.enabled();
bool rhs = rhsA.enabled() && rhsB.enabled();

if (lhs == rhs) // if enabled status is identical
return lhsA + lhsB < rhsA + rhsB; // compare the sums of both contributions
// one of the states in each pair should be enabled
assert(lhs != 0b00 && rhs != 0b00);
// both states valid (b11)
if (lhs == 0b11)
return true;
if (rhs == 0b11)
return false;
return lhs < rhs; // disabled states in 1st component go before disabled states in 2nd component

// sort both-enabled pairs first
static_assert(true > false, "Comparing enabled states requires true > false");
return lhs > rhs;
}
};

Expand All @@ -333,7 +337,7 @@ class ConnectingPrivate : public ComputeBasePrivate

// Check whether there are pending feasible states that could connect to source
template <Interface::Direction dir>
bool hasPendingOpposites(const InterfaceState* source) const;
bool hasPendingOpposites(const InterfaceState* source, const InterfaceState* target) const;

std::ostream& printPendingPairs(std::ostream& os = std::cerr) const;

Expand All @@ -342,9 +346,9 @@ class ConnectingPrivate : public ComputeBasePrivate
template <Interface::Direction other>
inline StatePair make_pair(Interface::const_iterator first, Interface::const_iterator second);

// get informed when new start or end state becomes available
// notify callback to get informed about newly inserted (or updated) start or end states
template <Interface::Direction other>
void newState(Interface::iterator it, bool updated);
void newState(Interface::iterator it, Interface::UpdateFlags updated);

// ordered list of pending state pairs
ordered<StatePair> pending;
Expand Down
44 changes: 36 additions & 8 deletions core/include/moveit/task_constructor/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <moveit/macros/class_forward.h>
#include <moveit/task_constructor/properties.h>
#include <moveit/task_constructor/cost_queue.h>
#include <moveit/task_constructor/utils.h>
#include <moveit_task_constructor_msgs/Solution.h>
#include <visualization_msgs/MarkerArray.h>

Expand Down Expand Up @@ -82,9 +83,11 @@ class InterfaceState
enum Status
{
ENABLED, // state is actively considered during planning
PRUNED, // state is disabled because a required connected state failed
FAILED, // state that failed, causing the whole partial solution to be disabled
ARMED, // disabled state in a Connecting interface that will become re-enabled with a new opposite state
PRUNED, // disabled state on a pruned solution branch
};
static const char* STATUS_COLOR[];

/** InterfaceStates are ordered according to two values:
* Depth of interlinked trajectory parts and accumulated trajectory costs along that path.
* Preference ordering considers high-depth first and within same depth, minimal cost paths.
Expand All @@ -100,8 +103,6 @@ class InterfaceState

inline Status status() const { return std::get<0>(*this); }
inline bool enabled() const { return std::get<0>(*this) == ENABLED; }
inline bool failed() const { return std::get<0>(*this) == FAILED; }
inline bool pruned() const { return std::get<0>(*this) == PRUNED; }

inline unsigned int depth() const { return std::get<1>(*this); }
inline double cost() const { return std::get<2>(*this); }
Expand Down Expand Up @@ -138,13 +139,21 @@ class InterfaceState

/// states are ordered by priority
inline bool operator<(const InterfaceState& other) const { return this->priority_ < other.priority_; }

inline const Priority& priority() const { return priority_; }
/// Update priority and call owner's notify() if possible
void updatePriority(const InterfaceState::Priority& priority);
/// Update status, but keep current priority
void updateStatus(Status status);

Interface* owner() const { return owner_; }

private:
// these methods should be only called by SolutionBase::set[Start|End]State()
inline void addIncoming(SolutionBase* t) { incoming_trajectories_.push_back(t); }
inline void addOutgoing(SolutionBase* t) { outgoing_trajectories_.push_back(t); }
// Set new priority without updating the owning interface (USE WITH CARE)
inline void setPriority(const Priority& prio) { priority_ = prio; }

private:
planning_scene::PlanningSceneConstPtr scene_;
Expand All @@ -169,6 +178,7 @@ class Interface : public ordered<InterfaceState*>
class iterator : public base_type::iterator
{
public:
iterator() = default;
iterator(base_type::iterator other) : base_type::iterator(other) {}

InterfaceState& operator*() const noexcept { return *base_type::iterator::operator*(); }
Expand All @@ -190,10 +200,27 @@ class Interface : public ordered<InterfaceState*>
{
FORWARD,
BACKWARD,
START = FORWARD,
END = BACKWARD
};
using NotifyFunction = std::function<void(iterator, bool)>;
enum Update
{
STATUS = 1 << 0,
PRIORITY = 1 << 1,
ALL = STATUS | PRIORITY,
};
using UpdateFlags = utils::Flags<Update>;
using NotifyFunction = std::function<void(iterator, UpdateFlags)>;

class DisableNotify
{
Interface& if_;
Interface::NotifyFunction old_;

public:
DisableNotify(Interface& i) : if_(i) { old_.swap(if_.notify_); }
~DisableNotify() { old_.swap(if_.notify_); }
};
friend class DisableNotify;

Interface(const NotifyFunction& notify = NotifyFunction());

/// add a new InterfaceState
Expand All @@ -204,9 +231,10 @@ class Interface : public ordered<InterfaceState*>

/// update state's priority (and call notify_ if it really has changed)
void updatePriority(InterfaceState* state, const InterfaceState::Priority& priority);
inline bool notifyEnabled() const { return static_cast<bool>(notify_); }

private:
const NotifyFunction notify_;
NotifyFunction notify_;

// restrict access to some functions to ensure consistency
// (we need to set/unset InterfaceState::owner_)
Expand Down
2 changes: 0 additions & 2 deletions core/include/moveit/task_constructor/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,6 @@ class Flags
Int i;
};

#define DECLARE_FLAGS(Flags, Enum) using Flags = QFlags<Enum>;

const moveit::core::LinkModel* getRigidlyConnectedParentLinkModel(const moveit::core::RobotState& state,
std::string frame);

Expand Down
Loading