Skip to content

[WIP] Move Relative with Pilz does not reject trajectory with collision #538

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion core/test/move_relative.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<launch>
<include file="$(find moveit_resources_panda_moveit_config)/launch/planning_context.launch">
<include file="$(find moveit_resources_panda_moveit_config)/launch/move_group.launch">
<arg name="load_robot_description" value="true"/>
</include>

Expand Down
100 changes: 82 additions & 18 deletions core/test/test_move_relative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <moveit/task_constructor/stages/move_relative.h>
#include <moveit/task_constructor/stages/fixed_state.h>
#include <moveit/task_constructor/solvers/cartesian_path.h>
#include <moveit/task_constructor/solvers/pipeline_planner.h>

#include <moveit/planning_scene/planning_scene.h>
#include <moveit/robot_trajectory/robot_trajectory.h>
Expand All @@ -13,23 +14,44 @@

#include <gtest/gtest.h>

#ifndef TYPED_TEST_SUITE // for Melodic
#define TYPED_TEST_SUITE(SUITE, TYPES) TYPED_TEST_CASE(SUITE, TYPES)
#endif

using namespace moveit::task_constructor;
using namespace planning_scene;
using namespace moveit::core;

constexpr double TAU{ 2 * M_PI };
constexpr double EPS{ 5e-5 };

template <typename Planner>
std::shared_ptr<Planner> create();
template <>
solvers::CartesianPathPtr create<solvers::CartesianPath>() {
return std::make_shared<solvers::CartesianPath>();
}
template <>
solvers::PipelinePlannerPtr create<solvers::PipelinePlanner>() {
auto p = std::make_shared<solvers::PipelinePlanner>("pilz_industrial_motion_planner");
p->setPlannerId("LIN");
p->setProperty("max_velocity_scaling_factor", 0.1);
p->setProperty("max_acceleration_scaling_factor", 0.1);
return p;
}

// provide a basic test fixture that prepares a Task
template <typename Planner = solvers::CartesianPath>
struct PandaMoveRelative : public testing::Test
{
Task t;
stages::MoveRelative* move;
PlanningScenePtr scene;
std::shared_ptr<Planner> planner;

const JointModelGroup* group;

PandaMoveRelative() {
PandaMoveRelative() : planner(create<Planner>()) {
t.setRobotModel(loadModel());

group = t.getRobotModel()->getJointModelGroup("panda_arm");
Expand All @@ -39,31 +61,44 @@ struct PandaMoveRelative : public testing::Test
scene->getCurrentStateNonConst().setToDefaultValues(t.getRobotModel()->getJointModelGroup("panda_arm"), "ready");
t.add(std::make_unique<stages::FixedState>("start", scene));

auto move_relative = std::make_unique<stages::MoveRelative>("move", std::make_shared<solvers::CartesianPath>());
auto move_relative = std::make_unique<stages::MoveRelative>("move", planner);
move_relative->setGroup(group->getName());
move = move_relative.get();
t.add(std::move(move_relative));
}
};

moveit_msgs::AttachedCollisionObject createAttachedObject(const std::string& id) {
moveit_msgs::AttachedCollisionObject aco;
aco.link_name = "panda_hand";
aco.object.header.frame_id = aco.link_name;
aco.object.operation = aco.object.ADD;
aco.object.id = id;
aco.object.primitives.resize(1, [] {
using PandaMoveRelativeCartesian = PandaMoveRelative<solvers::CartesianPath>;

moveit_msgs::CollisionObject createObject(const std::string& id, const geometry_msgs::Pose& pose) {
moveit_msgs::CollisionObject co;
co.header.frame_id = "panda_hand";
co.operation = co.ADD;
co.id = id;
co.primitives.resize(1, [] {
shape_msgs::SolidPrimitive p;
p.type = p.SPHERE;
p.dimensions.resize(1);
p.dimensions[p.SPHERE_RADIUS] = 0.01;
return p;
}());

co.pose = pose;
return co;
}

moveit_msgs::CollisionObject createObject(const std::string& id) {
geometry_msgs::Pose p;
p.position.x = 0.1;
p.orientation.w = 1.0;
aco.object.pose = p;

return createObject(id, p);
}

moveit_msgs::AttachedCollisionObject createAttachedObject(const std::string& id) {
moveit_msgs::AttachedCollisionObject aco;
aco.link_name = "panda_hand";
aco.object = createObject(id);

return aco;
}

Expand All @@ -79,13 +114,13 @@ void expect_const_position(const SolutionBaseConstPtr& solution, const std::stri
}
}

#define EXPECT_CONST_POSITION(...) \
{ \
SCOPED_TRACE("expect_constant_position(" #__VA_ARGS__ ")"); \
expect_const_position(__VA_ARGS__); \
#define EXPECT_CONST_POSITION(...) \
{ \
SCOPED_TRACE("expect_const_position(" #__VA_ARGS__ ")"); \
expect_const_position(__VA_ARGS__); \
}

TEST_F(PandaMoveRelative, cartesianRotateEEF) {
TEST_F(PandaMoveRelativeCartesian, cartesianRotateEEF) {
move->setDirection([] {
geometry_msgs::TwistStamped twist;
twist.header.frame_id = "world";
Expand All @@ -97,7 +132,7 @@ TEST_F(PandaMoveRelative, cartesianRotateEEF) {
EXPECT_CONST_POSITION(move->solutions().front(), group->getOnlyOneEndEffectorTip()->getName());
}

TEST_F(PandaMoveRelative, cartesianCircular) {
TEST_F(PandaMoveRelativeCartesian, cartesianCircular) {
const std::string tip = "panda_hand";
auto offset = Eigen::Translation3d(0, 0, 0.1);
move->setIKFrame(offset, tip);
Expand All @@ -112,7 +147,7 @@ TEST_F(PandaMoveRelative, cartesianCircular) {
EXPECT_CONST_POSITION(move->solutions().front(), tip, Eigen::Isometry3d(offset));
}

TEST_F(PandaMoveRelative, cartesianRotateAttachedIKFrame) {
TEST_F(PandaMoveRelativeCartesian, cartesianRotateAttachedIKFrame) {
const std::string attached_object{ "attached_object" };
scene->processAttachedCollisionObjectMsg(createAttachedObject(attached_object));
move->setIKFrame(attached_object);
Expand All @@ -128,6 +163,35 @@ TEST_F(PandaMoveRelative, cartesianRotateAttachedIKFrame) {
EXPECT_CONST_POSITION(move->solutions().front(), attached_object);
}

using PlannerTypes = ::testing::Types<solvers::CartesianPath, solvers::PipelinePlanner>;
TYPED_TEST_SUITE(PandaMoveRelative, PlannerTypes);
TYPED_TEST(PandaMoveRelative, cartesianCollisionMinMaxDistance) {
if (std::is_same<TypeParam, solvers::PipelinePlanner>::value)
GTEST_SKIP(); // Pilz PipelinePlanner current fails this test (see #538)

const std::string object{ "object" };
geometry_msgs::Pose object_pose;
object_pose.position.z = 0.4;
object_pose.orientation.w = 1.0;

this->scene->processCollisionObjectMsg(createObject(object, object_pose));

this->move->setIKFrame("panda_hand");
geometry_msgs::Vector3Stamped v;
v.header.frame_id = "panda_hand";
v.vector.z = 0.5;
this->move->setDirection(v);
EXPECT_FALSE(this->t.plan()) << "Plan should fail due to collision";

this->t.reset();
v.vector.z = 1.0;
this->move->setDirection(v);
this->move->setMinMaxDistance(0.1, 0.5);
EXPECT_TRUE(this->t.plan()) << "Plan should succeed due to min distance reached";
auto trajectory = std::dynamic_pointer_cast<const SubTrajectory>(this->move->solutions().front());
EXPECT_TRUE(this->scene->isPathValid(*trajectory->trajectory(), "panda_arm", false));
}

int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
ros::init(argc, argv, "move_relative_test");
Expand Down
Loading