Skip to content

Commit df6120a

Browse files
zkingstonwbthomasonZachary Kingston
authored
Add support to add custom end-effector attachments for Panda, UR5, and Fetch (#18)
* Added Panda Attachments initial implementation * Adding attachment to cmake * hax for running attachment fk * Regenerate for correct Panda * Regenerate attached to panda_hand link * Experiment: see if using raw pointers for attachments decreases overhead * Experiment: std::optional instead of std::unique_ptr for attachments * Experiment: remove useless conditional around attachment posing * attachment test code * attachment python interface * Experiment: eefk function for attachment debugging * working! * UR5 attachment FK (tool0 frame) * Fetch attachment FK (gripper_link) * fusing attachment code * remove hack * API QoL changes for attachments * made default params a bit bigger * started readme docs * small docs * Regenerate UR5 attachment with robotiq_85_base_link EE frame * Regenerate all attached FK with new function call style * Fixed FK functions * fix: formatting * Update scripts/README.md Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update scripts/README.md Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update src/vamp/pybullet_interface.py Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update src/vamp/__init__.py Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update scripts/attachments.py Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update scripts/attachments.py Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update src/impl/vamp/bindings/common.hh Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update src/impl/vamp/robots/baxter.hh Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * fix: nits from PR * Adding documentation, detach method * EE frames in docs * updates to docker * added default constructor in to_array * chore: run clang-format on environment.cc * fix: Make attachments compile with old GCC I had no idea noexcept could make an explicitly defaulted function become implicitly deleted... * fix: format * Update scripts/README.md Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Update scripts/README.md Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> * Array should be default initialized * list of robots --------- Co-authored-by: Wil Thomason <wil.thomason@gmail.com> Co-authored-by: Wil Thomason <wbthomason@users.noreply.github.com> Co-authored-by: Zachary Kingston <zak@xiphos.attlocal.net>
1 parent 96eb4d6 commit df6120a

File tree

27 files changed

+24153
-89
lines changed

27 files changed

+24153
-89
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ These objects can be created with the following:
207207
- Pointclouds via `add_pointcloud()` in `vamp.Environment`. This will construct a CAPT from the provided list of points, the minimum and maximum robot sphere radii, and radius for each point in the pointcloud.
208208
See the `src/impl/vamp/collision/` folder for more information.
209209

210+
Some robots (currently, the UR5, Panda, and Fetch) support attaching custom geometry (a collection of spheres) to the end-effector via `vamp.Attachment(relative_position, relative_quaternion_xyzw)`.
211+
Spheres can be added (in the attachment's frame) with `add_sphere(...)`.
212+
The attachment can be added to the environment with `vamp.Environment.attach(...)`, and removed with `vamp.Environment.detach()`.
213+
An example use of attachments with the Panda arm is available in `scripts/attachments.py`.
214+
215+
210216
## Code Overview
211217

212218
The code lives in the `src` folder, split into `impl` (the C++ core) and `vamp` (the Python interface).
@@ -246,7 +252,7 @@ Inside `impl/vamp`, the code is divided into the following directories:
246252
- [ ] Improved Python API
247253
- [ ] Batch configuration validation
248254
- [ ] Planning subgroups
249-
- [ ] Object attachment at end-effector
255+
- [X] Object attachment at end-effector
250256
- [ ] Mesh collision checking
251257
- [X] Pointcloud collision checking
252258
- [ ] Manifold-constrained planning

docker/ubuntu2004.dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM ubuntu:focal
22

33
ENV DEBIAN_FRONTEND=noninteractive
44
RUN apt-get update && \
5-
apt-get install -y cmake clang llvm libstdc++6 python3 python3-dev python3-pip libeigen3-dev
5+
apt-get install -y git cmake clang llvm libstdc++6 python3 python3-dev python3-pip libeigen3-dev
66
COPY . vamp
77
WORKDIR vamp
8-
RUN pip install --no-deps -v .
8+
RUN pip install -v .

docker/ubuntu2204-conda.dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ FROM ubuntu:jammy
33
ENV DEBIAN_FRONTEND=noninteractive
44

55
RUN apt-get update && \
6-
apt-get install -y wget && \
6+
apt-get install -y git wget && \
77
mkdir -p ~/miniconda3 && \
88
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh && \
99
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3 && \
@@ -16,4 +16,4 @@ COPY . vamp
1616
WORKDIR vamp
1717

1818
SHELL ["/root/miniconda3/bin/conda", "run", "-n", "vamp", "/bin/bash", "-c"]
19-
RUN pip install --no-deps -v .
19+
RUN pip install -v .

docker/ubuntu2204.dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM ubuntu:jammy
22

33
ENV DEBIAN_FRONTEND=noninteractive
44
RUN apt-get update && \
5-
apt-get install -y cmake clang libstdc++6 python3 python3-dev python3-pip libeigen3-dev
5+
apt-get install -y git cmake clang libstdc++6 python3 python3-dev python3-pip libeigen3-dev
66
COPY . vamp
77
WORKDIR vamp
8-
RUN pip install --no-deps -v .
8+
RUN pip install -v .

docker/ubuntu2404.dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ FROM ubuntu:noble
22

33
ENV DEBIAN_FRONTEND=noninteractive
44
RUN apt-get update && \
5-
apt-get install -y cmake clang libstdc++6 python3 python3-dev python3-pip libeigen3-dev
5+
apt-get install -y git cmake clang libstdc++6 python3 python3-dev python3-pip libeigen3-dev
66
COPY . vamp
77
WORKDIR vamp
8-
RUN pip install --break-system-packages --no-deps -v .
8+
RUN pip install --break-system-packages -v .

resources/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ See the `*_spherized.urdf` files for examples of these spherical decompositions
1010
We also use a secondary hierarchical decomposition: see the high-level single sphere URDF used for each robot in the `*_spherized_1.urdf` files.
1111
These decompositions are conservative estimations of the robot's mesh geometry.
1212

13+
## Attachments
14+
15+
There is support to attach custom geometry to the end-effector of the following robots, with respect to the following end-effector frames (see the robot's URDF for transform information):
16+
- UR5: `robotiq85_base_link`
17+
- Panda: `panda_hand`
18+
- Fetch: `gripper_link`
19+
1320
## Datasets
1421

1522
### MotionBenchMaker problems

scripts/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ This script has the following arguments that only affect benchmarking:
6464

6565
Visualization is enabled by `--visualize`, which shows the plan with the PyBullet visualizer.
6666

67+
## `attachments.py`
68+
Demonstrates planning with end-effector attachments using the same problem as in `sphere_cage_example.py`.
69+
A single sphere is attached to the end-effector of the Panda and carried through the cage.
70+
71+
This script has the following arguments that affect the placement of the attached sphere.
72+
- `attachment_radius`: Radius of the attached sphere.
73+
- `attachment_offset`: Offset of the attachment transform along the local-frame Z-axis of the end-effector (i.e., its distance from the end-effector).
74+
6775
## `flying_sphere.py`
6876
Demonstrates generating a roadmap over a heightfield for a flying sphere.
6977
The script has the following arguments:

scripts/attachments.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from pathlib import Path
2+
3+
import vamp
4+
from vamp import pybullet_interface as vpb
5+
6+
from fire import Fire
7+
8+
# Starting configuration
9+
a = [0., -0.785, 0., -2.356, 0., 1.571, 0.785]
10+
11+
# Goal configuration
12+
b = [2.35, 1., 0., -0.8, 0, 2.5, 0.785]
13+
14+
# Problem specification: a list of sphere centers
15+
problem = [
16+
[0.55, 0, 0.25],
17+
[0.35, 0.35, 0.25],
18+
[0, 0.55, 0.25],
19+
[-0.55, 0, 0.25],
20+
[-0.35, -0.35, 0.25],
21+
[0, -0.55, 0.25],
22+
[0.35, -0.35, 0.25],
23+
[0.35, 0.35, 0.8],
24+
[0, 0.55, 0.8],
25+
[-0.35, 0.35, 0.8],
26+
[-0.55, 0, 0.8],
27+
[-0.35, -0.35, 0.8],
28+
[0, -0.55, 0.8],
29+
[0.35, -0.35, 0.8],
30+
]
31+
32+
33+
def main(
34+
obstacle_radius: float = 0.2,
35+
attachment_radius: float = 0.07,
36+
attachment_offset: float = 0.14,
37+
planner: str = "rrtc",
38+
**kwargs,
39+
):
40+
41+
(vamp_module, planner_func, plan_settings,
42+
simp_settings) = vamp.configure_robot_and_planner_with_kwargs("panda", planner, **kwargs)
43+
44+
# Create an attachment offset on the Z-axis from the end-effector frame
45+
attachment = vamp.Attachment([0, 0, attachment_offset], [0, 0, 0, 1])
46+
47+
# Add a single sphere to the attachment - spheres are added in the attachment's local frame
48+
attachment.add_spheres([vamp.Sphere([0, 0, 0], attachment_radius)])
49+
50+
robot_dir = Path(__file__).parents[1] / 'resources' / 'panda'
51+
sim = vpb.PyBulletSimulator(str(robot_dir / "panda_spherized.urdf"), vamp.ROBOT_JOINTS['panda'], True)
52+
53+
e = vamp.Environment()
54+
for sphere in problem:
55+
e.add_sphere(vamp.Sphere(sphere, obstacle_radius))
56+
sim.add_sphere(obstacle_radius, sphere)
57+
58+
# Add the attchment to the VAMP environment
59+
e.attach(attachment)
60+
61+
# Add attachment sphere to visualization
62+
attachment_sphere = sim.add_sphere(attachment_radius, [0, 0, 0])
63+
64+
# Callback to update sphere's location in PyBullet visualization
65+
def callback(configuration):
66+
position, orientation_xyzw = vamp_module.eefk(configuration)
67+
attachment.set_ee_pose(position, orientation_xyzw)
68+
sphere = attachment.posed_spheres[0]
69+
70+
sim.update_object_position(attachment_sphere, sphere.position)
71+
72+
# Plan and display
73+
result = planner_func(a, b, e, plan_settings)
74+
simple = vamp_module.simplify(result.path, e, simp_settings)
75+
simple.path.interpolate(vamp.panda.resolution())
76+
77+
sim.animate(simple.path, callback)
78+
79+
80+
if __name__ == "__main__":
81+
Fire(main)

src/impl/vamp/bindings/common.hh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,18 @@ namespace vamp::binding
232232
{
233233
return filter_robot_from_pointcloud<Robot>(pc, start, environment, point_radius);
234234
}
235+
236+
inline static auto eefk(const ConfigurationArray &start)
237+
-> std::pair<std::array<float, 3>, std::array<float, 4>>
238+
{
239+
const auto &result = Robot::eefk(start);
240+
241+
std::array<float, 3> position = {result[0], result[1], result[2]};
242+
// A (x, y, z, w) quaternion
243+
std::array<float, 4> orientation = {result[3], result[4], result[5], result[6]};
244+
245+
return {position, orientation};
246+
}
235247
};
236248

237249
template <typename Robot>
@@ -504,6 +516,12 @@ namespace vamp::binding
504516
"point_radius"_a,
505517
"Filters all colliding points from a point cloud.");
506518

519+
submodule.def(
520+
"eefk",
521+
RH::eefk,
522+
"configuration"_a,
523+
"Returns the position and orientation (as a xyzw quaternion) of the robot's end-effector.");
524+
507525
return submodule;
508526
}
509527
} // namespace vamp::binding

src/impl/vamp/bindings/environment.cc

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ void vamp::binding::init_environment(nanobind::module_ &pymodule)
2828
.def_ro("y", &vc::Sphere<float>::y)
2929
.def_ro("z", &vc::Sphere<float>::z)
3030
.def_ro("r", &vc::Sphere<float>::r)
31+
.def_prop_ro(
32+
"position",
33+
[](vc::Sphere<float> &sphere) {
34+
return std::array<float, 3>{sphere.x, sphere.y, sphere.z};
35+
})
3136
.def_ro("min_distance", &vc::Sphere<float>::min_distance)
3237
.def_rw("name", &vc::Sphere<float>::name);
3338

@@ -152,7 +157,11 @@ void vamp::binding::init_environment(nanobind::module_ &pymodule)
152157
auto start_time = std::chrono::steady_clock::now();
153158
e.pointclouds.emplace_back(pc, r_min, r_max, r_point);
154159
return vamp::utils::get_elapsed_nanoseconds(start_time);
155-
});
160+
})
161+
.def(
162+
"attach",
163+
[](vc::Environment<float> &e, const vc::Attachment<float> &a) { e.attachments.emplace(a); })
164+
.def("detach", [](vc::Environment<float> &e) { e.attachments.reset(); });
156165

157166
pymodule.def(
158167
"filter_pointcloud",
@@ -169,4 +178,58 @@ void vamp::binding::init_environment(nanobind::module_ &pymodule)
169178
vc::filter_pointcloud(pc, min_dist, max_range, origin, workcell_min, workcell_max, cull);
170179
return {filtered, vamp::utils::get_elapsed_nanoseconds(start_time)};
171180
});
181+
182+
nb::class_<vc::Attachment<float>>(pymodule, "Attachment")
183+
.def(
184+
"__init__",
185+
[](vc::Attachment<float> *q,
186+
const std::array<float, 3> &center,
187+
const std::array<float, 4> &quaternion_xyzw) noexcept
188+
{
189+
new (q) vc::Attachment<float>(
190+
center[0],
191+
center[1],
192+
center[2],
193+
quaternion_xyzw[0],
194+
quaternion_xyzw[1],
195+
quaternion_xyzw[2],
196+
quaternion_xyzw[3]);
197+
},
198+
"Constructor for an attachment centered at a relative position and XYZW quaternion from the "
199+
"end-effector.")
200+
.def_prop_ro(
201+
"relative_frame",
202+
[](vc::Attachment<float> &a)
203+
{
204+
std::array<float, 3> position = {a.tf_tx, a.tf_ty, a.tf_tz};
205+
std::array<float, 4> quaternion_xyzw = {a.tf_rx, a.tf_ry, a.tf_rz, a.tf_rw};
206+
207+
return std::pair{position, quaternion_xyzw};
208+
})
209+
.def(
210+
"add_sphere",
211+
[](vc::Attachment<float> &a, collision::Sphere<float> &sphere)
212+
{ a.spheres.emplace_back(sphere); })
213+
.def(
214+
"add_spheres",
215+
[](vc::Attachment<float> &a, std::vector<collision::Sphere<float>> &spheres)
216+
{ a.spheres.insert(a.spheres.end(), spheres.cbegin(), spheres.cend()); })
217+
.def(
218+
"set_ee_pose",
219+
[](vc::Attachment<float> &a,
220+
const std::array<float, 3> &position,
221+
const std::array<float, 4> &quaternion_xyzw)
222+
{
223+
a.pose(
224+
position[0],
225+
position[1],
226+
position[2],
227+
quaternion_xyzw[0],
228+
quaternion_xyzw[1],
229+
quaternion_xyzw[2],
230+
quaternion_xyzw[3]);
231+
},
232+
"position"_a,
233+
"quaternion_xyzw"_a)
234+
.def_ro("posed_spheres", &vc::Attachment<float>::posed_spheres);
172235
}

0 commit comments

Comments
 (0)