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.

191 lines
6.2 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
  1. # Tutorial: Introduction to Stretch Body
  2. The Stretch_Body package provides a low-level Python API to the Stretch hardware. The Stretch_Body package is intended for advanced users who prefer to not use ROS to control the robot. It assumes a moderate level of experience programming robot sensors and actuators.
  3. The package is available on [Git and installable via Pip](https://github.com/hello-robot/stretch_body).
  4. It encapsulates the:
  5. * Mobile base
  6. * Arm
  7. * Lift
  8. * Head actuators
  9. * End-of-arm-actuators
  10. * Wrist board with accelerometer (Wacc)
  11. * Base power and IMU board (Pimu)
  12. As shown below, the primary programming interface to Stretch Body is the [Robot class](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot.py). This class encapsulates the various hardware module classes (e.g. Lift, Arm, etc). Each of these modules then communicates with the robot firmware over USB using various utility classes.
  13. ![alt_text](images/stretch_body_overview.png "image_tooltip")
  14. Stretch also includes 3rd party hardware devices that are not accessible through Stretch_Body. However, it is possible to directly access this hardware through open-source Python packages:
  15. * Laser range finder: [rplidar](https://github.com/SkoltechRobotics/rplidar)
  16. * Respeaker: [respeaker_python_library](https://github.com/respeaker/respeaker_python_library)
  17. * D435i: [pyrealsense2](https://pypi.org/project/pyrealsense2/)
  18. ## Robot Interface
  19. The primary developer interface to Stretch_Body is the [Robot class](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot.py). Let's write some code to explore the interface. Launch an interactive Python terminal:
  20. ```{.bash .shell-prompt}
  21. ipython
  22. ```
  23. Then type in the following:
  24. ```python linenums="1"
  25. import time
  26. import stretch_body.robot
  27. robot=stretch_body.robot.Robot()
  28. robot.startup()
  29. for i in range(10):
  30. robot.pretty_print()
  31. time.sleep(0.25)
  32. robot.stop()
  33. ```
  34. As you can see, this prints all robot sensors and state data to the console every 250ms.
  35. Looking at this in detail:
  36. ```python linenums="4"
  37. import stretch_body.robot
  38. robot=stretch_body.robot.Robot()
  39. robot.startup()
  40. ```
  41. Here we instantiated an instance of our robot through the Robot class. The call to `startup()` opens the serial ports to the various devices, loads the robot YAML parameters, and launches a few helper threads.
  42. ```python linenums="7"
  43. for i in range(10):
  44. robot.pretty_print()
  45. time.sleep(0.25)
  46. ```
  47. The call to `pretty_print()` prints to console all of the robot's sensor and state data. The sensor data is automatically updated in the background by a helper thread.
  48. ```python linenums="11"
  49. robot.stop()
  50. ```
  51. Finally, the `stop()` method shuts down the threads and cleanly closes the open serial ports.
  52. ### Units
  53. The Robot API uses SI units:
  54. * meters
  55. * radians
  56. * seconds
  57. * Newtons
  58. * Amps
  59. * Volts
  60. Parameters may be named with a suffix to help describe the unit type. For example:
  61. * pos_m : meters
  62. * pos_r: radians
  63. ### The Robot Status
  64. The Robot derives from the [Device class](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/device.py). It also encapsulates several other Devices:
  65. * [robot.head](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/head.py)
  66. * [robot.arm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/arm.py)
  67. * [robot.lift](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/lift.py)
  68. * [robot.base](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/base.py)
  69. * [robot.wacc](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/wacc.py)
  70. * [robot.pimu](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/pimu.py)
  71. * [robot.end_of_arm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py)
  72. All devices contain a Status dictionary. The Status contains the most recent sensor and state data of that device. For example, looking at the Arm class we see:
  73. ```python
  74. class Arm(Device):
  75. def __init__(self):
  76. ...
  77. self.status = {'pos': 0.0, 'vel': 0.0, 'force':0.0, \
  78. 'motor':self.motor.status,'timestamp_pc':0}
  79. ```
  80. The Status dictionaries are automatically updated by a background thread of the Robot class at around 25Hz. The Status data can be accessed via the Robot class as below:
  81. ```python
  82. if robot.arm.status['pos']>0.25:
  83. print('Arm extension greater than 0.25m')
  84. ```
  85. If an instantaneous snapshot of the entire Robot Status is needed, the `get_status()` method can be used instead:
  86. ```python
  87. status=robot.get_status()
  88. ```
  89. ### The Robot Command
  90. In contrast to the Robot Status which pulls data from the Devices, the Robot Command pushes data to the Devices.
  91. Consider the following example which extends and then retracts the arm by 0.1 meters:
  92. ```python linenums="1"
  93. import time
  94. import stretch_body.robot
  95. robot=stretch_body.robot.Robot()
  96. robot.startup()
  97. robot.arm.move_by(0.1)
  98. robot.push_command()
  99. time.sleep(2.0)
  100. robot.arm.move_by(-0.1)
  101. robot.push_command()
  102. time.sleep(2.0)
  103. robot.stop()
  104. ```
  105. A few important things are going on:
  106. ```python linenums="7"
  107. robot.arm.move_by(0.1)
  108. ```
  109. The `move_by()` method queues up the command to the stepper motor controller. However, the command does not yet execute.
  110. ```python linenums="8"
  111. robot.push_command()
  112. ```
  113. The `push_command()` causes all queued-up commands to be executed at once. This allows for the synchronization of motion across joints. For example, the following code will cause the base, arm, and lift to initiate motion simultaneously:
  114. ```python linenums="1"
  115. import time
  116. import stretch_body.robot
  117. robot=stretch_body.robot.Robot()
  118. robot.startup()
  119. robot.arm.move_by(0.1)
  120. robot.lift.move_by(0.1)
  121. robot.base.translate_by(0.1)
  122. robot.push_command()
  123. time.sleep(2.0)
  124. robot.stop()
  125. ```
  126. !!! note
  127. In this example we call `sleep()` to allow time for the motion to complete before initiating a new motion.
  128. !!! note
  129. The Dynamixel servos do not use the Hello Robot communication protocol. As such, the head, wrist, and gripper will move immediately upon issuing a motion command.
  130. ------
  131. <div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>