PageRenderTime 40ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/udom_utils/udom_visualization/src/udom_visualization/mesh_publisher_gui_node.py

https://gitlab.com/jsanch/udom
Python | 228 lines | 180 code | 15 blank | 33 comment | 0 complexity | f3b8415779a921dd6e60c9f1123f26ea MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- encoding: utf-8 -*-
  3. """
  4. This node publishes a configuration of a mesh based on .ele and .node files.
  5. The mesh configuration can be changed at run-time using via a GUI.
  6. **Output(s):**
  7. * `mesh`: The published mesh.
  8. - *type:* `udom_modeling_msgs/Mesh`
  9. **Parameter(s):**
  10. * `loop_rate`: Node cycle rate (in Hz).
  11. * `zero_index`: Whether the elements index start from zero (false means they start from one).
  12. * `mesh_config`: The name of the folder containing a .ele and a .node file with the same
  13. name as the directory, which describe the configuration of the mesh. The path is assumed
  14. to be the `config` directory of this package.
  15. """
  16. import threading
  17. import Tkinter
  18. import numpy as np
  19. import csv
  20. import rospy
  21. import rospkg
  22. import std_msgs.msg
  23. import geometry_msgs.msg
  24. import udom_modeling_msgs.msg
  25. ros_pack = rospkg.RosPack()
  26. package_path = ros_pack.get_path('udom_visualization')
  27. mesh = udom_modeling_msgs.msg.Mesh()
  28. mesh_file = 'bar_rest'
  29. event = std_msgs.msg.String()
  30. global lock
  31. lock = threading.Lock()
  32. def create_window():
  33. """
  34. Creates a GUI window to publish a pose.
  35. """
  36. master = Tkinter.Tk()
  37. # Mesh entry.
  38. mesh_entry = Tkinter.Entry(master)
  39. mesh_entry.insert(Tkinter.END, mesh_file)
  40. mesh_entry.grid(row=1, column=0)
  41. upload_button = Tkinter.Button(
  42. master, text='Update', command=(lambda e=mesh_entry: load_mesh_cb(e)))
  43. upload_button.grid(row=2, column=0)
  44. # Event buttons.
  45. start_button = Tkinter.Button(master, command=start_cb, text="START")
  46. stop_button = Tkinter.Button(master, command=stop_cb, text="STOP")
  47. reset_button = Tkinter.Button(master, command=reset_cb, text="RESET")
  48. start_button.grid(row=0, column=1)
  49. stop_button.grid(row=1, column=1)
  50. reset_button.grid(row=2, column=1)
  51. master.title("Mesh selector")
  52. master.mainloop()
  53. rospy.signal_shutdown("GUI closed")
  54. def load_mesh_cb(entry):
  55. """
  56. Loads the mesh.
  57. :param entry: The entry object containing the mesh to be uploaded.
  58. :type entry: Tkinter.Entry
  59. """
  60. global lock
  61. lock.acquire()
  62. mesh_file = entry.get()
  63. config_path = package_path + '/config/' + mesh_file + '/'
  64. # TODO: handle the case where zero_index is False
  65. update_mesh(mesh, config_path, mesh_file)
  66. event.data = 'e_start'
  67. lock.release()
  68. def start_cb():
  69. """
  70. Updates the event to 'e_start'.
  71. """
  72. global lock
  73. lock.acquire()
  74. event.data = 'e_start'
  75. lock.release()
  76. def stop_cb():
  77. """
  78. Updates the event to 'e_stop'.
  79. """
  80. global lock
  81. lock.acquire()
  82. event.data = 'e_stop'
  83. lock.release()
  84. def reset_cb():
  85. """
  86. Updates the event to 'e_reset'.
  87. """
  88. global lock
  89. lock.acquire()
  90. event.data = 'e_reset'
  91. lock.release()
  92. def publish_nodal_forces():
  93. """
  94. Publishes the nodal forces.
  95. """
  96. # Node cycle rate (in Hz).
  97. loop_rate = rospy.Rate(rospy.get_param('~loop_rate', 100))
  98. # Publishers
  99. pub_mesh = rospy.Publisher(
  100. "~mesh", udom_modeling_msgs.msg.Mesh, queue_size=10)
  101. pub_event_out = rospy.Publisher('~event_out', std_msgs.msg.String, queue_size=10)
  102. mesh_path = package_path + '/config/' + mesh_file + '/'
  103. update_mesh(mesh, mesh_path, mesh_file)
  104. while not rospy.is_shutdown():
  105. pub_mesh.publish(mesh)
  106. if event.data:
  107. pub_event_out.publish(event)
  108. event.data = ""
  109. loop_rate.sleep()
  110. def update_mesh(mesh_, file_dir, filename):
  111. """
  112. Updates the configuration of the mesh from 'file_dir' assuming it
  113. contains the .ele and .nodes files. It returns the mesh as a
  114. udom_modeling_msgs.msg.Mesh message.
  115. :param mesh_: The mesh to update.
  116. :type mesh_: udom_modeling_msgs.msg.Mesh
  117. :param file_dir: Absolute path to the directory with the .ele and .node
  118. files of the mesh to upload.
  119. :type file_dir: str
  120. :param filename: Filename of the .ele and .node files.
  121. :type filename: str
  122. :return: The uploaded mesh.
  123. :rtype: udom_modeling_msgs.msg.Mesh()
  124. """
  125. elements_file = file_dir + filename + '.ele'
  126. nodes_file = file_dir + filename + '.node'
  127. try:
  128. open(elements_file)
  129. open(nodes_file)
  130. except IOError as e:
  131. rospy.logerr("Error: {}".format(e))
  132. rospy.logwarn("Keeping current mesh.")
  133. return mesh_
  134. # Reset mesh.
  135. mesh_.vertices = []
  136. mesh_.tetrahedra = []
  137. first_line = True
  138. index = 0
  139. # Process elements
  140. with open(elements_file) as csv_file:
  141. reader = csv.reader(csv_file, delimiter=' ')
  142. # Skip header
  143. next(reader)
  144. for row in reader:
  145. if first_line:
  146. index = int(row[0])
  147. first_line = False
  148. # Skip empty lines
  149. if not ''.join(row).strip():
  150. continue
  151. # Get the values for the element columns and ignore the rest.
  152. rows = np.array(map(int, row[1:5]))
  153. if index:
  154. rows -= index
  155. tetrahedra = udom_modeling_msgs.msg.MeshTetrahedron(rows)
  156. mesh_.tetrahedra.append(tetrahedra)
  157. # Process nodes
  158. with open(nodes_file) as csv_file:
  159. reader = csv.reader(csv_file, delimiter=' ')
  160. # Skip header
  161. next(reader)
  162. for row in reader:
  163. # Skip empty lines
  164. if not ''.join(row).strip():
  165. continue
  166. rows = np.array(map(float, row[-3:]))
  167. point = geometry_msgs.msg.Point(x=rows[0], y=rows[1], z=rows[2])
  168. mesh_.vertices.append(point)
  169. return mesh_
  170. def main():
  171. rospy.init_node('nodal_forces_mock_up')
  172. import thread
  173. try:
  174. thread.start_new_thread(create_window, tuple())
  175. publish_nodal_forces()
  176. except rospy.ROSInterruptException:
  177. pass