Browse Source

Merge branch 'master' into tutorial/nav2

pull/4/head
Chintan Desai 1 year ago
committed by GitHub
parent
commit
995f8bd980
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 598 additions and 273 deletions
  1. +4
    -4
      README.md
  2. +3
    -3
      getting_started/README.md
  3. +2
    -2
      getting_started/best_practices.md
  4. +1
    -1
      getting_started/command_line_tools.md
  5. +6
    -6
      getting_started/quick_start_guide_re2.md
  6. +3
    -3
      getting_started/safety_guide.md
  7. +2
    -2
      getting_started/troubleshooting_guide.md
  8. +14
    -2
      mkdocs.yml
  9. +1
    -1
      ros1/README.md
  10. +2
    -2
      ros1/navigation_stack.md
  11. +1
    -1
      ros2/README.md
  12. +1
    -1
      stretch_body/README.md
  13. +31
    -29
      stretch_body/tutorial_collision_avoidance.md
  14. +7
    -8
      stretch_body/tutorial_command_line_tools.md
  15. +17
    -24
      stretch_body/tutorial_contact_models.md
  16. +11
    -10
      stretch_body/tutorial_custom_wrist_dof.md
  17. +21
    -19
      stretch_body/tutorial_dynamixel_servos.md
  18. +26
    -19
      stretch_body/tutorial_introduction.md
  19. +13
    -13
      stretch_body/tutorial_parameter_management.md
  20. +25
    -33
      stretch_body/tutorial_robot_motion.md
  21. +16
    -16
      stretch_body/tutorial_robot_sensors.md
  22. +8
    -9
      stretch_body/tutorial_safe_coding.md
  23. +16
    -16
      stretch_body/tutorial_splined_trajectories.md
  24. +60
    -32
      stretch_body/tutorial_stretch_body_api.md
  25. +18
    -17
      stretch_body/tutorial_tool_change.md
  26. +24
    -0
      stretch_tool_share/README.md
  27. +87
    -0
      stretch_tool_share/dex_to_standard.md
  28. +32
    -0
      stretch_tool_share/dex_to_standard_configure_params.py
  29. +15
    -0
      stretch_tool_share/dexwrist.md
  30. +34
    -0
      stretch_tool_share/dry_erase_holder.md
  31. +26
    -0
      stretch_tool_share/gripper_puller.md
  32. +40
    -0
      stretch_tool_share/gripper_removal.md
  33. +31
    -0
      stretch_tool_share/updating_urdf.md

+ 4
- 4
README.md View File

@ -1,16 +1,16 @@
![](./images/banner.png)
# Overview
![](./images/stretch_top_view.png)
The Stretch Tutorials reposotory provides tutorials on programming the Stretch RE1 and RE2 robots. The tutorials are organized into the following tracks.
The Stretch Tutorials repository provides tutorials on programming Stretch robots. The tutorials are organized into the following tracks.
| Tutorial Track | Description |
|--------------------------------------------------------|-------------------------------------------------------------------|
| [Getting to Know Stretch](./getting_started/README.md) | Everything a new user of Stretch needs to get started |
| [Stretch Body](./stretch_body/README.md) | Learn how to program Stretch using its low level Python interface |
| [ROS 1 (Melodic)](./ros1_melodic/README.md) | Learn how to program Stretch using its ROS1 (Melodic) interface |
| [ROS 1 (Noetic)](./ros1/README.md) | Learn how to program Stretch using its ROS1 (Noetic) interface |
| [Stretch Body Python SDK](./stretch_body/README.md) | Learn how to program Stretch using its low level Python interface |
| [ROS](./ros1/README.md) | Learn how to program Stretch using its ROS interface |
| [ROS 2 (Beta)](./ros2/README.md) | Learn how to program Stretch using its ROS2 interface |
| [Stretch Tool Share](./stretch_tool_share/README.md) | Learn how to update the end of arm tool hardware |
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 3
- 3
getting_started/README.md View File

@ -6,14 +6,14 @@ Please take the time to get to know your robot by going through these tutorials
## What Version of Robot Do I Have?
Stretch RE1 and RE2 are very similar. One quick way to tell the difference is to look at the robot's hostame:
Stretch RE1 and Stretch 2 are very similar. One quick way to tell the difference is to look at the robot's hostname:
```bash
>>$ hostname
stretch-re2-2001
```
Another way is to look for the distinctive pink stripe on the RE2 base:
Another way is to look for the distinctive pink stripe on the base of Stretch 2:
![](./images/pink_strip.png)
@ -22,7 +22,7 @@ Another way is to look for the distinctive pink stripe on the RE2 base:
| ---- | ------------------------------------------- | -------------------------------------------------- |
| 1 | [Safety Guide](safety_guide.md) | Guide to safe operation of the Stretch |
| 2 | [Quick Start RE1](quick_start_guide_re1.md) | Unboxing Stretch RE1 and getting started |
| 2 | [Quick Start RE2](quick_start_guide_re2.md) | Unboxing Stretch RE2 and getting started |
| 2 | [Quick Start Stretch 2](quick_start_guide_re2.md) | Unboxing Stretch 2 and getting started |
| 3 | [Best Practices](best_practices.md) | Best practices to keep Stretch charged and healthy |
| 4 | [Troubleshooting](troubleshooting_guide.md) | Solutions to common issues |

+ 2
- 2
getting_started/best_practices.md View File

@ -8,9 +8,9 @@ Keeping Stretch charged is important to the long-term health of its batteries -
[RE1 Battery Maintenance Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/docs/battery_maintenance_guide_re1/)
=== "Stretch RE2"
=== "Stretch 2"
[RE2 Battery Maintenance Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/docs/battery_maintenance_guide_re2/)
[Stretch 2 Battery Maintenance Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/docs/battery_maintenance_guide_re2/)
## Keeping the Robot Healthy

+ 1
- 1
getting_started/command_line_tools.md View File

@ -1,6 +1,6 @@
# Command Line Tools
The Stretch RE1 or RE2 comes with a set of command line tools that are helpful for introspection during general use or while troubleshooting issues. This page provides an overview of these tools. If you like, visit the [stretch_body](https://github.com/hello-robot/stretch_body/tree/master/tools/bin) repository to have a look under the hood.
The Stretch robot comes with a set of command line tools that are helpful for introspection during general use or while troubleshooting issues. This page provides an overview of these tools. If you like, visit the [stretch_body](https://github.com/hello-robot/stretch_body/tree/master/tools/bin) repository to have a look under the hood.
You can execute these commands from anywhere in the terminal. We recommend you to execute these commands as we follow each one of them. You can also find the description for the utility each tool provides by passing the optional '-h' flag along with the tool name in the terminal. For example, from anywhere in the terminal execute:
```console

+ 6
- 6
getting_started/quick_start_guide_re2.md View File

@ -1,6 +1,6 @@
# Stretch RE2: Quick Start Guide
# Stretch 2: Quick Start Guide
Congratulations on your Stretch RE2! This guide will get you started with your new robot.
Congratulations on your Stretch 2! This guide will get you started with your new robot.
## Safety
@ -8,7 +8,7 @@ Stretch has the potential to cause harm if not properly used. All users should r
## Unboxing
Please watch the [Stretch Unboxing Video](https://youtu.be/O-6VrqqGlig).
Please watch the [Stretch Unboxing Video](https://youtu.be/O-6VrqqGlig). Please note that the unboxing instructions for a Stretch 2 are the same as for a Stretch RE1.
## Robot Tour
@ -77,14 +77,14 @@ If you're done, let's power down. First attach the clip-clamp just below the sho
Hold down the Shutdown PC button on the Xbox controller for 2 seconds. This will cause the PC to turn off. You can then power down the robot with the On/Off switch.
Now that you're familiar with the robot, take a minute to watch the [Stretch Powered Best Practices Video](https://youtu.be/iEaapHNfEWA).
Now that you're familiar with the robot, take a minute to watch the [Stretch Powered Best Practices Video](https://youtu.be/iEaapHNfEWA). Please note that the best practices instructions for a Stretch 2 are the same as for a Stretch RE1.
### Safe Handling
Like any robot, it is possible to break Stretch if you're not careful. Use common sense when applying forces to its joints, transporting it, etc.
The [Stretch Unpowered Best Practices Video](https://youtu.be/mQdOGEksdYM) provides a quick overview of how to work with the robot.
The [Stretch Unpowered Best Practices Video](https://youtu.be/mQdOGEksdYM) provides a quick overview of how to work with the robot. Please note that the best practices instructions for a Stretch 2 are the same as for a Stretch RE1.
**Things that won't hurt the robot**:
@ -98,7 +98,7 @@ The [Stretch Unpowered Best Practices Video](https://youtu.be/mQdOGEksdYM) provi
* Manually moving the head and wrist. They will move but they want to go at their own speed.
* The lift will slowly descend when the robot is powered off. If the arm is retracted it may come to rest the tool on the base. If desired to hold the arm up when un-powered, the provided 'clip-clamp' can be clipped onto the mast below the shoulder to support it.
**NOTE**: The RE2 lift descends faster than the RE1. For the RE2 we recommend always attaching the clip-clamp prior to powering down the NUC computer
**NOTE**: The Stretch 2 lift descends faster than the Stretch RE1. For Stretch 2 we recommend always attaching the clip-clamp prior to powering down the NUC computer
**Things that can hurt the robot**:

+ 3
- 3
getting_started/safety_guide.md View File

@ -2,7 +2,7 @@
![](./images/warning_rs.png)
The Stretch RE1 and RE2 are potentially dangerous machine with safety hazards. **If improperly used it can cause injury or death.**
The Stretch robots are potentially dangerous machines with safety hazards. **If improperly used they can cause injury or death.**
* **All users must carefully read the following safety information prior to using the robot.**
* Anyone near the robot who has not read this safety information must be closely supervised at all times and made aware that the robot could be dangerous.
@ -10,7 +10,7 @@ The Stretch RE1 and RE2 are potentially dangerous machine with safety hazards. *
## Intended Use
**The Stretch RE1/RE2 (“Stretch”) are intended for use by researchers to conduct research in controlled indoor environments.** This product is not intended for other uses and lacks the required certifications for other uses, such as use in the home by consumers.
**The Stretch robots are intended for use by researchers to conduct research in controlled indoor environments.** This product is not intended for other uses and lacks the required certifications for other uses, such as use in a home environment by consumers.
## Safety Hazards
@ -172,7 +172,7 @@ The runstop logic is:
### Sharp Edges
Stretch RE1/RE2 is a piece of laboratory equipment. As such, its structure has moderately sharp edges and corners that can be unsafe. These edges can get snagged during motion, or they may cause lacerations when sufficient force is applied to a person. Care should be taken when grasping or otherwise making contact with Stretch that a sharp corner or edge is not contacted.
The Stretch robot is a piece of laboratory equipment. As such, its structure has moderately sharp edges and corners that can be unsafe. These edges can get snagged during motion, or they may cause lacerations when sufficient force is applied to a person. Care should be taken when grasping or otherwise making contact with Stretch that a sharp corner or edge is not contacted.
### Toppling

+ 2
- 2
getting_started/troubleshooting_guide.md View File

@ -23,9 +23,9 @@ In addition, check that the provided USB dongle is plugged into the robot USB po
Please review the troubleshooting section of the [RE1 Battery Maintenance Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/battery_maintenance_guide_re1/).
=== "Stretch RE2"
=== "Stretch 2"
Please review the troubleshooting section of the [RE2 Battery Maintenance Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/battery_maintenance_guide_re2).
Please review the troubleshooting section of the [Stretch 2 Battery Maintenance Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/battery_maintenance_guide_re2).
## RPC Transport Errors (Stretch doesn't respond to commands)

+ 14
- 2
mkdocs.yml View File

@ -87,14 +87,15 @@ nav:
- Overview: ./getting_started/README.md
- Basics:
- Safety Guide: ./getting_started/safety_guide.md
- Quick Start RE1: ./getting_started/quick_start_guide_re1.md
- Quick Start RE2: ./getting_started/quick_start_guide_re2.md
- Quick Start Stretch RE1: ./getting_started/quick_start_guide_re1.md
- Quick Start Stretch 2: ./getting_started/quick_start_guide_re2.md
- Best Practices: ./getting_started/best_practices.md
- Troubleshooting: ./getting_started/troubleshooting_guide.md
- Advanced:
- Command Line Tools: ./getting_started/command_line_tools.md
- Untethered Operation: ./getting_started/untethered_operation.md
- Updating Software: ./getting_started/updating_software.md
- Stretch Body Python SDK:
- Overview: ./stretch_body/README.md
- Basics:
@ -178,3 +179,14 @@ nav:
- Deep Perception: ./ros2/deep_perception.md
# - PointCloud Transformation: ./ros2/example_11.md
# - ArUco Tag Locator: ./ros2/example_12.md
- Stretch Tool Share:
- Overview: ./stretch_tool_share/README.md
- Basics:
- Gripper Removal: ./stretch_tool_share/gripper_removal.md
- Gripper Puller: ./stretch_tool_share/gripper_puller.md
- Dry Erase Holder: ./stretch_tool_share/dry_erase_holder.md
- Dex Wrist: ./stretch_tool_share/dexwrist.md
- Dex to Standard Wrist: ./stretch_tool_share/dex_to_standard.md
- Advanced:
- Updating URDF: ./stretch_tool_share/updating_urdf.md

+ 1
- 1
ros1/README.md View File

@ -5,7 +5,7 @@
Despite the name, ROS is not an operating system. ROS is a middleware framework that is a collection of transport protocols, development and debugging tools, and open-source packages. As a transport protocol, ROS enables distributed communication via messages between nodes. As a development and debugging toolkit, ROS provides build systems that allows for writing applications in a wide variety of languages (Python and C++ are used in this tutorial track), a launch system to manage the execution of mutiple nodes simultaneously, and command line tools to interact with the running system. Finally, as a popular ecosystem, there are many open-source ROS packages that allow users to quickly prototype with new sensors, actuators, planners, perception stacks, and more.
This tutorial track is for users looking to become familiar with programming the Stretch RE1 and RE2 via ROS Noetic. We recommend going through the tutorials in the following order:
This tutorial track is for users looking to get familiar with programming Stretch robots via ROS. We recommend going through the tutorials in the following order:
## Basics

+ 2
- 2
ros1/navigation_stack.md View File

@ -1,6 +1,6 @@
## Navigation Stack with Actual robot
stretch_navigation provides the standard ROS navigation stack as two launch files. This package utilizes gmapping, move_base, and AMCL to drive Stretch around a mapped space. Running this code will require the robot to be untethered.
stretch_navigation provides the standard ROS navigation stack as two launch files. This package utilizes gmapping, move_base, and AMCL to drive Stretch around a mapped space. Running this code will require the robot to be [untethered](https://docs.hello-robot.com/0.2/stretch-tutorials/getting_started/untethered_operation/).
Then run the following commands to map the space that the robot will navigate in.
@ -68,4 +68,4 @@ roslaunch stretch_navigation mapping.launch rviz:=false teleop_type:=none
rviz -d `rospack find stretch_navigation`/rviz/mapping.launch
# On your machine, Terminal 2:
roslaunch stretch_core teleop_twist.launch teleop_type:=keyboard # or use teleop_type:=joystick if you have a controller
```
```

+ 1
- 1
ros2/README.md View File

@ -7,7 +7,7 @@ NOTE: Stretch's ROS2 packages and this ROS2 tutorial track are both under active
Despite the name, ROS is not an operating system. ROS is a middleware framework that is a collection of transport protocols, development and debugging tools, and open-source packages. As a transport protocol, ROS enables distributed communication via messages between nodes. As a development and debugging toolkit, ROS provides build systems that allows for writing applications in a wide variety of languages (Python and C++ are used in this tutorial track), a launch system to manage the execution of mutiple nodes simultaneously, and command line tools to interact with the running system. Finally, as a popular ecosystem, there are many open-source ROS packages that allow users to quickly prototype with new sensors, actuators, planners, perception stacks, and more.
This tutorial track is for users looking to become familiar with programming the Stretch RE1 and RE2 via ROS 2. We recommend going through the tutorials in the following order:
This tutorial track is for users looking to get familiar with programming Stretch robots via ROS 2. We recommend going through the tutorials in the following order:
## Basics

+ 1
- 1
stretch_body/README.md View File

@ -1,6 +1,6 @@
![](../images/banner.png)
# Tutorial Track: Stretch Body
[Stretch Body](https://github.com/hello-robot/stretch_body) is a set of Python packages that allow a developer to directly program the hardware of the Stretch RE1 and RE2 robots. The Stretch Body interface is intended for users who choose to not use ROS.
[Stretch Body](https://github.com/hello-robot/stretch_body) is a set of Python packages that allow a developer to directly program the hardware of the Stretch robots. The Stretch Body interface is intended for users who are looking for an alternative to ROS.
Stretch Body currently supports both Python2 and Python3. These tutorials assume a general familiarity with Python as well as basic robot motion control.

+ 31
- 29
stretch_body/tutorial_collision_avoidance.md View File

@ -1,21 +1,22 @@
# Tutorial: Collision Avoidance
In this tutorial we will discuss the simple collision avoidance system that runs as a part of Stretch Body.
In this tutorial, we will discuss the simple collision avoidance system that runs as a part of Stretch Body.
## Overview
Stretch Body includes a system to prevent inadvertent self-collisions. It will dynamically limit the range of motion of each joint in order to prevent self-collisions.
Stretch Body includes a system to prevent inadvertent self-collisions. It will dynamically limit the range of motion of each joint to prevent self-collisions.
**NOTE**: Self collisions are still possible while using the collision-avoidance system. The factory default collision models are coarse and not necessarily complete.
!!! warning
Self collisions are still possible while using the collision-avoidance system. The factory default collision models are coarse and not necessarily complete.
This system is turned off by default starting with RE2. It may be turned off by default on many RE1 systems. First check if the collision detection system is turned on:
This system is turned off by default starting with Stretch 2. It may be turned off by default on many RE1 systems. First check if the collision detection system is turned on:
```bash
>>$ stretch_params.py | grep use_collision_manager
stretch_body.robot_params.nominal_params param.robot.use_collision_manager 1
```
If it is turned off you can enable it by adding the following to your stretch_user_yaml.py
If it is turned off you can enable it by adding the following to your stretch_user_yaml.py:
```bash
robot:
@ -24,24 +25,24 @@ robot:
## Common Self Collisions
Fortunately the simple kinematics of Stretch make self collisions fairly uncommon and simple to predict. The primary places where self collisions may occur are
Fortunately, the simple kinematics of Stretch make self-collisions fairly uncommon and simple to predict. The primary places where self-collisions may occur are
* The lift lowering the wrist or tool into the base
* The arm retracting the wrist or tool into the base
* The head_pan at `pos==0` and head_tilt at `pos=-90 deg` and the lift raising the arm into the camera (minor collision)
* The DexWrist (if installed) and colliding with itself
* The DexWrist (if installed) and colliding with the base
* The Dex Wrist (if installed) colliding with itself
* The Dex Wrist (if installed) colliding with the base
## Joint Limits
The collision avoidance system works by dynamically modifying the acceptable range of motion for each joint. By default, a joint's range is set to the physical hardstop limits. For example, the lift has a mechanical throw of 1.1m:
The collision avoidance system works by dynamically modifying the acceptable range of motion for each joint. By default, a joint's range is set to the physical hard stop limits. For example, the lift has a mechanical throw of 1.1m:
```bash
>>$stretch_params.py | grep range | grep lift
stretch_body.robot_params.factory_params param.lift.range_m [0.0, 1.1]
```
A reduced range-of-motion can be set at run-time by setting the Soft Motion Limit. For example, to limit the lift range of motion to 0.3 meter off the base:
A reduced range of motion can be set at run-time by setting the Soft Motion Limit. For example, to limit the lift range of motion to 0.3 meters off the base:
```python
import stretch_body.robot as robot
@ -50,9 +51,9 @@ r.startup()
r.lift.set_soft_motion_limit_min(0.3)
```
We see in the [API](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/lift.py), the value of `None` is used to designated no soft limit.
We see in the [API](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/lift.py), the value of `None` is used to designate no soft limit.
It is possible that when setting the Soft Motion Limit that the joint's current position is outside of the specified range. In this case, the joint will move to the nearest soft limit so as to comply with the limits. This can be demonstrated by:
It is possible that when setting the Soft Motion Limit the joint's current position is outside of the specified range. In this case, the joint will move to the nearest soft limit to comply with the limits. This can be demonstrated by:
```python
import stretch_body.robot as robot
@ -75,7 +76,7 @@ r.lift.set_soft_motion_limit_min(0.3)
The [RobotCollision](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision.py) class manages a set of [RobotCollisionModels](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision.py). Each [RobotCollisionModel](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision.py) computes the soft limits for a subset of joints based on a simple geometric model. This geometric model captures the enumerated set of potential collisions listed above.
We can see the which collision models will execute when `use_collision_manager` is set to 1:
We can see which collision models will execute when `use_collision_manager` is set to 1:
```bash
>>$ stretch_params.py | grep collision | grep enabled
@ -86,22 +87,24 @@ stretch_body.robot_params.nominal_params param.collision_stretch_gripper.enab
We see two models. One that protects the camera from the arm, and one that protects the base from the gripper. Each model is registered with the [RobotCollision](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision.py) instance as a loadable plug-in. The [Robot](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot.py) class calls the `RobotCollision.step` method periodically at approximately 10hz.
`RobotCollision.step` computes the 'AND' of the limits specified across each Collision Model such that the most restrictive joint limits are set for each joint using the `set_soft_motion_limit_min , set_soft_motion_limt_max` methods.
`RobotCollision.step` computes the 'AND' of the limits specified across each Collision Model such that the most restrictive joint limits are set for each joint using the `set_soft_motion_limit_min` and `set_soft_motion_limt_max` methods.
## Default Collision Models
The default collision models for Stretch Body are found in [robot_collision_models.py](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision_models.py). As of this writing, the provide models are:
The default collision models for Stretch Body are found in [robot_collision_models.py](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision_models.py). As of this writing, the provided models are:
* [CollisionArmCamera](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision_models.py#L8): Avoid collision of the head camera with the arm
* [CollisionStretchGripper](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision_models.py#L75): Avoid collision of the wrist-yaw and gripper with the base and ground
**NOTE**: The provided collision models are coarse and are provided to avoid common potentially harmful collisions only. Using these models it is still possible to collide the robot with itself in some cases.
!!! warning
The provided collision models are coarse and are provided to avoid common potentially harmful collisions only. Using these models it is still possible to collide the robot with itself in some cases.
**NOTE**: Additional collision models are provided for the DexWrist
!!! info
Additional collision models are provided for the DexWrist
### Working with Models
The collision models to be used by Stretch Body are defined with the `robot_collision` parameter. For example, we see in `robot_params.py` that the CollisionArmCamera is loaded by default
The collision models to be used by Stretch Body are defined with the `robot_collision` parameter. For example, we see in `robot_params.py` that the CollisionArmCamera is loaded by default:
```python
"robot_collision": {'models': ['collision_arm_camera']},
@ -152,7 +155,7 @@ robot_collision:
- collision_stretch_gripper
```
### Creating a Custom Collision Model
### Creating Custom Collision Models
The `step` method of a RobotCollisionModel returns the desired joint limits given that model. For example, the base class is simply:
@ -163,7 +166,7 @@ The `step` method of a RobotCollisionModel returns the desired joint limits give
'lift': [None, None],'arm': [None, None],'wrist_yaw': [None, None]}
```
, where the value of `None` specifies that no-limit is specified and the full range-of-motion for the joint is acceptable.
where the value of `None` specifies that no limit is specified and the full range of motion for the joint is acceptable.
We could define a new collision model that simply limits the lift range of motion to 1 meter by:
@ -174,12 +177,12 @@ We could define a new collision model that simply limits the lift range of motio
'lift': [None, 1.0],'arm': [None, None],'wrist_yaw': [None, None]}
```
It can be straightforward to create your own custom collision model. As an example, we will create a model that avoids collision of the arm with a table top by
It is straightforward to create a custom collision model. As an example, we will create a model that avoids collision of the arm with a tabletop by
* Prevent the lift from descending below the table top when the arm is extended
* Allow the lift to descend below the tabletop so long as the arm retracted
* Preventing the lift from descending below the table top when the arm is extended
* Allowing the lift to descend below the tabletop so long as the arm retracted
This assumes the arm is initially above the table top. To start, in a file `collision_arm_table.py` we add:
This assumes the arm is initially above the tabletop. To start, in a file `collision_arm_table.py` we add:
```python
from stretch_body.robot_collision import *
@ -211,16 +214,15 @@ class CollisionArmTable(RobotCollisionModel):
limits['lift']=[table_height+safety_margin,None]
return limits
```
In this example we include the `safety_margin` as a way to introduce some hysteresis around state changes to avoid toggling between the soft limits.
In this example, we include the `safety_margin` as a way to introduce some hysteresis around state changes to avoid toggling between the soft limits.
The following command should be run in order to add the working directory to the PYTHONPATH env , This can also be added to our bashrc to permanently edit the path:
The following command should be run to add the working directory to the PYTHONPATH env. This can also be added to our `.bashrc` to permanently edit the path:
```bash
>>$ export PYTHONPATH=$PYTHONPATH:/<path_to_modules>
```
Next we configure RobotCollision to use our CollisionArmTable model in `stretch_re1_user_yaml`:
Next, we configure RobotCollision to use our CollisionArmTable model in `stretch_re1_user_yaml`:
```yaml
robot_collision:
@ -234,7 +236,7 @@ collision_arm_table:
```
Finally, test out the model by driving the arm and lift around using the XBox teleoperation tool:
Finally, test out the model by driving the arm and lift around using the Xbox teleoperation tool:
```bash
>>$ stretch_xbox_controller_teleop.py

+ 7
- 8
stretch_body/tutorial_command_line_tools.md View File

@ -1,10 +1,10 @@
# Tutorial: Stretch Body Command Line Tools
Stretch Body includes the package [hello-robot-stretch-body-tools](https://github.com/hello-robot/stretch_body/tree/master/tools) -- a suite of command line tools that allow direct interaction with hardware subsystems.
Stretch Body includes the package [hello-robot-stretch-body-tools](https://github.com/hello-robot/stretch_body/tree/master/tools) - a suite of command line tools that allow direct interaction with hardware subsystems.
These tools are useful when developing and debugging applications. They also serve as code examples when developing applications for Stretch_Body.
These tools can be found by tab completion of 'stretch_' from a terminal.
These tools can be found by tab completion of 'stretch_' from a terminal.
```console
$ stretch_
@ -45,7 +45,7 @@ stretch_wrist_yaw_jog.py
stretch_xbox_controller_teleop.py
```
All tools accept '--help' as a command line argument to learn its function. For example:
All tools accept the '--help' flag as a command line argument to describe its function. For example:
```console
>>$ stretch_pimu_scope.py --help
@ -78,22 +78,21 @@ optional arguments:
--bump Scope base imu bump level
```
### Commonly Used Tools
## Commonly Used Tools
These are the tools a typical user will want to become familiar with.
These are the tools a typical user is expected to interact with regularly and would benefit from becoming familiar with.
| **Tool** | **Utility** |
| ------------------------------------- | ------------------------------------------------------------ |
| **stretch_robot_home.py** | Commonly run after booting up the robot in-order to calibrate the joints |
| **stretch_robot_system_check.py** | Scans for all hardware devices and ensure they are present on the bus and reporting valid values. Useful to verify that the robot is in good working order prior to commanding motion. It will report all success in green, failures in red. |
| **stretch_robot_system_check.py** | Scans for all hardware devices and ensures they are present on the bus and reporting valid values. Useful to verify that the robot is in good working order prior to commanding motion. It will report all success in green, failures in red. |
| **stretch_robot_stow.py** | Useful to return the robot arm and tool to a safe position within the base footprint. It can also be useful if a program fails to exit cleanly and the robot joints are not backdriveable. It will restore them to their 'Safety' state. |
| **stretch_robot_battery_check.py** | Quick way to check the battery voltage / current consumption |
| **stretch_xbox_controller_teleop.py** | Useful to quickly test if a robot can achieve a task by manually teleoperating the robot |
| **stretch_robot_dynamixel_reboot.py** | This will reset all Dynamixels in the robot, which may be needed if a servo overheats during high use and enters an error state. |
| **stretch_robot_dynamixel_reboot.py** | Resets all Dynamixels in the robot, which might be necessary if a servo overheats during use and enters an error state. |
Take a minute to explore each of these tools from the console.
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 17
- 24
stretch_body/tutorial_contact_models.md View File

@ -6,10 +6,10 @@ This tutorial introduces the Stretch Body contact detection system and explains
Guarded contact is our term for the Stretch contact sensitive behaviors. The guarded contact behavior is simply:
1. Detect when the actuator effort exceeds a user specified threshold during joint motion
2. If the threshold is exceeded,
1. Enable the default safety controller for the joint
2. Remain in the safety mode until a subsequent joint command is received
1. Detect when the actuator effort exceeds a user-specified threshold during joint motion.
2. If the threshold is exceeded:
1. Enable the default safety controller for the joint
2. Remain in safety mode until a subsequent joint command is received
Practically this enables the arm, for example, to move out yet stop upon collision. Let's test this out with the following script:
@ -41,7 +41,7 @@ robot.arm.wait_until_at_setpoint(timeout=5.0)
robot.stop()
```
You should see that the arm stops on contact when it extends, however it doesn't stop on contact when it then retracts. This is the guarded contact behavior in action.
You should see that the arm stops on contact when it extends, however, it doesn't stop on contact when it then retracts. This is the guarded contact behavior in action.
## Specifying Guarded Contacts
@ -49,14 +49,15 @@ The four stepper joints (base, arm, and lift) all support guarded contact settin
```python
def move_by(self,x_m,v_m=None, a_m=None, stiffness=None, contact_thresh_pos_N=None,contact_thresh_neg_N=None, req_calibration=True,contact_thresh_pos=None,contact_thresh_neg=None)
```
In this method you can optionally specify a contact threshold in the positive direction (`contact_thresh_pos`) and the negative direction `contact_thresh_neg`.
In this method, you can optionally specify a contact threshold in the positive and negative direction with `contact_thresh_pos` and `contact_thresh_neg` respectively.
**NOTE**: these optional parameters will default to `None`, in which case the motion will adopt the default settings as defined the robot's parameters
!!! note
These optional parameters will default to `None`, in which case the motion will adopt the default settings as defined by the robot's parameters.
**NOTE**: The parameters `contact_thresh_pos_N` and `contact_thresh_neg_N` are deprecate and no-longer supported.
!!! warning
The parameters `contact_thresh_pos_N` and `contact_thresh_neg_N` are deprecated and no longer supported.
```bash
>>$ stretch_params.py | grep arm | grep contact
@ -67,23 +68,21 @@ stretch_configuration_params.yaml param.arm.contact_models.effort_pct
## Contact Models
A contact model is simply a function that, given a user specified contact threshold, computes the motor current at which the motor controller will trigger a guarded contact. The following contact models are currently implemented:
A contact model is simply a function that, given a user-specified contact threshold, computes the motor current at which the motor controller will trigger a guarded contact. The following contact models are currently implemented:
### The Effort-Pct Contact Model
[Effort-Pct](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/prismatic_joint.py) is the default contact model for Stretch RE2. It simply scales the maximum range of motor currents into the range of [-100,100]. Thus, if you desire to have the robot arm extend but stop at 50% of its maximum current, you would write:
[Effort-Pct](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/prismatic_joint.py) is the default contact model for Stretch 2. It simply scales the maximum range of motor currents into the range of [-100,100]. Thus, if you desire to have the robot arm extend but stop at 50% of its maximum current, you would write:
```python
robot.arm.move_by(0.1,contact_thresh_pos=50.0)
```
## Adjusting Contact Behaviors
The default factory settings for contact thresholds are tuned to allow Stretch to move throughout its workspace without triggering false-positive guarded contact events. These settings are the worst case tuning as they account for the internal disturbances of the Stretch drive-train across its entire workspace.
The default factory settings for contact thresholds are tuned to allow Stretch to move throughout its workspace without triggering false-positive guarded contact events. These settings are the worst-case tuning as they account for the internal disturbances of the Stretch drive-train across its entire workspace.
It is possible to obtain greater contact sensitivity in carefully selected portions of the arm and lift workspace. Users who wish to programmatically adjust contact behaviors can create a simple test script and experiment with different values. For example:
It is possible to obtain greater contact sensitivity in carefully selected portions of the arm and lift workspace. Users who wish to programmatically adjust contact behaviors can create a simple test script and experiment with different values. For example:
```python
#!/usr/bin/env python
@ -109,7 +108,7 @@ robot.stop()
## Guarded Contact with the Base
Guarded contacts are enable by default for the arm and lift as they typically require safe and contact sensitive motion. They are turned off on the base by default as varying surface terrain can product undesired false-positive events.
Guarded contacts are enabled by default for the arm and lift as they typically require safe and contact-sensitive motion. They are turned off on the base by default as varying surface terrain can produce undesired false-positive events.
That being said, guarded contacts can be enabled on the base. They may be useful as a simple bump detector such that the base will stop when it runs into a wall.
@ -135,13 +134,11 @@ robot.base.wait_until_at_setpoint()
robot.stop()
```
## Advanced: Calibrating Contact Thresholds
The Stretch Factory package provides a tool to allow advanced users to recalibrate the default guarded contact thresholds. This tool can be useful if you've added additional payload to the arm and are experiencing false-positive guarded contact detections.
The tool sweeps the joint through its range-of-motion for `ncycle` iterations. It computes the maximum contact forces in both directions, adds a padding (`contact_thresh_calibration_margin`) to this value, and stores it to the robots Configuration yaml.
The tool sweeps the joint through its range of motion for `n-cycle` iterations. It computes the maximum contact forces in both directions, adds padding, `contact_thresh_calibration_margin`, to this value, and stores it to the robot's configuration YAML.
```bash
>>$ REx_calibrate_guarded_contact.py -h
@ -156,12 +153,8 @@ optional arguments:
-h, --help show this help message and exit
--lift Calibrate the lift joint
--arm Calibrate the arm joint
--ncycle NCYCLE Number of sweeps to run [4]
--ncycle NCYCLE Number of sweeps to run [4]
```
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 11
- 10
stretch_body/tutorial_custom_wrist_dof.md View File

@ -1,23 +1,24 @@
# Tutorial: Custom Wrist DOF
In this tutorial we explore how to add additional degrees of freedom to the Stretch wrist.
In this tutorial, we explore how to add additional degrees of freedom to the Stretch wrist.
Stretch exposes a Dynamixel X-Series TTL control bus at the end of its arm. It uses the [Dynamixel XL430-W250](https://emanual.robotis.com/docs/en/dxl/x/xl430-w250/) for the [WristYaw](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/wrist_yaw.py) and the [StretchGripper](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/stretch_gripper.py) degrees of freedom that come standard with the robot.
Stretch exposes a Dynamixel X-Series TTL control bus at the end of its arm. It uses the [Dynamixel XL430-W250](https://emanual.robotis.com/docs/en/dxl/x/xl430-w250/) for the [Wrist Yaw](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/wrist_yaw.py) and the [Stretch Gripper](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/stretch_gripper.py) that comes standard with the robot.
See the [Hardware User Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/docs/hardware_guide_re2/#wrist-tool-plate) to learn how to mechanically attach additional DOFs to the robot.
**Note: Stretch is compatible with [any Dynamixel X Series servo](https://emanual.robotis.com/docs/en/dxl/x/) that utilizes the TTL level Multidrop Bus.**
!!! note
Stretch is compatible with any [Dynamixel X Series servo](https://emanual.robotis.com/docs/en/dxl/x/) that utilizes the TTL level Multidrop Bus.
## Adding a Custom DOF
Adding one or more custom Dynamixel X Series servos to Stretch wrist involves:
* Creating a new class that derives from [DynamixelHelloXL430](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_hello_XL430.py)
* Adding YAML parameters to `stretch_user_params.yaml `that configure the servo as desired
* Adding YAML parameters to `stretch_user_params.yaml` that configure the servo as desired
* Adding YAML parameters to `stretch_user_params.yaml` that tell Stretch to include this class in its EndOfArm list of servos
Let's create a new DOF called MyWristPitch in a file named [my_wrist_pitch.py](./custom_wrist_dof/my_wrist_pitch.py). Place the file somewhere on the $PYTHONPATH.
Let's create a new DOF called MyWristPitch in a file named [my_wrist_pitch.py](./custom_wrist_dof/my_wrist_pitch.py). Place the file somewhere on the $PYTHONPATH.
```python
from stretch_body.dynamixel_hello_XL430 import DynamixelHelloXL430
@ -33,7 +34,7 @@ class MyWristPitch(DynamixelHelloXL430):
self.move_to(self.poses[p],v_r,a_r)
```
Now let's add the tools' parameters to your `stretch_user_params.yaml` in order to configure this servo. You may want to adapt these parameters to your application but the nominal values [found here](./custom_wrist_dof/stretch_user_params.yaml) usually work well. Below we highlight some of the more useful parameters.
Now let's add the tools' parameters to your `stretch_user_params.yaml` to configure this servo. You may want to adapt these parameters to your application but the nominal values [found here](./custom_wrist_dof/stretch_user_params.yaml) usually work well. Below we highlight some of the more useful parameters.
```yaml
my_wrist_pitch:
@ -46,9 +47,9 @@ my_wrist_pitch:
zero_t: 2048 #Position in ticks that corresponds to zero radians
```
For this example we are assuming a single turn joint that doesn't require hardstop based homing. We also assume the servo has the Robotis default ID of 1.
For this example, we are assuming a single-turn joint that doesn't require hard stop-based homing. We also assume the servo has the Robotis default ID of 1.
At this point your MyWristPitch class is ready to use. Plug the servo into the cable leaving the Stretch WristYaw joint. Experiment with the API from iPython
At this point, your MyWristPitch class is ready to use. Plug the servo into the cable leaving the Stretch WristYaw joint. Experiment with the API from iPython
```python
In [1]: import my_wrist_pitch
@ -64,7 +65,7 @@ In [5]: w.pose('tool_up')
In [6]: w.pose('tool_down')
```
Finally, you'll want to make your WristPitch available from `stretch_body.robot` Add the following [YAML](./custom_wrist_dof/stretch_user_params.yaml) to your `stretch_user_params.yaml`
Finally, you'll want to make your WristPitch available from `stretch_body.robot`. Add the following [YAML](./custom_wrist_dof/stretch_user_params.yaml) to your `stretch_user_params.yaml`
```yaml
end_of_arm:
@ -74,7 +75,7 @@ end_of_arm:
py_module_name: wrist_pitch
```
This tells `stretch_body.robot` to manage a wrist_`pitch.WristPitch`instance and add it to the [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) list of tools. Try it from iPython:
This tells `stretch_body.robot` to manage a `wrist_pitch.WristPitch` instance and add it to the [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) list of tools. Try it from iPython:
```python
In [1]: import stretch_body.robot as robot

+ 21
- 19
stretch_body/tutorial_dynamixel_servos.md View File

@ -1,7 +1,6 @@
# Tutorial: Working with Dynamixel Servos
In this tutorial we will go into the details with Dynamixel servos and Stretch.
In this tutorial, we will go into the details with Dynamixel servos and Stretch.
## Overview
@ -12,11 +11,12 @@ Stretch comes with two Dynamixel buses - one for the head and one for the end-of
/dev/hello-dynamixel-head /dev/hello-dynamixel-wrist
```
Typically, users will interact with these devices through either the [Head](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/head.py) or [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) interfaces. This tutorial is for users looking to work directly with the servos from the provided servo tools or through Stretch Body's low level Dynamixel API.
Typically, users will interact with these devices through either the [Head](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/head.py) or the [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) interfaces. This tutorial is for users looking to work directly with the servos from the provided servo tools or through Stretch Body's low-level Dynamixel API.
## Servo Tools
**NOTE**: The servo tools here are part of the [Stretch Factory package](https://github.com/hello-robot/stretch_factory) which is installed as a part of Stretch Body.
!!! note
The servo tools here are part of the [Stretch Factory package](https://github.com/hello-robot/stretch_factory) which is installed as a part of Stretch Body.
### Jogging the Servos
@ -49,7 +49,7 @@ e: enable torque
### Rebooting the Servos
Under high-load conditions the servos may enter an error state to protect themselves from thermal overload. In this case, the red LED on the servo will flash (if visible). In addition, the servo will be unresponsive to motion commands. In this case, allow the overheating servo to cool down and reboot the servos using the `stretch_robot_dynamixel_reboot.py` tool:
Under high-load conditions, the servos may enter an error state to protect themselves from thermal overload. In this case, the red LED on the servo will flash (if visible). In addition, the servo will be unresponsive to motion commands. In this case, allow the overheating servo to cool down and reboot the servos using the `stretch_robot_dynamixel_reboot.py` tool:
```bash
$ stretch_robot_dynamixel_reboot.py
@ -65,10 +65,10 @@ For use with S T R E T C H (TM) RESEARCH EDITION from Hello Robot Inc.
### Identify Servos on the Bus
If it is unclear which servos are on the bus, and at what baud rate, you can use the `REx_dynamixel_id_scan.py` tool. Here we see that the two head servos are at ID 11 and 12 at baud 57600.
If it is unclear which servos are on the bus, and at what baud rate, you can use the `REx_dynamixel_id_scan.py` tool. Here we see that the two head servos are at ID `11` and `12` at baud `57600`.
```bash
$ RE1_dynamixel_id_scan.py /dev/hello-dynamixel-head --baud 57600
$ REx_dynamixel_id_scan.py /dev/hello-dynamixel-head --baud 57600
Scanning bus /dev/hello-dynamixel-head at baud rate 57600
----------------------------------------------------------
[Dynamixel ID:000] ping Failed.
@ -100,7 +100,7 @@ Scanning bus /dev/hello-dynamixel-head at baud rate 57600
### Setting the Servo Baud Rate
Stretch ships with its Dynamixels servos configured to baudrate=115200. When adding your own servos to the end-of-arm tool, you may want to set the servo baud using the `RE1_dynamixel_set_baud.py` tool. For example:
Stretch ships with its Dynamixel servos configured to `baudrate=115200`. When adding your servos to the end-of-arm tool, you may want to set the servo baud using the `REx_dynamixel_set_baud.py` tool. For example:
```bash
$ REx_dynamixel_set_baud.py /dev/hello-dynamixel-wrist 13 115200
@ -110,13 +110,16 @@ Checking servo current baud for 57600
Identified current baud of 57600. Changing baud to 115200
Success at changing baud
```
**Note**: Earlier units of Stretch RE1 may be running Dynamixel servos at baud 57600
!!! note
Earlier units of Stretch RE1 may be running Dynamixel servos at baud 57600.
### Setting the Servo ID
Dynamixel servos come with ID=1 from the factory. When adding your own servos to the end-of-arm tool, you may want to set the servo ID using the `REx_dynamixel_id_change.py` tool. For example:
Dynamixel servos come with `ID=1` from the factory. When adding your servos to the end-of-arm tool, you may want to set the servo ID using the `REx_dynamixel_id_change.py` tool. For example:
```bash
$ RE1x_dynamixel_id_change.py /dev/hello-dynamixel-wrist 1 13 --baud 115200
$ REx_dynamixel_id_change.py /dev/hello-dynamixel-wrist 1 13 --baud 115200
[Dynamixel ID:001] ping Succeeded. Dynamixel model number : 1080
Ready to change ID 1 to 13. Hit enter to continue:
@ -126,7 +129,7 @@ Success at setting ID to 13
## Stretch Body Dynamixel API
Stretch Body's low level Dynamixel API includes a hierarchy of three classes
Stretch Body's low-level Dynamixel API includes a hierarchy of three classes
| Class |
| ------------------------------------------------------------ |
@ -134,17 +137,18 @@ Stretch Body's low level Dynamixel API includes a hierarchy of three classes
| [DynamixelHelloXL430](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_hello_XL430.py) |
| [DynamixelXL430](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_XL430.py) |
**NOTE**: The naming of XL430 is for legacy reasons. These classes will work with all X Series servos.
!!! note
The naming of XL430 is for legacy reasons. These classes will work with all X Series servos.
### DynamixelXChain
DynamixelXChain manages a set of daisy-chained servos on a single bus (for example the head_pan and head_tilt servos). It allows for greater communication bandwidth by doing group read/write over USB.
DynamixelXChain manages a set of daisy-chained servos on a single bus (for example the head_pan and head_tilt servos). It allows for greater communication bandwidth by doing a group read/write over USB.
The [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) class derives from DynamixelXChain in order to provide an extensible interface that supports a user integrating additional DOF to the robot. The tutorial [Adding Custom Wrist DOF](./tutorial_custom_wrist_dof.md) explains how to do this.
The [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) class derives from DynamixelXChain to provide an extensible interface that supports a user in integrating additional degrees of freedom to the robot. The tutorial [Adding Custom Wrist DoF](./tutorial_custom_wrist_dof.md) explains how to do this.
### DynamixelHelloXL430
DynamixelHelloXL430 provides an interface to servo motion that is consistent with the Stretch Body lift, arm, and base joints. It also manages the servo parameters and calibration. Let's explore this interface further. From iPython let's look at the status message for DynamixelHelloXL430
DynamixelHelloXL430 provides an interface to servo motion that is consistent with the Stretch Body lift, arm, and base joints. It also manages the servo parameters and calibration. Let's explore this interface further. From iPython, let's look at the status message for DynamixelHelloXL430
```bash
import stretch_body.dynamixel_hello_XL430
@ -193,7 +197,7 @@ In addition to `move_to` and `move_by`, the class also implements a splined traj
### DynamixelXL430
DynamixelXL430 provides a thin wrapper to the [Robotis Dynamixel SDK](http://emanual.robotis.com/docs/en/dxl/x/xl430-w250/#control-table). You may chose to interact with the servo at this level as well. For example to jog the head_pan 200 ticks:
DynamixelXL430 provides a thin wrapper to the [Robotis Dynamixel SDK](http://emanual.robotis.com/docs/en/dxl/x/xl430-w250/#control-table). You may choose to interact with the servo at this level as well. For example, to jog the head_pan 200 ticks:
```python
import stretch_body.dynamixel_XL430
import time
@ -208,7 +212,5 @@ time.sleep(2.0)
m.stop()
```
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 26
- 19
stretch_body/tutorial_introduction.md View File

@ -1,5 +1,5 @@
# Tutorial: Introduction to Stretch Body
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.
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.
The package is available on [Git and installable via Pip](https://github.com/hello-robot/stretch_body).
@ -9,11 +9,11 @@ It encapsulates the:
* Arm
* Lift
* Head actuators
* End -of-arm-actuators
* Wrist board with accelerometer (Wacc)
* End-of-arm-actuators
* Wrist board with accelerometer (Wacc)
* Base power and IMU board (Pimu)
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 communicate the robot's firmware over USB using various utility classes.
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.
![alt_text](images/stretch_body_overview.png "image_tooltip")
@ -24,8 +24,6 @@ Stretch also includes 3rd party hardware devices that are not accessible through
* D435i: [pyrealsense2](https://pypi.org/project/pyrealsense2/)
## Robot Interface
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:
@ -35,7 +33,7 @@ The primary developer interface to Stretch_Body is the [Robot class](https://gi
In [1]:
```
And type in the following:
Then type in the following:
```python linenums="1"
import time
@ -52,7 +50,7 @@ robot.stop()
```
As you can see, this prints all Robot sensor and state data to the console every 250ms.
As you can see, this prints all robot sensors and state data to the console every 250ms.
@ -64,7 +62,7 @@ robot=stretch_body.robot.Robot()
robot.startup()
```
Here we instantiated an instance of our Robot. The call to `startup()` opens the serial ports to the various devices, loads the Robot YAML parameters, and launches a few helper threads.
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.
```python linenums="7"
for i in range(10):
@ -78,11 +76,11 @@ The call to `pretty_print()` prints to console all of the robot's sensor and sta
robot.stop()
```
Finally, the `stop()` method shuts down the Robot threads and cleanly closes the open serial ports.
Finally, the `stop()` method shuts down the threads and cleanly closes the open serial ports.
### Units
The Robot API uses SI units of:
The Robot API uses SI units:
* meters
* radians
@ -98,7 +96,7 @@ Parameters may be named with a suffix to help describe the unit type. For exampl
### The Robot Status
The Robot derives from the [Device class](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/device.py). It also encapsulates a number of other Devices:
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:
* [robot.head](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/head.py)
* [robot.arm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/arm.py)
@ -118,7 +116,7 @@ class Arm(Device):
'motor':self.motor.status,'timestamp_pc':0}
```
The Status dictionaries are automatically updated by a background thread of the Robot at around 25Hz. The Status data can be accessed via the Robot. For example:
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:
```python
if robot.arm.status['pos']>0.25:
@ -129,8 +127,6 @@ If an instantaneous snapshot of the entire Robot Status is needed, the `get_stat
```python
status=robot.get_status()
if status['arm']['pos']>0.25:
print('Arm extension greater than 0.25m')
```
### The Robot Command
@ -169,18 +165,29 @@ The `move_by()` method queues up the command to the stepper motor controller. Ho
robot.push_command()
```
The `push_command()` causes all queued up commands to be executed at once. This allows for synchronization of motion across joints. For example, the following code will cause the base, arm, and lift to initiate motion simultaneously:
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:
```python linenums="1"
import time
import stretch_body.robot
robot=stretch_body.robot.Robot()
robot.startup()
```python
robot.arm.move_by(0.1)
robot.lift.move_by(0.1)
robot.base.translate_by(0.1)
robot.push_command()
time.sleep(2.0)
robot.stop()
```
**NOTE**: In this example we call `sleep()` to allow time for the motion to complete before initiating a new motion.
!!! note
In this example we call `sleep()` to allow time for the motion to complete before initiating a new motion.
**NOTE**: 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.
!!! note
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.
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 13
- 13
stretch_body/tutorial_parameter_management.md View File

@ -1,10 +1,10 @@
# Tutorial: Parameter Management
In this tutorial we will discuss how parameters are managed in Stretch Body and show examples of how to customize your robot by overriding parameters.
In this tutorial, we will discuss how parameters are managed in Stretch Body and show examples of how to customize your robot by overriding parameters.
## Overview
Stretch Body shares a global set of parameters across all of the hardware it manages. All members of the [Device class](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/device.py) have an instance of [RobotParams](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_params.py). This class constructs a dictionary of the device parameters and well as the global parameters for each device. For example from iPython try:
Stretch Body shares a global set of parameters across all of the hardware it manages. All members of the [Device class](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/device.py) have an instance of [RobotParams](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_params.py). This class constructs a dictionary of the device parameters as well as the global parameters for each device. For example, from iPython try:
```python
import stretch_body.arm
@ -31,7 +31,7 @@ Out[7]:
'range_m': [0.0, 0.52]}
```
Or to access another device params:
or to access another device params:
```python
a.robot_params['lift']
@ -64,10 +64,10 @@ Stretch Body utilizes a prioritized parameter organization such that default set
| 1 | user_params | $HELLO_FLEET_PATH/$HELLO_FLEET_ID/ stretch_user_params.yaml | Yaml file for users to override default settings and to define custom configurations. |
| 2 | configuration_params | $HELLO_FLEET_PATH/$HELLO_FLEET_ID/ stretch_configuration_params.yaml | Robot specific data (eg, serial numbers and calibrations). Calibration tools may update these. |
| 3 | external_params | Imported via a list defined as `params` in stretch_user_params.yaml | External Python parameter dictionaries for 3rd party devices and peripherals. |
| 4 | nominal_params | stretch_body.robot_params_RE2V0.py | Generic systems settings (Common across all robots of a given model. |
| 5 | nominal_system_params | stretch_body.robot_params.py | Generic systems settings (Common across all robots models). |
| 4 | nominal_params | stretch_body.robot_params_RE2V0.py | Generic systems settings (common across all robots of a given model. |
| 5 | nominal_system_params | stretch_body.robot_params.py | Generic systems settings (common across all robot models). |
This allows the user to override any of the parameters by defining it in their `stretch_user_params.yaml`. It also allows Hello Robot to periodically update parameters defined in the Python files via Pip upadates.
This allows the user to override any of the parameters by defining it in their `stretch_user_params.yaml`. It also allows Hello Robot to periodically update parameters defined in the Python files via Pip updates.
The tool `stretch_params.py` will print out all of the robot parameters as well as their origin. For example:
@ -98,9 +98,9 @@ stretch_body.robot_params.nominal_params param.arm.motion.slow.vel_m 0.05
...
```
The tool display each parameter's value as well as which parameter file it was loaded from.
The tool displays each parameter's value as well as which parameter file it was loaded from.
Now let's say you want to override the default motion settings for the arm. You could add the following to your `stretch_user_params.yaml`:
For example, if you want to override the default motion settings for the arm, you could add the following to your `stretch_user_params.yaml`:
```yaml
arm:
@ -118,24 +118,24 @@ stretch_body.robot_params.nominal_params param.arm.motion.default.accel_m 0.1
stretch_body.robot_params.nominal_params param.arm.motion.default.vel_m 0.1
```
The factory parameter settings should suffice for most use cases.
!!! note
The factory parameter settings should suffice for most use cases.
## Programmatically Modifying and Storing Parameters
A user want to compute the value of a parameter programmatically and modify the robot settings accordingly. For example, in the Stretch Factory tool [REx_base_calibrate_wheel_seperation.py](https://github.com/hello-robot/stretch_factory/blob/master/python/tools/REx_base_calibrate_wheel_separation.py) we see that the parameter `wheel_seperation_m` is recomputed as the variable `d_avg`. This new value could be used during the robot execution by simply
A user can compute the value of a parameter programmatically and modify the robot settings accordingly. For example, in the Stretch Factory tool [REx_base_calibrate_wheel_seperation.py](https://github.com/hello-robot/stretch_factory/blob/master/python/tools/REx_base_calibrate_wheel_separation.py) we see that the parameter `wheel_seperation_m` is recomputed as the variable `d_avg`. This new value could be used during the robot execution by simply:
```python
robot.base.params['wheel_seperation_m']=d_vag
```
, or it could be saved as a user override as :
or it could be saved as a user override:
```python
robot.write_user_param_to_YAML('base.wheel_separation_m', d_avg)
```
This will update the file `stretch_user_params.yaml`
This will update the file `stretch_user_params.yaml`.
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 25
- 33
stretch_body/tutorial_robot_motion.md View File

@ -1,6 +1,6 @@
# Tutorial: Robot Motion
As we've seen in previous tutorials, commanding robot motion can be simple and straight forward. For example, incremental motion of the arm can be commanded by:
As we've seen in previous tutorials, commanding robot motion is simple and straightforward. For example, the incremental motion of the arm can be commanded by:
```python linenums="1"
import stretch_body.robot
@ -14,7 +14,7 @@ time.sleep(2.0)
robot.stop()
```
Or, absolute motion can be commanded by:
The absolute motion can be commanded by:
```python linenums="1"
import stretch_body.robot
@ -30,9 +30,7 @@ robot.stop()
## Waiting on Motion
In the above examples we execute a `time.sleep()` after `robot.push_command()`. This allows the joint time to complete its motion. Instead we can use the `wait_until_at_setpoint()` method that polls the joint position versus the target position. We can also interrupt a motion by sending a new motion command at anytime. For example, try the following script:
In the above examples, we executed a `time.sleep()` after `robot.push_command()`. This allows the joint time to complete its motion. As an alternative, we can use the `wait_until_at_setpoint()` method that polls the joint position versus the target position. We can also interrupt a motion by sending a new motion command at any time. For example, try the following script:
```python linenums="1"
import stretch_body.robot
@ -60,13 +58,13 @@ You will see the arm fully retract, begin to extend, and then fully retract agai
## Motion Profiles
All joints support [trapezoidal based motion](https://www.motioncontroltips.com/what-is-a-motion-profile/) generation. Other types of controllers are available (splined trajectory, PID, velocity, etc) but they are not covered here . The trapezoidal motion controllers require three values:
All joints support [trapezoidal motion profile](https://www.motioncontroltips.com/what-is-a-motion-profile/) generation. Other types of controllers are available (splined trajectory, PID, velocity, etc) but they are not covered here. The trapezoidal motion controllers require three values:
* x: target position of joint
* v: maximum velocity of motion
* a: acceleration of motion
We provide 'default' settings for the velocity and acceleration settings, as well as 'fast', and 'slow' settings. These values have been tuned to be appropriate for safe motion of the robot. These values can queried using the `stretch_params.py` tool:
We provide 'defaults' for the velocity and acceleration settings, as well as 'fast', and 'slow' settings. These values have been tuned to be appropriate for the safe movement of the robot. These values can be queried using the `stretch_params.py` tool:
```bash
>>$stretch_params.py | grep arm | grep motion | grep default
@ -98,7 +96,7 @@ All joints obey motion limits which are specified in the robot parameters.
stretch_user_params.yaml param.arm.range_m [0.0, 0.515]
```
These are the mechanical limits of the joint. These limits have been set at the factory to prevent damage to the hardware. It is not recommended to set them to be greater than the factory specified values. However, they can be further limited if desired by setting soft motion limits:
These are the mechanical limits of the joints and have been set at the factory to prevent damage to the hardware. It is not recommended to set them to be greater than the factory-specified values. However, they can be further limited if desired by setting soft motion limits:
```python
import stretch_body.robot
@ -121,15 +119,11 @@ robot.arm.wait_until_at_setpoint()
robot.stop()
```
## Controlling Dynamixel Motion
The above examples have focused on the motion of the arm. Like the lift and the base, the arm utilizes Hello Robot's custom stepper motor controller. Control of the Dynamixels of the head and the end-of-arm is very similar to that of the arm (though not identical).
As we see here, the `robot.push_command` call is not required as the motion begins instantaneously and is not queued. In addition, the Dynamixel servos are managed as a chain of devices -- so we must pass in the joint name along with the command.
The above examples have focused on the motion of the arm. Like the lift and the base, the arm utilizes Hello Robot's custom stepper motor controller. Control of the Dynamixels of the head and the end-of-arm is very similar to that of the arm, though not identical.
As we see here, the `robot.push_command()` call is not required as the motion begins instantaneously and is not queued. In addition, the Dynamixel servos are managed as a chain of devices, so we must pass in the joint name along with the command.
```python
import stretch_body.robot
@ -151,7 +145,7 @@ time.sleep(3.0)
robot.stop()
```
Similarly to the stepper joints, the Dynamixel joints accept motion profile and motion limit commands. For example, here we restrict the head pan range of motion while executing both a fast and slow move:
Similar to the stepper joints, the Dynamixel joints accept motion profile and motion limit commands. For example, here we restrict the head pan range of motion while executing both a fast and slow move:
```python
import stretch_body.robot
@ -179,11 +173,9 @@ time.sleep(3.0)
robot.stop()
```
## Base Velocity Control
The Base also supports a velocity control mode which can be useful for use with navigation planner. The Base controllers will automatically switch between velocity and position based control. For example:
The Base also supports a velocity control mode which can be useful with navigation planners. The Base controllers will automatically switch between velocity and position control. For example:
```python
robot.base.translate_by(x_m=0.5)
@ -197,14 +189,14 @@ time.sleep(4.0) #wait
robot.base.set_rotational_velocity(v_r=0.0) #stop motion
robot.push_command()
```
As shown, care should be taken to set commanded velocities to zero on exit to avoid runaway.
!!! warning
As shown, care should be taken to set commanded velocities to zero on exit to avoid runaway.
## Advanced Topics
### Stepper Control Modes
Most users will control robot motion using the `move_to` and `move_by` commands as described above. There are numerous other low-level controller modes available. While these are a topic for advanced users, it is worth noting that each joint has a default safety mode and a default position control mode. These are:
Most users will control robot motion using the `move_to` and `move_by` commands as described above. However, there are numerous other low-level controller modes available. While this is a topic for advanced users, it is worth noting that each joint has a default safety mode and a default position control mode. These are:
| Joint | Default Safety Mode | Default Position Control Mode |
| --------------- | --------------------------- | ----------------------------- |
@ -217,11 +209,11 @@ Most users will control robot motion using the `move_to` and `move_by` commands
| wrist_yaw | Torque disabled | Trapezoidal position control |
| stretch_gripper | Torque disabled | Trapezoidal position control |
Each joint remains in Safety Mode when no program is running. When the `<device>.startup()` function is called, the joint controller transitions from Safety Mode to its Default Position Control Mode. It is then placed back in Safety Mode when `<device>.stop()` is called.
Each joint remains in its `Safety Mode` when no program is running. When the `<device>.startup()` function is called, the joint controller transitions from `Safety Mode` to its `Default Position Control Mode`. It is then placed back in `Safety Mode` when `<device>.stop()` is called.
### Motion Runstop
Runstop activation will cause the Base, Arm, and Lift to switch to Safety Mode and for subsequent motion commands will be ignored. The motion commands will resume smoothly when the runstop is deactivated. This is usually done via the runstop button. However, it can also be done via the Pimu interface. For example:
Runstop activation will cause the Base, Arm, and Lift to switch to `Safety Mode` and subsequent motion commands will be ignored. The motion commands will resume smoothly when the Runstop is deactivated. This is usually done via the Runstop button. However, it can also be done via the Pimu interface. For example:
```python
import stretch_body.robot
@ -253,18 +245,15 @@ robot.arm.wait_until_at_setpoint()
robot.stop()
```
### Guarded Motion
The Arm, Lift, and Base support a guarded motion function. It will automatically transition the actuator from Control mode to Safety mode when the exerted motor torque exceeds a threshold.
The Arm, Lift, and Base support a guarded motion function. It will automatically transition the actuator from Control mode to Safety mode when the exerted motor torque exceeds a threshold.
This functionality is most useful for the Lift and the Arm. It allows these joints to safely stop upon contact. It can be used to:
* Safely stop when contacting an actuator hardstop
* Safely stop when contacting an actuator hard stop
* Safely stop when making unexpected contact with the environment or a person
* Make a guarded motion where the robot reaches to a surface and then stops
* Make a guarded motion where the robot reaches a surface and then stops
For more information on guarded motion, see the [Contact Models Tutorial](./tutorial_contact_models.md)
@ -282,7 +271,7 @@ stretch_body.robot_params.nominal_params param.hello-motor-right-wheel.gains.e
### Motion Status
It can be useful to poll the status of a joint during motion in order to modify the robot behavior, etc. The useful status values include:
It can be useful to poll the status of a joint during a motion to modify the robot's behavior, etc. The useful status values include:
```python
robot.arm.status['pos'] #Joint position
@ -306,11 +295,14 @@ The following update rates apply to Stretch:
| Command data for Arm, Lift, Base, Wacc, Pimu | N/A | Commands are queued and executed upon calling robot.push_command( ) |
| Command data for End of Arm and Head servos | N/A | Commands execute immediately |
Motion commands are non-blocking and it is the responsibility of the user code to poll the Robot Status to determine when and if a motion target has been achieved.
!!! note
Motion commands are non-blocking and it is the responsibility of the user code to poll the Robot Status to determine when and if a motion target has been achieved.
The Stretch_Body interface is not designed to support high bandwidth control applications. The natural dynamics of the robot actuators do not support high bandwidth control, and the USB based interface limits high rate communication.
!!! info
The Stretch Body interface is not designed to support high bandwidth control applications. The natural dynamics of the robot actuators do not support high bandwidth control, and the USB-based interface limits high-rate communication.
In practice, a Python based control loop that calls push_command( ) at 1Hz to 10Hz is sufficiently matched to the robot natural dynamics.
!!! tip
In practice, a Python-based control loop that calls push_command() at 1Hz to 10Hz is sufficiently matched to the robot's natural dynamics.
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 16
- 16
stretch_body/tutorial_robot_sensors.md View File

@ -2,11 +2,11 @@
## Introduction
Stretch Body exposes a host of sensor data through the status dictionaries of its devices. In this tutorial we'll cover how to access, view, and configure this sensor data.
Stretch Body exposes a host of sensor data through the status dictionaries of its devices. In this tutorial, we'll cover how to access, view, and configure this sensor data.
## Tools to View Sensor Data
There are two useful tools for scoping Pimu and Wacc sensor data in real-time:
There are two useful tools for scoping Pimu and Wacc sensor data in real-time:
```bash
>>$ stretch_pimu_scope.py --help
@ -39,7 +39,7 @@ optional arguments:
--bump Scope base imu bump level
```
And,
and,
```bash
>>$ stretch_wacc_scope.py --help
@ -116,7 +116,7 @@ Firmware version: Stepper.v0.2.0p1
## Accessing the Status Dictionaries
Each Robot device has a status dictionary that is automatically updates with the latest sensor data. The primary dictionaries are:
Each Robot device has a status dictionary that is automatically updated with the latest sensor data. The primary dictionaries are:
* [Stepper Status](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/stepper.py#L104)
* [Wacc Status](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/wacc.py#L44)
@ -139,7 +139,7 @@ for i in range(10):
## Base IMU
The base has a 9 DOF IMU using the 9 DOF FXOS8700 + FXAS21002 chipset. This is the same chipset as used on the [Adafruit NXP IMU board](https://www.adafruit.com/product/3463).
The base has a 9-DoF IMU using the 9-DoF FXOS8700 + FXAS21002 chipset. This is the same chipset used on the [Adafruit NXP IMU board](https://www.adafruit.com/product/3463).
The [Pimu](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/pimu.py) reports back the IMU sensor readings in its [IMU status dictionary](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/pimu.py#L27). For example, from iPython try:
@ -200,7 +200,7 @@ It reports:
These values are computed on the Pimu. As we can see in [its firmware code](https://github.com/hello-robot/stretch_firmware/blob/master/arduino/hello_pimu/IMU.cpp), a 100Hz Madgwick filter is used to compute the orientation.
Stretch Body also implements a bump detector using the the IMU accelerometers. This detector simply [computes the sum-of-squares of AX, AY, and AZ](https://github.com/hello-robot/stretch_firmware/blob/master/arduino/hello_pimu/IMU.cpp#L223). This value is then compared to the following threshold to determine if a bump is present:
Stretch Body also implements a bump detector using the IMU accelerometers. This detector simply [computes the sum of squares of AX, AY, and AZ](https://github.com/hello-robot/stretch_firmware/blob/master/arduino/hello_pimu/IMU.cpp#L223). This value is then compared to the following threshold to determine if a bump is detected:
```bash
>>$ stretch_params.py | grep pimu | grep bump
@ -224,11 +224,12 @@ for i in range(100):
print('Bump event count %d'%r.pimu.status['bump_event_cnt'])
```
**NOTE**: The IMU is calibrated by Hello Robot at the factory. Please contact Hello Robot support for details on recalibrating your IMU.
!!! note
The IMU is calibrated by Hello Robot at the factory. Please contact Hello Robot support for details on recalibrating your IMU.
## Wrist Accelerometer
The wrist includes a 3 axis [ADXL343](https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL343.pdf) accelerometer which provides bump and tap detection capabilities. The Wacc reports back AX, AY, and AZ [in its status dictionary](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/wacc.py#L44) From iPython try:
The wrist includes a 3 axis [ADXL343](https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL343.pdf) accelerometer which provides bump and tap detection capabilities. The Wacc reports back AX, AY, and AZ [in its status dictionary](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/wacc.py#L44). For example, from iPython try:
```python
import stretch_body.robot
@ -276,9 +277,9 @@ Firmware version: Wacc.v0.2.0p1
```
In addition to AX, AY, and AZ we also see the `single_tap_count` value which reports back a count of the number of single-tap contacts the accelerometer has experiences since power-up.
In addition to AX, AY, and AZ we also see the `single_tap_count` value which reports back a count of the number of single-tap contacts the accelerometer has experienced since power-up.
The following Wacc parameters configure the accelerometer low-pass filter and single-tap settings. See the [ADXL343](https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL343.pdf) datasheet for more details.
The following Wacc parameters configure the accelerometer low-pass filter and single-tap settings. See the [ADXL343](https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL343.pdf) datasheet for more details.
```bash
>>$ stretch_params.py | grep wacc
@ -290,11 +291,9 @@ stretch_body.robot_params.nominal_params param.wacc.config.accel_single_tap
stretch_configuration_params.yaml param.wacc.config.accel_gravity_scale 1.0
```
## Cliff Sensors
Stretch has four Sharp GP2Y0A51SK0F IR cliff sensors pointed towards the floor. These report the distance to the floor, allowing for detection of thresholds, stair edges, etc.
Stretch has four Sharp GP2Y0A51SK0F IR cliff sensors pointed toward the floor. These report the distance to the floor, allowing for the detection of thresholds, stair edges, etc.
Relevant parameters for the cliff sensors are:
@ -325,9 +324,10 @@ Calibration passed. Storing to YAML...
The `stop_at_cliff` field causes the robot to execute a Runstop when the cliff sensor readings exceed the value `cliff_thresh`. The parameter `cliff_LPF` defines the low-pass-filter rate (Hz) on the analog sensor readings.
**Note: As configured at the factory, `stop_at_cliff` is set to zero and Stretch does not stop its motion based on the cliff sensor readings. Hello Robot makes no guarantees as to the reliability of Stretch's ability to avoid driving over ledges and stairs when this flag is enabled.**
!!! note
As configured at the factory, `stop_at_cliff` is set to zero and Stretch does not stop its motion based on the cliff sensor readings. Hello Robot makes no guarantees as to the reliability of Stretch's ability to avoid driving over ledges and stairs when this flag is enabled.
The range values from the sensors can be read from the `robot.pimu.status` message. Relevant fields are:
The range values from the sensors can be read from the `robot.pimu.status` message. The relevant fields are:
```python
import stretch_body.robot
@ -345,7 +345,7 @@ Out[5]: False
```
The `cliff_event` flag is set when any of the four sensor readings exceed `cliff_thresh` and `stop_at_cliff` is enabled. In the event of a Cliff Event, it must be reset by `robot.pimu.cliff_event_reset()`in order to reset the generated Runstop.
The `cliff_event` flag is set when any of the four sensor readings exceed `cliff_thresh` and `stop_at_cliff` is enabled. In the event of a Cliff Event, it must be reset by `robot.pimu.cliff_event_reset()` to reset the generated Runstop.
The cliff detection logic can be found in the [Pimu firmware](https://github.com/hello-robot/stretch_firmware/blob/master/arduino/hello_pimu/Pimu.cpp).

+ 8
- 9
stretch_body/tutorial_safe_coding.md View File

@ -1,6 +1,6 @@
# Tutorial: Safety Features
Stretch includes a number of built-in functions that help it maintain safe operating conditions. These functions can be disabled and enabled via the robot user parameters.
Stretch includes several built-in functions that help it maintain safe operating conditions. These functions can be disabled and enabled via the robot user parameters.
## Logging
@ -15,7 +15,7 @@ robot:
## Runstop Functions
The runstop deactivates all robot motion. It can be triggered by the physical button on the robot's head. It can also be triggered by internal monitors of the system state. The default configuration of these parameters is:
The Runstop deactivates all robot motion. It can be triggered by the physical button on the robot's head. It can also be triggered by internal monitors of the system state. The default configuration of these parameters is:
```bash
>>$ stretch_params.py | grep stop_at
@ -36,11 +36,12 @@ stretch_body.robot_params.nominal_params param.pimu.config.stop_at_tilt 0
The [Pimu firmware](https://github.com/hello-robot/stretch_firmware/tree/master/arduino/hello_pimu) details the implementation of these functions.
**NOTE**: The `stop_at_cliff` and `stop_at_tilt` functions are disabled by default as they are not robust to normal operating conditions of the robot. Therefore do not rely on these functions for robot safety.
!!! warning
The `stop_at_cliff` and `stop_at_tilt` functions are disabled by default as they are not robust to the normal operating conditions of the robot. Therefore do not rely on these functions for robot safety.
## Robot Monitor
The [Robot Monitor](https://github.com/hello-robot/stretch_body/blob/master/python/stretch_body/robot_monitor.py) is a thread that monitors the Robot Status data for significant events. For example, it can monitor the error flags from the Dynamixel servos and notify when a thermal overload occurs. The Robot Monitor logs warnings to a log file by default. T
The [Robot Monitor](https://github.com/hello-robot/stretch_body/blob/master/python/stretch_body/robot_monitor.py) is a thread that monitors the Robot Status data for significant events. For example, it can monitor the error flags from the Dynamixel servos and notify when a thermal overload occurs. The Robot Monitor logs warnings to a log file by default.
The default parameters associated with RobotMonitor are:
@ -78,7 +79,7 @@ robot:
log_to_console: 1
```
The run the tool and hit the runstop button, then hold it down for 2 seconds:
Then run the tool and hit the Runstop button, and then hold it down for 2 seconds:
```bash
>>$ stretch_robot_monitor.py
@ -91,11 +92,9 @@ Starting Robot Monitor. Ctrl-C to exit
[INFO] [robot_monitor]: Runstop deactivated
```
## Robot Sentry
The [Robot Sentry](https://github.com/hello-robot/stretch_body/blob/master/python/stretch_body/robot_sentry.py) is a thread that can override and also generate commands to the robot hardware. It's purpose is to keep the robot operating within a safe regime. For example, the Robot Sentry monitors the position of the Lift and Arm and limits the maximum base velocity and acceleration (in order to reduce the chance of toppling). The Robot Sentry reports events to the log file as well.
The [Robot Sentry](https://github.com/hello-robot/stretch_body/blob/master/python/stretch_body/robot_sentry.py) is a thread that can override and also generate commands to the robot hardware. Its purpose is to keep the robot operating within a safe regime. For example, the Robot Sentry monitors the position of the Lift and Arm and limits the maximum base velocity and acceleration to reduce the chance of toppling. The Robot Sentry reports events to the log file as well.
| YAML | Function |
| ------------------------ | ------------------------------------------------------------ |
@ -106,7 +105,7 @@ The [Robot Sentry](https://github.com/hello-robot/stretch_body/blob/master/pytho
## Collision Avoidance
See the [Collision Avoidance Tutorial](./tutorial_collision_avoidance.md) for more information the the Stretch collision avoidance system.
See the [Collision Avoidance Tutorial](./tutorial_collision_avoidance.md) for more information on the Stretch collision avoidance system.
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 16
- 16
stretch_body/tutorial_splined_trajectories.md View File

@ -4,12 +4,11 @@ Stretch Body supports splined trajectory controllers across all of its joints. T
## What are Splined Trajectories?
A splined trajectory is a smooth path that a robot joint follows over a specific period of time. [Cubic or quintic splines](https://en.wikipedia.org/wiki/Spline_(mathematics)) are used to represent the trajectory. As shown below, the splines (blue) are defined by a series of user provided waypoints (black dot). A waypoint is simply a target position, velocity, and optional acceleration at a given time. The spline ensures continuity and smoothness when interpolating between the waypoint targets.
A splined trajectory is a smooth path that a robot joint follows over a specific period of time. [Cubic or quintic splines](https://en.wikipedia.org/wiki/Spline_(mathematics)) are used to represent the trajectory. As shown below, the splines (blue) are defined by a series of user-provided waypoints (black dot). A waypoint is simply a target position, velocity, and optional acceleration at a given time. The spline ensures continuity and smoothness when interpolating between the waypoint targets.
During execution, the trajectory controller uses this splined representation to compute the instantaneous desired position, velocity, and acceleration of the joint (red). On Stretch, this instantaneous target is then passed to a lower-level position or velocity controller.
Splined trajectories are particularly useful when you want to coordinate motion across several joints. Because the trajectory representation is time based, it is straightforward to encode multi-joint coordination. Stretch Body supports both cubic and quintic spline. A quintic spline waypoint includes acceleration in the waypoint target, while a cubic spline does not.
Splined trajectories are particularly useful when you want to coordinate motion across several joints. Because the trajectory representation is time-based, it is straightforward to encode multi-joint coordination. Stretch Body supports both cubic and quintic splines. A quintic spline waypoint includes acceleration in the waypoint target, while a cubic spline does not.
![alt_text](images/splined_traj.png "image_tooltip")
@ -44,7 +43,8 @@ The tool GUI allows you to interactively construct a splined trajectory and then
![alt_text](images/traj_gui.png "image_tooltip")
**NOTE**: Use caution when commanding the base. Ensure that attached cables are long enough to support base motion. Alternatively you may want to put the base on top of a book so the wheel don't touch the ground.
!!! note
Use caution when commanding the base. Ensure that the attached cables are long enough to support the base motion. Alternatively, you may want to put the base on top of a book so the wheels don't touch the ground.
Finally, you can explore a full-body trajectory using the non-GUI version of the tool:
@ -52,11 +52,9 @@ Finally, you can explore a full-body trajectory using the non-GUI version of the
>>$ stretch_trajectory_jog.py --full_body
```
## Programming Trajectories
Programming a splined trajectory is straightforward. Try the following from iPython:
Programming a splined trajectory is straightforward. For example, try the following from iPython:
```python
import stretch_body.robot
@ -88,22 +86,21 @@ This will cause the arm to move from its current position to 0.45m, then back to
* This will execute a Cubic spline as we did not pass in accelerations to in `r.arm.trajectory.add`
* The call to `r.arm.follow_trajectory` is non-blocking and the trajectory generation is handled by a background thread of the Robot class
If you're interested in exploring the trajectory API further the [code for the `stretch_trajectory_jog.py`](https://github.com/hello-robot/stretch_body/blob/master/tools/bin/stretch_trajectory_jog.py)is a great reference to get started.
If you're interested in exploring the trajectory API further the [code for the `stretch_trajectory_jog.py`](https://github.com/hello-robot/stretch_body/blob/master/tools/bin/stretch_trajectory_jog.py) is a great reference to get started.
## Advanced: Controller Parameters
Sometimes the robot motion isn't quite what is expected when executing a splined trajectories. It is important that the trajectory be well-formed, meaning that it:
Sometimes the robot's motion isn't quite what is expected when executing a splined trajectory. It is important that the trajectory be well-formed, meaning that it:
* Respects the maximum velocity and accelerations limits of the joint
* Doesn't create a large 'excursion' outside of the acceptable range of motion in order to hit a target waypoint
* Doesn't create a large 'excursion' outside of the acceptable range of motion to hit a target waypoint
* Doesn't have waypoints so closely spaced together that it exceeds the nominal control rates of Stretch (~10-20 Hz)
For example, the arm trajectory below has a large excursion outside of the joints range of motion (white). This is because the second waypoint expects a non-zero velocity when the arm reaches full extension.
For example, the arm trajectory below has a large excursion outside of the joint's range of motion (white). This is because the second waypoint expects a non-zero velocity when the arm reaches full extension.
![](./images/bad_trajectory.png)
Often the trajectory waypoints will be generated from a motion planner. It is important that this planner incorporates the position, velocity, and acceleration constraints of the joint. These can be found by, for example
Often the trajectory waypoints will be generated from a motion planner. It is important for the planner to incorporate the position, velocity, and acceleration constraints of the joint. These can be found by, for example:
```bash
>>$ stretch_params.py | grep arm | grep motion | grep trajectory
@ -114,11 +111,14 @@ stretch_body.robot_params.nominal_params param.arm.motion.trajectory_max.accel_m
stretch_user_params.yaml param.arm.range_m [0.0, 0.515]
```
Fortunately the Stretch Body [Trajectory](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/trajectories.py) classes do some preliminary feasibility checking of trajectories using the [is_segment_feasible function](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/hello_utils.py#L290). This checks if the generated motions lie within the constraints of the `trajectory_max` parameters.
Fortunately, the Stretch Body [Trajectory](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/trajectories.py) classes do some preliminary feasibility checking of trajectories using the [is_segment_feasible function](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/hello_utils.py#L290). This checks if the generated motions lie within the constraints of the `trajectory_max` parameters.
It is generally important for the waypoints to be spaced far apart. Stretch isn't a dynamic and fast-moving robot, so there isn't a practical advantage to closely spaced waypoints at any rate.
It is generally important for the waypoints to be spaced far apart. Stretch isn't a dynamic and fast moving robot, so there isn't a practical advantage to closely spaced waypoints at any rate.
The stepper controllers (arm, lift, and base) can be updated at approximately 20 Hz maximum. Therefore, if your waypoints are spaced 50 ms apart, you run the risk of overflowing the stepper controller. Likewise, the Dynamixel joints can be updated at approximately 12 Hz.
The stepper controllers (arm, lift, and base) can be updated at approximately 20 Hz maximum. Therefore, if your waypoints are spaced 50 ms apart, you run the risk of overflowing the stepper controller. Likewise, the Dynamixel joints can be updated at approximately 12 Hz. As a rule of thumb, spacing the waypoints over 100 ms apart is a good idea.
!!! tip
As a rule of thumb, spacing the waypoints over 100 ms apart is a good idea.
------
<div align="center"> All materials are Copyright 2022 by Hello Robot Inc. Hello Robot and Stretch are registered trademarks.</div>

+ 60
- 32
stretch_body/tutorial_stretch_body_api.md View File

@ -1,13 +1,11 @@
# Stretch Body API Reference
Stretch Body is the Python interface to working with the Stretch RE1. This page serves as a reference of the interfaces defined in the `stretch_body` library.
Stretch Body is the Python interface for working with Stretch. This page serves as a reference for the interfaces defined in the `stretch_body` library.
See the [Stretch Body Tutorials](https://docs.hello-robot.com/0.2/stretch-tutorials/stretch_body/) for additional information on working with this library.
## The Robot Class
### Using the Robot class
The most common interface to Stretch is the [Robot](#stretch_body.robot.Robot) class. It is typically initialized as:
The most common interface to Stretch is the [Robot](#stretch_body.robot.Robot) class. This class encapsulates all devices on the robot. It is typically initialized as:
```python linenums='1'
import stretch_body.robot
@ -23,7 +21,7 @@ if not r.is_calibrated():
# interact with the robot here
```
The [`startup()`](#stretch_body.robot.Robot.startup) and [`home()`](#stretch_body.robot.Robot.home) methods starts communication with and homes each of the robot's devices, respectively. Through the [Robot](#stretch_body.robot.Robot) class, users can interact with all other devices on the robot. For example, continuing the example above:
The [`startup()`](#stretch_body.robot.Robot.startup) and [`home()`](#stretch_body.robot.Robot.home) methods start communication with and home each of the robot's devices, respectively. Through the [Robot](#stretch_body.robot.Robot) class, users can interact with all devices on the robot. For example, continuing the example above:
```python linenums='12'
# moving joints on the robot
@ -40,15 +38,17 @@ r.pimu.pretty_print()
r.stop()
```
Each of these devices are defined in other modules within `stretch_body`. In the [following section](#the-device-classes), we'll look at the API of these classes. The [`stop()`](#stretch_body.robot.Robot.stop) method shuts down communication with the robot's devices. All of [Robot's](#stretch_body.robot.Robot) subroutines are documented below.
Each of these devices is defined in separate modules within `stretch_body`. In the following section, we'll look at the API of these classes. The [`stop()`](#stretch_body.robot.Robot.stop) method shuts down communication with the robot's devices.
All methods in the [Robot](#stretch_body.robot.Robot) class are documented below.
::: stretch_body.robot.Robot
## The Device Classes
## The Device Class
The `stretch_body` library is modular in design. Each subcomponent of Stretch is defined in its own class and [the Robot class](#the-robot-class) provides an interface that ties all of these classes together. This modularity allows users to plug in new/modified subcomponents into the [Robot](#stretch_body.robot.Robot) interface by extending a device class.
The `stretch_body` library is modular in design. Each subcomponent of Stretch is defined in its class and the [Robot class](#the-robot-class) provides an interface that ties all of these classes together. This modularity allows users to plug in new/modified subcomponents into the [Robot](#stretch_body.robot.Robot) interface by extending the Device class.
It is possible to interface with a single subcomponent of Stretch by initializing its device class directly. In this section, we'll look at the API of seven device classes: the [arm](#stretch_body.arm.Arm), [lift](#stretch_body.lift.Lift), [base](#stretch_body.base.Base), [head](#stretch_body.head.Head), [end of arm](#stretch_body.end_of_arm.EndOfArm), [wacc](#stretch_body.wacc.Wacc), and [pimu](#stretch_body.pimu.Pimu) subcomponents of Stretch.
It is possible to interface with a single subcomponent of Stretch by initializing its device class directly. In this section, we'll look at the API of seven subclasses of the Device class: the [Arm](#stretch_body.arm.Arm), [Lift](#stretch_body.lift.Lift), [Base](#stretch_body.base.Base), [Head](#stretch_body.head.Head), [EndOfArm](#stretch_body.end_of_arm.EndOfArm), [Wacc](#stretch_body.wacc.Wacc), and [Pimu](#stretch_body.pimu.Pimu) subcomponents of Stretch.
### Using the Arm class
@ -70,7 +70,7 @@ a.home()
# interact with the arm here
```
Since both [Arm](#stretch_body.arm.Arm) and [Robot](#stretch_body.robot.Robot) subclass [Device](#stretch_body.device.Device), the same [`startup()`](#stretch_body.arm.Arm.startup) and [`stop()`](#stretch_body.arm.Arm.stop) methods are available here, as well as other [Device](#stretch_body.device.Device) methods such as [`home()`](#stretch_body.arm.Arm.home). Using the [Arm](#stretch_body.arm.Arm) class, we can read the arm's current state and send commands to the joint. For example, continuing the example above:
Since both [Arm](#stretch_body.arm.Arm) and [Robot](#stretch_body.robot.Robot) are subclasses of the [Device](#stretch_body.device.Device) class, the same [`startup()`](#stretch_body.arm.Arm.startup) and [`stop()`](#stretch_body.arm.Arm.stop) methods are available here, as well as other [Device](#stretch_body.device.Device) methods such as [`home()`](#stretch_body.arm.Arm.home). Using the [Arm](#stretch_body.arm.Arm) class, we can read the arm's current state and send commands to the joint. For example, continuing the example above:
```python linenums='11'
starting_position = a.status['pos']
@ -90,7 +90,9 @@ a.push_command()
a.motor.wait_until_at_setpoint()
```
The [`move_to()`](#stretch_body.arm.Arm.move_to) and [`move_by()`](#stretch_body.arm.Arm.move_by) methods queue absolute and relative commands to the arm respectively, while the nonblocking [`push_command()`](#stretch_body.arm.Arm.push_command) method pushes the queued command to the hardware for execution. Arm's attribute `motor`, an instance of the [Stepper](#stretch_body.stepper.Stepper) class, has [`wait_until_at_setpoint()`](#stretch_body.stepper.Stepper.wait_until_at_setpoint) which blocks program execution until the joint reaches the commanded goal. With [P1 or greater firmware](https://github.com/hello-robot/stretch_firmware/blob/master/tutorials/docs/updating_firmware.md) installed, it is also possible to queue a waypoint trajectory for the arm to follow:
The [`move_to()`](#stretch_body.arm.Arm.move_to) and [`move_by()`](#stretch_body.arm.Arm.move_by) methods queue absolute and relative position commands to the arm, respectively, while the nonblocking [`push_command()`](#stretch_body.arm.Arm.push_command) method pushes the queued position commands to the hardware for execution.
The attribute `motor`, an instance of the [Stepper](#stretch_body.stepper.Stepper) class, has the method [`wait_until_at_setpoint()`](#stretch_body.stepper.Stepper.wait_until_at_setpoint) which blocks program execution until the joint reaches the commanded goal. With [firmware P1 or greater](https://github.com/hello-robot/stretch_firmware/blob/master/tutorials/docs/updating_firmware.md) installed, it is also possible to queue a waypoint trajectory for the arm to follow:
```python linenums='26'
starting_position = a.status['pos']
@ -106,7 +108,9 @@ a.follow_trajectory()
import time; time.sleep(9)
```
Arm's attribute `trajectory`, an instance of the [PrismaticTrajectory](#stretch_body.trajectories.PrismaticTrajectory) class, has [`add()`](#stretch_body.trajectories.PrismaticTrajectory.add) which adds a single waypoint in a linear sliding trajectory. For a well formed `trajectory` (see [`is_valid()`](#stretch_body.trajectories.Spline.is_valid)), the [`follow_trajectory()`](#stretch_body.arm.Arm.follow_trajectory) method kicks off trajectory following for the telescoping arm. It is also possible to dynamically restrict the arm joint's range:
The attribute `trajectory`, an instance of the [PrismaticTrajectory](#stretch_body.trajectories.PrismaticTrajectory) class, has the method [`add()`](#stretch_body.trajectories.PrismaticTrajectory.add) which adds a single waypoint in a linear sliding trajectory. For a well-formed `trajectory` (see [`is_valid()`](#stretch_body.trajectories.Spline.is_valid)), the [`follow_trajectory()`](#stretch_body.arm.Arm.follow_trajectory) method starts tracking the trajectory for the telescoping arm.
It is also possible to dynamically restrict the arm joint range:
```python linenums='37'
range_upper_limit = 0.3 # meters
@ -125,7 +129,9 @@ print(a.status['pos']) # we should expect to see ~0.3
a.stop()
```
The [`set_soft_motion_limit_min/max()`](#stretch_body.arm.Arm.set_soft_motion_limit_min) methods form the basis of an experimental [self-collision avoidance](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision.py#L47) system built into Stretch Body. All of [Arm's](#stretch_body.arm.Arm) subroutines are documented below.
The [`set_soft_motion_limit_min/max()`](#stretch_body.arm.Arm.set_soft_motion_limit_min) methods form the basis of an experimental [self-collision avoidance](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_collision.py#L47) system built into Stretch Body.
All methods in the [Arm class](#stretch_body.arm.Arm) are documented below.
::: stretch_body.arm.Arm
@ -149,7 +155,7 @@ l.home()
# interact with the lift here
```
The [`startup()`](#stretch_body.lift.Lift.startup) and [`home()`](#stretch_body.lift.Lift.home) methods are extended from the [Device](#stretch_body.device.Device) class. Reading the lift's current state and sending commands to the joint occurs similarly to the [Arm](#stretch_body.arm.Arm):
The [`startup()`](#stretch_body.lift.Lift.startup) and [`home()`](#stretch_body.lift.Lift.home) methods are extended from the [Device](#stretch_body.device.Device) class. Reading the lift's current state and sending commands to the joint occurs similarly to the [Arm](#stretch_body.arm.Arm) class:
```python linenums='11'
starting_position = l.status['pos']
@ -160,7 +166,7 @@ l.push_command()
l.motor.wait_until_at_setpoint()
```
[Lift's](#stretch_body.lift.Lift) attribute `status` is a dictionary of the joint's current status. This state information is updated in the background in real time by default (disable by initializing as [`startup(threading=False)`](#stretch_body.lift.Lift.startup)). Use the [`pretty_print()`](#stretch_body.lift.Lift.pretty_print) method to print out this state info in a human interpretable format. Setting up waypoint trajectories for the lift is also similar to the [Arm](#stretch_body.arm.Arm):
The attribute `status` is a dictionary of the joint's current status. This state information is updated in the background in real-time by default (disable by initializing as [`startup(threading=False)`](#stretch_body.lift.Lift.startup)). Use the [`pretty_print()`](#stretch_body.lift.Lift.pretty_print) method to print out this state info in a human-interpretable format. Setting up waypoint trajectories for the lift is also similar to the [Arm](#stretch_body.arm.Arm):
```python linenums='17'
starting_position = l.status['pos']
@ -175,7 +181,9 @@ l.follow_trajectory()
import time; time.sleep(6)
```
[Lift's](#stretch_body.lift.Lift) attribute `trajectory` is also an instance of the [PrismaticTrajectory](#stretch_body.trajectories.PrismaticTrajectory) class, and by providing the instantaneous velocity argument `v_m` to the [`add()`](#stretch_body.trajectories.PrismaticTrajectory.add) method, a cubic spline has been loaded into the joint's `trajectory`. The call to [`follow_trajectory()`](#stretch_body.lift.Lift.follow_trajectory) begins hardware tracking of the spline. Finally, setting soft motion limits for the lift's range happens using:
The attribute `trajectory` is also an instance of the [PrismaticTrajectory](#stretch_body.trajectories.PrismaticTrajectory) class, and by providing the instantaneous velocity argument `v_m` to the [`add()`](#stretch_body.trajectories.PrismaticTrajectory.add) method, a cubic spline can be loaded into the joint's `trajectory`. The call to [`follow_trajectory()`](#stretch_body.lift.Lift.follow_trajectory) begins hardware tracking of the spline.
Finally, setting soft motion limits for the lift's range can be done using:
```python linenums='27'
# cut out 0.2m from the top and bottom of the lift's range
@ -186,7 +194,9 @@ l.push_command()
l.stop()
```
The [`set_soft_motion_limit_min/max()`](#stretch_body.lift.Lift.set_soft_motion_limit_min) methods perform clipping of the joint's range at the firmware level (can persist across reboots). All of [Lift's](#stretch_body.lift.Lift) subroutines are documented below.
The [`set_soft_motion_limit_min/max()`](#stretch_body.lift.Lift.set_soft_motion_limit_min) methods perform clipping of the joint's range at the firmware level (can persist across reboots).
All methods in the [Lift](#stretch_body.lift.Lift) class are documented below.
::: stretch_body.lift.Lift
@ -215,7 +225,7 @@ if not b.startup():
# interact with the base here
```
Stretch's mobile base is a differential drive configuration. The left and right wheels are accessible through [Base's](#stretch_body.base.Base) `left_wheel` and `right_wheel` attributes, both of which are instances of the [Stepper](#stretch_body.stepper.Stepper) class. The [`startup()`](#stretch_body.base.Base.startup) method is extended from the [Device](#stretch_body.device.Device) class. Since the mobile base is unconstrained, there is no homing method. We can read the base's current state and send commands using:
Stretch's mobile base is a differential drive configuration. The left and right wheels are accessible through [Base](#stretch_body.base.Base) `left_wheel` and `right_wheel` attributes, both of which are instances of the [Stepper](#stretch_body.stepper.Stepper) class. The [`startup()`](#stretch_body.base.Base.startup) method is extended from the [Device](#stretch_body.device.Device) class. Since the mobile base is unconstrained, there is no homing method. The [`pretty_print()`](#stretch_body.base.Base.pretty_print) method prints out mobile base state information in a human-interpretable format. We can read the base's current state and send commands using:
```python linenums='10'
b.pretty_print()
@ -231,7 +241,9 @@ b.push_command()
b.left_wheel.wait_until_at_setpoint()
```
The [`pretty_print()`](#stretch_body.base.Base.pretty_print) method prints out mobile base state info in a human interpretable format. The [`translate_by()`](#stretch_body.base.Base.translate_by) and [`rotate_by()`](#stretch_body.base.Base.rotate_by) methods send relative commands similar to the way [`move_by()`](#stretch_body.lift.Lift.move_by) behaves for the single degree of freedom joints. The mobile base also supports velocity control:
The [`translate_by()`](#stretch_body.base.Base.translate_by) and [`rotate_by()`](#stretch_body.base.Base.rotate_by) methods send relative commands similar to the way [`move_by()`](#stretch_body.lift.Lift.move_by) behaves for the single degree of freedom joints.
The mobile base also supports velocity control:
```python linenums='21'
# command the base to translate forward at 5cm / second
@ -254,7 +266,9 @@ b.enable_freewheel_mode()
b.push_command()
```
The [`set_translate_velocity()`](#stretch_body.base.Base.set_translate_velocity)/[`set_rotational_velocity()`](#stretch_body.base.Base.set_rotational_velocity) give velocity control over the translational/rotational components of the mobile base independently. The [`set_velocity()`](#stretch_body.base.Base.set_velocity) method gives control over both of these components simultaneously. To halt motion, you can command zero velocities or command the base into freewheel mode using [`enable_freewheel_mode()`](#stretch_body.base.Base.enable_freewheel_mode). The mobile base also supports waypoint trajectory following, but the waypoints are part of the SE2 group (a.k.a. each of the base's desired waypoints is defined as a (x, y) point and a theta orientation):
The [`set_translate_velocity()`](#stretch_body.base.Base.set_translate_velocity) and [`set_rotational_velocity()`](#stretch_body.base.Base.set_rotational_velocity) methods give velocity control over the translational and rotational components of the mobile base independently. The [`set_velocity()`](#stretch_body.base.Base.set_velocity) method gives control over both of these components simultaneously.
To halt motion, you can command zero velocities or command the base into freewheel mode using [`enable_freewheel_mode()`](#stretch_body.base.Base.enable_freewheel_mode). The mobile base also supports waypoint trajectory following, but the waypoints are part of the SE2 group, where a desired waypoint is defined as an (x, y) point and a theta orientation:
```python linenums='39'
# reset odometry calculation
@ -275,9 +289,11 @@ b.stop()
```
!!! warning
The [Base's](#stretch_body.base.Base) waypoint trajectory following has no notion of obstacles in the environment. It will blindly follow the commanded waypoints. For obstacle avoidance, perception and a path planner should be employed.
The [Base](#stretch_body.base.Base) waypoint trajectory following has no notion of obstacles in the environment. It will blindly follow the commanded waypoints. For obstacle avoidance, we recommend employing perception and a path planner.
The attribute `trajectory` is an instance of the [DiffDriveTrajectory](#stretch_body.trajectories.DiffDriveTrajectory) class. The call to [`follow_trajectory()`](#stretch_body.base.Base.follow_trajectory) begins hardware tracking of the spline.
[Base's](#stretch_body.base.Base) attribute `trajectory` is an instance of the [DiffDriveTrajectory](#stretch_body.trajectories.DiffDriveTrajectory) class. The call to [`follow_trajectory()`](#stretch_body.base.Base.follow_trajectory) begins hardware tracking of the spline. All of [Base's](#stretch_body.base.Base) subroutines are documented below.
All methods of the [Base](#stretch_body.base.Base) class are documented below.
::: stretch_body.base.Base
@ -286,7 +302,7 @@ b.stop()
![Stretch head blueprint](./images/tilt_detail_rs.png#only-light)
![Stretch head blueprint](./images/tilt_detail_rs.png#only-dark)
The interface to Stretch's head is the [Head](#stretch_body.head.Head) class. Stretch's head contains a Intel Realsense D435i depth camera, so the pan/tilt joints in the head allows Stretch to swivel and capture depth imagery of its surrounding. The head is typically initialized as:
The interface to Stretch's head is the [Head](#stretch_body.head.Head) class. The head contains an Intel Realsense D435i depth camera. The pan and tilt joints in the head allow Stretch to swivel and capture depth imagery of its surrounding. The head is typically initialized as:
```python linenums='1'
import stretch_body.head
@ -300,7 +316,7 @@ h.home()
# interact with the head here
```
[Head](#stretch_body.head.Head) is a subclass of [DynamixelXChain](#stretch_body.dynamixel_X_chain.DynamixelXChain), which in turn subclasses the [Device](#stretch_body.device.Device) class. Therefore, some of [Head's](#stretch_body.head.Head) methods, such as [`startup()`](#stretch_body.head.Head.startup) and [`home()`](#stretch_body.head.Head.home) methods are extended from the [Device](#stretch_body.device.Device) class, while other come from the [DynamixelXChain](#stretch_body.dynamixel_X_chain.DynamixelXChain) class. Reading the head's current state and sending commands to its revolute joints (head pan and tilt) happens using:
[Head](#stretch_body.head.Head) is a subclass of the [DynamixelXChain](#stretch_body.dynamixel_X_chain.DynamixelXChain) class, which in turn is a subclass of the [Device](#stretch_body.device.Device) class. Therefore, some of [Head's](#stretch_body.head.Head) methods, such as [`startup()`](#stretch_body.head.Head.startup) and [`home()`](#stretch_body.head.Head.home) are extended from the [Device](#stretch_body.device.Device) class, while others come from the [DynamixelXChain](#stretch_body.dynamixel_X_chain.DynamixelXChain) class. Reading the head's current state and sending commands to its revolute joints (head pan and tilt) can be achieved using:
```python linenums='10'
starting_position = h.status['head_pan']['pos']
@ -322,7 +338,15 @@ h.pose('ahead')
time.sleep(3)
```
[Head's](#stretch_body.head.Head) attribute `status` is a dictionary of dictionaries, where each subdictionary is the status of one of the head's joints. This state information is updated in the background in real time by default (disable by initializing as [`startup(threading=False)`](#stretch_body.head.Head.startup)). Use the [`pretty_print()`](#stretch_body.head.Head.pretty_print) method to print out this state info in a human interpretable format. Commanding the head's revolute joints is done through the [`move_to()`](#stretch_body.head.Head.move_to) and [`move_by()`](#stretch_body.head.Head.move_by) methods. Notice that unlike the previous joints, no push command call is required here. These joints are Dynamixel servos, which behave differently than the Hello Robot steppers. Their commands are not queued; they're executed as soon as they're received. [Head's](#stretch_body.head.Head) two joints, the 'head_pan' and 'head_tilt', are instances of the [DynamixelHelloXL430](#stretch_body.dynamixel_hello_XL430.DynamixelHelloXL430) class, and are retreiveable using the [`get_joint()`](#stretch_body.head.Head.get_joint) method. They have the [`wait_until_at_setpoint()`](#stretch_body.dynamixel_hello_XL430.DynamixelHelloXL430.wait_until_at_setpoint) method, which blocks program execution until the joint reaches the commanded goal. The [`pose()`](#stretch_body.head.Head.pose) method makes it easy to command the head to common head poses (e.g. looking 'ahead', at the end of arm 'tool', obstacles in front of the 'wheels', or 'up'). The head supports waypoint trajectories as well:
The attribute `status` is a dictionary of dictionaries, where each subdictionary is the status of one of the head's joints. This state information is updated in the background in real-time by default (disable by initializing as [`startup(threading=False)`](#stretch_body.head.Head.startup)). Use the [`pretty_print()`](#stretch_body.head.Head.pretty_print) method to print out this state information in a human-interpretable format.
Commanding the head's revolute joints is done through the [`move_to()`](#stretch_body.head.Head.move_to) and [`move_by()`](#stretch_body.head.Head.move_by) methods. Notice that, unlike the previous joints, no push command call is required here. These joints are Dynamixel servos, which behave differently than the Hello Robot steppers. Their commands are not queued and are executed as soon as they're received.
[Head's](#stretch_body.head.Head) two joints, the 'head_pan' and 'head_tilt' are instances of the [DynamixelHelloXL430](#stretch_body.dynamixel_hello_XL430.DynamixelHelloXL430) class and are retrievable using the [`get_joint()`](#stretch_body.head.Head.get_joint) method. They have the [`wait_until_at_setpoint()`](#stretch_body.dynamixel_hello_XL430.DynamixelHelloXL430.wait_until_at_setpoint) method, which blocks program execution until the joint reaches the commanded goal.
The [`pose()`](#stretch_body.head.Head.pose) method makes it easy to command the head to common head poses (e.g. looking 'ahead', at the end-of-arm 'tool', obstacles in front of the 'wheels', or 'up').
The head supports waypoint trajectories as well:
```python linenums='27'
# queue a trajectory consisting of three waypoints
@ -338,7 +362,9 @@ h.follow_trajectory()
import time; time.sleep(6)
```
The head pan/tilt [DynamixelHelloXL430](#stretch_body.dynamixel_hello_XL430.DynamixelHelloXL430) instances have an attribute `trajectory`, which is an instance of the [RevoluteTrajectory](#stretch_body.trajectories.RevoluteTrajectory) class. The call to [`follow_trajectory()`](#stretch_body.dynamixel_X_chain.DynamixelXChain.follow_trajectory) begins software tracking of the spline. Finally, setting soft motion limits for the head's pan/tilt range happens using:
The head pan and tilt [DynamixelHelloXL430](#stretch_body.dynamixel_hello_XL430.DynamixelHelloXL430) instances have an attribute `trajectory`, which is an instance of the [RevoluteTrajectory](#stretch_body.trajectories.RevoluteTrajectory) class. The call to [`follow_trajectory()`](#stretch_body.dynamixel_X_chain.DynamixelXChain.follow_trajectory) begins software tracking of the spline.
Finally, setting soft motion limits for the head's pan and tilt range can be achieved using:
```python linenums='38'
# clip the head_pan's range
@ -352,13 +378,15 @@ h.get_joint('head_tilt').set_soft_motion_limit_max(0.1)
h.stop()
```
The [`set_soft_motion_limit_min/max()`](#stretch_body.dynamixel_X_chain.DynamixelXChain.set_soft_motion_limit_min) methods perform clipping of the joint's range at the software level (cannot persist across reboots). All of [Head's](#stretch_body.head.Head) subroutines are documented below.
The [`set_soft_motion_limit_min/max()`](#stretch_body.dynamixel_X_chain.DynamixelXChain.set_soft_motion_limit_min) methods perform clipping of the joint's range at the software level (cannot persist across reboots).
All methods of the [Head](#stretch_body.head.Head) class are documented below.
::: stretch_body.head.Head
### Using the EndOfArm class
The interface to Stretch's end of arm is the [EndOfArm](#stretch_body.end_of_arm.EndOfArm) class. It is typically initialized as:
The interface to Stretch's end-of-arm is the [EndOfArm](#stretch_body.end_of_arm.EndOfArm) class. It is typically initialized as:
```python linenums='1'
import stretch_body.end_of_arm
@ -372,7 +400,7 @@ if not e.startup(threaded=True):
e.stop()
```
[EndOfArm's](#stretch_body.end_of_arm.EndOfArm) subroutines are documented below.
All methods of the [EndOfArm](#stretch_body.end_of_arm.EndOfArm) class are documented below.
::: stretch_body.end_of_arm.EndOfArm
@ -392,13 +420,13 @@ if not w.startup(threaded=True):
w.stop()
```
[Wacc's](#stretch_body.wacc.Wacc) subroutines are documented below.
All methods of the [Wacc](#stretch_body.wacc.Wacc) class are documented below.
::: stretch_body.wacc.Wacc
### Using the Pimu class
The interface to Stretch's power board is the [Pimu](#stretch_body.pimu.Pimu) (power + IMU) class. This board provides an 9 DOF IMUthat is accessible from the [Pimu](#stretch_body.pimu.Pimu) class. It is typically initialized as:
The interface to Stretch's power board is the [Pimu](#stretch_body.pimu.Pimu) (power + IMU) class. This board provides a 9-DOF IMU that is accessible from the [Pimu](#stretch_body.pimu.Pimu) class. It is typically initialized as:
```python linenums='1'
import stretch_body.pimu
@ -412,7 +440,7 @@ if not p.startup(threaded=True):
p.stop()
```
[Pimu's](#stretch_body.pimu.Pimu) subroutines are documented below.
All methods of the [Pimu](#stretch_body.pimu.Pimu) class are documented below.
::: stretch_body.pimu.Pimu

+ 18
- 17
stretch_body/tutorial_tool_change.md View File

@ -1,10 +1,10 @@
# Tutorial: Tool Change
Many users will want to work with tools other than the default Stretch Gripper that ships with the robot. In this tutorial you will learn how to configure the Stretch software interfaces to support other tools.
Many users will want to work with tools other than the default Stretch Gripper that ships with the robot. In this tutorial, you will learn how to configure the Stretch software interfaces to support other tools.
## Changing Tool Interfaces in Stretch Body
Stretch Body supports a plug-in based architecture for tools. A tool is an extension of the [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) class that supports additional degrees of freedom.
Stretch Body supports a plug-in-based architecture for tools. A tool is an extension of the [EndOfArm](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm.py) class that supports additional degrees of freedom.
### Standard Tools
@ -71,9 +71,9 @@ In [6]: r.end_of_arm.stow()
In [7]: r.stop()
```
## Loading Tool Interfaces from the Stretch Tool Share
## Loading Tool Interfaces from Stretch Tool Share
The [Stretch Tool Share](https://github.com/hello-robot/stretch_tool_share/) is an open Git repository for non-standard Stretch tools. It hosts the CAD, URDF, and Python files needed to integrate these tools onto your robot.
The [Stretch Tool Share](https://github.com/hello-robot/stretch_tool_share/) is an open Git repository for non-standard Stretch tools. It hosts the CAD, URDF, and Python files needed to integrate these tools with your robot.
To use Stretch Tool Share tools, first update your installation:
@ -81,7 +81,7 @@ To use Stretch Tool Share tools, first update your installation:
$ pip install -U hello-robot-stretch-tool-share
```
As an example, we see on the Tool Share that there is a tool, the [ToolDryEraseToolHolderV1](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/dry_erase_holder_v1/tool.py) which [extends the EndOfArm](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/usbcam_wrist_v1/tool.py) class. In order to load this tool interface , modify your `stretch_user_params.yaml` to load the tool as before. We will also need to tell it where to find the tool's [parameter file](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/dry_erase_holder_v1/params.py):
As an example, we see on the Tool Share that there is a tool, the [ToolDryEraseToolHolderV1](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/dry_erase_holder_v1/tool.py) which [extends the EndOfArm](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/usbcam_wrist_v1/tool.py) class. To load this tool interface, modify your `stretch_user_params.yaml` to load the tool as before. We will also need to tell it where to find the tool's [parameter file](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/dry_erase_holder_v1/params.py):
```yaml
robot:
@ -112,9 +112,9 @@ In [6]: r.end_of_arm.stow()
# Changing Tool Interfaces in Stretch ROS
Next we'll show how to change the ROS interface for a tool. Here we will continue with the [ToolDryEraseHolderV1](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/dry_erase_holder_v1/tool.py#L3) example. First, configure Stretch Body to use the tool as in the previous exercise.
Next, we'll see how to change the ROS interface for a tool. Here we will continue with the [ToolDryEraseHolderV1](https://github.com/hello-robot/stretch_tool_share/blob/master/python/stretch_tool_share/dry_erase_holder_v1/tool.py#L3) example. First, configure Stretch Body to use the tool as in the previous exercise.
Next, ensure your ROS is up to date:
Next, ensure ROS is up to date:
```console
$ cd ~/catkin_ws/src/stretch_ros/
@ -128,7 +128,7 @@ $ cd ~/repos
$ git clone https://github.com/hello-robot/stretch_tool_share
```
Copy in the tool's URDF data into the Stretch ROS repository:
Copy the tool's URDF data into the Stretch ROS repository:
```console
$ cd ~/repos/stretch_tool_share/tool_share/dry_erase_holder_v1
@ -136,7 +136,7 @@ $ cp stretch_description/urdf/*.xacro ~/catkin_ws/src/stretch_ros/stretch_descri
$ cp stretch_description/meshes/*.STL ~/catkin_ws/src/stretch_ros/stretch_description/meshes/
```
Now we will update the tool Xacro for Stretch. Open the file `~/catkin_ws/src/stretch_ros/stretch_description/urdf/stretch_description.xacro` in an editor. Comment out the current tool Xacro and include the Xacro for the dry erase holder.
Now we will update the tool Xacro for Stretch. Open the file `~/catkin_ws/src/stretch_ros/stretch_description/urdf/stretch_description.xacro` in an editor. Comment out the current tool Xacro and include the Xacro for the dry-erase holder.
```xml
<?xml version="1.0"?>
@ -153,7 +153,7 @@ Now we will update the tool Xacro for Stretch. Open the file `~/catkin_ws/src/st
</robot>
```
Finally, we'll update our already calibrated URDF to use this new tool:
Finally, we'll update the calibrated URDF to use this new tool:
```console
$ cd ~/catkin_ws/src/stretch_ros/stretch_description/urdf
@ -161,7 +161,7 @@ $ cp stretch.urdf stretch.urdf.bak
$ rosrun stretch_calibration update_urdf_after_xacro_change.sh
```
Ctrl-C when the `rosrun` command terminates and you're ready to visualize the tool in RViz:
Press Ctrl-C when the `rosrun` command terminates and you're ready to visualize the tool in RViz:
```console
$ roslaunch stretch_calibration simple_test_head_calibration.launch
@ -173,11 +173,11 @@ $ roslaunch stretch_calibration simple_test_head_calibration.launch
## Understanding How the Tool Plug-In Works
For users looking to create their own custom tools it can be useful to understand how the tool plug-in architecture works. Here we will walk through the basics of the system for both Stretch Body and Stretch ROS
For users looking to create their custom tools, it can be useful to understand how the tool plug-in architecture works. Here we will walk through the basics of the system for both Stretch Body and Stretch ROS
### Stretch Body
The [Robot](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot.py#L97) class expects an instance of EndOfArm tool to be present. The EndOfArm tool is an extension of the [DynamixelXChain](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_X_chain.py#L16) class, which manages a chain of Dynamixel servos.
The [Robot](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot.py#L97) class expects an instance of the EndOfArm tool to be present. The EndOfArm tool is an extension of the [DynamixelXChain](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_X_chain.py#L16) class, which manages a chain of Dynamixel servos.
A tool is defined via its parameters (either in user YAML or Python). For example, the ToolStretchGripper is defined in [robot_params.py](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/robot_params.py). These parameters tell the plug-in which [DynamixelHelloXL430](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_hello_XL430.py) instances to load and manage. Here we see:
@ -203,9 +203,9 @@ A tool is defined via its parameters (either in user YAML or Python). For exampl
},
```
This dictionary defines a tool of class ToolStretchGripper with two [DynamixelHelloXL430](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_hello_XL430.py) devices on its bus (StretchGripper and WristYaw).
This dictionary defines a tool of the class ToolStretchGripper with two [DynamixelHelloXL430](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/dynamixel_hello_XL430.py) devices on its bus (StretchGripper and WristYaw).
We see that the [ToolStretchGripper](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm_tools.py#L7) class extends the EndOfArm class and provides its own stowing behavior:
We see that the [ToolStretchGripper](https://github.com/hello-robot/stretch_body/blob/master/body/stretch_body/end_of_arm_tools.py#L7) class extends the EndOfArm class and provides its stowing behavior:
```python
class ToolStretchGripper(EndOfArm):
@ -220,7 +220,7 @@ class ToolStretchGripper(EndOfArm):
self.move_to('stretch_gripper', self.params['stow']['stretch_gripper'])
```
For tools that are not a part of Stretch Body, such as from the Tool Share, you must include the tool parameters as well in your `stretch_user_params.yaml`. A robot that must support many tools may have user YAML that looks like:
For tools that are not a part of Stretch Body, such as from the Tool Share, you must include the tool parameters as well in your `stretch_user_params.yaml`. A robot that supports many tools may have a user YAML that looks like:
```yaml
params:
@ -235,7 +235,8 @@ robot:
#tool: tool_stretch_dex_wrist_beta
```
For a more complex implementation of a tool we recommend reviewing the Stretch Dex Wrist implementation on the Stretch Tool Share.
!!! tip
For a more complex implementation of a tool, we recommend reviewing the Stretch Dex Wrist implementation on the Stretch Tool Share.
### Stretch ROS

+ 24
- 0
stretch_tool_share/README.md View File

@ -0,0 +1,24 @@
# Overview
We designed Stretch's hardware to be easily extended. You can make your own tool and attach it to the wrist to creatively expand what Stretch can do. Your tool can also use Dynamixel X-series servos from Robotis via the provided TTL bus.
In this tutorial, we provide examples of some of the tools that we've created. We've released them with a permissive Apache 2.0 license, so you're free to use them as you wish. We hope they'll inspire you to create your own.
We also include URDF and mesh files for many of the tools in their stretch_description folder. See the Stretch ROS documentation for guidance on integrating these tools into your robot model.
We'd love it if you shared your creations with the community. We recommend you create a GitHub repository for your own tools and then post an announcement to the forum to let people know about it.
| Tool | Description |
| :----------------------------------------------------------: | :----------------------------------------------------------: |
| Puller | Attachment to pull drawers, handles or push buttons |
| Dry Erase Holder | Compliant attachment for drawing on white-boards |
| DexWrist | A 3-DoF upgrade for the standard gripper |
| Updating URDF | Updating the URDF after changing a tool |
## Licenses
The contents in this tutorial that represent parts of the Stretch robot, such as its head, arm, wrist, and default gripper, are covered by the [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) license. Please note that the Stretch robot and its default gripper are also covered by pending patents. Please see the robot license for details.
Other contents in this tutorial created by Hello Robot Inc. that specifically pertain to the tools that attach to Stretch as accessories are covered by the [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) license. Please see the tool license for details.
The contents of this tutorial are intended for use with the Stretch mobile manipulator, which is a robot produced and sold by Hello Robot Inc. For further information, including inquiries about dual licensing, please contact Hello Robot Inc.

+ 87
- 0
stretch_tool_share/dex_to_standard.md View File

@ -0,0 +1,87 @@
# Dex to Standard Wrist
This tutorial will guide you through the steps of replacing a gripper with a Dex Wrist (3-DoF) for one with a Standard Wrist (1-DoF).
## Parts and Tools Required
Please note that this procedure does not require any additional parts or tools apart from the ones that were shipped with the robot:
- 8 [M2x6mm Torx FHCS bolts](https://www.mcmaster.com/90236A104/)
- 4 [M2.5x4mm Torx FHCS bolts](https://www.mcmaster.com/92703A448/)
- 2 [M2.5x8mm SHCS bolts](https://www.mcmaster.com/91290A102/)
- T6 Torx wrench
- T8 Torx wrench
- 2mm Hex key
## Removing Dex Wrist Gripper
Here we describe removing the Dex Wrist gripper. Please ensure that the robot is turned off before proceeding.
First, inspect the parts and ensure that you have everything you need for the procedure.
![Dex Wrist](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/dex_wrist_cable_detail.png)
Now, remove the cable clip by unscrewing the M2.5x8mm bolts and then unplug the Dynamixel cable out of the wrist pitch servo (pink).
![Remove the cable](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/dex_wrist_cable_route_rs.png)
Next, rotate the wrist yaw joint so that the wrist pitch servo body is accessible. Detach the pitch servo from the mounting bracket by unscrewing the four M2.5x4mm screws (C) with the T8 Torx wrench.
![Remove screws](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/dex_wrist_pitch_bracket_attach_rs.png)
Slide the wrist module out horizontally so that the bearing unmates from its post.
![Remove mating](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/dex_wrist_roll_install2_rs.png)
Then, lower the wrist module vertically away from the mounting bracket.
![Remove from mounting bracket](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/dex_wrist_roll_install_rs.png)
Lastly, detach the wrist mount bracket (A) from the bottom of the tool plate by removing the M2x6mm bolts (B) using a T6 Torx wrench.
![Remove tool plate](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/dex_wrist_bracket_install_rs.png)
## Attaching Standard Wrist Gripper
Here we describe attaching the Standard Wrist gripper.
First, note where the forward direction is on the wrist yaw tool plate. This is indicated by the additional alignment hole that is just outside the bolt pattern shown pointing down in the image.
![Alignment hole](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/dex_wrist_C_rs.png)
Then, route the Dynamixel cable through the center of the standard gripper mounting bracket and install the bracket with the eight screws and T6 Torx wrench. Make sure the forward marking on the bracket matches the forward marking on the wrist yaw.
![image alt text](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/re2/gripper_mount_a_rs.png)
Now, affix the four screws, with the shorter two going to the servo side, to hold the gripper to the bracket. Lastly, route the Dynamixel cable through the back of the gripper and plug it securely into the servo.
![image alt text](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/re2/gripper_mount_b_rs.png)
## Software Instructions
Once the hardware has been replaced, it's time to make the software changes for Stretch to recognize the Standart Wrist gripper. Turn on the robot and follow the instructions below.
To revert the changes in stretch_configuration_params.yaml, download the [dex_to_standard_configure_params.py script](https://github.com/hello-robot/stretch_tutorials/blob/master/stretch_tool_share/dex_to_standard_configure_params.py) and execute it in a terminal as below:
```bash
python3 dex_to_standard_configure_params.py
```
Next, to ensure the correct gripper is recognized by ROS, we need to update the URDF. For this, first open the stretch_description.xacro file like below.
```bash
cd ~/catkin_ws/src/stretch_ros/stretch_description/urdf
gedit stretch_description.xacro
```
Then, replace the contents of the file with the default [stretch_description.xacro](https://github.com/hello-robot/stretch_ros/blob/master/stretch_description/urdf/stretch_description.xacro).
Lastly, to generate the updated URDF, execute the following commands in a terminal.
```bash
rosrun stretch_calibration update_urdf_after_xacro_change.sh
cd ~/catkin_ws/src/stretch_ros/stretch_description/urdf
./export_urdf.sh
```
You can ensure that the gripper is functional by homing the Dynamixel servos with the following commands:
```bash
stretch_gripper_home.py
```
```bash
stretch_wrist_yaw_home.py
```
If you encounter any issues, please contact support.

+ 32
- 0
stretch_tool_share/dex_to_standard_configure_params.py View File

@ -0,0 +1,32 @@
from __future__ import print_function
import stretch_body.hello_utils
import stretch_body.robot_params
import argparse
from os.path import exists
import sys
model_name=stretch_body.robot_params.RobotParams()._robot_params['robot']['model_name']
if model_name=='RE2V0':
dex_wrist_yaml = {
'robot': {'use_collision_manager': 1, 'tool': 'tool_stretch_gripper'},
'params': [],
'stretch_gripper': {'range_t': [0, 8022], 'zero_t': 5212},
'lift': {'i_feedforward': 1.2},
'hello-motor-lift': {'gains': {'i_safety_feedforward': 1.2}}}
if model_name == 'RE1V0':
dex_wrist_yaml = {
'robot': {'use_collision_manager': 1, 'tool': 'tool_stretch_gripper'},
'params': [],
'stretch_gripper': {'range_t': [0, 8022], 'zero_t': 5212},
'lift': {'i_feedforward': 0.54},
'hello-motor-lift': {'gains': {'i_safety_feedforward': 0.4}}}
if not exists(stretch_body.hello_utils.get_fleet_directory()+'stretch_configuration_params.yaml'):
print('Please run tool RE1_migrate_params.py before continuing. For more details, see https://forum.hello-robot.com/t/425')
sys.exit(1)
configuration_yaml=stretch_body.hello_utils.read_fleet_yaml('stretch_configuration_params.yaml')
stretch_body.hello_utils.overwrite_dict(overwritee_dict=configuration_yaml, overwriter_dict=dex_wrist_yaml)
stretch_body.hello_utils.write_fleet_yaml('stretch_configuration_params.yaml', configuration_yaml,
header=stretch_body.robot_params.RobotParams().get_configuration_params_header())

+ 15
- 0
stretch_tool_share/dexwrist.md View File

@ -0,0 +1,15 @@
## Stretch Dex Wrist
**Created by**: Hello Robot Inc
The [Stretch Dex Wrist](https://hello-robot.com/stretch-dex-wrist) is commercially available from Hello Robot. The following hardware guides are available:
* [Stretch RE1 DexWrist Hardware Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/docs/dex_wrist_guide_re1/)
* [Stretch 2 DexWrist Hardware Guide](https://docs.hello-robot.com/0.2/stretch-hardware-guides/docs/dex_wrist_guide_re2/)
Additional resources available here include:
* [Gazebo Support](https://github.com/hello-robot/stretch_tool_share/blob/master/tool_share/stretch_dex_wrist/gazebo_support/README.md)
* [URDF](https://github.com/hello-robot/stretch_tool_share/tree/master/tool_share/stretch_dex_wrist/stretch_description)

+ 34
- 0
stretch_tool_share/dry_erase_holder.md View File

@ -0,0 +1,34 @@
## Dry Erase Holder
**Created by**: Hello Robot Inc
This tool allows Stretch to hold a dry erase marker. It is spring loaded, allowing for compliant interaction between the marker and a white board.
The tool can be integrated into your robot URDF by integrating its [stretch_description](https://github.com/hello-robot/stretch_tool_share/tree/master/tool_share/dry_erase_holder_V1/stretch_description) as described in the [Stretch ROS documentation](https://github.com/hello-robot/stretch_ros/tree/master/stretch_description).
<img src="https://raw.githubusercontent.com/hello-robot/stretch_tool_share/master/tool_share/dry_erase_holder_V1/images/dry_erase_A.PNG" alt="image" height=400 />
<img src="https://raw.githubusercontent.com/hello-robot/stretch_tool_share/master/tool_share/dry_erase_holder_V1/images/marker_holder.png" alt="image" height=400 />
## Parts List
| Item | Qty | Vendor |
| ------------- |:-------------:| -----: |
| [Expo Dry Erase](https://www.amazon.com/gp/product/B00006IFIL/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1) | 1 | Amazon |
| [M5x50mm Hex Head Bolt](https://www.mcmaster.com/91287A333) | 1 | McMaster-Carr |
| [M5 Nut](https://www.mcmaster.com/90591A260) | 2 | McMaster-Carr|
| [wrist_end_cap_5mm](https://github.com/hello-robot/stretch_tool_share/blob/master/tool_share/dry_erase_holder_V1/CAD/wrist_end_cap_5mm.STL) | 1 | PLA 3D Printer |
| [dry_erase_bushing_block](https://github.com/hello-robot/stretch_tool_share/blob/master/tool_share/dry_erase_holder_V1/CAD/dry_erase_bushing_block.STL) | 1 | PLA 3D Printer |
| [Size 30 Rubber Band](https://www.mcmaster.com/12205t76) | 2 | McMaster-Carr |
| [3/4" Shaft Collar](https://www.mcmaster.com/60475k74) | 1 | McMaster-Carr |
## Assembly instructions
[View 3D assembly](https://github.com/hello-robot/stretch_tool_share/blob/master/tool_share/dry_erase_holder_V1/CAD/ASSEM_Dry_Erase_Holder_V1.STL)
<img src="https://raw.githubusercontent.com/hello-robot/stretch_tool_share/master/tool_share/dry_erase_holder_V1/images/dry_erase_B.PNG" alt="image" height=700 />
1. Install the bolt into the dry_erase_bushing block and secure from below with an M5 nut.
2. Attach the dry erase bushing block to the tool plate, securing from below with the wrist_end_cap_5mm and an M5 nut. Orient the block so the marker points forward.
3. Attach the shaft collar to your dry erase marker, approximately 8mm from the back of the marker.
4. Slide the marker into the bushing block. Loop a rubber band around the back of the marker and over to one of the pegs on the side of the bushing block. Repeat with the other peg.
5. The marker should now easily spring back when pushed against. You're ready to write!

+ 26
- 0
stretch_tool_share/gripper_puller.md View File

@ -0,0 +1,26 @@
## Puller
**Created by**: Hello Robot Inc
This is a a simple puller attachment for the Stretch Compliant Gripper. We've used it to pull open many common drawers, cabinet doors, and even a mini-fridge door. You can also use it to push things closed. You can think of it as a circular hook used to pull things or a finger used to push things.
It attaches to the 6-32 stud on the side of the gripper. By turning the gripper sideways during manipulation, the hook can drop over the drawer handle, allowing the arm to retract and pull the door open.
<img src="https://raw.githubusercontent.com/hello-robot/stretch_tool_share/master/tool_share/puller_v1/images/drawer_pull_A.PNG" alt="image" height=300 />
<img src="https://raw.githubusercontent.com/hello-robot/stretch_tool_share/master/tool_share/puller_v1/images/drawer_pull_B.PNG" alt="image" height=400 />
## Parts List
| Item | Qty | Vendor |
| ------------- |:-------------:| -----: |
| [6-32 x 0.5" BHCS](https://www.mcmaster.com/91255A148) | 1 | McMaster-Carr|
| [6-32 x 1" aluminum threaded standoff](https://www.mcmaster.com/93330a449) | 1 | McMaster-Carr|
| [Puller_V1.STL](https://github.com/hello-robot/stretch_tool_share/blob/master/tool_share/puller_v1/CAD/Puller_V1.STL) | 1 | PLA 3D printer|
## Assembly instructions
[View 3D assembly](https://github.com/hello-robot/stretch_tool_share/blob/master/tool_share/puller_v1/CAD/ASSEM_Puller_V1.STL)
<img src="https://raw.githubusercontent.com/hello-robot/stretch_tool_share/master/tool_share/puller_v1/images/drawer_pull_C.PNG" alt="image" height=400 />
1. Screw the standoff on to the gripper's threaded post. Secure tightly and add a drop of light duty Loctite if desired.
2. Attach the plastic pull to the standoff using the BHCS.

+ 40
- 0
stretch_tool_share/gripper_removal.md View File

@ -0,0 +1,40 @@
# Gripper
The Stretch Compliant Gripper utilizes a Dynamixel XL430-W250-T servo to drive the spring grasper mechanism. The kinematics of the grasper mechanism are complex and non-linear relative to the motor position. As shown, it includes mounting features on one side to allow for attachment of simple rigid tools such as [hooks and pullers](https://github.com/hello-robot/stretch_tool_share/tree/master/tool_share/puller_v1).
![image alt text](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/re2/gripper.png)
<table>
<tr>
<td></td>
<td>Item</td>
<td>Notes</td>
</tr>
<tr>
<td>A</td>
<td>Stud attachment</td>
<td>Threaded 6-32</td>
</tr>
<tr>
<td>B</td>
<td>Thread attahcment</td>
<td>Threaded M4</td>
</tr>
</table>
The attachment features are spaced at 9mm.
The weight of the Stretch Compliant Gripper is 240g.
## Gripper Removal
Here we describe removing the Stretch Compliant gripper. Installation is simply these steps in reverse.
1. Unplug the Dynamixel cable from the back of the gripper.
2. Remove the 4 screws holding the gripper to the bracket.
3. Remove the gripper from the mounting bracket
4. Unscrew the 8 screws holding the mounting bracket to the bottom of the tool plate.
![image alt text](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/re2/gripper_mount_b_rs.png)
![image alt text](https://raw.githubusercontent.com/hello-robot/stretch_hardware_guides/master/docs/images/re2/gripper_mount_a_rs.png)

+ 31
- 0
stretch_tool_share/updating_urdf.md View File

@ -0,0 +1,31 @@
## Changing the Tool
If you wish to remove the default gripper and add a different tool, you will typically edit /stretch_description/urdf/stretch_description.xacro. Specifically, you will replace the following line in order to include the xacro for the new tool and then follow directions within stretch_ros/stretch_calibration to generate a new calibrated urdf file (stretch.urdf) that includes the new tool.
`<xacro:include filename="stretch_gripper.xacro" />`
As an example we provide the xacro `stretch_dry_erase_marker.xacro` and its dependent mesh files with stretch_ros.
Some of the tools found in the [Stretch Body Tool Share](https://github.com/hello-robot/stretch_tool_share/) include URDF data. To integrate these tools into the URDF for your Stretch
```bash
>>$ cd ~/repos
>>$ git clone https://github.com/hello-robot/stretch_tool_share
>>$ cd stretch_tool_share/<tool name>
>>$ cp stretch_description/urdf/* ~/catkin_ws/src/stretch_ros/stretch_description/urdf/
>>$ cp stretch_description/meshes/* ~/catkin_ws/src/stretch_ros/stretch_description/meshes/
```
Next add the xacro for the particular tool to `/stretch_description/urdf/stretch_description.xacro`. Then you can generate and preview the uncalibrated URDF:
```bash
>>$ cd ~/catkin_ws/src/stretch_ros/stretch_description/urdf
>>$ cp stretch.urdf stretch.urdf.bak
>>$ rosrun stretch_calibration update_urdf_after_xacro_change.sh
```
Now visualize the new tool
```bash
>>$ roslaunch stretch_calibration simple_test_head_calibration.launch
```

Loading…
Cancel
Save