PageRenderTime 64ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/udom_demo/udom_deformation_sensing/src/udom_deformation_sensing/coordinator.py

https://gitlab.com/jsanch/udom
Python | 298 lines | 244 code | 4 blank | 50 comment | 1 complexity | 103d8a458f4b70bce21d199f1fcc5d25 MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- encoding: utf-8 -*-
  3. """
  4. This node uses a pipeline of components to demonstrate deformation sensing.
  5. The component serves as a configurator/coordinator, i.e. it sets the required
  6. parameters for all the components and starts/stops them accordingly.
  7. It uses the following nodes:
  8. * `udom_sensor_model/tactile_sensor_model`
  9. * `udom_contact_model/contact_model`
  10. * `udom_topic_tools/force_merger`
  11. * `udom_geometric_transformation/force_transformer`
  12. * `udom_geometric_transformation/nodal_force_calculator`
  13. * `udom_deformation_modeling/deformation_model`
  14. **Assumptions:**
  15. * It assumes a BioTac sensor as the input sensor.
  16. **Input(s):**
  17. * `tactile_info`: The output data of a BioTac sensor.
  18. - *type:* `udom_perception_msgs/BiotacStamped`
  19. * `event_in`: The desired event for the node:
  20. `e_start`: starts the component.
  21. `e_stop`: stops the component.
  22. **Output(s):**
  23. * `mesh`: A mesh representation of the object with the updated nodes' position based
  24. on the deformation.
  25. - *type:* `udom_modeling_msgs/Mesh`
  26. * `event_out`: The current event of the node.
  27. `e_running`: when the component is running.
  28. `e_stopped`: when the component is stopped.
  29. - *type:* `std_msgs/String`
  30. **Parameter(s):**
  31. * `loop_rate`: Node cycle rate (in Hz).
  32. * `mesh_filename`: Filename of the volumetric mesh in a .veg format. **Note:** This file
  33. should be located in the config directory of the `deformation_sensing` package.
  34. * `reference_frame`: Reference frame of the object.
  35. * `constrained_nodes`: Constrained vertices of the mesh. Each constrained node must
  36. specify its three degrees of freedom. E.g., to constrain vertices 4, 10 and 14 the
  37. constrained_nodes should be [12, 13, 14, 30, 31, 32, 42, 43, 44].
  38. """
  39. import rospy
  40. import std_msgs.msg
  41. class Coordinator(object):
  42. """
  43. Coordinates a set of components to estimate the deformation of an object caused by
  44. an external force.
  45. """
  46. def __init__(self):
  47. """
  48. Instantiates a node to coordinate the components of the deformation sensing
  49. pipeline.
  50. """
  51. # Params
  52. self.started_components = False
  53. self.event = None
  54. self.tactile_demux_status = None
  55. self.sensor_model_status = None
  56. self.contact_model_status = None
  57. self.force_merger_status = None
  58. self.force_transformer_status = None
  59. self.nodal_force_calculator_status = None
  60. self.deformation_model_status = None
  61. # Node cycle rate (in Hz).
  62. self.loop_rate = rospy.Rate(rospy.get_param('~loop_rate', 10))
  63. # Publishers
  64. self.event_out = rospy.Publisher("~event_out", std_msgs.msg.String, queue_size=10)
  65. self.start_tactile_demux = rospy.Publisher(
  66. "~start_tactile_demux", std_msgs.msg.String, queue_size=10, latch=True)
  67. self.start_sensor_model = rospy.Publisher(
  68. "~start_sensor_model", std_msgs.msg.String, queue_size=10, latch=True)
  69. self.start_contact_model = rospy.Publisher(
  70. "~start_contact_model", std_msgs.msg.String, queue_size=10, latch=True)
  71. self.start_force_merger = rospy.Publisher(
  72. "~start_force_merger", std_msgs.msg.String, queue_size=10, latch=True)
  73. self.start_force_transformer = rospy.Publisher(
  74. "~start_force_transformer", std_msgs.msg.String, queue_size=10, latch=True)
  75. self.start_nodal_force_calculator = rospy.Publisher(
  76. "~start_nodal_force_calculator", std_msgs.msg.String, queue_size=10, latch=True)
  77. self.start_deformation_model = rospy.Publisher(
  78. "~start_deformation_model", std_msgs.msg.String, queue_size=10, latch=True)
  79. # Subscribers
  80. rospy.Subscriber("~event_in", std_msgs.msg.String, self.event_in_cb)
  81. rospy.Subscriber(
  82. "~tactile_demux_status", std_msgs.msg.String, self.tactile_demux_status_cb)
  83. rospy.Subscriber(
  84. "~sensor_model_status", std_msgs.msg.String, self.sensor_model_status_cb)
  85. rospy.Subscriber(
  86. "~contact_model_status", std_msgs.msg.String, self.contact_model_status_cb)
  87. rospy.Subscriber(
  88. "~force_merger_status", std_msgs.msg.String, self.force_merger_status_cb)
  89. rospy.Subscriber(
  90. "~force_transformer_status", std_msgs.msg.String,
  91. self.force_transformer_status_cb)
  92. rospy.Subscriber(
  93. "~nodal_force_calculator_status", std_msgs.msg.String,
  94. self.nodal_force_calculator_status_cb)
  95. rospy.Subscriber(
  96. "~deformation_model_status", std_msgs.msg.String,
  97. self.deformation_model_status_cb)
  98. def event_in_cb(self, msg):
  99. """
  100. Obtains an event for the component.
  101. :param msg: Event message for the node.
  102. :type msg: std_msgs.msg.String
  103. """
  104. self.event = msg.data
  105. def tactile_demux_status_cb(self, msg):
  106. """
  107. Obtains the status of the tactile demux (as an event).
  108. :param msg: Event message for the node.
  109. :type msg: std_msgs.msg.String
  110. """
  111. self.tactile_demux_status = msg.data
  112. def sensor_model_status_cb(self, msg):
  113. """
  114. Obtains the status of the sensor model (as an event).
  115. :param msg: Event message for the node.
  116. :type msg: std_msgs.msg.String
  117. """
  118. self.sensor_model_status = msg.data
  119. def contact_model_status_cb(self, msg):
  120. """
  121. Obtains the status of the contact model (as an event).
  122. :param msg: Event message for the node.
  123. :type msg: std_msgs.msg.String
  124. """
  125. self.contact_model_status = msg.data
  126. def force_merger_status_cb(self, msg):
  127. """
  128. Obtains the status of the force merger (as an event).
  129. :param msg: Event message for the node.
  130. :type msg: std_msgs.msg.String
  131. """
  132. self.force_merger_status = msg.data
  133. def force_transformer_status_cb(self, msg):
  134. """
  135. Obtains the status of the force transformer (as an event).
  136. :param msg: Event message for the node.
  137. :type msg: std_msgs.msg.String
  138. """
  139. self.force_transformer_status = msg.data
  140. def nodal_force_calculator_status_cb(self, msg):
  141. """
  142. Obtains the status of the nodal force calculator (as an event).
  143. :param msg: Event message for the node.
  144. :type msg: std_msgs.msg.String
  145. """
  146. self.nodal_force_calculator_status = msg.data
  147. def deformation_model_status_cb(self, msg):
  148. """
  149. Obtains the status of the deformation model (as an event).
  150. :param msg: Event message for the node.
  151. :type msg: std_msgs.msg.String
  152. """
  153. self.deformation_model_status = msg.data
  154. def start(self):
  155. """
  156. Starts the component.
  157. """
  158. rospy.loginfo("Ready to start...")
  159. state = 'INIT'
  160. while not rospy.is_shutdown():
  161. if state == 'INIT':
  162. state = self.init_state()
  163. elif state == 'RUNNING':
  164. state = self.running_state()
  165. rospy.logdebug("State: {0}".format(state))
  166. self.loop_rate.sleep()
  167. def init_state(self):
  168. """
  169. Executes the INIT state of the state machine.
  170. :return: The updated state.
  171. :rtype: str
  172. """
  173. if self.event in ['e_start', 'e_reset']:
  174. return 'RUNNING'
  175. else:
  176. return 'INIT'
  177. def running_state(self):
  178. """
  179. Executes the RUNNING state of the state machine.
  180. :return: The updated state.
  181. :rtype: str
  182. """
  183. self.toggle_components(self.event)
  184. if self.event == 'e_stop':
  185. status = 'e_stopped'
  186. self.event_out.publish(status)
  187. self.reset_component_data(status)
  188. return 'INIT'
  189. else:
  190. return 'RUNNING'
  191. def toggle_components(self, event):
  192. """
  193. Starts or stops the necessary components based on the event.
  194. :param event: The event that determines either to start or stop the components.
  195. :type event: str
  196. """
  197. if event == 'e_stop':
  198. self.start_tactile_demux.publish('e_stop')
  199. self.start_sensor_model.publish('e_stop')
  200. self.start_contact_model.publish('e_stop')
  201. self.start_force_merger.publish('e_stop')
  202. self.start_force_transformer.publish('e_stop')
  203. self.start_nodal_force_calculator.publish('e_stop')
  204. self.start_deformation_model.publish('e_stop')
  205. self.started_components = False
  206. if event == 'e_reset':
  207. self.start_deformation_model.publish('e_reset')
  208. self.event = 'e_start'
  209. self.started_components = False
  210. if event == 'e_start' and not self.started_components:
  211. self.start_tactile_demux.publish('e_start')
  212. self.start_sensor_model.publish('e_start')
  213. self.start_contact_model.publish('e_start')
  214. self.start_force_merger.publish('e_start')
  215. self.start_force_transformer.publish('e_start')
  216. self.start_nodal_force_calculator.publish('e_start')
  217. self.start_deformation_model.publish('e_start')
  218. self.started_components = True
  219. def reset_component_data(self, result):
  220. """
  221. Clears the data of the component.
  222. :param result: The result of the component, e.g. stopped, failure, success.
  223. :type result: str
  224. """
  225. self.toggle_components(result)
  226. self.event = None
  227. self.tactile_demux_status = None
  228. self.sensor_model_status = None
  229. self.contact_model_status = None
  230. self.force_merger_status = None
  231. self.force_transformer_status = None
  232. self.nodal_force_calculator_status = None
  233. self.deformation_model_status = None
  234. self.started_components = False
  235. def main():
  236. rospy.init_node("coordinator", anonymous=True)
  237. coordinator = Coordinator()
  238. coordinator.start()