-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Nav2 Simple (Python3) Commander Library (#2411)
* adding nav2_python_commander package * adding readme * launch files for the python commander examples * renaming to nav2_simple_commander * resolve review comments * fixing rosdep key * fixing up linters
- Loading branch information
1 parent
40f4c38
commit fa1d091
Showing
24 changed files
with
2,536 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
# Nav2 Simple (Python3) Commander | ||
|
||
## Overview | ||
|
||
The goal of this package is to provide a "navigation as a library" capability to Python3 users. We provide an API that handles all the ROS2-y and Action Server-y things for you such that you can focus on building an application leveraging the capabilities of Nav2. We also provide you with demos and examples of API usage to build common basic capabilities in autonomous mobile robotics. | ||
|
||
This was built by [Steve Macenski](https://www.linkedin.com/in/steve-macenski-41a985101/) at [Samsung Research](https://www.sra.samsung.com/), with initial prototypes being prepared for the Keynote at the [2021 ROS Developers Day](https://www.theconstructsim.com/ros-developers-day-2021/) conference (code can be found [here](https://github.com/SteveMacenski/nav2_rosdevday_2021)). | ||
|
||
![](media/readme.gif) | ||
|
||
## API | ||
|
||
The methods provided by the basic navigator are shown below, with inputs and expected returns. If a server fails, it may throw an exception or return a `None` object, so please be sure to properly wrap your navigation calls in try/catch and check results for `None` type. | ||
|
||
| Robot Navigator Method | Description | | ||
| --------------------------------- | -------------------------------------------------------------------------- | | ||
| setInitialPose(initial_pose) | Sets the initial pose (`PoseStamped`) of the robot to localization. | | ||
| goThroughPoses(poses) | Requests the robot to drive through a set of poses (list of `PoseStamped`).| | ||
| goToPose(pose) | Requests the robot to drive to a pose (`PoseStamped`). | | ||
| followWaypoints(poses) | Requests the robot to follow a set of waypoints (list of `PoseStamped`). This will execute the specific `TaskExecutor` at each pose. | | ||
| cancelNav() | Cancel an ongoing `goThroughPoses` `goToPose` or `followWaypoints` request.| | ||
| isNavComplete() | Checks if navigation is complete yet, times out at `100ms`. Returns `True` if completed and `False` if still going. | | ||
| getFeedback() | Gets feedback from navigation task, returns action server feedback object. | | ||
| getResult() | Gets final result of navigation task, to be called after `isNavComplete` returns `True`. Returns action server result object. | | ||
| getPath(start, goal) | Gets a path from a starting to a goal `PoseStamped`, `nav_msgs/Path`. | | ||
| getPathThroughPoses(start, goals) | Gets a path through a starting to a set of goals, a list of `PoseStamped`, `nav_msgs/Path`. | | ||
| changeMap(map_filepath) | Requests a change from the current map to `map_filepath`'s yaml. | | ||
| clearAllCostmaps() | Clears both the global and local costmaps. | | ||
| clearLocalCostmap() | Clears the local costmap. | | ||
| clearGlobalCostmap() | Clears the global costmap. | | ||
| getGlobalCostmap() | Returns the global costmap, `nav2_msgs/Costmap` | | ||
| getLocalCostmap() | Returns the local costmap, `nav2_msgs/Costmap` | | ||
| waitUntilNav2Active() | Blocks until Nav2 is completely online and lifecycle nodes are in the active state. To be used in conjunction with autostart or external lifecycle bringup. | | ||
| lifecycleStartup() | Sends a request to all lifecycle management servers to bring them into the active state, to be used if autostart is `false` and you want this program to control Nav2's lifecycle. | | ||
| lifecycleShutdown() | Sends a request to all lifecycle management servers to shut them down. | | ||
|
||
A general template for building applications is as follows: | ||
|
||
``` python3 | ||
|
||
from nav2_simple_commander.robot_navigator import BasicNavigator | ||
import rclpy | ||
|
||
rclpy.init() | ||
|
||
nav = BasicNavigator() | ||
... | ||
nav.setInitialPose(init_pose) | ||
nav.waitUntilNav2Active() # if autostarted, else use `lifecycleStartup()` | ||
... | ||
nav.goToPose(goal_pose) | ||
while not nav.isNavComplete(): | ||
feedback = nav.getFeedback() | ||
if feedback.navigation_duration > 600: | ||
nav.cancelNav() | ||
... | ||
result = nav.getResult() | ||
if result == NavigationResult.SUCCEEDED: | ||
print('Goal succeeded!') | ||
elif result == NavigationResult.CANCELED: | ||
print('Goal was canceled!') | ||
elif result == NavigationResult.FAILED: | ||
print('Goal failed!') | ||
``` | ||
|
||
## Usage of Demos and Examples | ||
|
||
Make sure to install the `aws_robomaker_small_warehouse_world` package or build it in your local workspace alongside Nav2. It can be found [here](https://github.com/aws-robotics/aws-robomaker-small-warehouse-world). The demonstrations, examples, and launch files assume you're working with this gazebo world (such that the hard-programmed shelf locations and routes highlighting the API are meaningful). | ||
|
||
Make sure you have set the model directory of turtlebot3 simulation and aws warehouse world to the `GAZEBO_MODEL_PATH`. There are 2 main ways to run the demos of the `nav2_simple_commander` API. | ||
|
||
### Automatically | ||
|
||
The main benefit of this is automatically showing the above demonstrations in a single command for the default robot model and world. This will make use of Nav2's default robot and parameters set out in the main simulation launch file in `nav2_bringup`. | ||
|
||
``` bash | ||
# Launch the launch file for the demo / example | ||
ros2 launch nav2_simple_commander demo_security_launch.py | ||
``` | ||
|
||
This will bring up the robot in the AWS Warehouse in a reasonable position, launch the autonomy script, and complete some task to demonstrate the `nav2_simple_commander` API. | ||
|
||
### Manually | ||
|
||
The main benefit of this is to be able to launch alternative robot models or different navigation configurations than the default for a specific technology demonstation. As long as Nav2 and the simulation (or physical robot) is running, the simple python commander examples / demos don't care what the robot is or how it got there. Since the examples / demos do contain hard-programmed item locations or routes, you should still utilize the AWS Warehouse. Obviously these are easy to update if you wish to adapt these examples / demos to another environment. | ||
|
||
``` bash | ||
# Terminal 1: launch your robot navigation and simulation (or physical robot). For example | ||
ros2 launch nav2_bringup tb3_simulation_launch.py world:=/path/to/aws_robomaker_small_warehouse_world/.world map:=/path/to/aws_robomaker_small_warehouse_world/.yaml | ||
|
||
# Terminal 2: launch your autonomy / application demo or example. For example | ||
ros2 run nav2_simple_commander demo_security | ||
``` | ||
|
||
Then you should see the autonomy application running! | ||
|
||
## Examples | ||
|
||
The `nav2_simple_commander` has a few examples to highlight the API functions available to you as a user: | ||
|
||
- `example_nav_to_pose.py` - Demonstrates the navigate to pose capabilities of the navigator, as well as a number of auxiliary methods. | ||
- `example_nav_through_poses.py` - Demonstrates the navigate through poses capabilities of the navigator, as well as a number of auxiliary methods. | ||
- `example_waypoint_follower.py` - Demonstrates the waypoint following capabilities of the navigator, as well as a number of auxiliary methods required. | ||
|
||
## Demos | ||
|
||
The `nav2_simple_commander` has a few demonstrations to highlight a couple of simple autonomy applications you can build using the `nav2_simple_commander` API: | ||
|
||
- `demo_security.py` - A simple security robot application, showing how to have a robot follow a security route using Navigate Through Poses to do a patrol route, indefinitely. | ||
- `demo_picking.py` - A simple item picking application, showing how to have a robot drive to a specific shelf in a warehouse to either pick an item or have a person place an item into a basket and deliver it to a destination for shipping using Navigate To Pose. | ||
- `demo_inspection.py` - A simple shelf inspection application, showing how to use the Waypoint Follower and task executors to take pictures, RFID scans, etc of shelves to analyze the current shelf statuses and locate items in the warehouse. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Copyright (c) 2021 Samsung Research America | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import os | ||
|
||
from ament_index_python.packages import get_package_share_directory | ||
|
||
from launch import LaunchDescription | ||
from launch.actions import ExecuteProcess, IncludeLaunchDescription | ||
from launch.launch_description_sources import PythonLaunchDescriptionSource | ||
from launch_ros.actions import Node | ||
|
||
|
||
def generate_launch_description(): | ||
warehouse_dir = get_package_share_directory('aws_robomaker_small_warehouse_world') | ||
nav2_bringup_dir = get_package_share_directory('nav2_bringup') | ||
python_commander_dir = get_package_share_directory('nav2_simple_commander') | ||
|
||
map_yaml_file = os.path.join(warehouse_dir, 'maps', '005', 'map.yaml') | ||
world = os.path.join(python_commander_dir, 'warehouse.world') | ||
|
||
# start the simulation | ||
start_gazebo_server_cmd = ExecuteProcess( | ||
cmd=['gzserver', '-s', 'libgazebo_ros_factory.so', world], | ||
cwd=[warehouse_dir], output='screen') | ||
|
||
start_gazebo_client_cmd = ExecuteProcess( | ||
cmd=['gzclient'], | ||
cwd=[warehouse_dir], output='screen') | ||
|
||
urdf = os.path.join(nav2_bringup_dir, 'urdf', 'turtlebot3_waffle.urdf') | ||
start_robot_state_publisher_cmd = Node( | ||
package='robot_state_publisher', | ||
executable='robot_state_publisher', | ||
name='robot_state_publisher', | ||
output='screen', | ||
arguments=[urdf]) | ||
|
||
# start the visualization | ||
rviz_cmd = IncludeLaunchDescription( | ||
PythonLaunchDescriptionSource( | ||
os.path.join(nav2_bringup_dir, 'launch', 'rviz_launch.py')), | ||
launch_arguments={'namespace': '', | ||
'use_namespace': 'False'}.items()) | ||
|
||
# start navigation | ||
bringup_cmd = IncludeLaunchDescription( | ||
PythonLaunchDescriptionSource( | ||
os.path.join(nav2_bringup_dir, 'launch', 'bringup_launch.py')), | ||
launch_arguments={'map': map_yaml_file}.items()) | ||
|
||
# start the demo autonomy task | ||
demo_cmd = Node( | ||
package='nav2_simple_commander', | ||
executable='demo_inspection', | ||
emulate_tty=True, | ||
output='screen') | ||
|
||
ld = LaunchDescription() | ||
ld.add_action(start_gazebo_server_cmd) | ||
ld.add_action(start_gazebo_client_cmd) | ||
ld.add_action(start_robot_state_publisher_cmd) | ||
ld.add_action(rviz_cmd) | ||
ld.add_action(bringup_cmd) | ||
ld.add_action(demo_cmd) | ||
return ld |
77 changes: 77 additions & 0 deletions
77
nav2_simple_commander/launch/nav_through_poses_example_launch.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Copyright (c) 2021 Samsung Research America | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import os | ||
|
||
from ament_index_python.packages import get_package_share_directory | ||
|
||
from launch import LaunchDescription | ||
from launch.actions import ExecuteProcess, IncludeLaunchDescription | ||
from launch.launch_description_sources import PythonLaunchDescriptionSource | ||
from launch_ros.actions import Node | ||
|
||
|
||
def generate_launch_description(): | ||
warehouse_dir = get_package_share_directory('aws_robomaker_small_warehouse_world') | ||
nav2_bringup_dir = get_package_share_directory('nav2_bringup') | ||
python_commander_dir = get_package_share_directory('nav2_simple_commander') | ||
|
||
map_yaml_file = os.path.join(warehouse_dir, 'maps', '005', 'map.yaml') | ||
world = os.path.join(python_commander_dir, 'warehouse.world') | ||
|
||
# start the simulation | ||
start_gazebo_server_cmd = ExecuteProcess( | ||
cmd=['gzserver', '-s', 'libgazebo_ros_factory.so', world], | ||
cwd=[warehouse_dir], output='screen') | ||
|
||
start_gazebo_client_cmd = ExecuteProcess( | ||
cmd=['gzclient'], | ||
cwd=[warehouse_dir], output='screen') | ||
|
||
urdf = os.path.join(nav2_bringup_dir, 'urdf', 'turtlebot3_waffle.urdf') | ||
start_robot_state_publisher_cmd = Node( | ||
package='robot_state_publisher', | ||
executable='robot_state_publisher', | ||
name='robot_state_publisher', | ||
output='screen', | ||
arguments=[urdf]) | ||
|
||
# start the visualization | ||
rviz_cmd = IncludeLaunchDescription( | ||
PythonLaunchDescriptionSource( | ||
os.path.join(nav2_bringup_dir, 'launch', 'rviz_launch.py')), | ||
launch_arguments={'namespace': '', | ||
'use_namespace': 'False'}.items()) | ||
|
||
# start navigation | ||
bringup_cmd = IncludeLaunchDescription( | ||
PythonLaunchDescriptionSource( | ||
os.path.join(nav2_bringup_dir, 'launch', 'bringup_launch.py')), | ||
launch_arguments={'map': map_yaml_file}.items()) | ||
|
||
# start the demo autonomy task | ||
demo_cmd = Node( | ||
package='nav2_simple_commander', | ||
executable='example_nav_through_poses', | ||
emulate_tty=True, | ||
output='screen') | ||
|
||
ld = LaunchDescription() | ||
ld.add_action(start_gazebo_server_cmd) | ||
ld.add_action(start_gazebo_client_cmd) | ||
ld.add_action(start_robot_state_publisher_cmd) | ||
ld.add_action(rviz_cmd) | ||
ld.add_action(bringup_cmd) | ||
ld.add_action(demo_cmd) | ||
return ld |
77 changes: 77 additions & 0 deletions
77
nav2_simple_commander/launch/nav_to_pose_example_launch.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# Copyright (c) 2021 Samsung Research America | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import os | ||
|
||
from ament_index_python.packages import get_package_share_directory | ||
|
||
from launch import LaunchDescription | ||
from launch.actions import ExecuteProcess, IncludeLaunchDescription | ||
from launch.launch_description_sources import PythonLaunchDescriptionSource | ||
from launch_ros.actions import Node | ||
|
||
|
||
def generate_launch_description(): | ||
warehouse_dir = get_package_share_directory('aws_robomaker_small_warehouse_world') | ||
nav2_bringup_dir = get_package_share_directory('nav2_bringup') | ||
python_commander_dir = get_package_share_directory('nav2_simple_commander') | ||
|
||
map_yaml_file = os.path.join(warehouse_dir, 'maps', '005', 'map.yaml') | ||
world = os.path.join(python_commander_dir, 'warehouse.world') | ||
|
||
# start the simulation | ||
start_gazebo_server_cmd = ExecuteProcess( | ||
cmd=['gzserver', '-s', 'libgazebo_ros_factory.so', world], | ||
cwd=[warehouse_dir], output='screen') | ||
|
||
start_gazebo_client_cmd = ExecuteProcess( | ||
cmd=['gzclient'], | ||
cwd=[warehouse_dir], output='screen') | ||
|
||
urdf = os.path.join(nav2_bringup_dir, 'urdf', 'turtlebot3_waffle.urdf') | ||
start_robot_state_publisher_cmd = Node( | ||
package='robot_state_publisher', | ||
executable='robot_state_publisher', | ||
name='robot_state_publisher', | ||
output='screen', | ||
arguments=[urdf]) | ||
|
||
# start the visualization | ||
rviz_cmd = IncludeLaunchDescription( | ||
PythonLaunchDescriptionSource( | ||
os.path.join(nav2_bringup_dir, 'launch', 'rviz_launch.py')), | ||
launch_arguments={'namespace': '', | ||
'use_namespace': 'False'}.items()) | ||
|
||
# start navigation | ||
bringup_cmd = IncludeLaunchDescription( | ||
PythonLaunchDescriptionSource( | ||
os.path.join(nav2_bringup_dir, 'launch', 'bringup_launch.py')), | ||
launch_arguments={'map': map_yaml_file}.items()) | ||
|
||
# start the demo autonomy task | ||
demo_cmd = Node( | ||
package='nav2_simple_commander', | ||
executable='example_nav_to_pose', | ||
emulate_tty=True, | ||
output='screen') | ||
|
||
ld = LaunchDescription() | ||
ld.add_action(start_gazebo_server_cmd) | ||
ld.add_action(start_gazebo_client_cmd) | ||
ld.add_action(start_robot_state_publisher_cmd) | ||
ld.add_action(rviz_cmd) | ||
ld.add_action(bringup_cmd) | ||
ld.add_action(demo_cmd) | ||
return ld |
Oops, something went wrong.