remove navigation2/nav2_system_tests
This commit is contained in:
@@ -1,74 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(nav2_system_tests)
|
||||
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(nav2_common REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(std_msgs REQUIRED)
|
||||
find_package(nav2_util REQUIRED)
|
||||
find_package(nav2_map_server REQUIRED)
|
||||
find_package(nav2_behavior_tree REQUIRED)
|
||||
find_package(nav2_msgs REQUIRED)
|
||||
find_package(nav_msgs REQUIRED)
|
||||
find_package(visualization_msgs REQUIRED)
|
||||
find_package(geometry_msgs REQUIRED)
|
||||
find_package(std_msgs REQUIRED)
|
||||
find_package(tf2_geometry_msgs REQUIRED)
|
||||
find_package(gazebo_ros_pkgs REQUIRED)
|
||||
find_package(nav2_amcl REQUIRED)
|
||||
find_package(nav2_lifecycle_manager REQUIRED)
|
||||
find_package(rclpy REQUIRED)
|
||||
find_package(nav2_navfn_planner REQUIRED)
|
||||
find_package(nav2_planner REQUIRED)
|
||||
find_package(navigation2)
|
||||
find_package(angles REQUIRED)
|
||||
find_package(behaviortree_cpp_v3 REQUIRED)
|
||||
|
||||
nav2_package()
|
||||
|
||||
set(dependencies
|
||||
rclcpp
|
||||
nav2_util
|
||||
nav2_map_server
|
||||
nav2_msgs
|
||||
nav_msgs
|
||||
visualization_msgs
|
||||
nav2_amcl
|
||||
nav2_lifecycle_manager
|
||||
nav2_behavior_tree
|
||||
gazebo_ros_pkgs
|
||||
geometry_msgs
|
||||
std_msgs
|
||||
tf2_geometry_msgs
|
||||
rclpy
|
||||
nav2_planner
|
||||
nav2_navfn_planner
|
||||
angles
|
||||
behaviortree_cpp_v3
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
|
||||
find_package(ament_cmake_gtest REQUIRED)
|
||||
find_package(ament_cmake_pytest REQUIRED)
|
||||
|
||||
add_subdirectory(src/behavior_tree)
|
||||
add_subdirectory(src/planning)
|
||||
add_subdirectory(src/localization)
|
||||
add_subdirectory(src/system)
|
||||
add_subdirectory(src/system_failure)
|
||||
add_subdirectory(src/updown)
|
||||
add_subdirectory(src/waypoint_follower)
|
||||
add_subdirectory(src/behaviors/spin)
|
||||
add_subdirectory(src/behaviors/wait)
|
||||
add_subdirectory(src/behaviors/backup)
|
||||
add_subdirectory(src/behaviors/drive_on_heading)
|
||||
add_subdirectory(src/behaviors/assisted_teleop)
|
||||
add_subdirectory(src/costmap_filters)
|
||||
install(DIRECTORY maps DESTINATION share/${PROJECT_NAME})
|
||||
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
@@ -1,14 +0,0 @@
|
||||
# System Tests
|
||||
|
||||
The package provides tests for Component-Testing, Subsystem-Testing, and Full-System integration. Its main goal is to provide a location for smoke and integration tests of the navigation system to ensure that things are working properly on a high level. Unit and specific subsystem testing happens in the packages specific to those algorithms.
|
||||
|
||||
Most tests in this package will spin up Gazebo instances of a robot in an environment to have the robot complete some task in the space while tracking a specific modules results. Some examples include
|
||||
|
||||
- System tests of a robot in a sandbox environment trying navigate to pose, navigate through poses, and waypoint following navigation types
|
||||
- Random planning of thousands of paths in a generated environment to ensure default planners are working properly
|
||||
- Testing the system can be brought up and down on the lifecycle transitions successfully multiple times
|
||||
- Testing that the keepout and speed restricted zones work in a practical environment without going into keepout zones and slowing in speed restricted areas
|
||||
- Testing behaviors in a sandbox environment to ensure they trigger and complete collision checking properly
|
||||
- Testing system failures are properly recorded and can be recovered from
|
||||
|
||||
This is primarily for use in Nav2 CI to establish a high degree of maintainer confidence when merging in large architectural changes to the Nav2 project. However, this is also useful to test installs of Nav2 locally or for additional information.
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 310 B |
@@ -1,6 +0,0 @@
|
||||
image: empty.pgm
|
||||
resolution: 0.1
|
||||
origin: [-10.000000, -10.000000, 0.000000]
|
||||
negate: 0
|
||||
occupied_thresh: 0.65
|
||||
free_thresh: 0.196
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +0,0 @@
|
||||
image: keepout_mask.pgm
|
||||
resolution: 0.050000
|
||||
origin: [-10.000000, -10.000000, 0.000000]
|
||||
negate: 0
|
||||
occupied_thresh: 0.65
|
||||
free_thresh: 0.196
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1,8 +0,0 @@
|
||||
image: map_circular.pgm
|
||||
resolution: 0.050000
|
||||
origin: [-10.000000, -10.000000, 0.000000]
|
||||
negate: 0
|
||||
occupied_thresh: 0.65
|
||||
free_thresh: 0.196
|
||||
map_type: occupancy
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +0,0 @@
|
||||
image: speed_mask.pgm
|
||||
mode: scale
|
||||
resolution: 0.050000
|
||||
origin: [-10.000000, -10.000000, 0.000000]
|
||||
negate: 0
|
||||
occupied_thresh: 0.99
|
||||
free_thresh: 0.01
|
||||
@@ -1,38 +0,0 @@
|
||||
# Dynamic Obstacle
|
||||
|
||||
Dynamic Obstacle. 30x30x30 cm box.
|
||||
|
||||
Updates its velocity direction and amount every 3 seconds. Max velocity is 0.5.
|
||||
|
||||
## How to Configure a Dynamic Obstacle
|
||||
|
||||
dynamic_obstacle/model.sdf
|
||||
|
||||
<plugin name="random" filename="libRandomVelocityPlugin.so">
|
||||
|
||||
-- Name of the link in this model that receives the velocity
|
||||
<link>link</link>
|
||||
|
||||
-- Initial velocity that is applied to the link
|
||||
<initial_velocity>0 0.05 0</initial_velocity>
|
||||
|
||||
-- Scaling factor that is used to compute a new velocity
|
||||
<velocity_factor>0.5</velocity_factor>
|
||||
|
||||
-- Time delay between new velocities
|
||||
<update_period>3</update_period>
|
||||
|
||||
-- X velocity treshold values
|
||||
<min_x>-0.5</min_x>
|
||||
<max_x>0.5</max_x>
|
||||
|
||||
-- Y velocity treshold values
|
||||
<min_y>-0.5</min_y>
|
||||
<max_y>0.5</max_y>
|
||||
|
||||
-- Z velocity treshold values
|
||||
<min_z>-10</min_z>
|
||||
<max_z>-5</max_z>
|
||||
|
||||
</plugin>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<model>
|
||||
<name>DynamicObstacle</name>
|
||||
<version>1.0</version>
|
||||
<sdf version="1.6">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>Husnu Melih Erdogan</name>
|
||||
<email>h.meliherdogan@gmail.com</email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
Randomly moving obstacle.
|
||||
</description>
|
||||
</model>
|
||||
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<sdf version="1.6">
|
||||
<model name="DynamicObstacle">
|
||||
<pose>0 0 0.15 0 0 0</pose>
|
||||
<link name="link">
|
||||
<gravity>1</gravity>
|
||||
<inertial>
|
||||
<pose>0 0 0 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.17</ixx>
|
||||
<ixy>0.00</ixy>
|
||||
<ixz>0.00</ixz>
|
||||
<iyy>0.17</iyy>
|
||||
<iyz>0.00</iyz>
|
||||
<izz>0.17</izz>
|
||||
</inertia>
|
||||
<mass>10</mass>
|
||||
</inertial>
|
||||
<kinematic>false</kinematic>
|
||||
<collision name="collision">
|
||||
<max_contacts>10</max_contacts>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.3 0.3 0.3</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<surface>
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>0.0</mu>
|
||||
<mu2>0.0</mu2>
|
||||
</ode>
|
||||
</friction>
|
||||
<bounce>
|
||||
<restitution_coefficient>0.0</restitution_coefficient>
|
||||
<threshold>100000</threshold>
|
||||
</bounce>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kd>1</kd>
|
||||
<kp>2147483647</kp>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.0</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
<visual name="visual">
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.3 0.3 0.3</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
<plugin name="random" filename="libRandomVelocityPlugin.so">
|
||||
<link>link</link>
|
||||
<initial_velocity>0 0.05 0</initial_velocity>
|
||||
<velocity_factor>0.5</velocity_factor>
|
||||
<update_period>3</update_period>
|
||||
<min_x>-0.5</min_x>
|
||||
<max_x>0.5</max_x>
|
||||
<min_y>-0.5</min_y>
|
||||
<max_y>0.5</max_y>
|
||||
<min_z>-10</min_z>
|
||||
<max_z>-5</max_z>
|
||||
</plugin>
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -1,16 +0,0 @@
|
||||
# Dynamic World Model
|
||||
|
||||
A world model with a ground plane, 20x20 meter empty room, and 9 dynamic obstacles.
|
||||
|
||||
## How to Add a Dynamic Obstacle
|
||||
|
||||
dynamic_world/world.model
|
||||
|
||||
<model name="DynamicObstacle">
|
||||
-- Position of the new obstacle
|
||||
<pose>-4 4 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<sdf version="1.6">
|
||||
<world name="default">
|
||||
<include>
|
||||
<uri>model://sun</uri>
|
||||
</include>
|
||||
<include>
|
||||
<uri>model://ground_plane</uri>
|
||||
</include>
|
||||
|
||||
<model name="EmptyRoom">
|
||||
<include>
|
||||
<uri>model://empty_room</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle1">
|
||||
<pose>-4 4 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle2">
|
||||
<pose>-4 0 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle3">
|
||||
<pose>-4 -4 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle4">
|
||||
<pose>0 4 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle5">
|
||||
<pose>0 0 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle6">
|
||||
<pose>0 -4 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle7">
|
||||
<pose>4 4 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle8">
|
||||
<pose>4 0 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<model name="DynamicObstacle9">
|
||||
<pose>4 -4 0.15 0 0 0</pose>
|
||||
<include>
|
||||
<uri>model://dynamic_obstacle</uri>
|
||||
</include>
|
||||
</model>
|
||||
|
||||
<include>
|
||||
<pose>2.0 2.0 0.0 0.0 0.0 0.0</pose>
|
||||
<uri>model://turtlebot3_waffle</uri>
|
||||
</include>
|
||||
</world>
|
||||
</sdf>
|
||||
@@ -1,3 +0,0 @@
|
||||
# Empty Room
|
||||
|
||||
20x20 meter empty room.
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<model>
|
||||
<name>EmptyRoom</name>
|
||||
<version>1.0</version>
|
||||
<sdf version="1.6">model.sdf</sdf>
|
||||
<author>
|
||||
<name></name>
|
||||
<email></email>
|
||||
</author>
|
||||
<description></description>
|
||||
</model>
|
||||
@@ -1,164 +0,0 @@
|
||||
<?xml version='1.0'?>
|
||||
<sdf version='1.6'>
|
||||
<model name='EmptyRoom'>
|
||||
<static>1</static>
|
||||
<pose frame=''>0.0 0.0 0.0 0.0 0.0 0.0</pose>
|
||||
<link name='Wall_1'>
|
||||
<collision name='Wall_1_Collision'>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<max_contacts>1</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
</collision>
|
||||
<visual name='Wall_1_Visual'>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Grey</name>
|
||||
</script>
|
||||
<ambient>1 1 1 1</ambient>
|
||||
</material>
|
||||
<meta>
|
||||
<layer>0</layer>
|
||||
</meta>
|
||||
</visual>
|
||||
<pose frame=''>-4.925 0 0 0 -0 -1.5708</pose>
|
||||
</link>
|
||||
<link name='Wall_2'>
|
||||
<collision name='Wall_2_Collision'>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<max_contacts>1</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
</collision>
|
||||
<visual name='Wall_2_Visual'>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Grey</name>
|
||||
</script>
|
||||
<ambient>1 1 1 1</ambient>
|
||||
</material>
|
||||
<meta>
|
||||
<layer>0</layer>
|
||||
</meta>
|
||||
</visual>
|
||||
<pose frame=''>-0 -4.925 0 0 -0 0</pose>
|
||||
</link>
|
||||
<link name='Wall_3'>
|
||||
<collision name='Wall_3_Collision'>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<max_contacts>1</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
</collision>
|
||||
<visual name='Wall_3_Visual'>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Grey</name>
|
||||
</script>
|
||||
<ambient>1 1 1 1</ambient>
|
||||
</material>
|
||||
<meta>
|
||||
<layer>0</layer>
|
||||
</meta>
|
||||
</visual>
|
||||
<pose frame=''>4.925 0 0 0 -0 1.5708</pose>
|
||||
</link>
|
||||
<link name='Wall_4'>
|
||||
<collision name='Wall_4_Collision'>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<max_contacts>1</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
</collision>
|
||||
<visual name='Wall_4_Visual'>
|
||||
<pose frame=''>0 0 0.5 0 -0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>10 0.15 1</size>
|
||||
</box>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Grey</name>
|
||||
</script>
|
||||
<ambient>1 1 1 1</ambient>
|
||||
</material>
|
||||
<meta>
|
||||
<layer>0</layer>
|
||||
</meta>
|
||||
</visual>
|
||||
<pose frame=''>-0 4.925 0 0 -0 3.14159</pose>
|
||||
</link>
|
||||
<static>1</static>
|
||||
</model>
|
||||
</sdf>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,247 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<sdf version="1.4">
|
||||
<model name="turtlebot3_burger">
|
||||
|
||||
<link name="base">
|
||||
|
||||
<inertial>
|
||||
<pose>-0.032 0 0.070 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>1.0</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="base_collision">
|
||||
<pose>-0.032 0 0.070 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.140 0.140 0.140</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="base_visual">
|
||||
<pose>-0.032 0 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/burger_base.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
|
||||
<collision name="caster_collision">
|
||||
<pose>-0.081 0 -0.004 0 0 0</pose>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0</slip1>
|
||||
<slip2>0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="lidar">
|
||||
<inertial>
|
||||
<pose>-0.020 0 0.161 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.125</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="lidar_sensor_collision">
|
||||
<pose>-0.020 0 0.161 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.0508</radius>
|
||||
<length>0.055</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="lidar_sensor_visual">
|
||||
<pose>-0.032 0 0.171 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/lds.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
|
||||
<sensor name="hls_lfcd_lds" type="ray">
|
||||
<always_on>1</always_on>
|
||||
<visualize>0</visualize>
|
||||
<pose>-0.032 0 0.171 0 0 0</pose>
|
||||
<update_rate>1800</update_rate>
|
||||
<ray>
|
||||
<scan>
|
||||
<horizontal>
|
||||
<samples>360</samples>
|
||||
<resolution>1.000000</resolution>
|
||||
<min_angle>0.000000</min_angle>
|
||||
<max_angle>6.280000</max_angle>
|
||||
</horizontal>
|
||||
</scan>
|
||||
<range>
|
||||
<min>0.120000</min>
|
||||
<max>3.5</max>
|
||||
<resolution>0.015000</resolution>
|
||||
</range>
|
||||
<noise>
|
||||
<type>gaussian</type>
|
||||
<mean>0.0</mean>
|
||||
<stddev>0.01</stddev>
|
||||
</noise>
|
||||
</ray>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="left_wheel">
|
||||
|
||||
<inertial>
|
||||
<pose>0 0.08 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="left_wheel_collision">
|
||||
<pose>0 0.08 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="left_wheel_visual">
|
||||
<pose>0 0.08 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/left_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name="right_wheel">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 -0.08 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="right_wheel_collision">
|
||||
<pose>0.0 -0.08 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="right_wheel_visual">
|
||||
<pose>0.0 -0.08 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/right_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<joint name="left_wheel_joint" type="revolute">
|
||||
<parent>base</parent>
|
||||
<child>left_wheel</child>
|
||||
<pose>0.0 0.08 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 1 0</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="right_wheel_joint" type="revolute">
|
||||
<parent>base</parent>
|
||||
<child>right_wheel</child>
|
||||
<pose>0.0 -0.08 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 1 0</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="lidar_joint" type="fixed">
|
||||
<parent>base</parent>
|
||||
<child>lidar</child>
|
||||
<pose>-0.032 0 0.171 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
<use_parent_model_frame>true</use_parent_model_frame>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<model>
|
||||
<name>TurtleBot3(Burger)</name>
|
||||
<version>1.0</version>
|
||||
<sdf version="1.4">model-1_4.sdf</sdf>
|
||||
<sdf version="1.5">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>Taehun Lim(Darby)</name>
|
||||
<email>thlim@robotis.com</email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
TurtleBot3 Burger
|
||||
</description>
|
||||
</model>
|
||||
@@ -1,247 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<sdf version="1.5">
|
||||
<model name="turtlebot3_burger">
|
||||
|
||||
<link name="base">
|
||||
|
||||
<inertial>
|
||||
<pose>-0.032 0 0.070 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>1.0</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="base_collision">
|
||||
<pose>-0.032 0 0.070 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.140 0.140 0.140</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="base_visual">
|
||||
<pose>-0.032 0 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/burger_base.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
|
||||
<collision name="caster_collision">
|
||||
<pose>-0.081 0 -0.004 0 0 0</pose>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0</slip1>
|
||||
<slip2>0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="lidar">
|
||||
<inertial>
|
||||
<pose>-0.020 0 0.161 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.125</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="lidar_sensor_collision">
|
||||
<pose>-0.020 0 0.161 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.0508</radius>
|
||||
<length>0.055</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="lidar_sensor_visual">
|
||||
<pose>-0.032 0 0.171 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/lds.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
|
||||
<sensor name="hls_lfcd_lds" type="ray">
|
||||
<always_on>1</always_on>
|
||||
<visualize>0</visualize>
|
||||
<pose>-0.032 0 0.171 0 0 0</pose>
|
||||
<update_rate>1800</update_rate>
|
||||
<ray>
|
||||
<scan>
|
||||
<horizontal>
|
||||
<samples>360</samples>
|
||||
<resolution>1.000000</resolution>
|
||||
<min_angle>0.000000</min_angle>
|
||||
<max_angle>6.280000</max_angle>
|
||||
</horizontal>
|
||||
</scan>
|
||||
<range>
|
||||
<min>0.120000</min>
|
||||
<max>3.5</max>
|
||||
<resolution>0.015000</resolution>
|
||||
</range>
|
||||
<noise>
|
||||
<type>gaussian</type>
|
||||
<mean>0.0</mean>
|
||||
<stddev>0.01</stddev>
|
||||
</noise>
|
||||
</ray>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="left_wheel">
|
||||
|
||||
<inertial>
|
||||
<pose>0 0.08 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="left_wheel_collision">
|
||||
<pose>0 0.08 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="left_wheel_visual">
|
||||
<pose>0 0.08 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/left_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name="right_wheel">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 -0.08 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="right_wheel_collision">
|
||||
<pose>0.0 -0.08 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="right_wheel_visual">
|
||||
<pose>0.0 -0.08 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_burger/meshes/right_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<joint name="left_wheel_joint" type="revolute">
|
||||
<parent>base</parent>
|
||||
<child>left_wheel</child>
|
||||
<pose>0.0 0.08 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 1 0</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="right_wheel_joint" type="revolute">
|
||||
<parent>base</parent>
|
||||
<child>right_wheel</child>
|
||||
<pose>0.0 -0.08 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 1 0</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="lidar_joint" type="fixed">
|
||||
<parent>base</parent>
|
||||
<child>lidar</child>
|
||||
<pose>-0.032 0 0.171 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
<use_parent_model_frame>true</use_parent_model_frame>
|
||||
</axis>
|
||||
</joint>
|
||||
<static>0</static>
|
||||
</model>
|
||||
</sdf>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,521 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<sdf version="1.4">
|
||||
<model name="turtlebot3_waffle">
|
||||
<pose>0.0 0.0 0.0 0.0 0.0 0.0</pose>
|
||||
|
||||
<link name="base_footprint"/>
|
||||
|
||||
<link name="base_link">
|
||||
|
||||
<inertial>
|
||||
<pose>-0.064 0 0.048 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>1.0</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="base_collision">
|
||||
<pose>-0.064 0 0.048 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.265 0.265 0.089</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="base_visual">
|
||||
<pose>-0.064 0 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/waffle_base.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name="imu_link">
|
||||
<sensor name="tb3_imu" type="imu">
|
||||
<always_on>true</always_on>
|
||||
<update_rate>200</update_rate>
|
||||
<imu>
|
||||
<angular_velocity>
|
||||
<x>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</x>
|
||||
<y>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</y>
|
||||
<z>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</z>
|
||||
</angular_velocity>
|
||||
<linear_acceleration>
|
||||
<x>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</x>
|
||||
<y>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</y>
|
||||
<z>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</z>
|
||||
</linear_acceleration>
|
||||
</imu>
|
||||
<plugin name="turtlebot3_imu" filename="libgazebo_ros_imu_sensor.so">
|
||||
<initial_orientation_as_reference>false</initial_orientation_as_reference>
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=imu</remapping>
|
||||
</ros>
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="base_scan">
|
||||
<inertial>
|
||||
<pose>-0.052 0 0.111 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.125</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="lidar_sensor_collision">
|
||||
<pose>-0.052 0 0.111 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.0508</radius>
|
||||
<length>0.055</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="lidar_sensor_visual">
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/lds.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
|
||||
<sensor name="hls_lfcd_lds" type="ray">
|
||||
<always_on>true</always_on>
|
||||
<visualize>true</visualize>
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<update_rate>5</update_rate>
|
||||
<ray>
|
||||
<scan>
|
||||
<horizontal>
|
||||
<samples>360</samples>
|
||||
<resolution>1.000000</resolution>
|
||||
<min_angle>0.000000</min_angle>
|
||||
<max_angle>6.280000</max_angle>
|
||||
</horizontal>
|
||||
</scan>
|
||||
<range>
|
||||
<min>0.120000</min>
|
||||
<max>3.5</max>
|
||||
<resolution>0.015000</resolution>
|
||||
</range>
|
||||
<noise>
|
||||
<type>gaussian</type>
|
||||
<mean>0.0</mean>
|
||||
<stddev>0.01</stddev>
|
||||
</noise>
|
||||
</ray>
|
||||
<plugin name="turtlebot3_laserscan" filename="libgazebo_ros_ray_sensor.so">
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=scan</remapping>
|
||||
</ros>
|
||||
<output_type>sensor_msgs/LaserScan</output_type>
|
||||
<frame_name>base_scan</frame_name>
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="wheel_left_link">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="wheel_left_collision">
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="wheel_left_visual">
|
||||
<pose>0.0 0.144 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/left_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name="wheel_right_link">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="wheel_right_collision">
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="wheel_right_visual">
|
||||
<pose>0.0 -0.144 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/right_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name='caster_back_right_link'>
|
||||
<pose>-0.177 -0.064 -0.004 0 0 0</pose>
|
||||
<inertial>
|
||||
<mass>0.001</mass>
|
||||
<inertia>
|
||||
<ixx>0.00001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.00001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.00001</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
<collision name='collision'>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name='caster_back_left_link'>
|
||||
<pose>-0.177 0.064 -0.004 0 0 0</pose>
|
||||
<inertial>
|
||||
<mass>0.001</mass>
|
||||
<inertia>
|
||||
<ixx>0.00001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.00001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.00001</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
<collision name='collision'>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="camera_link"/>
|
||||
|
||||
<link name="camera_rgb_frame">
|
||||
<inertial>
|
||||
<pose>0.069 -0.047 0.107 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.035</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="collision">
|
||||
<pose>0 0 0.047 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.008 0.130 0.022</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
<pose>0.069 -0.047 0.107 0 0 0</pose>
|
||||
<sensor name="camera" type="camera">
|
||||
<always_on>true</always_on>
|
||||
<visualize>true</visualize>
|
||||
<update_rate>30</update_rate>
|
||||
<camera name="intel_realsense_r200">
|
||||
<horizontal_fov>1.02974</horizontal_fov>
|
||||
<image>
|
||||
<width>1920</width>
|
||||
<height>1080</height>
|
||||
<format>R8G8B8</format>
|
||||
</image>
|
||||
<clip>
|
||||
<near>0.02</near>
|
||||
<far>300</far>
|
||||
</clip>
|
||||
<noise>
|
||||
<type>gaussian</type>
|
||||
<!-- Noise is sampled independently per pixel on each frame.
|
||||
That pixel's noise value is added to each of its color
|
||||
channels, which at that point lie in the range [0,1]. -->
|
||||
<mean>0.0</mean>
|
||||
<stddev>0.007</stddev>
|
||||
</noise>
|
||||
</camera>
|
||||
<plugin name="camera_driver" filename="libgazebo_ros_camera.so">
|
||||
<ros>
|
||||
<!-- <namespace>test_cam</namespace> -->
|
||||
<!-- <remapping>image_raw:=image_demo</remapping> -->
|
||||
<!-- <remapping>camera_info:=camera_info_demo</remapping> -->
|
||||
</ros>
|
||||
<!-- camera_name>omit so it defaults to sensor name</camera_name-->
|
||||
<!-- frame_name>omit so it defaults to link name</frameName-->
|
||||
<!-- <hack_baseline>0.07</hack_baseline> -->
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<joint name="base_joint" type="fixed">
|
||||
<parent>base_footprint</parent>
|
||||
<child>base_link</child>
|
||||
<pose>0.0 0.0 0.010 0 0 0</pose>
|
||||
</joint>
|
||||
|
||||
<joint name="wheel_left_joint" type="revolute">
|
||||
<parent>base_link</parent>
|
||||
<child>wheel_left_link</child>
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="wheel_right_joint" type="revolute">
|
||||
<parent>base_link</parent>
|
||||
<child>wheel_right_link</child>
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name='caster_back_right_joint' type='ball'>
|
||||
<parent>base_link</parent>
|
||||
<child>caster_back_right_link</child>
|
||||
</joint>
|
||||
|
||||
<joint name='caster_back_left_joint' type='ball'>
|
||||
<parent>base_link</parent>
|
||||
<child>caster_back_left_link</child>
|
||||
</joint>
|
||||
|
||||
<joint name="lidar_joint" type="fixed">
|
||||
<parent>base_link</parent>
|
||||
<child>base_scan</child>
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="camera_joint" type="fixed">
|
||||
<parent>base_link</parent>
|
||||
<child>camera_link</child>
|
||||
<pose>0.064 -0.065 0.094 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="camera_rgb_joint" type="fixed">
|
||||
<parent>camera_link</parent>
|
||||
<child>camera_rgb_frame</child>
|
||||
<pose>0.005 0.018 0.013 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<plugin name="turtlebot3_diff_drive" filename="libgazebo_ros_diff_drive.so">
|
||||
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>/tf:=tf</remapping>
|
||||
</ros>
|
||||
|
||||
<update_rate>30</update_rate>
|
||||
|
||||
<!-- wheels -->
|
||||
<left_joint>wheel_left_joint</left_joint>
|
||||
<right_joint>wheel_right_joint</right_joint>
|
||||
|
||||
<!-- kinematics -->
|
||||
<wheel_separation>0.287</wheel_separation>
|
||||
<wheel_diameter>0.066</wheel_diameter>
|
||||
|
||||
<!-- limits -->
|
||||
<max_wheel_torque>20</max_wheel_torque>
|
||||
<max_wheel_acceleration>1.0</max_wheel_acceleration>
|
||||
|
||||
<command_topic>cmd_vel</command_topic>
|
||||
|
||||
<!-- output -->
|
||||
<publish_odom>true</publish_odom>
|
||||
<publish_odom_tf>true</publish_odom_tf>
|
||||
<publish_wheel_tf>false</publish_wheel_tf>
|
||||
|
||||
<odometry_topic>odom</odometry_topic>
|
||||
<odometry_frame>odom</odometry_frame>
|
||||
<robot_base_frame>base_footprint</robot_base_frame>
|
||||
|
||||
</plugin>
|
||||
|
||||
<plugin name="turtlebot3_joint_state" filename="libgazebo_ros_joint_state_publisher.so">
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=joint_states</remapping>
|
||||
</ros>
|
||||
<update_rate>30</update_rate>
|
||||
<joint_name>wheel_left_joint</joint_name>
|
||||
<joint_name>wheel_right_joint</joint_name>
|
||||
</plugin>
|
||||
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<model>
|
||||
<name>TurtleBot3(Waffle)</name>
|
||||
<version>2.0</version>
|
||||
<sdf version="1.4">model-1_4.sdf</sdf>
|
||||
<sdf version="1.5">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>Taehun Lim(Darby)</name>
|
||||
<email>thlim@robotis.com</email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
TurtleBot3 Waffle
|
||||
</description>
|
||||
</model>
|
||||
@@ -1,521 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<sdf version="1.5">
|
||||
<model name="turtlebot3_waffle">
|
||||
<pose>0.0 0.0 0.0 0.0 0.0 0.0</pose>
|
||||
|
||||
<link name="base_footprint"/>
|
||||
|
||||
<link name="base_link">
|
||||
|
||||
<inertial>
|
||||
<pose>-0.064 0 0.048 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>1.0</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="base_collision">
|
||||
<pose>-0.064 0 0.048 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.265 0.265 0.089</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="base_visual">
|
||||
<pose>-0.064 0 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/waffle_base.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name="imu_link">
|
||||
<sensor name="tb3_imu" type="imu">
|
||||
<always_on>true</always_on>
|
||||
<update_rate>200</update_rate>
|
||||
<imu>
|
||||
<angular_velocity>
|
||||
<x>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</x>
|
||||
<y>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</y>
|
||||
<z>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</z>
|
||||
</angular_velocity>
|
||||
<linear_acceleration>
|
||||
<x>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</x>
|
||||
<y>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</y>
|
||||
<z>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</z>
|
||||
</linear_acceleration>
|
||||
</imu>
|
||||
<plugin name="turtlebot3_imu" filename="libgazebo_ros_imu_sensor.so">
|
||||
<initial_orientation_as_reference>false</initial_orientation_as_reference>
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=imu</remapping>
|
||||
</ros>
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="base_scan">
|
||||
<inertial>
|
||||
<pose>-0.052 0 0.111 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.125</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="lidar_sensor_collision">
|
||||
<pose>-0.052 0 0.111 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.0508</radius>
|
||||
<length>0.055</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<visual name="lidar_sensor_visual">
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/lds.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
|
||||
<sensor name="hls_lfcd_lds" type="ray">
|
||||
<always_on>true</always_on>
|
||||
<visualize>true</visualize>
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<update_rate>5</update_rate>
|
||||
<ray>
|
||||
<scan>
|
||||
<horizontal>
|
||||
<samples>360</samples>
|
||||
<resolution>1.000000</resolution>
|
||||
<min_angle>0.000000</min_angle>
|
||||
<max_angle>6.280000</max_angle>
|
||||
</horizontal>
|
||||
</scan>
|
||||
<range>
|
||||
<min>0.120000</min>
|
||||
<max>3.5</max>
|
||||
<resolution>0.015000</resolution>
|
||||
</range>
|
||||
<noise>
|
||||
<type>gaussian</type>
|
||||
<mean>0.0</mean>
|
||||
<stddev>0.01</stddev>
|
||||
</noise>
|
||||
</ray>
|
||||
<plugin name="turtlebot3_laserscan" filename="libgazebo_ros_ray_sensor.so">
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=scan</remapping>
|
||||
</ros>
|
||||
<output_type>sensor_msgs/LaserScan</output_type>
|
||||
<frame_name>base_scan</frame_name>
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="wheel_left_link">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="wheel_left_collision">
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="wheel_left_visual">
|
||||
<pose>0.0 0.144 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/left_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name="wheel_right_link">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="wheel_right_collision">
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name="wheel_right_visual">
|
||||
<pose>0.0 -0.144 0.023 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_waffle/meshes/right_tire.dae</uri>
|
||||
<scale>0.001 0.001 0.001</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</visual>
|
||||
</link>
|
||||
|
||||
<link name='caster_back_right_link'>
|
||||
<pose>-0.177 -0.064 -0.004 0 0 0</pose>
|
||||
<inertial>
|
||||
<mass>0.001</mass>
|
||||
<inertia>
|
||||
<ixx>0.00001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.00001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.00001</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
<collision name='collision'>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name='caster_back_left_link'>
|
||||
<pose>-0.177 0.064 -0.004 0 0 0</pose>
|
||||
<inertial>
|
||||
<mass>0.001</mass>
|
||||
<inertia>
|
||||
<ixx>0.00001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.00001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.00001</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
<collision name='collision'>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="camera_link"/>
|
||||
|
||||
<link name="camera_rgb_frame">
|
||||
<inertial>
|
||||
<pose>0.069 -0.047 0.107 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.035</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="collision">
|
||||
<pose>0 0.047 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.008 0.130 0.022</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
<pose>0.069 -0.047 0.107 0 0 0</pose>
|
||||
<sensor name="camera" type="camera">
|
||||
<always_on>true</always_on>
|
||||
<visualize>true</visualize>
|
||||
<update_rate>30</update_rate>
|
||||
<camera name="intel_realsense_r200">
|
||||
<horizontal_fov>1.02974</horizontal_fov>
|
||||
<image>
|
||||
<width>1920</width>
|
||||
<height>1080</height>
|
||||
<format>R8G8B8</format>
|
||||
</image>
|
||||
<clip>
|
||||
<near>0.02</near>
|
||||
<far>300</far>
|
||||
</clip>
|
||||
<noise>
|
||||
<type>gaussian</type>
|
||||
<!-- Noise is sampled independently per pixel on each frame.
|
||||
That pixel's noise value is added to each of its color
|
||||
channels, which at that point lie in the range [0,1]. -->
|
||||
<mean>0.0</mean>
|
||||
<stddev>0.007</stddev>
|
||||
</noise>
|
||||
</camera>
|
||||
<plugin name="camera_driver" filename="libgazebo_ros_camera.so">
|
||||
<ros>
|
||||
<!-- <namespace>test_cam</namespace> -->
|
||||
<!-- <remapping>image_raw:=image_demo</remapping> -->
|
||||
<!-- <remapping>camera_info:=camera_info_demo</remapping> -->
|
||||
</ros>
|
||||
<!-- camera_name>omit so it defaults to sensor name</camera_name-->
|
||||
<!-- frame_name>omit so it defaults to link name</frameName-->
|
||||
<!-- <hack_baseline>0.07</hack_baseline> -->
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<joint name="base_joint" type="fixed">
|
||||
<parent>base_footprint</parent>
|
||||
<child>base_link</child>
|
||||
<pose>0.0 0.0 0.010 0 0 0</pose>
|
||||
</joint>
|
||||
|
||||
<joint name="wheel_left_joint" type="revolute">
|
||||
<parent>base_link</parent>
|
||||
<child>wheel_left_link</child>
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="wheel_right_joint" type="revolute">
|
||||
<parent>base_link</parent>
|
||||
<child>wheel_right_link</child>
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name='caster_back_right_joint' type='ball'>
|
||||
<parent>base_link</parent>
|
||||
<child>caster_back_right_link</child>
|
||||
</joint>
|
||||
|
||||
<joint name='caster_back_left_joint' type='ball'>
|
||||
<parent>base_link</parent>
|
||||
<child>caster_back_left_link</child>
|
||||
</joint>
|
||||
|
||||
<joint name="lidar_joint" type="fixed">
|
||||
<parent>base_link</parent>
|
||||
<child>base_scan</child>
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="camera_joint" type="fixed">
|
||||
<parent>base_link</parent>
|
||||
<child>camera_link</child>
|
||||
<pose>0.064 -0.065 0.094 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="camera_rgb_joint" type="fixed">
|
||||
<parent>camera_link</parent>
|
||||
<child>camera_rgb_frame</child>
|
||||
<pose>0.005 0.018 0.013 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<plugin name="turtlebot3_diff_drive" filename="libgazebo_ros_diff_drive.so">
|
||||
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>/tf:=tf</remapping>
|
||||
</ros>
|
||||
|
||||
<update_rate>30</update_rate>
|
||||
|
||||
<!-- wheels -->
|
||||
<left_joint>wheel_left_joint</left_joint>
|
||||
<right_joint>wheel_right_joint</right_joint>
|
||||
|
||||
<!-- kinematics -->
|
||||
<wheel_separation>0.287</wheel_separation>
|
||||
<wheel_diameter>0.066</wheel_diameter>
|
||||
|
||||
<!-- limits -->
|
||||
<max_wheel_torque>20</max_wheel_torque>
|
||||
<max_wheel_acceleration>1.0</max_wheel_acceleration>
|
||||
|
||||
<command_topic>cmd_vel</command_topic>
|
||||
|
||||
<!-- output -->
|
||||
<publish_odom>true</publish_odom>
|
||||
<publish_odom_tf>true</publish_odom_tf>
|
||||
<publish_wheel_tf>false</publish_wheel_tf>
|
||||
|
||||
<odometry_topic>odom</odometry_topic>
|
||||
<odometry_frame>odom</odometry_frame>
|
||||
<robot_base_frame>base_footprint</robot_base_frame>
|
||||
|
||||
</plugin>
|
||||
|
||||
<plugin name="turtlebot3_joint_state" filename="libgazebo_ros_joint_state_publisher.so">
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=joint_states</remapping>
|
||||
</ros>
|
||||
<update_rate>30</update_rate>
|
||||
<joint_name>wheel_left_joint</joint_name>
|
||||
<joint_name>wheel_right_joint</joint_name>
|
||||
</plugin>
|
||||
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<model>
|
||||
<name>TurtleBot3_Waffle_DepthCamera</name>
|
||||
<version>2.0</version>
|
||||
<sdf version="1.5">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>Taehun Lim(Darby)</name>
|
||||
<email>thlim@robotis.com</email>
|
||||
|
||||
<name>Melih Erdogan(mlherd)</name>
|
||||
<email>h.meliherdogan@gmail.com</email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
TurtleBot3 Waffle with Depth Camera
|
||||
</description>
|
||||
</model>
|
||||
@@ -1,454 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<sdf version="1.5">
|
||||
<model name="TurtleBot3_Waffle_DepthCamera">
|
||||
<pose>0.0 0.0 0.0 0.0 0.0 0.0</pose>
|
||||
|
||||
<link name="base_footprint"/>
|
||||
|
||||
<link name="base_link">
|
||||
|
||||
<inertial>
|
||||
<pose>-0.064 0 0.048 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>1.0</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="base_collision">
|
||||
<pose>-0.064 0 0.048 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.265 0.265 0.089</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="imu_link">
|
||||
<sensor name="tb3_imu" type="imu">
|
||||
<always_on>true</always_on>
|
||||
<update_rate>200</update_rate>
|
||||
<imu>
|
||||
<angular_velocity>
|
||||
<x>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</x>
|
||||
<y>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</y>
|
||||
<z>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>2e-4</stddev>
|
||||
</noise>
|
||||
</z>
|
||||
</angular_velocity>
|
||||
<linear_acceleration>
|
||||
<x>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</x>
|
||||
<y>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</y>
|
||||
<z>
|
||||
<noise type="gaussian">
|
||||
<mean>0.0</mean>
|
||||
<stddev>1.7e-2</stddev>
|
||||
</noise>
|
||||
</z>
|
||||
</linear_acceleration>
|
||||
</imu>
|
||||
<plugin name="turtlebot3_imu" filename="libgazebo_ros_imu_sensor.so">
|
||||
<initial_orientation_as_reference>false</initial_orientation_as_reference>
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=imu</remapping>
|
||||
</ros>
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="base_scan">
|
||||
<inertial>
|
||||
<pose>-0.052 0 0.111 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.125</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="lidar_sensor_collision">
|
||||
<pose>-0.052 0 0.111 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.0508</radius>
|
||||
<length>0.055</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
</collision>
|
||||
|
||||
<sensor name="hls_lfcd_lds" type="ray">
|
||||
<always_on>true</always_on>
|
||||
<visualize>true</visualize>
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<update_rate>5</update_rate>
|
||||
<ray>
|
||||
<scan>
|
||||
<horizontal>
|
||||
<samples>360</samples>
|
||||
<resolution>1.000000</resolution>
|
||||
<min_angle>0.000000</min_angle>
|
||||
<max_angle>6.280000</max_angle>
|
||||
</horizontal>
|
||||
</scan>
|
||||
<range>
|
||||
<min>0.120000</min>
|
||||
<max>3.5</max>
|
||||
<resolution>0.015000</resolution>
|
||||
</range>
|
||||
<noise>
|
||||
<type>gaussian</type>
|
||||
<mean>0.0</mean>
|
||||
<stddev>0.01</stddev>
|
||||
</noise>
|
||||
</ray>
|
||||
<plugin name="turtlebot3_laserscan" filename="libgazebo_ros_ray_sensor.so">
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=scan</remapping>
|
||||
</ros>
|
||||
<output_type>sensor_msgs/LaserScan</output_type>
|
||||
<frame_name>base_scan</frame_name>
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<link name="wheel_left_link">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="wheel_left_collision">
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="wheel_right_link">
|
||||
|
||||
<inertial>
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.1</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="wheel_right_collision">
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.033</radius>
|
||||
<length>0.018</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<surface>
|
||||
<!-- This friction pamareter don't contain reliable data!! -->
|
||||
<friction>
|
||||
<ode>
|
||||
<mu>100000.0</mu>
|
||||
<mu2>100000.0</mu2>
|
||||
<fdir1>0 0 0</fdir1>
|
||||
<slip1>0.0</slip1>
|
||||
<slip2>0.0</slip2>
|
||||
</ode>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name='caster_back_right_link'>
|
||||
<pose>-0.177 -0.064 -0.004 0 0 0</pose>
|
||||
<inertial>
|
||||
<mass>0.001</mass>
|
||||
<inertia>
|
||||
<ixx>0.00001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.00001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.00001</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
<collision name='collision'>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name='caster_back_left_link'>
|
||||
<pose>-0.177 0.064 -0.004 0 0 0</pose>
|
||||
<inertial>
|
||||
<mass>0.001</mass>
|
||||
<inertia>
|
||||
<ixx>0.00001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.00001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.00001</izz>
|
||||
</inertia>
|
||||
</inertial>
|
||||
<collision name='collision'>
|
||||
<geometry>
|
||||
<sphere>
|
||||
<radius>0.005000</radius>
|
||||
</sphere>
|
||||
</geometry>
|
||||
<surface>
|
||||
<contact>
|
||||
<ode>
|
||||
<soft_cfm>0</soft_cfm>
|
||||
<soft_erp>0.2</soft_erp>
|
||||
<kp>1e+5</kp>
|
||||
<kd>1</kd>
|
||||
<max_vel>0.01</max_vel>
|
||||
<min_depth>0.001</min_depth>
|
||||
</ode>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
</link>
|
||||
|
||||
<link name="camera_link">
|
||||
<inertial>
|
||||
<pose>0.069 -0.047 0.107 0 0 0</pose>
|
||||
<inertia>
|
||||
<ixx>0.001</ixx>
|
||||
<ixy>0.000</ixy>
|
||||
<ixz>0.000</ixz>
|
||||
<iyy>0.001</iyy>
|
||||
<iyz>0.000</iyz>
|
||||
<izz>0.001</izz>
|
||||
</inertia>
|
||||
<mass>0.035</mass>
|
||||
</inertial>
|
||||
|
||||
<collision name="collision">
|
||||
<pose>0 0.047 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<box>
|
||||
<size>0.008 0.130 0.022</size>
|
||||
</box>
|
||||
</geometry>
|
||||
</collision>
|
||||
<pose>0.069 -0.047 0.107 0 0 0</pose>
|
||||
|
||||
<sensor name="intel_realsense_r200_depth" type="depth">
|
||||
<always_on>1</always_on>
|
||||
<update_rate>15</update_rate>
|
||||
<pose>0.064 -0.047 0.107 0 0 0</pose>
|
||||
<camera name="realsense_depth_camera">
|
||||
</camera>
|
||||
<plugin name="intel_realsense_r200_depth_driver" filename="libgazebo_ros_camera.so">
|
||||
<ros>
|
||||
<!--
|
||||
<remapping>custom_camera/image_raw:=custom_camera/custom_image</remapping>
|
||||
<remapping>custom_camera/image_depth:=custom_camera/custom_image_depth</remapping>
|
||||
<remapping>custom_camera/camera_info:=custom_camera/custom_info_raw</remapping>
|
||||
<remapping>custom_camera/camera_info_depth:=custom_camera/custom_info_depth</remapping>
|
||||
<remapping>custom_camera/points:=custom_camera/custom_points</remapping>
|
||||
-->
|
||||
</ros>
|
||||
<camera_name>intel_realsense_r200_depth</camera_name>
|
||||
<frame_name>camera_depth_frame</frame_name>
|
||||
<hack_baseline>0.07</hack_baseline>
|
||||
<min_depth>0.001</min_depth>
|
||||
</plugin>
|
||||
</sensor>
|
||||
</link>
|
||||
|
||||
<joint name="base_joint" type="fixed">
|
||||
<parent>base_footprint</parent>
|
||||
<child>base_link</child>
|
||||
<pose>0.0 0.0 0.010 0 0 0</pose>
|
||||
</joint>
|
||||
|
||||
<joint name="wheel_left_joint" type="revolute">
|
||||
<parent>base_link</parent>
|
||||
<child>wheel_left_link</child>
|
||||
<pose>0.0 0.144 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="wheel_right_joint" type="revolute">
|
||||
<parent>base_link</parent>
|
||||
<child>wheel_right_link</child>
|
||||
<pose>0.0 -0.144 0.023 -1.57 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name='caster_back_right_joint' type='ball'>
|
||||
<parent>base_link</parent>
|
||||
<child>caster_back_right_link</child>
|
||||
</joint>
|
||||
|
||||
<joint name='caster_back_left_joint' type='ball'>
|
||||
<parent>base_link</parent>
|
||||
<child>caster_back_left_link</child>
|
||||
</joint>
|
||||
|
||||
<joint name="lidar_joint" type="fixed">
|
||||
<parent>base_link</parent>
|
||||
<child>base_scan</child>
|
||||
<pose>-0.064 0 0.121 0 0 0</pose>
|
||||
<axis>
|
||||
<xyz>0 0 1</xyz>
|
||||
</axis>
|
||||
</joint>
|
||||
|
||||
<joint name="camera_joint" type="fixed">
|
||||
<parent>base_link</parent>
|
||||
<child>camera_link</child>
|
||||
</joint>
|
||||
|
||||
<plugin name="turtlebot3_diff_drive" filename="libgazebo_ros_diff_drive.so">
|
||||
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>/tf:=tf</remapping>
|
||||
</ros>
|
||||
|
||||
<update_rate>30</update_rate>
|
||||
|
||||
<!-- wheels -->
|
||||
<left_joint>wheel_left_joint</left_joint>
|
||||
<right_joint>wheel_right_joint</right_joint>
|
||||
|
||||
<!-- kinematics -->
|
||||
<wheel_separation>0.287</wheel_separation>
|
||||
<wheel_diameter>0.066</wheel_diameter>
|
||||
|
||||
<!-- limits -->
|
||||
<max_wheel_torque>20</max_wheel_torque>
|
||||
<max_wheel_acceleration>1.0</max_wheel_acceleration>
|
||||
|
||||
<command_topic>cmd_vel</command_topic>
|
||||
|
||||
<!-- output -->
|
||||
<publish_odom>true</publish_odom>
|
||||
<publish_odom_tf>true</publish_odom_tf>
|
||||
<publish_wheel_tf>false</publish_wheel_tf>
|
||||
|
||||
<odometry_topic>odom</odometry_topic>
|
||||
<odometry_frame>odom</odometry_frame>
|
||||
<robot_base_frame>base_footprint</robot_base_frame>
|
||||
|
||||
</plugin>
|
||||
|
||||
<plugin name="turtlebot3_joint_state" filename="libgazebo_ros_joint_state_publisher.so">
|
||||
<ros>
|
||||
<!-- <namespace>/tb3</namespace> -->
|
||||
<remapping>~/out:=joint_states</remapping>
|
||||
</ros>
|
||||
<update_rate>30</update_rate>
|
||||
<joint_name>wheel_left_joint</joint_name>
|
||||
<joint_name>wheel_right_joint</joint_name>
|
||||
</plugin>
|
||||
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -1,76 +0,0 @@
|
||||
<COLLADA version="1.4.1" xmlns="http://www.collada.org/2005/11/COLLADASchema">
|
||||
<asset>
|
||||
<created>2017-03-30T01:06:40</created>
|
||||
<modified>2017-03-30T01:06:40</modified>
|
||||
<unit name="inch" meter="0.0254"/>
|
||||
<up_axis>Y_UP</up_axis>
|
||||
</asset>
|
||||
<library_visual_scenes>
|
||||
<visual_scene id="ID1">
|
||||
<node>
|
||||
<instance_geometry url="#ID2">
|
||||
<bind_material>
|
||||
<technique_common>
|
||||
<instance_material symbol="Material0" target="#ID9"/>
|
||||
</technique_common>
|
||||
</bind_material>
|
||||
</instance_geometry>
|
||||
</node>
|
||||
</visual_scene>
|
||||
</library_visual_scenes>
|
||||
<library_geometries>
|
||||
<geometry id="ID2">
|
||||
<mesh>
|
||||
<source id="ID3">
|
||||
<float_array id="ID4" count="108">-28.8675 50 100 -57.735 9.66338e-13 0 -57.735 1.13687e-12 100 -28.8675 50 0 -57.735 1.13687e-12 100 -28.8675 -50 0 -28.8675 -50 100 -57.735 9.66338e-13 0 -28.8675 -50 100 28.8675 -50 0 28.8675 -50 100 -28.8675 -50 0 28.8675 -50 100 57.735 1.7053e-12 0 57.735 1.36424e-12 100 28.8675 -50 0 57.735 1.36424e-12 100 28.8675 50 2.498e-13 28.8675 50 100 57.735 1.7053e-12 0 28.8675 50 100 -28.8675 50 0 -28.8675 50 100 28.8675 50 2.498e-13 -57.735 1.13687e-12 100 57.735 1.36424e-12 100 -28.8675 50 100 -28.8675 -50 100 28.8675 -50 100 28.8675 50 100 -57.735 9.66338e-13 0 28.8675 -50 0 -28.8675 -50 0 57.735 1.7053e-12 0 -28.8675 50 0 28.8675 50 2.498e-13</float_array>
|
||||
<technique_common>
|
||||
<accessor stride="3" count="36" source="#ID4">
|
||||
<param type="float" name="X"/>
|
||||
<param type="float" name="Y"/>
|
||||
<param type="float" name="Z"/>
|
||||
</accessor>
|
||||
</technique_common>
|
||||
</source>
|
||||
<source id="ID5">
|
||||
<float_array id="ID6" count="108">-0.866025 0.5 0 -0.866025 0.5 0 -0.866025 0.5 0 -0.866025 0.5 0 -0.866025 -0.5 0 -0.866025 -0.5 0 -0.866025 -0.5 0 -0.866025 -0.5 0 5.51091e-16 -1 0 5.51091e-16 -1 0 5.51091e-16 -1 0 5.51091e-16 -1 0 0.866025 -0.5 0 0.866025 -0.5 0 0.866025 -0.5 0 0.866025 -0.5 0 0.866025 0.5 0 0.866025 0.5 0 0.866025 0.5 0 0.866025 0.5 0 -4.28626e-16 1 0 -4.28626e-16 1 0 -4.28626e-16 1 0 -4.28626e-16 1 0 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1</float_array>
|
||||
<technique_common>
|
||||
<accessor stride="3" count="36" source="#ID6">
|
||||
<param type="float" name="X"/>
|
||||
<param type="float" name="Y"/>
|
||||
<param type="float" name="Z"/>
|
||||
</accessor>
|
||||
</technique_common>
|
||||
</source>
|
||||
<vertices id="ID7">
|
||||
<input semantic="POSITION" source="#ID3"/>
|
||||
<input semantic="NORMAL" source="#ID5"/>
|
||||
</vertices>
|
||||
<triangles count="20" material="Material0">
|
||||
<input semantic="VERTEX" source="#ID7" offset="0"/>
|
||||
<p>0 1 2 1 0 3 4 5 6 5 4 7 8 9 10 9 8 11 12 13 14 13 12 15 16 17 18 17 16 19 20 21 22 21 20 23 24 25 26 24 27 28 28 25 24 26 25 29 30 31 32 31 30 33 33 34 35 33 30 34</p>
|
||||
</triangles>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</library_geometries>
|
||||
<library_materials>
|
||||
<material id="ID9">
|
||||
<instance_effect url="#ID8"/>
|
||||
</material>
|
||||
</library_materials>
|
||||
<library_effects>
|
||||
<effect id="ID8">
|
||||
<profile_COMMON>
|
||||
<technique sid="COMMON">
|
||||
<lambert>
|
||||
<diffuse>
|
||||
<color>0.392157 0.976471 0.121569 1</color>
|
||||
</diffuse>
|
||||
</lambert>
|
||||
</technique>
|
||||
</profile_COMMON>
|
||||
</effect>
|
||||
</library_effects>
|
||||
<scene>
|
||||
<instance_visual_scene url="#ID1"/>
|
||||
</scene>
|
||||
</COLLADA>
|
||||
@@ -1,76 +0,0 @@
|
||||
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
|
||||
<asset>
|
||||
<created>2017-03-30T02:35:53</created>
|
||||
<modified>2017-03-30T02:35:53</modified>
|
||||
<unit name="inch" meter="0.0254"/>
|
||||
<up_axis>Y_UP</up_axis>
|
||||
</asset>
|
||||
<library_visual_scenes>
|
||||
<visual_scene id="ID1">
|
||||
<node>
|
||||
<instance_geometry url="#ID2">
|
||||
<bind_material>
|
||||
<technique_common>
|
||||
<instance_material symbol="Material0" target="#ID9"/>
|
||||
</technique_common>
|
||||
</bind_material>
|
||||
</instance_geometry>
|
||||
</node>
|
||||
</visual_scene>
|
||||
</library_visual_scenes>
|
||||
<library_geometries>
|
||||
<geometry id="ID2">
|
||||
<mesh>
|
||||
<source id="ID3">
|
||||
<float_array count="216" id="ID4">-400 230.94 0 -400 230.94 200 4.54747e-13 461.88 200 6.25278e-13 461.88 0 6.25278e-13 461.88 0 4.54747e-13 461.88 200 400 230.94 200 400 230.94 0 400 230.94 0 400 230.94 200 400 -230.94 200 400 -230.94 0 400 -230.94 0 400 -230.94 200 -1.7053e-13 -461.88 200 2.27374e-13 -461.88 0 2.27374e-13 -461.88 0 -1.7053e-13 -461.88 200 -400 -230.94 200 -400 -230.94 0 450 259.808 200 -3.69482e-13 519.615 200 -2.27374e-13 519.615 0 450 259.808 0 -3.69482e-13 519.615 200 -450 259.808 200 -450 259.808 0 -2.27374e-13 519.615 0 -450 259.808 200 -450 -259.808 200 -450 -259.808 0 -450 259.808 0 -450 -259.808 200 -1.13687e-13 -519.615 200 -2.27374e-13 -519.615 0 -450 -259.808 0 -1.13687e-13 -519.615 200 450 -259.808 200 450 -259.808 0 -2.27374e-13 -519.615 0 450 -259.808 0 450 259.808 200 450 259.808 0 450 -259.808 200 -400 -230.94 0 -400 -230.94 200 -400 230.94 200 -400 230.94 0 -1.7053e-13 -461.88 200 -1.13687e-13 -519.615 200 -400 -230.94 200 -450 -259.808 200 -450 259.808 200 450 -259.808 200 400 -230.94 200 400 230.94 200 4.54747e-13 461.88 200 -3.69482e-13 519.615 200 -400 230.94 200 450 259.808 200 -2.27374e-13 -519.615 0 400 -230.94 0 2.27374e-13 -461.88 0 400 230.94 0 -2.27374e-13 519.615 0 6.25278e-13 461.88 0 450 -259.808 0 450 259.808 0 -400 230.94 0 -450 259.808 0 -400 -230.94 0 -450 -259.808 0</float_array>
|
||||
<technique_common>
|
||||
<accessor count="72" source="#ID4" stride="3">
|
||||
<param name="X" type="float"/>
|
||||
<param name="Y" type="float"/>
|
||||
<param name="Z" type="float"/>
|
||||
</accessor>
|
||||
</technique_common>
|
||||
</source>
|
||||
<source id="ID5">
|
||||
<float_array count="216" id="ID6">0.5 -0.866025 0 0.5 -0.866025 0 0.5 -0.866025 0 0.5 -0.866025 0 -0.5 -0.866025 -0 -0.5 -0.866025 -0 -0.5 -0.866025 -0 -0.5 -0.866025 -0 -1 -6.12323e-17 -0 -1 -6.12323e-17 -0 -1 -6.12323e-17 -0 -1 -6.12323e-17 -0 -0.5 0.866025 0 -0.5 0.866025 0 -0.5 0.866025 0 -0.5 0.866025 0 0.5 0.866025 0 0.5 0.866025 0 0.5 0.866025 0 0.5 0.866025 0 0.5 0.866025 0 0.5 0.866025 0 0.5 0.866025 0 0.5 0.866025 0 -0.5 0.866025 0 -0.5 0.866025 0 -0.5 0.866025 0 -0.5 0.866025 0 -1 -5.21642e-16 0 -1 -5.21642e-16 0 -1 -5.21642e-16 0 -1 -5.21642e-16 0 -0.5 -0.866025 0 -0.5 -0.866025 0 -0.5 -0.866025 0 -0.5 -0.866025 0 0.5 -0.866025 0 0.5 -0.866025 0 0.5 -0.866025 0 0.5 -0.866025 0 1 0 0 1 0 0 1 0 0 1 0 0 1 1.83697e-16 0 1 1.83697e-16 0 1 1.83697e-16 0 1 1.83697e-16 0 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1 -0 -0 -1</float_array>
|
||||
<technique_common>
|
||||
<accessor count="72" source="#ID6" stride="3">
|
||||
<param name="X" type="float"/>
|
||||
<param name="Y" type="float"/>
|
||||
<param name="Z" type="float"/>
|
||||
</accessor>
|
||||
</technique_common>
|
||||
</source>
|
||||
<vertices id="ID7">
|
||||
<input semantic="POSITION" source="#ID3"/>
|
||||
<input semantic="NORMAL" source="#ID5"/>
|
||||
</vertices>
|
||||
<triangles count="48" material="Material0">
|
||||
<input semantic="VERTEX" source="#ID7" offset="0"/>
|
||||
<p>0 2 1 0 3 2 4 6 5 4 7 6 8 10 9 8 11 10 12 14 13 12 15 14 16 18 17 16 19 18 20 22 21 22 20 23 24 26 25 26 24 27 28 30 29 30 28 31 32 34 33 34 32 35 36 38 37 38 36 39 40 42 41 40 41 43 44 46 45 44 47 46 48 50 49 50 52 51 53 54 49 55 57 56 48 49 54 57 52 58 58 56 57 53 59 55 57 55 59 53 55 54 49 50 51 52 50 58 60 62 61 63 65 64 63 67 66 68 69 64 66 61 63 64 67 63 60 61 66 60 70 62 69 70 71 60 71 70 64 65 68 69 68 70</p>
|
||||
</triangles>
|
||||
</mesh>
|
||||
</geometry>
|
||||
</library_geometries>
|
||||
<library_materials>
|
||||
<material id="ID9">
|
||||
<instance_effect url="#ID8"/>
|
||||
</material>
|
||||
</library_materials>
|
||||
<library_effects>
|
||||
<effect id="ID8">
|
||||
<profile_COMMON>
|
||||
<technique sid="COMMON">
|
||||
<lambert>
|
||||
<diffuse>
|
||||
<color>0.603922 0.647059 0.686275 1</color>
|
||||
</diffuse>
|
||||
</lambert>
|
||||
</technique>
|
||||
</profile_COMMON>
|
||||
</effect>
|
||||
</library_effects>
|
||||
<scene>
|
||||
<instance_visual_scene url="#ID1"/>
|
||||
</scene>
|
||||
</COLLADA>
|
||||
@@ -1,549 +0,0 @@
|
||||
<sdf version='1.4'>
|
||||
<!-- Draw Circle -->
|
||||
<model name='ros_symbol'>
|
||||
<static>1</static>
|
||||
<link name='symbol'>
|
||||
<collision name='one_one'>
|
||||
<pose>-1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='one_one'>
|
||||
<pose>-1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='one_two'>
|
||||
<pose>-1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='one_two'>
|
||||
<pose>-1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='one_three'>
|
||||
<pose>-1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='one_three'>
|
||||
<pose>-1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='two_one'>
|
||||
<pose>0 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='two_one'>
|
||||
<pose>0 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='two_two'>
|
||||
<pose>0 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='two_two'>
|
||||
<pose>0 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='two_three'>
|
||||
<pose>0 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='two_three'>
|
||||
<pose>0 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='three_one'>
|
||||
<pose>1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='three_one'>
|
||||
<pose>1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='three_two'>
|
||||
<pose>1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='three_two'>
|
||||
<pose>1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='three_three'>
|
||||
<pose>1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='three_three'>
|
||||
<pose>1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<!-- Draw Hexagon -->
|
||||
<collision name='head'>
|
||||
<pose>3.5 0 -0.5 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.8 0.8 0.8</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='head'>
|
||||
<pose>3.5 0 -0.5 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.8 0.8 0.8</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='left_hand'>
|
||||
<pose>1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='left_hand'>
|
||||
<pose>1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='right_hand'>
|
||||
<pose>1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='right_hand'>
|
||||
<pose>1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='left_foot'>
|
||||
<pose>-1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='left_foot'>
|
||||
<pose>-1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='right_foot'>
|
||||
<pose>-1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='right_foot'>
|
||||
<pose>-1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<!-- Draw Wall -->
|
||||
<collision name='body'>
|
||||
<pose>0 0 -0.3 0 0 -1.5708</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/wall.dae</uri>
|
||||
<scale>0.25 0.25 0.25</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='body'>
|
||||
<pose>0 0 -0.3 0 0 -1.5708</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/wall.dae</uri>
|
||||
<scale>0.25 0.25 0.25</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/FlatBlack</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
</link>
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<model>
|
||||
<name>TurtleBot3 World</name>
|
||||
<version>1.0</version>
|
||||
<sdf version="1.4">model-1_4.sdf</sdf>
|
||||
<sdf version="1.5">model.sdf</sdf>
|
||||
|
||||
<author>
|
||||
<name>Taehun Lim(Darby)</name>
|
||||
<email>thlim@robotis.com</email>
|
||||
</author>
|
||||
|
||||
<description>
|
||||
World of TurtleBot3 with ROS symbol
|
||||
</description>
|
||||
</model>
|
||||
@@ -1,549 +0,0 @@
|
||||
<sdf version='1.5'>
|
||||
<!-- Draw Circle -->
|
||||
<model name='ros_symbol'>
|
||||
<static>1</static>
|
||||
<link name='symbol'>
|
||||
<collision name='one_one'>
|
||||
<pose>-1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='one_one'>
|
||||
<pose>-1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='one_two'>
|
||||
<pose>-1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='one_two'>
|
||||
<pose>-1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='one_three'>
|
||||
<pose>-1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='one_three'>
|
||||
<pose>-1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='two_one'>
|
||||
<pose>0 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='two_one'>
|
||||
<pose>0 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='two_two'>
|
||||
<pose>0 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='two_two'>
|
||||
<pose>0 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='two_three'>
|
||||
<pose>0 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='two_three'>
|
||||
<pose>0 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='three_one'>
|
||||
<pose>1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='three_one'>
|
||||
<pose>1.1 -1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='three_two'>
|
||||
<pose>1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='three_two'>
|
||||
<pose>1.1 0 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='three_three'>
|
||||
<pose>1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='three_three'>
|
||||
<pose>1.1 1.1 0.25 0 0 0</pose>
|
||||
<geometry>
|
||||
<cylinder>
|
||||
<radius>0.15</radius>
|
||||
<length>0.5</length>
|
||||
</cylinder>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/White</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<!-- Draw Hexagon -->
|
||||
<collision name='head'>
|
||||
<pose>3.5 0 -0.5 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.8 0.8 0.8</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='head'>
|
||||
<pose>3.5 0 -0.5 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.8 0.8 0.8</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='left_hand'>
|
||||
<pose>1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='left_hand'>
|
||||
<pose>1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='right_hand'>
|
||||
<pose>1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='right_hand'>
|
||||
<pose>1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='left_foot'>
|
||||
<pose>-1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='left_foot'>
|
||||
<pose>-1.8 2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<collision name='right_foot'>
|
||||
<pose>-1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='right_foot'>
|
||||
<pose>-1.8 -2.7 0 0 0 0</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/hexagon.dae</uri>
|
||||
<scale>0.55 0.55 0.55</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/Green</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
|
||||
<!-- Draw Wall -->
|
||||
<collision name='body'>
|
||||
<pose>0 0 -0.3 0 0 -1.5708</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/wall.dae</uri>
|
||||
<scale>0.25 0.25 0.25</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<max_contacts>10</max_contacts>
|
||||
<surface>
|
||||
<bounce/>
|
||||
<friction>
|
||||
<ode/>
|
||||
</friction>
|
||||
<contact>
|
||||
<ode/>
|
||||
</contact>
|
||||
</surface>
|
||||
</collision>
|
||||
|
||||
<visual name='body'>
|
||||
<pose>0 0 -0.3 0 0 -1.5708</pose>
|
||||
<geometry>
|
||||
<mesh>
|
||||
<uri>model://turtlebot3_world/meshes/wall.dae</uri>
|
||||
<scale>0.25 0.25 0.25</scale>
|
||||
</mesh>
|
||||
</geometry>
|
||||
<material>
|
||||
<script>
|
||||
<uri>file://media/materials/scripts/gazebo.material</uri>
|
||||
<name>Gazebo/FlatBlack</name>
|
||||
</script>
|
||||
</material>
|
||||
</visual>
|
||||
</link>
|
||||
</model>
|
||||
</sdf>
|
||||
@@ -1,69 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="3">
|
||||
<name>nav2_system_tests</name>
|
||||
<version>1.1.18</version>
|
||||
<description>TODO</description>
|
||||
<maintainer email="carlos.a.orduno@intel.com">Carlos Orduno</maintainer>
|
||||
<license>Apache-2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<build_depend>nav2_common</build_depend>
|
||||
|
||||
<build_depend>rclcpp</build_depend>
|
||||
<build_depend>rclpy</build_depend>
|
||||
<build_depend>nav2_util</build_depend>
|
||||
<build_depend>nav2_map_server</build_depend>
|
||||
<build_depend>nav2_msgs</build_depend>
|
||||
<build_depend>nav2_lifecycle_manager</build_depend>
|
||||
<build_depend>nav2_navfn_planner</build_depend>
|
||||
<build_depend>nav2_behavior_tree</build_depend>
|
||||
<build_depend>nav_msgs</build_depend>
|
||||
<build_depend>visualization_msgs</build_depend>
|
||||
<build_depend>nav2_amcl</build_depend>
|
||||
<build_depend>launch_ros</build_depend>
|
||||
<build_depend>launch_testing</build_depend>
|
||||
<build_depend>geometry_msgs</build_depend>
|
||||
<build_depend>std_msgs</build_depend>
|
||||
<build_depend>tf2_geometry_msgs</build_depend>
|
||||
<build_depend>gazebo_ros_pkgs</build_depend>
|
||||
<build_depend>launch_ros</build_depend>
|
||||
<build_depend>launch_testing</build_depend>
|
||||
<build_depend>nav2_planner</build_depend>
|
||||
|
||||
<exec_depend>launch_ros</exec_depend>
|
||||
<exec_depend>launch_testing</exec_depend>
|
||||
<exec_depend>rclcpp</exec_depend>
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>nav2_bringup</exec_depend>
|
||||
<exec_depend>nav2_util</exec_depend>
|
||||
<exec_depend>nav2_map_server</exec_depend>
|
||||
<exec_depend>nav2_msgs</exec_depend>
|
||||
<exec_depend>nav2_lifecycle_manager</exec_depend>
|
||||
<exec_depend>nav2_navfn_planner</exec_depend>
|
||||
<exec_depend>nav2_behavior_tree</exec_depend>
|
||||
<exec_depend>nav_msgs</exec_depend>
|
||||
<exec_depend>visualization_msgs</exec_depend>
|
||||
<exec_depend>geometry_msgs</exec_depend>
|
||||
<exec_depend>nav2_amcl</exec_depend>
|
||||
<exec_depend>std_msgs</exec_depend>
|
||||
<exec_depend>tf2_geometry_msgs</exec_depend>
|
||||
<exec_depend>gazebo_ros_pkgs</exec_depend>
|
||||
<exec_depend>navigation2</exec_depend>
|
||||
<exec_depend>lcov</exec_depend>
|
||||
<exec_depend>robot_state_publisher</exec_depend>
|
||||
<exec_depend>nav2_planner</exec_depend>
|
||||
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_cmake_pytest</test_depend>
|
||||
<test_depend>launch</test_depend>
|
||||
<test_depend>launch_ros</test_depend>
|
||||
<test_depend>launch_testing</test_depend>
|
||||
<test_depend>python3-zmq</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# Simple bash script to loop over the Nav2 "bt_navigator" system test
|
||||
#
|
||||
# options:
|
||||
# -c <#> - number of times to loop
|
||||
# -o <file> - name of summary output file
|
||||
# -l <file> - name to use for failing log files
|
||||
# -d <dds> - name of DDS implementation to use (ex: rmw_fastrtps_cpp)
|
||||
|
||||
failcount=0
|
||||
loopcount=1
|
||||
|
||||
while getopts c:o:l:d: option
|
||||
do
|
||||
case "$option"
|
||||
in
|
||||
c) loopcount=$OPTARG;;
|
||||
o) outfile=$OPTARG;;
|
||||
l) logfile=$OPTARG;;
|
||||
d) dds=$OPTARG;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Total loop count = " $loopcount
|
||||
export RMW_IMPLEMENTATION=$dds
|
||||
|
||||
for ((i=1; i<=$loopcount; i++))
|
||||
do
|
||||
echo "******************************"
|
||||
echo "Loop number: " $i
|
||||
echo "Running with DDS: " $dds
|
||||
echo "******************************"
|
||||
|
||||
ctest -V -R test_bt_navigator$ -O $logfile
|
||||
result=$?
|
||||
echo "RESULT =" $result
|
||||
if [ "$result" != "0" ]
|
||||
then
|
||||
((failcount+=1))
|
||||
echo "TEST $i FAILED" >> $outfile
|
||||
mv $logfile $logfile.$i.fail
|
||||
fi
|
||||
echo $i "TESTS COMPLETED"
|
||||
echo $failcount "TOTAL FAILURES"
|
||||
done
|
||||
echo $failcount " FAILURES / " $loopcount
|
||||
echo $failcount " FAILURES / " $loopcount >> $outfile
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
find_package(Boost COMPONENTS system filesystem REQUIRED)
|
||||
|
||||
ament_add_gtest(test_behavior_tree_node
|
||||
test_behavior_tree_node.cpp
|
||||
server_handler.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(test_behavior_tree_node
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
target_include_directories(test_behavior_tree_node PUBLIC ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(test_behavior_tree_node
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
)
|
||||
@@ -1,207 +0,0 @@
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#ifndef BEHAVIOR_TREE__DUMMY_SERVERS_HPP_
|
||||
#define BEHAVIOR_TREE__DUMMY_SERVERS_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
#include "rclcpp_action/rclcpp_action.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
using namespace std::chrono_literals; // NOLINT
|
||||
using namespace std::chrono; // NOLINT
|
||||
using namespace std::placeholders; // NOLINT
|
||||
|
||||
template<class ServiceT>
|
||||
class DummyService
|
||||
{
|
||||
public:
|
||||
explicit DummyService(
|
||||
const rclcpp::Node::SharedPtr & node,
|
||||
std::string service_name)
|
||||
: node_(node),
|
||||
service_name_(service_name),
|
||||
request_count_(0),
|
||||
disabled_(false)
|
||||
{
|
||||
server_ = node->create_service<ServiceT>(
|
||||
service_name,
|
||||
std::bind(&DummyService::handle_service, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
void disable()
|
||||
{
|
||||
server_.reset();
|
||||
disabled_ = true;
|
||||
}
|
||||
|
||||
void enable()
|
||||
{
|
||||
if (disabled_) {
|
||||
server_ = node_->create_service<ServiceT>(
|
||||
service_name_,
|
||||
std::bind(&DummyService::handle_service, this, _1, _2, _3));
|
||||
disabled_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
enable();
|
||||
request_count_ = 0;
|
||||
}
|
||||
|
||||
int getRequestCount() const
|
||||
{
|
||||
return request_count_;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void fillResponse(
|
||||
const std::shared_ptr<typename ServiceT::Request>/*request*/,
|
||||
const std::shared_ptr<typename ServiceT::Response>/*response*/) {}
|
||||
|
||||
void handle_service(
|
||||
const std::shared_ptr<rmw_request_id_t>/*request_header*/,
|
||||
const std::shared_ptr<typename ServiceT::Request> request,
|
||||
const std::shared_ptr<typename ServiceT::Response> response)
|
||||
{
|
||||
request_count_++;
|
||||
fillResponse(request, response);
|
||||
}
|
||||
|
||||
private:
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
typename rclcpp::Service<ServiceT>::SharedPtr server_;
|
||||
std::string service_name_;
|
||||
int request_count_;
|
||||
bool disabled_;
|
||||
};
|
||||
|
||||
template<class ActionT>
|
||||
class DummyActionServer
|
||||
{
|
||||
public:
|
||||
explicit DummyActionServer(
|
||||
const rclcpp::Node::SharedPtr & node,
|
||||
std::string action_name)
|
||||
: action_name_(action_name),
|
||||
goal_count_(0)
|
||||
{
|
||||
this->action_server_ = rclcpp_action::create_server<ActionT>(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_clock_interface(),
|
||||
node->get_node_logging_interface(),
|
||||
node->get_node_waitables_interface(),
|
||||
action_name,
|
||||
std::bind(&DummyActionServer::handle_goal, this, _1, _2),
|
||||
std::bind(&DummyActionServer::handle_cancel, this, _1),
|
||||
std::bind(&DummyActionServer::handle_accepted, this, _1));
|
||||
}
|
||||
|
||||
void setFailureRanges(const std::vector<std::pair<int, int>> & failureRanges)
|
||||
{
|
||||
failure_ranges_ = failureRanges;
|
||||
}
|
||||
|
||||
void setRunningRanges(const std::vector<std::pair<int, int>> & runningRanges)
|
||||
{
|
||||
running_ranges_ = runningRanges;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
failure_ranges_.clear();
|
||||
running_ranges_.clear();
|
||||
goal_count_ = 0;
|
||||
}
|
||||
|
||||
int getGoalCount() const
|
||||
{
|
||||
return goal_count_;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::shared_ptr<typename ActionT::Result> fillResult()
|
||||
{
|
||||
return std::make_shared<typename ActionT::Result>();
|
||||
}
|
||||
|
||||
virtual rclcpp_action::GoalResponse handle_goal(
|
||||
const rclcpp_action::GoalUUID &,
|
||||
std::shared_ptr<const typename ActionT::Goal>/*goal*/)
|
||||
{
|
||||
return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
|
||||
}
|
||||
|
||||
virtual rclcpp_action::CancelResponse handle_cancel(
|
||||
const typename std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>>)
|
||||
{
|
||||
return rclcpp_action::CancelResponse::ACCEPT;
|
||||
}
|
||||
|
||||
void execute(
|
||||
const typename std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>> goal_handle)
|
||||
{
|
||||
goal_count_++;
|
||||
auto result = fillResult();
|
||||
|
||||
// if current goal index exists in running range, the thread sleeps for 1 second
|
||||
// to simulate a long running action
|
||||
for (auto & index : running_ranges_) {
|
||||
if (goal_count_ >= index.first && goal_count_ <= index.second) {
|
||||
std::this_thread::sleep_for(1s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if current goal index exists in failure range, the goal will be aborted
|
||||
for (auto & index : failure_ranges_) {
|
||||
if (goal_count_ >= index.first && goal_count_ <= index.second) {
|
||||
goal_handle->abort(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// goal succeeds for all other indices
|
||||
goal_handle->succeed(result);
|
||||
}
|
||||
|
||||
void handle_accepted(
|
||||
const std::shared_ptr<rclcpp_action::ServerGoalHandle<ActionT>> goal_handle)
|
||||
{
|
||||
using namespace std::placeholders; // NOLINT
|
||||
// this needs to return quickly to avoid blocking the executor, so spin up a new thread
|
||||
std::thread{std::bind(&DummyActionServer::execute, this, _1), goal_handle}.detach();
|
||||
}
|
||||
|
||||
protected:
|
||||
typename rclcpp_action::Server<ActionT>::SharedPtr action_server_;
|
||||
std::string action_name_;
|
||||
|
||||
// contains pairs of indices which define a range for which the
|
||||
// requested action goal will return running for 1s or be aborted
|
||||
// for all other indices, the action server will return success
|
||||
std::vector<std::pair<int, int>> failure_ranges_;
|
||||
std::vector<std::pair<int, int>> running_ranges_;
|
||||
|
||||
int goal_count_;
|
||||
};
|
||||
|
||||
#endif // BEHAVIOR_TREE__DUMMY_SERVERS_HPP_
|
||||
@@ -1,96 +0,0 @@
|
||||
// Copyright (c) 2020 Vinny Ruia
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include "server_handler.hpp"
|
||||
|
||||
using namespace std::chrono_literals; // NOLINT
|
||||
using namespace std::chrono; // NOLINT
|
||||
|
||||
ServerHandler::ServerHandler()
|
||||
: is_active_(false)
|
||||
{
|
||||
node_ = rclcpp::Node::make_shared("behavior_tree_tester");
|
||||
|
||||
clear_local_costmap_server = std::make_unique<DummyService<nav2_msgs::srv::ClearEntireCostmap>>(
|
||||
node_, "local_costmap/clear_entirely_local_costmap");
|
||||
clear_global_costmap_server = std::make_unique<DummyService<nav2_msgs::srv::ClearEntireCostmap>>(
|
||||
node_, "global_costmap/clear_entirely_global_costmap");
|
||||
compute_path_to_pose_server = std::make_unique<ComputePathToPoseActionServer>(node_);
|
||||
follow_path_server = std::make_unique<DummyActionServer<nav2_msgs::action::FollowPath>>(
|
||||
node_, "follow_path");
|
||||
spin_server = std::make_unique<DummyActionServer<nav2_msgs::action::Spin>>(
|
||||
node_, "spin");
|
||||
wait_server = std::make_unique<DummyActionServer<nav2_msgs::action::Wait>>(
|
||||
node_, "wait");
|
||||
backup_server = std::make_unique<DummyActionServer<nav2_msgs::action::BackUp>>(
|
||||
node_, "backup");
|
||||
drive_on_heading_server = std::make_unique<DummyActionServer<nav2_msgs::action::DriveOnHeading>>(
|
||||
node_, "drive_on_heading");
|
||||
ntp_server = std::make_unique<DummyActionServer<nav2_msgs::action::ComputePathThroughPoses>>(
|
||||
node_, "compute_path_through_poses");
|
||||
}
|
||||
|
||||
ServerHandler::~ServerHandler()
|
||||
{
|
||||
if (is_active_) {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void ServerHandler::activate()
|
||||
{
|
||||
if (is_active_) {
|
||||
throw std::runtime_error("Trying to activate while already activated");
|
||||
}
|
||||
|
||||
is_active_ = true;
|
||||
server_thread_ =
|
||||
std::make_shared<std::thread>(std::bind(&ServerHandler::spinThread, this));
|
||||
|
||||
std::cout << "Server handler is active!" << std::endl;
|
||||
}
|
||||
|
||||
void ServerHandler::deactivate()
|
||||
{
|
||||
if (!is_active_) {
|
||||
throw std::runtime_error("Trying to deactivate while already inactive");
|
||||
}
|
||||
|
||||
is_active_ = false;
|
||||
server_thread_->join();
|
||||
|
||||
std::cout << "Server handler has been deactivated!" << std::endl;
|
||||
}
|
||||
|
||||
void ServerHandler::reset() const
|
||||
{
|
||||
clear_global_costmap_server->reset();
|
||||
clear_local_costmap_server->reset();
|
||||
compute_path_to_pose_server->reset();
|
||||
follow_path_server->reset();
|
||||
spin_server->reset();
|
||||
wait_server->reset();
|
||||
backup_server->reset();
|
||||
drive_on_heading_server->reset();
|
||||
}
|
||||
|
||||
void ServerHandler::spinThread()
|
||||
{
|
||||
rclcpp::spin(node_);
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright (c) 2020 Vinny Ruia
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#ifndef BEHAVIOR_TREE__SERVER_HANDLER_HPP_
|
||||
#define BEHAVIOR_TREE__SERVER_HANDLER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "nav2_msgs/srv/clear_entire_costmap.hpp"
|
||||
#include "nav2_msgs/action/compute_path_to_pose.hpp"
|
||||
#include "nav2_msgs/action/follow_path.hpp"
|
||||
#include "nav2_msgs/action/spin.hpp"
|
||||
#include "nav2_msgs/action/back_up.hpp"
|
||||
#include "nav2_msgs/action/wait.hpp"
|
||||
#include "nav2_msgs/action/drive_on_heading.hpp"
|
||||
#include "nav2_msgs/action/compute_path_through_poses.hpp"
|
||||
|
||||
#include "geometry_msgs/msg/point_stamped.hpp"
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "dummy_servers.hpp"
|
||||
|
||||
class ComputePathToPoseActionServer
|
||||
: public DummyActionServer<nav2_msgs::action::ComputePathToPose>
|
||||
{
|
||||
public:
|
||||
explicit ComputePathToPoseActionServer(const rclcpp::Node::SharedPtr & node)
|
||||
: DummyActionServer(node, "compute_path_to_pose")
|
||||
{
|
||||
result_ = std::make_shared<nav2_msgs::action::ComputePathToPose::Result>();
|
||||
geometry_msgs::msg::PoseStamped pose;
|
||||
pose.header = result_->path.header;
|
||||
pose.pose.position.x = 0.0;
|
||||
pose.pose.position.y = 0.0;
|
||||
pose.pose.position.z = 0.0;
|
||||
pose.pose.orientation.x = 0.0;
|
||||
pose.pose.orientation.y = 0.0;
|
||||
pose.pose.orientation.z = 0.0;
|
||||
pose.pose.orientation.w = 1.0;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
result_->path.poses.push_back(pose);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<nav2_msgs::action::ComputePathToPose::Result> fillResult() override
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<nav2_msgs::action::ComputePathToPose::Result> result_;
|
||||
};
|
||||
|
||||
class ServerHandler
|
||||
{
|
||||
public:
|
||||
ServerHandler();
|
||||
~ServerHandler();
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate();
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return is_active_;
|
||||
}
|
||||
|
||||
void reset() const;
|
||||
|
||||
public:
|
||||
std::unique_ptr<DummyService<nav2_msgs::srv::ClearEntireCostmap>> clear_local_costmap_server;
|
||||
std::unique_ptr<DummyService<nav2_msgs::srv::ClearEntireCostmap>> clear_global_costmap_server;
|
||||
std::unique_ptr<ComputePathToPoseActionServer> compute_path_to_pose_server;
|
||||
std::unique_ptr<DummyActionServer<nav2_msgs::action::FollowPath>> follow_path_server;
|
||||
std::unique_ptr<DummyActionServer<nav2_msgs::action::Spin>> spin_server;
|
||||
std::unique_ptr<DummyActionServer<nav2_msgs::action::Wait>> wait_server;
|
||||
std::unique_ptr<DummyActionServer<nav2_msgs::action::BackUp>> backup_server;
|
||||
std::unique_ptr<DummyActionServer<nav2_msgs::action::DriveOnHeading>> drive_on_heading_server;
|
||||
std::unique_ptr<DummyActionServer<nav2_msgs::action::ComputePathThroughPoses>> ntp_server;
|
||||
|
||||
private:
|
||||
void spinThread();
|
||||
|
||||
bool is_active_;
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
std::shared_ptr<std::thread> server_thread_;
|
||||
};
|
||||
|
||||
#endif // BEHAVIOR_TREE__SERVER_HANDLER_HPP_
|
||||
@@ -1,656 +0,0 @@
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "behaviortree_cpp_v3/behavior_tree.h"
|
||||
#include "behaviortree_cpp_v3/bt_factory.h"
|
||||
#include "behaviortree_cpp_v3/utils/shared_library.h"
|
||||
|
||||
#include "tf2_ros/buffer.h"
|
||||
#include "tf2_ros/transform_listener.h"
|
||||
#include "tf2_ros/create_timer_ros.h"
|
||||
|
||||
#include "nav2_util/odometry_utils.hpp"
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "ament_index_cpp/get_package_share_directory.hpp"
|
||||
|
||||
#include "server_handler.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
class BehaviorTreeHandler
|
||||
{
|
||||
public:
|
||||
BehaviorTreeHandler()
|
||||
{
|
||||
node_ = rclcpp::Node::make_shared("behavior_tree_handler");
|
||||
|
||||
tf_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
|
||||
auto timer_interface = std::make_shared<tf2_ros::CreateTimerROS>(
|
||||
node_->get_node_base_interface(), node_->get_node_timers_interface());
|
||||
tf_->setCreateTimerInterface(timer_interface);
|
||||
tf_->setUsingDedicatedThread(true);
|
||||
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_, node_, false);
|
||||
|
||||
odom_smoother_ = std::make_shared<nav2_util::OdomSmoother>(node_);
|
||||
|
||||
const std::vector<std::string> plugin_libs = {
|
||||
"nav2_compute_path_to_pose_action_bt_node",
|
||||
"nav2_compute_path_through_poses_action_bt_node",
|
||||
"nav2_smooth_path_action_bt_node",
|
||||
"nav2_follow_path_action_bt_node",
|
||||
"nav2_spin_action_bt_node",
|
||||
"nav2_wait_action_bt_node",
|
||||
"nav2_assisted_teleop_action_bt_node",
|
||||
"nav2_back_up_action_bt_node",
|
||||
"nav2_drive_on_heading_bt_node",
|
||||
"nav2_clear_costmap_service_bt_node",
|
||||
"nav2_is_stuck_condition_bt_node",
|
||||
"nav2_goal_reached_condition_bt_node",
|
||||
"nav2_initial_pose_received_condition_bt_node",
|
||||
"nav2_goal_updated_condition_bt_node",
|
||||
"nav2_globally_updated_goal_condition_bt_node",
|
||||
"nav2_is_path_valid_condition_bt_node",
|
||||
"nav2_reinitialize_global_localization_service_bt_node",
|
||||
"nav2_rate_controller_bt_node",
|
||||
"nav2_distance_controller_bt_node",
|
||||
"nav2_speed_controller_bt_node",
|
||||
"nav2_truncate_path_action_bt_node",
|
||||
"nav2_truncate_path_local_action_bt_node",
|
||||
"nav2_goal_updater_node_bt_node",
|
||||
"nav2_recovery_node_bt_node",
|
||||
"nav2_pipeline_sequence_bt_node",
|
||||
"nav2_round_robin_node_bt_node",
|
||||
"nav2_transform_available_condition_bt_node",
|
||||
"nav2_time_expired_condition_bt_node",
|
||||
"nav2_path_expiring_timer_condition",
|
||||
"nav2_distance_traveled_condition_bt_node",
|
||||
"nav2_single_trigger_bt_node",
|
||||
"nav2_is_battery_low_condition_bt_node",
|
||||
"nav2_navigate_through_poses_action_bt_node",
|
||||
"nav2_navigate_to_pose_action_bt_node",
|
||||
"nav2_remove_passed_goals_action_bt_node",
|
||||
"nav2_planner_selector_bt_node",
|
||||
"nav2_controller_selector_bt_node",
|
||||
"nav2_goal_checker_selector_bt_node",
|
||||
"nav2_controller_cancel_bt_node",
|
||||
"nav2_path_longer_on_approach_bt_node",
|
||||
"nav2_assisted_teleop_cancel_bt_node",
|
||||
"nav2_wait_cancel_bt_node",
|
||||
"nav2_spin_cancel_bt_node",
|
||||
"nav2_back_up_cancel_bt_node",
|
||||
"nav2_drive_on_heading_cancel_bt_node",
|
||||
"nav2_goal_updated_controller_bt_node"
|
||||
};
|
||||
for (const auto & p : plugin_libs) {
|
||||
factory_.registerFromPlugin(BT::SharedLibrary::getOSName(p));
|
||||
}
|
||||
}
|
||||
|
||||
bool loadBehaviorTree(const std::string & filename)
|
||||
{
|
||||
// Read the input BT XML from the specified file into a string
|
||||
std::ifstream xml_file(filename);
|
||||
|
||||
if (!xml_file.good()) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Couldn't open input XML file: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto xml_string = std::string(
|
||||
std::istreambuf_iterator<char>(xml_file),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
// Create the blackboard that will be shared by all of the nodes in the tree
|
||||
blackboard = BT::Blackboard::create();
|
||||
|
||||
// Put items on the blackboard
|
||||
blackboard->set<rclcpp::Node::SharedPtr>("node", node_); // NOLINT
|
||||
blackboard->set<std::chrono::milliseconds>(
|
||||
"server_timeout", std::chrono::milliseconds(20)); // NOLINT
|
||||
blackboard->set<std::chrono::milliseconds>(
|
||||
"bt_loop_duration", std::chrono::milliseconds(10)); // NOLINT
|
||||
blackboard->set<std::chrono::milliseconds>(
|
||||
"wait_for_service_timeout", std::chrono::milliseconds(1000)); // NOLINT
|
||||
blackboard->set<std::shared_ptr<tf2_ros::Buffer>>("tf_buffer", tf_); // NOLINT
|
||||
blackboard->set<bool>("initial_pose_received", false); // NOLINT
|
||||
blackboard->set<int>("number_recoveries", 0); // NOLINT
|
||||
blackboard->set<std::shared_ptr<nav2_util::OdomSmoother>>("odom_smoother", odom_smoother_); // NOLINT
|
||||
|
||||
// set dummy goal on blackboard
|
||||
geometry_msgs::msg::PoseStamped goal;
|
||||
goal.header.stamp = node_->now();
|
||||
goal.header.frame_id = "map";
|
||||
goal.pose.position.x = 0.0;
|
||||
goal.pose.position.y = 0.0;
|
||||
goal.pose.position.z = 0.0;
|
||||
goal.pose.orientation.x = 0.0;
|
||||
goal.pose.orientation.y = 0.0;
|
||||
goal.pose.orientation.z = 0.0;
|
||||
goal.pose.orientation.w = 1.0;
|
||||
|
||||
blackboard->set<geometry_msgs::msg::PoseStamped>("goal", goal); // NOLINT
|
||||
|
||||
// Create the Behavior Tree from the XML input
|
||||
try {
|
||||
tree = factory_.createTreeFromText(xml_string, blackboard);
|
||||
} catch (BT::RuntimeError & exp) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "%s: %s", filename.c_str(), exp.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
BT::Blackboard::Ptr blackboard;
|
||||
BT::Tree tree;
|
||||
|
||||
private:
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
|
||||
std::shared_ptr<tf2_ros::Buffer> tf_;
|
||||
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
|
||||
std::shared_ptr<nav2_util::OdomSmoother> odom_smoother_;
|
||||
|
||||
BT::BehaviorTreeFactory factory_;
|
||||
};
|
||||
|
||||
class BehaviorTreeTestFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
// initialize ROS
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
server_handler = std::make_shared<ServerHandler>();
|
||||
if (!server_handler->isActive()) {
|
||||
server_handler->activate();
|
||||
}
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
// shutdown ROS
|
||||
rclcpp::shutdown();
|
||||
|
||||
server_handler.reset();
|
||||
bt_handler.reset();
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
server_handler->reset();
|
||||
bt_handler = std::make_shared<BehaviorTreeHandler>();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
bt_handler.reset();
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::shared_ptr<ServerHandler> server_handler;
|
||||
static std::shared_ptr<BehaviorTreeHandler> bt_handler;
|
||||
};
|
||||
|
||||
std::shared_ptr<ServerHandler> BehaviorTreeTestFixture::server_handler = nullptr;
|
||||
std::shared_ptr<BehaviorTreeHandler> BehaviorTreeTestFixture::bt_handler = nullptr;
|
||||
|
||||
TEST_F(BehaviorTreeTestFixture, TestBTXMLFiles)
|
||||
{
|
||||
fs::path root = ament_index_cpp::get_package_share_directory("nav2_bt_navigator");
|
||||
root /= "behavior_trees/";
|
||||
|
||||
if (boost::filesystem::exists(root) && boost::filesystem::is_directory(root)) {
|
||||
for (auto const & entry : boost::filesystem::recursive_directory_iterator(root)) {
|
||||
if (boost::filesystem::is_regular_file(entry) && entry.path().extension() == ".xml") {
|
||||
std::cout << entry.path().string() << std::endl;
|
||||
EXPECT_EQ(bt_handler->loadBehaviorTree(entry.path().string()), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test scenario:
|
||||
*
|
||||
* ComputePathToPose and FollowPath return SUCCESS
|
||||
* The behavior tree should execute correctly and return SUCCESS
|
||||
*/
|
||||
TEST_F(BehaviorTreeTestFixture, TestAllSuccess)
|
||||
{
|
||||
// Load behavior tree from file
|
||||
fs::path bt_file = ament_index_cpp::get_package_share_directory("nav2_bt_navigator");
|
||||
bt_file /= "behavior_trees/";
|
||||
bt_file /= "navigate_to_pose_w_replanning_and_recovery.xml";
|
||||
EXPECT_EQ(bt_handler->loadBehaviorTree(bt_file.string()), true);
|
||||
|
||||
BT::NodeStatus result = BT::NodeStatus::RUNNING;
|
||||
|
||||
while (result == BT::NodeStatus::RUNNING) {
|
||||
result = bt_handler->tree.tickRoot();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// The final result should be success since all action servers returned success
|
||||
EXPECT_EQ(result, BT::NodeStatus::SUCCESS);
|
||||
|
||||
// Goal count should be 1 since only one goal is sent to ComputePathToPose and FollowPath servers
|
||||
EXPECT_EQ(server_handler->compute_path_to_pose_server->getGoalCount(), 1);
|
||||
EXPECT_EQ(server_handler->follow_path_server->getGoalCount(), 1);
|
||||
|
||||
// Goal count should be 0 since no goal is sent to all other servers
|
||||
EXPECT_EQ(server_handler->spin_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->wait_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->backup_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->clear_local_costmap_server->getRequestCount(), 0);
|
||||
EXPECT_EQ(server_handler->clear_global_costmap_server->getRequestCount(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test scenario:
|
||||
*
|
||||
* ComputePathToPose returns FAILURE and ClearGlobalCostmap-Context returns FAILURE
|
||||
* PipelineSequence returns FAILURE and NavigateRecovery triggers RecoveryFallback
|
||||
* GoalUpdated returns FAILURE and RoundRobin is triggered
|
||||
* RoundRobin triggers ClearingActions Sequence which returns FAILURE
|
||||
* RoundRobin triggers Spin, Wait, and BackUp which return FAILURE
|
||||
* RoundRobin returns FAILURE hence RecoveryCallbackk returns FAILURE
|
||||
* Finally NavigateRecovery returns FAILURE
|
||||
* The behavior tree should also return FAILURE
|
||||
*/
|
||||
TEST_F(BehaviorTreeTestFixture, TestAllFailure)
|
||||
{
|
||||
// Load behavior tree from file
|
||||
fs::path bt_file = ament_index_cpp::get_package_share_directory("nav2_bt_navigator");
|
||||
bt_file /= "behavior_trees/";
|
||||
bt_file /= "navigate_to_pose_w_replanning_and_recovery.xml";
|
||||
EXPECT_EQ(bt_handler->loadBehaviorTree(bt_file.string()), true);
|
||||
|
||||
// Set all action server to fail the first 100 times
|
||||
std::vector<std::pair<int, int>> failureRange;
|
||||
failureRange.emplace_back(std::pair<int, int>(0, 100));
|
||||
server_handler->compute_path_to_pose_server->setFailureRanges(failureRange);
|
||||
server_handler->follow_path_server->setFailureRanges(failureRange);
|
||||
server_handler->spin_server->setFailureRanges(failureRange);
|
||||
server_handler->wait_server->setFailureRanges(failureRange);
|
||||
server_handler->backup_server->setFailureRanges(failureRange);
|
||||
|
||||
// Disable services
|
||||
server_handler->clear_global_costmap_server->disable();
|
||||
server_handler->clear_local_costmap_server->disable();
|
||||
|
||||
BT::NodeStatus result = BT::NodeStatus::RUNNING;
|
||||
|
||||
while (result == BT::NodeStatus::RUNNING) {
|
||||
result = bt_handler->tree.tickRoot();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// The final result should be failure
|
||||
EXPECT_EQ(result, BT::NodeStatus::FAILURE);
|
||||
|
||||
// Goal count should be 1 since only one goal is sent to ComputePathToPose
|
||||
EXPECT_EQ(server_handler->compute_path_to_pose_server->getGoalCount(), 1);
|
||||
|
||||
// Goal count should be 0 since no goal is sent to FollowPath action server
|
||||
EXPECT_EQ(server_handler->follow_path_server->getGoalCount(), 0);
|
||||
|
||||
// All recovery action servers were sent 1 goal
|
||||
EXPECT_EQ(server_handler->spin_server->getGoalCount(), 1);
|
||||
EXPECT_EQ(server_handler->wait_server->getGoalCount(), 1);
|
||||
EXPECT_EQ(server_handler->backup_server->getGoalCount(), 1);
|
||||
|
||||
// Service count is 0 since the server was disabled
|
||||
EXPECT_EQ(server_handler->clear_local_costmap_server->getRequestCount(), 0);
|
||||
EXPECT_EQ(server_handler->clear_global_costmap_server->getRequestCount(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test scenario:
|
||||
*
|
||||
* ComputePathToPose returns FAILURE on the first try triggering the planner recovery
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns SUCCESS when retried
|
||||
* FollowPath returns FAILURE on the first try triggering the controller recovery
|
||||
* ClearLocalCostmap-Context returns SUCCESS and FollowPath returns SUCCESS when retried
|
||||
* The behavior tree should return SUCCESS
|
||||
*/
|
||||
TEST_F(BehaviorTreeTestFixture, TestNavigateSubtreeRecoveries)
|
||||
{
|
||||
// Load behavior tree from file
|
||||
fs::path bt_file = ament_index_cpp::get_package_share_directory("nav2_bt_navigator");
|
||||
bt_file /= "behavior_trees/";
|
||||
bt_file /= "navigate_to_pose_w_replanning_and_recovery.xml";
|
||||
EXPECT_EQ(bt_handler->loadBehaviorTree(bt_file.string()), true);
|
||||
|
||||
// Set ComputePathToPose and FollowPath action servers to fail for the first action
|
||||
std::vector<std::pair<int, int>> failureRange;
|
||||
failureRange.emplace_back(std::pair<int, int>(0, 1));
|
||||
server_handler->compute_path_to_pose_server->setFailureRanges(failureRange);
|
||||
server_handler->follow_path_server->setFailureRanges(failureRange);
|
||||
|
||||
BT::NodeStatus result = BT::NodeStatus::RUNNING;
|
||||
|
||||
while (result == BT::NodeStatus::RUNNING) {
|
||||
result = bt_handler->tree.tickRoot();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// The final result should be success
|
||||
EXPECT_EQ(result, BT::NodeStatus::SUCCESS);
|
||||
|
||||
// Goal count should be 2 since only two goals were sent to ComputePathToPose and FollowPath
|
||||
EXPECT_EQ(server_handler->compute_path_to_pose_server->getGoalCount(), 2);
|
||||
EXPECT_EQ(server_handler->follow_path_server->getGoalCount(), 2);
|
||||
|
||||
// Navigate subtree recovery services are called once each
|
||||
EXPECT_EQ(server_handler->clear_local_costmap_server->getRequestCount(), 1);
|
||||
EXPECT_EQ(server_handler->clear_global_costmap_server->getRequestCount(), 1);
|
||||
|
||||
// Goal count should be 0 since no goal is sent to all other servers
|
||||
EXPECT_EQ(server_handler->spin_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->wait_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->backup_server->getGoalCount(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test scenario:
|
||||
*
|
||||
* ComputePathToPose returns FAILURE on the first try triggering the planner recovery
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns SUCCESS when retried
|
||||
* FollowPath returns FAILURE on the first try triggering the controller recovery
|
||||
* ClearLocalCostmap-Context returns SUCCESS and FollowPath is retried
|
||||
* FollowPath returns FAILURE again and PipelineSequence returns FAILURE
|
||||
* NavigateRecovery triggers RecoveryFallback and GoalUpdated returns FAILURE
|
||||
* RoundRobin triggers ClearingActions Sequence which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns SUCCESS
|
||||
* FollowPath returns FAILURE on the third try triggering the controller recovery
|
||||
* ClearLocalCostmap-Context returns SUCCESS and FollowPath returns SUCCESS on the fourth try
|
||||
* The behavior tree should return SUCCESS
|
||||
*/
|
||||
TEST_F(BehaviorTreeTestFixture, TestNavigateRecoverySimple)
|
||||
{
|
||||
// Load behavior tree from file
|
||||
fs::path bt_file = ament_index_cpp::get_package_share_directory("nav2_bt_navigator");
|
||||
bt_file /= "behavior_trees/";
|
||||
bt_file /= "navigate_to_pose_w_replanning_and_recovery.xml";
|
||||
EXPECT_EQ(bt_handler->loadBehaviorTree(bt_file.string()), true);
|
||||
|
||||
// Set ComputePathToPose action server to fail for the first action
|
||||
std::vector<std::pair<int, int>> plannerFailureRange;
|
||||
plannerFailureRange.emplace_back(std::pair<int, int>(0, 1));
|
||||
server_handler->compute_path_to_pose_server->setFailureRanges(plannerFailureRange);
|
||||
|
||||
// Set FollowPath action server to fail for the first 3 actions
|
||||
std::vector<std::pair<int, int>> controllerFailureRange;
|
||||
controllerFailureRange.emplace_back(std::pair<int, int>(0, 3));
|
||||
server_handler->follow_path_server->setFailureRanges(controllerFailureRange);
|
||||
|
||||
BT::NodeStatus result = BT::NodeStatus::RUNNING;
|
||||
|
||||
while (result == BT::NodeStatus::RUNNING) {
|
||||
result = bt_handler->tree.tickRoot();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// The final result should be success
|
||||
EXPECT_EQ(result, BT::NodeStatus::SUCCESS);
|
||||
|
||||
// FollowPath is called 4 times
|
||||
EXPECT_EQ(server_handler->follow_path_server->getGoalCount(), 4);
|
||||
|
||||
// ComputePathToPose is called 3 times
|
||||
EXPECT_EQ(server_handler->compute_path_to_pose_server->getGoalCount(), 3);
|
||||
|
||||
// Local costmap is cleared 3 times
|
||||
EXPECT_EQ(server_handler->clear_local_costmap_server->getRequestCount(), 3);
|
||||
|
||||
// Global costmap is cleared 2 times
|
||||
EXPECT_EQ(server_handler->clear_global_costmap_server->getRequestCount(), 2);
|
||||
|
||||
// Goal count should be 0 since only no goal is sent to all other servers
|
||||
EXPECT_EQ(server_handler->spin_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->wait_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->backup_server->getGoalCount(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test scenario:
|
||||
*
|
||||
* ComputePathToPose returns FAILURE on the first try triggering the planner recovery
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns FAILURE when retried
|
||||
* PipelineSequence returns FAILURE and NavigateRecovery triggers RecoveryFallback
|
||||
* GoalUpdated returns FAILURE, RoundRobin triggers ClearingActions Sequence which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
*
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns SUCCESS (retry #1)
|
||||
* FollowPath returns FAILURE on the first try triggering the controller recovery
|
||||
* ClearLocalCostmap-Context returns SUCCESS and FollowPath is retried
|
||||
* FollowPath returns FAILURE again and PipelineSequence returns FAILURE
|
||||
* NavigateRecovery triggers RecoveryFallback and GoalUpdated returns FAILURE
|
||||
* RoundRobin triggers Spin which returns FAILURE
|
||||
* RoundRobin triggers Wait which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
*
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns FAILURE (retry #2)
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns FAILURE when retried
|
||||
* PipelineSequence returns FAILURE NavigateRecovery triggers RecoveryFallback
|
||||
* GoalUpdated returns FAILURE and RoundRobin triggers BackUp which returns FAILURE
|
||||
* RoundRobin triggers ClearingActions Sequence which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
*
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns FAILURE (retry #3)
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns FAILURE when retried
|
||||
* PipelineSequence returns FAILURE NavigateRecovery triggers RecoveryFallback
|
||||
* GoalUpdated returns FAILURE and RoundRobin triggers Spin which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
*
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns FAILURE (retry #4)
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns FAILURE when retried
|
||||
* PipelineSequence returns FAILURE NavigateRecovery triggers RecoveryFallback
|
||||
* GoalUpdated returns FAILURE and RoundRobin triggers Wait which returns FAILURE
|
||||
* RoundRobin triggers BackUp which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
*
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns SUCCESS (retry #5)
|
||||
* FollowPath returns FAILURE on the first try triggering the controller recovery
|
||||
* ClearLocalCostmap-Context returns SUCCESS and FollowPath is retried
|
||||
* FollowPath returns FAILURE again and PipelineSequence returns FAILURE
|
||||
* NavigateRecovery triggers RecoveryFallback and GoalUpdated returns FAILURE
|
||||
* RoundRobin triggers ClearingActions Sequence which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
*
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns FAILURE (retry #6)
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns FAILURE when retried
|
||||
* PipelineSequence returns FAILURE and NavigateRecovery finally also returns FAILURE
|
||||
*
|
||||
* The behavior tree should return FAILURE
|
||||
*/
|
||||
TEST_F(BehaviorTreeTestFixture, TestNavigateRecoveryComplex)
|
||||
{
|
||||
// Load behavior tree from file
|
||||
fs::path bt_file = ament_index_cpp::get_package_share_directory("nav2_bt_navigator");
|
||||
bt_file /= "behavior_trees/";
|
||||
bt_file /= "navigate_to_pose_w_replanning_and_recovery.xml";
|
||||
EXPECT_EQ(bt_handler->loadBehaviorTree(bt_file.string()), true);
|
||||
|
||||
// Set ComputePathToPose action server to fail for the first 2 actions
|
||||
std::vector<std::pair<int, int>> plannerFailureRange;
|
||||
plannerFailureRange.emplace_back(std::pair<int, int>(0, 2));
|
||||
plannerFailureRange.emplace_back(std::pair<int, int>(4, 9));
|
||||
plannerFailureRange.emplace_back(std::pair<int, int>(11, 12));
|
||||
server_handler->compute_path_to_pose_server->setFailureRanges(plannerFailureRange);
|
||||
|
||||
// Set FollowPath action server to fail for the first 2 actions
|
||||
std::vector<std::pair<int, int>> controllerFailureRange;
|
||||
controllerFailureRange.emplace_back(std::pair<int, int>(0, 4));
|
||||
server_handler->follow_path_server->setFailureRanges(controllerFailureRange);
|
||||
|
||||
// Set Spin action server to fail for the first action
|
||||
std::vector<std::pair<int, int>> spinFailureRange;
|
||||
spinFailureRange.emplace_back(std::pair<int, int>(0, 1));
|
||||
server_handler->spin_server->setFailureRanges(spinFailureRange);
|
||||
|
||||
// Set Wait action server to fail for the first action
|
||||
std::vector<std::pair<int, int>> waitFailureRange;
|
||||
waitFailureRange.emplace_back(std::pair<int, int>(2, 2));
|
||||
server_handler->wait_server->setFailureRanges(waitFailureRange);
|
||||
|
||||
// Set BackUp action server to fail for the first action
|
||||
std::vector<std::pair<int, int>> backupFailureRange;
|
||||
backupFailureRange.emplace_back(std::pair<int, int>(0, 1));
|
||||
server_handler->backup_server->setFailureRanges(backupFailureRange);
|
||||
|
||||
BT::NodeStatus result = BT::NodeStatus::RUNNING;
|
||||
|
||||
while (result == BT::NodeStatus::RUNNING) {
|
||||
result = bt_handler->tree.tickRoot();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// The final result should be success
|
||||
EXPECT_EQ(result, BT::NodeStatus::FAILURE);
|
||||
|
||||
// ComputePathToPose is called 12 times
|
||||
EXPECT_EQ(server_handler->compute_path_to_pose_server->getGoalCount(), 12);
|
||||
|
||||
// FollowPath is called 4 times
|
||||
EXPECT_EQ(server_handler->follow_path_server->getGoalCount(), 4);
|
||||
|
||||
// Local costmap is cleared 5 times
|
||||
EXPECT_EQ(server_handler->clear_local_costmap_server->getRequestCount(), 5);
|
||||
|
||||
// Global costmap is cleared 8 times
|
||||
EXPECT_EQ(server_handler->clear_global_costmap_server->getRequestCount(), 8);
|
||||
|
||||
// All recovery action servers receive 2 goals
|
||||
EXPECT_EQ(server_handler->spin_server->getGoalCount(), 2);
|
||||
EXPECT_EQ(server_handler->wait_server->getGoalCount(), 2);
|
||||
EXPECT_EQ(server_handler->backup_server->getGoalCount(), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test scenario:
|
||||
*
|
||||
* ComputePathToPose returns FAILURE on the first try triggering the planner recovery
|
||||
* ClearGlobalCostmap-Context returns SUCCESS and ComputePathToPose returns FAILURE when retried
|
||||
* PipelineSequence returns FAILURE and NavigateRecovery triggers RecoveryFallback
|
||||
* GoalUpdated returns FAILURE, RoundRobin triggers ClearingActions Sequence which returns SUCCESS
|
||||
* RoundRobin returns SUCCESS and RecoveryFallback returns SUCCESS
|
||||
* PipelineSequence is triggered again and ComputePathToPose returns SUCCESS
|
||||
* FollowPath returns FAILURE on the first try triggering the controller recovery
|
||||
* ClearLocalCostmap-Context returns SUCCESS and FollowPath is retried
|
||||
* FollowPath returns FAILURE and PipelineSequence returns FAILURE
|
||||
* NavigateRecovery triggers RecoveryFallback which triggers GoalUpdated
|
||||
* GoalUpdated returns FAILURE and RecoveryFallback triggers RoundRobin
|
||||
* RoundRobin triggers Spin which returns RUNNING
|
||||
*
|
||||
* At this point a new goal is updated on the blackboard
|
||||
*
|
||||
* RecoveryFallback triggers GoalUpdated which returns SUCCESS this time
|
||||
* Since GoalUpdated returned SUCCESS, RoundRobin and hence Spin is halted
|
||||
* RecoveryFallback also returns SUCCESS and PipelineSequence is retried
|
||||
* PipelineSequence triggers ComputePathToPose which returns SUCCESS
|
||||
* FollowPath returns SUCCESS and NavigateRecovery finally also returns SUCCESS
|
||||
*
|
||||
* The behavior tree should return SUCCESS
|
||||
*/
|
||||
TEST_F(BehaviorTreeTestFixture, TestRecoverySubtreeGoalUpdated)
|
||||
{
|
||||
// Load behavior tree from file
|
||||
fs::path bt_file = ament_index_cpp::get_package_share_directory("nav2_bt_navigator");
|
||||
bt_file /= "behavior_trees/";
|
||||
bt_file /= "navigate_to_pose_w_replanning_and_recovery.xml";
|
||||
EXPECT_EQ(bt_handler->loadBehaviorTree(bt_file.string()), true);
|
||||
|
||||
// Set ComputePathToPose action server to fail for the first 2 actions
|
||||
std::vector<std::pair<int, int>> plannerFailureRange;
|
||||
plannerFailureRange.emplace_back(std::pair<int, int>(0, 2));
|
||||
server_handler->compute_path_to_pose_server->setFailureRanges(plannerFailureRange);
|
||||
|
||||
// Set FollowPath action server to fail for the first 2 actions
|
||||
std::vector<std::pair<int, int>> controllerFailureRange;
|
||||
controllerFailureRange.emplace_back(std::pair<int, int>(0, 2));
|
||||
server_handler->follow_path_server->setFailureRanges(controllerFailureRange);
|
||||
|
||||
// Set Spin action server to return running for the first action
|
||||
std::vector<std::pair<int, int>> spinRunningRange;
|
||||
spinRunningRange.emplace_back(std::pair<int, int>(1, 1));
|
||||
server_handler->spin_server->setRunningRanges(spinRunningRange);
|
||||
|
||||
BT::NodeStatus result = BT::NodeStatus::RUNNING;
|
||||
|
||||
while (result == BT::NodeStatus::RUNNING) {
|
||||
result = bt_handler->tree.tickRoot();
|
||||
|
||||
// Update goal on blackboard after Spin has been triggered once
|
||||
// to simulate a goal update during a recovery action
|
||||
if (server_handler->spin_server->getGoalCount() > 0) {
|
||||
geometry_msgs::msg::PoseStamped goal;
|
||||
goal.pose.position.x = 1.0;
|
||||
goal.pose.position.y = 1.0;
|
||||
goal.pose.position.z = 1.0;
|
||||
goal.pose.orientation.x = 0.0;
|
||||
goal.pose.orientation.y = 0.0;
|
||||
goal.pose.orientation.z = 0.0;
|
||||
goal.pose.orientation.w = 1.0;
|
||||
bt_handler->blackboard->set<geometry_msgs::msg::PoseStamped>("goal", goal); // NOLINT
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// The final result should be success
|
||||
EXPECT_EQ(result, BT::NodeStatus::SUCCESS);
|
||||
|
||||
// ComputePathToPose is called 4 times
|
||||
EXPECT_EQ(server_handler->compute_path_to_pose_server->getGoalCount(), 4);
|
||||
|
||||
// FollowPath is called 3 times
|
||||
EXPECT_EQ(server_handler->follow_path_server->getGoalCount(), 3);
|
||||
|
||||
// Local costmap is cleared 2 times
|
||||
EXPECT_EQ(server_handler->clear_local_costmap_server->getRequestCount(), 2);
|
||||
|
||||
// Global costmap is cleared 2 times
|
||||
EXPECT_EQ(server_handler->clear_global_costmap_server->getRequestCount(), 2);
|
||||
|
||||
// Spin server receives 1 action
|
||||
EXPECT_EQ(server_handler->spin_server->getGoalCount(), 1);
|
||||
|
||||
// All recovery action servers receive 0 goals
|
||||
EXPECT_EQ(server_handler->wait_server->getGoalCount(), 0);
|
||||
EXPECT_EQ(server_handler->backup_server->getGoalCount(), 0);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
bool all_successful = RUN_ALL_TESTS();
|
||||
return all_successful;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Behavior Test
|
||||
|
||||
Provides some simple tests for behavior plugins.
|
||||
It creates an instance of the stack, with the behavior server loading different behavior plugins, and checks for successful behavior behaviors.
|
||||
@@ -1,23 +0,0 @@
|
||||
set(test_assisted_teleop_behavior test_assisted_teleop_behavior_node)
|
||||
|
||||
ament_add_gtest_executable(${test_assisted_teleop_behavior}
|
||||
test_assisted_teleop_behavior_node.cpp
|
||||
assisted_teleop_behavior_tester.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(${test_assisted_teleop_behavior}
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
ament_add_test(test_assisted_teleop_behavior
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_assisted_teleop_behavior_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_assisted_teleop_behavior}>
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_recovery.xml
|
||||
)
|
||||
-277
@@ -1,277 +0,0 @@
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "assisted_teleop_behavior_tester.hpp"
|
||||
#include "nav2_util/geometry_utils.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::chrono; // NOLINT
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
AssistedTeleopBehaviorTester::AssistedTeleopBehaviorTester()
|
||||
: is_active_(false),
|
||||
initial_pose_received_(false)
|
||||
{
|
||||
node_ = rclcpp::Node::make_shared("assisted_teleop_behavior_test");
|
||||
|
||||
tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
|
||||
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
|
||||
|
||||
client_ptr_ = rclcpp_action::create_client<AssistedTeleop>(
|
||||
node_->get_node_base_interface(),
|
||||
node_->get_node_graph_interface(),
|
||||
node_->get_node_logging_interface(),
|
||||
node_->get_node_waitables_interface(),
|
||||
"assisted_teleop");
|
||||
|
||||
initial_pose_pub_ =
|
||||
node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>("initialpose", 10);
|
||||
|
||||
preempt_pub_ =
|
||||
node_->create_publisher<std_msgs::msg::Empty>("preempt_teleop", 10);
|
||||
|
||||
cmd_vel_pub_ =
|
||||
node_->create_publisher<geometry_msgs::msg::Twist>("cmd_vel_teleop", 10);
|
||||
|
||||
subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
|
||||
"amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
|
||||
std::bind(&AssistedTeleopBehaviorTester::amclPoseCallback, this, std::placeholders::_1));
|
||||
|
||||
filtered_vel_sub_ = node_->create_subscription<geometry_msgs::msg::Twist>(
|
||||
"cmd_vel",
|
||||
rclcpp::SystemDefaultsQoS(),
|
||||
std::bind(&AssistedTeleopBehaviorTester::filteredVelCallback, this, std::placeholders::_1));
|
||||
|
||||
std::string costmap_topic = "/local_costmap/costmap_raw";
|
||||
std::string footprint_topic = "/local_costmap/published_footprint";
|
||||
|
||||
costmap_sub_ = std::make_shared<nav2_costmap_2d::CostmapSubscriber>(
|
||||
node_,
|
||||
costmap_topic);
|
||||
|
||||
footprint_sub_ = std::make_shared<nav2_costmap_2d::FootprintSubscriber>(
|
||||
node_,
|
||||
footprint_topic,
|
||||
*tf_buffer_);
|
||||
|
||||
collision_checker_ = std::make_unique<nav2_costmap_2d::CostmapTopicCollisionChecker>(
|
||||
*costmap_sub_,
|
||||
*footprint_sub_
|
||||
);
|
||||
|
||||
stamp_ = node_->now();
|
||||
}
|
||||
|
||||
AssistedTeleopBehaviorTester::~AssistedTeleopBehaviorTester()
|
||||
{
|
||||
if (is_active_) {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void AssistedTeleopBehaviorTester::activate()
|
||||
{
|
||||
if (is_active_) {
|
||||
throw std::runtime_error("Trying to activate while already active");
|
||||
return;
|
||||
}
|
||||
|
||||
while (!initial_pose_received_) {
|
||||
RCLCPP_WARN(node_->get_logger(), "Initial pose not received");
|
||||
sendInitialPose();
|
||||
std::this_thread::sleep_for(100ms);
|
||||
rclcpp::spin_some(node_);
|
||||
}
|
||||
|
||||
// Wait for lifecycle_manager_navigation to activate behavior_server
|
||||
std::this_thread::sleep_for(10s);
|
||||
|
||||
if (!client_ptr_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action client not initialized");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client_ptr_->wait_for_action_server(10s)) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action server not available after waiting");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Assisted Teleop action server is ready");
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
void AssistedTeleopBehaviorTester::deactivate()
|
||||
{
|
||||
if (!is_active_) {
|
||||
throw std::runtime_error("Trying to deactivate while already inactive");
|
||||
}
|
||||
is_active_ = false;
|
||||
}
|
||||
|
||||
bool AssistedTeleopBehaviorTester::defaultAssistedTeleopTest(
|
||||
const float lin_vel,
|
||||
const float ang_vel)
|
||||
{
|
||||
if (!is_active_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Not activated");
|
||||
return false;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "Sending goal");
|
||||
|
||||
auto goal_handle_future = client_ptr_->async_send_goal(nav2_msgs::action::AssistedTeleop::Goal());
|
||||
|
||||
if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<AssistedTeleop>::SharedPtr goal_handle = goal_handle_future.get();
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the server to be done with the goal
|
||||
auto result_future = client_ptr_->async_get_result(goal_handle);
|
||||
|
||||
rclcpp::Rate r(1);
|
||||
|
||||
counter_ = 0;
|
||||
auto start_time = std::chrono::system_clock::now();
|
||||
while (rclcpp::ok()) {
|
||||
geometry_msgs::msg::Twist cmd_vel = geometry_msgs::msg::Twist();
|
||||
cmd_vel.linear.x = lin_vel;
|
||||
cmd_vel.angular.z = ang_vel;
|
||||
cmd_vel_pub_->publish(cmd_vel);
|
||||
|
||||
if (counter_ > 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
if (current_time - start_time > 25s) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Exceeded Timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp::spin_some(node_);
|
||||
r.sleep();
|
||||
}
|
||||
|
||||
auto preempt_msg = std_msgs::msg::Empty();
|
||||
preempt_pub_->publish(preempt_msg);
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "Waiting for result");
|
||||
if (rclcpp::spin_until_future_complete(node_, result_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "get result call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<AssistedTeleop>::WrappedResult
|
||||
wrapped_result = result_future.get();
|
||||
|
||||
switch (wrapped_result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED: break;
|
||||
case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was aborted");
|
||||
return false;
|
||||
case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was canceled");
|
||||
return false;
|
||||
default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
|
||||
return false;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "result received");
|
||||
|
||||
geometry_msgs::msg::PoseStamped current_pose;
|
||||
if (!nav2_util::getCurrentPose(current_pose, *tf_buffer_, "odom")) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Current robot pose is not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
geometry_msgs::msg::Pose2D pose_2d;
|
||||
pose_2d.x = current_pose.pose.position.x;
|
||||
pose_2d.y = current_pose.pose.position.y;
|
||||
pose_2d.theta = tf2::getYaw(current_pose.pose.orientation);
|
||||
|
||||
if (!collision_checker_->isCollisionFree(pose_2d)) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Ended in collision");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssistedTeleopBehaviorTester::sendInitialPose()
|
||||
{
|
||||
geometry_msgs::msg::PoseWithCovarianceStamped pose;
|
||||
pose.header.frame_id = "map";
|
||||
pose.header.stamp = stamp_;
|
||||
pose.pose.pose.position.x = -2.0;
|
||||
pose.pose.pose.position.y = -0.5;
|
||||
pose.pose.pose.position.z = 0.0;
|
||||
pose.pose.pose.orientation.x = 0.0;
|
||||
pose.pose.pose.orientation.y = 0.0;
|
||||
pose.pose.pose.orientation.z = 0.0;
|
||||
pose.pose.pose.orientation.w = 1.0;
|
||||
for (int i = 0; i < 35; i++) {
|
||||
pose.pose.covariance[i] = 0.0;
|
||||
}
|
||||
pose.pose.covariance[0] = 0.08;
|
||||
pose.pose.covariance[7] = 0.08;
|
||||
pose.pose.covariance[35] = 0.05;
|
||||
|
||||
initial_pose_pub_->publish(pose);
|
||||
RCLCPP_INFO(node_->get_logger(), "Sent initial pose");
|
||||
}
|
||||
|
||||
void AssistedTeleopBehaviorTester::amclPoseCallback(
|
||||
const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr)
|
||||
{
|
||||
initial_pose_received_ = true;
|
||||
}
|
||||
|
||||
void AssistedTeleopBehaviorTester::filteredVelCallback(
|
||||
geometry_msgs::msg::Twist::SharedPtr msg)
|
||||
{
|
||||
if (msg->linear.x == 0.0f) {
|
||||
counter_++;
|
||||
} else {
|
||||
counter_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#ifndef BEHAVIORS__ASSISTED_TELEOP__ASSISTED_TELEOP_BEHAVIOR_TESTER_HPP_
|
||||
#define BEHAVIORS__ASSISTED_TELEOP__ASSISTED_TELEOP_BEHAVIOR_TESTER_HPP_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
#include "angles/angles.h"
|
||||
#include "geometry_msgs/msg/pose_stamped.hpp"
|
||||
#include "geometry_msgs/msg/pose_with_covariance_stamped.hpp"
|
||||
#include "geometry_msgs/msg/twist.hpp"
|
||||
#include "geometry_msgs/msg/pose2_d.hpp"
|
||||
#include "nav2_costmap_2d/costmap_topic_collision_checker.hpp"
|
||||
#include "nav2_msgs/action/assisted_teleop.hpp"
|
||||
#include "nav2_util/node_thread.hpp"
|
||||
#include "nav2_util/robot_utils.hpp"
|
||||
#include "rclcpp_action/rclcpp_action.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "std_msgs/msg/empty.hpp"
|
||||
|
||||
#include "tf2/utils.h"
|
||||
#include "tf2_ros/buffer.h"
|
||||
#include "tf2_ros/transform_listener.h"
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
class AssistedTeleopBehaviorTester
|
||||
{
|
||||
public:
|
||||
using AssistedTeleop = nav2_msgs::action::AssistedTeleop;
|
||||
|
||||
AssistedTeleopBehaviorTester();
|
||||
~AssistedTeleopBehaviorTester();
|
||||
|
||||
// Runs a single test with given target yaw
|
||||
bool defaultAssistedTeleopTest(
|
||||
const float lin_vel,
|
||||
const float ang_vel);
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate();
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return is_active_;
|
||||
}
|
||||
|
||||
private:
|
||||
void sendInitialPose();
|
||||
|
||||
void amclPoseCallback(geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr);
|
||||
|
||||
void filteredVelCallback(geometry_msgs::msg::Twist::SharedPtr msg);
|
||||
|
||||
unsigned int counter_;
|
||||
bool is_active_;
|
||||
bool initial_pose_received_;
|
||||
rclcpp::Time stamp_;
|
||||
|
||||
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
|
||||
// Publishers
|
||||
rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr initial_pose_pub_;
|
||||
rclcpp::Publisher<std_msgs::msg::Empty>::SharedPtr preempt_pub_;
|
||||
rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr cmd_vel_pub_;
|
||||
|
||||
// Subscribers
|
||||
rclcpp::Subscription<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr subscription_;
|
||||
rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr filtered_vel_sub_;
|
||||
|
||||
// Action client to call AssistedTeleop action
|
||||
rclcpp_action::Client<AssistedTeleop>::SharedPtr client_ptr_;
|
||||
|
||||
// collision checking
|
||||
std::shared_ptr<nav2_costmap_2d::CostmapSubscriber> costmap_sub_;
|
||||
std::shared_ptr<nav2_costmap_2d::FootprintSubscriber> footprint_sub_;
|
||||
std::unique_ptr<nav2_costmap_2d::CostmapTopicCollisionChecker> collision_checker_;
|
||||
};
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
|
||||
#endif // BEHAVIORS__ASSISTED_TELEOP__ASSISTED_TELEOP_BEHAVIOR_TESTER_HPP_
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
#! /usr/bin/env python3
|
||||
# Copyright (c) 2012 Samsung Research America
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import ExecuteProcess, IncludeLaunchDescription, SetEnvironmentVariable
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
map_yaml_file = os.getenv('TEST_MAP')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
bt_navigator_xml = os.path.join(get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees',
|
||||
os.getenv('BT_NAVIGATOR_XML'))
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
params_file = os.path.join(bringup_dir, 'params/nav2_params.yaml')
|
||||
|
||||
# Replace the `use_astar` setting on the params file
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key='',
|
||||
param_rewrites='',
|
||||
convert_types=True)
|
||||
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
# Launch gazebo server for simulation
|
||||
ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so',
|
||||
'--minimal_comms', world],
|
||||
output='screen'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(
|
||||
os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
|
||||
launch_arguments={
|
||||
'map': map_yaml_file,
|
||||
'use_sim_time': 'True',
|
||||
'params_file': configured_params,
|
||||
'bt_xml_file': bt_navigator_xml,
|
||||
'autostart': 'True'}.items()),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
testExecutable = os.getenv('TEST_EXECUTABLE')
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[testExecutable],
|
||||
name='test_assisted_teleop_behavior_node',
|
||||
output='screen')
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2022 Joshua Wallace
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "assisted_teleop_behavior_tester.hpp"
|
||||
#include "nav2_msgs/action/back_up.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using nav2_system_tests::AssistedTeleopBehaviorTester;
|
||||
|
||||
struct TestParameters
|
||||
{
|
||||
float lin_vel;
|
||||
float ang_vel;
|
||||
};
|
||||
|
||||
|
||||
std::string testNameGenerator(const testing::TestParamInfo<TestParameters> &)
|
||||
{
|
||||
static int test_index = 0;
|
||||
std::string name = "AssistedTeleopTest" + std::to_string(test_index);
|
||||
++test_index;
|
||||
return name;
|
||||
}
|
||||
|
||||
class AssistedTeleopBehaviorTestFixture
|
||||
: public ::testing::TestWithParam<TestParameters>
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
assisted_teleop_behavior_tester = new AssistedTeleopBehaviorTester();
|
||||
if (!assisted_teleop_behavior_tester->isActive()) {
|
||||
assisted_teleop_behavior_tester->activate();
|
||||
}
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
delete assisted_teleop_behavior_tester;
|
||||
assisted_teleop_behavior_tester = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
static AssistedTeleopBehaviorTester * assisted_teleop_behavior_tester;
|
||||
};
|
||||
|
||||
AssistedTeleopBehaviorTester *
|
||||
AssistedTeleopBehaviorTestFixture::assisted_teleop_behavior_tester = nullptr;
|
||||
|
||||
TEST_P(AssistedTeleopBehaviorTestFixture, testAssistedTeleopBehavior)
|
||||
{
|
||||
auto test_params = GetParam();
|
||||
|
||||
if (!assisted_teleop_behavior_tester->isActive()) {
|
||||
assisted_teleop_behavior_tester->activate();
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
success = assisted_teleop_behavior_tester->defaultAssistedTeleopTest(
|
||||
test_params.lin_vel,
|
||||
test_params.ang_vel);
|
||||
|
||||
EXPECT_TRUE(success);
|
||||
}
|
||||
|
||||
std::vector<TestParameters> test_params = {TestParameters{-0.1, 0.0},
|
||||
TestParameters{0.35, 0.05}};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
TestAssistedTeleopBehavior,
|
||||
AssistedTeleopBehaviorTestFixture,
|
||||
::testing::Values(
|
||||
test_params[0],
|
||||
test_params[1]),
|
||||
testNameGenerator
|
||||
);
|
||||
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// initialize ROS
|
||||
rclcpp::init(argc, argv);
|
||||
|
||||
bool all_successful = RUN_ALL_TESTS();
|
||||
|
||||
// shutdown ROS
|
||||
rclcpp::shutdown();
|
||||
|
||||
return all_successful;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
set(test_backup_behavior test_backup_behavior_node)
|
||||
|
||||
ament_add_gtest_executable(${test_backup_behavior}
|
||||
test_backup_behavior_node.cpp
|
||||
backup_behavior_tester.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(${test_backup_behavior}
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
ament_add_test(test_backup_recovery
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_backup_behavior_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_backup_behavior}>
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_recovery.xml
|
||||
)
|
||||
@@ -1,223 +0,0 @@
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "backup_behavior_tester.hpp"
|
||||
#include "nav2_util/geometry_utils.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::chrono; // NOLINT
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
BackupBehaviorTester::BackupBehaviorTester()
|
||||
: is_active_(false),
|
||||
initial_pose_received_(false)
|
||||
{
|
||||
rclcpp::NodeOptions options;
|
||||
options.parameter_overrides({{"use_sim_time", true}});
|
||||
node_ = rclcpp::Node::make_shared("backup_behavior_test", options);
|
||||
|
||||
tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
|
||||
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
|
||||
|
||||
client_ptr_ = rclcpp_action::create_client<BackUp>(
|
||||
node_->get_node_base_interface(),
|
||||
node_->get_node_graph_interface(),
|
||||
node_->get_node_logging_interface(),
|
||||
node_->get_node_waitables_interface(),
|
||||
"backup");
|
||||
|
||||
publisher_ =
|
||||
node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>("initialpose", 10);
|
||||
|
||||
subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
|
||||
"amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
|
||||
std::bind(&BackupBehaviorTester::amclPoseCallback, this, std::placeholders::_1));
|
||||
|
||||
stamp_ = node_->now();
|
||||
}
|
||||
|
||||
BackupBehaviorTester::~BackupBehaviorTester()
|
||||
{
|
||||
if (is_active_) {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void BackupBehaviorTester::activate()
|
||||
{
|
||||
if (is_active_) {
|
||||
throw std::runtime_error("Trying to activate while already active");
|
||||
return;
|
||||
}
|
||||
|
||||
while (!initial_pose_received_) {
|
||||
RCLCPP_WARN(node_->get_logger(), "Initial pose not received");
|
||||
sendInitialPose();
|
||||
std::this_thread::sleep_for(100ms);
|
||||
rclcpp::spin_some(node_);
|
||||
}
|
||||
|
||||
// Wait for lifecycle_manager_navigation to activate behavior_server
|
||||
std::this_thread::sleep_for(10s);
|
||||
|
||||
if (!client_ptr_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action client not initialized");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client_ptr_->wait_for_action_server(10s)) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action server not available after waiting");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Backup action server is ready");
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
void BackupBehaviorTester::deactivate()
|
||||
{
|
||||
if (!is_active_) {
|
||||
throw std::runtime_error("Trying to deactivate while already inactive");
|
||||
}
|
||||
is_active_ = false;
|
||||
}
|
||||
|
||||
bool BackupBehaviorTester::defaultBackupBehaviorTest(
|
||||
const BackUp::Goal goal_msg,
|
||||
const double tolerance)
|
||||
{
|
||||
if (!is_active_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Not activated");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sleep to let behavior server be ready for serving in multiple runs
|
||||
std::this_thread::sleep_for(5s);
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Sending goal");
|
||||
|
||||
geometry_msgs::msg::PoseStamped initial_pose;
|
||||
if (!nav2_util::getCurrentPose(initial_pose, *tf_buffer_, "odom")) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Current robot pose is not available.");
|
||||
return false;
|
||||
}
|
||||
RCLCPP_INFO(node_->get_logger(), "Found current robot pose");
|
||||
|
||||
auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
|
||||
|
||||
if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<BackUp>::SharedPtr goal_handle = goal_handle_future.get();
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the server to be done with the goal
|
||||
auto result_future = client_ptr_->async_get_result(goal_handle);
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "Waiting for result");
|
||||
if (rclcpp::spin_until_future_complete(node_, result_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "get result call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<BackUp>::WrappedResult wrapped_result = result_future.get();
|
||||
|
||||
switch (wrapped_result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED: break;
|
||||
case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was aborted");
|
||||
return false;
|
||||
case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was canceled");
|
||||
return false;
|
||||
default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
|
||||
return false;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "result received");
|
||||
|
||||
geometry_msgs::msg::PoseStamped current_pose;
|
||||
if (!nav2_util::getCurrentPose(current_pose, *tf_buffer_, "odom")) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Current robot pose is not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
double dist = nav2_util::geometry_utils::euclidean_distance(initial_pose, current_pose);
|
||||
|
||||
if (fabs(dist) > fabs(goal_msg.target.x) + tolerance) {
|
||||
RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Distance from goal is %lf (tolerance %lf)",
|
||||
fabs(dist - goal_msg.target.x), tolerance);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BackupBehaviorTester::sendInitialPose()
|
||||
{
|
||||
geometry_msgs::msg::PoseWithCovarianceStamped pose;
|
||||
pose.header.frame_id = "map";
|
||||
pose.header.stamp = stamp_;
|
||||
pose.pose.pose.position.x = -2.0;
|
||||
pose.pose.pose.position.y = -0.5;
|
||||
pose.pose.pose.position.z = 0.0;
|
||||
pose.pose.pose.orientation.x = 0.0;
|
||||
pose.pose.pose.orientation.y = 0.0;
|
||||
pose.pose.pose.orientation.z = 0.0;
|
||||
pose.pose.pose.orientation.w = 1.0;
|
||||
for (int i = 0; i < 35; i++) {
|
||||
pose.pose.covariance[i] = 0.0;
|
||||
}
|
||||
pose.pose.covariance[0] = 0.08;
|
||||
pose.pose.covariance[7] = 0.08;
|
||||
pose.pose.covariance[35] = 0.05;
|
||||
|
||||
publisher_->publish(pose);
|
||||
RCLCPP_INFO(node_->get_logger(), "Sent initial pose");
|
||||
}
|
||||
|
||||
void BackupBehaviorTester::amclPoseCallback(
|
||||
const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr)
|
||||
{
|
||||
initial_pose_received_ = true;
|
||||
}
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#ifndef BEHAVIORS__BACKUP__BACKUP_BEHAVIOR_TESTER_HPP_
|
||||
#define BEHAVIORS__BACKUP__BACKUP_BEHAVIOR_TESTER_HPP_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp_action/rclcpp_action.hpp"
|
||||
#include "angles/angles.h"
|
||||
#include "nav2_msgs/action/back_up.hpp"
|
||||
#include "nav2_util/robot_utils.hpp"
|
||||
#include "nav2_util/node_thread.hpp"
|
||||
#include "geometry_msgs/msg/pose_stamped.hpp"
|
||||
#include "geometry_msgs/msg/pose_with_covariance_stamped.hpp"
|
||||
|
||||
#include "tf2/utils.h"
|
||||
#include "tf2_ros/buffer.h"
|
||||
#include "tf2_ros/transform_listener.h"
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
class BackupBehaviorTester
|
||||
{
|
||||
public:
|
||||
using BackUp = nav2_msgs::action::BackUp;
|
||||
using GoalHandleBackup = rclcpp_action::ClientGoalHandle<BackUp>;
|
||||
|
||||
BackupBehaviorTester();
|
||||
~BackupBehaviorTester();
|
||||
|
||||
// Runs a single test with given target yaw
|
||||
bool defaultBackupBehaviorTest(
|
||||
const BackUp::Goal goal_msg,
|
||||
const double tolerance);
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate();
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return is_active_;
|
||||
}
|
||||
|
||||
private:
|
||||
void sendInitialPose();
|
||||
|
||||
void amclPoseCallback(geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr);
|
||||
|
||||
bool is_active_;
|
||||
bool initial_pose_received_;
|
||||
rclcpp::Time stamp_;
|
||||
|
||||
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
|
||||
// Publisher to publish initial pose
|
||||
rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr publisher_;
|
||||
|
||||
// Subscriber for amcl pose
|
||||
rclcpp::Subscription<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr subscription_;
|
||||
|
||||
// Action client to call Backup action
|
||||
rclcpp_action::Client<BackUp>::SharedPtr client_ptr_;
|
||||
};
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
|
||||
#endif // BEHAVIORS__BACKUP__BACKUP_BEHAVIOR_TESTER_HPP_
|
||||
@@ -1,102 +0,0 @@
|
||||
#! /usr/bin/env python3
|
||||
# Copyright (c) 2012 Samsung Research America
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import ExecuteProcess, IncludeLaunchDescription, SetEnvironmentVariable
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
map_yaml_file = os.getenv('TEST_MAP')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
bt_navigator_xml = os.path.join(get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees',
|
||||
os.getenv('BT_NAVIGATOR_XML'))
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
params_file = os.path.join(bringup_dir, 'params/nav2_params.yaml')
|
||||
|
||||
# Replace the `use_astar` setting on the params file
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key='',
|
||||
param_rewrites='',
|
||||
convert_types=True)
|
||||
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
# Launch gazebo server for simulation
|
||||
ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so',
|
||||
'--minimal_comms', world],
|
||||
output='screen'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(
|
||||
os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
|
||||
launch_arguments={
|
||||
'map': map_yaml_file,
|
||||
'use_sim_time': 'True',
|
||||
'params_file': configured_params,
|
||||
'bt_xml_file': bt_navigator_xml,
|
||||
'autostart': 'True'}.items()),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
testExecutable = os.getenv('TEST_EXECUTABLE')
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[testExecutable], name='test_backup_behavior_node', output='screen',
|
||||
)
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,128 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2022 Joshua Wallace
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "backup_behavior_tester.hpp"
|
||||
#include "nav2_msgs/action/back_up.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using nav2_system_tests::BackupBehaviorTester;
|
||||
|
||||
struct TestParameters
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float speed;
|
||||
float tolerance;
|
||||
};
|
||||
|
||||
|
||||
std::string testNameGenerator(const testing::TestParamInfo<TestParameters> &)
|
||||
{
|
||||
static int test_index = 0;
|
||||
std::string name = "BackUpTest" + std::to_string(test_index);
|
||||
++test_index;
|
||||
return name;
|
||||
}
|
||||
|
||||
class BackupBehaviorTestFixture
|
||||
: public ::testing::TestWithParam<TestParameters>
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
backup_behavior_tester = new BackupBehaviorTester();
|
||||
if (!backup_behavior_tester->isActive()) {
|
||||
backup_behavior_tester->activate();
|
||||
}
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
delete backup_behavior_tester;
|
||||
backup_behavior_tester = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
static BackupBehaviorTester * backup_behavior_tester;
|
||||
};
|
||||
|
||||
BackupBehaviorTester * BackupBehaviorTestFixture::backup_behavior_tester = nullptr;
|
||||
|
||||
TEST_P(BackupBehaviorTestFixture, testBackupBehavior)
|
||||
{
|
||||
auto test_params = GetParam();
|
||||
auto goal = nav2_msgs::action::BackUp::Goal();
|
||||
goal.target.x = test_params.x;
|
||||
goal.target.y = test_params.y;
|
||||
goal.speed = test_params.speed;
|
||||
float tolerance = test_params.tolerance;
|
||||
|
||||
if (!backup_behavior_tester->isActive()) {
|
||||
backup_behavior_tester->activate();
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
success = backup_behavior_tester->defaultBackupBehaviorTest(goal, tolerance);
|
||||
|
||||
float dist_to_obstacle = 2.0f;
|
||||
|
||||
if ( ((dist_to_obstacle - std::fabs(test_params.x)) < std::fabs(goal.speed)) ||
|
||||
std::fabs(goal.target.y) > 0)
|
||||
{
|
||||
EXPECT_FALSE(success);
|
||||
} else {
|
||||
EXPECT_TRUE(success);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TestParameters> test_params = {TestParameters{-0.05, 0.0, -0.2, 0.01},
|
||||
TestParameters{-0.05, 0.1, -0.2, 0.01},
|
||||
TestParameters{-2.0, 0.0, -0.2, 0.1}};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BackupBehaviorTests,
|
||||
BackupBehaviorTestFixture,
|
||||
::testing::Values(
|
||||
test_params[0],
|
||||
test_params[1],
|
||||
test_params[2]),
|
||||
testNameGenerator
|
||||
);
|
||||
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// initialize ROS
|
||||
rclcpp::init(argc, argv);
|
||||
|
||||
bool all_successful = RUN_ALL_TESTS();
|
||||
|
||||
// shutdown ROS
|
||||
rclcpp::shutdown();
|
||||
|
||||
return all_successful;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
set(test_drive_on_heading_behavior test_drive_on_heading_behavior_node)
|
||||
|
||||
ament_add_gtest_executable(${test_drive_on_heading_behavior}
|
||||
test_drive_on_heading_behavior_node.cpp
|
||||
drive_on_heading_behavior_tester.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(${test_drive_on_heading_behavior}
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
ament_add_test(test_drive_on_heading_recovery
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_drive_on_heading_behavior_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_drive_on_heading_behavior}>
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_recovery.xml
|
||||
)
|
||||
-224
@@ -1,224 +0,0 @@
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "drive_on_heading_behavior_tester.hpp"
|
||||
#include "nav2_util/geometry_utils.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::chrono; // NOLINT
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
DriveOnHeadingBehaviorTester::DriveOnHeadingBehaviorTester()
|
||||
: is_active_(false),
|
||||
initial_pose_received_(false)
|
||||
{
|
||||
rclcpp::NodeOptions options;
|
||||
options.parameter_overrides({{"use_sim_time", true}});
|
||||
node_ = rclcpp::Node::make_shared("DriveOnHeading_behavior_test", options);
|
||||
|
||||
tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
|
||||
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
|
||||
|
||||
client_ptr_ = rclcpp_action::create_client<DriveOnHeading>(
|
||||
node_->get_node_base_interface(),
|
||||
node_->get_node_graph_interface(),
|
||||
node_->get_node_logging_interface(),
|
||||
node_->get_node_waitables_interface(),
|
||||
"drive_on_heading");
|
||||
|
||||
publisher_ =
|
||||
node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>("initialpose", 10);
|
||||
|
||||
subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
|
||||
"amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
|
||||
std::bind(&DriveOnHeadingBehaviorTester::amclPoseCallback, this, std::placeholders::_1));
|
||||
|
||||
stamp_ = node_->now();
|
||||
}
|
||||
|
||||
DriveOnHeadingBehaviorTester::~DriveOnHeadingBehaviorTester()
|
||||
{
|
||||
if (is_active_) {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void DriveOnHeadingBehaviorTester::activate()
|
||||
{
|
||||
if (is_active_) {
|
||||
throw std::runtime_error("Trying to activate while already active");
|
||||
return;
|
||||
}
|
||||
|
||||
while (!initial_pose_received_) {
|
||||
RCLCPP_WARN(node_->get_logger(), "Initial pose not received");
|
||||
sendInitialPose();
|
||||
std::this_thread::sleep_for(100ms);
|
||||
rclcpp::spin_some(node_);
|
||||
}
|
||||
|
||||
// Wait for lifecycle_manager_navigation to activate behavior_server
|
||||
std::this_thread::sleep_for(10s);
|
||||
|
||||
if (!client_ptr_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action client not initialized");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client_ptr_->wait_for_action_server(10s)) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action server not available after waiting");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "DriveOnHeading action server is ready");
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
void DriveOnHeadingBehaviorTester::deactivate()
|
||||
{
|
||||
if (!is_active_) {
|
||||
throw std::runtime_error("Trying to deactivate while already inactive");
|
||||
}
|
||||
is_active_ = false;
|
||||
}
|
||||
|
||||
bool DriveOnHeadingBehaviorTester::defaultDriveOnHeadingBehaviorTest(
|
||||
const DriveOnHeading::Goal goal_msg,
|
||||
const double tolerance)
|
||||
{
|
||||
if (!is_active_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Not activated");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sleep to let behavior server be ready for serving in multiple runs
|
||||
std::this_thread::sleep_for(5s);
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Sending goal");
|
||||
|
||||
geometry_msgs::msg::PoseStamped initial_pose;
|
||||
if (!nav2_util::getCurrentPose(initial_pose, *tf_buffer_, "odom")) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Current robot pose is not available.");
|
||||
return false;
|
||||
}
|
||||
RCLCPP_INFO(node_->get_logger(), "Found current robot pose");
|
||||
|
||||
auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
|
||||
|
||||
if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<DriveOnHeading>::SharedPtr goal_handle = goal_handle_future.get();
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the server to be done with the goal
|
||||
auto result_future = client_ptr_->async_get_result(goal_handle);
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "Waiting for result");
|
||||
if (rclcpp::spin_until_future_complete(node_, result_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "get result call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<DriveOnHeading>::WrappedResult wrapped_result =
|
||||
result_future.get();
|
||||
|
||||
switch (wrapped_result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED: break;
|
||||
case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was aborted");
|
||||
return false;
|
||||
case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was canceled");
|
||||
return false;
|
||||
default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
|
||||
return false;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "result received");
|
||||
|
||||
geometry_msgs::msg::PoseStamped current_pose;
|
||||
if (!nav2_util::getCurrentPose(current_pose, *tf_buffer_, "odom")) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Current robot pose is not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
double dist = nav2_util::geometry_utils::euclidean_distance(initial_pose, current_pose);
|
||||
|
||||
if (fabs(dist) > fabs(goal_msg.target.x) + tolerance) {
|
||||
RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Distance from goal is %lf (tolerance %lf)",
|
||||
fabs(dist - goal_msg.target.x), tolerance);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DriveOnHeadingBehaviorTester::sendInitialPose()
|
||||
{
|
||||
geometry_msgs::msg::PoseWithCovarianceStamped pose;
|
||||
pose.header.frame_id = "map";
|
||||
pose.header.stamp = stamp_;
|
||||
pose.pose.pose.position.x = -2.0;
|
||||
pose.pose.pose.position.y = -0.5;
|
||||
pose.pose.pose.position.z = 0.0;
|
||||
pose.pose.pose.orientation.x = 0.0;
|
||||
pose.pose.pose.orientation.y = 0.0;
|
||||
pose.pose.pose.orientation.z = 0.0;
|
||||
pose.pose.pose.orientation.w = 1.0;
|
||||
for (int i = 0; i < 35; i++) {
|
||||
pose.pose.covariance[i] = 0.0;
|
||||
}
|
||||
pose.pose.covariance[0] = 0.08;
|
||||
pose.pose.covariance[7] = 0.08;
|
||||
pose.pose.covariance[35] = 0.05;
|
||||
|
||||
publisher_->publish(pose);
|
||||
RCLCPP_INFO(node_->get_logger(), "Sent initial pose");
|
||||
}
|
||||
|
||||
void DriveOnHeadingBehaviorTester::amclPoseCallback(
|
||||
const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr)
|
||||
{
|
||||
initial_pose_received_ = true;
|
||||
}
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
-90
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#ifndef BEHAVIORS__DRIVE_ON_HEADING__DRIVE_ON_HEADING_BEHAVIOR_TESTER_HPP_
|
||||
#define BEHAVIORS__DRIVE_ON_HEADING__DRIVE_ON_HEADING_BEHAVIOR_TESTER_HPP_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp_action/rclcpp_action.hpp"
|
||||
#include "angles/angles.h"
|
||||
#include "nav2_msgs/action/drive_on_heading.hpp"
|
||||
#include "nav2_util/robot_utils.hpp"
|
||||
#include "nav2_util/node_thread.hpp"
|
||||
#include "geometry_msgs/msg/pose_stamped.hpp"
|
||||
#include "geometry_msgs/msg/pose_with_covariance_stamped.hpp"
|
||||
|
||||
#include "tf2/utils.h"
|
||||
#include "tf2_ros/buffer.h"
|
||||
#include "tf2_ros/transform_listener.h"
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
class DriveOnHeadingBehaviorTester
|
||||
{
|
||||
public:
|
||||
using DriveOnHeading = nav2_msgs::action::DriveOnHeading;
|
||||
using GoalHandleDriveOnHeading = rclcpp_action::ClientGoalHandle<DriveOnHeading>;
|
||||
|
||||
DriveOnHeadingBehaviorTester();
|
||||
~DriveOnHeadingBehaviorTester();
|
||||
|
||||
// Runs a single test with given target yaw
|
||||
bool defaultDriveOnHeadingBehaviorTest(
|
||||
const DriveOnHeading::Goal goal_msg,
|
||||
double tolerance);
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate();
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return is_active_;
|
||||
}
|
||||
|
||||
private:
|
||||
void sendInitialPose();
|
||||
|
||||
void amclPoseCallback(geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr);
|
||||
|
||||
bool is_active_;
|
||||
bool initial_pose_received_;
|
||||
rclcpp::Time stamp_;
|
||||
|
||||
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
|
||||
// Publisher to publish initial pose
|
||||
rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr publisher_;
|
||||
|
||||
// Subscriber for amcl pose
|
||||
rclcpp::Subscription<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr subscription_;
|
||||
|
||||
// Action client to call DriveOnHeading action
|
||||
rclcpp_action::Client<DriveOnHeading>::SharedPtr client_ptr_;
|
||||
};
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
|
||||
#endif // BEHAVIORS__DRIVE_ON_HEADING__DRIVE_ON_HEADING_BEHAVIOR_TESTER_HPP_
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
#! /usr/bin/env python3
|
||||
# Copyright (c) 2012 Samsung Research America
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import ExecuteProcess, IncludeLaunchDescription, SetEnvironmentVariable
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
map_yaml_file = os.getenv('TEST_MAP')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
bt_navigator_xml = os.path.join(get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees',
|
||||
os.getenv('BT_NAVIGATOR_XML'))
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
params_file = os.path.join(bringup_dir, 'params/nav2_params.yaml')
|
||||
|
||||
# Replace the `use_astar` setting on the params file
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key='',
|
||||
param_rewrites='',
|
||||
convert_types=True)
|
||||
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
# Launch gazebo server for simulation
|
||||
ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so',
|
||||
'--minimal_comms', world],
|
||||
output='screen'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(
|
||||
os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
|
||||
launch_arguments={
|
||||
'map': map_yaml_file,
|
||||
'use_sim_time': 'True',
|
||||
'params_file': configured_params,
|
||||
'bt_xml_file': bt_navigator_xml,
|
||||
'autostart': 'True'}.items()),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
testExecutable = os.getenv('TEST_EXECUTABLE')
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[testExecutable],
|
||||
name='test_drive_on_heading_behavior_node',
|
||||
output='screen')
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "drive_on_heading_behavior_tester.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using nav2_system_tests::DriveOnHeadingBehaviorTester;
|
||||
|
||||
struct TestParameters
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float speed;
|
||||
float time_allowance;
|
||||
float tolerance;
|
||||
};
|
||||
|
||||
std::string testNameGenerator(const testing::TestParamInfo<TestParameters> &)
|
||||
{
|
||||
static int test_index = 0;
|
||||
std::string name = "DriveOnHeadingTest" + std::to_string(test_index);
|
||||
++test_index;
|
||||
return name;
|
||||
}
|
||||
|
||||
class DriveOnHeadingBehaviorTestFixture
|
||||
: public ::testing::TestWithParam<TestParameters>
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
drive_on_heading_behavior_tester = new DriveOnHeadingBehaviorTester();
|
||||
if (!drive_on_heading_behavior_tester->isActive()) {
|
||||
drive_on_heading_behavior_tester->activate();
|
||||
}
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
delete drive_on_heading_behavior_tester;
|
||||
drive_on_heading_behavior_tester = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
static DriveOnHeadingBehaviorTester * drive_on_heading_behavior_tester;
|
||||
};
|
||||
|
||||
DriveOnHeadingBehaviorTester * DriveOnHeadingBehaviorTestFixture::drive_on_heading_behavior_tester =
|
||||
nullptr;
|
||||
|
||||
TEST_P(DriveOnHeadingBehaviorTestFixture, testBackupBehavior)
|
||||
{
|
||||
auto test_params = GetParam();
|
||||
auto goal = nav2_msgs::action::DriveOnHeading::Goal();
|
||||
goal.target.x = test_params.x;
|
||||
goal.target.y = test_params.y;
|
||||
goal.speed = test_params.speed;
|
||||
goal.time_allowance.sec = test_params.time_allowance;
|
||||
float tolerance = test_params.tolerance;
|
||||
|
||||
if (!drive_on_heading_behavior_tester->isActive()) {
|
||||
drive_on_heading_behavior_tester->activate();
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
success = drive_on_heading_behavior_tester->defaultDriveOnHeadingBehaviorTest(
|
||||
goal,
|
||||
tolerance);
|
||||
|
||||
float dist_to_obstacle = 2.0f;
|
||||
if ( ((dist_to_obstacle - std::fabs(test_params.x)) < std::fabs(goal.speed)) ||
|
||||
std::fabs(goal.target.y) > 0 ||
|
||||
goal.time_allowance.sec < 2.0 ||
|
||||
!((goal.target.x > 0.0) == (goal.speed > 0.0)))
|
||||
{
|
||||
EXPECT_FALSE(success);
|
||||
} else {
|
||||
EXPECT_TRUE(success);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TestParameters> test_params = {TestParameters{-0.05, 0.0, -0.2, 10.0, 0.01},
|
||||
TestParameters{-0.05, 0.1, -0.2, 10.0, 0.01},
|
||||
TestParameters{-2.0, 0.0, -0.2, 10.0, 0.1},
|
||||
TestParameters{-0.05, 0.0, -0.01, 1.0, 0.01},
|
||||
TestParameters{0.05, 0.0, -0.2, 10.0, 0.01}};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DriveOnHeadingBehaviorTests,
|
||||
DriveOnHeadingBehaviorTestFixture,
|
||||
::testing::Values(
|
||||
test_params[0],
|
||||
test_params[1],
|
||||
test_params[2],
|
||||
test_params[3],
|
||||
test_params[4]),
|
||||
testNameGenerator);
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// initialize ROS
|
||||
rclcpp::init(argc, argv);
|
||||
|
||||
bool all_successful = RUN_ALL_TESTS();
|
||||
|
||||
// shutdown ROS
|
||||
rclcpp::shutdown();
|
||||
|
||||
return all_successful;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
set(test_spin_behavior_exec test_spin_behavior_node)
|
||||
|
||||
ament_add_gtest_executable(${test_spin_behavior_exec}
|
||||
test_spin_behavior_node.cpp
|
||||
spin_behavior_tester.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(${test_spin_behavior_exec}
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
ament_add_test(test_spin_behavior
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_spin_behavior_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_spin_behavior_exec}>
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_recovery.xml
|
||||
)
|
||||
|
||||
ament_add_test(test_spin_behavior_fake
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_spin_behavior_fake_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_spin_behavior_exec}>
|
||||
MAKE_FAKE_COSTMAP=true
|
||||
)
|
||||
@@ -1,351 +0,0 @@
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "spin_behavior_tester.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::chrono; // NOLINT
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
SpinBehaviorTester::SpinBehaviorTester()
|
||||
: is_active_(false),
|
||||
initial_pose_received_(false)
|
||||
{
|
||||
node_ = rclcpp::Node::make_shared("spin_behavior_test");
|
||||
|
||||
|
||||
tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
|
||||
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
|
||||
tf_broadcaster_ = std::make_shared<tf2_ros::TransformBroadcaster>(node_);
|
||||
if (std::getenv("MAKE_FAKE_COSTMAP") != NULL) {
|
||||
// if this variable is set, make a fake costmap
|
||||
make_fake_costmap_ = true;
|
||||
} else {
|
||||
make_fake_costmap_ = false;
|
||||
}
|
||||
|
||||
client_ptr_ = rclcpp_action::create_client<Spin>(
|
||||
node_->get_node_base_interface(),
|
||||
node_->get_node_graph_interface(),
|
||||
node_->get_node_logging_interface(),
|
||||
node_->get_node_waitables_interface(),
|
||||
"spin");
|
||||
|
||||
publisher_ =
|
||||
node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>("initialpose", 10);
|
||||
fake_costmap_publisher_ =
|
||||
node_->create_publisher<nav2_msgs::msg::Costmap>(
|
||||
"local_costmap/costmap_raw",
|
||||
rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable());
|
||||
fake_footprint_publisher_ = node_->create_publisher<geometry_msgs::msg::PolygonStamped>(
|
||||
"local_costmap/published_footprint", rclcpp::SystemDefaultsQoS());
|
||||
|
||||
subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
|
||||
"amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
|
||||
std::bind(&SpinBehaviorTester::amclPoseCallback, this, std::placeholders::_1));
|
||||
|
||||
stamp_ = node_->now();
|
||||
}
|
||||
|
||||
SpinBehaviorTester::~SpinBehaviorTester()
|
||||
{
|
||||
if (is_active_) {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void SpinBehaviorTester::activate()
|
||||
{
|
||||
if (is_active_) {
|
||||
throw std::runtime_error("Trying to activate while already active");
|
||||
return;
|
||||
}
|
||||
if (!make_fake_costmap_) {
|
||||
while (!initial_pose_received_) {
|
||||
RCLCPP_WARN(node_->get_logger(), "Initial pose not received");
|
||||
sendInitialPose();
|
||||
std::this_thread::sleep_for(100ms);
|
||||
rclcpp::spin_some(node_);
|
||||
}
|
||||
} else {
|
||||
sendFakeOdom(0.0);
|
||||
}
|
||||
|
||||
// Wait for lifecycle_manager_navigation to activate behavior_server
|
||||
std::this_thread::sleep_for(10s);
|
||||
|
||||
if (!client_ptr_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action client not initialized");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client_ptr_->wait_for_action_server(10s)) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action server not available after waiting");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Spin action server is ready");
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
void SpinBehaviorTester::deactivate()
|
||||
{
|
||||
if (!is_active_) {
|
||||
throw std::runtime_error("Trying to deactivate while already inactive");
|
||||
}
|
||||
is_active_ = false;
|
||||
}
|
||||
|
||||
bool SpinBehaviorTester::defaultSpinBehaviorTest(
|
||||
const float target_yaw,
|
||||
const double tolerance)
|
||||
{
|
||||
if (!is_active_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Not activated");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sleep to let behavior server be ready for serving in multiple runs
|
||||
std::this_thread::sleep_for(5s);
|
||||
|
||||
if (make_fake_costmap_) {
|
||||
sendFakeOdom(0.0);
|
||||
}
|
||||
|
||||
auto goal_msg = Spin::Goal();
|
||||
goal_msg.target_yaw = target_yaw;
|
||||
|
||||
// Initialize fake costmap
|
||||
if (make_fake_costmap_) {
|
||||
sendFakeCostmap(target_yaw);
|
||||
sendFakeOdom(0.0);
|
||||
}
|
||||
|
||||
geometry_msgs::msg::PoseStamped initial_pose;
|
||||
if (!nav2_util::getCurrentPose(initial_pose, *tf_buffer_, "odom")) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Current robot pose is not available.");
|
||||
return false;
|
||||
}
|
||||
RCLCPP_INFO(node_->get_logger(), "Found current robot pose");
|
||||
RCLCPP_INFO(
|
||||
node_->get_logger(),
|
||||
"Init Yaw is %lf",
|
||||
fabs(tf2::getYaw(initial_pose.pose.orientation)));
|
||||
RCLCPP_INFO(node_->get_logger(), "Before sending goal");
|
||||
|
||||
// Initialize fake costmap
|
||||
if (make_fake_costmap_) {
|
||||
sendFakeCostmap(target_yaw);
|
||||
sendFakeOdom(0.0);
|
||||
}
|
||||
|
||||
rclcpp::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
|
||||
|
||||
if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<Spin>::SharedPtr goal_handle = goal_handle_future.get();
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the server to be done with the goal
|
||||
auto result_future = client_ptr_->async_get_result(goal_handle);
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "Waiting for result");
|
||||
rclcpp::sleep_for(std::chrono::milliseconds(1000));
|
||||
|
||||
if (make_fake_costmap_) { // if we are faking the costmap, we will fake success.
|
||||
sendFakeOdom(0.0);
|
||||
sendFakeCostmap(target_yaw);
|
||||
RCLCPP_INFO(node_->get_logger(), "target_yaw %lf", target_yaw);
|
||||
// Slowly increment command yaw by increment to simulate the robot slowly spinning into place
|
||||
float step_size = tolerance / 4.0;
|
||||
for (float command_yaw = 0.0;
|
||||
abs(command_yaw) < abs(target_yaw);
|
||||
command_yaw = command_yaw + step_size)
|
||||
{
|
||||
sendFakeOdom(command_yaw);
|
||||
sendFakeCostmap(target_yaw);
|
||||
rclcpp::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
sendFakeOdom(target_yaw);
|
||||
sendFakeCostmap(target_yaw);
|
||||
RCLCPP_INFO(node_->get_logger(), "After sending goal");
|
||||
}
|
||||
if (rclcpp::spin_until_future_complete(node_, result_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "get result call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<Spin>::WrappedResult wrapped_result = result_future.get();
|
||||
|
||||
switch (wrapped_result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED: break;
|
||||
case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was aborted");
|
||||
return false;
|
||||
case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was canceled");
|
||||
return false;
|
||||
default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
|
||||
return false;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "result received");
|
||||
|
||||
geometry_msgs::msg::PoseStamped current_pose;
|
||||
if (!nav2_util::getCurrentPose(current_pose, *tf_buffer_, "odom")) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Current robot pose is not available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
double goal_yaw = angles::normalize_angle(
|
||||
tf2::getYaw(initial_pose.pose.orientation) + target_yaw);
|
||||
double dyaw = angles::shortest_angular_distance(
|
||||
goal_yaw, tf2::getYaw(current_pose.pose.orientation));
|
||||
|
||||
if (fabs(dyaw) > tolerance) {
|
||||
RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Init Yaw is %lf (tolerance %lf)",
|
||||
fabs(tf2::getYaw(initial_pose.pose.orientation)), tolerance);
|
||||
RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Current Yaw is %lf (tolerance %lf)",
|
||||
fabs(tf2::getYaw(current_pose.pose.orientation)), tolerance);
|
||||
RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Angular distance from goal is %lf (tolerance %lf)",
|
||||
fabs(dyaw), tolerance);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpinBehaviorTester::sendFakeCostmap(float angle)
|
||||
{
|
||||
nav2_msgs::msg::Costmap fake_costmap;
|
||||
|
||||
fake_costmap.header.frame_id = "odom";
|
||||
fake_costmap.header.stamp = stamp_;
|
||||
fake_costmap.metadata.layer = "master";
|
||||
fake_costmap.metadata.resolution = .1;
|
||||
fake_costmap.metadata.size_x = 100;
|
||||
fake_costmap.metadata.size_y = 100;
|
||||
fake_costmap.metadata.origin.position.x = 0;
|
||||
fake_costmap.metadata.origin.position.y = 0;
|
||||
fake_costmap.metadata.origin.orientation.w = 1.0;
|
||||
float costmap_val = 0;
|
||||
for (int ix = 0; ix < 100; ix++) {
|
||||
for (int iy = 0; iy < 100; iy++) {
|
||||
if (abs(angle) > M_PI_2f32) {
|
||||
// fake obstacles in the way so we get failure due to potential collision
|
||||
costmap_val = 100;
|
||||
}
|
||||
fake_costmap.data.push_back(costmap_val);
|
||||
}
|
||||
}
|
||||
fake_costmap_publisher_->publish(fake_costmap);
|
||||
}
|
||||
|
||||
void SpinBehaviorTester::sendInitialPose()
|
||||
{
|
||||
geometry_msgs::msg::PoseWithCovarianceStamped pose;
|
||||
pose.header.frame_id = "map";
|
||||
pose.header.stamp = stamp_;
|
||||
pose.pose.pose.position.x = -2.0;
|
||||
pose.pose.pose.position.y = -0.5;
|
||||
pose.pose.pose.position.z = 0.0;
|
||||
pose.pose.pose.orientation.x = 0.0;
|
||||
pose.pose.pose.orientation.y = 0.0;
|
||||
pose.pose.pose.orientation.z = 0.0;
|
||||
pose.pose.pose.orientation.w = 1.0;
|
||||
for (int i = 0; i < 35; i++) {
|
||||
pose.pose.covariance[i] = 0.0;
|
||||
}
|
||||
pose.pose.covariance[0] = 0.08;
|
||||
pose.pose.covariance[7] = 0.08;
|
||||
pose.pose.covariance[35] = 0.05;
|
||||
|
||||
publisher_->publish(pose);
|
||||
RCLCPP_INFO(node_->get_logger(), "Sent initial pose");
|
||||
}
|
||||
|
||||
void SpinBehaviorTester::sendFakeOdom(float angle)
|
||||
{
|
||||
geometry_msgs::msg::TransformStamped transformStamped;
|
||||
|
||||
transformStamped.header.stamp = stamp_;
|
||||
transformStamped.header.frame_id = "odom";
|
||||
transformStamped.child_frame_id = "base_link";
|
||||
transformStamped.transform.translation.x = 0.0;
|
||||
transformStamped.transform.translation.y = 0.0;
|
||||
transformStamped.transform.translation.z = 0.0;
|
||||
tf2::Quaternion q;
|
||||
q.setRPY(0, 0, angle);
|
||||
transformStamped.transform.rotation.x = q.x();
|
||||
transformStamped.transform.rotation.y = q.y();
|
||||
transformStamped.transform.rotation.z = q.z();
|
||||
transformStamped.transform.rotation.w = q.w();
|
||||
|
||||
tf_broadcaster_->sendTransform(transformStamped);
|
||||
|
||||
geometry_msgs::msg::PolygonStamped footprint;
|
||||
footprint.header.frame_id = "odom";
|
||||
footprint.header.stamp = stamp_;
|
||||
footprint.polygon.points.resize(4);
|
||||
footprint.polygon.points[0].x = 0.22;
|
||||
footprint.polygon.points[0].y = 0.22;
|
||||
footprint.polygon.points[1].x = 0.22;
|
||||
footprint.polygon.points[1].y = -0.22;
|
||||
footprint.polygon.points[2].x = -0.22;
|
||||
footprint.polygon.points[2].y = -0.22;
|
||||
footprint.polygon.points[3].x = -0.22;
|
||||
footprint.polygon.points[3].y = 0.22;
|
||||
fake_footprint_publisher_->publish(footprint);
|
||||
}
|
||||
void SpinBehaviorTester::amclPoseCallback(
|
||||
const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr)
|
||||
{
|
||||
initial_pose_received_ = true;
|
||||
}
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
@@ -1,108 +0,0 @@
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#ifndef BEHAVIORS__SPIN__SPIN_BEHAVIOR_TESTER_HPP_
|
||||
#define BEHAVIORS__SPIN__SPIN_BEHAVIOR_TESTER_HPP_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp_action/rclcpp_action.hpp"
|
||||
#include "angles/angles.h"
|
||||
#include "nav2_msgs/action/spin.hpp"
|
||||
#include "nav2_msgs/msg/costmap.hpp"
|
||||
#include "nav2_util/robot_utils.hpp"
|
||||
#include "nav2_util/node_thread.hpp"
|
||||
#include "geometry_msgs/msg/point32.hpp"
|
||||
#include "geometry_msgs/msg/polygon_stamped.hpp"
|
||||
#include "geometry_msgs/msg/pose_stamped.hpp"
|
||||
#include "geometry_msgs/msg/pose_with_covariance_stamped.hpp"
|
||||
#include "geometry_msgs/msg/transform_stamped.hpp"
|
||||
#include "geometry_msgs/msg/quaternion.hpp"
|
||||
|
||||
#include "tf2/utils.h"
|
||||
#include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
|
||||
#include "tf2_ros/buffer.h"
|
||||
#include "tf2_ros/transform_broadcaster.h"
|
||||
#include "tf2_ros/transform_listener.h"
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
class SpinBehaviorTester
|
||||
{
|
||||
public:
|
||||
using Spin = nav2_msgs::action::Spin;
|
||||
using GoalHandleSpin = rclcpp_action::ClientGoalHandle<Spin>;
|
||||
|
||||
SpinBehaviorTester();
|
||||
~SpinBehaviorTester();
|
||||
|
||||
// Runs a single test with given target yaw
|
||||
bool defaultSpinBehaviorTest(
|
||||
float target_yaw,
|
||||
double tolerance = 0.1);
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate();
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return is_active_;
|
||||
}
|
||||
|
||||
private:
|
||||
void sendInitialPose();
|
||||
|
||||
void sendFakeCostmap(float angle);
|
||||
void sendFakeOdom(float angle);
|
||||
|
||||
void amclPoseCallback(geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr);
|
||||
|
||||
bool is_active_;
|
||||
bool initial_pose_received_;
|
||||
bool make_fake_costmap_;
|
||||
rclcpp::Time stamp_;
|
||||
|
||||
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
|
||||
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
|
||||
// Publisher to publish initial pose
|
||||
rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr publisher_;
|
||||
|
||||
// Publisher to publish fake costmap raw
|
||||
rclcpp::Publisher<nav2_msgs::msg::Costmap>::SharedPtr fake_costmap_publisher_;
|
||||
|
||||
// Publisher to publish fake costmap footprint
|
||||
rclcpp::Publisher<geometry_msgs::msg::PolygonStamped>::SharedPtr fake_footprint_publisher_;
|
||||
|
||||
// Subscriber for amcl pose
|
||||
rclcpp::Subscription<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr subscription_;
|
||||
|
||||
// Action client to call spin action
|
||||
rclcpp_action::Client<Spin>::SharedPtr client_ptr_;
|
||||
};
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
|
||||
#endif // BEHAVIORS__SPIN__SPIN_BEHAVIOR_TESTER_HPP_
|
||||
@@ -1,161 +0,0 @@
|
||||
#! /usr/bin/env python3
|
||||
# Copyright (c) 2019 Samsung Research America
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import DeclareLaunchArgument, ExecuteProcess, SetEnvironmentVariable
|
||||
from launch.substitutions import LaunchConfiguration
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
|
||||
namespace = LaunchConfiguration('namespace')
|
||||
use_sim_time = LaunchConfiguration('use_sim_time')
|
||||
autostart = LaunchConfiguration('autostart')
|
||||
params_file = LaunchConfiguration('params_file')
|
||||
default_nav_through_poses_bt_xml = LaunchConfiguration('default_nav_through_poses_bt_xml')
|
||||
default_nav_to_pose_bt_xml = LaunchConfiguration('default_nav_to_pose_bt_xml')
|
||||
map_subscribe_transient_local = LaunchConfiguration('map_subscribe_transient_local')
|
||||
|
||||
# Create our own temporary YAML files that include substitutions
|
||||
param_substitutions = {
|
||||
'use_sim_time': use_sim_time,
|
||||
'default_nav_through_poses_bt_xml': default_nav_through_poses_bt_xml,
|
||||
'default_nav_to_pose_bt_xml': default_nav_to_pose_bt_xml,
|
||||
'autostart': autostart,
|
||||
'map_subscribe_transient_local': map_subscribe_transient_local}
|
||||
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key=namespace,
|
||||
param_rewrites=param_substitutions,
|
||||
convert_types=True)
|
||||
|
||||
lifecycle_nodes = ['behavior_server']
|
||||
|
||||
# Map fully qualified names to relative ones so the node's namespace can be prepended.
|
||||
# In case of the transforms (tf), currently, there doesn't seem to be a better alternative
|
||||
# https://github.com/ros/geometry2/issues/32
|
||||
# https://github.com/ros/robot_state_publisher/pull/30
|
||||
# TODO(orduno) Substitute with `PushNodeRemapping`
|
||||
# https://github.com/ros2/launch_ros/issues/56
|
||||
remappings = [('/tf', 'tf'),
|
||||
('/tf_static', 'tf_static')]
|
||||
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
DeclareLaunchArgument(
|
||||
'namespace', default_value='',
|
||||
description='Top-level namespace'),
|
||||
|
||||
DeclareLaunchArgument(
|
||||
'use_sim_time', default_value='false',
|
||||
description='Use simulation (Gazebo) clock if true'),
|
||||
|
||||
DeclareLaunchArgument(
|
||||
'autostart', default_value='true',
|
||||
description='Automatically startup the nav2 stack'),
|
||||
|
||||
DeclareLaunchArgument(
|
||||
'params_file',
|
||||
default_value=os.path.join(bringup_dir, 'params', 'nav2_params.yaml'),
|
||||
description='Full path to the ROS2 parameters file to use'),
|
||||
|
||||
DeclareLaunchArgument(
|
||||
'default_nav_through_poses_bt_xml',
|
||||
default_value=os.path.join(
|
||||
get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees', 'navigate_through_poses_w_replanning_and_recovery.xml'),
|
||||
description='Full path to the behavior tree xml file to use'),
|
||||
|
||||
DeclareLaunchArgument(
|
||||
'default_nav_to_pose_bt_xml',
|
||||
default_value=os.path.join(
|
||||
get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees', 'navigate_to_pose_w_replanning_and_recovery.xml'),
|
||||
description='Full path to the behavior tree xml file to use'),
|
||||
|
||||
DeclareLaunchArgument(
|
||||
'map_subscribe_transient_local', default_value='false',
|
||||
description='Whether to set the map subscriber QoS to transient local'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'map', 'odom']),
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
Node(
|
||||
package='nav2_behaviors',
|
||||
executable='behavior_server',
|
||||
name='behavior_server',
|
||||
output='screen',
|
||||
parameters=[configured_params],
|
||||
remappings=remappings),
|
||||
|
||||
Node(
|
||||
package='nav2_lifecycle_manager',
|
||||
executable='lifecycle_manager',
|
||||
name='lifecycle_manager_navigation',
|
||||
output='screen',
|
||||
parameters=[{'use_sim_time': use_sim_time},
|
||||
{'autostart': autostart},
|
||||
{'node_names': lifecycle_nodes}]),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
testExecutable = os.getenv('TEST_EXECUTABLE')
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[testExecutable],
|
||||
name='test_spin_behavior_fake_node',
|
||||
output='screen')
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,102 +0,0 @@
|
||||
#! /usr/bin/env python3
|
||||
# Copyright (c) 2019 Samsung Research America
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import ExecuteProcess, IncludeLaunchDescription, SetEnvironmentVariable
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
map_yaml_file = os.getenv('TEST_MAP')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
bt_navigator_xml = os.path.join(get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees',
|
||||
os.getenv('BT_NAVIGATOR_XML'))
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
params_file = os.path.join(bringup_dir, 'params/nav2_params.yaml')
|
||||
|
||||
# Replace the `use_astar` setting on the params file
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key='',
|
||||
param_rewrites='',
|
||||
convert_types=True)
|
||||
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
# Launch gazebo server for simulation
|
||||
ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so',
|
||||
'--minimal_comms', world],
|
||||
output='screen'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(
|
||||
os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
|
||||
launch_arguments={
|
||||
'map': map_yaml_file,
|
||||
'use_sim_time': 'True',
|
||||
'params_file': configured_params,
|
||||
'bt_xml_file': bt_navigator_xml,
|
||||
'autostart': 'True'}.items()),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
testExecutable = os.getenv('TEST_EXECUTABLE')
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[testExecutable], name='test_spin_behavior_node', output='screen',
|
||||
)
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,109 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "spin_behavior_tester.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using nav2_system_tests::SpinBehaviorTester;
|
||||
|
||||
std::string testNameGenerator(const testing::TestParamInfo<std::tuple<float, float>> & param)
|
||||
{
|
||||
std::string name = std::to_string(std::abs(std::get<0>(param.param))) + "_" + std::to_string(
|
||||
std::get<1>(param.param));
|
||||
name.erase(std::remove(name.begin(), name.end(), '.'), name.end());
|
||||
return name;
|
||||
}
|
||||
|
||||
class SpinBehaviorTestFixture
|
||||
: public ::testing::TestWithParam<std::tuple<float, float>>
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
spin_recovery_tester = new SpinBehaviorTester();
|
||||
if (!spin_recovery_tester->isActive()) {
|
||||
spin_recovery_tester->activate();
|
||||
}
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
delete spin_recovery_tester;
|
||||
spin_recovery_tester = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
static SpinBehaviorTester * spin_recovery_tester;
|
||||
};
|
||||
|
||||
SpinBehaviorTester * SpinBehaviorTestFixture::spin_recovery_tester = nullptr;
|
||||
|
||||
TEST_P(SpinBehaviorTestFixture, testSpinRecovery)
|
||||
{
|
||||
float target_yaw = std::get<0>(GetParam());
|
||||
float tolerance = std::get<1>(GetParam());
|
||||
|
||||
bool success = false;
|
||||
int num_tries = 3;
|
||||
for (int i = 0; i != num_tries; i++) {
|
||||
success = success || spin_recovery_tester->defaultSpinBehaviorTest(target_yaw, tolerance);
|
||||
if (success) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (std::getenv("MAKE_FAKE_COSTMAP") != NULL && abs(target_yaw) > M_PI_2f32) {
|
||||
// if this variable is set, make a fake costmap
|
||||
// in the fake spin test, we expect a collision for angles > M_PI_2
|
||||
EXPECT_EQ(false, success);
|
||||
} else {
|
||||
EXPECT_EQ(true, success);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SpinRecoveryTests,
|
||||
SpinBehaviorTestFixture,
|
||||
::testing::Values(
|
||||
std::make_tuple(-M_PIf32 / 6.0, 0.1),
|
||||
std::make_tuple(M_PI_4f32, 0.1),
|
||||
std::make_tuple(-M_PI_2f32, 0.1),
|
||||
std::make_tuple(M_PIf32, 0.1),
|
||||
std::make_tuple(3.0 * M_PIf32 / 2.0, 0.15),
|
||||
std::make_tuple(-2.0 * M_PIf32, 0.1),
|
||||
std::make_tuple(4.0 * M_PIf32, 0.15)),
|
||||
testNameGenerator);
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// initialize ROS
|
||||
rclcpp::init(argc, argv);
|
||||
|
||||
bool all_successful = RUN_ALL_TESTS();
|
||||
|
||||
// shutdown ROS
|
||||
rclcpp::shutdown();
|
||||
|
||||
return all_successful;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
set(test_wait_behavior_exec test_wait_behavior_node)
|
||||
|
||||
ament_add_gtest_executable(${test_wait_behavior_exec}
|
||||
test_wait_behavior_node.cpp
|
||||
wait_behavior_tester.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(${test_wait_behavior_exec}
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
ament_add_test(test_wait_behavior
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_wait_behavior_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_wait_behavior_exec}>
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_behavior.xml
|
||||
)
|
||||
@@ -1,102 +0,0 @@
|
||||
#! /usr/bin/env python3
|
||||
# Copyright (c) 2019 Samsung Research America
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import ExecuteProcess, IncludeLaunchDescription, SetEnvironmentVariable
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
map_yaml_file = os.getenv('TEST_MAP')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
bt_navigator_xml = os.path.join(get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees',
|
||||
os.getenv('BT_NAVIGATOR_XML'))
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
params_file = os.path.join(bringup_dir, 'params/nav2_params.yaml')
|
||||
|
||||
# Replace the `use_astar` setting on the params file
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key='',
|
||||
param_rewrites='',
|
||||
convert_types=True)
|
||||
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
# Launch gazebo server for simulation
|
||||
ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so',
|
||||
'--minimal_comms', world],
|
||||
output='screen'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(
|
||||
os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
|
||||
launch_arguments={
|
||||
'map': map_yaml_file,
|
||||
'use_sim_time': 'True',
|
||||
'params_file': configured_params,
|
||||
'bt_xml_file': bt_navigator_xml,
|
||||
'autostart': 'True'}.items()),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
testExecutable = os.getenv('TEST_EXECUTABLE')
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[testExecutable], name='test_wait_behavior_node', output='screen',
|
||||
)
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,106 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <cmath>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "wait_behavior_tester.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using nav2_system_tests::WaitBehaviorTester;
|
||||
|
||||
std::string testNameGenerator(const testing::TestParamInfo<std::tuple<float, float>> & param)
|
||||
{
|
||||
std::string name = std::to_string(std::abs(std::get<0>(param.param))) + "_" + std::to_string(
|
||||
std::get<1>(param.param));
|
||||
name.erase(std::remove(name.begin(), name.end(), '.'), name.end());
|
||||
return name;
|
||||
}
|
||||
|
||||
class WaitBehaviorTestFixture
|
||||
: public ::testing::TestWithParam<std::tuple<float, float>>
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
wait_behavior_tester = new WaitBehaviorTester();
|
||||
if (!wait_behavior_tester->isActive()) {
|
||||
wait_behavior_tester->activate();
|
||||
}
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
delete wait_behavior_tester;
|
||||
wait_behavior_tester = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
static WaitBehaviorTester * wait_behavior_tester;
|
||||
};
|
||||
|
||||
WaitBehaviorTester * WaitBehaviorTestFixture::wait_behavior_tester = nullptr;
|
||||
|
||||
TEST_P(WaitBehaviorTestFixture, testSWaitBehavior)
|
||||
{
|
||||
float wait_time = std::get<0>(GetParam());
|
||||
float cancel = std::get<1>(GetParam());
|
||||
|
||||
bool success = false;
|
||||
int num_tries = 3;
|
||||
for (int i = 0; i != num_tries; i++) {
|
||||
if (cancel == 1.0) {
|
||||
success = success || wait_behavior_tester->behaviorTestCancel(wait_time);
|
||||
} else {
|
||||
success = success || wait_behavior_tester->behaviorTest(wait_time);
|
||||
}
|
||||
if (success) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ(true, success);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
WaitBehaviorTests,
|
||||
WaitBehaviorTestFixture,
|
||||
::testing::Values(
|
||||
std::make_tuple(1.0, 0.0),
|
||||
std::make_tuple(2.0, 0.0),
|
||||
std::make_tuple(5.0, 0.0),
|
||||
std::make_tuple(10.0, 1.0)),
|
||||
testNameGenerator);
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// initialize ROS
|
||||
rclcpp::init(argc, argv);
|
||||
|
||||
bool all_successful = RUN_ALL_TESTS();
|
||||
|
||||
// shutdown ROS
|
||||
rclcpp::shutdown();
|
||||
|
||||
return all_successful;
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "wait_behavior_tester.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace std::chrono; // NOLINT
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
WaitBehaviorTester::WaitBehaviorTester()
|
||||
: is_active_(false),
|
||||
initial_pose_received_(false)
|
||||
{
|
||||
node_ = rclcpp::Node::make_shared("wait_behavior_test");
|
||||
|
||||
tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
|
||||
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
|
||||
|
||||
client_ptr_ = rclcpp_action::create_client<Wait>(
|
||||
node_->get_node_base_interface(),
|
||||
node_->get_node_graph_interface(),
|
||||
node_->get_node_logging_interface(),
|
||||
node_->get_node_waitables_interface(),
|
||||
"wait");
|
||||
|
||||
publisher_ =
|
||||
node_->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>("initialpose", 10);
|
||||
|
||||
subscription_ = node_->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
|
||||
"amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
|
||||
std::bind(&WaitBehaviorTester::amclPoseCallback, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
WaitBehaviorTester::~WaitBehaviorTester()
|
||||
{
|
||||
if (is_active_) {
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitBehaviorTester::activate()
|
||||
{
|
||||
if (is_active_) {
|
||||
throw std::runtime_error("Trying to activate while already active");
|
||||
return;
|
||||
}
|
||||
|
||||
while (!initial_pose_received_) {
|
||||
RCLCPP_WARN(node_->get_logger(), "Initial pose not received");
|
||||
sendInitialPose();
|
||||
std::this_thread::sleep_for(100ms);
|
||||
rclcpp::spin_some(node_);
|
||||
}
|
||||
|
||||
// Wait for lifecycle_manager_navigation to activate behavior_server
|
||||
std::this_thread::sleep_for(10s);
|
||||
|
||||
if (!client_ptr_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action client not initialized");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!client_ptr_->wait_for_action_server(10s)) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Action server not available after waiting");
|
||||
is_active_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Wait action server is ready");
|
||||
is_active_ = true;
|
||||
}
|
||||
|
||||
void WaitBehaviorTester::deactivate()
|
||||
{
|
||||
if (!is_active_) {
|
||||
throw std::runtime_error("Trying to deactivate while already inactive");
|
||||
}
|
||||
is_active_ = false;
|
||||
}
|
||||
|
||||
bool WaitBehaviorTester::behaviorTest(
|
||||
const float wait_time)
|
||||
{
|
||||
if (!is_active_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Not activated");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sleep to let behavior server be ready for serving in multiple runs
|
||||
std::this_thread::sleep_for(5s);
|
||||
|
||||
auto start_time = node_->now();
|
||||
auto goal_msg = Wait::Goal();
|
||||
goal_msg.time = rclcpp::Duration(wait_time, 0.0);
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Sending goal");
|
||||
|
||||
auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
|
||||
|
||||
if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<Wait>::SharedPtr goal_handle = goal_handle_future.get();
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the server to be done with the goal
|
||||
auto result_future = client_ptr_->async_get_result(goal_handle);
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "Waiting for result");
|
||||
if (rclcpp::spin_until_future_complete(node_, result_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "get result call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<Wait>::WrappedResult wrapped_result = result_future.get();
|
||||
|
||||
switch (wrapped_result.code) {
|
||||
case rclcpp_action::ResultCode::SUCCEEDED: break;
|
||||
case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was aborted");
|
||||
return false;
|
||||
case rclcpp_action::ResultCode::CANCELED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was canceled");
|
||||
return false;
|
||||
default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
|
||||
return false;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "result received");
|
||||
|
||||
if ((node_->now() - start_time).seconds() < static_cast<double>(wait_time)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaitBehaviorTester::behaviorTestCancel(
|
||||
const float wait_time)
|
||||
{
|
||||
if (!is_active_) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Not activated");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sleep to let behavior server be ready for serving in multiple runs
|
||||
std::this_thread::sleep_for(5s);
|
||||
|
||||
auto start_time = node_->now();
|
||||
auto goal_msg = Wait::Goal();
|
||||
goal_msg.time = rclcpp::Duration(wait_time, 0.0);
|
||||
|
||||
RCLCPP_INFO(this->node_->get_logger(), "Sending goal");
|
||||
|
||||
auto goal_handle_future = client_ptr_->async_send_goal(goal_msg);
|
||||
|
||||
if (rclcpp::spin_until_future_complete(node_, goal_handle_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "send goal call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp_action::ClientGoalHandle<Wait>::SharedPtr goal_handle = goal_handle_future.get();
|
||||
if (!goal_handle) {
|
||||
RCLCPP_ERROR(node_->get_logger(), "Goal was rejected by server");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the server to be done with the goal
|
||||
auto result_future = client_ptr_->async_cancel_all_goals();
|
||||
|
||||
RCLCPP_INFO(node_->get_logger(), "Waiting for cancellation");
|
||||
if (rclcpp::spin_until_future_complete(node_, result_future) !=
|
||||
rclcpp::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
RCLCPP_ERROR(node_->get_logger(), "get cancel result call failed :(");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto status = goal_handle_future.get()->get_status();
|
||||
|
||||
switch (status) {
|
||||
case rclcpp_action::GoalStatus::STATUS_SUCCEEDED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal succeeded");
|
||||
return false;
|
||||
case rclcpp_action::GoalStatus::STATUS_ABORTED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal was aborted");
|
||||
return false;
|
||||
case rclcpp_action::GoalStatus::STATUS_CANCELED: RCLCPP_INFO(
|
||||
node_->get_logger(),
|
||||
"Goal was canceled");
|
||||
return true;
|
||||
case rclcpp_action::GoalStatus::STATUS_CANCELING: RCLCPP_INFO(
|
||||
node_->get_logger(),
|
||||
"Goal is cancelling");
|
||||
return true;
|
||||
case rclcpp_action::GoalStatus::STATUS_EXECUTING: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal is executing");
|
||||
return false;
|
||||
case rclcpp_action::GoalStatus::STATUS_ACCEPTED: RCLCPP_ERROR(
|
||||
node_->get_logger(),
|
||||
"Goal is processing");
|
||||
return false;
|
||||
default: RCLCPP_ERROR(node_->get_logger(), "Unknown result code");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void WaitBehaviorTester::sendInitialPose()
|
||||
{
|
||||
geometry_msgs::msg::PoseWithCovarianceStamped pose;
|
||||
pose.header.frame_id = "map";
|
||||
pose.header.stamp = rclcpp::Time();
|
||||
pose.pose.pose.position.x = -2.0;
|
||||
pose.pose.pose.position.y = -0.5;
|
||||
pose.pose.pose.position.z = 0.0;
|
||||
pose.pose.pose.orientation.x = 0.0;
|
||||
pose.pose.pose.orientation.y = 0.0;
|
||||
pose.pose.pose.orientation.z = 0.0;
|
||||
pose.pose.pose.orientation.w = 1.0;
|
||||
for (int i = 0; i < 35; i++) {
|
||||
pose.pose.covariance[i] = 0.0;
|
||||
}
|
||||
pose.pose.covariance[0] = 0.08;
|
||||
pose.pose.covariance[7] = 0.08;
|
||||
pose.pose.covariance[35] = 0.05;
|
||||
|
||||
publisher_->publish(pose);
|
||||
RCLCPP_INFO(node_->get_logger(), "Sent initial pose");
|
||||
}
|
||||
|
||||
void WaitBehaviorTester::amclPoseCallback(
|
||||
const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr)
|
||||
{
|
||||
initial_pose_received_ = true;
|
||||
}
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
@@ -1,91 +0,0 @@
|
||||
// Copyright (c) 2020 Samsung Research
|
||||
// Copyright (c) 2020 Sarthak Mittal
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#ifndef BEHAVIORS__WAIT__WAIT_BEHAVIOR_TESTER_HPP_
|
||||
#define BEHAVIORS__WAIT__WAIT_BEHAVIOR_TESTER_HPP_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp_action/rclcpp_action.hpp"
|
||||
#include "angles/angles.h"
|
||||
#include "nav2_msgs/action/wait.hpp"
|
||||
#include "nav2_util/robot_utils.hpp"
|
||||
#include "nav2_util/node_thread.hpp"
|
||||
#include "geometry_msgs/msg/pose_stamped.hpp"
|
||||
#include "geometry_msgs/msg/pose_with_covariance_stamped.hpp"
|
||||
|
||||
#include "tf2/utils.h"
|
||||
#include "tf2_ros/buffer.h"
|
||||
#include "tf2_ros/transform_listener.h"
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
class WaitBehaviorTester
|
||||
{
|
||||
public:
|
||||
using Wait = nav2_msgs::action::Wait;
|
||||
using GoalHandleWait = rclcpp_action::ClientGoalHandle<Wait>;
|
||||
|
||||
WaitBehaviorTester();
|
||||
~WaitBehaviorTester();
|
||||
|
||||
// Runs a single test with given target yaw
|
||||
bool behaviorTest(
|
||||
float time);
|
||||
|
||||
bool behaviorTestCancel(float time);
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate();
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return is_active_;
|
||||
}
|
||||
|
||||
private:
|
||||
void sendInitialPose();
|
||||
|
||||
void amclPoseCallback(geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr);
|
||||
|
||||
bool is_active_;
|
||||
bool initial_pose_received_;
|
||||
|
||||
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
|
||||
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
|
||||
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
|
||||
// Publisher to publish initial pose
|
||||
rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr publisher_;
|
||||
|
||||
// Subscriber for amcl pose
|
||||
rclcpp::Subscription<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr subscription_;
|
||||
|
||||
// Action client to call wait action
|
||||
rclcpp_action::Client<Wait>::SharedPtr client_ptr_;
|
||||
};
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
|
||||
#endif // BEHAVIORS__WAIT__WAIT_BEHAVIOR_TESTER_HPP_
|
||||
@@ -1,47 +0,0 @@
|
||||
ament_add_test(test_keepout_filter
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_keepout_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_MASK=${PROJECT_SOURCE_DIR}/maps/keepout_mask.yaml
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
PARAMS_FILE=${CMAKE_CURRENT_SOURCE_DIR}/keepout_params.yaml
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_recovery.xml
|
||||
ASTAR=False
|
||||
)
|
||||
|
||||
ament_add_test(test_speed_filter_global
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_speed_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_MASK=${PROJECT_SOURCE_DIR}/maps/speed_mask.yaml
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
PARAMS_FILE=${CMAKE_CURRENT_SOURCE_DIR}/speed_global_params.yaml
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_recovery.xml
|
||||
ASTAR=False
|
||||
)
|
||||
|
||||
ament_add_test(test_speed_filter_local
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_speed_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_MASK=${PROJECT_SOURCE_DIR}/maps/speed_mask.yaml
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
PARAMS_FILE=${CMAKE_CURRENT_SOURCE_DIR}/speed_local_params.yaml
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
BT_NAVIGATOR_XML=navigate_to_pose_w_replanning_and_recovery.xml
|
||||
ASTAR=False
|
||||
)
|
||||
@@ -1,333 +0,0 @@
|
||||
amcl:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
alpha1: 0.2
|
||||
alpha2: 0.2
|
||||
alpha3: 0.2
|
||||
alpha4: 0.2
|
||||
alpha5: 0.2
|
||||
base_frame_id: "base_footprint"
|
||||
beam_skip_distance: 0.5
|
||||
beam_skip_error_threshold: 0.9
|
||||
beam_skip_threshold: 0.3
|
||||
do_beamskip: true
|
||||
global_frame_id: "map"
|
||||
lambda_short: 0.1
|
||||
laser_likelihood_max_dist: 2.0
|
||||
laser_max_range: 100.0
|
||||
laser_min_range: -1.0
|
||||
laser_model_type: "likelihood_field_prob"
|
||||
max_beams: 60
|
||||
max_particles: 2000
|
||||
min_particles: 500
|
||||
odom_frame_id: "odom"
|
||||
pf_err: 0.05
|
||||
pf_z: 0.99
|
||||
recovery_alpha_fast: 0.0
|
||||
recovery_alpha_slow: 0.0
|
||||
resample_interval: 1
|
||||
robot_model_type: "nav2_amcl::OmniMotionModel"
|
||||
save_pose_rate: 0.5
|
||||
sigma_hit: 0.2
|
||||
tf_broadcast: true
|
||||
transform_tolerance: 1.0
|
||||
update_min_a: 0.2
|
||||
update_min_d: 0.25
|
||||
z_hit: 0.5
|
||||
z_max: 0.05
|
||||
z_rand: 0.5
|
||||
z_short: 0.05
|
||||
scan_topic: scan
|
||||
|
||||
bt_navigator:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
global_frame: map
|
||||
robot_base_frame: base_link
|
||||
odom_topic: /odom
|
||||
# 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are set in the launch
|
||||
# files to allow for a commandline change default used is the
|
||||
# nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml &
|
||||
# nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml
|
||||
plugin_lib_names:
|
||||
- nav2_compute_path_to_pose_action_bt_node
|
||||
- nav2_compute_path_through_poses_action_bt_node
|
||||
- nav2_smooth_path_action_bt_node
|
||||
- nav2_follow_path_action_bt_node
|
||||
- nav2_spin_action_bt_node
|
||||
- nav2_wait_action_bt_node
|
||||
- nav2_assisted_teleop_action_bt_node
|
||||
- nav2_back_up_action_bt_node
|
||||
- nav2_drive_on_heading_bt_node
|
||||
- nav2_clear_costmap_service_bt_node
|
||||
- nav2_is_stuck_condition_bt_node
|
||||
- nav2_goal_reached_condition_bt_node
|
||||
- nav2_goal_updated_condition_bt_node
|
||||
- nav2_is_path_valid_condition_bt_node
|
||||
- nav2_initial_pose_received_condition_bt_node
|
||||
- nav2_reinitialize_global_localization_service_bt_node
|
||||
- nav2_rate_controller_bt_node
|
||||
- nav2_distance_controller_bt_node
|
||||
- nav2_speed_controller_bt_node
|
||||
- nav2_truncate_path_action_bt_node
|
||||
- nav2_truncate_path_local_action_bt_node
|
||||
- nav2_goal_updater_node_bt_node
|
||||
- nav2_recovery_node_bt_node
|
||||
- nav2_pipeline_sequence_bt_node
|
||||
- nav2_round_robin_node_bt_node
|
||||
- nav2_transform_available_condition_bt_node
|
||||
- nav2_time_expired_condition_bt_node
|
||||
- nav2_distance_traveled_condition_bt_node
|
||||
- nav2_single_trigger_bt_node
|
||||
- nav2_goal_updated_controller_bt_node
|
||||
- nav2_is_battery_low_condition_bt_node
|
||||
- nav2_navigate_through_poses_action_bt_node
|
||||
- nav2_navigate_to_pose_action_bt_node
|
||||
- nav2_remove_passed_goals_action_bt_node
|
||||
- nav2_controller_cancel_bt_node
|
||||
- nav2_path_longer_on_approach_bt_node
|
||||
- nav2_wait_cancel_bt_node
|
||||
- nav2_spin_cancel_bt_node
|
||||
- nav2_back_up_cancel_bt_node
|
||||
- nav2_assisted_teleop_cancel_bt_node
|
||||
- nav2_drive_on_heading_cancel_bt_node
|
||||
|
||||
bt_navigator_navigate_through_poses_rclcpp_node:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
bt_navigator_navigate_to_pose_rclcpp_node:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
controller_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
controller_frequency: 20.0
|
||||
min_x_velocity_threshold: 0.001
|
||||
min_y_velocity_threshold: 0.5
|
||||
min_theta_velocity_threshold: 0.001
|
||||
progress_checker_plugin: "progress_checker"
|
||||
goal_checker_plugins: ["goal_checker"]
|
||||
controller_plugins: ["FollowPath"]
|
||||
|
||||
# Progress checker parameters
|
||||
progress_checker:
|
||||
plugin: "nav2_controller::SimpleProgressChecker"
|
||||
required_movement_radius: 0.5
|
||||
movement_time_allowance: 10.0
|
||||
# Goal checker parameters
|
||||
goal_checker:
|
||||
plugin: "nav2_controller::SimpleGoalChecker"
|
||||
xy_goal_tolerance: 0.25
|
||||
yaw_goal_tolerance: 0.25
|
||||
stateful: True
|
||||
# DWB parameters
|
||||
FollowPath:
|
||||
plugin: "dwb_core::DWBLocalPlanner"
|
||||
debug_trajectory_details: True
|
||||
prune_distance: 1.0
|
||||
forward_prune_distance: 1.0
|
||||
min_vel_x: 0.0
|
||||
min_vel_y: 0.0
|
||||
max_vel_x: 0.26
|
||||
max_vel_y: 0.0
|
||||
max_vel_theta: 1.0
|
||||
min_speed_xy: 0.0
|
||||
max_speed_xy: 0.26
|
||||
min_speed_theta: 0.0
|
||||
# Add high threshold velocity for turtlebot 3 issue.
|
||||
# https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/75
|
||||
acc_lim_x: 2.5
|
||||
acc_lim_y: 0.0
|
||||
acc_lim_theta: 3.2
|
||||
decel_lim_x: -2.5
|
||||
decel_lim_y: 0.0
|
||||
decel_lim_theta: -3.2
|
||||
vx_samples: 20
|
||||
vy_samples: 5
|
||||
vtheta_samples: 20
|
||||
sim_time: 1.7
|
||||
linear_granularity: 0.05
|
||||
angular_granularity: 0.025
|
||||
transform_tolerance: 0.2
|
||||
xy_goal_tolerance: 0.25
|
||||
trans_stopped_velocity: 0.25
|
||||
short_circuit_trajectory_evaluation: True
|
||||
stateful: True
|
||||
critics: ["RotateToGoal", "Oscillation", "BaseObstacle", "GoalAlign", "PathAlign", "PathDist", "GoalDist"]
|
||||
BaseObstacle.scale: 0.02
|
||||
PathAlign.scale: 32.0
|
||||
PathAlign.forward_point_distance: 0.1
|
||||
GoalAlign.scale: 24.0
|
||||
GoalAlign.forward_point_distance: 0.1
|
||||
PathDist.scale: 32.0
|
||||
GoalDist.scale: 24.0
|
||||
RotateToGoal.scale: 32.0
|
||||
RotateToGoal.slowing_factor: 5.0
|
||||
RotateToGoal.lookahead_time: -1.0
|
||||
publish_cost_grid_pc: True
|
||||
|
||||
local_costmap:
|
||||
local_costmap:
|
||||
ros__parameters:
|
||||
update_frequency: 5.0
|
||||
publish_frequency: 2.0
|
||||
global_frame: odom
|
||||
robot_base_frame: base_link
|
||||
use_sim_time: True
|
||||
rolling_window: true
|
||||
width: 3
|
||||
height: 3
|
||||
resolution: 0.05
|
||||
robot_radius: 0.22
|
||||
plugins: ["voxel_layer", "inflation_layer"]
|
||||
filters: ["keepout_filter"]
|
||||
inflation_layer:
|
||||
plugin: "nav2_costmap_2d::InflationLayer"
|
||||
cost_scaling_factor: 3.0
|
||||
inflation_radius: 0.55
|
||||
voxel_layer:
|
||||
plugin: "nav2_costmap_2d::VoxelLayer"
|
||||
enabled: True
|
||||
publish_voxel_map: True
|
||||
origin_z: 0.0
|
||||
z_resolution: 0.05
|
||||
z_voxels: 16
|
||||
max_obstacle_height: 2.0
|
||||
mark_threshold: 0
|
||||
observation_sources: scan
|
||||
scan:
|
||||
topic: /scan
|
||||
max_obstacle_height: 2.0
|
||||
clearing: True
|
||||
marking: True
|
||||
data_type: "LaserScan"
|
||||
raytrace_max_range: 3.0
|
||||
raytrace_min_range: 0.0
|
||||
obstacle_max_range: 2.5
|
||||
obstacle_min_range: 0.0
|
||||
static_layer:
|
||||
map_subscribe_transient_local: True
|
||||
keepout_filter:
|
||||
plugin: "nav2_costmap_2d::KeepoutFilter"
|
||||
enabled: True
|
||||
filter_info_topic: "/costmap_filter_info"
|
||||
always_send_full_costmap: True
|
||||
|
||||
global_costmap:
|
||||
global_costmap:
|
||||
ros__parameters:
|
||||
update_frequency: 1.0
|
||||
publish_frequency: 1.0
|
||||
global_frame: map
|
||||
robot_base_frame: base_link
|
||||
use_sim_time: True
|
||||
robot_radius: 0.22
|
||||
resolution: 0.05
|
||||
track_unknown_space: true
|
||||
plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
|
||||
filters: ["keepout_filter"]
|
||||
obstacle_layer:
|
||||
plugin: "nav2_costmap_2d::ObstacleLayer"
|
||||
enabled: True
|
||||
observation_sources: scan
|
||||
scan:
|
||||
topic: /scan
|
||||
max_obstacle_height: 2.0
|
||||
clearing: True
|
||||
marking: True
|
||||
data_type: "LaserScan"
|
||||
static_layer:
|
||||
plugin: "nav2_costmap_2d::StaticLayer"
|
||||
map_subscribe_transient_local: True
|
||||
inflation_layer:
|
||||
plugin: "nav2_costmap_2d::InflationLayer"
|
||||
cost_scaling_factor: 3.0
|
||||
inflation_radius: 0.55
|
||||
keepout_filter:
|
||||
plugin: "nav2_costmap_2d::KeepoutFilter"
|
||||
enabled: True
|
||||
filter_info_topic: "/costmap_filter_info"
|
||||
always_send_full_costmap: True
|
||||
|
||||
map_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
yaml_filename: "turtlebot3_world.yaml"
|
||||
|
||||
map_saver:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
save_map_timeout: 5.0
|
||||
free_thresh_default: 0.25
|
||||
occupied_thresh_default: 0.65
|
||||
map_subscribe_transient_local: True
|
||||
|
||||
planner_server:
|
||||
ros__parameters:
|
||||
expected_planner_frequency: 20.0
|
||||
use_sim_time: True
|
||||
planner_plugins: ["GridBased"]
|
||||
GridBased:
|
||||
plugin: "nav2_navfn_planner/NavfnPlanner"
|
||||
tolerance: 0.5
|
||||
use_astar: False
|
||||
allow_unknown: True
|
||||
|
||||
smoother_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
behavior_server:
|
||||
ros__parameters:
|
||||
costmap_topic: local_costmap/costmap_raw
|
||||
footprint_topic: local_costmap/published_footprint
|
||||
cycle_frequency: 10.0
|
||||
behavior_plugins: ["spin", "backup", "drive_on_heading", "wait"]
|
||||
spin:
|
||||
plugin: "nav2_behaviors/Spin"
|
||||
backup:
|
||||
plugin: "nav2_behaviors/BackUp"
|
||||
drive_on_heading:
|
||||
plugin: "nav2_behaviors/DriveOnHeading"
|
||||
wait:
|
||||
plugin: "nav2_behaviors/Wait"
|
||||
global_frame: odom
|
||||
robot_base_frame: base_link
|
||||
transform_tolerance: 0.1
|
||||
use_sim_time: true
|
||||
simulate_ahead_time: 2.0
|
||||
max_rotational_vel: 1.0
|
||||
min_rotational_vel: 0.4
|
||||
rotational_acc_lim: 3.2
|
||||
|
||||
robot_state_publisher:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
waypoint_follower:
|
||||
ros__parameters:
|
||||
loop_rate: 20
|
||||
stop_on_failure: false
|
||||
waypoint_task_executor_plugin: "waypoint_task_executor"
|
||||
waypoint_task_executor:
|
||||
plugin: "nav2_waypoint_follower::WaitAtWaypoint"
|
||||
enabled: True
|
||||
waypoint_pause_duration: 0
|
||||
|
||||
costmap_filter_info_server:
|
||||
ros__parameters:
|
||||
use_sim_time: true
|
||||
type: 0
|
||||
filter_info_topic: "/costmap_filter_info"
|
||||
mask_topic: "/filter_mask"
|
||||
base: 0.0
|
||||
multiplier: 1.0
|
||||
|
||||
filter_mask_server:
|
||||
ros__parameters:
|
||||
use_sim_time: true
|
||||
frame_id: "map"
|
||||
topic_name: "/filter_mask"
|
||||
yaml_filename: "keepout_mask.yaml"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 104 KiB |
@@ -1,324 +0,0 @@
|
||||
amcl:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
alpha1: 0.2
|
||||
alpha2: 0.2
|
||||
alpha3: 0.2
|
||||
alpha4: 0.2
|
||||
alpha5: 0.2
|
||||
base_frame_id: "base_footprint"
|
||||
beam_skip_distance: 0.5
|
||||
beam_skip_error_threshold: 0.9
|
||||
beam_skip_threshold: 0.3
|
||||
do_beamskip: false
|
||||
global_frame_id: "map"
|
||||
lambda_short: 0.1
|
||||
laser_likelihood_max_dist: 2.0
|
||||
laser_max_range: 100.0
|
||||
laser_min_range: -1.0
|
||||
laser_model_type: "beam"
|
||||
max_beams: 60
|
||||
max_particles: 2000
|
||||
min_particles: 500
|
||||
odom_frame_id: "odom"
|
||||
pf_err: 0.05
|
||||
pf_z: 0.99
|
||||
recovery_alpha_fast: 0.0
|
||||
recovery_alpha_slow: 0.0
|
||||
resample_interval: 1
|
||||
robot_model_type: "nav2_amcl::DifferentialMotionModel"
|
||||
save_pose_rate: 0.5
|
||||
sigma_hit: 0.2
|
||||
tf_broadcast: true
|
||||
transform_tolerance: 1.0
|
||||
update_min_a: 0.2
|
||||
update_min_d: 0.25
|
||||
z_hit: 0.5
|
||||
z_max: 0.05
|
||||
z_rand: 0.5
|
||||
z_short: 0.05
|
||||
scan_topic: scan
|
||||
|
||||
bt_navigator:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
global_frame: map
|
||||
robot_base_frame: base_link
|
||||
odom_topic: /odom
|
||||
# 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are set in the launch
|
||||
# files to allow for a commandline change default used is the
|
||||
# nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml &
|
||||
# nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml
|
||||
plugin_lib_names:
|
||||
- nav2_compute_path_to_pose_action_bt_node
|
||||
- nav2_compute_path_through_poses_action_bt_node
|
||||
- nav2_smooth_path_action_bt_node
|
||||
- nav2_follow_path_action_bt_node
|
||||
- nav2_spin_action_bt_node
|
||||
- nav2_wait_action_bt_node
|
||||
- nav2_assisted_teleop_action_bt_node
|
||||
- nav2_back_up_action_bt_node
|
||||
- nav2_drive_on_heading_bt_node
|
||||
- nav2_clear_costmap_service_bt_node
|
||||
- nav2_is_stuck_condition_bt_node
|
||||
- nav2_goal_reached_condition_bt_node
|
||||
- nav2_goal_updated_condition_bt_node
|
||||
- nav2_globally_updated_goal_condition_bt_node
|
||||
- nav2_is_path_valid_condition_bt_node
|
||||
- nav2_initial_pose_received_condition_bt_node
|
||||
- nav2_reinitialize_global_localization_service_bt_node
|
||||
- nav2_rate_controller_bt_node
|
||||
- nav2_distance_controller_bt_node
|
||||
- nav2_speed_controller_bt_node
|
||||
- nav2_truncate_path_action_bt_node
|
||||
- nav2_truncate_path_local_action_bt_node
|
||||
- nav2_goal_updater_node_bt_node
|
||||
- nav2_recovery_node_bt_node
|
||||
- nav2_pipeline_sequence_bt_node
|
||||
- nav2_round_robin_node_bt_node
|
||||
- nav2_transform_available_condition_bt_node
|
||||
- nav2_time_expired_condition_bt_node
|
||||
- nav2_distance_traveled_condition_bt_node
|
||||
- nav2_single_trigger_bt_node
|
||||
- nav2_goal_updated_controller_bt_node
|
||||
- nav2_is_battery_low_condition_bt_node
|
||||
- nav2_navigate_through_poses_action_bt_node
|
||||
- nav2_navigate_to_pose_action_bt_node
|
||||
- nav2_remove_passed_goals_action_bt_node
|
||||
- nav2_controller_cancel_bt_node
|
||||
- nav2_path_longer_on_approach_bt_node
|
||||
- nav2_wait_cancel_bt_node
|
||||
- nav2_spin_cancel_bt_node
|
||||
- nav2_back_up_cancel_bt_node
|
||||
- nav2_assisted_teleop_cancel_bt_node
|
||||
- nav2_drive_on_heading_cancel_bt_node
|
||||
|
||||
bt_navigator_navigate_through_poses_rclcpp_node:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
bt_navigator_navigate_to_pose_rclcpp_node:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
controller_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
controller_frequency: 20.0
|
||||
min_x_velocity_threshold: 0.001
|
||||
min_y_velocity_threshold: 0.5
|
||||
min_theta_velocity_threshold: 0.001
|
||||
speed_limit_topic: "/speed_limit"
|
||||
progress_checker_plugin: "progress_checker"
|
||||
goal_checker_plugins: ["goal_checker"]
|
||||
controller_plugins: ["FollowPath"]
|
||||
|
||||
# Progress checker parameters
|
||||
progress_checker:
|
||||
plugin: "nav2_controller::SimpleProgressChecker"
|
||||
required_movement_radius: 0.5
|
||||
movement_time_allowance: 10.0
|
||||
# Goal checker parameters
|
||||
goal_checker:
|
||||
plugin: "nav2_controller::SimpleGoalChecker"
|
||||
xy_goal_tolerance: 0.25
|
||||
yaw_goal_tolerance: 0.25
|
||||
stateful: True
|
||||
# DWB parameters
|
||||
FollowPath:
|
||||
plugin: "dwb_core::DWBLocalPlanner"
|
||||
debug_trajectory_details: True
|
||||
min_vel_x: 0.0
|
||||
min_vel_y: 0.0
|
||||
max_vel_x: 0.26
|
||||
max_vel_y: 0.0
|
||||
max_vel_theta: 1.0
|
||||
min_speed_xy: 0.0
|
||||
max_speed_xy: 0.26
|
||||
min_speed_theta: 0.0
|
||||
# Add high threshold velocity for turtlebot 3 issue.
|
||||
# https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/75
|
||||
acc_lim_x: 2.5
|
||||
acc_lim_y: 0.0
|
||||
acc_lim_theta: 3.2
|
||||
decel_lim_x: -2.5
|
||||
decel_lim_y: 0.0
|
||||
decel_lim_theta: -3.2
|
||||
vx_samples: 20
|
||||
vy_samples: 5
|
||||
vtheta_samples: 20
|
||||
sim_time: 1.7
|
||||
linear_granularity: 0.05
|
||||
angular_granularity: 0.025
|
||||
transform_tolerance: 0.2
|
||||
xy_goal_tolerance: 0.25
|
||||
trans_stopped_velocity: 0.25
|
||||
short_circuit_trajectory_evaluation: True
|
||||
stateful: True
|
||||
critics: ["RotateToGoal", "Oscillation", "BaseObstacle", "GoalAlign", "PathAlign", "PathDist", "GoalDist"]
|
||||
BaseObstacle.scale: 0.02
|
||||
PathAlign.scale: 32.0
|
||||
PathAlign.forward_point_distance: 0.1
|
||||
GoalAlign.scale: 24.0
|
||||
GoalAlign.forward_point_distance: 0.1
|
||||
PathDist.scale: 32.0
|
||||
GoalDist.scale: 24.0
|
||||
RotateToGoal.scale: 32.0
|
||||
RotateToGoal.slowing_factor: 5.0
|
||||
RotateToGoal.lookahead_time: -1.0
|
||||
|
||||
local_costmap:
|
||||
local_costmap:
|
||||
ros__parameters:
|
||||
update_frequency: 5.0
|
||||
publish_frequency: 2.0
|
||||
global_frame: odom
|
||||
robot_base_frame: base_link
|
||||
use_sim_time: True
|
||||
rolling_window: true
|
||||
width: 3
|
||||
height: 3
|
||||
resolution: 0.05
|
||||
robot_radius: 0.22
|
||||
plugins: ["voxel_layer", "inflation_layer"]
|
||||
inflation_layer:
|
||||
plugin: "nav2_costmap_2d::InflationLayer"
|
||||
cost_scaling_factor: 3.0
|
||||
inflation_radius: 0.55
|
||||
voxel_layer:
|
||||
plugin: "nav2_costmap_2d::VoxelLayer"
|
||||
enabled: True
|
||||
publish_voxel_map: True
|
||||
origin_z: 0.0
|
||||
z_resolution: 0.05
|
||||
z_voxels: 16
|
||||
max_obstacle_height: 2.0
|
||||
mark_threshold: 0
|
||||
observation_sources: scan
|
||||
scan:
|
||||
topic: /scan
|
||||
max_obstacle_height: 2.0
|
||||
clearing: True
|
||||
marking: True
|
||||
data_type: "LaserScan"
|
||||
static_layer:
|
||||
map_subscribe_transient_local: True
|
||||
always_send_full_costmap: True
|
||||
|
||||
global_costmap:
|
||||
global_costmap:
|
||||
ros__parameters:
|
||||
update_frequency: 1.0
|
||||
publish_frequency: 1.0
|
||||
global_frame: map
|
||||
robot_base_frame: base_link
|
||||
use_sim_time: True
|
||||
robot_radius: 0.22
|
||||
resolution: 0.05
|
||||
track_unknown_space: true
|
||||
plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
|
||||
filters: ["speed_filter"]
|
||||
obstacle_layer:
|
||||
plugin: "nav2_costmap_2d::ObstacleLayer"
|
||||
enabled: True
|
||||
observation_sources: scan
|
||||
scan:
|
||||
topic: /scan
|
||||
max_obstacle_height: 2.0
|
||||
clearing: True
|
||||
marking: True
|
||||
data_type: "LaserScan"
|
||||
static_layer:
|
||||
plugin: "nav2_costmap_2d::StaticLayer"
|
||||
map_subscribe_transient_local: True
|
||||
inflation_layer:
|
||||
plugin: "nav2_costmap_2d::InflationLayer"
|
||||
cost_scaling_factor: 3.0
|
||||
inflation_radius: 0.55
|
||||
speed_filter:
|
||||
plugin: "nav2_costmap_2d::SpeedFilter"
|
||||
enabled: True
|
||||
filter_info_topic: "/costmap_filter_info"
|
||||
speed_limit_topic: "/speed_limit"
|
||||
always_send_full_costmap: True
|
||||
|
||||
map_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
yaml_filename: "turtlebot3_world.yaml"
|
||||
|
||||
map_saver:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
save_map_timeout: 5.0
|
||||
free_thresh_default: 0.25
|
||||
occupied_thresh_default: 0.65
|
||||
map_subscribe_transient_local: True
|
||||
|
||||
planner_server:
|
||||
ros__parameters:
|
||||
expected_planner_frequency: 20.0
|
||||
use_sim_time: True
|
||||
planner_plugins: ["GridBased"]
|
||||
GridBased:
|
||||
plugin: "nav2_navfn_planner/NavfnPlanner"
|
||||
tolerance: 0.5
|
||||
use_astar: False
|
||||
allow_unknown: True
|
||||
|
||||
smoother_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
behavior_server:
|
||||
ros__parameters:
|
||||
costmap_topic: local_costmap/costmap_raw
|
||||
footprint_topic: local_costmap/published_footprint
|
||||
cycle_frequency: 10.0
|
||||
behavior_plugins: ["spin", "backup", "drive_on_heading", "wait"]
|
||||
spin:
|
||||
plugin: "nav2_behaviors/Spin"
|
||||
backup:
|
||||
plugin: "nav2_behaviors/BackUp"
|
||||
drive_on_heading:
|
||||
plugin: "nav2_behaviors/DriveOnHeading"
|
||||
wait:
|
||||
plugin: "nav2_behaviors/Wait"
|
||||
global_frame: odom
|
||||
robot_base_frame: base_link
|
||||
transform_tolerance: 0.1
|
||||
use_sim_time: true
|
||||
simulate_ahead_time: 2.0
|
||||
max_rotational_vel: 1.0
|
||||
min_rotational_vel: 0.4
|
||||
rotational_acc_lim: 3.2
|
||||
|
||||
robot_state_publisher:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
waypoint_follower:
|
||||
ros__parameters:
|
||||
loop_rate: 20
|
||||
stop_on_failure: false
|
||||
waypoint_task_executor_plugin: "waypoint_task_executor"
|
||||
waypoint_task_executor:
|
||||
plugin: "nav2_waypoint_follower::WaitAtWaypoint"
|
||||
enabled: True
|
||||
waypoint_pause_duration: 0
|
||||
|
||||
costmap_filter_info_server:
|
||||
ros__parameters:
|
||||
use_sim_time: true
|
||||
type: 1
|
||||
filter_info_topic: "/costmap_filter_info"
|
||||
mask_topic: "/filter_mask"
|
||||
base: 100.0
|
||||
multiplier: -1.0
|
||||
|
||||
filter_mask_server:
|
||||
ros__parameters:
|
||||
use_sim_time: true
|
||||
frame_id: "map"
|
||||
topic_name: "/filter_mask"
|
||||
yaml_filename: "speed_mask.yaml"
|
||||
@@ -1,324 +0,0 @@
|
||||
amcl:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
alpha1: 0.2
|
||||
alpha2: 0.2
|
||||
alpha3: 0.2
|
||||
alpha4: 0.2
|
||||
alpha5: 0.2
|
||||
base_frame_id: "base_footprint"
|
||||
beam_skip_distance: 0.5
|
||||
beam_skip_error_threshold: 0.9
|
||||
beam_skip_threshold: 0.3
|
||||
do_beamskip: false
|
||||
global_frame_id: "map"
|
||||
lambda_short: 0.1
|
||||
laser_likelihood_max_dist: 2.0
|
||||
laser_max_range: 100.0
|
||||
laser_min_range: -1.0
|
||||
laser_model_type: "beam"
|
||||
max_beams: 60
|
||||
max_particles: 2000
|
||||
min_particles: 500
|
||||
odom_frame_id: "odom"
|
||||
pf_err: 0.05
|
||||
pf_z: 0.99
|
||||
recovery_alpha_fast: 0.0
|
||||
recovery_alpha_slow: 0.0
|
||||
resample_interval: 1
|
||||
robot_model_type: "nav2_amcl::DifferentialMotionModel"
|
||||
save_pose_rate: 0.5
|
||||
sigma_hit: 0.2
|
||||
tf_broadcast: true
|
||||
transform_tolerance: 1.0
|
||||
update_min_a: 0.2
|
||||
update_min_d: 0.25
|
||||
z_hit: 0.5
|
||||
z_max: 0.05
|
||||
z_rand: 0.5
|
||||
z_short: 0.05
|
||||
scan_topic: scan
|
||||
|
||||
bt_navigator:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
global_frame: map
|
||||
robot_base_frame: base_link
|
||||
odom_topic: /odom
|
||||
# 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are set in the launch
|
||||
# files to allow for a commandline change default used is the
|
||||
# nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml &
|
||||
# nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml
|
||||
plugin_lib_names:
|
||||
- nav2_compute_path_to_pose_action_bt_node
|
||||
- nav2_compute_path_through_poses_action_bt_node
|
||||
- nav2_smooth_path_action_bt_node
|
||||
- nav2_follow_path_action_bt_node
|
||||
- nav2_spin_action_bt_node
|
||||
- nav2_wait_action_bt_node
|
||||
- nav2_assisted_teleop_action_bt_node
|
||||
- nav2_back_up_action_bt_node
|
||||
- nav2_drive_on_heading_bt_node
|
||||
- nav2_clear_costmap_service_bt_node
|
||||
- nav2_is_stuck_condition_bt_node
|
||||
- nav2_goal_reached_condition_bt_node
|
||||
- nav2_goal_updated_condition_bt_node
|
||||
- nav2_globally_updated_goal_condition_bt_node
|
||||
- nav2_is_path_valid_condition_bt_node
|
||||
- nav2_initial_pose_received_condition_bt_node
|
||||
- nav2_reinitialize_global_localization_service_bt_node
|
||||
- nav2_rate_controller_bt_node
|
||||
- nav2_distance_controller_bt_node
|
||||
- nav2_speed_controller_bt_node
|
||||
- nav2_truncate_path_action_bt_node
|
||||
- nav2_truncate_path_local_action_bt_node
|
||||
- nav2_goal_updater_node_bt_node
|
||||
- nav2_recovery_node_bt_node
|
||||
- nav2_pipeline_sequence_bt_node
|
||||
- nav2_round_robin_node_bt_node
|
||||
- nav2_transform_available_condition_bt_node
|
||||
- nav2_time_expired_condition_bt_node
|
||||
- nav2_distance_traveled_condition_bt_node
|
||||
- nav2_single_trigger_bt_node
|
||||
- nav2_goal_updated_controller_bt_node
|
||||
- nav2_is_battery_low_condition_bt_node
|
||||
- nav2_navigate_through_poses_action_bt_node
|
||||
- nav2_navigate_to_pose_action_bt_node
|
||||
- nav2_remove_passed_goals_action_bt_node
|
||||
- nav2_controller_cancel_bt_node
|
||||
- nav2_path_longer_on_approach_bt_node
|
||||
- nav2_wait_cancel_bt_node
|
||||
- nav2_spin_cancel_bt_node
|
||||
- nav2_back_up_cancel_bt_node
|
||||
- nav2_assisted_teleop_cancel_bt_node
|
||||
- nav2_drive_on_heading_cancel_bt_node
|
||||
|
||||
bt_navigator_navigate_through_poses_rclcpp_node:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
bt_navigator_navigate_to_pose_rclcpp_node:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
controller_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
controller_frequency: 20.0
|
||||
min_x_velocity_threshold: 0.001
|
||||
min_y_velocity_threshold: 0.5
|
||||
min_theta_velocity_threshold: 0.001
|
||||
speed_limit_topic: "/speed_limit"
|
||||
progress_checker_plugin: "progress_checker"
|
||||
goal_checker_plugins: ["goal_checker"]
|
||||
controller_plugins: ["FollowPath"]
|
||||
|
||||
# Progress checker parameters
|
||||
progress_checker:
|
||||
plugin: "nav2_controller::SimpleProgressChecker"
|
||||
required_movement_radius: 0.5
|
||||
movement_time_allowance: 10.0
|
||||
# Goal checker parameters
|
||||
goal_checker:
|
||||
plugin: "nav2_controller::SimpleGoalChecker"
|
||||
xy_goal_tolerance: 0.25
|
||||
yaw_goal_tolerance: 0.25
|
||||
stateful: True
|
||||
# DWB parameters
|
||||
FollowPath:
|
||||
plugin: "dwb_core::DWBLocalPlanner"
|
||||
debug_trajectory_details: True
|
||||
min_vel_x: 0.0
|
||||
min_vel_y: 0.0
|
||||
max_vel_x: 0.26
|
||||
max_vel_y: 0.0
|
||||
max_vel_theta: 1.0
|
||||
min_speed_xy: 0.0
|
||||
max_speed_xy: 0.26
|
||||
min_speed_theta: 0.0
|
||||
# Add high threshold velocity for turtlebot 3 issue.
|
||||
# https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/75
|
||||
acc_lim_x: 2.5
|
||||
acc_lim_y: 0.0
|
||||
acc_lim_theta: 3.2
|
||||
decel_lim_x: -2.5
|
||||
decel_lim_y: 0.0
|
||||
decel_lim_theta: -3.2
|
||||
vx_samples: 20
|
||||
vy_samples: 5
|
||||
vtheta_samples: 20
|
||||
sim_time: 1.7
|
||||
linear_granularity: 0.05
|
||||
angular_granularity: 0.025
|
||||
transform_tolerance: 0.2
|
||||
xy_goal_tolerance: 0.25
|
||||
trans_stopped_velocity: 0.25
|
||||
short_circuit_trajectory_evaluation: True
|
||||
stateful: True
|
||||
critics: ["RotateToGoal", "Oscillation", "BaseObstacle", "GoalAlign", "PathAlign", "PathDist", "GoalDist"]
|
||||
BaseObstacle.scale: 0.02
|
||||
PathAlign.scale: 32.0
|
||||
PathAlign.forward_point_distance: 0.1
|
||||
GoalAlign.scale: 24.0
|
||||
GoalAlign.forward_point_distance: 0.1
|
||||
PathDist.scale: 32.0
|
||||
GoalDist.scale: 24.0
|
||||
RotateToGoal.scale: 32.0
|
||||
RotateToGoal.slowing_factor: 5.0
|
||||
RotateToGoal.lookahead_time: -1.0
|
||||
|
||||
local_costmap:
|
||||
local_costmap:
|
||||
ros__parameters:
|
||||
update_frequency: 5.0
|
||||
publish_frequency: 2.0
|
||||
global_frame: odom
|
||||
robot_base_frame: base_link
|
||||
use_sim_time: True
|
||||
rolling_window: true
|
||||
width: 3
|
||||
height: 3
|
||||
resolution: 0.05
|
||||
robot_radius: 0.22
|
||||
plugins: ["voxel_layer", "inflation_layer"]
|
||||
filters: ["speed_filter"]
|
||||
inflation_layer:
|
||||
plugin: "nav2_costmap_2d::InflationLayer"
|
||||
cost_scaling_factor: 3.0
|
||||
inflation_radius: 0.55
|
||||
voxel_layer:
|
||||
plugin: "nav2_costmap_2d::VoxelLayer"
|
||||
enabled: True
|
||||
publish_voxel_map: True
|
||||
origin_z: 0.0
|
||||
z_resolution: 0.05
|
||||
z_voxels: 16
|
||||
max_obstacle_height: 2.0
|
||||
mark_threshold: 0
|
||||
observation_sources: scan
|
||||
scan:
|
||||
topic: /scan
|
||||
max_obstacle_height: 2.0
|
||||
clearing: True
|
||||
marking: True
|
||||
data_type: "LaserScan"
|
||||
static_layer:
|
||||
map_subscribe_transient_local: True
|
||||
speed_filter:
|
||||
plugin: "nav2_costmap_2d::SpeedFilter"
|
||||
enabled: True
|
||||
filter_info_topic: "/costmap_filter_info"
|
||||
speed_limit_topic: "/speed_limit"
|
||||
always_send_full_costmap: True
|
||||
|
||||
global_costmap:
|
||||
global_costmap:
|
||||
ros__parameters:
|
||||
update_frequency: 1.0
|
||||
publish_frequency: 1.0
|
||||
global_frame: map
|
||||
robot_base_frame: base_link
|
||||
use_sim_time: True
|
||||
robot_radius: 0.22
|
||||
resolution: 0.05
|
||||
track_unknown_space: true
|
||||
plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
|
||||
obstacle_layer:
|
||||
plugin: "nav2_costmap_2d::ObstacleLayer"
|
||||
enabled: True
|
||||
observation_sources: scan
|
||||
scan:
|
||||
topic: /scan
|
||||
max_obstacle_height: 2.0
|
||||
clearing: True
|
||||
marking: True
|
||||
data_type: "LaserScan"
|
||||
static_layer:
|
||||
plugin: "nav2_costmap_2d::StaticLayer"
|
||||
map_subscribe_transient_local: True
|
||||
inflation_layer:
|
||||
plugin: "nav2_costmap_2d::InflationLayer"
|
||||
cost_scaling_factor: 3.0
|
||||
inflation_radius: 0.55
|
||||
always_send_full_costmap: True
|
||||
|
||||
map_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
yaml_filename: "turtlebot3_world.yaml"
|
||||
|
||||
map_saver:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
save_map_timeout: 5.0
|
||||
free_thresh_default: 0.25
|
||||
occupied_thresh_default: 0.65
|
||||
map_subscribe_transient_local: True
|
||||
|
||||
planner_server:
|
||||
ros__parameters:
|
||||
expected_planner_frequency: 20.0
|
||||
use_sim_time: True
|
||||
planner_plugins: ["GridBased"]
|
||||
GridBased:
|
||||
plugin: "nav2_navfn_planner/NavfnPlanner"
|
||||
tolerance: 0.5
|
||||
use_astar: False
|
||||
allow_unknown: True
|
||||
|
||||
smoother_server:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
behavior_server:
|
||||
ros__parameters:
|
||||
costmap_topic: local_costmap/costmap_raw
|
||||
footprint_topic: local_costmap/published_footprint
|
||||
cycle_frequency: 10.0
|
||||
behavior_plugins: ["spin", "backup", "drive_on_heading", "wait"]
|
||||
spin:
|
||||
plugin: "nav2_behaviors/Spin"
|
||||
backup:
|
||||
plugin: "nav2_behaviors/BackUp"
|
||||
drive_on_heading:
|
||||
plugin: "nav2_behaviors/DriveOnHeading"
|
||||
wait:
|
||||
plugin: "nav2_behaviors/Wait"
|
||||
global_frame: odom
|
||||
robot_base_frame: base_link
|
||||
transform_tolerance: 0.1
|
||||
use_sim_time: true
|
||||
simulate_ahead_time: 2.0
|
||||
max_rotational_vel: 1.0
|
||||
min_rotational_vel: 0.4
|
||||
rotational_acc_lim: 3.2
|
||||
|
||||
robot_state_publisher:
|
||||
ros__parameters:
|
||||
use_sim_time: True
|
||||
|
||||
waypoint_follower:
|
||||
ros__parameters:
|
||||
loop_rate: 20
|
||||
stop_on_failure: false
|
||||
waypoint_task_executor_plugin: "waypoint_task_executor"
|
||||
waypoint_task_executor:
|
||||
plugin: "nav2_waypoint_follower::WaitAtWaypoint"
|
||||
enabled: True
|
||||
waypoint_pause_duration: 0
|
||||
|
||||
costmap_filter_info_server:
|
||||
ros__parameters:
|
||||
use_sim_time: true
|
||||
type: 1
|
||||
filter_info_topic: "/costmap_filter_info"
|
||||
mask_topic: "/filter_mask"
|
||||
base: 100.0
|
||||
multiplier: -1.0
|
||||
|
||||
filter_mask_server:
|
||||
ros__parameters:
|
||||
use_sim_time: true
|
||||
frame_id: "map"
|
||||
topic_name: "/filter_mask"
|
||||
yaml_filename: "speed_mask.yaml"
|
||||
@@ -1,149 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2018 Intel Corporation
|
||||
# Copyright (c) 2020 Samsung Research Russia
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import ExecuteProcess, IncludeLaunchDescription, SetEnvironmentVariable
|
||||
from launch.launch_context import LaunchContext
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
map_yaml_file = os.getenv('TEST_MAP')
|
||||
filter_mask_file = os.getenv('TEST_MASK')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
bt_navigator_xml = os.path.join(get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees',
|
||||
os.getenv('BT_NAVIGATOR_XML'))
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
params_file = os.path.join(script_dir, 'keepout_params.yaml')
|
||||
|
||||
# Replace the `use_astar` setting on the params file
|
||||
param_substitutions = {
|
||||
'planner_server.ros__parameters.GridBased.use_astar': os.getenv('ASTAR'),
|
||||
'filter_mask_server.ros__parameters.yaml_filename': filter_mask_file,
|
||||
'map_server.ros__parameters.yaml_filename': map_yaml_file}
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key='',
|
||||
param_rewrites=param_substitutions,
|
||||
convert_types=True)
|
||||
|
||||
context = LaunchContext()
|
||||
new_yaml = configured_params.perform(context)
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
# Launch gazebo server for simulation
|
||||
ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so',
|
||||
'--minimal_comms', world],
|
||||
output='screen'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
Node(
|
||||
package='nav2_lifecycle_manager',
|
||||
executable='lifecycle_manager',
|
||||
name='lifecycle_manager_filters',
|
||||
output='screen',
|
||||
parameters=[{
|
||||
'node_names':
|
||||
[
|
||||
'filter_mask_server', 'costmap_filter_info_server'
|
||||
]
|
||||
},
|
||||
{'autostart': True}]),
|
||||
|
||||
# Nodes required for Costmap Filters configuration
|
||||
Node(
|
||||
package='nav2_map_server',
|
||||
executable='map_server',
|
||||
name='filter_mask_server',
|
||||
output='screen',
|
||||
parameters=[new_yaml]),
|
||||
|
||||
Node(
|
||||
package='nav2_map_server',
|
||||
executable='costmap_filter_info_server',
|
||||
name='costmap_filter_info_server',
|
||||
output='screen',
|
||||
parameters=[new_yaml]),
|
||||
|
||||
IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(
|
||||
os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
|
||||
launch_arguments={'namespace': '',
|
||||
'use_namespace': 'False',
|
||||
'map': map_yaml_file,
|
||||
'use_sim_time': 'True',
|
||||
'params_file': new_yaml,
|
||||
'bt_xml_file': bt_navigator_xml,
|
||||
'autostart': 'True'}.items()),
|
||||
|
||||
Node(
|
||||
package='nav2_costmap_2d',
|
||||
executable='nav2_costmap_2d_cloud',
|
||||
name='costmap_2d_cloud',
|
||||
output='screen',
|
||||
remappings=[('voxel_grid', 'local_costmap/voxel_grid')]),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[os.path.join(os.getenv('TEST_DIR'), 'tester_node.py'),
|
||||
'-t', 'keepout', '-r', '-2.0', '-0.5', '0.0', '-0.5'],
|
||||
name='tester_node',
|
||||
output='screen')
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,140 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2018 Intel Corporation
|
||||
# Copyright (c) 2020 Samsung Research Russia
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from ament_index_python.packages import get_package_share_directory
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
from launch.actions import ExecuteProcess, IncludeLaunchDescription, SetEnvironmentVariable
|
||||
from launch.launch_context import LaunchContext
|
||||
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
||||
from launch_ros.actions import Node
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
from nav2_common.launch import RewrittenYaml
|
||||
|
||||
|
||||
def generate_launch_description():
|
||||
map_yaml_file = os.getenv('TEST_MAP')
|
||||
filter_mask_file = os.getenv('TEST_MASK')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
bt_navigator_xml = os.path.join(get_package_share_directory('nav2_bt_navigator'),
|
||||
'behavior_trees',
|
||||
os.getenv('BT_NAVIGATOR_XML'))
|
||||
|
||||
bringup_dir = get_package_share_directory('nav2_bringup')
|
||||
params_file = os.getenv('PARAMS_FILE')
|
||||
|
||||
# Replace the `use_astar` setting on the params file
|
||||
param_substitutions = {
|
||||
'planner_server.ros__parameters.GridBased.use_astar': os.getenv('ASTAR'),
|
||||
'filter_mask_server.ros__parameters.yaml_filename': filter_mask_file,
|
||||
'map_server.ros__parameters.yaml_filename': map_yaml_file}
|
||||
configured_params = RewrittenYaml(
|
||||
source_file=params_file,
|
||||
root_key='',
|
||||
param_rewrites=param_substitutions,
|
||||
convert_types=True)
|
||||
context = LaunchContext()
|
||||
new_yaml = configured_params.perform(context)
|
||||
return LaunchDescription([
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_BUFFERED_STREAM', '1'),
|
||||
SetEnvironmentVariable('RCUTILS_LOGGING_USE_STDOUT', '1'),
|
||||
|
||||
# Launch gazebo server for simulation
|
||||
ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so',
|
||||
'--minimal_comms', world],
|
||||
output='screen'),
|
||||
|
||||
# TODO(orduno) Launch the robot state publisher instead
|
||||
# using a local copy of TB3 urdf file
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link']),
|
||||
|
||||
Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan']),
|
||||
|
||||
Node(
|
||||
package='nav2_lifecycle_manager',
|
||||
executable='lifecycle_manager',
|
||||
name='lifecycle_manager_filters',
|
||||
output='screen',
|
||||
parameters=[{
|
||||
'node_names':
|
||||
[
|
||||
'filter_mask_server', 'costmap_filter_info_server'
|
||||
]
|
||||
},
|
||||
{'autostart': True}]),
|
||||
|
||||
# Nodes required for Costmap Filters configuration
|
||||
Node(
|
||||
package='nav2_map_server',
|
||||
executable='map_server',
|
||||
name='filter_mask_server',
|
||||
output='screen',
|
||||
parameters=[new_yaml]),
|
||||
|
||||
Node(
|
||||
package='nav2_map_server',
|
||||
executable='costmap_filter_info_server',
|
||||
name='costmap_filter_info_server',
|
||||
output='screen',
|
||||
parameters=[new_yaml]),
|
||||
|
||||
IncludeLaunchDescription(
|
||||
PythonLaunchDescriptionSource(
|
||||
os.path.join(bringup_dir, 'launch', 'bringup_launch.py')),
|
||||
launch_arguments={'namespace': '',
|
||||
'use_namespace': 'False',
|
||||
'map': map_yaml_file,
|
||||
'use_sim_time': 'True',
|
||||
'params_file': new_yaml,
|
||||
'bt_xml_file': bt_navigator_xml,
|
||||
'autostart': 'True'}.items()),
|
||||
])
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
ld = generate_launch_description()
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[os.path.join(os.getenv('TEST_DIR'), 'tester_node.py'),
|
||||
'-t', 'speed', '-r', '-2.0', '-0.5', '0.0', '-0.5'],
|
||||
name='tester_node',
|
||||
output='screen')
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,537 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2018 Intel Corporation.
|
||||
# Copyright (c) 2020 Samsung Research Russia
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
from enum import Enum
|
||||
import math
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from action_msgs.msg import GoalStatus
|
||||
from geometry_msgs.msg import Pose
|
||||
from geometry_msgs.msg import PoseStamped
|
||||
from geometry_msgs.msg import PoseWithCovarianceStamped
|
||||
from lifecycle_msgs.srv import GetState
|
||||
from nav2_msgs.action import NavigateToPose
|
||||
from nav2_msgs.msg import SpeedLimit
|
||||
from nav2_msgs.srv import ManageLifecycleNodes
|
||||
from nav_msgs.msg import OccupancyGrid
|
||||
from nav_msgs.msg import Path
|
||||
|
||||
import rclpy
|
||||
from rclpy.action import ActionClient
|
||||
from rclpy.node import Node
|
||||
from rclpy.qos import QoSDurabilityPolicy, QoSHistoryPolicy, QoSReliabilityPolicy
|
||||
from rclpy.qos import QoSProfile
|
||||
from sensor_msgs.msg import PointCloud2
|
||||
|
||||
|
||||
class TestType(Enum):
|
||||
KEEPOUT = 0
|
||||
SPEED = 1
|
||||
|
||||
|
||||
class FilterMask():
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
filter_mask: OccupancyGrid
|
||||
):
|
||||
self.filter_mask = filter_mask
|
||||
|
||||
# Converts world coordinates into filter mask map coordinate.
|
||||
# Returns filter mask map coordinates or (-1, -1) in case
|
||||
# if world coordinates are out of mask bounds.
|
||||
def worldToMap(self, wx: float, wy: float):
|
||||
origin_x = self.filter_mask.info.origin.position.x
|
||||
origin_y = self.filter_mask.info.origin.position.y
|
||||
size_x = self.filter_mask.info.width
|
||||
size_y = self.filter_mask.info.height
|
||||
resolution = self.filter_mask.info.resolution
|
||||
|
||||
if wx < origin_x or wy < origin_y:
|
||||
return -1, -1
|
||||
|
||||
mx = int((wx - origin_x) / resolution)
|
||||
my = int((wy - origin_y) / resolution)
|
||||
|
||||
if mx < size_x and my < size_y:
|
||||
return mx, my
|
||||
|
||||
return -1, -1
|
||||
|
||||
# Gets filter_mask[mx, my] value
|
||||
def getValue(self, mx, my):
|
||||
size_x = self.filter_mask.info.width
|
||||
return self.filter_mask.data[mx + my * size_x]
|
||||
|
||||
|
||||
class NavTester(Node):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
test_type: TestType,
|
||||
initial_pose: Pose,
|
||||
goal_pose: Pose,
|
||||
namespace: str = ''
|
||||
):
|
||||
super().__init__(node_name='nav2_tester', namespace=namespace)
|
||||
self.initial_pose_pub = self.create_publisher(PoseWithCovarianceStamped,
|
||||
'initialpose', 10)
|
||||
self.goal_pub = self.create_publisher(PoseStamped, 'goal_pose', 10)
|
||||
|
||||
transient_local_qos = QoSProfile(
|
||||
durability=QoSDurabilityPolicy.TRANSIENT_LOCAL,
|
||||
reliability=QoSReliabilityPolicy.RELIABLE,
|
||||
history=QoSHistoryPolicy.KEEP_LAST,
|
||||
depth=1)
|
||||
|
||||
volatile_qos = QoSProfile(
|
||||
durability=QoSDurabilityPolicy.RMW_QOS_POLICY_DURABILITY_VOLATILE,
|
||||
reliability=QoSReliabilityPolicy.RELIABLE,
|
||||
history=QoSHistoryPolicy.RMW_QOS_POLICY_HISTORY_KEEP_LAST,
|
||||
depth=1)
|
||||
|
||||
self.model_pose_sub = self.create_subscription(PoseWithCovarianceStamped,
|
||||
'amcl_pose', self.poseCallback,
|
||||
transient_local_qos)
|
||||
self.clearing_ep_sub = self.create_subscription(PointCloud2,
|
||||
'local_costmap/clearing_endpoints',
|
||||
self.clearingEndpointsCallback,
|
||||
transient_local_qos)
|
||||
self.test_type = test_type
|
||||
self.filter_test_result = True
|
||||
self.clearing_endpoints_received = False
|
||||
self.voxel_marked_received = False
|
||||
self.voxel_unknown_received = False
|
||||
self.cost_cloud_received = False
|
||||
|
||||
if self.test_type == TestType.KEEPOUT:
|
||||
self.plan_sub = self.create_subscription(Path, 'plan',
|
||||
self.planCallback, volatile_qos)
|
||||
self.voxel_marked_sub = self.create_subscription(PointCloud2,
|
||||
'voxel_marked_cloud',
|
||||
self.voxelMarkedCallback,
|
||||
1)
|
||||
self.voxel_unknown_sub = self.create_subscription(PointCloud2,
|
||||
'voxel_unknown_cloud',
|
||||
self.voxelUnknownCallback,
|
||||
1)
|
||||
self.cost_cloud_sub = self.create_subscription(PointCloud2,
|
||||
'cost_cloud',
|
||||
self.dwbCostCloudCallback,
|
||||
1)
|
||||
elif self.test_type == TestType.SPEED:
|
||||
self.speed_it = 0
|
||||
# Expected chain of speed limits
|
||||
self.limits = [50.0, 0.0]
|
||||
# Permissive array: all received speed limits must match to "limits" from above
|
||||
self.limit_passed = [False, False]
|
||||
self.plan_sub = self.create_subscription(SpeedLimit, 'speed_limit',
|
||||
self.speedLimitCallback, volatile_qos)
|
||||
|
||||
self.mask_received = False
|
||||
self.mask_sub = self.create_subscription(OccupancyGrid, 'filter_mask',
|
||||
self.maskCallback, transient_local_qos)
|
||||
|
||||
self.initial_pose_received = False
|
||||
self.initial_pose = initial_pose
|
||||
self.goal_pose = goal_pose
|
||||
self.action_client = ActionClient(
|
||||
self, NavigateToPose, 'navigate_to_pose')
|
||||
|
||||
def info_msg(self, msg: str):
|
||||
self.get_logger().info('\033[1;37;44m' + msg + '\033[0m')
|
||||
|
||||
def warn_msg(self, msg: str):
|
||||
self.get_logger().warn('\033[1;37;43m' + msg + '\033[0m')
|
||||
|
||||
def error_msg(self, msg: str):
|
||||
self.get_logger().error('\033[1;37;41m' + msg + '\033[0m')
|
||||
|
||||
def setInitialPose(self):
|
||||
msg = PoseWithCovarianceStamped()
|
||||
msg.pose.pose = self.initial_pose
|
||||
msg.header.frame_id = 'map'
|
||||
self.info_msg('Publishing Initial Pose')
|
||||
self.initial_pose_pub.publish(msg)
|
||||
self.currentPose = self.initial_pose
|
||||
|
||||
def getStampedPoseMsg(self, pose: Pose):
|
||||
msg = PoseStamped()
|
||||
msg.header.frame_id = 'map'
|
||||
msg.pose = pose
|
||||
return msg
|
||||
|
||||
def publishGoalPose(self, goal_pose: Optional[Pose] = None):
|
||||
self.goal_pose = goal_pose if goal_pose is not None else self.goal_pose
|
||||
self.goal_pub.publish(self.getStampedPoseMsg(self.goal_pose))
|
||||
|
||||
def runNavigateAction(self, goal_pose: Optional[Pose] = None):
|
||||
# Sends a `NavToPose` action request and waits for completion
|
||||
self.info_msg("Waiting for 'NavigateToPose' action server")
|
||||
while not self.action_client.wait_for_server(timeout_sec=1.0):
|
||||
self.info_msg(
|
||||
"'NavigateToPose' action server not available, waiting...")
|
||||
|
||||
self.goal_pose = goal_pose if goal_pose is not None else self.goal_pose
|
||||
goal_msg = NavigateToPose.Goal()
|
||||
goal_msg.pose = self.getStampedPoseMsg(self.goal_pose)
|
||||
|
||||
self.info_msg('Sending goal request...')
|
||||
send_goal_future = self.action_client.send_goal_async(goal_msg)
|
||||
|
||||
rclpy.spin_until_future_complete(self, send_goal_future)
|
||||
goal_handle = send_goal_future.result()
|
||||
|
||||
if not goal_handle.accepted:
|
||||
self.error_msg('Goal rejected')
|
||||
return False
|
||||
|
||||
self.info_msg('Goal accepted')
|
||||
get_result_future = goal_handle.get_result_async()
|
||||
|
||||
self.info_msg("Waiting for 'NavigateToPose' action to complete")
|
||||
rclpy.spin_until_future_complete(self, get_result_future)
|
||||
status = get_result_future.result().status
|
||||
if status != GoalStatus.STATUS_SUCCEEDED:
|
||||
self.info_msg(f'Goal failed with status code: {status}')
|
||||
return False
|
||||
|
||||
self.info_msg('Goal succeeded!')
|
||||
return True
|
||||
|
||||
def isInKeepout(self, x, y):
|
||||
mx, my = self.filter_mask.worldToMap(x, y)
|
||||
if mx == -1 and my == -1: # Out of mask's area
|
||||
return False
|
||||
if self.filter_mask.getValue(mx, my) == 100: # Occupied
|
||||
return True
|
||||
return False
|
||||
|
||||
# Checks that (x, y) position does not belong to a keepout zone.
|
||||
def checkKeepout(self, x, y):
|
||||
if not self.mask_received:
|
||||
self.warn_msg('Filter mask was not received')
|
||||
elif self.isInKeepout(x, y):
|
||||
self.filter_test_result = False
|
||||
self.error_msg(f'Pose ({x}, {y}) belongs to keepout zone')
|
||||
return False
|
||||
return True
|
||||
|
||||
# Checks that currently received speed_limit is equal to the it-th item
|
||||
# of expected speed "limits" array.
|
||||
# If so, sets it-th item of permissive array "limit_passed" to be true.
|
||||
# Otherwise it will be remained to be false.
|
||||
# Also verifies that speed limit messages received no more than N-times
|
||||
# (where N - is the length of "limits" array),
|
||||
# otherwise sets overall "filter_test_result" to be false.
|
||||
def checkSpeed(self, it, speed_limit):
|
||||
if it >= len(self.limits):
|
||||
self.error_msg('Got excess speed limit')
|
||||
self.filter_test_result = False
|
||||
return
|
||||
if speed_limit == self.limits[it]:
|
||||
self.limit_passed[it] = True
|
||||
else:
|
||||
self.error_msg('Incorrect speed limit received: ' + str(speed_limit) +
|
||||
', but should be: ' + str(self.limits[it]))
|
||||
|
||||
def poseCallback(self, msg):
|
||||
self.info_msg('Received amcl_pose')
|
||||
self.current_pose = msg.pose.pose
|
||||
self.initial_pose_received = True
|
||||
if self.test_type == TestType.KEEPOUT:
|
||||
if not self.checkKeepout(msg.pose.pose.position.x, msg.pose.pose.position.y):
|
||||
self.error_msg('Robot goes into keepout zone')
|
||||
|
||||
def planCallback(self, msg):
|
||||
self.info_msg('Received plan')
|
||||
for pose in msg.poses:
|
||||
if not self.checkKeepout(pose.pose.position.x, pose.pose.position.y):
|
||||
self.error_msg('Path plan intersects with keepout zone')
|
||||
return
|
||||
|
||||
def clearingEndpointsCallback(self, msg):
|
||||
if len(msg.data) > 0:
|
||||
self.clearing_endpoints_received = True
|
||||
|
||||
def voxelMarkedCallback(self, msg):
|
||||
if len(msg.data) > 0:
|
||||
self.voxel_marked_received = True
|
||||
|
||||
def voxelUnknownCallback(self, msg):
|
||||
if len(msg.data) > 0:
|
||||
self.voxel_unknown_received = True
|
||||
|
||||
def dwbCostCloudCallback(self, msg):
|
||||
self.info_msg('Received cost_cloud points')
|
||||
if len(msg.data) > 0:
|
||||
self.cost_cloud_received = True
|
||||
|
||||
def speedLimitCallback(self, msg):
|
||||
self.info_msg(f'Received speed limit: {msg.speed_limit}')
|
||||
self.checkSpeed(self.speed_it, msg.speed_limit)
|
||||
self.speed_it += 1
|
||||
|
||||
def maskCallback(self, msg):
|
||||
self.info_msg('Received filter mask')
|
||||
self.filter_mask = FilterMask(msg)
|
||||
self.mask_received = True
|
||||
|
||||
def wait_for_filter_mask(self, timeout):
|
||||
start_time = time.time()
|
||||
|
||||
while not self.mask_received:
|
||||
self.info_msg('Waiting for filter mask to be received ...')
|
||||
rclpy.spin_once(self, timeout_sec=1)
|
||||
if (time.time() - start_time) > timeout:
|
||||
self.error_msg('Time out to waiting filter mask')
|
||||
return False
|
||||
return True
|
||||
|
||||
def wait_for_pointcloud_subscribers(self, timeout):
|
||||
start_time = time.time()
|
||||
while not self.voxel_unknown_received or not self.voxel_marked_received \
|
||||
or not self.clearing_endpoints_received:
|
||||
self.info_msg(
|
||||
'Waiting for voxel_marked_cloud/voxel_unknown_cloud/\
|
||||
clearing_endpoints msg to be received ...')
|
||||
rclpy.spin_once(self, timeout_sec=1)
|
||||
if (time.time() - start_time) > timeout:
|
||||
self.error_msg(
|
||||
'Time out to waiting for voxel_marked_cloud/voxel_unknown_cloud/\
|
||||
clearing_endpoints msgs')
|
||||
return False
|
||||
return True
|
||||
|
||||
def reachesGoal(self, timeout, distance):
|
||||
goalReached = False
|
||||
start_time = time.time()
|
||||
|
||||
while not goalReached:
|
||||
rclpy.spin_once(self, timeout_sec=1)
|
||||
if self.distanceFromGoal() < distance:
|
||||
goalReached = True
|
||||
self.info_msg('*** GOAL REACHED ***')
|
||||
return True
|
||||
elif timeout is not None:
|
||||
if (time.time() - start_time) > timeout:
|
||||
self.error_msg('Robot timed out reaching its goal!')
|
||||
return False
|
||||
|
||||
def distanceFromGoal(self):
|
||||
d_x = self.current_pose.position.x - self.goal_pose.position.x
|
||||
d_y = self.current_pose.position.y - self.goal_pose.position.y
|
||||
distance = math.sqrt(d_x * d_x + d_y * d_y)
|
||||
self.info_msg(f'Distance from goal is: {distance}')
|
||||
return distance
|
||||
|
||||
def wait_for_node_active(self, node_name: str):
|
||||
# Waits for the node within the tester namespace to become active
|
||||
self.info_msg(f'Waiting for {node_name} to become active')
|
||||
node_service = f'{node_name}/get_state'
|
||||
state_client = self.create_client(GetState, node_service)
|
||||
while not state_client.wait_for_service(timeout_sec=1.0):
|
||||
self.info_msg(f'{node_service} service not available, waiting...')
|
||||
req = GetState.Request() # empty request
|
||||
state = 'UNKNOWN'
|
||||
while (state != 'active'):
|
||||
self.info_msg(f'Getting {node_name} state...')
|
||||
future = state_client.call_async(req)
|
||||
rclpy.spin_until_future_complete(self, future)
|
||||
if future.result() is not None:
|
||||
state = future.result().current_state.label
|
||||
self.info_msg(f'Result of get_state: {state}')
|
||||
else:
|
||||
self.error_msg('Exception while calling service: %r' %
|
||||
future.exception())
|
||||
time.sleep(5)
|
||||
|
||||
def shutdown(self):
|
||||
self.info_msg('Shutting down')
|
||||
self.action_client.destroy()
|
||||
|
||||
transition_service = 'lifecycle_manager_navigation/manage_nodes'
|
||||
mgr_client = self.create_client(
|
||||
ManageLifecycleNodes, transition_service)
|
||||
while not mgr_client.wait_for_service(timeout_sec=1.0):
|
||||
self.info_msg(f'{transition_service} service not available, waiting...')
|
||||
|
||||
req = ManageLifecycleNodes.Request()
|
||||
req.command = ManageLifecycleNodes.Request().SHUTDOWN
|
||||
future = mgr_client.call_async(req)
|
||||
try:
|
||||
self.info_msg('Shutting down navigation lifecycle manager...')
|
||||
rclpy.spin_until_future_complete(self, future)
|
||||
future.result()
|
||||
self.info_msg(
|
||||
'Shutting down navigation lifecycle manager complete.')
|
||||
except Exception as e: # noqa: B902
|
||||
self.error_msg(f'Service call failed {e!r}')
|
||||
transition_service = 'lifecycle_manager_localization/manage_nodes'
|
||||
mgr_client = self.create_client(
|
||||
ManageLifecycleNodes, transition_service)
|
||||
while not mgr_client.wait_for_service(timeout_sec=1.0):
|
||||
self.info_msg(f'{transition_service} service not available, waiting...')
|
||||
|
||||
req = ManageLifecycleNodes.Request()
|
||||
req.command = ManageLifecycleNodes.Request().SHUTDOWN
|
||||
future = mgr_client.call_async(req)
|
||||
try:
|
||||
self.info_msg('Shutting down localization lifecycle manager...')
|
||||
rclpy.spin_until_future_complete(self, future)
|
||||
future.result()
|
||||
self.info_msg(
|
||||
'Shutting down localization lifecycle manager complete')
|
||||
except Exception as e: # noqa: B902
|
||||
self.error_msg(f'Service call failed {e!r}')
|
||||
|
||||
def wait_for_initial_pose(self):
|
||||
self.initial_pose_received = False
|
||||
while not self.initial_pose_received:
|
||||
self.info_msg('Setting initial pose')
|
||||
self.setInitialPose()
|
||||
self.info_msg('Waiting for amcl_pose to be received')
|
||||
rclpy.spin_once(self, timeout_sec=1)
|
||||
|
||||
|
||||
def test_RobotMovesToGoal(robot_tester):
|
||||
robot_tester.info_msg('Setting goal pose')
|
||||
robot_tester.publishGoalPose()
|
||||
robot_tester.info_msg('Waiting 60 seconds for robot to reach goal')
|
||||
return robot_tester.reachesGoal(timeout=60, distance=0.5)
|
||||
|
||||
|
||||
# Tests that all received speed limits are correct:
|
||||
# If overall "filter_test_result" is true
|
||||
# checks that all items in "limit_passed" permissive array are also true.
|
||||
# In other words, it verifies that all speed limits are received
|
||||
# exactly (by count and values) as expected by "limits" array.
|
||||
def test_SpeedLimitsAllCorrect(robot_tester):
|
||||
if not robot_tester.filter_test_result:
|
||||
return False
|
||||
for passed in robot_tester.limit_passed:
|
||||
if not passed:
|
||||
robot_tester.error_msg('Did not meet one of the speed limit')
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def run_all_tests(robot_tester):
|
||||
# set transforms to use_sim_time
|
||||
result = True
|
||||
if (result):
|
||||
robot_tester.wait_for_node_active('amcl')
|
||||
robot_tester.wait_for_initial_pose()
|
||||
robot_tester.wait_for_node_active('bt_navigator')
|
||||
result = robot_tester.wait_for_filter_mask(10)
|
||||
if (result):
|
||||
result = robot_tester.runNavigateAction()
|
||||
|
||||
if robot_tester.test_type == TestType.KEEPOUT:
|
||||
result = result and robot_tester.wait_for_pointcloud_subscribers(10)
|
||||
|
||||
if (result):
|
||||
result = test_RobotMovesToGoal(robot_tester)
|
||||
|
||||
if (result):
|
||||
if robot_tester.test_type == TestType.KEEPOUT:
|
||||
result = robot_tester.filter_test_result
|
||||
result = result and robot_tester.cost_cloud_received
|
||||
elif robot_tester.test_type == TestType.SPEED:
|
||||
result = test_SpeedLimitsAllCorrect(robot_tester)
|
||||
|
||||
# Add more tests here if desired
|
||||
|
||||
if (result):
|
||||
robot_tester.info_msg('Test PASSED')
|
||||
else:
|
||||
robot_tester.error_msg('Test FAILED')
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def fwd_pose(x=0.0, y=0.0, z=0.01):
|
||||
initial_pose = Pose()
|
||||
initial_pose.position.x = x
|
||||
initial_pose.position.y = y
|
||||
initial_pose.position.z = z
|
||||
initial_pose.orientation.x = 0.0
|
||||
initial_pose.orientation.y = 0.0
|
||||
initial_pose.orientation.z = 0.0
|
||||
initial_pose.orientation.w = 1.0
|
||||
return initial_pose
|
||||
|
||||
|
||||
def get_tester(args):
|
||||
|
||||
# Requested tester for one robot
|
||||
type_str = args.type
|
||||
init_x, init_y, final_x, final_y = args.robot[0]
|
||||
test_type = TestType.KEEPOUT # Default value
|
||||
if type_str == 'speed':
|
||||
test_type = TestType.SPEED
|
||||
|
||||
tester = NavTester(
|
||||
test_type,
|
||||
initial_pose=fwd_pose(float(init_x), float(init_y)),
|
||||
goal_pose=fwd_pose(float(final_x), float(final_y)))
|
||||
tester.info_msg(
|
||||
'Starting tester, robot going from ' + init_x + ', ' + init_y +
|
||||
' to ' + final_x + ', ' + final_y + '.')
|
||||
return tester
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
# The robot(s) positions from the input arguments
|
||||
parser = argparse.ArgumentParser(
|
||||
description='System-level costmap filters tester node')
|
||||
parser.add_argument('-t', '--type', type=str, action='store', dest='type',
|
||||
help='Type of costmap filter being tested.')
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument('-r', '--robot', action='append', nargs=4,
|
||||
metavar=('init_x', 'init_y', 'final_x', 'final_y'),
|
||||
help='The robot starting and final positions.')
|
||||
|
||||
args, unknown = parser.parse_known_args()
|
||||
|
||||
rclpy.init()
|
||||
|
||||
# Create tester for the robot
|
||||
tester = get_tester(args)
|
||||
|
||||
# wait a few seconds to make sure entire stacks are up
|
||||
time.sleep(10)
|
||||
|
||||
passed = run_all_tests(tester)
|
||||
|
||||
# stop and shutdown the nav stack to exit cleanly
|
||||
tester.shutdown()
|
||||
tester.info_msg('Done Shutting Down.')
|
||||
|
||||
if not passed:
|
||||
tester.info_msg('Exiting failed')
|
||||
exit(1)
|
||||
else:
|
||||
tester.info_msg('Exiting passed')
|
||||
exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,13 +0,0 @@
|
||||
add_executable(dummy_controller_node
|
||||
src/dummy_controller/main.cpp
|
||||
src/dummy_controller/dummy_controller.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(dummy_controller_node
|
||||
rclcpp
|
||||
std_msgs
|
||||
nav2_util
|
||||
nav2_behavior_tree
|
||||
nav2_msgs
|
||||
nav_msgs
|
||||
)
|
||||
@@ -1,104 +0,0 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "dummy_controller.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
DummyController::DummyController()
|
||||
: Node("DummyController")
|
||||
{
|
||||
RCLCPP_INFO(get_logger(), "Initializing DummyController...");
|
||||
|
||||
auto temp_node = std::shared_ptr<rclcpp::Node>(this, [](auto) {});
|
||||
|
||||
vel_pub_ =
|
||||
this->create_publisher<geometry_msgs::msg::Twist>("cmd_vel", 1);
|
||||
|
||||
task_server_ = std::make_unique<nav2_behavior_tree::FollowPathTaskServer>(temp_node, false),
|
||||
task_server_->setExecuteCallback(
|
||||
std::bind(&DummyController::followPath, this, std::placeholders::_1));
|
||||
|
||||
// Start listening for incoming ComputePathToPose action server requests
|
||||
task_server_->start();
|
||||
|
||||
RCLCPP_INFO(get_logger(), "Initialized DummyController");
|
||||
}
|
||||
|
||||
DummyController::~DummyController()
|
||||
{
|
||||
RCLCPP_INFO(get_logger(), "Shutting down DummyController");
|
||||
}
|
||||
|
||||
void
|
||||
DummyController::followPath(const nav2_behavior_tree::FollowPathCommand::SharedPtr /*command*/)
|
||||
{
|
||||
RCLCPP_INFO(get_logger(), "Starting controller ");
|
||||
|
||||
auto start_time = std::chrono::system_clock::now();
|
||||
auto time_since_msg = std::chrono::system_clock::now();
|
||||
|
||||
while (true) {
|
||||
// Dummy controller computation time
|
||||
std::this_thread::sleep_for(50ms);
|
||||
|
||||
if (task_server_->cancelRequested()) {
|
||||
RCLCPP_INFO(get_logger(), "Task cancelled");
|
||||
setZeroVelocity();
|
||||
task_server_->setCanceled();
|
||||
return;
|
||||
}
|
||||
|
||||
// Log a message every second
|
||||
auto current_time = std::chrono::system_clock::now();
|
||||
if (current_time - time_since_msg >= 1s) {
|
||||
RCLCPP_INFO(get_logger(), "Following path");
|
||||
time_since_msg = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
// Output control command
|
||||
auto cmd_vel = std::make_unique<geometry_msgs::msg::Twist>();
|
||||
cmd_vel->linear.x = 0.1;
|
||||
vel_pub_->publish(std::move(cmd_vel));
|
||||
|
||||
if (current_time - start_time >= 30s) {
|
||||
RCLCPP_INFO(get_logger(), "Reached end point");
|
||||
setZeroVelocity();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nav2_behavior_tree::FollowPathResult result;
|
||||
task_server_->setResult(result);
|
||||
}
|
||||
|
||||
void DummyController::setZeroVelocity()
|
||||
{
|
||||
auto cmd_vel = std::make_unique<geometry_msgs::msg::Twist>();
|
||||
cmd_vel->linear.x = 0.0;
|
||||
cmd_vel->linear.y = 0.0;
|
||||
cmd_vel->angular.z = 0.0;
|
||||
vel_pub_->publish(std::move(cmd_vel));
|
||||
}
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
@@ -1,45 +0,0 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef DUMMY_CONTROLLER__DUMMY_CONTROLLER_HPP_
|
||||
#define DUMMY_CONTROLLER__DUMMY_CONTROLLER_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "nav2_behavior_tree/follow_path_task.hpp"
|
||||
#include "geometry_msgs/msg/twist.hpp"
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
class DummyController : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
DummyController();
|
||||
~DummyController();
|
||||
|
||||
nav2_behavior_tree::TaskStatus followPath(
|
||||
const nav2_behavior_tree::FollowPathCommand::SharedPtr command);
|
||||
|
||||
private:
|
||||
void setZeroVelocity();
|
||||
|
||||
std::unique_ptr<nav2_behavior_tree::FollowPathTaskServer> task_server_;
|
||||
|
||||
std::shared_ptr<rclcpp::Publisher<geometry_msgs::msg::Twist>> vel_pub_;
|
||||
};
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
|
||||
#endif // DUMMY_CONTROLLER__DUMMY_CONTROLLER_HPP_
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <memory>
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "dummy_controller.hpp"
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
rclcpp::init(argc, argv);
|
||||
rclcpp::spin(std::make_shared<nav2_system_tests::DummyController>());
|
||||
rclcpp::shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
add_executable(dummy_planner_node
|
||||
src/dummy_planner/main.cpp
|
||||
src/dummy_planner/dummy_planner.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(dummy_planner_node
|
||||
rclcpp
|
||||
std_msgs
|
||||
nav2_util
|
||||
nav2_behavior_tree
|
||||
nav2_msgs
|
||||
nav_msgs
|
||||
)
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
|
||||
#include "dummy_planner.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
DummyPlanner::DummyPlanner()
|
||||
: Node("DummyPlanner")
|
||||
{
|
||||
RCLCPP_INFO(get_logger(), "Initializing DummyPlanner...");
|
||||
|
||||
auto temp_node = std::shared_ptr<rclcpp::Node>(this, [](auto) {});
|
||||
|
||||
task_server_ =
|
||||
std::make_unique<nav2_behavior_tree::ComputePathToPoseTaskServer>(temp_node, false),
|
||||
task_server_->setExecuteCallback(
|
||||
std::bind(&DummyPlanner::computePlan, this, std::placeholders::_1));
|
||||
|
||||
// Start listening for incoming ComputePathToPose task requests
|
||||
task_server_->start();
|
||||
|
||||
RCLCPP_INFO(get_logger(), "Initialized DummyPlanner");
|
||||
}
|
||||
|
||||
DummyPlanner::~DummyPlanner()
|
||||
{
|
||||
RCLCPP_INFO(get_logger(), "Shutting down DummyPlanner");
|
||||
}
|
||||
|
||||
void
|
||||
DummyPlanner::computePlan(const nav2_behavior_tree::ComputePathToPoseCommand::SharedPtr cmd)
|
||||
{
|
||||
RCLCPP_INFO(
|
||||
get_logger(), "Attempting to a find path from (%.2f, %.2f) to "
|
||||
"(%.2f, %.2f).", cmd->start.position.x, cmd->start.position.y,
|
||||
cmd->goal.position.x, cmd->goal.position.y);
|
||||
|
||||
// Dummy path computation time
|
||||
std::this_thread::sleep_for(500ms);
|
||||
|
||||
if (task_server_->cancelRequested()) {
|
||||
RCLCPP_INFO(get_logger(), "Cancelled planning task.");
|
||||
task_server_->setCanceled();
|
||||
return;
|
||||
}
|
||||
|
||||
RCLCPP_INFO(get_logger(), "Found a dummy path");
|
||||
|
||||
nav2_behavior_tree::ComputePathToPoseResult result;
|
||||
// set succeeded
|
||||
task_server_->setResult(result);
|
||||
}
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef DUMMY_PLANNER__DUMMY_PLANNER_HPP_
|
||||
#define DUMMY_PLANNER__DUMMY_PLANNER_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "nav2_behavior_tree/compute_path_to_pose_task.hpp"
|
||||
|
||||
namespace nav2_system_tests
|
||||
{
|
||||
|
||||
class DummyPlanner : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
DummyPlanner();
|
||||
~DummyPlanner();
|
||||
|
||||
nav2_behavior_tree::TaskStatus computePathToPose(
|
||||
const nav2_behavior_tree::ComputePathToPoseCommand::SharedPtr command);
|
||||
|
||||
private:
|
||||
std::unique_ptr<nav2_behavior_tree::ComputePathToPoseTaskServer> task_server_;
|
||||
};
|
||||
|
||||
} // namespace nav2_system_tests
|
||||
|
||||
#endif // DUMMY_PLANNER__DUMMY_PLANNER_HPP_
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License. Reserved.
|
||||
|
||||
#include <memory>
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "dummy_planner.hpp"
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
rclcpp::init(argc, argv);
|
||||
rclcpp::spin(std::make_shared<nav2_system_tests::DummyPlanner>());
|
||||
rclcpp::shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
ament_add_gtest_executable(test_localization_node
|
||||
test_localization_node.cpp
|
||||
)
|
||||
ament_target_dependencies(test_localization_node
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
|
||||
ament_add_test(test_localization
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_localization_launch.py"
|
||||
TIMEOUT 180
|
||||
ENV
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map_circular.yaml
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:test_localization_node>
|
||||
TEST_WORLD=${PROJECT_SOURCE_DIR}/worlds/turtlebot3_ros2_demo.world
|
||||
GAZEBO_MODEL_PATH=${PROJECT_SOURCE_DIR}/models
|
||||
)
|
||||
@@ -1,22 +0,0 @@
|
||||
# Localization Testing
|
||||
|
||||
The intention of the localization test is to ensure robot’s pose and transforms are available.
|
||||
|
||||
Currently, only a simple test that checks the `initialpose` has been implemented. The `test_localization` module publishes an initial pose on `initialpose` topic and then it listens to `amcl_pose` topic. If the `amcl_pose` is similar to `initial pose` within a predefined tolerance the test passes.
|
||||
|
||||
## To run the test
|
||||
First, build the package
|
||||
```
|
||||
colcon build --symlink-install
|
||||
```
|
||||
After building, from /build/nav2_system_tests directory run:
|
||||
```
|
||||
ctest -V -R test_localization
|
||||
```
|
||||
Alternately you can run all the tests in the package using colcon:
|
||||
```
|
||||
colcon test --packages-select nav2_system_tests
|
||||
```
|
||||
|
||||
## Future Plan
|
||||
Once rosbag functionality becomes available, this test can be extended to utilize a recorded trajectory with map and scan data to monitor the `amcl_pose` and `transforms` without a need to run Gazebo and map_server.
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2018 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from launch import LaunchDescription
|
||||
from launch import LaunchService
|
||||
import launch.actions
|
||||
from launch.actions import ExecuteProcess
|
||||
import launch_ros.actions
|
||||
from launch_testing.legacy import LaunchTestService
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
mapFile = os.getenv('TEST_MAP')
|
||||
testExecutable = os.getenv('TEST_EXECUTABLE')
|
||||
world = os.getenv('TEST_WORLD')
|
||||
|
||||
launch_gazebo = launch.actions.ExecuteProcess(
|
||||
cmd=['gzserver', '-s', 'libgazebo_ros_init.so', '--minimal_comms', world],
|
||||
output='screen')
|
||||
link_footprint = launch_ros.actions.Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_footprint', 'base_link'])
|
||||
footprint_scan = launch_ros.actions.Node(
|
||||
package='tf2_ros',
|
||||
executable='static_transform_publisher',
|
||||
output='screen',
|
||||
arguments=['0', '0', '0', '0', '0', '0', 'base_link', 'base_scan'])
|
||||
run_map_server = launch_ros.actions.Node(
|
||||
package='nav2_map_server',
|
||||
executable='map_server',
|
||||
name='map_server',
|
||||
output='screen',
|
||||
parameters=[{'yaml_filename': mapFile}])
|
||||
run_amcl = launch_ros.actions.Node(
|
||||
package='nav2_amcl',
|
||||
executable='amcl',
|
||||
output='screen')
|
||||
run_lifecycle_manager = launch_ros.actions.Node(
|
||||
package='nav2_lifecycle_manager',
|
||||
executable='lifecycle_manager',
|
||||
name='lifecycle_manager',
|
||||
output='screen',
|
||||
parameters=[{'node_names': ['map_server', 'amcl']}, {'autostart': True}])
|
||||
ld = LaunchDescription([launch_gazebo, link_footprint, footprint_scan,
|
||||
run_map_server, run_amcl, run_lifecycle_manager])
|
||||
|
||||
test1_action = ExecuteProcess(
|
||||
cmd=[testExecutable],
|
||||
name='test_localization_node',
|
||||
output='screen'
|
||||
)
|
||||
|
||||
lts = LaunchTestService()
|
||||
lts.add_test_action(ld, test1_action)
|
||||
ls = LaunchService(argv=argv)
|
||||
ls.include_launch_description(ld)
|
||||
return lts.run(ls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright (c) 2018 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <memory>
|
||||
#include "gtest/gtest.h"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "nav2_amcl/amcl_node.hpp"
|
||||
#include "std_msgs/msg/string.hpp"
|
||||
#include "geometry_msgs/msg/pose_array.hpp"
|
||||
#include "geometry_msgs/msg/pose_stamped.hpp"
|
||||
|
||||
using std::placeholders::_1;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
// rclcpp::init can only be called once per process, so this needs to be a global variable
|
||||
class RclCppFixture
|
||||
{
|
||||
public:
|
||||
RclCppFixture() {rclcpp::init(0, nullptr);}
|
||||
~RclCppFixture() {rclcpp::shutdown();}
|
||||
};
|
||||
RclCppFixture g_rclcppfixture;
|
||||
|
||||
class TestAmclPose : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
TestAmclPose()
|
||||
{
|
||||
pose_callback_ = false;
|
||||
initTestPose();
|
||||
tol_ = 0.25;
|
||||
|
||||
node = rclcpp::Node::make_shared("localization_test");
|
||||
|
||||
while (node->count_subscribers("scan") < 1) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
initial_pose_pub_ = node->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>(
|
||||
"initialpose", rclcpp::SystemDefaultsQoS());
|
||||
subscription_ = node->create_subscription<geometry_msgs::msg::PoseWithCovarianceStamped>(
|
||||
"amcl_pose", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
|
||||
std::bind(&TestAmclPose::amcl_pose_callback, this, _1));
|
||||
initial_pose_pub_->publish(testPose_);
|
||||
}
|
||||
|
||||
bool defaultAmclTest();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<rclcpp::Node> node;
|
||||
void initTestPose();
|
||||
|
||||
private:
|
||||
void amcl_pose_callback(const geometry_msgs::msg::PoseWithCovarianceStamped::SharedPtr msg)
|
||||
{
|
||||
auto amcl_pose = msg->pose;
|
||||
amcl_pose_x = amcl_pose.pose.position.x;
|
||||
amcl_pose_y = amcl_pose.pose.position.y;
|
||||
pose_callback_ = true;
|
||||
}
|
||||
rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr initial_pose_pub_;
|
||||
rclcpp::Subscription<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr subscription_;
|
||||
geometry_msgs::msg::PoseWithCovarianceStamped testPose_;
|
||||
double amcl_pose_x;
|
||||
double amcl_pose_y;
|
||||
bool pose_callback_;
|
||||
float tol_;
|
||||
};
|
||||
|
||||
bool TestAmclPose::defaultAmclTest()
|
||||
{
|
||||
initial_pose_pub_->publish(testPose_);
|
||||
while (!pose_callback_) {
|
||||
// TODO(mhpanah): Initial pose should only be published once.
|
||||
initial_pose_pub_->publish(testPose_);
|
||||
std::this_thread::sleep_for(1s);
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
if (std::abs(amcl_pose_x - testPose_.pose.pose.position.x) < tol_ &&
|
||||
std::abs(amcl_pose_y - testPose_.pose.pose.position.y) < tol_)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TestAmclPose::initTestPose()
|
||||
{
|
||||
testPose_.header.frame_id = "map";
|
||||
testPose_.header.stamp = rclcpp::Time();
|
||||
testPose_.pose.pose.position.x = -2.0;
|
||||
testPose_.pose.pose.position.y = -0.5;
|
||||
testPose_.pose.pose.position.z = 0.0;
|
||||
testPose_.pose.pose.orientation.x = 0.0;
|
||||
testPose_.pose.pose.orientation.y = 0.0;
|
||||
testPose_.pose.pose.orientation.z = 0.0;
|
||||
testPose_.pose.pose.orientation.w = 1.0;
|
||||
for (int i = 0; i < 35; i++) {
|
||||
testPose_.pose.covariance[i] = 0.0;
|
||||
}
|
||||
testPose_.pose.covariance[0] = 0.08;
|
||||
testPose_.pose.covariance[7] = 0.08;
|
||||
testPose_.pose.covariance[35] = 0.05;
|
||||
}
|
||||
|
||||
TEST_F(TestAmclPose, SimpleAmclTest)
|
||||
{
|
||||
EXPECT_EQ(true, defaultAmclTest());
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
set(test_planner_costmaps_exec test_planner_costmaps_node)
|
||||
|
||||
ament_add_gtest_executable(${test_planner_costmaps_exec}
|
||||
test_planner_costmaps_node.cpp
|
||||
planner_tester.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(${test_planner_costmaps_exec}
|
||||
${nav2_map_server_LIBRARIES})
|
||||
|
||||
ament_target_dependencies(${test_planner_costmaps_exec}
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
set(test_planner_random_exec test_planner_random_node)
|
||||
|
||||
ament_add_gtest_executable(${test_planner_random_exec}
|
||||
test_planner_random_node.cpp
|
||||
planner_tester.cpp
|
||||
)
|
||||
|
||||
ament_target_dependencies(${test_planner_random_exec}
|
||||
${dependencies}
|
||||
)
|
||||
|
||||
target_link_libraries(${test_planner_random_exec}
|
||||
${nav2_map_server_LIBRARIES})
|
||||
|
||||
ament_add_test(test_planner_costmaps
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_planner_costmaps_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
ENV
|
||||
TEST_LAUNCH_DIR=${TEST_LAUNCH_DIR}
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_planner_costmaps_exec}>
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map.pgm
|
||||
)
|
||||
|
||||
ament_add_test(test_planner_random
|
||||
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
|
||||
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/test_planner_random_launch.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
ENV
|
||||
TEST_LAUNCH_DIR=${TEST_LAUNCH_DIR}
|
||||
TEST_EXECUTABLE=$<TARGET_FILE:${test_planner_random_exec}>
|
||||
TEST_MAP=${PROJECT_SOURCE_DIR}/maps/map.pgm
|
||||
)
|
||||
|
||||
ament_add_gtest(test_planner_plugins
|
||||
test_planner_plugins.cpp
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
ament_target_dependencies(test_planner_plugins rclcpp geometry_msgs nav2_msgs ${dependencies})
|
||||
target_link_libraries(test_planner_plugins
|
||||
# stdc++fs
|
||||
)
|
||||
|
||||
ament_add_gtest(test_planner_is_path_valid
|
||||
test_planner_is_path_valid.cpp
|
||||
planner_tester.cpp)
|
||||
|
||||
ament_target_dependencies(test_planner_is_path_valid rclcpp geometry_msgs nav2_msgs ${dependencies})
|
||||
@@ -1,15 +0,0 @@
|
||||
# Global Planner Component Testing
|
||||
|
||||
A PlannerTester node provides the world representation in the form of a costmap, sends a request to generate a path, and receives and checks the quality of the generated path.
|
||||
|
||||
As mentioned above, currently the world is represented as a costmap. Simplified versions of the world model and costmap are used for testing.
|
||||
|
||||
PlannerTester can sequentially pass random starting and goal poses and check the returned path for possible collision along the path.
|
||||
|
||||
Below is an example of the output from randomized testing. Blue spheres represent the starting locations, green, the goals. Red lines are the computed paths. Grey cells represent obstacles.
|
||||
|
||||

|
||||
|
||||
*Note: Currently robot size is 1x1 cells, no obstacle inflation is done on the costmap*
|
||||
|
||||
*Note: The Navfn algorithm sometimes fails to generate a path as you can see from the 'orphan' spheres.*
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 285 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user