WUT Velma robot API
create_gazebo_ar_markers.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 
6 
7 # Copyright (c) 2021, Robot Control and Pattern Recognition Group,
8 # Institute of Control and Computation Engineering
9 # Warsaw University of Technology
10 #
11 # All rights reserved.
12 #
13 # Redistribution and use in source and binary forms, with or without
14 # modification, are permitted provided that the following conditions are met:
15 # * Redistributions of source code must retain the above copyright
16 # notice, this list of conditions and the following disclaimer.
17 # * Redistributions in binary form must reproduce the above copyright
18 # notice, this list of conditions and the following disclaimer in the
19 # documentation and/or other materials provided with the distribution.
20 # * Neither the name of the Warsaw University of Technology nor the
21 # names of its contributors may be used to endorse or promote products
22 # derived from this software without specific prior written permission.
23 #
24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 # DISCLAIMED. IN NO EVENT SHALL <COPYright HOLDER> BE LIABLE FOR ANY
28 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #
35 # Author: Dawid Seredynski
36 #
37 
38 import roslib; roslib.load_manifest('rcprg_gazebo_utils')
39 
40 import sys
41 import rospy
42 import math
43 import copy
44 import tf
45 
46 from std_msgs.msg import ColorRGBA
49 from visualization_msgs.msg import *
50 from geometry_msgs.msg import *
51 from tf.transformations import *
52 import tf_conversions.posemath as pm
53 import PyKDL
55 import actionlib
56 from gazebo_msgs.srv import *
57 
58 
59 import os
60 import subprocess
61 
62 def getMarkerModelName(size_cm, marker_id):
63  return 'ar_marker_{}cm_{}'.format(size_cm, marker_id)
64 
65 def getMeshFilename(size_cm):
66  return 'ar_marker_{}cm.dae'.format(size_cm)
67 
68 def getMaterialFilename(marker_id):
69  return 'MarkerData_{}.png'.format(marker_id)
70 
71 def generateModelConfig(size_cm, marker_id):
72  return '<?xml version="1.0"?>\n' +\
73  '<model>\n' +\
74  ' <name>AR Marker {}cm {}</name>\n'.format(size_cm, marker_id) +\
75  ' <version>1.0</version>\n' +\
76  ' <sdf version="1.5">model.sdf</sdf>\n' +\
77  ' <author>\n' +\
78  ' <name>Dawid Seredynski</name>\n' +\
79  ' <email>dawid.seredynski(at)gmail.com</email>\n' +\
80  ' </author>\n' +\
81  ' <description>\n' +\
82  ' AR marker {}cm {}.\n'.format(size_cm, marker_id) +\
83  ' </description>\n' +\
84  '</model>\n'
85 
86 def generateSdf(size_cm, marker_id):
87  return '<?xml version="1.0" ?>\n' +\
88  '<sdf version="1.5">\n' +\
89  ' <model name="{}">\n'.format( getMarkerModelName(size_cm, marker_id) ) +\
90  ' <link name="link">\n' +\
91  ' <gravity>false</gravity>\n' +\
92  ' <inertial>\n' +\
93  ' <pose>0 0 0 0 0 0</pose>\n' +\
94  ' <mass>0.01</mass>\n' +\
95  ' <inertia>\n' +\
96  ' <ixx>0.000079</ixx>\n' +\
97  ' <ixy>0</ixy>\n' +\
98  ' <ixz>0</ixz>\n' +\
99  ' <iyy>0.000079</iyy>\n' +\
100  ' <iyz>0</iyz>\n' +\
101  ' <izz>0.000025</izz>\n' +\
102  ' </inertia>\n' +\
103  ' </inertial>\n' +\
104  ' <visual name="visual">\n' +\
105  ' <pose>0 0 0 0 0 0</pose>\n' +\
106  ' <geometry>\n' +\
107  ' <mesh>\n' +\
108  ' <uri>model://{}/meshes/{}</uri>\n'.format(
109  getMarkerModelName(size_cm, marker_id), getMeshFilename(size_cm)) +\
110  ' </mesh>\n' +\
111  ' </geometry>\n' +\
112  ' </visual>\n' +\
113  ' </link>\n' +\
114  ' </model>\n' +\
115  '</sdf>\n'
116 
117 def generateMesh(size_cm, marker_id):
118  return '<?xml version="1.0" encoding="utf-8"?>\n' +\
119  '<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\n' +\
120  ' <asset>\n' +\
121  ' <contributor>\n' +\
122  ' <author>Blender User</author>\n' +\
123  ' <authoring_tool>Blender 2.91.0 commit date:2020-11-25, commit time:08:34, hash:0f45cab862b8</authoring_tool>\n' +\
124  ' </contributor>\n' +\
125  ' <created>2021-05-19T08:11:01</created>\n' +\
126  ' <modified>2021-05-19T08:11:01</modified>\n' +\
127  ' <unit name="meter" meter="1"/>\n' +\
128  ' <up_axis>Z_UP</up_axis>\n' +\
129  ' </asset>\n' +\
130  ' <library_effects>\n' +\
131  ' <effect id="Material_002-effect">\n' +\
132  ' <profile_COMMON>\n' +\
133  ' <newparam sid="markerdata_png-surface">\n' +\
134  ' <surface type="2D">\n' +\
135  ' <init_from>markerdata_png</init_from>\n' +\
136  ' </surface>\n' +\
137  ' </newparam>\n' +\
138  ' <newparam sid="markerdata_png-sampler">\n' +\
139  ' <sampler2D>\n' +\
140  ' <source>markerdata_png-surface</source>\n' +\
141  ' </sampler2D>\n' +\
142  ' </newparam>\n' +\
143  ' <technique sid="common">\n' +\
144  ' <lambert>\n' +\
145  ' <emission>\n' +\
146  ' <color sid="emission">0 0 0 1</color>\n' +\
147  ' </emission>\n' +\
148  ' <diffuse>\n' +\
149  ' <texture texture="markerdata_png-sampler" texcoord="Cylinder-mesh-map-0"/>\n' +\
150  ' </diffuse>\n' +\
151  ' <index_of_refraction>\n' +\
152  ' <float sid="ior">1</float>\n' +\
153  ' </index_of_refraction>\n' +\
154  ' </lambert>\n' +\
155  ' </technique>\n' +\
156  ' </profile_COMMON>\n' +\
157  ' </effect>\n' +\
158  ' <effect id="Material_001-effect">\n' +\
159  ' <profile_COMMON>\n' +\
160  ' <technique sid="common">\n' +\
161  ' <lambert>\n' +\
162  ' <emission>\n' +\
163  ' <color sid="emission">0 0 0 1</color>\n' +\
164  ' </emission>\n' +\
165  ' <diffuse>\n' +\
166  ' <color sid="diffuse">0.512 0.512 0.512 1</color>\n' +\
167  ' </diffuse>\n' +\
168  ' <index_of_refraction>\n' +\
169  ' <float sid="ior">1</float>\n' +\
170  ' </index_of_refraction>\n' +\
171  ' </lambert>\n' +\
172  ' </technique>\n' +\
173  ' </profile_COMMON>\n' +\
174  ' </effect>\n' +\
175  ' </library_effects>\n' +\
176  ' <library_images>\n' +\
177  ' <image id="markerdata_png" name="markerdata_png">\n' +\
178  ' <init_from>../materials/{}</init_from>\n'.format( getMaterialFilename(marker_id) ) +\
179  ' </image>\n' +\
180  ' </library_images>\n' +\
181  ' <library_materials>\n' +\
182  ' <material id="Material_002-material" name="Material_002">\n' +\
183  ' <instance_effect url="#Material_002-effect"/>\n' +\
184  ' </material>\n' +\
185  ' <material id="Material_001-material" name="Material_001">\n' +\
186  ' <instance_effect url="#Material_001-effect"/>\n' +\
187  ' </material>\n' +\
188  ' </library_materials>\n' +\
189  ' <library_geometries>\n' +\
190  ' <geometry id="Cylinder-mesh" name="Cylinder">\n' +\
191  ' <mesh>\n' +\
192  ' <source id="Cylinder-mesh-positions">\n' +\
193  ' <float_array id="Cylinder-mesh-positions-array" count="24">-0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5 0.5 0.5 0.5 0.5 -0.5 0.5</float_array>\n' +\
194  ' <technique_common>\n' +\
195  ' <accessor source="#Cylinder-mesh-positions-array" count="8" stride="3">\n' +\
196  ' <param name="X" type="float"/>\n' +\
197  ' <param name="Y" type="float"/>\n' +\
198  ' <param name="Z" type="float"/>\n' +\
199  ' </accessor>\n' +\
200  ' </technique_common>\n' +\
201  ' </source>\n' +\
202  ' <source id="Cylinder-mesh-normals">\n' +\
203  ' <float_array id="Cylinder-mesh-normals-array" count="18">-1 0 0 0 1 0 1 0 0 0 -1 0 0 0 -1 0 0 1</float_array>\n' +\
204  ' <technique_common>\n' +\
205  ' <accessor source="#Cylinder-mesh-normals-array" count="6" stride="3">\n' +\
206  ' <param name="X" type="float"/>\n' +\
207  ' <param name="Y" type="float"/>\n' +\
208  ' <param name="Z" type="float"/>\n' +\
209  ' </accessor>\n' +\
210  ' </technique_common>\n' +\
211  ' </source>\n' +\
212  ' <source id="Cylinder-mesh-map-0">\n' +\
213  ' <float_array id="Cylinder-mesh-map-0-array" count="72">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.9998999 9.998e-5 0.9999001 0.9998999 1.00099e-4 0.9998999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9.998e-5 1.0001e-4 0.9998999 9.998e-5 1.00099e-4 0.9998999</float_array>\n' +\
214  ' <technique_common>\n' +\
215  ' <accessor source="#Cylinder-mesh-map-0-array" count="36" stride="2">\n' +\
216  ' <param name="S" type="float"/>\n' +\
217  ' <param name="T" type="float"/>\n' +\
218  ' </accessor>\n' +\
219  ' </technique_common>\n' +\
220  ' </source>\n' +\
221  ' <vertices id="Cylinder-mesh-vertices">\n' +\
222  ' <input semantic="POSITION" source="#Cylinder-mesh-positions"/>\n' +\
223  ' </vertices>\n' +\
224  ' <triangles material="Material_002-material" count="12">\n' +\
225  ' <input semantic="VERTEX" source="#Cylinder-mesh-vertices" offset="0"/>\n' +\
226  ' <input semantic="NORMAL" source="#Cylinder-mesh-normals" offset="1"/>\n' +\
227  ' <input semantic="TEXCOORD" source="#Cylinder-mesh-map-0" offset="2" set="0"/>\n' +\
228  ' <p>4 0 0 5 0 1 1 0 2 5 1 3 6 1 4 2 1 5 6 2 6 7 2 7 3 2 8 7 3 9 4 3 10 0 3 11 0 4 12 1 4 13 2 4 14 7 5 15 6 5 16 5 5 17 0 0 18 4 0 19 1 0 20 1 1 21 5 1 22 2 1 23 2 2 24 6 2 25 3 2 26 3 3 27 7 3 28 0 3 29 3 4 30 0 4 31 2 4 32 4 5 33 7 5 34 5 5 35</p>\n' +\
229  ' </triangles>\n' +\
230  ' </mesh>\n' +\
231  ' </geometry>\n' +\
232  ' </library_geometries>\n' +\
233  ' <library_visual_scenes>\n' +\
234  ' <visual_scene id="Scene" name="Scene">\n' +\
235  ' <node id="Cylinder" name="Cylinder" type="NODE">\n' +\
236  ' <matrix sid="transform">{} 0 0 0 0 {} 0 0 0 0 {} 0 0 0 0 1</matrix>\n'.format(0.01*size_cm, 0.01*size_cm, 0.002) +\
237  ' <instance_geometry url="#Cylinder-mesh" name="Cylinder">\n' +\
238  ' <bind_material>\n' +\
239  ' <technique_common>\n' +\
240  ' <instance_material symbol="Material_002-material" target="#Material_002-material">\n' +\
241  ' <bind_vertex_input semantic="Cylinder-mesh-map-0" input_semantic="TEXCOORD" input_set="0"/>\n' +\
242  ' </instance_material>\n' +\
243  ' <instance_material symbol="Material_001-material" target="#Material_001-material">\n' +\
244  ' <bind_vertex_input semantic="Cylinder-mesh-map-0" input_semantic="TEXCOORD" input_set="0"/>\n' +\
245  ' </instance_material>\n' +\
246  ' </technique_common>\n' +\
247  ' </bind_material>\n' +\
248  ' </instance_geometry>\n' +\
249  ' </node>\n' +\
250  ' </visual_scene>\n' +\
251  ' </library_visual_scenes>\n' +\
252  ' <scene>\n' +\
253  ' <instance_visual_scene url="#Scene"/>\n' +\
254  ' </scene>\n' +\
255  '</COLLADA>'
256 
257 def createMaterialFile(path, size_cm, marker_id):
258  subprocess.call(['rosrun', 'ar_track_alvar', 'createMarker', '-s', str(size_cm), str(marker_id)],
259  cwd=path)
260 
261 def createMarkerGazeboModel(path, size_cm, marker_id):
262  dir_name = getMarkerModelName(size_cm, marker_id)
263  path_in = path + '/' + dir_name
264 
265  try:
266  os.mkdir(path_in)
267  except OSError:
268  print ("Creation of the directory %s failed" % path)
269  return False
270  else:
271  print ("Successfully created the directory %s " % path)
272 
273  with open(path_in + '/model.config', 'w') as f:
274  f.write( generateModelConfig(size_cm, marker_id) )
275 
276  with open(path_in + '/model.sdf', 'w') as f:
277  f.write( generateSdf(size_cm, marker_id) )
278 
279  path_meshes = path_in + '/meshes'
280  os.mkdir(path_meshes)
281  with open(path_meshes + '/' + getMeshFilename(size_cm), 'w') as f:
282  f.write( generateMesh(size_cm, marker_id) )
283 
284  path_materials = path_in + '/materials'
285  os.mkdir(path_materials)
286  createMaterialFile(path_materials, size_cm, marker_id)
287 
288 if __name__ == "__main__":
289 
290  for marker_id in range(0, 35):
291  createMarkerGazeboModel('.', 8, marker_id)
292  exit(0)
293 
def getMarkerModelName(size_cm, marker_id)
def createMarkerGazeboModel(path, size_cm, marker_id)
def generateModelConfig(size_cm, marker_id)
def createMaterialFile(path, size_cm, marker_id)