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

Generating documentation using pdoc #54

Merged
merged 5 commits into from
Jan 10, 2024
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
10 changes: 9 additions & 1 deletion dev/DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ Depending on your python version, you will get a file called `pymp.cpython-310-x

To install the entire package along with python glue code, do `python3.[version] -m pip install .` inside the root directory of the project.

### Stub generation
## Documentation Generation

### Stub Generation

Stubs are useful for type checking and IDE autocompletion. To generate stubs, you **first need to have mplib compiled and installed**. Then, do `python3.[version] -m pip install pybind11_stubgen` and then run `bash dev/generate_stubs.sh`. This will generate stubs for the entire project in the `stubs/` directory. Note that you might need to change the version of the python inside the script. The default is 3.11.

### Website Generation

We use `pdoc` to generate the documentation. First install a version of mplib referring to the section above.

Then, you will need to install `pdoc` with `python3.[version] -m pip install pdoc`. The reason the version is important is because `pdoc` will actually do analysis on the files, so it will scrape through the mplib installed in the site package. Then, run `bash dev/generate_pdoc.sh` from the root of MPlib. This will generate the documentation in the `docs/` directory. Note that you might need to change the version of the python inside the script. The default is 3.11.
8 changes: 8 additions & 0 deletions dev/generate_pdoc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# python3.[version] -m pip install pdoc
# run from the root of the project

current_dir=$(pwd)
cd ~ # go out of the current directory to avoid picking up local mplib (need global)
python3.11 -m pdoc -o $current_dir/docs mplib
cd $current_dir
7 changes: 7 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=./mplib.html"/>
</head>
</html>
267 changes: 267 additions & 0 deletions docs/mplib.html

Large diffs are not rendered by default.

243 changes: 243 additions & 0 deletions docs/mplib/examples.html

Large diffs are not rendered by default.

683 changes: 683 additions & 0 deletions docs/mplib/examples/collision_avoidance.html

Large diffs are not rendered by default.

733 changes: 733 additions & 0 deletions docs/mplib/examples/constrained_planning.html

Large diffs are not rendered by default.

597 changes: 597 additions & 0 deletions docs/mplib/examples/demo.html

Large diffs are not rendered by default.

1,050 changes: 1,050 additions & 0 deletions docs/mplib/examples/demo_setup.html

Large diffs are not rendered by default.

536 changes: 536 additions & 0 deletions docs/mplib/examples/detect_collision.html

Large diffs are not rendered by default.

667 changes: 667 additions & 0 deletions docs/mplib/examples/moving_robot.html

Large diffs are not rendered by default.

866 changes: 866 additions & 0 deletions docs/mplib/examples/two_stage_motion.html

Large diffs are not rendered by default.

3,424 changes: 3,424 additions & 0 deletions docs/mplib/planner.html

Large diffs are not rendered by default.

238 changes: 238 additions & 0 deletions docs/mplib/pymp.html

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions docs/search.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions mplib/README.md
5 changes: 4 additions & 1 deletion mplib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from .planner import Planner
"""
.. include:: ./README.md
"""

from mplib.planner import Planner
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import sapien.core as sapien
import mplib
import numpy as np
from demo_setup import DemoSetup
from .demo_setup import DemoSetup

class PlanningDemo(DemoSetup):
""" The shows the planner's ability to generate a collision free path with the straight path causes collisions """
def __init__(self):
"""
Same setup as demo.py except the boxes are of difference sizes and different use
Red box is the target we want to grab
Blue box is the obstacle we want to avoid
green box is the landing pad on which we want to place the red box
"""
super().__init__()
self.setup_scene()
self.load_robot()
Expand All @@ -21,26 +26,29 @@ def __init__(self):
self.table = builder.build_kinematic(name='table')
self.table.set_pose(sapien.Pose([0.56, 0, - 0.025]))

# boxes
# red box is the target we want to grab
builder = self.scene.create_actor_builder()
builder.add_box_collision(half_size=[0.02, 0.02, 0.06])
builder.add_box_visual(half_size=[0.02, 0.02, 0.06], color=[1, 0, 0])
self.red_cube = builder.build(name='red_cube')
self.red_cube.set_pose(sapien.Pose([0.7, 0, 0.06]))

# green box is the landing pad on which we want to place the red box
builder = self.scene.create_actor_builder()
builder.add_box_collision(half_size=[0.04, 0.04, 0.005])
builder.add_box_visual(half_size=[0.04, 0.04, 0.005], color=[0, 1, 0])
self.green_cube = builder.build(name='green_cube')
self.green_cube.set_pose(sapien.Pose([0.4, 0.3, 0.005]))

# blue box is the obstacle we want to avoid
builder = self.scene.create_actor_builder()
builder.add_box_collision(half_size=[0.05, 0.2, 0.1])
builder.add_box_visual(half_size=[0.05, 0.2, 0.1], color=[0, 0, 1])
self.blue_cube = builder.build(name='blue_cube')
self.blue_cube.set_pose(sapien.Pose([0.55, 0, 0.1]))

def add_point_cloud(self):
""" we tell the planner about the obstacle through a point cloud """
import trimesh
box = trimesh.creation.box([0.1, 0.4, 0.2])
points, _ = trimesh.sample.sample_surface(box, 1000)
Expand All @@ -49,14 +57,19 @@ def add_point_cloud(self):
return

def demo(self, with_screw=True, use_point_cloud=True, use_attach=True):
"""
We pick up the red box while avoiding the blue box and place it back down on top of the green box
"""
pickup_pose = [0.7, 0, 0.12, 0, 1, 0, 0]
delivery_pose = [0.4, 0.3, 0.13, 0, 1, 0, 0]

# tell the planner where the obstacle is
if use_point_cloud:
self.add_point_cloud()

# move to the pickup pose
pickup_pose[2] += 0.2
# no attach since nothing picked up yet
# no need to check collision against attached object since nothing picked up yet
self.move_to_pose(pickup_pose, with_screw, use_point_cloud, use_attach=False)
self.open_gripper()
pickup_pose[2] -= 0.12
Expand All @@ -67,6 +80,7 @@ def demo(self, with_screw=True, use_point_cloud=True, use_attach=True):
if use_attach:
self.planner.update_attached_box([0.04, 0.04, 0.12], [0, 0, 0.14, 1, 0, 0, 0])

# move to the delivery pose
pickup_pose[2] += 0.12
self.move_to_pose(pickup_pose, with_screw, use_point_cloud, use_attach)
delivery_pose[2] += 0.2
Expand All @@ -78,5 +92,10 @@ def demo(self, with_screw=True, use_point_cloud=True, use_attach=True):
self.move_to_pose(delivery_pose, with_screw, use_point_cloud, use_attach=False)

if __name__ == '__main__':
"""
As you change some of the parameters, you will see different behaviors
In particular, when point cloud is not used, the robot will attemt to go through the blue box
If attach is not used, the robot will avoid the blue box on its way to the pickup pose but will knock it over with the attached red cube on its way to the delivery pose
"""
demo = PlanningDemo()
demo.demo(False, True, True)
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
#!/usr/bin/env python3

import mplib
import numpy as np
import transforms3d

from demo_setup import DemoSetup
from .demo_setup import DemoSetup

class ConstrainedPlanningDemo(DemoSetup):
"""
This demo shows the planner's ability to plan with constraints.
For this particular demo, we move to several poses while pointing the end effector roughly 15 degrees w.r.t. -z axis
"""
def __init__(self):
""" set up the scene and load the robot """
super().__init__()
self.setup_scene()
self.load_robot()
self.setup_planner()

def add_point_cloud(self):
""" add some random obstacles to make the planning more challenging """
import trimesh
box = trimesh.creation.box([0.1, 0.4, 0.2])
points, _ = trimesh.sample.sample_surface(box, 1000)
Expand All @@ -22,18 +26,28 @@ def add_point_cloud(self):
return

def get_eef_z(self):
""" helper function for constraint """
ee_idx = self.planner.link_name_2_idx[self.planner.move_group]
ee_pose = self.planner.robot.get_pinocchio_model().get_link_pose(ee_idx)
mat = transforms3d.quaternions.quat2mat(ee_pose[3:])
return mat[:,2]

def make_f(self):
"""
create a constraint function that takes in a qpos and outputs a scalar
A valid constraint function should evaluates to 0 when the constraint is satisfied
See [ompl constrained planning](https://ompl.kavrakilab.org/constrainedPlanning.html) for more details
"""
def f(x, out):
self.planner.robot.set_qpos(x)
out[0] = self.get_eef_z().dot(np.array([0,0,-1]))-0.966 # maintain 15 degrees w.r.t. -z axis
return f

def make_j(self):
"""
create the jacobian of the constraint function w.r.t. qpos
This is needed because the planner uses the jacobian to project a random sample to the constraint manifold
"""
def j(x, out):
full_qpos = self.planner.pad_qpos(x)
jac = self.planner.robot.get_pinocchio_model().compute_single_link_jacobian(full_qpos, len(self.planner.move_group_joint_indices)-1)
Expand All @@ -43,6 +57,10 @@ def j(x, out):
return j

def demo(self):
"""
We first plan with constraints to three poses, then plan without constraints to the same poses
While not always the case, sometimes without constraints, the end effector will tilt almost upside down
"""
# this starting pose has the end effector tilted roughly 15 degrees
starting_qpos = [0, 0.19, 0.0, -2.61, 0.0, 2.88, 0.78, 0, 0]
self.robot.set_qpos(starting_qpos)
Expand Down Expand Up @@ -75,7 +93,7 @@ def demo(self):
self.follow_path(result)

# without constraint
print("without constraint. some movements tilt the end effector almost upside down")
print("without constraint. certain movements can sometimes tilt the end effector almost upside down")
for pose in poses:
result = self.planner.plan_qpos_to_pose(
pose,
Expand Down
18 changes: 14 additions & 4 deletions examples/demo.py → mplib/examples/demo.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import sapien.core as sapien
import mplib
import numpy as np
from demo_setup import DemoSetup
from .demo_setup import DemoSetup

class PlanningDemo(DemoSetup):
"""
This is the most basic demo of the motion planning library where the robot tries to shuffle three boxes around
"""
def __init__(self):
"""
Setting up the scene, the planner, and adding some objects to the scene
Afterwards, put down a table and three boxes. For details on how to do this, see the sapien documentation
"""
super().__init__()
# load the world, the robot, and then setup the planner. See demo_setup.py for more details
self.setup_scene()
self.load_robot()
self.setup_planner()

# Set initial joint positions
init_qpos = [0, 0.19634954084936207, 0.0, -2.617993877991494, 0.0, 2.941592653589793, 0.7853981633974483, 0, 0]
init_qpos = [0, 0.19, 0.0, -2.62, 0.0, 2.94, 0.79, 0, 0]
self.robot.set_qpos(init_qpos)

# table top
Expand Down Expand Up @@ -41,6 +47,10 @@ def __init__(self):
self.blue_cube.set_pose(sapien.Pose([0.6, 0.1, 0.07]))

def demo(self):
"""
Declare three poses for the robot to move to, each one corresponding to the position of a box
Pick up the box, and set it down 0.1m to the right of its original position
"""
poses = [[0.4, 0.3, 0.12, 0, 1, 0, 0],
[0.2, -0.3, 0.08, 0, 1, 0, 0],
[0.6, 0.1, 0.14, 0, 1, 0, 0]]
Expand Down
Loading