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

Testable Constraint Output #266

Merged
merged 52 commits into from
Jan 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
3fcb61f
Added TestableOutcomeClass.
evil-sherdil Nov 26, 2017
46ed3d8
Added NonCollidingOutcome.hpp
evil-sherdil Nov 26, 2017
4dfa900
Include TestableOutcome in Testable. Fix TestableOutcome to make it w…
evil-sherdil Nov 26, 2017
9368a14
Updated Testable isSatisfied signature and changed *bunch* of signatu…
evil-sherdil Nov 26, 2017
235e0da
Changed NonCollidingOutcome name to reflect CollisionFree name change…
evil-sherdil Nov 26, 2017
98ef161
Started CollisionFreeOutcome.cpp. Small changed to make it build once…
evil-sherdil Nov 26, 2017
9c36bae
Wrote toString for CollisionFreeOutcome.
evil-sherdil Nov 26, 2017
62af07b
Made CollisionFree fill _outcome on a collision (if not nullptr).
evil-sherdil Nov 26, 2017
081e23e
Fixed test files to make tests build. Will run make format in just a …
evil-sherdil Nov 27, 2017
d28417c
Added testing for CollisionFreeOutcome.
evil-sherdil Nov 27, 2017
faffb52
Use move semantics in CollisionFreeOutcome toString method.
evil-sherdil Nov 27, 2017
3ecb343
Ran make format.
evil-sherdil Nov 27, 2017
a276c6a
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
jslee02 Nov 27, 2017
c281a03
Adressed nits from @jslee02. Moving to squish those unused param warn…
evil-sherdil Nov 28, 2017
f83c72a
Merge branch 'sniyaz/feature/testableConstraintOutput' of https://git…
evil-sherdil Nov 28, 2017
9863a86
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
brianhou Nov 28, 2017
924041b
Silence unused param warning, ran make format again.
evil-sherdil Nov 28, 2017
a4a0309
Used dynamic_cast in CollisionFree when populating outcome fields. Ba…
evil-sherdil Nov 28, 2017
2af9453
Modify CollisionFreeOutcome to take Contact references as inputs as p…
evil-sherdil Nov 28, 2017
4ec21f8
Move include of sstream into .cpp file instead of header.
evil-sherdil Nov 28, 2017
4e2e20f
Made tests take advantage of programatic acess to data. Required addi…
evil-sherdil Nov 28, 2017
b8e0010
Made getter methods for Contact vectors const because they can be.
evil-sherdil Nov 28, 2017
816e86e
Address nits from @jslee02.
evil-sherdil Nov 30, 2017
4174efc
Two small nits I missed in the last commit.
evil-sherdil Nov 30, 2017
511555a
Aaaaaand, one more!
evil-sherdil Nov 30, 2017
b3da15d
Implemented createOutcome functionality in Testable base class.
evil-sherdil Dec 1, 2017
e061d63
Use auto collisionOutcome as per request of @brianhou.
evil-sherdil Dec 1, 2017
e1ed415
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
evil-sherdil Dec 5, 2017
6c2dbec
Moved dynamic cast for outcome in CollisionFree.
evil-sherdil Dec 5, 2017
d3ada66
Added method to clear CollisionFreeOutcome. Use this method in Collis…
evil-sherdil Dec 5, 2017
7b10b67
Fixed directory placement of outcome classes. Renamed DummyOutcome --…
evil-sherdil Dec 5, 2017
0868db7
Added simple functionality to DefaultOutcome.
evil-sherdil Dec 5, 2017
cbc1b34
Responded to most recent review comments by making every Testable der…
evil-sherdil Dec 6, 2017
7a3b762
Run make format.
evil-sherdil Dec 6, 2017
079b2f3
[WIP] Refactor castic logic into helper, and use this in CollisionFre…
evil-sherdil Dec 6, 2017
e990862
[WIP] Replace redundant casting login in different Testables with hel…
evil-sherdil Dec 6, 2017
ce4160d
[WIP] Mop up some extra casts that were missed prior.
evil-sherdil Dec 6, 2017
4768cda
Added documentation.
evil-sherdil Dec 6, 2017
43c8f92
Make CollisionFree a friend class of CollisionFreeOutcome, use Eigen …
evil-sherdil Dec 6, 2017
e5e5d5b
Modify FrameTestable to "pass through" outcome object to mPoseConstra…
evil-sherdil Dec 6, 2017
354d3d5
Rename DefaultOutcome ---> DefaultTestableOutcome. Final clean up as …
evil-sherdil Dec 6, 2017
18b2dda
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
brianhou Dec 7, 2017
cd9d522
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
brianhou Dec 7, 2017
2c67a67
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
brianhou Dec 8, 2017
0f6731b
Address @mkoval's comments.
brianhou Dec 11, 2017
d1b2040
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
jslee02 Dec 12, 2017
ab1556f
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
jslee02 Dec 15, 2017
b70af0a
Update nits: comment and renamed dynamic_cast_if_present to dynamic_c…
evil-sherdil Jan 5, 2018
9208f04
Undo the use of the Eigen allocator in CollisionFreeOutcome.
evil-sherdil Jan 5, 2018
12647a3
Update CHANGELOG.md
brianhou Jan 6, 2018
2fae405
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
brianhou Jan 6, 2018
1357778
Merge branch 'master' into sniyaz/feature/testableConstraintOutput
jslee02 Jan 6, 2018
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 @@ -9,6 +9,7 @@

* Added methods for removing groups from NonColliding constraints: [#247](https://github.com/personalrobotics/aikido/pull/247)
* Renamed NonColliding to CollisionFree: [#256](https://github.com/personalrobotics/aikido/pull/256)
* Added TestableOutcome class: [#266](https://github.com/personalrobotics/aikido/pull/266)

* Perception

Expand Down
7 changes: 6 additions & 1 deletion include/aikido/constraint/CartesianProductTestable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ class CartesianProductTestable : public Testable
statespace::StateSpacePtr getStateSpace() const override;

bool isSatisfied(
const aikido::statespace::StateSpace::State* _state) const override;
const aikido::statespace::StateSpace::State* _state,
TestableOutcome* outcome = nullptr) const override;

/// Return an instance of DefaultTestableOutcome, since this class doesn't
/// have a more specialized TestableOutcome derivative assigned to it.
std::unique_ptr<TestableOutcome> createOutcome() const override;

private:
std::shared_ptr<statespace::CartesianProduct> mStateSpace;
Expand Down
13 changes: 11 additions & 2 deletions include/aikido/constraint/CollisionFree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <dart/collision/CollisionGroup.hpp>
#include <dart/collision/CollisionOption.hpp>
#include "../statespace/dart/MetaSkeletonStateSpace.hpp"
#include "CollisionFreeOutcome.hpp"
#include "Testable.hpp"

namespace aikido {
Expand Down Expand Up @@ -39,9 +40,17 @@ class CollisionFree : public Testable
// Documentation inherited.
statespace::StateSpacePtr getStateSpace() const override;

// Documentation inherited.
/// \copydoc Testable::isSatisfied()
/// \note Outcome is expected to be an instance of CollisionFreeOutcome.
/// This method will cast outcome to a pointer of this type, and then populate
/// the collision information (which bodies are in self/pairwise collision).
bool isSatisfied(
const aikido::statespace::StateSpace::State* _state) const override;
const aikido::statespace::StateSpace::State* _state,
TestableOutcome* outcome = nullptr) const override;

/// \copydoc Testable::createOutcome()
/// \note Returns an instance of CollisionFreeOutcome.
std::unique_ptr<TestableOutcome> createOutcome() const override;

/// Checks collision between group1 and group2.
/// \param group1 First collision group.
Expand Down
61 changes: 61 additions & 0 deletions include/aikido/constraint/CollisionFreeOutcome.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#ifndef AIKIDO_CONSTRAINT_COLLISIONFREEOUTCOME_HPP_
#define AIKIDO_CONSTRAINT_COLLISIONFREEOUTCOME_HPP_

#include <vector>
#include "TestableOutcome.hpp"
#include "dart/collision/CollisionObject.hpp"
#include "dart/collision/Contact.hpp"
#include "dart/dynamics/BodyNode.hpp"
#include "dart/dynamics/ShapeFrame.hpp"
#include "dart/dynamics/ShapeNode.hpp"

namespace aikido {
namespace constraint {

/// TestableOutcome derivative class intended as (optional) input to isSatisfied
/// method in CollisionFree class.
class CollisionFreeOutcome : public TestableOutcome
{
friend class CollisionFree;

public:
/// Documentation inherited.
bool isSatisfied() const override;

/// Returns a string with each pair of CollisionObject names on a separate
/// line. Each pair is also marked as being a normal collision or self
/// collision.
std::string toString() const override;

/// Clears this outcome object. Useful in the event that a CollisionFree
/// object is passed to the isSatisfied() method of more than one constraint
/// object.
Copy link
Member

Choose a reason for hiding this comment

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

Very tiny nitpick: It's also useful if an instance is passed to isSatisfied() multiple times on the same constraint object. 🙃 This is actually the more common case in a planner.

void clear();

/// Return a copy of the vector storing the Contact objects from pairwise
/// collisions.
std::vector<dart::collision::Contact> getPairwiseContacts() const;

/// Return a copy of the vector storing the Contact objects from self
/// collisions.
std::vector<dart::collision::Contact> getSelfContacts() const;

/// Gets the name of a CollisionObject. The name returned is that of the
/// corresponding BodyNode (if possible). If not, the name of the ShapeFrame
/// is returned instead. This is a helper for toString().
/// \param[in] object object pointer to CollisionObject we want the name of.
std::string getCollisionObjectName(
const dart::collision::CollisionObject* object) const;

protected:
/// Holds Contact objects from pairwise collisions.
std::vector<dart::collision::Contact> mPairwiseContacts;
Copy link
Member

Choose a reason for hiding this comment

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

dart::collision::Contact contains fixed-size vectorizable types, so this std::vector must use an Eigen::aligned_allocator to avoid SSE alignment issues.

Copy link
Member

Choose a reason for hiding this comment

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

@mkoval dart::collision::Contact actually contains no types listed in the link; Eigen::Vector3d is not applicapable.

Sorry, I should have replied this before @sniyaz make the changes. 😭

Copy link
Member

Choose a reason for hiding this comment

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

You're right! 😱 I always forget that Vector3d is not a vectorizable because it contains an odd number of bytes. Sorry creating extra work. 😰


/// Holds Contact objects from self collisions.
std::vector<dart::collision::Contact> mSelfContacts;
Copy link
Member

Choose a reason for hiding this comment

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

This should us an Eigen::aligned_allocator. See my comment on mPairwiseContacts.

};

} // namespace constraint
} // namespace aikido

#endif // AIKIDO_CONSTRAINT_COLLISIONFREEOUTCOME_HPP_
35 changes: 35 additions & 0 deletions include/aikido/constraint/DefaultTestableOutcome.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef AIKIDO_CONSTRAINT_DEFAULTTESTABLEOUTCOME_HPP_
#define AIKIDO_CONSTRAINT_DEFAULTTESTABLEOUTCOME_HPP_

#include "TestableOutcome.hpp"

namespace aikido {
namespace constraint {

/// Simple default TestableOutcome derivative class. An instance of this class
/// is returned when createOutcome() is called on an instance of a class that
/// inherits Testable, but has no corresponding TestableOutcome derivative
/// implemented.
class DefaultTestableOutcome : public TestableOutcome
{
public:
/// Returns whether the isSatisfied method this object was passed to
/// returned true or false.
bool isSatisfied() const override;

/// String representation of isSatisfied return value.
std::string toString() const override;

/// Used by the isSatisfied this outcome object is passed to set whether the
/// constraint was satisifed or not.
/// \param[in] satisfiedFlag whether the constraint was satisfied or not.
void setSatisfiedFlag(bool satisfiedFlag);

protected:
bool mSatisfiedFlag;
};

} // namespace constraint
} // namespace aikido

#endif // AIKIDO_CONSTRAINT_DEFAULTTESTABLEOUTCOME_HPP_
12 changes: 11 additions & 1 deletion include/aikido/constraint/FrameTestable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,17 @@ class FrameTestable : public Testable
/// \param _state a MetaskeletonState to set the configuration of this
/// constraint's metaskeketon. This state's StateSpace should match
/// StateSpace returend by getStateSpace().
Copy link
Member

Choose a reason for hiding this comment

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

Document the TestableOutcome argument. I suggest making it simply return whatever TestableOutcome is returned by the _poseConstraint passed to this class' constructor.

bool isSatisfied(const statespace::StateSpace::State* _state) const override;
/// \param outcome Testable outcome derivative class. Passed to the
/// isSatisfied method of mPoseConstraint to allow "pass through" of
/// debugging information.
bool isSatisfied(
const statespace::StateSpace::State* _state,
TestableOutcome* outcome = nullptr) const override;

/// Return the outcome of mPoseConstraint->createOutcome(). Reason:
/// isSatisfied in this class will just pass outcome to the isSatisfied
/// method of of mPoseConstraint.
std::unique_ptr<TestableOutcome> createOutcome() const override;

// Documentation inhereted
std::shared_ptr<statespace::StateSpace> getStateSpace() const override;
Expand Down
8 changes: 7 additions & 1 deletion include/aikido/constraint/Satisfied.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ class Satisfied : public constraint::Differentiable,
/// Returns \c true.
///
/// \param state a state in \c getStateSpace()
bool isSatisfied(const statespace::StateSpace::State* state) const override;
bool isSatisfied(
const statespace::StateSpace::State* state,
TestableOutcome* outcome = nullptr) const override;

/// Return an instance of DefaultTestableOutcome, since this class doesn't
/// have a more specialized TestableOutcome derivative assigned to it.
std::unique_ptr<TestableOutcome> createOutcome() const override;

/// Sets \c _out to \c _s.
///
Expand Down
8 changes: 7 additions & 1 deletion include/aikido/constraint/TSR.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,13 @@ class TSR : public Sampleable,
std::unique_ptr<SampleGenerator> createSampleGenerator() const override;

// Documentation inherited.
bool isSatisfied(const statespace::StateSpace::State* _s) const override;
bool isSatisfied(
const statespace::StateSpace::State* _s,
TestableOutcome* outcome = nullptr) const override;

/// Return an instance of DefaultTestableOutcome, since this class doesn't
/// have a more specialized TestableOutcome derivative assigned to it.
std::unique_ptr<TestableOutcome> createOutcome() const override;

/// Throws an invalid_argument exception if this TSR is invalid.
/// For a TSR to be valid, mBw(i, 0) <= mBw(i, 1).
Expand Down
19 changes: 17 additions & 2 deletions include/aikido/constraint/Testable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,42 @@

#include <memory>
#include "../statespace/StateSpace.hpp"
#include "DefaultTestableOutcome.hpp"

namespace aikido {
namespace constraint {

class TestableOutcome;

/// Constraint which can be tested.
class Testable
{
public:
virtual ~Testable() = default;

/// Returns true if state satisfies this constraint.
Copy link
Member

Choose a reason for hiding this comment

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

Document the TestableOutcome parameter. Most importantly: (1) what type it must be and (2) what happens if it is not specified. 😉

/// \param[in] _state given state to test.
/// \param[in] outcome pointer to TestableOutcome derivative instance that
/// method will populate with useful information. Each derivative class of
/// Testable may expect outcome to be a different derivative class of
/// TestableOutcome (this casting and population is done under the hood). If
/// this argument is missing, it is ignored.
virtual bool isSatisfied(
const statespace::StateSpace::State* _state) const = 0;
const statespace::StateSpace::State* _state,
TestableOutcome* outcome = nullptr) const = 0;

/// Returns StateSpace in which this constraint operates.
virtual statespace::StateSpacePtr getStateSpace() const = 0;

/// Return an instance of a TestableOutcome derivative class that corresponds
/// to this constraint class. Ensures that correct outcome object is passed
/// to isSatisfied (and casts, etc do not explode).
virtual std::unique_ptr<TestableOutcome> createOutcome() const = 0;
};

using TestablePtr = std::shared_ptr<Testable>;

} // namespace constraint
} // namespace aikido

#endif // AIKIDO_CONSTRAINT_TESTABLE_HPP_
#endif // AIKIDO_CONSTRAINT_TESTABLE_HPP_
7 changes: 6 additions & 1 deletion include/aikido/constraint/TestableIntersection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ class TestableIntersection : public Testable

// Documentation inherited.
bool isSatisfied(
const aikido::statespace::StateSpace::State* state) const override;
const aikido::statespace::StateSpace::State* state,
TestableOutcome* outcome = nullptr) const override;

/// Return an instance of DefaultTestableOutcome, since this class doesn't
/// have a more specialized TestableOutcome derivative assigned to it.
std::unique_ptr<TestableOutcome> createOutcome() const override;

// Documentation inherited.
statespace::StateSpacePtr getStateSpace() const override;
Expand Down
36 changes: 36 additions & 0 deletions include/aikido/constraint/TestableOutcome.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef AIKIDO_CONSTRAINT_TESTABLEOUTCOME_HPP_
#define AIKIDO_CONSTRAINT_TESTABLEOUTCOME_HPP_

#include <string>

namespace aikido {
namespace constraint {

/// Base class for constraint outcomes. At a high level, each constraint can
/// have a corresponding derivative of TestableOutcome that is passed as an
/// optional parameter to its isSatisfied method. This allow programmatic access
/// to data on why the constraint was (or was not) satisfied.
class TestableOutcome
{
public:
/// Returns true if isSatisfied call this outcome object was passed to
/// returned true. False otherwise.
virtual bool isSatisfied() const = 0;

/// String representation of the outcome. Provides useful, programmatic
/// access to debug information.
virtual std::string toString() const = 0;
};

/// Helper function. Avoids repeating logic for casting TestableOutcome
/// pointers down to pointers for a derivative class. Mostly used in the
/// isSatisfied methods of classes that inherit Testable.
template <class Child>
Child* dynamic_cast_or_throw(TestableOutcome* outcome);

} // namespace constraint
} // namespace aikido

#include "detail/TestableOutcome-impl.hpp"

#endif // AIKIDO_CONSTRAINT_TESTABLEOUTCOME_HPP_
28 changes: 28 additions & 0 deletions include/aikido/constraint/detail/TestableOutcome-impl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <sstream>
#include <stdexcept>
#include <typeinfo>

namespace aikido {
namespace constraint {

//==============================================================================
template <class Child>
Child* dynamic_cast_or_throw(TestableOutcome* outcome)
{
if (!outcome)
return nullptr;

auto childPtr = dynamic_cast<Child*>(outcome);
if (!childPtr)
{
std::stringstream message;
message << "TestableOutcome pointer is not of type " << typeid(Child).name()
<< ".";
throw std::invalid_argument(message.str());
}

return childPtr;
}

} // namespace constraint
} // namespace aikido
8 changes: 7 additions & 1 deletion include/aikido/constraint/uniform/RnBoxConstraint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ class RBoxConstraint : public constraint::Differentiable,
std::vector<constraint::ConstraintType> getConstraintTypes() const override;

// Documentation inherited.
bool isSatisfied(const statespace::StateSpace::State* state) const override;
bool isSatisfied(
const statespace::StateSpace::State* state,
TestableOutcome* outcome = nullptr) const override;

/// Return an instance of DefaultTestableOutcome, since this class doesn't
/// have a more specialized TestableOutcome derivative assigned to it.
std::unique_ptr<TestableOutcome> createOutcome() const override;

// Documentation inherited.
bool project(
Expand Down
10 changes: 8 additions & 2 deletions include/aikido/constraint/uniform/SE2BoxConstraint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,14 @@ class SE2BoxConstraint : public constraint::Projectable,
// Documentation inherited.
statespace::StateSpacePtr getStateSpace() const override;

// Documentation inherited.
bool isSatisfied(const statespace::StateSpace::State* state) const override;
/// Documentation inherited.
bool isSatisfied(
const statespace::StateSpace::State* state,
TestableOutcome* outcome = nullptr) const override;

/// Return an instance of DefaultTestableOutcome, since this class doesn't
/// have a more specialized TestableOutcome derivative assigned to it.
std::unique_ptr<TestableOutcome> createOutcome() const override;

// Documentation inherited.
bool project(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,19 +175,36 @@ std::vector<ConstraintType> RBoxConstraint<N>::getConstraintTypes() const
//==============================================================================
template <int N>
bool RBoxConstraint<N>::isSatisfied(
const statespace::StateSpace::State* state) const
const statespace::StateSpace::State* state, TestableOutcome* outcome) const
{
auto defaultOutcomeObject
= dynamic_cast_or_throw<DefaultTestableOutcome>(outcome);

const auto value = mSpace->getValue(
static_cast<const typename statespace::R<N>::State*>(state));

for (auto i = 0; i < value.size(); ++i)
{
if (value[i] < mLowerLimits[i] || value[i] > mUpperLimits[i])
{
if (defaultOutcomeObject)
defaultOutcomeObject->setSatisfiedFlag(false);
return false;
}
}

if (defaultOutcomeObject)
defaultOutcomeObject->setSatisfiedFlag(true);
return true;
}

//==============================================================================
template <int N>
std::unique_ptr<TestableOutcome> RBoxConstraint<N>::createOutcome() const
{
return std::unique_ptr<TestableOutcome>(new DefaultTestableOutcome);
}

//==============================================================================
template <int N>
bool RBoxConstraint<N>::project(
Expand Down
Loading