Source code for brom_drake.motion_planning.algorithms.motion_planner

"""
motion_planner.py
Description:

        This file defines the MotionPlanner class.
        This class is used to plan motion for a robot.
"""
import numpy as np
from pydrake.geometry import SceneGraph
from pydrake.multibody.plant import MultibodyPlant
from pydrake.multibody.tree import ModelInstanceIndex


[docs] class MotionPlanner: def __init__( self, robot_model_idx: ModelInstanceIndex, plant: MultibodyPlant, scene_graph: SceneGraph, random_seed: int = 23, ): """ Description: This function initializes the motion planner. """ # Input Processing self.robot_model_idx = robot_model_idx self.plant = plant self.scene_graph = scene_graph # Setup self.root_context = None # Usually, the diagram context that we can use to extract the plant's context # Set the random seed self.random_seed = random_seed np.random.seed(self.random_seed) @property def dim_q(self) -> int: if not self.plant.is_finalized(): raise ValueError("Plant has not been finalized yet! Can not compute num_actuated_dofs().") return self.plant.num_actuated_dofs(self.robot_model_idx)
[docs] def check_collision_in_config( self, q_model: np.ndarray, ) -> bool: """ Description: This function checks for collisions in the robot's environment. """ # Input Processing if self.root_context is None: raise ValueError("Plant context is not initialized yet!") # Setup plant_context = self.plant.GetMyMutableContextFromRoot(self.root_context) scene_graph_context = self.scene_graph.GetMyMutableContextFromRoot(self.root_context) # Set the configuration self.plant.SetPositions( plant_context, self.robot_model_idx, q_model ) # Note: This method will be inaccurate if using arbitrary, nonconvex meshes! # https://drake.mit.edu/pydrake/pydrake.geometry.html?highlight=queryobject#pydrake.geometry.QueryObject.HasCollisions query_object = self.scene_graph.get_query_output_port().Eval(scene_graph_context) # return query_object.HasCollisions() # Alternative method to check for collisions closest_points = query_object.ComputeSignedDistancePairwiseClosestPoints() eps0 = 1e-2 for pair in closest_points: if pair.distance < eps0: return True # Otherwise return false return False
@property def joint_limits(self) -> np.ndarray: """ Description: This function retrieves the joint limits of the robot. """ # Setup joint_indicies = self.plant.GetJointIndices(self.robot_model_idx) joint_limits = np.zeros((0, 2)) for ii, joint_index in enumerate(joint_indicies): # Check to see if joint is actuated; if not, then ignore joint_ii = self.plant.get_joint(joint_index) joint_can_move = joint_ii.can_rotate() or joint_ii.can_translate() if not joint_can_move: continue lower_limits = self.plant.get_joint(joint_index).position_lower_limits() if len(lower_limits) == 0: lower_limits = [-np.inf] upper_limits = self.plant.get_joint(joint_index).position_upper_limits() if len(upper_limits) == 0: upper_limits = [np.inf] # Append limits to the joint_limits array joint_limits = np.vstack(( joint_limits, [lower_limits[0], upper_limits[0]] )) return joint_limits
[docs] def sample_random_configuration(self) -> np.ndarray: """ Description ----------- This function samples a random configuration within the joint limits. """ return np.random.uniform( self.joint_limits[:, 0], self.joint_limits[:, 1] )