m12watanabe1a 2022-05-27
add test
@f19089baa490c0f2b780304ea7a5c2576fc135d4
p9n_interface/include/p9n_interface/hw_types.hpp
--- p9n_interface/include/p9n_interface/hw_types.hpp
+++ p9n_interface/include/p9n_interface/hw_types.hpp
@@ -15,6 +15,7 @@
 #pragma once
 
 #include <string>
+#include <sstream>
 
 namespace p9n_interface
 {
@@ -25,17 +26,10 @@
   DUALSENSE,
 };
 
-std::string getHWName(const HW_TYPE & hw_type)
+namespace HW_NAME
 {
-  switch (hw_type) {
-    case HW_TYPE::DUALSHOCK3:
-      return "DualShock3";
-    case HW_TYPE::DUALSHOCK4:
-      return "DualShock4";
-    case HW_TYPE::DUALSENSE:
-      return "DualSense";
-    default:
-      return "Unknown";
-  }
-}
+const char DUALSHOCK3[] = "DualShock3";
+const char DUALSHOCK4[] = "DualShock4";
+const char DUALSENSE[] = "Dualsense";
+}  // namespace HW_NAME
 }  // namespace p9n_interface
p9n_interface/include/p9n_interface/p9n_interface.hpp
--- p9n_interface/include/p9n_interface/p9n_interface.hpp
+++ p9n_interface/include/p9n_interface/p9n_interface.hpp
@@ -40,6 +40,11 @@
   size_t select;
   size_t start;
   size_t PS;
+
+  size_t dpad_up;
+  size_t dpad_down;
+  size_t dpad_right;
+  size_t dpad_left;
 } JoyButtonIdx;
 
 typedef struct
@@ -56,11 +61,15 @@
   size_t L2_analog;
 } JoyAxesIdx;
 
+std::string getAllHwName();
+std::string getHwName(const HW_TYPE &);
+HW_TYPE getHwType(const std::string & hw_name);
+
 class PlayStationInterface
 {
 private:
   HW_TYPE HW_TYPE_;
-  sensor_msgs::msg::Joy::UniquePtr joy_;
+  sensor_msgs::msg::Joy::ConstSharedPtr joy_;
   const rclcpp::Logger LOGGER_;
   std::unique_ptr<JoyButtonIdx> btn_idx_;
   std::unique_ptr<JoyAxesIdx> axes_idx_;
@@ -70,7 +79,9 @@
 
 public:
   explicit PlayStationInterface(const HW_TYPE);
-  void setJoyMsg(sensor_msgs::msg::Joy::UniquePtr);
+  void setJoyMsg(sensor_msgs::msg::Joy::ConstSharedPtr);
+
+  bool pressedAny();
 
   bool pressedSquare();
   bool pressedCircle();
@@ -86,6 +97,11 @@
   bool pressedStart();
   bool pressedPS();
 
+  bool pressedDPadUp();
+  bool pressedDPadDown();
+  bool pressedDPadLeft();
+  bool pressedDPadRight();
+
   float pressedDPadX();
   float pressedDPadY();
 
p9n_interface/src/p9n_interface.cpp
--- p9n_interface/src/p9n_interface.cpp
+++ p9n_interface/src/p9n_interface.cpp
@@ -16,6 +16,43 @@
 
 namespace p9n_interface
 {
+
+std::string getAllHwName()
+{
+  std::stringstream ss;
+  ss << HW_NAME::DUALSHOCK3 << ", ";
+  ss << HW_NAME::DUALSHOCK4 << ", ";
+  ss << HW_NAME::DUALSENSE;
+  return ss.str();
+}
+
+std::string getHwName(const HW_TYPE & hw_type)
+{
+  switch (hw_type) {
+    case HW_TYPE::DUALSHOCK3:
+      return HW_NAME::DUALSHOCK3;
+    case HW_TYPE::DUALSHOCK4:
+      return HW_NAME::DUALSHOCK4;
+    case HW_TYPE::DUALSENSE:
+      return HW_NAME::DUALSENSE;
+    default:
+      throw std::runtime_error("Invalid hardware type.");
+  }
+}
+
+HW_TYPE getHwType(const std::string & hw_name)
+{
+  if (hw_name == HW_NAME::DUALSHOCK3) {
+    return HW_TYPE::DUALSHOCK3;
+  } else if (hw_name == HW_NAME::DUALSHOCK4) {
+    return HW_TYPE::DUALSHOCK4;
+  } else if (hw_name == HW_NAME::DUALSENSE) {
+    return HW_TYPE::DUALSENSE;
+  }
+  throw std::runtime_error("Invalid hardware name: " + hw_name);
+}
+
+
 PlayStationInterface::PlayStationInterface(
   const HW_TYPE type
 )
@@ -24,8 +61,8 @@
 {
   RCLCPP_INFO(
     this->LOGGER_,
-    "Hardware Type: %s",
-    getHWName(type).c_str());
+    "Hardware: %s",
+    getHwName(this->HW_TYPE_).c_str());
 
   this->btn_idx_ = std::make_unique<JoyButtonIdx>();
   this->axes_idx_ = std::make_unique<JoyAxesIdx>();
@@ -101,9 +138,29 @@
   return false;
 }
 
-void PlayStationInterface::setJoyMsg(sensor_msgs::msg::Joy::UniquePtr msg)
+void PlayStationInterface::setJoyMsg(sensor_msgs::msg::Joy::ConstSharedPtr msg)
 {
-  this->joy_ = std::move(msg);
+  this->joy_ = msg;
+}
+
+bool PlayStationInterface::pressedAny()
+{
+  if (!this->isAvailable()) {
+    return false;
+  }
+
+  bool pressed = false;
+  for (auto btn : this->joy_->buttons) {
+    pressed |= btn;
+  }
+  for (size_t i = 0; i < this->joy_->axes.size(); ++i) {
+    if (i == this->axes_idx_->L2_analog || i == this->axes_idx_->R2_analog) {
+      pressed |= this->joy_->axes.at(i) < 0.0;
+      continue;
+    }
+    pressed |= std::abs(this->joy_->axes.at(i)) > 1e-1;
+  }
+  return pressed;
 }
 
 bool PlayStationInterface::pressedSquare()
@@ -205,13 +262,47 @@
     this->btn_idx_->PS);
 }
 
+bool PlayStationInterface::pressedDPadUp()
+{
+  return this->pressedDPadY() == 1.0;
+}
+
+bool PlayStationInterface::pressedDPadDown()
+{
+  return this->pressedDPadY() == -1.0;
+}
+
+bool PlayStationInterface::pressedDPadRight()
+{
+  return this->pressedDPadX() == -1.0;
+}
+
+bool PlayStationInterface::pressedDPadLeft()
+{
+  return this->pressedDPadX() == 1.0;
+}
+
 float PlayStationInterface::pressedDPadX()
 {
   if (!this->isAvailable()) {
     return false;
   }
-  return this->joy_->axes.at(
-    this->axes_idx_->d_pad_x);
+  switch (this->HW_TYPE_) {
+    case HW_TYPE::DUALSHOCK3:
+      if (this->joy_->buttons.at(this->btn_idx_->dpad_up)) {
+        return 1.0;
+      } else if (this->joy_->buttons.at(this->btn_idx_->dpad_down)) {
+        return -1.0;
+      } else {
+        return 0.0;
+      }
+    case HW_TYPE::DUALSHOCK4:
+    case HW_TYPE::DUALSENSE:
+      return this->joy_->axes.at(
+        this->axes_idx_->d_pad_x);
+    default:
+      throw std::runtime_error("Invalid hardware type");
+  }
 }
 
 float PlayStationInterface::pressedDPadY()
@@ -219,8 +310,22 @@
   if (!this->isAvailable()) {
     return false;
   }
-  return this->joy_->axes.at(
-    this->axes_idx_->d_pad_y);
+  switch (this->HW_TYPE_) {
+    case HW_TYPE::DUALSHOCK3:
+      if (this->joy_->buttons.at(this->btn_idx_->dpad_right)) {
+        return -1.0;
+      } else if (this->joy_->buttons.at(this->btn_idx_->dpad_left)) {
+        return 1.0;
+      } else {
+        return 0.0;
+      }
+    case HW_TYPE::DUALSHOCK4:
+    case HW_TYPE::DUALSENSE:
+      return this->joy_->axes.at(
+        this->axes_idx_->d_pad_y);
+    default:
+      throw std::runtime_error("Invalid hardware type");
+  }
 }
 
 float PlayStationInterface::tiltedStickLX()
 
p9n_test/.vscode/c_cpp_properties.json (added)
+++ p9n_test/.vscode/c_cpp_properties.json
@@ -0,0 +1,22 @@
+{
+  "configurations": [
+    {
+      "browse": {
+        "databaseFilename": "${workspaceFolder}/.vscode/browse.vc.db",
+        "limitSymbolsToIncludedHeaders": false
+      },
+      "includePath": [
+        "/opt/ros/galactic/include/**",
+        "/usr/include/**",
+        "${workspaceFolder}/include/**",
+        "${workspaceFolder}/../p9n_interface/include/**"
+      ],
+      "name": "ROS",
+      "intelliSenseMode": "clang-x64",
+      "compilerPath": "/usr/bin/gcc",
+      "cStandard": "c99",
+      "cppStandard": "c++17"
+    }
+  ],
+  "version": 4
+}(파일 끝에 줄바꿈 문자 없음)
 
p9n_test/.vscode/cspell.json (added)
+++ p9n_test/.vscode/cspell.json
@@ -0,0 +1,1 @@
+../../.vscode/cspell.json(파일 끝에 줄바꿈 문자 없음)
 
p9n_test/.vscode/settings.json (added)
+++ p9n_test/.vscode/settings.json
@@ -0,0 +1,1 @@
+../../.vscode/settings.json(파일 끝에 줄바꿈 문자 없음)
 
p9n_test/.vscode/uncrustify.cfg (added)
+++ p9n_test/.vscode/uncrustify.cfg
@@ -0,0 +1,1 @@
+../../.vscode/uncrustify.cfg(파일 끝에 줄바꿈 문자 없음)
 
p9n_test/CMakeLists.txt (added)
+++ p9n_test/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.8)
+project(p9n_test)
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  add_compile_options(-Wall -Wextra -Wpedantic)
+endif()
+
+find_package(ament_cmake_auto REQUIRED)
+ament_auto_find_build_dependencies()
+
+
+# Playstation Test ==================================================
+set(TARGET p9n_test_node)
+ament_auto_add_library(
+  ${TARGET}
+    SHARED
+      src/${TARGET}.cpp
+      src/workflow_handler.cpp)
+rclcpp_components_register_node(
+  ${TARGET}
+    PLUGIN "p9n_test::PlayStationTest"
+    EXECUTABLE ${TARGET}_exec)
+# End Playstation Test ==============================================
+
+if(BUILD_TESTING)
+  find_package(ament_lint_auto REQUIRED)
+  set(ament_cmake_copyright_FOUND TRUE)
+  set(ament_cmake_cpplint_FOUND TRUE)
+  ament_lint_auto_find_test_dependencies()
+endif()
+
+ament_auto_package(INSTALL_TO_SHARE launch)
 
p9n_test/include/p9n_test/p9n_test_node.hpp (added)
+++ p9n_test/include/p9n_test/p9n_test_node.hpp
@@ -0,0 +1,47 @@
+// Copyright 2022 HarvestX Inc.
+//
+// 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.
+
+#pragma once
+
+#include <string>
+#include <memory>
+#include <sensor_msgs/msg/joy.hpp>
+#include <rclcpp/rclcpp.hpp>
+
+#include "p9n_test/workflow_handler.hpp"
+#include <p9n_interface/p9n_interface.hpp>
+
+namespace p9n_test
+{
+class PlayStationTest : public rclcpp::Node
+{
+private:
+  p9n_interface::HW_TYPE hw_type_;
+  int max_trial_;
+
+  std::unique_ptr<WorkflowHandler> wf_handler_;
+  std::unique_ptr<
+    p9n_interface::PlayStationInterface> p9n_interface_;
+
+  rclcpp::Subscription<sensor_msgs::msg::Joy>::SharedPtr joy_sub_;
+
+public:
+  explicit PlayStationTest(const rclcpp::NodeOptions &);
+  void onJoy(sensor_msgs::msg::Joy::ConstSharedPtr);
+
+};
+}  // namespace p9n_test
+
+#include "rclcpp_components/register_node_macro.hpp"
+RCLCPP_COMPONENTS_REGISTER_NODE(p9n_test::PlayStationTest)
 
p9n_test/include/p9n_test/workflow_handler.hpp (added)
+++ p9n_test/include/p9n_test/workflow_handler.hpp
@@ -0,0 +1,78 @@
+// Copyright 2022 HarvestX Inc.
+//
+// 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.
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <memory>
+
+#include <p9n_interface/p9n_interface.hpp>
+
+namespace p9n_test
+{
+
+enum class Task
+{
+  CROSS = 0,
+  CIRCLE,
+  TRIANGLE,
+  SQUARE,
+
+  L1,
+  R1,
+  L2,
+  R2,
+
+  SELECT,
+  START,
+  PS,
+
+  DPAD_UP,
+  DPAD_DOWN,
+  DPAD_RIGHT,
+  DPAD_LEFT,
+
+  STICK_L_LEFT,
+  STICK_L_UP,
+  STICK_R_LEFT,
+  STICK_R_UP,
+
+  END
+};
+
+class WorkflowHandler
+{
+private:
+  int trial_ = 0;
+  int current_task_idx_ = 0;
+  bool done_ = false;
+  rclcpp::Logger LOGGER_ = rclcpp::get_logger("WorkflowHandler");
+
+  std::vector<int> failed_idx_list_;
+
+public:
+  void goNextTask();
+  bool execCurrentTask(
+    std::reference_wrapper<
+      std::unique_ptr<p9n_interface::PlayStationInterface>>);
+  std::string getCurrentTaskStr();
+  std::string getTaskStr(const int);
+  bool isDone();
+  bool isTrialGreaterThan(const int);
+  void explainNextTask(bool = false);
+  void markCurrentTaskAsFailed();
+  void showResult();
+};
+}  // namespace p9n_test
 
p9n_test/launch/test.launch.py (added)
+++ p9n_test/launch/test.launch.py
@@ -0,0 +1,41 @@
+# Copyright 2022 HarvestX Inc.
+#
+# 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.
+
+from launch import LaunchDescription
+from launch_ros.actions import ComposableNodeContainer
+from launch_ros.descriptions import ComposableNode
+
+
+def generate_launch_description():
+    """Generate launch description."""
+    nodes = [
+        ComposableNodeContainer(
+            name='joy_container',
+            namespace='p9n',
+            package='rclcpp_components',
+            executable='component_container',
+            composable_node_descriptions=[
+                ComposableNode(
+                    package='joy',
+                    plugin='joy::Joy',
+                    name='joy',
+                ),
+                ComposableNode(
+                    package='p9n_test',
+                    plugin='p9n_test::PlayStationTest',
+                    name='p9n_test'
+                ),
+            ])]
+
+    return LaunchDescription(nodes)
 
p9n_test/package.xml (added)
+++ p9n_test/package.xml
@@ -0,0 +1,24 @@
+<?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>p9n_test</name>
+  <version>0.0.0</version>
+  <description>PlayStation JoyController Test</description>
+  <maintainer email="m12watanabe1a@gmail.com">m12watanabe1a</maintainer>
+  <license>Apache License 2.0</license>
+
+  <buildtool_depend>ament_cmake_auto</buildtool_depend>
+
+  <depend>rclcpp</depend>
+  <depend>rclcpp_components</depend>
+  <depend>p9n_interface</depend>
+  <depend>sensor_msgs</depend>
+  <exec_depend>joy</exec_depend>
+
+  <test_depend>ament_lint_auto</test_depend>
+  <test_depend>ament_lint_common</test_depend>
+
+  <export>
+    <build_type>ament_cmake</build_type>
+  </export>
+</package>(파일 끝에 줄바꿈 문자 없음)
 
p9n_test/src/p9n_test_node.cpp (added)
+++ p9n_test/src/p9n_test_node.cpp
@@ -0,0 +1,117 @@
+// Copyright 2022 HarvestX Inc.
+//
+// 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 "p9n_test/p9n_test_node.hpp"
+
+namespace p9n_test
+{
+PlayStationTest::PlayStationTest(const rclcpp::NodeOptions & options)
+: rclcpp::Node("p9n_test_node", options)
+{
+  const std::string hw_name = this->declare_parameter<std::string>(
+    "controller_type", p9n_interface::HW_NAME::DUALSENSE);
+
+  try {
+    this->hw_type_ = p9n_interface::getHwType(hw_name);
+  } catch (std::runtime_error & e) {
+    RCLCPP_ERROR(
+      this->get_logger(),
+      e.what());
+
+    RCLCPP_ERROR(
+      this->get_logger(),
+      "Please select hardware from %s",
+      p9n_interface::getAllHwName().c_str());
+    rclcpp::shutdown();
+    return;
+  }
+
+  this->max_trial_ = this->declare_parameter<int>("trial", 3);
+  if (this->max_trial_ < 1) {
+    RCLCPP_ERROR(
+      this->get_logger(),
+      "Trial should be grater than 1");
+    rclcpp::shutdown();
+    return;
+  }
+
+  this->joy_sub_ = this->create_subscription<sensor_msgs::msg::Joy>(
+    "joy", rclcpp::SensorDataQoS(rclcpp::KeepLast(1)),
+    std::bind(&PlayStationTest::onJoy, this, std::placeholders::_1));
+
+  this->wf_handler_ = std::make_unique<WorkflowHandler>();
+  this->p9n_interface_ =
+    std::make_unique<p9n_interface::PlayStationInterface>(this->hw_type_);
+
+
+  if (this->joy_sub_->get_publisher_count() == 0) {
+    RCLCPP_ERROR(
+      this->get_logger(),
+      "Joy node not launched");
+    rclcpp::shutdown();
+    return;
+  }
+}
+
+void PlayStationTest::onJoy(sensor_msgs::msg::Joy::ConstSharedPtr joy_msg)
+{
+  this->p9n_interface_->setJoyMsg(joy_msg);
+  this->wf_handler_->explainNextTask(true);
+  if (!this->p9n_interface_->pressedAny()) {
+    return;
+  }
+
+  bool status = this->wf_handler_->execCurrentTask(this->p9n_interface_);
+
+  if (status) {
+    RCLCPP_INFO(this->get_logger(), "OK");
+    this->wf_handler_->goNextTask();
+  } else {
+    // When Task failed ..
+    if (!this->wf_handler_->isTrialGreaterThan(this->max_trial_)) {
+      // You still have chance to try...
+      RCLCPP_ERROR(
+        this->get_logger(),
+        "Invalid input given. Try again...");
+    } else {
+      // Game over ...
+      // Skip current trial.
+      RCLCPP_ERROR(
+        this->get_logger(),
+        "Failed %d times...",
+        this->max_trial_);
+      RCLCPP_ERROR(
+        this->get_logger(),
+        "Go next");
+      this->wf_handler_->markCurrentTaskAsFailed();
+      this->wf_handler_->goNextTask();
+      return;
+    }
+  }
+
+
+  if (this->wf_handler_->isDone()) {
+    RCLCPP_INFO(this->get_logger(), "Done!");
+    this->wf_handler_->showResult();
+    rclcpp::shutdown();
+    return;
+  }
+
+  // Delay for button chattering
+  using namespace std::chrono_literals;
+  rclcpp::sleep_for(500ms);
+}
+
+
+}  // namespace p9n_test
 
p9n_test/src/workflow_handler.cpp (added)
+++ p9n_test/src/workflow_handler.cpp
@@ -0,0 +1,214 @@
+// Copyright 2022 HarvestX Inc.
+//
+// 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 "p9n_test/workflow_handler.hpp"
+
+
+namespace p9n_test
+{
+void WorkflowHandler::goNextTask()
+{
+  this->trial_ = 0;
+  this->current_task_idx_ += 1;
+  if (this->current_task_idx_ ==
+    static_cast<size_t>(Task::END))
+  {
+    this->done_ = true;
+  } else {
+    this->explainNextTask();
+  }
+}
+
+bool WorkflowHandler::execCurrentTask(
+  std::reference_wrapper<std::unique_ptr<p9n_interface::PlayStationInterface>>
+  ref_if)
+{
+  this->trial_ += 1;
+  bool trial_result = false;
+
+  switch (this->current_task_idx_) {
+    case static_cast<int>(Task::CROSS):
+      trial_result = ref_if.get()->pressedCross();
+      break;
+    case static_cast<int>(Task::CIRCLE):
+      trial_result = ref_if.get()->pressedCircle();
+      break;
+    case static_cast<int>(Task::TRIANGLE):
+      trial_result = ref_if.get()->pressedTriangle();
+      break;
+    case static_cast<int>(Task::SQUARE):
+      trial_result = ref_if.get()->pressedSquare();
+      break;
+    case static_cast<int>(Task::L1):
+      trial_result = ref_if.get()->pressedL1();
+      break;
+    case static_cast<int>(Task::R1):
+      trial_result = ref_if.get()->pressedR1();
+      break;
+    case static_cast<int>(Task::L2):
+      trial_result = ref_if.get()->pressedL2();
+      break;
+    case static_cast<int>(Task::R2):
+      trial_result = ref_if.get()->pressedR2();
+      break;
+    case static_cast<int>(Task::SELECT):
+      trial_result = ref_if.get()->pressedSelect();
+      break;
+    case static_cast<int>(Task::START):
+      trial_result = ref_if.get()->pressedStart();
+      break;
+    case static_cast<int>(Task::PS):
+      trial_result = ref_if.get()->pressedPS();
+      break;
+    case static_cast<int>(Task::DPAD_UP):
+      trial_result = ref_if.get()->pressedDPadUp();
+      break;
+    case static_cast<int>(Task::DPAD_DOWN):
+      trial_result = ref_if.get()->pressedDPadDown();
+      break;
+    case static_cast<int>(Task::DPAD_RIGHT):
+      trial_result = ref_if.get()->pressedDPadRight();
+      break;
+    case static_cast<int>(Task::DPAD_LEFT):
+      trial_result = ref_if.get()->pressedDPadLeft();
+      break;
+    case static_cast<int>(Task::STICK_L_LEFT):
+      trial_result =
+        ref_if.get()->tiltedStickLX() > 1e-1;
+      break;
+    case static_cast<int>(Task::STICK_L_UP):
+      trial_result =
+        ref_if.get()->tiltedStickLY() > 1e-1;
+      break;
+    case static_cast<int>(Task::STICK_R_LEFT):
+      trial_result =
+        ref_if.get()->tiltedStickRX() > 1e-1;
+      break;
+    case static_cast<int>(Task::STICK_R_UP):
+      trial_result =
+        ref_if.get()->tiltedStickRY() > 1e-1;
+      break;
+    case static_cast<int>(Task::END):
+    default:
+      RCLCPP_ERROR(
+        this->LOGGER_,
+        "Now workflow remains");
+      return true;
+  }
+
+  return trial_result;
+}
+
+std::string WorkflowHandler::getCurrentTaskStr()
+{
+  return this->getTaskStr(this->current_task_idx_);
+}
+
+std::string WorkflowHandler::getTaskStr(const int task_idx)
+{
+  switch (task_idx) {
+    case static_cast<int>(Task::CROSS):
+      return "☓";
+    case static_cast<int>(Task::CIRCLE):
+      return "○";
+    case static_cast<int>(Task::TRIANGLE):
+      return "△";
+    case static_cast<int>(Task::SQUARE):
+      return "□";
+    case static_cast<int>(Task::L1):
+      return "L1";
+    case static_cast<int>(Task::R1):
+      return "R1";
+    case static_cast<int>(Task::L2):
+      return "L2";
+    case static_cast<int>(Task::R2):
+      return "R2";
+    case static_cast<int>(Task::SELECT):
+      return "Select";
+    case static_cast<int>(Task::START):
+      return "Start";
+    case static_cast<int>(Task::PS):
+      return "PS";
+    case static_cast<int>(Task::DPAD_UP):
+      return "Button ↑";
+    case static_cast<int>(Task::DPAD_DOWN):
+      return "Button ↓";
+    case static_cast<int>(Task::DPAD_RIGHT):
+      return "Button →";
+    case static_cast<int>(Task::DPAD_LEFT):
+      return "Button ←";
+    case static_cast<int>(Task::STICK_L_LEFT):
+      return "Stick L ←";
+    case static_cast<int>(Task::STICK_L_UP):
+      return "Stick L ↑";
+    case static_cast<int>(Task::STICK_R_LEFT):
+      return "Stick R ←";
+    case static_cast<int>(Task::STICK_R_UP):
+      return "Stick R ↑";
+    case static_cast<int>(Task::END):
+    default:
+      return "All Task Done";
+  }
+}
+
+bool WorkflowHandler::isDone()
+{
+  return this->done_;
+}
+
+bool WorkflowHandler::isTrialGreaterThan(const int max)
+{
+  return this->trial_ >= max;
+}
+
+void WorkflowHandler::explainNextTask(bool once)
+{
+  const std::string text =
+    "Press [ " + this->getCurrentTaskStr() +
+    " ] button : ";
+  if (once) {
+    RCLCPP_WARN_ONCE(
+      this->LOGGER_,
+      text.c_str());
+  } else {
+    RCLCPP_WARN(
+      this->LOGGER_,
+      text.c_str());
+  }
+}
+
+void WorkflowHandler::markCurrentTaskAsFailed()
+{
+  this->failed_idx_list_.emplace_back(this->current_task_idx_);
+}
+
+void WorkflowHandler::showResult()
+{
+  if (this->failed_idx_list_.empty()) {
+    RCLCPP_INFO(
+      this->LOGGER_,
+      "Passed all task! ��");
+  } else {
+    std::stringstream ss;
+    ss << "Failed target: ";
+    for (auto failed_idx : this->failed_idx_list_) {
+      ss << "[ " <<
+        this->getTaskStr(failed_idx) << " ] ";
+    }
+    RCLCPP_ERROR(
+      this->LOGGER_,
+      ss.str().c_str());
+  }
+}
+}  // namespace p9n_test
Add a comment
List