From 2d31a8d3346d3a9ba6ab99a94d208bdf5879b413 Mon Sep 17 00:00:00 2001 From: Wilco Bonestroo <w.j.bonestroo@saxion.nl> Date: Fri, 20 Nov 2020 21:17:49 +0100 Subject: [PATCH] Add prefer forward critic test (#2097) * Test setting the parameters. * Added the score tests. * Use variables for parameters and add test for non-default values. * Cleanup. Removed commented out code. --- .../dwb_critics/CMakeLists.txt | 3 + .../dwb_critics/test/CMakeLists.txt | 2 + .../dwb_critics/test/prefer_forward_test.cpp | 229 ++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 nav2_dwb_controller/dwb_critics/test/CMakeLists.txt create mode 100644 nav2_dwb_controller/dwb_critics/test/prefer_forward_test.cpp diff --git a/nav2_dwb_controller/dwb_critics/CMakeLists.txt b/nav2_dwb_controller/dwb_critics/CMakeLists.txt index 7b7cb8c7..606ba052 100644 --- a/nav2_dwb_controller/dwb_critics/CMakeLists.txt +++ b/nav2_dwb_controller/dwb_critics/CMakeLists.txt @@ -74,6 +74,9 @@ if(BUILD_TESTING) # the following line skips the linter which checks for copyrights set(ament_cmake_copyright_FOUND TRUE) ament_lint_auto_find_test_dependencies() + find_package(ament_cmake_gtest REQUIRED) + + add_subdirectory(test) endif() ament_export_include_directories(include) diff --git a/nav2_dwb_controller/dwb_critics/test/CMakeLists.txt b/nav2_dwb_controller/dwb_critics/test/CMakeLists.txt new file mode 100644 index 00000000..d654dab0 --- /dev/null +++ b/nav2_dwb_controller/dwb_critics/test/CMakeLists.txt @@ -0,0 +1,2 @@ +ament_add_gtest(prefer_forward_tests prefer_forward_test.cpp) +target_link_libraries(prefer_forward_tests dwb_critics) \ No newline at end of file diff --git a/nav2_dwb_controller/dwb_critics/test/prefer_forward_test.cpp b/nav2_dwb_controller/dwb_critics/test/prefer_forward_test.cpp new file mode 100644 index 00000000..460b5d04 --- /dev/null +++ b/nav2_dwb_controller/dwb_critics/test/prefer_forward_test.cpp @@ -0,0 +1,229 @@ +/* + * Software License Agreement (BSD License) + * + * Copyright (c) 2018, Wilco Bonestroo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <math.h> +#include <vector> + +#include <memory> +#include <string> +#include <limits> + +#include "gtest/gtest.h" +#include "rclcpp/rclcpp.hpp" +#include "dwb_critics/prefer_forward.hpp" +#include "nav2_costmap_2d/costmap_2d.hpp" +#include "nav2_util/lifecycle_node.hpp" +#include "nav2_util/node_utils.hpp" + +static constexpr double default_penalty = 1.0; +static constexpr double default_strafe_x = 0.1; +static constexpr double default_strafe_theta = 0.2; +static constexpr double default_theta_scale = 10.0; + +TEST(PreferForward, StartNode) +{ + auto critic = std::make_shared<dwb_critics::PreferForwardCritic>(); + auto costmap_ros = std::make_shared<nav2_costmap_2d::Costmap2DROS>("test_global_costmap"); + auto node = nav2_util::LifecycleNode::make_shared("costmap_tester"); + node->configure(); + node->activate(); + + std::string name = "test"; + std::string ns = "ns"; + critic->initialize(node, name, ns, costmap_ros); + + EXPECT_EQ(node->get_parameter(ns + "." + name + ".penalty").as_double(), default_penalty); + EXPECT_EQ(node->get_parameter(ns + "." + name + ".strafe_x").as_double(), default_strafe_x); + EXPECT_EQ( + node->get_parameter(ns + "." + name + ".strafe_theta").as_double(), default_strafe_theta); + EXPECT_EQ(node->get_parameter(ns + "." + name + ".theta_scale").as_double(), default_theta_scale); +} + +TEST(PreferForward, NegativeVelocityX) +{ + auto critic = std::make_shared<dwb_critics::PreferForwardCritic>(); + dwb_msgs::msg::Trajectory2D trajectory; + + // score must be equal to the penalty (1.0) for any negative x velocity + trajectory.velocity.x = -1.0; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.x = -0.00001; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.x = -0.1; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.x = std::numeric_limits<double>::lowest(); + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.x = -std::numeric_limits<double>::min(); + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); +} + +TEST(PreferForward, Strafe) +{ + auto critic = std::make_shared<dwb_critics::PreferForwardCritic>(); + dwb_msgs::msg::Trajectory2D trajectory; + + // score must be equal to the penalty (1.0) when x vel is lower than 0.1 + // and theta is between -0.2 and 0.2 + trajectory.velocity.x = 0.05; + trajectory.velocity.theta = -0.1; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.x = 0.0999999; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.x = 0.000001; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.theta = -0.19; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); + + trajectory.velocity.theta = 0.19; + EXPECT_EQ(critic->scoreTrajectory(trajectory), default_penalty); +} + +TEST(PreferForward, Normal) +{ + auto critic = std::make_shared<dwb_critics::PreferForwardCritic>(); + dwb_msgs::msg::Trajectory2D trajectory; + + // score must be equal to the theta * scaling factor (10.0) + trajectory.velocity.x = 0.2; + trajectory.velocity.theta = -0.1; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.1 * default_theta_scale); + + trajectory.velocity.theta = 0.1; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.1 * default_theta_scale); + + trajectory.velocity.theta = -0.2; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.2 * default_theta_scale); + + trajectory.velocity.theta = 0.2; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.2 * default_theta_scale); + + trajectory.velocity.theta = 1.5; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 1.5 * default_theta_scale); +} + +TEST(PreferForward, NoneDefaultValues) +{ + auto critic = std::make_shared<dwb_critics::PreferForwardCritic>(); + auto costmap_ros = std::make_shared<nav2_costmap_2d::Costmap2DROS>("test_global_costmap"); + auto node = nav2_util::LifecycleNode::make_shared("costmap_tester"); + node->configure(); + node->activate(); + + double penalty = 18.3; + double strafe_x = 0.5; + double strafe_theta = 0.4; + double theta_scale = 15.0; + + std::string name = "test"; + std::string ns = "ns"; + + nav2_util::declare_parameter_if_not_declared( + node, ns + "." + name + ".penalty", + rclcpp::ParameterValue(penalty)); + nav2_util::declare_parameter_if_not_declared( + node, ns + "." + name + ".strafe_x", + rclcpp::ParameterValue(strafe_x)); + nav2_util::declare_parameter_if_not_declared( + node, ns + "." + name + ".strafe_theta", + rclcpp::ParameterValue(strafe_theta)); + nav2_util::declare_parameter_if_not_declared( + node, ns + "." + name + ".theta_scale", + rclcpp::ParameterValue(theta_scale)); + + critic->initialize(node, name, ns, costmap_ros); + critic->onInit(); + + dwb_msgs::msg::Trajectory2D trajectory; + trajectory.velocity.x = 0.05; + trajectory.velocity.theta = -0.1; + + EXPECT_EQ(critic->scoreTrajectory(trajectory), penalty); + + // score must be equal to the penalty when x vel is lower than strafe_x + // and theta is between -strafe_theta and strafe_theta + trajectory.velocity.x = 0.4; + trajectory.velocity.theta = -0.39; + EXPECT_EQ(critic->scoreTrajectory(trajectory), penalty); + + trajectory.velocity.x = 0.0999999; + EXPECT_EQ(critic->scoreTrajectory(trajectory), penalty); + + trajectory.velocity.x = 0.000001; + EXPECT_EQ(critic->scoreTrajectory(trajectory), penalty); + + trajectory.velocity.theta = -0.09999; + EXPECT_EQ(critic->scoreTrajectory(trajectory), penalty); + + trajectory.velocity.theta = 0.09999; + EXPECT_EQ(critic->scoreTrajectory(trajectory), penalty); + + // score must be equal to the theta * scaling factor (10.0) + trajectory.velocity.x = 0.5; + trajectory.velocity.theta = -0.1; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.1 * theta_scale); + + trajectory.velocity.theta = 0.1; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.1 * theta_scale); + + trajectory.velocity.theta = -0.2; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.2 * theta_scale); + + trajectory.velocity.theta = 0.2; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 0.2 * theta_scale); + + trajectory.velocity.theta = 1.5; + EXPECT_EQ(critic->scoreTrajectory(trajectory), 1.5 * theta_scale); +} + +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; +} -- GitLab