-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
596 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,4 +126,4 @@ def prepare_collision_scene(collision_model): | |
) | ||
|
||
viz.display(q) | ||
time.sleep(0.2) | ||
time.sleep(0.1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import hppfcl | ||
import pinocchio | ||
from pinocchio.visualize import MeshcatVisualizer | ||
import numpy as np | ||
from os.path import dirname, join, abspath | ||
import time | ||
|
||
from pyroboplan.core.utils import get_random_collision_free_state | ||
from pyroboplan.planning.rrt import RRTPlanner, RRTPlannerOptions | ||
from pyroboplan.planning.utils import discretize_joint_space_path | ||
|
||
|
||
def prepare_scene(visual_model, collision_model): | ||
"""Helper function to create a collision scene for this example.""" | ||
|
||
# Add collision objects | ||
obstacle_sphere_1 = pinocchio.GeometryObject( | ||
"obstacle_sphere_1", | ||
0, | ||
hppfcl.Sphere(0.2), | ||
pinocchio.SE3(np.eye(3), np.array([0.0, 0.1, 1.1])), | ||
) | ||
obstacle_sphere_1.meshColor = np.array([0.0, 1.0, 0.0, 0.5]) | ||
visual_model.addGeometryObject(obstacle_sphere_1) | ||
collision_model.addGeometryObject(obstacle_sphere_1) | ||
|
||
obstacle_sphere_2 = pinocchio.GeometryObject( | ||
"obstacle_sphere_2", | ||
0, | ||
hppfcl.Sphere(0.25), | ||
pinocchio.SE3(np.eye(3), np.array([0.5, 0.5, 0.5])), | ||
) | ||
obstacle_sphere_2.meshColor = np.array([1.0, 1.0, 0.0, 0.5]) | ||
visual_model.addGeometryObject(obstacle_sphere_2) | ||
collision_model.addGeometryObject(obstacle_sphere_2) | ||
|
||
obstacle_box_1 = pinocchio.GeometryObject( | ||
"obstacle_box_1", | ||
0, | ||
hppfcl.Box(0.25, 0.25, 0.25), | ||
pinocchio.SE3(np.eye(3), np.array([-0.5, 0.5, 0.7])), | ||
) | ||
obstacle_box_1.meshColor = np.array([1.0, 0.0, 0.0, 0.5]) | ||
visual_model.addGeometryObject(obstacle_box_1) | ||
collision_model.addGeometryObject(obstacle_box_1) | ||
|
||
obstacle_box_2 = pinocchio.GeometryObject( | ||
"obstacle_box_2", | ||
0, | ||
hppfcl.Box(0.33, 0.33, 0.33), | ||
pinocchio.SE3(np.eye(3), np.array([-0.5, -0.5, 0.75])), | ||
) | ||
obstacle_box_2.meshColor = np.array([0.0, 0.0, 1.0, 0.5]) | ||
visual_model.addGeometryObject(obstacle_box_2) | ||
collision_model.addGeometryObject(obstacle_box_2) | ||
|
||
|
||
if __name__ == "__main__": | ||
# Create models and data | ||
pinocchio_model_dir = join(dirname(str(abspath(__file__))), "..", "models") | ||
package_dir = join(pinocchio_model_dir, "panda_description") | ||
urdf_filename = join(package_dir, "urdf", "panda.urdf") | ||
|
||
model, collision_model, visual_model = pinocchio.buildModelsFromUrdf( | ||
urdf_filename, package_dirs=pinocchio_model_dir | ||
) | ||
data = model.createData() | ||
|
||
prepare_scene(visual_model, collision_model) | ||
|
||
# Initialize visualizer | ||
viz = MeshcatVisualizer(model, collision_model, visual_model, data=data) | ||
viz.initViewer(open=True) | ||
viz.loadViewerModel() | ||
|
||
# Define the active collision pairs | ||
collision_names = [ | ||
cobj.name for cobj in collision_model.geometryObjects if "panda" in cobj.name | ||
] | ||
obstacle_names = [ | ||
"obstacle_box_1", | ||
"obstacle_box_2", | ||
"obstacle_sphere_1", | ||
"obstacle_sphere_2", | ||
] | ||
for obstacle_name in obstacle_names: | ||
for collision_name in collision_names: | ||
collision_model.addCollisionPair( | ||
pinocchio.CollisionPair( | ||
collision_model.getGeometryId(collision_name), | ||
collision_model.getGeometryId(obstacle_name), | ||
) | ||
) | ||
collision_data = pinocchio.GeometryData(collision_model) | ||
|
||
# Define the start and end configurations | ||
q_start = get_random_collision_free_state(model, collision_model) | ||
q_end = get_random_collision_free_state(model, collision_model) | ||
viz.display(q_start) | ||
time.sleep(1.0) | ||
|
||
# Search for a path | ||
options = RRTPlannerOptions() | ||
options.max_angle_step = 0.05 | ||
options.max_connection_dist = 0.25 | ||
options.goal_biasing_probability = 0.15 | ||
|
||
planner = RRTPlanner(model, collision_model) | ||
path = planner.plan(q_start, q_end, options=options) | ||
planner.visualize(viz, "panda_hand", show_tree=True) | ||
|
||
# Animate the path | ||
input("Press 'Enter' to animate the path.") | ||
for idx in range(1, len(path)): | ||
segment_start = path[idx - 1] | ||
segment_end = path[idx] | ||
q_path = discretize_joint_space_path( | ||
segment_start, segment_end, options.max_angle_step | ||
) | ||
for q in q_path: | ||
viz.display(q) | ||
time.sleep(0.05) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import numpy as np | ||
|
||
from ..core.utils import configuration_distance | ||
|
||
|
||
class Node: | ||
"""Describes an individual node in a graph.""" | ||
|
||
def __init__(self, q, parent=None, cost=0.0): | ||
""" | ||
Creates a graph node instance. | ||
Parameters | ||
---------- | ||
q : array-like | ||
The joint configuration associated with the node. | ||
parent : `pyroboplan.planning.graph.Node`, optional. | ||
The parent of the node, which is either None or another Node object. | ||
cost : float, optional | ||
The cost associated with the node. | ||
""" | ||
self.q = q | ||
self.parent = parent | ||
self.cost = cost | ||
self.neighbors = set() | ||
|
||
|
||
class Edge: | ||
"""Describes an individual edge in a graph.""" | ||
|
||
def __init__(self, nodeA, nodeB, cost=0.0): | ||
""" | ||
Creates a graph edge instance. | ||
Parameters | ||
---------- | ||
nodeA : `pyroboplan.planning.graph.Node` | ||
The first node in the edge. | ||
nodeB : `pyroboplan.planning.graph.Node` | ||
The second node in the edge. | ||
cost : float, optional | ||
The cost associated with the edge. | ||
""" | ||
self.nodeA = nodeA | ||
self.nodeB = nodeB | ||
self.cost = cost | ||
|
||
|
||
class Graph: | ||
"""Describes a graph of robot configuration states for motion planning.""" | ||
|
||
def __init__(self): | ||
""" | ||
Creates a graph instance with no edges or nodes. | ||
""" | ||
self.nodes = set() | ||
self.edges = set() | ||
|
||
def add_node(self, node): | ||
""" | ||
Adds a node to the graph. | ||
Parameters | ||
---------- | ||
node : `pyroboplan.planning.graph.Node` | ||
The node to add to the graph. | ||
""" | ||
self.nodes.add(node) | ||
|
||
def add_edge(self, nodeA, nodeB): | ||
""" | ||
Adds an edge to the graph. | ||
Parameters | ||
---------- | ||
nodeA : `pyroboplan.planning.graph.Node` | ||
The first node in the edge. | ||
nodeB : `pyroboplan.planning.graph.Node` | ||
The second node in the edge. | ||
""" | ||
cost = configuration_distance(nodeA.q, nodeB.q) | ||
self.edges.add(Edge(nodeA, nodeB, cost)) | ||
nodeA.neighbors.add(nodeB) | ||
nodeB.neighbors.add(nodeA) | ||
|
||
def get_nearest_node(self, q): | ||
""" | ||
Gets the nearest node to a specifed robot configuration. | ||
Parameters | ||
---------- | ||
q : array-like | ||
The robot configuration to use in this query. | ||
Returns | ||
------- | ||
`pyroboplan.planning.graph.Node` or None | ||
The nearest node to the input configuration, or None if the graph is empty. | ||
""" | ||
nearest_node = None | ||
min_dist = np.inf | ||
|
||
for node in self.nodes: | ||
dist = configuration_distance(q, node.q) | ||
if dist < min_dist: | ||
min_dist = dist | ||
nearest_node = node | ||
|
||
return nearest_node |
Oops, something went wrong.