blender_gazebo.py
Go to the documentation of this file.
1 bl_info = {
2  "name": "ROS Gazebo Exporter",
3  "author": "Dave Niewinski",
4  "version": (0,0,1),
5  "blender": (2,80,0),
6  "location": "File > Import-Export",
7  "description": "Export Gazebo",
8  "category": "Import-Export"
9 }
10 
11 import bpy
12 import os
13 import subprocess
14 from bpy_extras.io_utils import ExportHelper
15 from bpy.props import StringProperty
16 import xml.etree.ElementTree as ET
17 
18 class InternalData():
19  def __init__(self):
20  self.text = ""
21 
22  def getRoot(self):
23  return ET.fromstring(self.text)
24 
26  def __init__(self):
27  self.text = '''<launch>
28  <param name="$NAME$_description" command="$(find xacro)/xacro --inorder '$(find $PACKAGE$)/urdf/$NAME$.urdf.xacro'" />
29 
30  <node name="spawn_$NAME$" pkg="gazebo_ros" type="spawn_model" args="-param $NAME$_description -urdf -model $NAME$" respawn="false"/>
31 </launch>
32 '''
33 
35  def __init__(self):
36  self.text = '''<?xml version="1.0"?>
37 <robot name="robot" xmlns:xacro="http://www.ros.org/wiki/xacro">
38  <link name="$NAME$_link">
39  <inertial>
40  <origin xyz="0 0 0" rpy="0 0 0"/>
41  <mass value="1"/>
42  <inertia ixx="1" ixy="0" ixz="0" iyy="1" iyz="0" izz="1"/>
43  </inertial>
44  <visual>
45  <origin xyz="0 0 0" rpy="0 0 0"/>
46  <geometry>
47  <mesh filename="package://$PACKAGE$/meshes/$VISUAL$"/>
48  </geometry>
49  </visual>
50  <collision>
51  <origin xyz="0 0 0" rpy="0 0 0"/>
52  <geometry>
53  <mesh filename="package://$PACKAGE$/meshes/$COLLISION$"/>
54  </geometry>
55  </collision>
56  </link>
57 
58  <gazebo> <static>true</static></gazebo>
59 </robot>
60 '''
61 
63  def __init__(self):
64  self.text = '''<launch>
65  <arg name="use_sim_time" default="true" />
66  <arg name="gui" default="true" />
67  <arg name="headless" default="false" />
68  <arg name="world_name" default="$(find blender_gazebo)/worlds/actually_empty_world.world" />
69 
70  <include file="$(find gazebo_ros)/launch/empty_world.launch">
71  <arg name="debug" value="0" />
72  <arg name="gui" value="$(arg gui)" />
73  <arg name="use_sim_time" value="$(arg use_sim_time)" />
74  <arg name="headless" value="$(arg headless)" />
75  <arg name="world_name" value="$(arg world_name)" />
76  </include>
77 </launch>
78 '''
79 
80 class GazeboExport(bpy.types.Operator, ExportHelper) :
81  bl_idname = "object.exportgazebo";
82  bl_label = "Export Gazebo";
83  bl_options = {'REGISTER', 'UNDO'};
84 
85  filename_ext = ".launch"
86  filter_glob: StringProperty(default="*.launch", options={'HIDDEN'})
87 
88  def __init__(self):
89  self.collision_suffix = "_collision"
90 
91  def checkDir(self, dir):
92  if not os.path.exists(dir):
93  os.makedirs(dir)
94 
95  def getPackagePaths(self, launch_file, make_dirs=True):
96  (dirname, filename) = os.path.split(launch_file)
97  (shortname, extension) = os.path.splitext(filename)
98  root_dir = os.path.abspath(os.path.join(dirname, ".."))
99  mesh_dir = os.path.join(root_dir, "meshes/")
100  urdf_dir = os.path.join(root_dir, "urdf/")
101  launch_dir = os.path.join(root_dir, "launch/")
102  package_name = root_dir.split("/")
103  package_name = package_name[-1]
104 
105  if make_dirs:
106  self.checkDir(mesh_dir)
107  self.checkDir(urdf_dir)
108  self.checkDir(launch_dir)
109 
110  return root_dir, mesh_dir, urdf_dir, launch_dir, package_name, shortname
111 
112  def writeURDF(self, name, package_name, visual, collision, urdf_dir):
113  body_urdf = BodyURDF().getRoot()
114 
115  for c in body_urdf.findall(".//mesh"):
116  for k in c.attrib.keys():
117  c.set(k, c.attrib[k].replace("$PACKAGE$", package_name).replace("$VISUAL$", visual).replace("$COLLISION$", collision))
118  for c in body_urdf.findall("link"):
119  for k in c.attrib.keys():
120  c.set(k, c.attrib[k].replace("$NAME$", name))
121 
122  outFile = open(urdf_dir + name + ".urdf.xacro", 'wb')
123  outFile.write(ET.tostring(body_urdf))
124  outFile.close()
125 
126  def writeLaunch(self, name, package_name, launch_dir):
127  body_launch = BodyLaunch().getRoot()
128 
129  for c in body_launch.findall("*"):
130  for k in c.attrib.keys():
131  c.set(k, c.attrib[k].replace("$NAME$", name).replace("$PACKAGE$", package_name))
132 
133  outFile = open(launch_dir + "spawn_" + name + ".launch", 'wb')
134  outFile.write(ET.tostring(body_launch))
135  outFile.close()
136 
137  def exportSTL(self, ob, name, dir):
138  bpy.ops.object.select_all(action='DESELECT')
139  ob.select_set(True)
140  bpy.ops.export_mesh.stl(filepath= dir + name, use_selection=True, use_mesh_modifiers=True)
141 
142  def exportDAE(self, ob, name, dir):
143  bpy.ops.object.select_all(action='DESELECT')
144  ob.select_set(True)
145  bpy.ops.wm.collada_export(filepath= dir + name, apply_modifiers=True, selected=True)
146 
147  def execute(self, context):
148  root_dir, mesh_dir, urdf_dir, launch_dir, package_name, prefix = self.getPackagePaths(self.filepath)
149  world_launch = WorldLaunch().getRoot()
150 
151  for ob in bpy.data.objects:
152  if ob.type == 'MESH':
153  if self.collision_suffix not in ob.name:
154  print("Working on " + ob.name)
155  body_name = prefix + "_" + ob.name
156  visual_name = body_name + ".dae"
157  self.exportDAE(ob, visual_name, mesh_dir)
158 
159  collision_name = ob.name + self.collision_suffix
160  try:
161  collision_file = bpy.data.objects[collision_name]
162  print("Found custom collision mesh")
163  collision_name = body_name + self.collision_suffix + ".stl"
164  self.exportSTL(collision_file, collision_name, mesh_dir)
165  except:
166  collision_name = visual_name
167 
168  self.writeURDF(body_name, package_name, visual_name, collision_name, urdf_dir)
169  self.writeLaunch(body_name, package_name, launch_dir)
170  world_launch.append(ET.Element("include", attrib={"file": "$(find " + package_name + ")/launch/spawn_" + body_name + ".launch"}))
171 
172  outFile = open(launch_dir + "/" + prefix + ".launch", 'wb')
173  outFile.write(ET.tostring(world_launch))
174  outFile.close()
175 
176  return {'FINISHED'}
177 
178 def menu_func(self, context):
179  self.layout.operator(GazeboExport.bl_idname, text="Gazebo Launch (.launch)");
180 
181 def register():
182  bpy.utils.register_class(GazeboExport)
183  bpy.types.TOPBAR_MT_file_export.append(menu_func)
184 
186  bpy.utils.unregister_class(GazeboExport)
187  bpy.types.TOPBAR_MT_file_export.remove(menu_func);
188 
189 if __name__ == "__main__" :
190  register()
def exportDAE(self, ob, name, dir)
def execute(self, context)
def exportSTL(self, ob, name, dir)
def menu_func(self, context)
def writeLaunch(self, name, package_name, launch_dir)
def getPackagePaths(self, launch_file, make_dirs=True)
def writeURDF(self, name, package_name, visual, collision, urdf_dir)


blender_gazebo
Author(s):
autogenerated on Tue Dec 10 2019 03:17:51