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

support modifying wrappers in user stages #253

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
15 changes: 9 additions & 6 deletions core/include/moveit/task_constructor/container.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,15 @@ class ParallelContainerBase : public ContainerBase
/// lift child solution to external interface, adapting the costs and comment
void liftSolution(const SolutionBase& solution, double cost, std::string comment);

/// spawn a new solution with given state as start and end
void spawn(InterfaceState&& state, SubTrajectory&& trajectory);
/// propagate a solution forwards
void sendForward(const InterfaceState& from, InterfaceState&& to, SubTrajectory&& trajectory);
/// propagate a solution backwards
void sendBackward(InterfaceState&& from, const InterfaceState& to, SubTrajectory&& trajectory);
/// lift a modified solution based on the solution of a child stage
void liftModifiedSolution(const SolutionBasePtr& new_solution, const SolutionBase& child_solution);
/// lift a modified solution, changing the (single!) new associated start or end InterfaceState
void liftModifiedSolution(const SolutionBasePtr& new_solution, InterfaceState&& new_propagated_state,
const SolutionBase& child_solution);
/// lift a modified solution, providing new start and end states
/// The new states will only be used if this's should actually create the corresponding states
void liftModifiedSolution(const SolutionBasePtr& new_solution, InterfaceState&& new_start_state,
InterfaceState&& new_end_state, const SolutionBase& child_solution);
};

/** Plan for different alternatives in parallel.
Expand Down
6 changes: 4 additions & 2 deletions core/include/moveit/task_constructor/container_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,11 @@ class ContainerBasePrivate : public StagePrivate
/// 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);
/// lift solution from internal to external level
/// lift solution from internal to external level, possibly replacing the generated InterfaceStates with new_*
/// If specified, *new_from/*new_to will be moved from.
void liftSolution(const SolutionBasePtr& solution, const InterfaceState* internal_from,
const InterfaceState* internal_to);
const InterfaceState* internal_to, InterfaceState* new_from = nullptr,
InterfaceState* new_to = nullptr);

/// protected writable overloads
inline auto& internalToExternalMap() { return internal_external_.left; }
Expand Down
5 changes: 5 additions & 0 deletions core/include/moveit/task_constructor/stage_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,12 @@ class StagePrivate
void spawn(InterfaceState&& state, const SolutionBasePtr& solution);
void connect(const InterfaceState& from, const InterfaceState& to, const SolutionBasePtr& solution);

// store stage-owned data structures
bool storeSolution(const SolutionBasePtr& solution, const InterfaceState* from, const InterfaceState* to);
inline InterfaceState* storeState(InterfaceState&& state) {
return &*states_.insert(states_.end(), std::move(state));
}

void newSolution(const SolutionBasePtr& solution);
bool storeFailures() const { return introspection_ != nullptr; }
void runCompute() {
Expand Down
136 changes: 105 additions & 31 deletions core/src/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,44 +196,99 @@ void ContainerBasePrivate::copyState(Interface::iterator external, const Interfa
}

// create a clone of external state within target interface (child's starts() or ends())
auto internal = states_.insert(states_.end(), InterfaceState(*external));
target->add(*internal);
InterfaceState* internal = storeState(InterfaceState{ *external });

// and remember the mapping between them
internalToExternalMap().insert(std::make_pair(&*internal, &*external));
internalToExternalMap().insert(std::make_pair(internal, &*external));
target->add(*internal);
}

void ContainerBasePrivate::liftSolution(const SolutionBasePtr& solution, const InterfaceState* internal_from,
const InterfaceState* internal_to) {
computeCost(*internal_from, *internal_to, *solution);

// map internal to external states
auto find_or_create_external = [this](const InterfaceState* internal, bool& created) -> InterfaceState* {
const InterfaceState* internal_to, InterfaceState* new_from,
InterfaceState* new_to) {
// NOLINTNEXTLINE(readability-identifier-naming)
auto findExternal = [this](const InterfaceState* internal) -> const InterfaceState* {
auto it = internalToExternalMap().find(internal);
if (it != internalToExternalMap().end())
return const_cast<InterfaceState*>(it->second);
if (it != internalToExternalMap().end()) {
return &*it->second;
}

InterfaceState* external = &*states_.insert(states_.end(), InterfaceState(*internal));
internalToExternalMap().insert(std::make_pair(internal, external));
created = true;
return external;
return nullptr;
};
bool created_from = false;
bool created_to = false;
InterfaceState* external_from = find_or_create_external(internal_from, created_from);
InterfaceState* external_to = find_or_create_external(internal_to, created_to);

if (!storeSolution(solution, external_from, external_to))
// external states, nullptr if they don't exist yet
const InterfaceState* external_from{ findExternal(internal_from) };
const InterfaceState* external_to{ findExternal(internal_to) };

// TODO(v4hn) rethink this. ComputeIK is exactly this case. Do I want to support an n:m mapping from internal to
// external?
if ((new_from && external_from && external_from != new_from) || (new_to && external_to && external_to != new_to)) {
ROS_ERROR_STREAM_NAMED("Container", "Container '" << name_ << "' tried to lift a modified solution from child '"
<< solution->creator()->name()
<< "', but a different one already exists. Children's "
"InterfaceStates can only ever match one ");
return;
}

// computeCost
// If there are no external states known yet, we can pass internal_{from/to} here
// because in this case the lifted states that will be created later
// are equivalent up to the connected Solutions (which are not relevant for CostTerms)
{
auto getPreliminaryState = [](const InterfaceState* external, const InterfaceState* new_state,
const InterfaceState* internal) -> const InterfaceState& {
if (external)
return *external;
if (new_state)
return *new_state;
else
return *internal;
};
computeCost(getPreliminaryState(external_from, new_from, internal_from),
getPreliminaryState(external_to, new_to, internal_to), *solution);
}

// storeSolution
// only pass stored external states here (others are not relevant for pruning)
if (!storeSolution(solution, external_from, external_to)) {
return;
}

// store unstored states in stage-internal storage

// NOLINTNEXTLINE(readability-identifier-naming)
auto createState = [this](const InterfaceState& internal, InterfaceState* new_external) {
InterfaceState* external{ storeState(new_external ? std::move(*new_external) : InterfaceState{ internal }) };
internalToExternalMap().insert(std::make_pair(&internal, external));
v4hn marked this conversation as resolved.
Show resolved Hide resolved
return external;
};

const bool create_from{ external_from == nullptr };
const bool create_to{ external_to == nullptr };

if (create_from) {
assert(requiredInterface().testFlag(WRITES_PREV_END));
external_from = createState(*internal_from, new_from);
}
if (create_to) {
assert(requiredInterface().testFlag(WRITES_NEXT_START));
external_to = createState(*internal_to, new_to);
}

// connect solution to start/end state
assert(external_from);
assert(external_to);

// connect solution to stored states
solution->setStartState(*external_from);
solution->setEndState(*external_to);

// spawn created states in external interfaces
if (created_from)
prevEnds()->add(*external_from);
if (created_to)
nextStarts()->add(*external_to);
// spawn new external states
if (!solution->isFailure()) {
if (create_from)
prevEnds()->add(*const_cast<InterfaceState*>(external_from));
if (create_to)
nextStarts()->add(*const_cast<InterfaceState*>(external_to));
}

newSolution(solution);
}
Expand Down Expand Up @@ -735,18 +790,37 @@ void ParallelContainerBase::liftSolution(const SolutionBase& solution, double co
solution.start(), solution.end());
}

void ParallelContainerBase::spawn(InterfaceState&& state, SubTrajectory&& t) {
pimpl()->StagePrivate::spawn(std::move(state), std::make_shared<SubTrajectory>(std::move(t)));
void ParallelContainerBase::liftModifiedSolution(const SolutionBasePtr& modified_solution, const SolutionBase& child_solution) {
// child_solution is correctly prepared by a child of this container
assert(child_solution.creator());
assert(child_solution.creator()->parent() == this);
v4hn marked this conversation as resolved.
Show resolved Hide resolved

pimpl()->liftSolution(modified_solution, child_solution.start(), child_solution.end());
}

void ParallelContainerBase::sendForward(const InterfaceState& from, InterfaceState&& to, SubTrajectory&& t) {
pimpl()->StagePrivate::sendForward(from, std::move(to), std::make_shared<SubTrajectory>(std::move(t)));
void ParallelContainerBase::liftModifiedSolution(const SolutionBasePtr& new_solution, InterfaceState&& new_propagated_state, const SolutionBase& child_solution) {
assert(child_solution.creator());
assert(child_solution.creator()->parent() == this);

if(pimpl()->requiredInterface() == GENERATE){
// in this case we need a second InterfaceState to move from
InterfaceState new_to{ new_propagated_state };
pimpl()->liftSolution(new_solution, child_solution.start(), child_solution.end(), &new_propagated_state, &new_to);
}
else {
// pass new_propagated_state as start *and* end. We know at most one will be used.
pimpl()->liftSolution(new_solution, child_solution.start(), child_solution.end(), &new_propagated_state, &new_propagated_state);
}
}

void ParallelContainerBase::sendBackward(InterfaceState&& from, const InterfaceState& to, SubTrajectory&& t) {
pimpl()->StagePrivate::sendBackward(std::move(from), to, std::make_shared<SubTrajectory>(std::move(t)));
void ParallelContainerBase::liftModifiedSolution(const SolutionBasePtr& new_solution, InterfaceState&& new_from, InterfaceState&& new_to, const SolutionBase& child_solution) {
assert(child_solution.creator());
assert(child_solution.creator()->parent() == this);

pimpl()->liftSolution(new_solution, child_solution.start(), child_solution.end(), &new_from, &new_to);
}


WrapperBasePrivate::WrapperBasePrivate(WrapperBase* me, const std::string& name)
: ParallelContainerBasePrivate(me, name) {}

Expand Down
16 changes: 8 additions & 8 deletions core/src/stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,14 @@ void StagePrivate::sendForward(const InterfaceState& from, InterfaceState&& to,

me()->forwardProperties(from, to);

auto to_it = states_.insert(states_.end(), std::move(to));
InterfaceState* to_stored{ storeState(std::move(to)) };

// register stored interfaces with solution
solution->setStartState(from);
solution->setEndState(*to_it);
solution->setEndState(*to_stored);

if (!solution->isFailure())
nextStarts()->add(*to_it);
nextStarts()->add(*to_stored);

newSolution(solution);
}
Expand All @@ -182,13 +182,13 @@ void StagePrivate::sendBackward(InterfaceState&& from, const InterfaceState& to,

me()->forwardProperties(to, from);

auto from_it = states_.insert(states_.end(), std::move(from));
InterfaceState* from_stored{ storeState(std::move(from)) };

solution->setStartState(*from_it);
solution->setStartState(*from_stored);
solution->setEndState(to);

if (!solution->isFailure())
prevEnds()->add(*from_it);
prevEnds()->add(*from_stored);

newSolution(solution);
}
Expand All @@ -201,8 +201,8 @@ void StagePrivate::spawn(InterfaceState&& state, const SolutionBasePtr& solution
if (!storeSolution(solution, nullptr, nullptr))
return; // solution dropped

auto from = states_.insert(states_.end(), InterfaceState(state)); // copy
auto to = states_.insert(states_.end(), std::move(state));
InterfaceState* from{ storeState(InterfaceState{ state }) };
InterfaceState* to{ storeState(std::move(state)) };

solution->setStartState(*from);
solution->setEndState(*to);
Expand Down
34 changes: 17 additions & 17 deletions core/src/stages/compute_ik.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,15 +335,15 @@ void ComputeIK::compute() {
->getParentJointModel()
->getDescendantLinkModels();
if (colliding) {
SubTrajectory solution;
auto solution = std::make_shared<SubTrajectory>();
generateCollisionMarkers(sandbox_state, appender, links_to_visualize);
std::copy(failure_markers.begin(), failure_markers.end(), std::back_inserter(solution.markers()));
solution.markAsFailure();
std::copy(failure_markers.begin(), failure_markers.end(), std::back_inserter(solution->markers()));
solution->markAsFailure();
// TODO: visualize collisions
solution.setComment(s.comment() + " eef in collision: " + listCollisionPairs(collisions.contacts, ", "));
solution->setComment(s.comment() + " eef in collision: " + listCollisionPairs(collisions.contacts, ", "));
auto colliding_scene{ scene->diff() };
colliding_scene->setCurrentState(sandbox_state);
spawn(InterfaceState(colliding_scene), std::move(solution));
liftModifiedSolution(solution, InterfaceState(colliding_scene), s);
return;
} else
generateVisualMarkers(sandbox_state, appender, links_to_visualize);
Expand Down Expand Up @@ -396,18 +396,18 @@ void ComputeIK::compute() {
for (size_t i = previous; i != ik_solutions.size(); ++i) {
// create a new scene for each solution as they will have different robot states
planning_scene::PlanningScenePtr solution_scene = scene->diff();
SubTrajectory solution;
solution.setComment(s.comment());
auto solution = std::make_shared<SubTrajectory>();
solution->setComment(s.comment());

// frames at target pose and ik frame
rviz_marker_tools::appendFrame(solution.markers(), target_pose_msg, 0.1, "ik frame");
rviz_marker_tools::appendFrame(solution.markers(), ik_pose_msg, 0.1, "ik frame");
rviz_marker_tools::appendFrame(solution->markers(), target_pose_msg, 0.1, "ik frame");
rviz_marker_tools::appendFrame(solution->markers(), ik_pose_msg, 0.1, "ik frame");

if (succeeded && i + 1 == ik_solutions.size())
// compute cost as distance to compare_pose
solution.setCost(s.cost() + jmg->distance(ik_solutions.back().data(), compare_pose.data()));
solution->setCost(s.cost() + jmg->distance(ik_solutions.back().data(), compare_pose.data()));
else // found an IK solution, but this was not valid
solution.markAsFailure();
solution->markAsFailure();

// set scene's robot state
robot_state::RobotState& solution_state = solution_scene->getCurrentStateNonConst();
Expand All @@ -416,7 +416,7 @@ void ComputeIK::compute() {

InterfaceState state(solution_scene);
forwardProperties(*s.start(), state);
spawn(std::move(state), std::move(solution));
liftModifiedSolution(solution, std::move(state), s);
}

// TODO: magic constant should be a property instead ("current_seed_only", or equivalent)
Expand All @@ -428,15 +428,15 @@ void ComputeIK::compute() {

if (ik_solutions.empty()) { // failed to find any solution
planning_scene::PlanningScenePtr scene = s.start()->scene()->diff();
SubTrajectory solution;
auto solution = std::make_shared<SubTrajectory>();

solution.markAsFailure();
solution.setComment(s.comment() + " no IK found");
solution->markAsFailure();
solution->setComment(s.comment() + " no IK found");

// ik target link placement
std::copy(failure_markers.begin(), failure_markers.end(), std::back_inserter(solution.markers()));
std::copy(failure_markers.begin(), failure_markers.end(), std::back_inserter(solution->markers()));

spawn(InterfaceState(scene), std::move(solution));
liftModifiedSolution(solution, InterfaceState(scene), s);
}
}
} // namespace stages
Expand Down
4 changes: 2 additions & 2 deletions core/test/test_cost_terms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ TEST(CostTerm, CompositeSolutions) {
{
auto s1{ std::make_unique<ForwardCostMockup>() };
auto s2{ std::make_unique<ForwardCostMockup>() };
auto c1{ std::make_unique<SerialContainer>() };
auto c1{ std::make_unique<SerialContainer>("c1") };
auto constant1{ std::make_shared<cost::Constant>(1.0) };
s1->setCostTerm(constant1);
s2->setCostTerm(constant1);
Expand All @@ -334,7 +334,7 @@ TEST(CostTerm, CompositeSolutionsContainerCost) {
auto s1_ptr{ s1.get() };
auto s2{ std::make_unique<ForwardTrajectoryMockup>() };

auto c1{ std::make_unique<SerialContainer>() };
auto c1{ std::make_unique<SerialContainer>("c1") };
c1->add(std::move(s1));
c1->add(std::move(s2));

Expand Down