Skip to content

Commit 154e32b

Browse files
kamiradisea-bass
andauthored
Adds orientation constraints (#55)
* tweaks constrained planning tut to have only box and orientation constraints * [FT] adds orientation constraints * Add docstring based on latest code cleanup * Fix build errors * Working inequality and equality constraints position and orientation --------- Co-authored-by: Sebastian Castro <[email protected]> Co-authored-by: Sebastian Castro <[email protected]>
1 parent 4abd38f commit 154e32b

File tree

3 files changed

+155
-54
lines changed

3 files changed

+155
-54
lines changed

Diff for: include/ktopt_interface/ktopt_planning_context.hpp

+12-4
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,13 @@
1111
#include <drake/planning/trajectory_optimization/kinematic_trajectory_optimization.h>
1212
#include <drake/systems/framework/diagram.h>
1313
#include <drake/systems/framework/diagram_builder.h>
14-
#include <drake/multibody/inverse_kinematics/minimum_distance_lower_bound_constraint.h>
15-
#include <drake/multibody/inverse_kinematics/position_constraint.h>
1614
#include <drake/multibody/parsing/parser.h>
1715
#include <drake/multibody/plant/multibody_plant.h>
1816

1917
namespace ktopt_interface
2018
{
2119
// declare all namespaces to be used
22-
using drake::multibody::MinimumDistanceLowerBoundConstraint;
2320
using drake::multibody::MultibodyPlant;
24-
using drake::multibody::PositionConstraint;
2521
using drake::planning::trajectory_optimization::KinematicTrajectoryOptimization;
2622
using drake::systems::Context;
2723
using drake::systems::Diagram;
@@ -91,6 +87,18 @@ class KTOptPlanningContext : public planning_interface::PlanningContext
9187
void addPathPositionConstraints(KinematicTrajectoryOptimization& trajopt, const MultibodyPlant<double>& plant,
9288
Context<double>& plant_context, const double padding);
9389

90+
/**
91+
* @brief Adds path orientation constraints, if any, to the planning problem.
92+
* @param trajopt The Drake object containing the trajectory optimization problem.
93+
* @param plant The Drake multibody plant to use for planning.
94+
* @param plant_context The context associated with the multibody plant.
95+
* @param padding Additional orientation padding on the MoveIt constraint, in radians.
96+
* This ensures that constraints are more likely to hold for the entire trajectory, since the
97+
* Drake mathematical program only optimizes constraints at discrete points along the path.
98+
*/
99+
void addPathOrientationConstraints(KinematicTrajectoryOptimization& trajopt, const MultibodyPlant<double>& plant,
100+
Context<double>& plant_context, const double padding);
101+
94102
private:
95103
/// @brief The ROS parameters associated with this motion planner.
96104
const ktopt_interface::Params params_;

Diff for: parameters/ktopt_moveit_parameters.yaml

+9-1
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,22 @@ ktopt_interface:
7676
gt_eq<>: [0.0]
7777
}
7878
}
79-
num_position_constraint_points: {
79+
num_position_inequality_points: {
8080
type: int,
8181
description: "Number of points on the path where MoveIt's bounding box constraint needs to be imposed.",
8282
default_value: 10,
8383
validation: {
8484
gt_eq<>: [2]
8585
}
8686
}
87+
num_position_equality_points: {
88+
type: int,
89+
description: "Number of points on the path where MoveIt's equality position constraint needs to be imposed.",
90+
default_value: 25,
91+
validation: {
92+
gt_eq<>: [2]
93+
}
94+
}
8795
position_constraint_padding: {
8896
type: double,
8997
description: "Padding distance for position constraints, in meters, to make sure optimizing at sampled points still globally meets constraints.",

Diff for: src/ktopt_planning_context.cpp

+134-49
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
#include <drake/geometry/geometry_instance.h>
66
#include <drake/geometry/geometry_roles.h>
77
#include <drake/geometry/proximity_properties.h>
8+
#include <drake/multibody/inverse_kinematics/minimum_distance_lower_bound_constraint.h>
9+
#include <drake/multibody/inverse_kinematics/orientation_constraint.h>
10+
#include <drake/multibody/inverse_kinematics/position_constraint.h>
11+
#include <drake/math/rigid_transform.h>
12+
#include <drake/math/rotation_matrix.h>
813
#include <drake/solvers/solve.h>
914
#include <drake/visualization/visualization_config.h>
1015
#include <drake/visualization/visualization_config_functions.h>
@@ -78,7 +83,7 @@ void KTOptPlanningContext::solve(planning_interface::MotionPlanResponse& res)
7883
moveit::drake::getJerkBounds(joint_model_group, plant, lower_jerk_bounds, upper_jerk_bounds);
7984

8085
// q represents the complete state (joint positions and velocities)
81-
auto q = Eigen::VectorXd::Zero(plant.num_positions() + plant.num_velocities());
86+
Eigen::VectorXd q = Eigen::VectorXd::Zero(plant.num_positions() + plant.num_velocities());
8287
q << moveit::drake::getJointPositionVector(start_state, getGroupName(), plant);
8388
q << moveit::drake::getJointVelocityVector(start_state, getGroupName(), plant);
8489

@@ -137,6 +142,7 @@ void KTOptPlanningContext::solve(planning_interface::MotionPlanResponse& res)
137142

138143
// process path_constraints
139144
addPathPositionConstraints(trajopt, plant, plant_context, params_.position_constraint_padding);
145+
addPathOrientationConstraints(trajopt, plant, plant_context, params_.orientation_constraint_padding);
140146

141147
// solve the program
142148
auto result = drake::solvers::Solve(prog);
@@ -155,7 +161,7 @@ void KTOptPlanningContext::solve(planning_interface::MotionPlanResponse& res)
155161
// add collision constraints
156162
for (int s = 0; s < params_.num_collision_check_points; ++s)
157163
{
158-
trajopt.AddPathPositionConstraint(std::make_shared<MinimumDistanceLowerBoundConstraint>(
164+
trajopt.AddPathPositionConstraint(std::make_shared<drake::multibody::MinimumDistanceLowerBoundConstraint>(
159165
&plant, params_.collision_check_lower_distance_bound, &plant_context),
160166
static_cast<double>(s) / (params_.num_collision_check_points - 1));
161167
}
@@ -204,66 +210,145 @@ void KTOptPlanningContext::addPathPositionConstraints(KinematicTrajectoryOptimiz
204210
const auto& req = getMotionPlanRequest();
205211

206212
// check for path position constraints
207-
if (!req.path_constraints.position_constraints.empty())
213+
for (const auto& position_constraint : req.path_constraints.position_constraints)
208214
{
209-
for (const auto& position_constraint : req.path_constraints.position_constraints)
215+
// Extract the bounding box's center (primitive pose)
216+
const auto& primitive_pose = position_constraint.constraint_region.primitive_poses[0];
217+
Eigen::Vector3d box_center(primitive_pose.position.x, primitive_pose.position.y, primitive_pose.position.z);
218+
Eigen::Quaterniond box_orientation(primitive_pose.orientation.w, primitive_pose.orientation.x,
219+
primitive_pose.orientation.y, primitive_pose.orientation.z);
220+
drake::math::RigidTransformd X_AbarA(box_orientation, box_center);
221+
222+
// Extract dimensions of the bounding box from
223+
// constraint_region.primitives Assuming it is a box
224+
// (shape_msgs::SolidPrimitive::BOX) and has dimensions in [x, y, z]
225+
const auto link_ee_name = position_constraint.link_name;
226+
if (!plant.HasBodyNamed(link_ee_name))
210227
{
211-
// Extract the bounding box's center (primitive pose)
212-
const auto& primitive_pose = position_constraint.constraint_region.primitive_poses[0];
213-
Eigen::Vector3d box_center(primitive_pose.position.x, primitive_pose.position.y, primitive_pose.position.z);
214-
215-
// Extract dimensions of the bounding box from
216-
// constraint_region.primitives Assuming it is a box
217-
// (shape_msgs::SolidPrimitive::BOX) and has dimensions in [x, y, z]
218-
const auto link_ee_name = position_constraint.link_name;
219-
if (!plant.HasBodyNamed(link_ee_name))
220-
{
221-
RCLCPP_ERROR(getLogger(),
222-
"The link specified in the PositionConstraint message, %s, does not exist in the Drake "
223-
"plant.",
224-
link_ee_name.c_str());
225-
continue;
226-
}
227-
const auto& link_ee_frame = plant.GetFrameByName(link_ee_name);
228+
RCLCPP_ERROR(getLogger(),
229+
"The link specified in the PositionConstraint message, %s, does not exist in the Drake "
230+
"plant.",
231+
link_ee_name.c_str());
232+
continue;
233+
}
234+
// frameB
235+
const auto& link_ee_frame = plant.GetFrameByName(link_ee_name);
228236

229-
const auto base_frame_name = position_constraint.header.frame_id;
230-
if (!plant.HasBodyNamed(base_frame_name))
231-
{
232-
RCLCPP_ERROR(getLogger(),
233-
"The link specified in the PositionConstraint message, %s, does not exist in the Drake "
234-
"plant.",
235-
base_frame_name.c_str());
236-
continue;
237-
}
238-
const auto& base_frame = plant.GetFrameByName(base_frame_name);
237+
const auto base_frame_name = position_constraint.header.frame_id;
238+
if (!plant.HasBodyNamed(base_frame_name))
239+
{
240+
RCLCPP_ERROR(getLogger(),
241+
"The link specified in the PositionConstraint message, %s, does not exist in the Drake "
242+
"plant.",
243+
base_frame_name.c_str());
244+
continue;
245+
}
246+
// frameA
247+
const auto& base_frame = plant.GetFrameByName(base_frame_name);
239248

240-
const auto& primitive = position_constraint.constraint_region.primitives[0];
241-
if (primitive.type != shape_msgs::msg::SolidPrimitive::BOX)
242-
{
243-
RCLCPP_WARN(getLogger(), "Expects a bounding box constraint as a SolidPrimitive::BOX");
244-
continue;
245-
}
249+
const auto& primitive = position_constraint.constraint_region.primitives[0];
250+
if (primitive.type != shape_msgs::msg::SolidPrimitive::BOX)
251+
{
252+
RCLCPP_WARN(getLogger(), "Expects a bounding box constraint as a SolidPrimitive::BOX");
253+
continue;
254+
}
246255

247-
// Calculate the lower and upper bounds based on the box dimensions
248-
// around the center
249-
const auto offset_vec = Eigen::Vector3d(std::max(0.0, primitive.dimensions[0] / 2.0 - padding),
250-
std::max(0.0, primitive.dimensions[1] / 2.0 - padding),
251-
std::max(0.0, primitive.dimensions[2] / 2.0 - padding));
252-
const auto lower_bound = box_center - offset_vec;
253-
const auto upper_bound = box_center + offset_vec;
256+
// Calculate the lower and upper bounds based on the box dimensions
257+
// around the center
258+
const auto offset_vec = Eigen::Vector3d(std::max(padding, primitive.dimensions[0] / 2.0 - padding),
259+
std::max(padding, primitive.dimensions[1] / 2.0 - padding),
260+
std::max(padding, primitive.dimensions[2] / 2.0 - padding));
254261

262+
// Check if equality constraint
263+
if (req.path_constraints.name == "use_equality_constraints")
264+
{
265+
// Add position constraint to each knot point of the trajectory
266+
for (int i = 0; i < params_.num_position_equality_points; ++i)
267+
{
268+
trajopt.AddPathPositionConstraint(std::make_shared<drake::multibody::PositionConstraint>(
269+
&plant, base_frame, X_AbarA, -offset_vec, offset_vec, link_ee_frame,
270+
Eigen::Vector3d(0.0, 0.0, 0.0), &plant_context),
271+
static_cast<double>(i) / (params_.num_position_equality_points - 1));
272+
}
273+
}
274+
else
275+
{
255276
// Add position constraint to each knot point of the trajectory
256-
for (int i = 0; i < params_.num_position_constraint_points; ++i)
277+
for (int i = 0; i < params_.num_position_inequality_points; ++i)
257278
{
258-
trajopt.AddPathPositionConstraint(
259-
std::make_shared<PositionConstraint>(&plant, base_frame, lower_bound, upper_bound, link_ee_frame,
260-
Eigen::Vector3d(0.0, 0.0, 0.0), &plant_context),
261-
static_cast<double>(i) / (params_.num_position_constraint_points - 1));
279+
trajopt.AddPathPositionConstraint(std::make_shared<drake::multibody::PositionConstraint>(
280+
&plant, base_frame, X_AbarA, -offset_vec, offset_vec, link_ee_frame,
281+
Eigen::Vector3d(0.0, 0.0, 0.0), &plant_context),
282+
static_cast<double>(i) / (params_.num_position_inequality_points - 1));
262283
}
263284
}
264285
}
265286
}
266287

288+
void KTOptPlanningContext::addPathOrientationConstraints(KinematicTrajectoryOptimization& trajopt,
289+
const MultibodyPlant<double>& plant,
290+
Context<double>& plant_context, const double padding)
291+
{
292+
// retrieve the motion planning request
293+
const auto& req = getMotionPlanRequest();
294+
295+
// check for path position constraints
296+
for (const auto& orientation_constraint : req.path_constraints.orientation_constraints)
297+
{
298+
// NOTE: Current thesis, when you apply a Drake Orientation Constraint it
299+
// expects the following
300+
// Frame A: The frame in which the orientation constraint is defined
301+
// Frame B: The frame to which the orientation constraint is enforced
302+
// theta_bound: The angle difference between frame A's orientation and
303+
// frame B's orientation
304+
305+
// Extract FrameA and FrameB for orientation constraint
306+
// frame B
307+
const auto link_ee_name = orientation_constraint.link_name;
308+
if (!plant.HasBodyNamed(link_ee_name))
309+
{
310+
RCLCPP_ERROR(getLogger(),
311+
"The link specified in the Orientation Constraint message, %s, does not exist in the Drake "
312+
"plant.",
313+
link_ee_name.c_str());
314+
continue;
315+
}
316+
const auto& link_ee_frame = plant.GetFrameByName(link_ee_name);
317+
318+
// frame A
319+
const auto base_frame_name = orientation_constraint.header.frame_id;
320+
if (!plant.HasBodyNamed(base_frame_name))
321+
{
322+
RCLCPP_ERROR(getLogger(),
323+
"The link specified in the Orientation Constraint message, %s, does not exist in the Drake "
324+
"plant.",
325+
base_frame_name.c_str());
326+
continue;
327+
}
328+
const auto& base_frame = plant.GetFrameByName(base_frame_name);
329+
330+
// Extract the orientation of that Frame B needs to be constrained to w.r.t Frame A
331+
const auto& constrained_orientation = orientation_constraint.orientation;
332+
// convert to drake's RotationMatrix
333+
const auto R_BbarB = drake::math::RotationMatrixd(Eigen::Quaterniond(
334+
constrained_orientation.w, constrained_orientation.x, constrained_orientation.y, constrained_orientation.z));
335+
336+
// NOTE: There are 3 tolerances given for the orientation constraint in moveit
337+
// message, Drake only takes in a single theta bound. For now, we take any
338+
// of the tolerances as the theta bound
339+
const double theta_bound = orientation_constraint.absolute_x_axis_tolerance - padding;
340+
341+
// Add orientation constraint to each knot point of the trajectory
342+
for (int i = 0; i < params_.num_orientation_constraint_points; ++i)
343+
{
344+
trajopt.AddPathPositionConstraint(std::make_shared<drake::multibody::OrientationConstraint>(
345+
&plant, link_ee_frame, drake::math::RotationMatrixd::Identity(), base_frame,
346+
R_BbarB, theta_bound, &plant_context),
347+
static_cast<double>(i) / (params_.num_orientation_constraint_points - 1));
348+
}
349+
}
350+
}
351+
267352
bool KTOptPlanningContext::terminate()
268353
{
269354
RCLCPP_ERROR(getLogger(), "KTOptPlanningContext::terminate() is not implemented!");

0 commit comments

Comments
 (0)