You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
5.3 KiB

  1. ## Example 4
  2. !!! note
  3. ROS 2 tutorials are still under active development.
  4. ![image](https://raw.githubusercontent.com/hello-robot/stretch_tutorials/ROS2/images/balloon.png)
  5. Let's bring up Stretch in RViz by using the following command.
  6. ```{.bash .shell-prompt}
  7. ros2 launch stretch_core stretch_driver.launch.py
  8. ros2 run rviz2 rviz2 -d `ros2 pkg prefix stretch_calibration`/share/stretch_calibration/rviz/stretch_simple_test.rviz
  9. ```
  10. In a new terminal run the following commands to create a marker.
  11. ```{.bash .shell-prompt}
  12. ros2 run stretch_ros_tutorials marker
  13. ```
  14. The gif below demonstrates how to add a new *Marker* display type, and change the topic name from `visualization_marker` to `balloon`. A red sphere Marker should appear above the Stretch robot.
  15. ![image](https://raw.githubusercontent.com/hello-robot/stretch_tutorials/ROS2/images/balloon.gif)
  16. ### The Code
  17. ```python
  18. #!/usr/bin/env python3
  19. import rclpy
  20. from rclpy.node import Node
  21. from visualization_msgs.msg import Marker
  22. class Balloon(Node):
  23. def __init__(self):
  24. super().__init__('stretch_marker')
  25. self.publisher_ = self.create_publisher(Marker, 'balloon', 10)
  26. self.marker = Marker()
  27. self.marker.header.frame_id = '/base_link'
  28. self.marker.header.stamp = self.get_clock().now().to_msg()
  29. self.marker.type = self.marker.SPHERE
  30. self.marker.id = 0
  31. self.marker.action = self.marker.ADD
  32. self.marker.scale.x = 0.5
  33. self.marker.scale.y = 0.5
  34. self.marker.scale.z = 0.5
  35. self.marker.color.r = 1.0
  36. self.marker.color.g = 0.0
  37. self.marker.color.b = 0.0
  38. self.marker.color.a = 1.0
  39. self.marker.pose.position.x = 0.0
  40. self.marker.pose.position.y = 0.0
  41. self.marker.pose.position.z = 2.0
  42. self.get_logger().info("Publishing the balloon topic. Use RViz to visualize.")
  43. def publish_marker(self):
  44. self.publisher_.publish(self.marker)
  45. def main(args=None):
  46. rclpy.init(args=args)
  47. balloon = Balloon()
  48. while rclpy.ok():
  49. balloon.publish_marker()
  50. balloon.destroy_node()
  51. rclpy.shutdown()
  52. if __name__ == '__main__':
  53. main()
  54. ```
  55. ### The Code Explained
  56. Now let's break the code down.
  57. ```python
  58. #!/usr/bin/env python3
  59. ```
  60. Every Python ROS [Node](http://docs.ros.org/en/humble/Tutorials/Beginner-CLI-Tools/Understanding-ROS2-Nodes/Understanding-ROS2-Nodes.html) will have this declaration at the top. The first line makes sure your script is executed as a Python script.
  61. ```python
  62. import rclpy
  63. from rclpy.node import Node
  64. from visualization_msgs.msg import Marker
  65. ```
  66. You need to import rclpy if you are writing a ROS 2 Node. Import the `Marker` type from the visualization_msgs.msg package. This import is required to publish a Marker, which will be visualized in RViz.
  67. ```python
  68. self.publisher_ = self.create_publisher(Marker, 'balloon', 10)
  69. ```
  70. This declares that your node is publishing to the */ballon* topic using the message type *Twist*.
  71. ```python
  72. self.marker = Marker()
  73. self.marker.header.frame_id = '/base_link'
  74. self.marker.header.stamp = self.get_clock().now().to_msg()
  75. self.marker.type = self.marker.SPHERE
  76. ```
  77. Create a maker. Markers of all shapes share a common type. Set the frame ID and type. The frame ID is the frame in which the position of the marker is specified. The type is the shape of the marker. Further details on marker shapes can be found here: [RViz Markers](http://wiki.ros.org/rviz/DisplayTypes/Marker)
  78. ```python
  79. self.marker.id = 0
  80. ```
  81. Each marker has a unique ID number. If you have more than one marker that you want displayed at a given time, then each needs to have a unique ID number. If you publish a new marker with the same ID number of an existing marker, it will replace the existing marker with that ID number.
  82. ```python
  83. self.marker.action = self.marker.ADD
  84. ```
  85. This line of code sets the action. You can add, delete, or modify markers.
  86. ```python
  87. self.marker.scale.x = 0.5
  88. self.marker.scale.y = 0.5
  89. self.marker.scale.z = 0.5
  90. ```
  91. These are the size parameters for the marker. These will vary by marker type.
  92. ```python
  93. self.marker.color.r = 1.0
  94. self.marker.color.g = 0.0
  95. self.marker.color.b = 0.0
  96. ```
  97. Color of the object, specified as r/g/b/a, with values in the range of [0, 1].
  98. ```python
  99. self.marker.color.a = 1.0
  100. ```
  101. The alpha value is from 0 (invisible) to 1 (opaque). If you don't set this then it will automatically default to zero, making your marker invisible.
  102. ```python
  103. self.marker.pose.position.x = 0.0
  104. self.marker.pose.position.y = 0.0
  105. self.marker.pose.position.z = 2.0
  106. ```
  107. Specify the pose of the marker. Since spheres are rotationally invariant, we're only going to specify the positional elements. As usual, these are in the coordinate frame named in frame_id. In this case, the position will always be directly 2 meters above the frame_id (*base_link*), and will move with it.
  108. ```python
  109. def publish_marker(self):
  110. self.publisher_.publish(self.marker)
  111. ```
  112. Publish the Marker data structure to be visualized in RViz.
  113. ```python
  114. def main(args=None):
  115. rclpy.init(args=args)
  116. balloon = Balloon()
  117. ```
  118. The next line, rospy.init. In this case, your node will take on the name talker. NOTE: the name must be a base name, i.e. it cannot contain any slashes "/".
  119. Setup Balloon class with `balloon = Balloon()`
  120. ```python
  121. while rclpy.ok():
  122. balloon.publish_marker()
  123. balloon.destroy_node()
  124. rclpy.shutdown()
  125. ```
  126. This loop is a fairly standard rclpy construct: checking the rclpy.ok() flag and then doing work. You have to run this check to see if your program should exit (e.g. if there is a Ctrl-C or otherwise).