Skip to content

Commit 15c9687

Browse files
authored
Add rudimentary stl support (#64)
1 parent a24729d commit 15c9687

File tree

7 files changed

+104
-13
lines changed

7 files changed

+104
-13
lines changed

Diff for: README.md

+15
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,18 @@ To rebuild only the `moveit_drake` package:
105105
rm -rf build/moveit_drake install/moveit_drake
106106
colcon build --packages-select moveit_drake
107107
```
108+
109+
## Known issues
110+
111+
### .stl support
112+
113+
Unfortunately, Drake does not support `.stl` files (11/28/2024, see [drake#19408](https://github.com/RobotLocomotion/drake/issues/19408)).
114+
We're working around this by replacing the `.stl` files in the urdf string with `.obj` files in the plugin implementations.
115+
Make sure that the moveit config you're using contains the relevant `.stl` files.
116+
If it doesn't, take a look into the scripts/ directory.
117+
We've provided a simple python script to add additional `.obj` files for given `.stl` files. Usage:
118+
119+
```
120+
./scripts/convert_stl_to_obj.py /PATH/TO/YOUR/MESH/DIR
121+
```
122+
Don't forget to rebuild your description package so the `.obj` files are copied into the workspace's install directory.

Diff for: include/ktopt_interface/ktopt_planning_context.hpp

-3
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,6 @@ class KTOptPlanningContext : public planning_interface::PlanningContext
103103
/// @brief The ROS parameters associated with this motion planner.
104104
const ktopt_interface::Params params_;
105105

106-
/// @brief The URDF robot description.
107-
std::string robot_description_;
108-
109106
/// @brief The Drake diagram describing the entire system.
110107
std::unique_ptr<Diagram<double>> diagram_;
111108

Diff for: include/moveit/drake/conversions.hpp

+8
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,12 @@ getPiecewisePolynomial(const ::robot_trajectory::RobotTrajectory& robot_trajecto
147147
void getRobotTrajectory(const ::drake::trajectories::Trajectory<double>& drake_trajectory, const double delta_t,
148148
const ::drake::multibody::MultibodyPlant<double>& plant,
149149
std::shared_ptr<::robot_trajectory::RobotTrajectory>& moveit_trajectory);
150+
151+
/**
152+
* @brief Converts all STL file paths in a URDF string to OBJ file paths
153+
*
154+
* @param input Input robot description
155+
* @return std::string Robot description with all STL file paths replaced by OBJ file paths
156+
*/
157+
[[nodiscard]] std::string replaceSTLWithOBJ(const std::string& input);
150158
} // namespace moveit::drake

Diff for: moveit_drake.repos

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ repositories:
1313
version: main
1414
moveit_resources:
1515
type: git
16-
url: https://github.com/moveit/moveit_resources
17-
version: ros2
16+
url: https://github.com/sjahr/moveit_resources
17+
version: moveit_drake
1818
moveit_msgs:
1919
type: git
2020
url: https://github.com/moveit/moveit_msgs

Diff for: scripts/convert_stl_to_obj.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import trimesh
5+
import argparse
6+
7+
8+
def convert_stl_to_obj(directory):
9+
"""
10+
Finds all STL files in the given directory and subdirectories, and converts each to an OBJ file.
11+
12+
Args:
13+
directory (str): The path to the directory to search.
14+
"""
15+
for root, _, files in os.walk(directory):
16+
for file in files:
17+
stl_path = os.path.join(root, file)
18+
file_root, file_ext = os.path.splitext(stl_path)
19+
20+
if file_ext.lower() == ".stl": # Check if the file is an STL file
21+
obj_path = file_root + ".obj" # Create the OBJ file path
22+
23+
try:
24+
# Load the STL file
25+
mesh = trimesh.load(stl_path)
26+
27+
# Export the mesh as OBJ
28+
mesh.export(obj_path)
29+
30+
print(f"Converted: {stl_path} -> {obj_path}")
31+
except Exception as e:
32+
print(f"Failed to convert {stl_path}: {e}")
33+
34+
35+
def main():
36+
parser = argparse.ArgumentParser(description="Convert STL files to OBJ format.")
37+
parser.add_argument(
38+
"directory", type=str, help="The directory to search for STL files."
39+
)
40+
args = parser.parse_args()
41+
42+
if os.path.isdir(args.directory):
43+
convert_stl_to_obj(args.directory)
44+
else:
45+
print("The provided path is not a directory. Please check and try again.")
46+
47+
48+
if __name__ == "__main__":
49+
main()

Diff for: src/conversions.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,28 @@ void getRobotTrajectory(const ::drake::trajectories::Trajectory<double>& drake_t
237237
t_prev = t;
238238
}
239239
}
240+
241+
std::string replaceSTLWithOBJ(const std::string& input)
242+
{
243+
std::string result = input;
244+
const std::string lower_case_stl = ".stl";
245+
const std::string upper_case_stl = ".STL";
246+
const std::string replacement = ".obj";
247+
248+
size_t pos = 0;
249+
while ((pos = result.find(lower_case_stl, pos)) != std::string::npos)
250+
{
251+
result.replace(pos, lower_case_stl.length(), replacement);
252+
pos += replacement.length(); // Move past the replacement to avoid infinite loop
253+
}
254+
255+
pos = 0;
256+
while ((pos = result.find(upper_case_stl, pos)) != std::string::npos)
257+
{
258+
result.replace(pos, upper_case_stl.length(), replacement);
259+
pos += replacement.length(); // Move past the replacement to avoid infinite loop
260+
}
261+
262+
return result;
263+
}
240264
} // namespace moveit::drake

Diff for: src/ktopt_planning_context.cpp

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <cmath>
2+
#include <iostream>
3+
#include <string>
24

35
#include <drake/geometry/meshcat_params.h>
46
#include <drake/geometry/geometry_frame.h>
@@ -358,8 +360,6 @@ bool KTOptPlanningContext::terminate()
358360

359361
void KTOptPlanningContext::setRobotDescription(const std::string& robot_description)
360362
{
361-
robot_description_ = robot_description;
362-
363363
// also perform some drake related initialisations here
364364
builder = std::make_unique<DiagramBuilder<double>>();
365365

@@ -369,13 +369,11 @@ void KTOptPlanningContext::setRobotDescription(const std::string& robot_descript
369369

370370
auto [plant, scene_graph] = drake::multibody::AddMultibodyPlantSceneGraph(builder.get(), 0.0);
371371

372-
// TODO:(kamiradi) Figure out object parsing
373-
// auto robot_instance = Parser(plant_,
374-
// scene_graph_).AddModelsFromString(robot_description_, ".urdf");
372+
// Drake cannot handle stl files, so we convert them to obj. Make sure these files are available in your moveit config!
373+
const auto description_with_obj = moveit::drake::replaceSTLWithOBJ(robot_description);
374+
auto robot_instance =
375+
drake::multibody::Parser(&plant, &scene_graph).AddModelsFromString(description_with_obj, ".urdf");
375376

376-
const char* ModelUrl = params_.drake_robot_description.c_str();
377-
const std::string urdf = drake::multibody::PackageMap{}.ResolveUrl(ModelUrl);
378-
auto robot_instance = drake::multibody::Parser(&plant, &scene_graph).AddModels(urdf);
379377
plant.WeldFrames(plant.world_frame(), plant.GetFrameByName(params_.base_frame));
380378

381379
// planning scene transcription

0 commit comments

Comments
 (0)