├── simulation_ws
├── src
│ ├── cloudwatch_simulation
│ │ ├── maps
│ │ │ └── .gitignore
│ │ ├── launch
│ │ │ ├── view_empty_world.launch
│ │ │ ├── test_world.launch
│ │ │ ├── start_map_service.launch
│ │ │ ├── small_house.launch
│ │ │ ├── bookstore.launch
│ │ │ ├── empty_world.launch
│ │ │ ├── turtlebot3_navigation.launch
│ │ │ ├── worldforge_turtlebot_navigation.launch
│ │ │ ├── small_house_turtlebot_navigation.launch
│ │ │ └── bookstore_turtlebot_navigation.launch
│ │ ├── CMakeLists.txt
│ │ ├── package.xml
│ │ └── worlds
│ │ │ └── empty.world
│ ├── test_nodes
│ │ ├── src
│ │ │ └── test_nodes
│ │ │ │ └── __init__.py
│ │ ├── setup.py
│ │ ├── package.xml
│ │ ├── launch
│ │ │ └── test.launch
│ │ ├── CMakeLists.txt
│ │ └── nodes
│ │ │ └── navigation_test.py
│ ├── aws_robomaker_simulation_common
│ │ ├── src
│ │ │ └── aws_robomaker_simulation_common
│ │ │ │ └── __init__.py
│ │ ├── setup.py
│ │ ├── README.md
│ │ ├── CMakeLists.txt
│ │ ├── package.xml
│ │ ├── worlds
│ │ │ └── empty.world
│ │ └── nodes
│ │ │ └── route_manager.py
│ └── LICENSE.txt
└── .rosinstall
├── robot_ws
├── src
│ ├── cloudwatch_robot
│ │ ├── src
│ │ │ └── cloudwatch_robot
│ │ │ │ └── __init__.py
│ │ ├── config
│ │ │ ├── health_metrics_config.yaml
│ │ │ ├── cloudwatch_logs_config.yaml
│ │ │ └── cloudwatch_metrics_config.yaml
│ │ ├── deploymentScripts
│ │ │ ├── post_launch_file.sh
│ │ │ ├── pre_launch_file.sh
│ │ │ └── post_check_monitor_nodes.sh
│ │ ├── setup.py
│ │ ├── launch
│ │ │ ├── deploy_rotate.launch
│ │ │ ├── deploy_await_commands.launch
│ │ │ ├── rotate.launch
│ │ │ ├── await_commands.launch
│ │ │ └── monitoring.launch
│ │ ├── package.xml
│ │ ├── nodes
│ │ │ ├── rotate.py
│ │ │ ├── monitor_speed.py
│ │ │ ├── monitor_distance_to_goal.py
│ │ │ └── monitor_obstacle_distance.py
│ │ └── CMakeLists.txt
│ └── LICENSE.txt
└── .rosinstall
├── map_config
├── bookstore.rb
├── default.rb
├── worldforge.rb
├── small_house.rb
├── small_warehouse.rb
├── no_roof_small_warehouse.rb
└── default_args.json
├── scripts
├── build.sh
├── bundle.sh
├── genmap.sh
├── genmap_script.sh
├── add_map_plugin.py
└── setup.sh
├── docs
└── images
│ ├── BookstoreRVizPlan01.png
│ └── CloudWatchMetrics01.png
├── NOTICE
├── .github
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── lint.yml
│ ├── ros1.yml
│ └── ros2.yml
├── CODE_OF_CONDUCT.md
├── .gitignore
├── LICENSE
├── Makefile
├── CONTRIBUTING.md
├── roboMakerSettings.json
└── README.md
/simulation_ws/src/cloudwatch_simulation/maps/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/simulation_ws/src/test_nodes/src/test_nodes/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/src/cloudwatch_robot/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/simulation_ws/src/aws_robomaker_simulation_common/src/aws_robomaker_simulation_common/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/map_config/bookstore.rb:
--------------------------------------------------------------------------------
1 | @map_res = 0.05
2 | @robot_init_x = 0.0
3 | @robot_init_y = 0.0
4 | @map_size_x = 25
5 | @map_size_y = 25
--------------------------------------------------------------------------------
/map_config/default.rb:
--------------------------------------------------------------------------------
1 | @map_res = 0.05
2 | @robot_init_x = 0.0
3 | @robot_init_y = 0.0
4 | @map_size_x = 25
5 | @map_size_y = 25
--------------------------------------------------------------------------------
/map_config/worldforge.rb:
--------------------------------------------------------------------------------
1 | @map_res = 0.05
2 | @robot_init_x = 0.0
3 | @robot_init_y = 0.0
4 | @map_size_x = 30
5 | @map_size_y = 30
--------------------------------------------------------------------------------
/map_config/small_house.rb:
--------------------------------------------------------------------------------
1 | @map_res = 0.05
2 | @robot_init_x = 3.0
3 | @robot_init_y = 3.0
4 | @map_size_x = 25
5 | @map_size_y = 25
6 |
--------------------------------------------------------------------------------
/map_config/small_warehouse.rb:
--------------------------------------------------------------------------------
1 | @map_res = 0.05
2 | @robot_init_x = 0.0
3 | @robot_init_y = 0.0
4 | @map_size_x = 25
5 | @map_size_y = 25
--------------------------------------------------------------------------------
/map_config/no_roof_small_warehouse.rb:
--------------------------------------------------------------------------------
1 | @map_res = 0.05
2 | @robot_init_x = 0.0
3 | @robot_init_y = 0.0
4 | @map_size_x = 25
5 | @map_size_y = 25
--------------------------------------------------------------------------------
/scripts/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | COLCON_LOG_PATH="$@/logs" colcon build --base-paths "$@" --build-base "$@/build" --install-base "$@/install"
4 |
--------------------------------------------------------------------------------
/docs/images/BookstoreRVizPlan01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-robotics/aws-robomaker-sample-application-cloudwatch/ros1/docs/images/BookstoreRVizPlan01.png
--------------------------------------------------------------------------------
/docs/images/CloudWatchMetrics01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aws-robotics/aws-robomaker-sample-application-cloudwatch/ros1/docs/images/CloudWatchMetrics01.png
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/config/health_metrics_config.yaml:
--------------------------------------------------------------------------------
1 | # metrics sampling interval in seconds
2 | interval: 5
3 |
4 | #Robot Id
5 | robot_id: Turtlebot3
--------------------------------------------------------------------------------
/scripts/bundle.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | COLCON_LOG_PATH="$@/logs" colcon bundle --base-paths "$@" --build-base "$@/build" --install-base "$@/install" --bundle-base "$@/bundle"
4 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
3 | This product includes software developed by
4 | Amazon Technologies, Inc (http://www.amazon.com/).
5 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | *Issue #, if available:*
2 |
3 | *Description of changes:*
4 |
5 |
6 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
7 |
--------------------------------------------------------------------------------
/robot_ws/.rosinstall:
--------------------------------------------------------------------------------
1 | # Amazon ROS CloudServiceIntegration package dependencies
2 | - git: {local-name: src/deps/turtlebot3-description-reduced-mesh, uri: "https://github.com/aws-robotics/turtlebot3-description-reduced-mesh.git", version: "ros1"}
3 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/view_empty_world.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | simulation_ws/src/aws-robomaker-bookstore-world
2 | simulation_ws/src/aws-robomaker-small-house-world
3 | robot_ws/build
4 | robot_ws/bundle
5 | robot_ws/install
6 | robot_ws/log
7 | robot_ws/src/deps
8 | simulation_ws/build
9 | simulation_ws/bundle
10 | simulation_ws/install
11 | simulation_ws/log
12 | simulation_ws/src/deps
13 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/deploymentScripts/post_launch_file.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a script which can be run after launching the ROS processes.
3 | # You can include a post-check of ROS processes in this post-launch file.
4 | # Non-zero exit status from script would cause robot deployment failure.
5 | # Use "deploymentScripts/post_launch_file.sh" as the postLaunchFile path.
6 |
7 | echo Hello World, post-launch
8 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/deploymentScripts/pre_launch_file.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a script which can be run before running the ROS launch file.
3 | # You can include a pre-check of robot environment in this pre-launch file.
4 | # Non-zero exit status from script would cause robot deployment failure.
5 | # Use "deploymentScripts/pre_launch_file.sh" as the preLaunchFile path.
6 |
7 | echo Hello World, pre-launch
8 |
--------------------------------------------------------------------------------
/simulation_ws/src/test_nodes/setup.py:
--------------------------------------------------------------------------------
1 | ## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
2 | ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
3 |
4 | from distutils.core import setup
5 | from catkin_pkg.python_setup import generate_distutils_setup
6 |
7 | # fetch values from package.xml
8 | setup_args = generate_distutils_setup(
9 | packages=['test_nodes'],
10 | package_dir={'': 'src'}
11 | )
12 |
13 | setup(**setup_args)
14 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/setup.py:
--------------------------------------------------------------------------------
1 | # ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
2 | # See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
3 |
4 | from distutils.core import setup
5 |
6 | from catkin_pkg.python_setup import generate_distutils_setup
7 |
8 | # fetch values from package.xml
9 | setup_args = generate_distutils_setup(
10 | packages=['cloudwatch_robot'],
11 | package_dir={'': 'src'}
12 | )
13 |
14 | setup(**setup_args)
15 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/launch/deploy_rotate.launch:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/simulation_ws/src/aws_robomaker_simulation_common/setup.py:
--------------------------------------------------------------------------------
1 | # ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
2 | # See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
3 |
4 | from distutils.core import setup
5 |
6 | from catkin_pkg.python_setup import generate_distutils_setup
7 |
8 | # fetch values from package.xml
9 | setup_args = generate_distutils_setup(
10 | packages=['aws_robomaker_simulation_common'],
11 | package_dir={'': 'src'}
12 | )
13 |
14 | setup(**setup_args)
15 |
--------------------------------------------------------------------------------
/simulation_ws/src/aws_robomaker_simulation_common/README.md:
--------------------------------------------------------------------------------
1 | # AWS RoboMaker Simulations Common utilities and helpers
2 |
3 | ### Route Manager
4 | Node that sends a route of target goals to the robot. Sends to the move_base server.
5 |
6 | Includes in your .launch:
7 | ```
8 |
9 | ...
10 |
11 |
12 |
13 | ...
14 |
15 | ```
16 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(cloudwatch_simulation)
3 |
4 | find_package(catkin REQUIRED COMPONENTS
5 | gazebo_ros
6 | turtlebot3_description # required to install .rviz model
7 | )
8 |
9 | catkin_package()
10 |
11 | install(DIRECTORY launch worlds maps
12 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
13 | )
14 |
15 | # Copy the rviz model for easier access in RoboMaker RViz
16 | install(FILES ${turtlebot3_description_DIR}/../rviz/model.rviz
17 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz
18 | RENAME turtlebot3_model.rviz
19 | )
20 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/test_world.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/simulation_ws/src/test_nodes/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | test_nodes
4 | 1.2.1
5 |
6 | AWS RoboMaker simulation test nodes.
7 |
8 | MIT
9 | AWS RoboMaker
10 | AWS RoboMaker
11 | catkin
12 | rospy
13 | std_msgs
14 | rosgraph_msgs
15 | aws_robomaker_simulation_ros_pkgs
16 | ros_monitoring_msgs
17 |
18 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: "Lint cloudwatch-sample-application-ros1"
2 | on:
3 | pull_request:
4 |
5 | jobs:
6 | ament_lint:
7 | runs-on: ubuntu-latest
8 | container:
9 | image: rostooling/setup-ros-docker:ubuntu-focal-ros-rolling-ros-base-latest
10 | strategy:
11 | fail-fast: false
12 | matrix:
13 | linter: [flake8, pep257, xmllint, copyright]
14 | steps:
15 | - uses: actions/checkout@v2
16 | - uses: ros-tooling/action-ros-lint@v0.1
17 | with:
18 | distribution: rolling
19 | linter: ${{ matrix.linter }}
20 | package-name: |
21 | aws_robomaker_simulation_common
22 | cloudwatch_simulation
23 | cloudwatch_robot
24 |
--------------------------------------------------------------------------------
/map_config/default_args.json:
--------------------------------------------------------------------------------
1 | {
2 | "no_roof_small_warehouse": [
3 | "./map_config/no_roof_small_warehouse.rb",
4 | "aws-robomaker-small-warehouse-world"
5 | ],
6 | "bookstore": [
7 | "./map_config/bookstore.rb",
8 | "aws-robomaker-bookstore-world"
9 | ],
10 | "small_warehouse": [
11 | "./map_config/small_warehouse.rb",
12 | "aws-robomaker-small-warehouse-world"
13 | ],
14 | "small_house": [
15 | "./map_config/small_house.rb",
16 | "aws-robomaker-small-house-world"
17 | ],
18 | "worldforge": [
19 | "./map_config/worldforge.rb",
20 | "./simulation_ws/src/aws_robomaker_worldforge_pkgs/aws_robomaker_worldforge_worlds/worlds"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/start_map_service.launch:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/small_house.launch:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/deploymentScripts/post_check_monitor_nodes.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # This is a script which can be run after launching the ROS processes.
3 | # You can include a post-check of ROS processes in this post-launch file.
4 | # Non-zero exit status from script would cause robot deployment failure.
5 | # Use "deploymentScripts/post_launch_file.sh" as the postLaunchFile path.
6 |
7 | # Wait all monitoring nodes starts.
8 | sleep 30
9 | # ping and verify nodes started
10 | set -e
11 | rosnode ping -c 3 monitor_speed
12 | rosnode ping -c 3 monitor_obstacle_distance
13 | rosnode ping -c 3 monitor_distance_to_goal
14 | rosnode ping -c 3 cloudwatch_logger
15 | rosnode ping -c 3 cloudwatch_metrics_collector
16 | rosnode ping -c 3 health_metric_collector
17 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/launch/deploy_await_commands.launch:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/simulation_ws/src/aws_robomaker_simulation_common/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(aws_robomaker_simulation_common)
3 |
4 | find_package(catkin REQUIRED COMPONENTS
5 | gazebo_ros
6 | turtlebot3_navigation # required for copy of .rviz file
7 | )
8 |
9 | catkin_package()
10 | catkin_python_setup()
11 |
12 | install(DIRECTORY worlds
13 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
14 | )
15 |
16 | catkin_install_python(PROGRAMS
17 | nodes/route_manager.py
18 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
19 | )
20 |
21 | # Copy the rviz models for easier access in AWS RoboMaker RViz
22 | install(FILES ${turtlebot3_navigation_DIR}/../rviz/turtlebot3_navigation.rviz
23 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz
24 | RENAME turtlebot3_navigation.rviz
25 | )
26 |
--------------------------------------------------------------------------------
/simulation_ws/src/test_nodes/launch/test.launch:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/bookstore.launch:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/config/cloudwatch_logs_config.yaml:
--------------------------------------------------------------------------------
1 | # name of the log group to use. If it doesn't exist, will try to create it first
2 | # default value is: ros_log_group
3 | log_group_name: robomaker_cloudwatch_monitoring_example
4 |
5 | # name of the log stream to send logs to. If it doesn't exist, will try to create it first
6 | # default value is: ros_log_stream
7 | log_stream_name: turtlebot3
8 |
9 | # how often to send a batch of logs to cloudwatch in the log group and log stream specified
10 | # default value is: 5.0
11 | publish_frequency: 5.0
12 |
13 | # whether to subscribe to the rosout_agg topic to get logs
14 | # default value is: true
15 | sub_to_rosout: true
16 |
17 | # other topics to subscribe to get logs
18 | # default value is: empty list
19 | topics: []
20 |
21 | #aws region configuration
22 | aws_client_configuration:
23 | region: "us-west-2"
24 | connect_timeout_ms: 9000
25 | request_timeout_ms: 9000
26 |
--------------------------------------------------------------------------------
/simulation_ws/.rosinstall:
--------------------------------------------------------------------------------
1 | - git: {local-name: src/deps/aws-robomaker-bookstore-world, uri: "https://github.com/aws-robotics/aws-robomaker-bookstore-world", version: ros1}
2 | - git: {local-name: src/deps/aws-robomaker-small-house-world, uri: "https://github.com/aws-robotics/aws-robomaker-small-house-world", version: ros1}
3 | - git: {local-name: src/deps/aws-robomaker-small-warehouse-world, uri: "https://github.com/aws-robotics/aws-robomaker-small-warehouse-world", version: ros1}
4 | - git: {local-name: src/deps/aws-robomaker-simulation-ros-pkgs, uri: 'https://github.com/aws-robotics/aws-robomaker-simulation-ros-pkgs.git', version: master}
5 | - git: {local-name: src/deps/map_generation_plugin, uri: 'https://github.com/marinaKollmitz/gazebo_ros_2Dmap_plugin', version: 0820610f46235cd7ce1458ea030ef83b1616da37}
6 | - git: {local-name: src/deps/turtlebot3-description-reduced-mesh, uri: "https://github.com/aws-robotics/turtlebot3-description-reduced-mesh.git", version: "ros1"}
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
4 | software and associated documentation files (the "Software"), to deal in the Software
5 | without restriction, including without limitation the rights to use, copy, modify,
6 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7 | permit persons to whom the Software is furnished to do so.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
10 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
11 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
12 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
13 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
14 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/empty_world.launch:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/simulation_ws/src/aws_robomaker_simulation_common/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | aws_robomaker_simulation_common
4 | 1.2.1
5 |
6 | AWS RoboMaker simulation package for commonly used nodes and helpers.
7 |
8 | Apache 2.0
9 | AWS RoboMaker
10 | AWS RoboMaker
11 | catkin
12 | turtlebot3_navigation
13 | gazebo_ros
14 | gazebo
15 | gazebo_plugins
16 |
17 |
18 | moveit_ros
19 | dwa_local_planner
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/robot_ws/src/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2018 Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/simulation_ws/src/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2018 Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all setup build build_robot build_simulation bundle bundle_robot bundle_simulation clean clean_robot_build clean_robot_bundle clean_simulation_build clean_simulation_bundle
2 | .DEFAULT_GOAL := all
3 |
4 | all: bundle
5 |
6 | # This forces each step in 'ci' to run in serial, but each step will run all of its commands in parallel
7 | ci:
8 | $(MAKE) setup
9 | $(MAKE) build
10 | $(MAKE) bundle
11 |
12 | setup:
13 | scripts/setup.sh
14 |
15 | build: build_robot build_simulation
16 |
17 | build_robot:
18 | scripts/build.sh ./robot_ws
19 |
20 | build_simulation:
21 | scripts/build.sh ./simulation_ws
22 |
23 | bundle: bundle_robot bundle_simulation
24 |
25 | bundle_robot: build_robot
26 | scripts/bundle.sh ./robot_ws
27 |
28 | bundle_simulation: build_simulation
29 | scripts/bundle.sh ./simulation_ws
30 |
31 | clean: clean_robot_build clean_robot_bundle clean_simulation_build clean_simulation_bundle
32 |
33 | clean_robot_build:
34 | rm -rf ./robot_ws/build ./robot_ws/install
35 |
36 | clean_robot_bundle:
37 | rm -rf ./robot_ws/bundle
38 |
39 | clean_simulation_build:
40 | rm -rf ./simulation_ws/build ./simulation_ws/install
41 |
42 | clean_simulation_bundle:
43 | rm -rf ./simulation_ws/bundle
44 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | cloudwatch_simulation
4 | 1.2.1
5 |
6 | AWS RoboMaker simulation package for launching a TurtleBot3 in a empty world or a small house.
7 |
8 | MIT
9 | AWS RoboMaker
10 | AWS RoboMaker
11 | catkin
12 | roscpp
13 | std_msgs
14 | sensor_msgs
15 | geometry_msgs
16 | nav_msgs
17 | tf
18 | gazebo_ros
19 | gazebo_plugins
20 |
21 | turtlebot3_description
22 |
23 | turtlebot3_navigation
24 | gazebo
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/launch/rotate.launch:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/turtlebot3_navigation.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/simulation_ws/src/aws_robomaker_simulation_common/worlds/empty.world:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 | model://sun
11 |
12 |
13 |
14 |
15 | model://ground_plane
16 |
17 |
18 |
19 | 1000.0
20 | 0.001
21 | 1
22 |
23 |
24 | quick
25 | 150
26 | 0
27 | 1.400000
28 | 1
29 |
30 |
31 | 0.00001
32 | 0.2
33 | 2000.000000
34 | 0.01000
35 |
36 |
37 |
38 |
39 | 0.4 0.4 0.4 1
40 | 0.7 0.7 0.7 1
41 | true
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/launch/await_commands.launch:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | cloudwatch_robot
4 | 1.2.1
5 |
6 | AWS RoboMaker robot package that provides a sample application for integrating AWS CloudWatch with ROS.
7 |
8 | MIT
9 | AWS RoboMaker
10 | AWS RoboMaker
11 | catkin
12 | rospy
13 | roscpp
14 |
15 | std_msgs
16 | sensor_msgs
17 | geometry_msgs
18 | nav_msgs
19 |
20 | message_generation
21 | message_runtime
22 | message_runtime
23 |
24 |
25 | cloudwatch_logger
26 | cloudwatch_metrics_collector
27 | cloudwatch_logs_common
28 | cloudwatch_metrics_common
29 | aws_common
30 | aws_ros1_common
31 | ros_monitoring_msgs
32 |
33 |
34 | health_metric_collector
35 |
36 |
37 | turtlebot3_msgs
38 | robot_state_publisher
39 |
40 | turtlebot3_bringup
41 |
42 | turtlebot3_description
43 |
44 | turtlebot3_navigation
45 |
46 | turtlebot3_description_reduced_mesh
47 |
48 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/nodes/rotate.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | # software and associated documentation files (the "Software"), to deal in the Software
7 | # without restriction, including without limitation the rights to use, copy, modify,
8 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | # permit persons to whom the Software is furnished to do so.
10 | #
11 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
18 | from geometry_msgs.msg import Twist
19 |
20 | import rospy
21 |
22 |
23 | class Rotator:
24 |
25 | def __init__(self):
26 | self._cmd_pub = rospy.Publisher('/cmd_vel', Twist, queue_size=1)
27 |
28 | def rotate_forever(self):
29 | self.twist = Twist()
30 |
31 | direction = 1
32 | angular_speed = 0.2
33 | r = rospy.Rate(0.1)
34 | while not rospy.is_shutdown():
35 | self.twist.angular.z = direction * angular_speed
36 | self._cmd_pub.publish(self.twist)
37 | rospy.loginfo('Rotating Robot: %s', self.twist)
38 | r.sleep()
39 |
40 |
41 | def main():
42 | rospy.init_node('rotate')
43 | try:
44 | rotator = Rotator()
45 | rotator.rotate_forever()
46 | except rospy.ROSInterruptException:
47 | pass
48 |
49 |
50 | if __name__ == '__main__':
51 | main()
52 |
--------------------------------------------------------------------------------
/scripts/genmap.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # -------------------------------------------------------------------------
4 |
5 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 |
19 | # -------------------------------------------------------------------------
20 |
21 | # This script adds map generation plugin to the input world and plugin config parameters
22 |
23 | # Input args via command line:
24 | # [required]
25 | # [required]
26 | # [required]
27 |
28 | set -e
29 |
30 | if [ $# -ne 3 ]; then
31 | echo "expects 3 arguments"
32 | exit 2
33 | fi
34 |
35 | worldfile=$2
36 | config=$1
37 | worldbody=`xpath -q -e '/sdf/world/*' $worldfile`
38 | template="""
39 | <%
40 | %>
41 |
42 |
43 | $worldbody
44 |
45 | <%= @map_res %>
46 | 0.3
47 | <%= @map_size_x %>
48 | <%= @map_size_y %>
49 | <%= @robot_init_x %>
50 | <%= @robot_init_y %>
51 |
52 |
53 |
54 | """
55 | echo $template | erb -r "$config" | xmllint --format - > $3
56 | echo $3
57 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/worldforge_turtlebot_navigation.launch:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/scripts/genmap_script.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # -------------------------------------------------------------------------
4 |
5 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 |
19 | # -------------------------------------------------------------------------
20 |
21 | # This script generates map files for the input world
22 |
23 | # Input args via command line:
24 | # [required]
25 |
26 | set -e
27 |
28 | if [ $# -ne 1 ]; then
29 | echo "Expect 1 argument";
30 | exit 2;
31 | fi
32 |
33 | if [ $1 = "worldforge" ] && [ -z "$WORLD_ID" ]; then
34 | echo "For WorldForge world, please set WORLD_ID to your worldforge world as per the README instructions"
35 | exit 2;
36 | fi
37 |
38 | echo "Sudo password may be needed to install system dependencies"
39 | sudo apt-get install ruby-dev libxml-xpath-perl libxml2-utils
40 |
41 | cd simulation_ws
42 | rosws update
43 | rosdep install --from-paths src --ignore-src -r -y
44 | cd ..
45 |
46 | set +e
47 |
48 | OUTPUT=`python scripts/add_map_plugin.py default --world_name $1`
49 |
50 | if [ $? -eq 2 ]
51 | then
52 | echo $OUTPUT
53 | exit $?
54 | else
55 | world_source_path=$OUTPUT
56 | fi
57 |
58 | set -e
59 |
60 | cd simulation_ws
61 | colcon build
62 | source install/local_setup.sh
63 | cd ..
64 |
65 | map_output_path=$(dirname $(dirname $world_source_path))/maps/map
66 |
67 | roslaunch cloudwatch_simulation start_map_service.launch &
68 |
69 | python << END
70 | import rospy
71 |
72 | rospy.wait_for_service('/gazebo_2Dmap_plugin/generate_map')
73 | END
74 |
75 | rosservice call /gazebo_2Dmap_plugin/generate_map
76 | rosrun map_server map_saver -f $map_output_path /map:=/map2d
77 |
78 | cd simulation_ws
79 | colcon build
80 |
81 | kill $!
82 |
83 | echo "--- Map file generated at $map_output_path"
84 |
--------------------------------------------------------------------------------
/simulation_ws/src/test_nodes/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # Set minimum required version of cmake, project name and compile options
3 | ################################################################################
4 | cmake_minimum_required(VERSION 2.8.3)
5 | project(test_nodes)
6 |
7 | ################################################################################
8 | # Find catkin packages and libraries for catkin and system dependencies
9 | ################################################################################
10 | find_package(catkin REQUIRED COMPONENTS
11 | rospy
12 | std_msgs
13 | rosgraph_msgs
14 | )
15 |
16 | ################################################################################
17 | # Setup for python modules and scripts
18 | ################################################################################
19 | catkin_python_setup()
20 |
21 | ################################################################################
22 | # Declare ROS messages, services and actions
23 | ################################################################################
24 |
25 | ################################################################################
26 | # Declare ROS dynamic reconfigure parameters
27 | ################################################################################
28 |
29 | ################################################################################
30 | # Declare catkin specific configuration to be passed to dependent projects
31 | ################################################################################
32 | catkin_package(
33 | CATKIN_DEPENDS
34 | rospy
35 | std_msgs
36 | rosgraph_msgs
37 | )
38 |
39 | ################################################################################
40 | # Build
41 | ################################################################################
42 |
43 | ################################################################################
44 | # Install
45 | ################################################################################
46 | catkin_install_python(PROGRAMS
47 | nodes/navigation_test.py
48 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
49 | )
50 |
51 | install(DIRECTORY launch
52 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
53 | )
54 |
55 | ################################################################################
56 | # Test
57 | ################################################################################
58 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/nodes/monitor_speed.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | # software and associated documentation files (the "Software"), to deal in the Software
7 | # without restriction, including without limitation the rights to use, copy, modify,
8 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | # permit persons to whom the Software is furnished to do so.
10 | #
11 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
18 | import time
19 |
20 | from nav_msgs.msg import Odometry
21 | from ros_monitoring_msgs.msg import MetricData, MetricDimension, MetricList
22 | import rospy
23 | from std_msgs.msg import Header
24 |
25 |
26 | class Monitor:
27 |
28 | def __init__(self, data_topic, data_msg, metric_topic, transform):
29 | self.metrics_pub = rospy.Publisher(metric_topic, MetricList, queue_size=1)
30 | self.topic_sub = rospy.Subscriber(data_topic, data_msg, self.callback)
31 | self.transform = transform
32 |
33 | def callback(self, message):
34 | self.metrics_pub.publish(self.transform(message))
35 |
36 |
37 | def odom_to_speed(odom):
38 | header = Header()
39 | header.stamp = rospy.Time.from_sec(time.time())
40 |
41 | dimensions = [
42 | MetricDimension(name='robot_id', value='Turtlebot3'),
43 | MetricDimension(name='category', value='RobotOperations'),
44 | ]
45 |
46 | linear_speed = MetricData(
47 | header=header,
48 | metric_name='linear_speed',
49 | unit=MetricData.UNIT_NONE,
50 | value=odom.twist.twist.linear.x,
51 | time_stamp=rospy.Time.from_sec(time.time()),
52 | dimensions=dimensions,
53 | )
54 |
55 | angular_speed = MetricData(
56 | header=header,
57 | metric_name='angular_speed',
58 | unit=MetricData.UNIT_NONE,
59 | value=odom.twist.twist.angular.z,
60 | time_stamp=rospy.Time.from_sec(time.time()),
61 | dimensions=dimensions,
62 | )
63 |
64 | return MetricList([linear_speed, angular_speed])
65 |
66 |
67 | def main():
68 | rospy.init_node('speed_monitor')
69 | monitor = Monitor(data_topic='/odom',
70 | data_msg=Odometry,
71 | metric_topic='/metrics',
72 | transform=odom_to_speed)
73 | if (monitor):
74 | rospy.spin()
75 |
76 |
77 | if __name__ == '__main__':
78 | main()
79 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/small_house_turtlebot_navigation.launch:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/nodes/monitor_distance_to_goal.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | # software and associated documentation files (the "Software"), to deal in the Software
7 | # without restriction, including without limitation the rights to use, copy, modify,
8 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | # permit persons to whom the Software is furnished to do so.
10 | #
11 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
18 | from itertools import izip
19 | import time
20 |
21 | from nav_msgs.msg import Path
22 | import numpy as np
23 | from ros_monitoring_msgs.msg import MetricData, MetricDimension, MetricList
24 | import rospy
25 | from std_msgs.msg import Header
26 |
27 |
28 | class MonitorDistanceToGoal:
29 |
30 | def __init__(self):
31 | self.scan_sub = rospy.Subscriber(
32 | '/move_base/NavfnROS/plan', Path, callback=self.report_metric
33 | )
34 | self.metrics_pub = rospy.Publisher('/metrics', MetricList, queue_size=1)
35 |
36 | def calc_path_distance(self, msg):
37 | points = [(p.pose.position.x, p.pose.position.y) for p in msg.poses]
38 | array = np.array(points, dtype=np.dtype('f8', 'f8'))
39 | return sum((np.linalg.norm(p0 - p1) for p0, p1 in izip(array[:-2], array[1:])))
40 |
41 | def report_metric(self, msg):
42 | if not msg.poses:
43 | rospy.logdebug('Path empty, not calculating distance')
44 | return
45 |
46 | distance = self.calc_path_distance(msg)
47 | rospy.logdebug('Distance to goal: %s', distance)
48 |
49 | header = Header()
50 | header.stamp = rospy.Time.from_sec(time.time())
51 |
52 | dimensions = [
53 | MetricDimension(name='robot_id', value='Turtlebot3'),
54 | MetricDimension(name='category', value='RobotOperations'),
55 | ]
56 | metric = MetricData(
57 | header=header,
58 | metric_name='distance_to_goal',
59 | unit=MetricData.UNIT_NONE,
60 | value=distance,
61 | time_stamp=rospy.Time.from_sec(time.time()),
62 | dimensions=dimensions,
63 | )
64 |
65 | self.metrics_pub.publish(MetricList([metric]))
66 |
67 |
68 | def main():
69 | rospy.init_node('monitor_goal_to_distance')
70 | try:
71 | monitor = MonitorDistanceToGoal()
72 | if (monitor):
73 | rospy.spin()
74 | except rospy.ROSInterruptException:
75 | pass
76 |
77 |
78 | if __name__ == '__main__':
79 | main()
80 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/launch/monitoring.launch:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | $(arg aws_region)
38 | $(arg aws_metrics_namespace)-$(arg launch_id)
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | $(arg aws_region)
49 | $(arg log_group_name)-$(arg launch_id)
50 |
51 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/nodes/monitor_obstacle_distance.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | # software and associated documentation files (the "Software"), to deal in the Software
7 | # without restriction, including without limitation the rights to use, copy, modify,
8 | # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | # permit persons to whom the Software is furnished to do so.
10 | #
11 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16 | # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
18 | import time
19 |
20 | from ros_monitoring_msgs.msg import MetricData, MetricDimension, MetricList
21 | import rospy
22 | from sensor_msgs.msg import LaserScan
23 | from std_msgs.msg import Header
24 |
25 |
26 | class MonitorNearestObstacle:
27 |
28 | def __init__(self):
29 | self.scan_sub = rospy.Subscriber('scan', LaserScan, callback=self.report_metric)
30 | self.metrics_pub = rospy.Publisher('/metrics', MetricList, queue_size=1)
31 |
32 | def filter_scan(self, msg):
33 | rospy.loginfo(
34 | 'Filtering scan values in value range (%s,%s)', msg.range_min, msg.range_max
35 | )
36 | return [
37 | msg.ranges[i]
38 | for i in range(360)
39 | if msg.ranges[i] >= msg.range_min and msg.ranges[i] <= msg.range_max
40 | ]
41 |
42 | def report_metric(self, msg):
43 | filtered_scan = self.filter_scan(msg)
44 | if not filtered_scan:
45 | rospy.loginfo(
46 | 'No obstacles with scan range (%s,%s)', msg.range_min, msg.range_max
47 | )
48 | return
49 |
50 | min_distance = min(filtered_scan)
51 | rospy.loginfo('Nearest obstacle: %s', min_distance)
52 |
53 | header = Header()
54 | header.stamp = rospy.Time.from_sec(time.time())
55 |
56 | dimensions = [
57 | MetricDimension(name='robot_id', value='Turtlebot3'),
58 | MetricDimension(name='category', value='RobotOperations'),
59 | ]
60 | metric = MetricData(
61 | header=header,
62 | metric_name='nearest_obstacle_distance',
63 | unit=MetricData.UNIT_NONE,
64 | value=min_distance,
65 | time_stamp=rospy.Time.from_sec(time.time()),
66 | dimensions=dimensions,
67 | )
68 |
69 | self.metrics_pub.publish(MetricList([metric]))
70 |
71 |
72 | def main():
73 | rospy.init_node('monitor_obstacle_distance')
74 | try:
75 | monitor = MonitorNearestObstacle()
76 | if (monitor):
77 | rospy.spin()
78 | except rospy.ROSInterruptException:
79 | pass
80 |
81 |
82 | if __name__ == '__main__':
83 | main()
84 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/launch/bookstore_turtlebot_navigation.launch:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/scripts/add_map_plugin.py:
--------------------------------------------------------------------------------
1 | # -------------------------------------------------------------------------
2 |
3 | # Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | # -------------------------------------------------------------------------
18 |
19 | import sys
20 | import os
21 | import subprocess
22 | import argparse
23 | import json
24 |
25 |
26 | def process_args(args, default_args):
27 | '''
28 | Processes arguments for map plugin tool.
29 | '''
30 |
31 | # default arguments
32 | if hasattr(args, 'world_name'):
33 | world_name = args.world_name
34 | config_file = default_args[world_name][0]
35 | try:
36 | world_file = "simulation_ws/src/deps/{0}/worlds/{1}.world".format(default_args[world_name][1], world_name) if world_name!="worldforge" \
37 | else os.path.join(default_args[world_name][1], os.environ['WORLD_ID'], os.environ['WORLD_ID']+".world")
38 | except KeyError:
39 | raise KeyError("Please set WORLD_ID to your worldforge world as per the README instructions")
40 | output_file = "simulation_ws/src/cloudwatch_simulation/worlds/map_plugin.world"
41 |
42 | #custom config file, world file, output file
43 | else:
44 | config_file, world_file, output_file = args.config_file, args.world_file, args.output_file
45 |
46 | p_args = [os.path.abspath(x) for x in [config_file, world_file, output_file]]
47 |
48 | return p_args
49 |
50 |
51 | def main():
52 |
53 | default_arg_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, 'map_config/default_args.json')
54 | with open(default_arg_path, 'r') as f:
55 | default_args = json.load(f)
56 |
57 | parser = argparse.ArgumentParser(description="Arguments for default/custom usage of map_plugin tool.")
58 |
59 | subparsers = parser.add_subparsers(help='types of usage')
60 |
61 | # default tool usage
62 | default_parser = subparsers.add_parser("default")
63 | default_parser.add_argument("--world_name", required=True, help="takes a default world_name, each referring to an existing aws-robotics worlds", choices=list(default_args.keys()), type=str)
64 |
65 | # custom tool usage
66 | custom_parser = subparsers.add_parser("custom")
67 | custom_parser.add_argument("-c", "--config_file", required=True, help="config file (.rb) for the map plugin parameters", type=str)
68 | custom_parser.add_argument("-w", "--world_file", required=True, help="path to the original world file", type=str)
69 | custom_parser.add_argument("-o", "--output_file", required=True, help="output path of the new world file", type=str)
70 |
71 | args = process_args(parser.parse_args(), default_args)
72 |
73 | plugin_tool_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "genmap.sh")
74 | cmd = ' '.join([plugin_tool_path] + args)
75 |
76 | try:
77 | out = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
78 | except subprocess.CalledProcessError as e:
79 | print("Execution failed with exitcode {0}\n\n{1}".format(e.returncode, e.output))
80 | sys.exit(e.returncode)
81 | else:
82 | print("{}\n".format(out))
83 |
84 | if __name__=="__main__":
85 | main()
86 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
4 | documentation, we greatly value feedback and contributions from our community.
5 |
6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
7 | information to effectively respond to your bug report or contribution.
8 |
9 |
10 | ## Reporting Bugs/Feature Requests
11 |
12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features.
13 |
14 | When filing an issue, please check [existing open](https://github.com/aws/aws-robomaker-sample-application-cloudwatch/issues), or [recently closed](https://github.com/aws/aws-robomaker-sample-application-cloudwatch/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
16 |
17 | * A reproducible test case or series of steps
18 | * The version of our code being used
19 | * Any modifications you've made relevant to the bug
20 | * Anything unusual about your environment or deployment
21 |
22 |
23 | ## Contributing via Pull Requests
24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
25 |
26 | 1. You are working against the latest source on the *master* branch.
27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
29 |
30 | To send us a pull request, please:
31 |
32 | 1. Fork the repository.
33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
34 | 3. Ensure local tests pass.
35 | 4. Commit to your fork using clear commit messages.
36 | 5. Send us a pull request, answering any default questions in the pull request interface.
37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
38 |
39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
41 |
42 |
43 | ## Finding contributions to work on
44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/aws-robomaker-sample-application-cloudwatch/labels/help%20wanted) issues is a great place to start.
45 |
46 |
47 | ## Code of Conduct
48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
50 | opensource-codeofconduct@amazon.com with any additional questions or comments.
51 |
52 |
53 | ## Security issue notifications
54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
55 |
56 |
57 | ## Licensing
58 |
59 | See the [LICENSE](https://github.com/aws/aws-robomaker-sample-application-cloudwatch/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
60 |
61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.
62 |
--------------------------------------------------------------------------------
/simulation_ws/src/cloudwatch_simulation/worlds/empty.world:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 | 0.8 -0.75 0.35 0 0.25 2.35
13 |
14 |
15 |
16 |
17 |
18 | model://sun
19 |
20 |
21 |
22 |
23 | model://ground_plane
24 |
25 |
26 |
27 |
28 |
29 |
30 | false
31 | model://robocup_3Dsim_ball
32 |
33 |
34 | 0 0 0.10 0 0 0
35 |
36 | 2 2 0.01
37 |
38 | 10
39 |
40 | random
41 |
42 |
43 |
44 |
45 |
46 |
47 | false
48 | 0 0 0.10 0.0 0.0 0.0
49 |
50 |
51 |
52 |
53 | 0.1 0.1 0.1
54 | model://robocup_3Dsim_ball/meshes/ball.dae
55 |
56 |
57 |
58 |
59 |
60 |
61 | 0.1
62 |
63 |
64 |
65 |
66 | 0.50
67 |
68 | 0.01
69 | 0.0
70 | 0.0
71 | 0.01
72 | 0.0
73 | 0.01
74 |
75 |
76 |
77 |
78 | 0 0 0.10 0 0 0
79 |
80 | 3 3 0.01
81 |
82 | 3
83 |
84 | random
85 |
86 |
87 |
88 |
89 | 1000.0
90 | 0.001
91 | 1
92 |
93 |
94 | quick
95 | 150
96 | 0
97 | 1.400000
98 | 1
99 |
100 |
101 | 0.00001
102 | 0.2
103 | 2000.000000
104 | 0.01000
105 |
106 |
107 |
108 |
109 | 0.4 0.4 0.4 1
110 | 0.7 0.7 0.7 1
111 | true
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/config/cloudwatch_metrics_config.yaml:
--------------------------------------------------------------------------------
1 | # An optional metric namespace parameter. If provided it will set the namespace for all metrics provided by this node to
2 | # the provided value. If the node is running on a AWS RoboMaker system then the provided launch file will ignore this parameter in
3 | # favor of the namespace specified by the RoboMaker ecosystem
4 | aws_metrics_namespace: "robomaker_cloudwatch_monitoring_example"
5 |
6 | # An optional list of topics to listen to. If not provided or is empty the node will just listen on the global "metrics"
7 | # topic. If this list is not empty then the node will not subscribe to the "metrics" topic and will only subscribe to the
8 | # topics in the list.
9 | #aws_monitored_metric_topics: ["metrics"]
10 |
11 | # This is the AWS Client Configuration used by the AWS service client in the Node. If given the node will load the
12 | # provided configuration when initializing the client.
13 | aws_client_configuration:
14 | # Specifies where you want the client to communicate. Examples include us-east-1 or us-west-1. You must ensure that
15 | # the service you want to use has an endpoint in the region you configure.
16 | region: "us-west-2"
17 |
18 | # Built in the constructor and pulls information from your operating system. Do not alter the user agent.
19 | #userAgent: ""
20 |
21 | # Use this to override the http endpoint used to talk to a service. If you set this, you must also set authenticationRegion.
22 | #endpointOverride: ""
23 |
24 | # These settings allow you to configure a proxy for all communication with AWS. Examples of when this functionality
25 | # might be useful include debugging in conjunction with the Burp suite, or using a proxy to connect to the Internet.
26 | #proxyHost: ""
27 | #proxyPort: 0
28 | #proxyUserName: ""
29 | #proxyPassword: ""
30 |
31 | # Enables you to tell the HTTP client where to find your SSL certificate trust store (for example, a directory
32 | # prepared with OpenSSL's c_rehash utility). You shouldn't need to do this unless you are using symlinks in your
33 | # environment. This has no effect on Windows or OS X.
34 | #caPath: ""
35 | #caFile: ""
36 |
37 | # Values that determine the length of time, in milliseconds, to wait before timing out a request. You can increase
38 | # this value if you need to transfer large files, such as in Amazon S3 or Amazon CloudFront.
39 | requestTimeoutMs: 2000
40 | connectTimeoutMs: 2000
41 |
42 | # The maximum number of allowed connections to a single server for your HTTP communications. The default value is 25.
43 | # You can set this value as high as you can support the bandwidth. We recommend a value around 25.
44 | #maxConnections: 25
45 |
46 |
47 | # Use dual stack endpoint in the endpoint calculation. You must ensure that the service you want to use supports ipv6 in the region you select.
48 | #useDualStack: false
49 |
50 | # Enable adjustment for clock skew
51 | #enableClockSkewAdjustment: true
52 |
53 | # If set to true the http stack will follow redirect codes
54 | #followRedirects: false
55 |
56 | # Specifies whether to enable SSL certificate verification. If necessary, you can disable SSL certificate verification by setting verifySSL to false.
57 | #verifySSL: true
58 |
59 | # This is the storage resolution level for presenting metrics in CloudWatch.
60 | # Valid values are 1 and 60. Setting this to 1 specifies this metric as a
61 | # high-resolution metric, so that CloudWatch stores the metric with sub-minute
62 | # resolution down to one second. Setting this to 60 specifies this metric as a
63 | # regular-resolution metric, which CloudWatch stores at 1-minute resolution.
64 | # Currently, high resolution is available only for custom metrics. For more
65 | # information about high-resolution metrics, see http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html
66 | storage_resolution: 1
67 |
--------------------------------------------------------------------------------
/robot_ws/src/cloudwatch_robot/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | # Set minimum required version of cmake, project name and compile options
3 | ################################################################################
4 | cmake_minimum_required(VERSION 2.8.3)
5 | project(cloudwatch_robot)
6 |
7 | ################################################################################
8 | # Find catkin packages and libraries for catkin and system dependencies
9 | ################################################################################
10 | find_package(catkin REQUIRED COMPONENTS
11 | rospy
12 | std_msgs
13 | sensor_msgs
14 | geometry_msgs
15 | nav_msgs
16 | message_generation
17 | cloudwatch_metrics_collector
18 | cloudwatch_logger
19 | health_metric_collector
20 | turtlebot3_description # required to install turtlebot3 .rviz model
21 | turtlebot3_navigation # required to install navigation .rviz model
22 | )
23 |
24 | ################################################################################
25 | # Setup for python modules and scripts
26 | ################################################################################
27 | catkin_python_setup()
28 |
29 | ################################################################################
30 | # Declare ROS messages, services and actions
31 | ################################################################################
32 | #add_action_files(
33 | # FILES
34 | # Turtlebot3.action
35 | #)
36 |
37 | #generate_messages(
38 | # DEPENDENCIES
39 | # std_msgs
40 | # geometry_msgs
41 | # nav_msgs
42 | #)
43 |
44 | ################################################################################
45 | # Declare ROS dynamic reconfigure parameters
46 | ################################################################################
47 |
48 | ################################################################################
49 | # Declare catkin specific configuration to be passed to dependent projects
50 | ################################################################################
51 | catkin_package(
52 | DEPENDS
53 | rospy
54 | std_msgs
55 | geometry_msgs
56 | nav_msgs
57 | message_runtime
58 | cloudwatch_metrics_collector
59 | cloudwatch_logger
60 | health_metric_collector
61 | )
62 |
63 | ################################################################################
64 | # Build
65 | ################################################################################
66 | include_directories(
67 | include
68 | ${catkin_INCLUDE_DIRS}
69 | )
70 |
71 | ################################################################################
72 | # Install
73 | ################################################################################
74 | catkin_install_python(PROGRAMS
75 | nodes/rotate.py
76 | nodes/monitor_speed.py
77 | nodes/monitor_obstacle_distance.py
78 | nodes/monitor_distance_to_goal.py
79 | DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
80 | )
81 |
82 | install(DIRECTORY launch config
83 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
84 | )
85 |
86 | install(DIRECTORY deploymentScripts
87 | DESTINATION ${CATKIN_GLOBAL_SHARE_DESTINATION}
88 | )
89 |
90 | # Copy the rviz model for easier access in AWS RoboMaker RViz
91 | install(FILES ${turtlebot3_description_DIR}/../rviz/model.rviz
92 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz
93 | RENAME turtlebot3_model.rviz
94 | )
95 |
96 | # Copy the rviz model for easier access in AWS RoboMaker RViz
97 | install(FILES ${turtlebot3_navigation_DIR}/../rviz/turtlebot3_navigation.rviz
98 | DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/rviz
99 | RENAME turtlebot3_navigation.rviz
100 | )
101 |
102 | ################################################################################
103 | # Test
104 | ################################################################################
--------------------------------------------------------------------------------
/roboMakerSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "runConfigurations":[
3 | {
4 | "id":"CloudWatch_Cfg01",
5 | "name":"CloudWatch Robot",
6 | "type":"colcon build",
7 | "cfg":{
8 | "workingDir":"./CloudWatch/robot_ws",
9 | "cmdArgs":""
10 | }
11 | },
12 | {
13 | "id":"CloudWatch_Cfg02",
14 | "name":"CloudWatch Robot",
15 | "type":"colcon bundle",
16 | "cfg":{
17 | "workingDir":"./CloudWatch/robot_ws",
18 | "cmdArgs":""
19 | }
20 | },
21 | {
22 | "id":"CloudWatch_Cfg03",
23 | "name":"CloudWatch Simulation",
24 | "type":"colcon build",
25 | "cfg":{
26 | "workingDir":"./CloudWatch/simulation_ws",
27 | "cmdArgs":""
28 | }
29 | },
30 | {
31 | "id":"CloudWatch_Cfg04",
32 | "name":"CloudWatch Simulation",
33 | "type":"colcon bundle",
34 | "cfg":{
35 | "workingDir":"./CloudWatch/simulation_ws",
36 | "cmdArgs":""
37 | }
38 | },
39 | {
40 | "id":"CloudWatch_SimulationJob",
41 | "name":"CloudWatch Robot Monitoring",
42 | "type":"simulation",
43 | "cfg":{
44 | "robotApp":{
45 | "name":"RoboMakerCloudWatchRobot",
46 | "sourceBundleFile":"./CloudWatch/robot_ws/bundle/output.tar",
47 | "s3Bucket":"",
48 | "architecture":"X86_64",
49 | "launchConfig":{
50 | "packageName":"cloudwatch_robot",
51 | "launchFile":"await_commands.launch",
52 | "environmentVariables":{
53 | "TURTLEBOT3_MODEL":"waffle_pi"
54 | }
55 | },
56 | "robotSoftwareSuite":{
57 | "name":"ROS",
58 | "version":""
59 | }
60 | },
61 | "simulationApp":{
62 | "name":"RoboMakerCloudWatchSimulation",
63 | "sourceBundleFile":"./CloudWatch/simulation_ws/bundle/output.tar",
64 | "s3Bucket":"",
65 | "architecture":"X86_64",
66 | "launchConfig":{
67 | "packageName":"cloudwatch_simulation",
68 | "launchFile":"bookstore_turtlebot_navigation.launch",
69 | "environmentVariables":{
70 | "TURTLEBOT3_MODEL":"waffle_pi"
71 | }
72 | },
73 | "robotSoftwareSuite":{
74 | "name":"ROS",
75 | "version":""
76 | },
77 | "simulationSoftwareSuite":{
78 | "name":"Gazebo",
79 | "version":""
80 | },
81 | "renderingEngine":{
82 | "name":"OGRE",
83 | "version":"1.x"
84 | }
85 | },
86 | "simulation":{
87 | "outputLocation":"",
88 | "failureBehavior":"Fail",
89 | "maxJobDurationInSeconds":28800,
90 | "iamRole":"",
91 | "vpcConfig": {
92 | "assignPublicIp": true,
93 | "securityGroups": [ "" ],
94 | "subnets": [ "" ]
95 | }
96 | }
97 | }
98 | },
99 | {
100 | "id":"CloudWatch_wf1",
101 | "type":"workflow",
102 | "name":"CloudWatch - Build and Bundle All",
103 | "runCfgIds":[
104 | "CloudWatch_Cfg01",
105 | "CloudWatch_Cfg02",
106 | "CloudWatch_Cfg03",
107 | "CloudWatch_Cfg04"
108 | ]
109 | }
110 | ]
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/scripts/setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -ex
3 |
4 | while [[ "$#" -gt 0 ]]; do
5 | case $1 in
6 | --install-ros) ros_distro=$2; shift ;;
7 | esac
8 | shift
9 | done
10 |
11 | supported_ros_distros=("melodic")
12 |
13 | install_ros(){
14 | echo "Installing ROS $ros_distro"
15 | #Install ROS Prerequisites
16 | apt update
17 | apt-get install -y lsb-release gnupg2 curl && apt-get clean all
18 | rm -f "/etc/apt/sources.list.d/ros-latest.list"
19 | sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
20 | apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
21 | curl -sSL 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xC1CF6E31E6BADE8868B172B4F42ED6FBAB17C654' | apt-key add -
22 | apt update
23 |
24 | #Install ROS $ros_distro
25 | apt install -y ros-$ros_distro-desktop-full
26 | source /opt/ros/$ros_distro/setup.bash
27 | }
28 |
29 |
30 | setup_sample_app(){
31 | echo "Setting up sample application. Installing tools and dependencies."
32 | #setup key for colcon bundle
33 | apt-key adv --fetch-keys 'http://packages.osrfoundation.org/gazebo.key'
34 | apt update
35 | apt install -y python-rosdep git
36 | if [ ! -f "/etc/ros/rosdep/sources.list.d/20-default.list" ];
37 | then
38 | rosdep init
39 | fi
40 | rosdep update
41 |
42 | apt-get install -y python3-apt python3-pip python3-vcstool
43 | pip3 install -U setuptools colcon-common-extensions colcon-ros-bundle
44 |
45 | cd robot_ws
46 | vcs import < .rosinstall
47 | rosdep install --from-paths src --ignore-src -r -y
48 | cd ..
49 |
50 | cd simulation_ws
51 | vcs import < .rosinstall
52 | rosdep install --from-paths src --ignore-src -r -y
53 | # need to install pyparsing==2.0.2 at the end to make sure that it overwrites
54 | # pyparsing-3.0 to make sure colcon build works
55 | pip3 install -U pyparsing==2.0.2
56 | cd ..
57 | }
58 |
59 | if [ -d "/opt/ros" ];
60 | then
61 | echo "A ROS installation already exists in your environment."
62 | if [ ! -z "$ros_distro" ];
63 | then
64 | echo "Ignoring request to install $ros_distro because a ROS installation already exists in your environment."
65 | fi
66 |
67 | found_supported_ros=false
68 | #check if their ros installation(s) are supported
69 | for distro in $supported_ros_distros
70 | do
71 | if [ -d "/opt/ros/$distro" ]
72 | then
73 | source /opt/ros/$distro/setup.bash
74 | #save to verify installation below
75 | ros_distro=$distro
76 | found_supported_ros=true
77 | break
78 | fi
79 | done
80 |
81 | #if supported versions are not found
82 | if [ ! found_supported_ros ]
83 | then
84 | echo "ERROR: your installed ROS Distro(s) are not supported. Exiting."
85 | exit 1
86 | fi
87 |
88 | elif [ -z "$ros_distro" ];
89 | then
90 | echo "No ROS Installation was found and no ROS Distro was specified. Defaulting to installing ROS Melodic"
91 | ros_distro="melodic"
92 | install_ros
93 | source /opt/ros/$ros_distro/setup.bash
94 | elif [[ " ${supported_ros_distros[@]} " =~ " ${ros_distro} " ]]; #check if item in list
95 | then
96 | echo "No ROS Installation found. Installing $ros_distro"
97 | install_ros
98 | source /opt/ros/$ros_distro/setup.bash
99 | elif [[ ! " ${supported_ros_distros[@]} " =~ " ${ros_distro} " ]]; #check if item in list
100 | then
101 | echo "The selected ROS Distro $ros_distro is not supported. Exiting."
102 | exit 0
103 | fi
104 |
105 | #Verify Installation
106 | if [ $ROS_DISTRO != $ros_distro ];
107 | then
108 | echo "The ROS installation was unsuccessful, Sample Application setup cannot continue. Exiting."
109 | exit 1
110 | else
111 | echo "ROS Installation was successful, continuing with Sample Application setup."
112 | fi
113 |
114 |
115 | setup_sample_app
116 |
--------------------------------------------------------------------------------
/.github/workflows/ros1.yml:
--------------------------------------------------------------------------------
1 | name: build-and-bundle
2 | on:
3 | pull_request:
4 | push:
5 | branches:
6 | - ros1
7 | schedule:
8 | - cron: '0 */2 * * *' # runs every 2 hrs on a daily basis
9 |
10 | jobs:
11 | build_and_bundle_ros1:
12 | strategy:
13 | matrix:
14 | distro: ['melodic']
15 | gazebo: [9]
16 | include:
17 | - distro: melodic
18 | gazebo: 9
19 | ubuntu_distro: bionic
20 | runs-on: ubuntu-latest
21 | if: ${{ github.event_name != 'push' || github.ref != 'refs/heads/ros2' }}
22 | name: 'Build and Bundle (ROS1)'
23 | container:
24 | image: ubuntu:${{ matrix.ubuntu_distro }}
25 | outputs:
26 | robot_ws_build_result: ${{ steps.robot_ws_build.outcome }}
27 | simulation_ws_build_result: ${{ steps.simulation_ws_build.outcome }}
28 | steps:
29 | - name: Checkout Branch
30 | uses: actions/checkout@v1
31 | - name: Scan using git-secrets
32 | uses: aws-robotics/aws-robomaker-github-actions/git-secrets-scan-action@3.0.6
33 | - id: robot_ws_build
34 | name: Build and Bundle Robot Workspace
35 | uses: aws-robotics/aws-robomaker-github-actions/robomaker-sample-app-ci@3.0.8
36 | with:
37 | ros-distro: ${{ matrix.distro }}
38 | workspace-dir: robot_ws
39 | generate-sources: true
40 | retries: 3
41 | - id: simulation_ws_build
42 | name: Build and Bundle Simulation Workspace
43 | uses: aws-robotics/aws-robomaker-github-actions/robomaker-sample-app-ci@3.0.8
44 | with:
45 | ros-distro: ${{ matrix.distro }}
46 | workspace-dir: simulation_ws
47 | retries: 3
48 | - name: Configure AWS Credentials
49 | uses: aws-actions/configure-aws-credentials@v1.5.4
50 | with:
51 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_ROS1 }}
52 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_ROS1 }}
53 | aws-region: ${{ secrets.AWS_REGION }}
54 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }}
55 | - id: upload_bundle
56 | name: Upload bundle to S3
57 | uses: aws-robotics/aws-robomaker-github-actions/s3-cp-action@3.0.6
58 | env:
59 | AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET_ROS1 }}
60 | AWS_REGION: ${{ secrets.AWS_REGION }}
61 | FILES: 'sources.zip sources.tar.gz robot_ws.tar simulation_ws.tar'
62 | DEST: 'travis/cloudwatch/${{ matrix.distro }}/gazebo${{ matrix.gazebo }}/${{ steps.robot_ws_build.outputs.sample-app-version }}.${{ github.run_number }}/'
63 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }} # upload to S3 on "schedule" build if the build was successful
64 | - name: Get time stamp
65 | id: time
66 | run: echo "::set-output name=timestamp::$(date +%s)"
67 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }}
68 | - name: Update App-manifest version number
69 | id: update-app-manifest
70 | uses: aws-robotics/aws-robomaker-github-actions/codecommit-put-file-action@3.0.6
71 | env:
72 | AWS_CODECOMMIT_REPO_NAME: '${{ secrets.AWS_CODECOMMIT_REPO_NAME_PREFIX_CLOUDWATCH }}-${{ matrix.distro }}-gazebo${{ matrix.gazebo }}'
73 | AWS_CODECOMMIT_BRANCH_NAME: ${{ secrets.AWS_CODECOMMIT_BRANCH_NAME_CLOUDWATCH }}
74 | DEST_FILE_CONTENT: '{"application_version": "${{ steps.robot_ws_build.outputs.sample-app-version }}.${{ github.run_number }}", "timestamp":"${{ steps.time.outputs.timestamp }}"}'
75 | DEST_FILE_PATH: '/version.json'
76 | COMMIT_MSG: 'Updating to version ${{ steps.robot_ws_build.outputs.sample-app-version }}.${{ github.run_number }}. Commit for this version bump: ${{ github.sha }}.'
77 | USER_EMAIL: 'ros-contributions@amazon.com'
78 | USER_NAME: 'ros-contributions'
79 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }} # Update app-manifest version number if the build was successful
80 |
81 | log_workflow_status_to_cloudwatch:
82 | runs-on: ubuntu-latest
83 | container:
84 | image: ubuntu:bionic
85 | needs:
86 | - build_and_bundle_ros1
87 | if: ${{ always() && github.event_name != 'pull_request' }}
88 | steps:
89 | - name: Configure AWS Credentials
90 | uses: aws-actions/configure-aws-credentials@v1.5.4
91 | with:
92 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_ROS1 }}
93 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_ROS1 }}
94 | aws-region: ${{ secrets.AWS_REGION }}
95 | - name: Log Robot Workspace Build Status
96 | uses: ros-tooling/action-cloudwatch-metrics@0.0.4
97 | with:
98 | namespace: RobotWorkspaceBuild
99 | metric-value: ${{ contains(needs.build_and_bundle_ros1.outputs.robot_ws_build_result, 'success') }}
100 | - name: Log Simulation Workspace Build Status
101 | uses: ros-tooling/action-cloudwatch-metrics@0.0.4
102 | with:
103 | namespace: SimulationWorkspaceBuild
104 | metric-value: ${{ contains(needs.build_and_bundle_ros1.outputs.simulation_ws_build_result, 'success') }}
105 | - name: Log Bundle Upload Status
106 | uses: ros-tooling/action-cloudwatch-metrics@0.0.4
107 | with:
108 | namespace: BundleUpload
109 | metric-value: ${{ contains(needs.build_and_bundle_ros1.result, 'success') }}
110 | if: ${{ github.event_name == 'schedule' }}
111 |
--------------------------------------------------------------------------------
/simulation_ws/src/test_nodes/nodes/navigation_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import rospy
4 | import rostest
5 | import time
6 | import os
7 | import unittest
8 |
9 | from rosgraph_msgs.msg import Clock
10 | from ros_monitoring_msgs.msg import MetricList
11 | from robomaker_simulation_msgs.msg import Tag
12 | from robomaker_simulation_msgs.srv import Cancel, AddTags
13 |
14 | METRIC_NAME = "distance_to_goal"
15 |
16 |
17 | class NavigationTest(unittest.TestCase):
18 | """
19 | This test case will send a number of expected goals and monitor their status.
20 | If the robot reaches all of the destinations, it will mark the test as passed.
21 | """
22 |
23 | def cancel_job(self):
24 | rospy.wait_for_service("/robomaker/job/cancel")
25 | requestCancel = rospy.ServiceProxy("/robomaker/job/cancel", Cancel)
26 | response = requestCancel()
27 | if response.success:
28 | self.is_cancelled = True
29 | rospy.loginfo("Successfully requested cancel job")
30 | self.set_tag(
31 | name=self.test_name +
32 | "_Time_Elapsed_End",
33 | value=str(
34 | time.time()).split(
35 | ".",
36 | 1)[0])
37 | else:
38 | rospy.logerr("Cancel request failed: %s", response.message)
39 |
40 | def set_tag(self, name, value):
41 | rospy.wait_for_service("/robomaker/job/add_tags")
42 | requestAddTags = rospy.ServiceProxy("/robomaker/job/add_tags", AddTags)
43 | tags = ([Tag(key=name, value=value)])
44 | response = requestAddTags(tags)
45 | if response.success:
46 | rospy.loginfo("Successfully added tags: %s", tags)
47 | else:
48 | rospy.logerr(
49 | "Add tags request failed for tags (%s): %s",
50 | tags,
51 | response.message)
52 |
53 | def setUp(self):
54 | self.latch = False
55 | self.successful_navigations = 0
56 | self.test_name = "Robot_Monitoring_Tests_" + \
57 | str(time.time()).split(".", 1)[0]
58 | self.is_completed = False
59 | rospy.loginfo("Test Name: %s", self.test_name)
60 | self.navigation_success_count = rospy.get_param(
61 | 'NAVIGATION_SUCCESS_COUNT')
62 | self.timeout = rospy.get_param("SIM_TIMEOUT_SECONDS")
63 |
64 | def set_latched(self):
65 | self.latch = True
66 |
67 | def set_unlatched(self):
68 | self.latch = False
69 |
70 | def increment_navigations(self):
71 | self.successful_navigations = self.successful_navigations + 1
72 |
73 | def is_complete(self):
74 | return self.successful_navigations >= self.navigation_success_count
75 |
76 | def check_timeout(self, msg):
77 | """
78 | Cancel the test if it times out. The timeout is based on the
79 | /clock topic (simulation time).
80 | """
81 | if msg.clock.secs > self.timeout and not self.is_cancelled:
82 | rospy.loginfo("Test timed out, cancelling job")
83 | self.set_tag(name=self.test_name + "_Status", value="Failed")
84 | self.set_tag(
85 | name=self.test_name +
86 | "_Timed_Out",
87 | value=str(
88 | self.timeout))
89 | self.cancel_job()
90 |
91 | def check_complete(self, msgs):
92 | for msg in msgs.metrics:
93 | if msg.metric_name == METRIC_NAME:
94 | rospy.loginfo("Metric Name: %s", msg.metric_name)
95 | rospy.loginfo("Metric Value: %s", msg.value)
96 | """
97 | If our distance to goal metric drops below .5 and we've
98 | achieved our goal count then we are complete and we tag the
99 | job success and cancel. Else, we continue checking progress
100 | towards a new goal once the distance to goal climbs back
101 | above 1. Note that we're using what the nav stack thinks
102 | is the distance to goal, in the real world we'd want to use
103 | a ground truth value to ensure accuracy.
104 | """
105 | if msg.value <= .5 and self.is_completed == False and self.latch == False:
106 | self.set_latched()
107 | self.increment_navigations()
108 | self.set_tag(
109 | name=self.test_name + "_Successful_Nav_" + str(
110 | self.successful_navigations), value=str(
111 | self.successful_navigations))
112 | if self.is_complete():
113 | self.is_completed = True
114 | self.set_tag(
115 | name=self.test_name + "_Status", value="Passed")
116 | self.cancel_job()
117 | elif msg.value > 1 and self.is_completed == False:
118 | self.set_unlatched()
119 |
120 | def test_navigation(self):
121 | try:
122 | self.is_cancelled = False
123 | self.set_tag(
124 | name=self.test_name +
125 | "_Time_Elapsed_Start",
126 | value=str(
127 | time.time()).split(
128 | ".",
129 | 1)[0])
130 | rospy.Subscriber("/metrics", MetricList, self.check_complete)
131 | rospy.Subscriber("/clock", Clock, self.check_timeout)
132 | rospy.spin()
133 | except Exception as e:
134 | rospy.logerror("Error", e)
135 | self.set_tag(name=self.test_name, value="Failed")
136 | # We cancel the job here and let the service bring down the
137 | # simulation. We don't exit.
138 | self.cancel_job()
139 |
140 | def runTest(self):
141 | # Start the navigation test
142 | self.test_navigation()
143 |
144 |
145 | if __name__ == "__main__":
146 | rospy.init_node("navigation_test", log_level=rospy.INFO)
147 | rostest.rosrun("test_nodes", "navigation_test", NavigationTest)
148 |
--------------------------------------------------------------------------------
/.github/workflows/ros2.yml:
--------------------------------------------------------------------------------
1 | name: build-and-bundle
2 | on:
3 | pull_request:
4 | push:
5 | branches:
6 | - ros2
7 | schedule:
8 | - cron: '0 */2 * * *' # runs every 2 hrs on a daily basis
9 |
10 | jobs:
11 | build_and_bundle_ros2:
12 | strategy:
13 | matrix:
14 | distro: ['dashing']
15 | gazebo: [9]
16 | include:
17 | - distro: dashing
18 | gazebo: 9
19 | ubuntu_distro: bionic
20 | runs-on: ubuntu-latest
21 | if: ${{ github.event_name == 'schedule' || github.ref == 'refs/heads/ros2' }}
22 | name: 'Build and Bundle (ROS2)'
23 | container:
24 | image: rostooling/setup-ros-docker:ubuntu-${{ matrix.ubuntu_distro }}-ros-${{ matrix.distro }}-ros-base-latest
25 | outputs:
26 | robot_ws_build_result: ${{ steps.robot_ws_build.outcome }}
27 | simulation_ws_build_result: ${{ steps.simulation_ws_build.outcome }}
28 | steps:
29 | - name: Checkout Branch
30 | uses: actions/checkout@v1
31 | with:
32 | ref: 'ros2'
33 | - name: Setup Permissions
34 | run: |
35 | # TODO(ros-tooling/setup-ros-docker#7): calling chown is necessary for now
36 | sudo chown -R rosbuild:rosbuild "$HOME" .
37 | - name: Scan using git-secrets
38 | uses: aws-robotics/aws-robomaker-github-actions/git-secrets-scan-action@2.4.2
39 | - id: robot_ws_build
40 | name: Build and Bundle Robot Workspace
41 | uses: aws-robotics/aws-robomaker-github-actions/robomaker-sample-app-ci@2.4.2
42 | with:
43 | ros-distro: ${{ matrix.distro }}
44 | gazebo-version: ${{ matrix.gazebo }}
45 | workspace-dir: robot_ws
46 | generate-sources: true
47 | colcon-bundle-retries: 3
48 | - id: simulation_ws_build
49 | name: Build and Bundle Simulation Workspace
50 | uses: aws-robotics/aws-robomaker-github-actions/robomaker-sample-app-ci@2.4.2
51 | with:
52 | ros-distro: ${{ matrix.distro }}
53 | gazebo-version: ${{ matrix.gazebo }}
54 | workspace-dir: simulation_ws
55 | colcon-bundle-retries: 3
56 | - name: Configure AWS Credentials
57 | uses: aws-actions/configure-aws-credentials@v1.5.4
58 | with:
59 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_ROS2 }}
60 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_ROS2 }}
61 | aws-region: ${{ secrets.AWS_REGION }}
62 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }}
63 | - id: upload_bundle
64 | name: Upload bundle to S3
65 | uses: aws-robotics/aws-robomaker-github-actions/s3-cp-action@2.4.2
66 | env:
67 | AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET_ROS2 }}
68 | AWS_REGION: ${{ secrets.AWS_REGION }}
69 | FILES: 'sources.zip sources.tar.gz robot_ws.tar simulation_ws.tar'
70 | DEST: 'travis/cloudwatch/${{ steps.robot_ws_build.outputs.ros-distro }}/${{ steps.robot_ws_build.outputs.gazebo-version }}/${{ steps.robot_ws_build.outputs.sample-app-version }}.${{ github.run_number }}/'
71 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }} # upload to S3 on "schedule" build if the build was successful
72 | - name: Get time stamp
73 | id: time
74 | run: echo "::set-output name=timestamp::$(date +%s)"
75 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }}
76 | - name: Update App-manifest version number
77 | id: update-app-manifest
78 | uses: aws-robotics/aws-robomaker-github-actions/codecommit-put-file-action@2.4.2
79 | env:
80 | AWS_CODECOMMIT_REPO_NAME: '${{ secrets.AWS_CODECOMMIT_REPO_NAME_PREFIX_CLOUDWATCH }}-${{ matrix.distro }}-gazebo${{ matrix.gazebo }}'
81 | AWS_CODECOMMIT_BRANCH_NAME: ${{ secrets.AWS_CODECOMMIT_BRANCH_NAME_CLOUDWATCH }}
82 | DEST_FILE_CONTENT: '{"application_version": "${{ steps.robot_ws_build.outputs.sample-app-version }}.${{ github.run_number }}", "timestamp":"${{ steps.time.outputs.timestamp }}"}'
83 | DEST_FILE_PATH: '/version.json'
84 | COMMIT_MSG: 'Updating to version ${{ steps.robot_ws_build.outputs.sample-app-version }}.${{ github.run_number }}. Commit for this version bump: ${{ github.sha }}.'
85 | USER_EMAIL: 'ros-contributions@amazon.com'
86 | USER_NAME: 'ros-contributions'
87 | if: ${{ github.event_name == 'schedule' && contains(steps.robot_ws_build.outcome, 'success') && contains(steps.simulation_ws_build.outcome, 'success') }} # Update app-manifest version number if the build was successful
88 |
89 | log_workflow_status_to_cloudwatch:
90 | runs-on: ubuntu-latest
91 | container:
92 | image: ubuntu:bionic
93 | needs:
94 | - build_and_bundle_ros2
95 | if: ${{ always() && github.event_name != 'pull_request' }}
96 | steps:
97 | - name: Configure AWS Credentials
98 | uses: aws-actions/configure-aws-credentials@v1.5.4
99 | with:
100 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_ROS2 }}
101 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_ROS2 }}
102 | aws-region: ${{ secrets.AWS_REGION }}
103 | - name: Log Robot Workspace Build Status
104 | uses: ros-tooling/action-cloudwatch-metrics@0.0.4
105 | with:
106 | metric-dimensions: >-
107 | [
108 | { "Name": "github.event_name", "Value": "${{ github.event_name }}" },
109 | { "Name": "github.ref", "Value": "refs/heads/ros2" },
110 | { "Name": "github.repository", "Value": "${{ github.repository }}" }
111 | ]
112 | namespace: RobotWorkspaceBuild
113 | metric-value: ${{ contains(needs.build_and_bundle_ros2.outputs.robot_ws_build_result, 'success') }}
114 | - name: Log Simulation Workspace Build Status
115 | uses: ros-tooling/action-cloudwatch-metrics@0.0.4
116 | with:
117 | metric-dimensions: >-
118 | [
119 | { "Name": "github.event_name", "Value": "${{ github.event_name }}" },
120 | { "Name": "github.ref", "Value": "refs/heads/ros2" },
121 | { "Name": "github.repository", "Value": "${{ github.repository }}" }
122 | ]
123 | namespace: SimulationWorkspaceBuild
124 | metric-value: ${{ contains(needs.build_and_bundle_ros2.outputs.simulation_ws_build_result, 'success') }}
125 | - name: Log Bundle Upload Status
126 | uses: ros-tooling/action-cloudwatch-metrics@0.0.4
127 | with:
128 | metric-dimensions: >-
129 | [
130 | { "Name": "github.event_name", "Value": "${{ github.event_name }}" },
131 | { "Name": "github.ref", "Value": "refs/heads/ros2" },
132 | { "Name": "github.repository", "Value": "${{ github.repository }}" }
133 | ]
134 | namespace: BundleUpload
135 | metric-value: ${{ contains(needs.build_and_bundle_ros2.result, 'success') }}
136 | if: ${{ github.event_name == 'schedule' }}
137 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AWS RoboMaker Sample Application - CloudWatch Monitoring
2 |
3 | Monitor health and operational metrics for a fleet of robots in a simulated home using AWS CloudWatch Metrics and AWS CloudWatch Logs. Streamed metrics include speed, distance to nearest obstacle, distance to current goal, robot CPU utilization, and RAM usage.
4 |
5 | It demonstrates how to emit metrics and logs to AWS CloudWatch to monitor your robots.
6 |
7 | _RoboMaker sample applications include third-party software licensed under open-source licenses and is provided for demonstration purposes only. Incorporation or use of RoboMaker sample applications in connection with your production workloads or a commercial products or devices may affect your legal rights or obligations under the applicable open-source licenses. Source code information can be found [here](https://github.com/aws-robotics/aws-robomaker-sample-application-cloudwatch)._
8 |
9 |
10 | ## Installation
11 |
12 | The following will be installed
13 |
14 | - [Colcon](https://colcon.readthedocs.io/en/released/user/installation.html) - Used for building and bundling the application.
15 | - [vcstool](https://github.com/dirk-thomas/vcstool#how-to-install-vcstool) - Used to pull in sample app dependencies that are only available from source, not from apt or pip.
16 | - [rosdep](http://wiki.ros.org/rosdep#Installing_rosdep) - rosdep is a command-line tool for installing system dependencies of ROS packages.
17 |
18 | If ROS is detected, then ROS Installation will be skipped.
19 | - [ROS Melodic](http://wiki.ros.org/melodic/Installation/Ubuntu) - Other versions may work, however they have not been tested
20 |
21 | ## AWS Setup
22 |
23 | ### AWS Credentials
24 | You will need to create an AWS Account and configure the credentials to be able to communicate with AWS services. You may find [AWS Configuration and Credential Files](https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html) helpful.
25 |
26 | ### AWS Permissions
27 | To run this application you will need an IAM user with the following permissions:
28 | ```
29 | logs:PutLogEvents
30 | logs:DescribeLogGroups
31 | logs:DescribeLogStreams
32 | logs:CreateLogStream
33 | logs:CreateLogGroup
34 | ```
35 |
36 | You can find instructions for creating a new IAM Policy [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create.html#access_policies_create-start). In the JSON tab paste the following policy document:
37 |
38 | ```
39 | {
40 | "Version": "2012-10-17",
41 | "Statement": [
42 | {
43 | "Sid": "CloudWatchRobotRole",
44 | "Effect": "Allow",
45 | "Action": [
46 | "cloudwatch:PutMetricData",
47 | "logs:PutLogEvents",
48 | "logs:DescribeLogGroups",
49 | "logs:DescribeLogStreams",
50 | "logs:CreateLogStream",
51 | "logs:CreateLogGroup"
52 | ],
53 | "Resource": "*"
54 | }
55 | ]
56 | }
57 | ```
58 |
59 | ## Build
60 |
61 | ### Install requirements
62 | Follow links above for instructions on installing required software.
63 |
64 | - *Full Setup Including ROS Install*
65 | currently only melodic is supported, ROS Installation will be skipped if its already present.
66 |
67 | ```bash
68 | source scripts/setup.sh
69 | ```
70 |
71 | ### Robot
72 |
73 | ```bash
74 | cd robot_ws
75 | colcon build
76 | ```
77 |
78 | ### Simulation
79 |
80 | ```bash
81 | cd simulation_ws
82 | colcon build
83 | ```
84 |
85 | ## Run
86 |
87 | The `TURTLEBOT3_MODEL` environment variable must be set when running both robot and simulation application. Currently only `waffle_pi` is supported. Set it by
88 |
89 | ```bash
90 | export TURTLEBOT3_MODEL=waffle_pi
91 | ```
92 |
93 | Launch the application with the following commands:
94 |
95 | - *Running Robot Application on a Robot*
96 | ```bash
97 | source robot_ws/install/local_setup.sh
98 | roslaunch cloudwatch_robot deploy_rotate.launch
99 | ```
100 |
101 | - *Running Robot Application in a Simulation*
102 | ```bash
103 | source robot_ws/install/local_setup.sh
104 | roslaunch cloudwatch_robot [command]
105 | ```
106 | There are two robot launch commands:
107 | - `rotate.launch` - The robot starts rotating
108 | - `await_commands.launch` - The robot is idle waiting movement commands, use this for teleop and navigation
109 |
110 |
111 | - *Running Simulation Application*
112 | ```bash
113 | source simulation_ws/install/local_setup.sh
114 | roslaunch cloudwatch_simulation [command]
115 | ```
116 | There are three simulation launch commands for three different worlds:
117 | - `empty_world.launch` - Empty world with some balls surrounding the turtlebot at (0,0)
118 | - `bookstore_turtlebot_navigation.launch` - A retail space where the robot navigates to random goals
119 | - `small_house_turtlebot_navigation.launch` - A retail space where the robot navigates to random goals
120 |
121 | Alternatively, to run turtlebot navigation to follow dynamic goals,
122 | ```bash
123 | roslaunch cloudwatch_simulation [command] follow_route:=false dynamic_route:=true
124 | ```
125 |
126 | Note that when running robot applications on a robot, `use_sim_time` should be set to `false` (which is the default value in `deploy_rotate.launch` and `deploy_await_commands.launch`). When running robot applications along with simulation applications, `use_sim_time` should be set to `true` for both applications (which is the default value in `rotate.launch`, `await_commands.launch` and all the launch files in simulation workspace).
127 |
128 | When running simulation applications, run command with `gui:=true` to run gazebo client for visualization.
129 |
130 | For navigation, you can generate a map with map generation plugin. See [this](#generate-occupancy-map-via-map-generation-plugin) for instructions.
131 |
132 | 
133 |
134 | ### Run with a AWS Robomaker WorldForge world
135 |
136 | Pre-requisite: Generate a map for your worldforge exported world following these [instructions](#generate-map-for-a-worldforge-world-with-default-config).
137 |
138 | Build your workspace to reference the newly generated maps,
139 | ```bash
140 | cd simulation_ws
141 | colcon build
142 | ```
143 |
144 | Launch the navigation application with the following commands:
145 | ```bash
146 | export TURTLEBOT3_MODEL=waffle_pi
147 | source simulation_ws/install/local_setup.sh
148 | roslaunch cloudwatch_simulation worldforge_turtlebot_navigation.launch
149 | ```
150 |
151 | ### Monitoring with CloudWatch Logs
152 | Robot logs from ROS nodes are streamed into CloudWatch Logs to Log Group `robomaker_cloudwatch_monitoring_example`. See `cloudwatch_robot/config/cloudwatch_logs_config.yaml`.
153 |
154 | ### Monitoring with CloudWatch Metrics
155 | Robot metrics from ROS nodes are reported into CloudWatch Metrics `robomaker_cloudwatch_monitoring_example`. Metric resolution is configured at 10 seconds. See `cloudwatch_robot/config/cloudwatch_metrics_config.yaml`.
156 |
157 | Operational metrics include:
158 | - linear speed
159 | - angular speed
160 | - distance to nearest obstacle (closest lidar scan return)
161 | - distance to planned goal (bookstore only, requires its navigation system)
162 |
163 | Health metrics include CPU and RAM usage.
164 |
165 | 
166 |
167 | ## Using this sample with RoboMaker
168 |
169 | You first need to install colcon-ros-bundle. Python 3.5 or above is required.
170 |
171 | ```bash
172 | pip3 install colcon-ros-bundle
173 | ```
174 |
175 | After colcon-ros-bundle is installed you need to build your robot or simulation, then you can bundle with:
176 |
177 | ```bash
178 | # Bundling Robot Application
179 | cd robot_ws
180 | source install/local_setup.sh
181 | colcon bundle
182 |
183 | # Bundling Simulation Application
184 | cd simulation_ws
185 | source install/local_setup.sh
186 | colcon bundle
187 | ```
188 |
189 | This produces the artifacts `robot_ws/bundle/output.tar` and `simulation_ws/bundle/output.tar` respectively.
190 |
191 | You'll need to upload these to an s3 bucket, then you can use these files to
192 | [create a robot application](https://docs.aws.amazon.com/robomaker/latest/dg/create-robot-application.html),
193 | [create a simulation application](https://docs.aws.amazon.com/robomaker/latest/dg/create-simulation-application.html),
194 | and [create a simulation job](https://docs.aws.amazon.com/robomaker/latest/dg/create-simulation-job.html) in RoboMaker.
195 |
196 |
197 | ## Generate Occupancy Map via map generation plugin
198 |
199 | Procedurally generate an occupancy map for any gazebo world. This map can then be plugged in to navigate a robot in Worldforge worlds. For other aws-robotics worlds, this procedure is optional for the use-cases mentioned in this README.
200 |
201 |
202 | ### Generate map for a aws-robotics world with default config
203 |
204 | Currently, the following aws-robotics worlds are supported,
205 | - [`bookstore`](https://github.com/aws-robotics/aws-robomaker-bookstore-world)
206 | - [`small_house`](https://github.com/aws-robotics/aws-robomaker-small-house-world)
207 | - [`small_warehouse`](https://github.com/aws-robotics/aws-robomaker-small-warehouse-world)
208 | - [`no_roof_small_warehouse`](https://github.com/aws-robotics/aws-robomaker-small-warehouse-world)
209 |
210 |
211 | To generate a map, simply run
212 | ```bash
213 | ./scripts/genmap_script.sh
214 | ```
215 |
216 | where `` can be any value in the list above.
217 |
218 | ### Generate map for a WorldForge world with default config
219 |
220 | After exporting a world from WorldForge, unzip and move the contents under simulation_ws workspace
221 |
222 | ```bash
223 | unzip exported_world.zip
224 | mv aws_robomaker_worldforge_pkgs simulation_ws/src/
225 |
226 | #For worldforge worlds, set WORLD_ID to the name of your WF exported world (eg: generation_40r67s111n9x_world_3),
227 | export WORLD_ID=
228 |
229 | # Run map generation script
230 | ./scripts/genmap_script.sh worldforge
231 | ```
232 |
233 | ### Generate map for a custom world with custom config
234 |
235 | ```bash
236 | # Install dependencies (Ubuntu >18.04)
237 | sudo apt-get install ruby-dev libxml-xpath-perl libxml2-utils
238 | ```
239 |
240 | ```bash
241 | # Fetch and install ROS dependencies
242 | cd simulation_ws
243 | vcs import < .rosinstall
244 | rosdep install --from-paths src -r -y
245 | cd ..
246 | ```
247 |
248 | ```bash
249 | # Run plugin with custom world/config,
250 | python scripts/add_map_plugin.py custom -c -w -o
251 | ```
252 |
253 | ```bash
254 | # Build with plugin added
255 | cd simulation_ws
256 | colcon build
257 | source install/local_setup.sh
258 |
259 | # Start map service (for custom worlds, relocate your world file with the added plugin to src/cloudwatch_simulation/worlds/map_plugin.world before running this)
260 | roslaunch cloudwatch_simulation start_map_service.launch
261 |
262 | # Generate map (start in a different terminal AFTER you see "[INFO] [*] occupancy map plugin started" message in previous terminal)
263 | rosservice call /gazebo_2Dmap_plugin/generate_map
264 |
265 | # Save map
266 | rosrun map_server map_saver -f /map:=/map2d
267 | ```
268 |
269 | ```bash
270 | # Move the generated map file to cloudwatch_simulation simulation workspace map directory
271 | mv simulation_ws/src/cloudwatch_simulation/maps/map.yaml
272 | ```
273 |
274 | ## AWS ROS Packages used by this Sample
275 |
276 | - RoboMakerUtils-Common
277 | - RoboMakerUtils-ROS1
278 | - CloudWatch-Common
279 | - CloudWatchLogs-ROS1
280 | - CloudWatchMetrics-ROS1
281 | - HealthMetricsCollector-ROS1
282 | - MonitoringMessages-ROS1
283 |
284 | ## License
285 |
286 | MIT-0 - See LICENSE for further information
287 |
288 | ## How to Contribute
289 |
290 | Create issues and pull requests against this Repository on Github
291 |
--------------------------------------------------------------------------------
/simulation_ws/src/aws_robomaker_simulation_common/nodes/route_manager.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | import itertools
18 | from math import cos, sin
19 | import random
20 |
21 | import actionlib
22 | from geometry_msgs.msg import Point, Quaternion
23 | from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
24 | from nav_msgs.msg import MapMetaData, OccupancyGrid, Path
25 | import rospy
26 | import tf.transformations as transform
27 |
28 |
29 | class GoalGenerator():
30 | """
31 | Generate new goals for robot.
32 |
33 | - Description
34 | -------------
35 | Reads map data published on /map and /map_metadata topics
36 | and provides valid random goal poses in the map.
37 |
38 | Assumes that the map is held static after node
39 | initialisation and is not updated while the node is running.
40 | """
41 |
42 | def __init__(self):
43 | # Assuming map is static after node init and not updated while the node
44 | # is running. If not, this must be refreshed at regular intervals or on
45 | # some callbacks.
46 | self.meta_data = rospy.wait_for_message('map_metadata', MapMetaData)
47 | self.occupancy_data = rospy.wait_for_message('map', OccupancyGrid)
48 |
49 | # map.yaml only specifies x,y and yaw transforms of the origin wrt
50 | # world frame
51 | self.map_orientation = transform.euler_from_quaternion(
52 | [
53 | self.meta_data.origin.orientation.x,
54 | self.meta_data.origin.orientation.y,
55 | self.meta_data.origin.orientation.z,
56 | self.meta_data.origin.orientation.w])
57 | self.map_yaw = self.map_orientation[2] # (in radians)
58 | self.map_origin_x0 = self.meta_data.origin.position.x
59 | self.map_origin_y0 = self.meta_data.origin.position.y
60 | self.resolution = self.meta_data.resolution
61 |
62 | def ravel_index(self, x, y):
63 | """
64 | Ravel 2d grid coordinates in row-major order.
65 |
66 | Args
67 | ----
68 | x(int): in grid coordinates
69 | y(int): in grid coordinates
70 |
71 | Returns
72 | -------
73 | int
74 |
75 | """
76 | return y * (self.meta_data.width) + x
77 |
78 | def grid_to_world_2d(self, x, y):
79 | """
80 | Transform x-y planar grid coordinates to world coordinates.
81 |
82 | The function adheres to the assumption that
83 | grid-world transform is only x-y translation and yaw rotation.
84 |
85 | Args
86 | ----
87 | x(int): in grid coordinates
88 | x(int): in grid coordinates
89 |
90 | Returns
91 | -------
92 | List(int): in world coordinates
93 |
94 | """
95 | x_world = self.map_origin_x0 + \
96 | (cos(self.map_yaw) * (self.resolution * x)
97 | - sin(self.map_yaw) * (self.resolution * y))
98 | y_world = self.map_origin_y0 + \
99 | (sin(self.map_yaw) * (self.resolution * x) +
100 | cos(self.map_yaw) * (self.resolution * y))
101 |
102 | return [x_world, y_world]
103 |
104 | def _create_pos(
105 | self,
106 | x_world,
107 | y_world,
108 | z_world,
109 | euler_orientation_x,
110 | euler_orientation_y,
111 | euler_orientation_z):
112 | """
113 | Wrap 3D euler location and orientation input to a Pose.
114 |
115 | Args
116 | ----
117 | x(float): in world coordinates
118 | y(float): in world coordinates
119 | z(float): in world coordinates
120 | orientation_x(float): in world coordinates,
121 | orientation_y(float): in world coordinates
122 | orientation_z(float): in world coordinates
123 |
124 | Returns
125 | -------
126 | Pose:
127 | {
128 | 'position': {
129 | 'x': double
130 | 'y': double
131 | 'z': double
132 | }
133 | 'orientation': {
134 | 'x': double
135 | 'y': double
136 | 'z': double
137 | 'w': double
138 | }
139 | }
140 |
141 | """
142 | position = {
143 | 'x': x_world,
144 | 'y': y_world,
145 | 'z': z_world
146 | }
147 |
148 | # Make sure the quaternion is valid and normalized
149 | quaternion_orientation = transform.quaternion_from_euler(
150 | euler_orientation_x, euler_orientation_y, euler_orientation_z)
151 | orientation = {
152 | 'x': quaternion_orientation[0],
153 | 'y': quaternion_orientation[1],
154 | 'z': quaternion_orientation[2],
155 | 'w': quaternion_orientation[3]
156 | }
157 |
158 | p = {
159 | 'pose':
160 | {
161 | 'position': position,
162 | 'orientation': orientation
163 | }
164 | }
165 |
166 | return p
167 |
168 | def check_noise(self, x, y, row_id=None):
169 | """
170 | Check if the point in the world is not a map consistency.
171 |
172 | - Low resolution/ noisy sensor data might lead to
173 | noisy patches in the map.
174 | - This function checks if the random valid point is not a noisy
175 | bleap on the map by looking for its neighbor consistency.
176 |
177 | Args
178 | ----
179 | x (int): in grid coordinates
180 | y (int): in grid coordinates
181 |
182 | Returns
183 | -------
184 | bool. False if noise, else True
185 |
186 | """
187 | # to make it depend on resolution
188 | delta_x = max(2, self.meta_data.width // 50)
189 | delta_y = max(2, self.meta_data.height // 50)
190 |
191 | l_bound, r_bound = max(
192 | 0, x - delta_x), min(self.meta_data.width - 1, x + delta_x)
193 | t_bound, b_bound = max(
194 | 0, y - delta_y), min(self.meta_data.height - 1, y + delta_y)
195 |
196 | for _x in range(l_bound, r_bound):
197 | for _y in range(t_bound, b_bound):
198 | _row_id = self.ravel_index(_x, _y)
199 | if self.occupancy_data.data[_row_id] != 0:
200 | return False
201 |
202 | return True
203 |
204 | def get_next(self):
205 | """
206 | Get next goal.
207 |
208 | Scan the map for a valid goal.
209 | Convert to world coordinates and wraps as a Pose
210 | to be consumed by route manager.
211 |
212 | Args
213 | ----
214 |
215 | Returns
216 | -------
217 | Pose:
218 | {
219 | 'position': {
220 | 'x': double
221 | 'y': double
222 | 'z': double
223 | }
224 | 'orientation': {
225 | 'x': double
226 | 'y': double
227 | 'z': double
228 | 'w': double
229 | }
230 | }
231 |
232 | """
233 | z_world_floor = 0.
234 | euler_orientation = [0., 0., 0.]
235 |
236 | rospy.loginfo('Searching for a valid goal')
237 | timeout_iter = 100
238 | iteration = 0
239 | while iteration < timeout_iter:
240 | _x = random.randint(0, self.meta_data.width - 1)
241 | _y = random.randint(0, self.meta_data.height - 1)
242 | _row_id = self.ravel_index(_x, _y)
243 | if self.occupancy_data.data[_row_id] == 0 and self.check_noise(
244 | _x, _y, row_id=_row_id):
245 | x_world, y_world = self.grid_to_world_2d(_x, _y)
246 | rospy.loginfo('Valid goal found!')
247 | return self._create_pos(
248 | x_world, y_world, z_world_floor, *euler_orientation)
249 |
250 | rospy.logerr('Could not find a valid goal in the world. Check that \
251 | your occupancy map has Trinary value representation and is not \
252 | visually noisy/incorrect')
253 | return None
254 |
255 |
256 | class RouteManager():
257 | """
258 | Send goals to move_base server for the specified route. Routes forever.
259 |
260 | Loads the route from yaml.
261 | Use RViz to record 2D nav goals.
262 | Echo the input goal on topic /move_base_simple/goal
263 | """
264 |
265 | route_modes = {
266 | 'inorder': lambda goals: itertools.cycle(goals),
267 | 'random': lambda goals: (
268 | random.choice(goals) for i in itertools.count()),
269 | 'dynamic': lambda goals: GoalGenerator()}
270 |
271 | def __init__(self):
272 | self.route = []
273 |
274 | self.client = actionlib.SimpleActionClient('move_base', MoveBaseAction)
275 | self.client.wait_for_server()
276 |
277 | self.route_mode = rospy.get_param('~mode')
278 | if self.route_mode not in RouteManager.route_modes:
279 | rospy.logerr(
280 | 'Route mode %s unknown, exiting route manager',
281 | self.route_mode)
282 | return
283 |
284 | poses = rospy.get_param('~poses', [])
285 | if not poses and self.route_mode != 'dynamic':
286 | rospy.loginfo(
287 | 'Route manager initialized no goals, unable to route')
288 |
289 | self.goals = RouteManager.route_modes[self.route_mode](poses)
290 | rospy.loginfo('Route manager initialized in %s mode', self.route_mode)
291 |
292 | self.bad_goal_counter = 0
293 |
294 | def to_move_goal(self, pose):
295 | if pose is None:
296 | raise ValueError('Goal position cannot be NULL')
297 |
298 | goal = MoveBaseGoal()
299 | goal.target_pose.header.stamp = rospy.Time.now()
300 | goal.target_pose.header.frame_id = 'map'
301 | goal.target_pose.pose.position = Point(**pose['pose']['position'])
302 | goal.target_pose.pose.orientation = Quaternion(
303 | **pose['pose']['orientation'])
304 | return goal
305 |
306 | def route_forever(self):
307 | rate = rospy.Rate(1)
308 | while not rospy.is_shutdown():
309 | if self.bad_goal_counter > 10:
310 | rospy.loginfo(
311 | 'Stopping route manager due to too many bad goals.\
312 | Check that your occupancy map has Trinary value\
313 | representation and is not\
314 | visually noisy/incorrect'
315 | )
316 | return
317 | else:
318 | rospy.loginfo(
319 | 'Route mode is %s, getting next goal',
320 | self.route_mode)
321 | try:
322 | if self.route_mode == 'dynamic':
323 | # TODO: flake8 linting standard does not allow over-riding
324 | # the built-in python method next() which is required to
325 | # make 'self.goals' a iterator.
326 | current_goal = self.to_move_goal(self.goals.get_next())
327 | else:
328 | current_goal = self.to_move_goal(next(self.goals))
329 | except ValueError as e:
330 | rospy.loginfo(
331 | 'No valid goal was found in the map, stopping route manager\
332 | due to following exception,\n{0}'.format(str(e)))
333 | return
334 |
335 | rospy.loginfo('Sending target goal: %s', current_goal)
336 | self.client.send_goal(current_goal)
337 |
338 | try:
339 | # wait 5sec for global plan to be published. If not, scan
340 | # for a new goal..
341 | rospy.wait_for_message(
342 | '/move_base/DWAPlannerROS/global_plan',
343 | Path,
344 | timeout=5
345 | )
346 |
347 | if not self.client.wait_for_result():
348 | rospy.logerr(
349 | 'Move server not ready, will try again...')
350 | elif self.client.get_result():
351 | rospy.loginfo('Goal done: %s', current_goal)
352 |
353 | rate.sleep()
354 |
355 | except rospy.exceptions.ROSException:
356 | self.bad_goal_counter += 1
357 | rospy.logwarn(
358 | 'No plan found for goal. Scanning for a new goal...')
359 |
360 |
361 | def main():
362 | rospy.init_node('route_manager')
363 | try:
364 | route_manger = RouteManager()
365 | route_manger.route_forever()
366 | except rospy.ROSInterruptException:
367 | pass
368 |
369 |
370 | if __name__ == '__main__':
371 | main()
372 |
--------------------------------------------------------------------------------