From 4189b20b8f908c76764d358e854b513b969e4966 Mon Sep 17 00:00:00 2001
From: rafal-gorecki <126687345+rafal-gorecki@users.noreply.github.com>
Date: Fri, 8 Nov 2024 10:20:06 +0100
Subject: [PATCH 1/3] Ros2 docking manager no lights (#430)
* Manage lights
* Simple working version
* Clean up
* Clean up and add types enums
* Simplifications
* Change ports
* Add use_docking arg
* Fix port
* Fix port
* Add more cases to tests
* update
* Fix ports
* Add dock_pose field, improve description, add dependencies
* Docking manager without lights
* Auto review
* Update CONFIGURATION.md
* Typo
* Coderabbit suggestions
* Jakub suggestions
* Fix tests
* Jakub suggestions
---
README.md | 2 +
.../src/system_monitor_node.cpp | 1 -
panther_docking/launch/docking.launch.py | 64 +++---
.../launch/simulate_robot.launch.py | 14 ++
panther_gazebo/package.xml | 1 +
panther_manager/CMakeLists.txt | 105 ++++------
panther_manager/CONFIGURATION.md | 9 +
.../behavior_trees/DockingBT.btproj | 28 +++
panther_manager/behavior_trees/docking.xml | 62 ++++++
panther_manager/config/docking_manager.yaml | 12 ++
panther_manager/config/lights_manager.yaml | 1 +
.../panther_manager/behavior_tree_utils.hpp | 78 ++++++--
.../panther_manager/docking_manager_node.hpp | 67 +++++++
.../action/call_set_bool_service_node.hpp | 3 +-
.../call_set_led_animation_service_node.hpp | 10 +-
.../plugins/action/dock_robot_node.hpp | 39 ++--
.../action/shutdown_hosts_from_file_node.hpp | 6 +-
.../action/shutdown_single_host_node.hpp | 17 +-
.../plugins/action/signal_shutdown_node.hpp | 2 +-
.../plugins/action/undock_robot_node.hpp | 17 +-
...buttons_pressed.hpp => check_bool_msg.hpp} | 24 +--
.../plugins/condition/check_joy_msg.hpp | 68 +++++++
.../decorator/tick_after_timeout_node.hpp | 3 +-
panther_manager/launch/manager.launch.py | 23 +++
panther_manager/package.xml | 3 +
panther_manager/src/docking_manager_node.cpp | 122 ++++++++++++
.../src/docking_manager_node_main.cpp | 38 ++++
panther_manager/src/lights_manager_node.cpp | 28 +--
.../src/plugins/action/dock_robot_node.cpp | 3 -
.../src/plugins/action/undock_robot_node.cpp | 1 -
.../plugins/condition/are_buttons_pressed.cpp | 48 -----
.../src/plugins/condition/check_bool_msg.cpp | 34 ++++
.../src/plugins/condition/check_joy_msg.cpp | 92 +++++++++
panther_manager/src/safety_manager_node.cpp | 22 +--
.../condition/test_are_buttons_pressed.cpp | 119 -----------
.../plugins/condition/test_check_bool_msg.cpp | 102 ++++++++++
.../plugins/condition/test_check_joy_msg.cpp | 186 ++++++++++++++++++
.../test/test_behavior_tree_utils.cpp | 60 ++++--
38 files changed, 1136 insertions(+), 378 deletions(-)
create mode 100644 panther_manager/behavior_trees/DockingBT.btproj
create mode 100644 panther_manager/behavior_trees/docking.xml
create mode 100644 panther_manager/config/docking_manager.yaml
create mode 100644 panther_manager/include/panther_manager/docking_manager_node.hpp
rename panther_manager/include/panther_manager/plugins/condition/{are_buttons_pressed.hpp => check_bool_msg.hpp} (61%)
create mode 100644 panther_manager/include/panther_manager/plugins/condition/check_joy_msg.hpp
create mode 100644 panther_manager/src/docking_manager_node.cpp
create mode 100644 panther_manager/src/docking_manager_node_main.cpp
delete mode 100644 panther_manager/src/plugins/condition/are_buttons_pressed.cpp
create mode 100644 panther_manager/src/plugins/condition/check_bool_msg.cpp
create mode 100644 panther_manager/src/plugins/condition/check_joy_msg.cpp
delete mode 100644 panther_manager/test/plugins/condition/test_are_buttons_pressed.cpp
create mode 100644 panther_manager/test/plugins/condition/test_check_bool_msg.cpp
create mode 100644 panther_manager/test/plugins/condition/test_check_joy_msg.cpp
diff --git a/README.md b/README.md
index 633e44f3..3e7a1f2e 100644
--- a/README.md
+++ b/README.md
@@ -88,6 +88,7 @@ Launch arguments are largely common to both simulation and physical robot. Howev
| 🤖🖥️ | `components_config_path` | Additional components configuration file. Components described in this file are dynamically included in Panther's urdf. Panther options are described in [the manual](https://husarion.com/manuals/panther/panther-options).
***string:*** [`components.yaml`](./panther_description/config/components.yaml) |
| 🤖🖥️ | `controller_config_path` | Path to controller configuration file. A path to custom configuration can be specified here.
***string:*** [`{wheel_type}_controller.yaml`](./panther_controller/config/) |
| 🤖 | `disable_manager` | Enable or disable manager_bt_node.
***bool:*** `False` |
+| 🤖🖥️ | `docking_bt_project_path` | Path to BehaviorTree project file, responsible for docking management.
***string:*** [`DockingBT.btproj`](./panther_manager/behavior_trees/DockingBT.btproj) |
| 🤖🖥️ | `fuse_gps` | Include GPS for data fusion.
***bool:*** `False` |
| 🖥️ | `gz_bridge_config_path` | Path to the parameter_bridge configuration file.
***string:*** [`gz_bridge.yaml`](./panther_gazebo/config/gz_bridge.yaml) |
| 🖥️ | `gz_gui` | Run simulation with specific GUI layout.
***string:*** [`teleop.config`](https://github.com/husarion/husarion_gz_worlds/blob/main/config/teleop.config) |
@@ -104,6 +105,7 @@ Launch arguments are largely common to both simulation and physical robot. Howev
| 🖥️ | `robots` | The list of the robots spawned in the simulation e.g. `robots:='robot1={x: 1.0, y: -2.0}; robot2={x: 1.0, y: -4.0}'`
***string:*** `''` |
| 🤖🖥️ | `safety_bt_project_path` | Path to BehaviorTree project file, responsible for safety and shutdown management.
***string:*** [`PantherSafetyBT.btproj`](./panther_manager/behavior_trees/PantherSafetyBT.btproj) |
| 🤖🖥️ | `shutdown_hosts_config_path` | Path to file with list of hosts to request shutdown.
***string:*** [`shutdown_hosts_config.yaml`](./panther_manager/config/shutdown_hosts_config.yaml) |
+| 🤖🖥️ | `use_docking` | Enable docking server.
***bool:*** `True` |
| 🤖🖥️ | `use_ekf` | Enable or disable EKF.
***bool:*** `True` |
| 🤖🖥️ | `use_sim` | Whether simulation is used.
***bool:*** `False` |
| 🤖🖥️ | `user_led_animations_file` | Path to a YAML file with a description of the user-defined animations.
***string:*** `''` |
diff --git a/panther_diagnostics/src/system_monitor_node.cpp b/panther_diagnostics/src/system_monitor_node.cpp
index bc921a75..5da51464 100644
--- a/panther_diagnostics/src/system_monitor_node.cpp
+++ b/panther_diagnostics/src/system_monitor_node.cpp
@@ -28,7 +28,6 @@
#include "panther_utils/ros_utils.hpp"
#include "panther_diagnostics/filesystem.hpp"
-#include "panther_diagnostics/types.hpp"
namespace panther_diagnostics
{
diff --git a/panther_docking/launch/docking.launch.py b/panther_docking/launch/docking.launch.py
index d386bd31..84fa4b44 100644
--- a/panther_docking/launch/docking.launch.py
+++ b/panther_docking/launch/docking.launch.py
@@ -13,8 +13,8 @@
# limitations under the License.
from launch import LaunchDescription
-from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
-from launch.launch_description_sources import PythonLaunchDescriptionSource
+from launch.actions import DeclareLaunchArgument
+from launch.conditions import IfCondition
from launch.substitutions import (
EnvironmentVariable,
LaunchConfiguration,
@@ -26,12 +26,13 @@
def generate_launch_description():
- use_sim = LaunchConfiguration("use_sim")
- declare_use_sim_arg = DeclareLaunchArgument(
- "use_sim",
- default_value="False",
- description="Whether simulation is used",
- choices=[True, False, "True", "False", "true", "false", "1", "0"],
+ docking_server_config_path = LaunchConfiguration("docking_server_config_path")
+ declare_docking_server_config_path_arg = DeclareLaunchArgument(
+ "docking_server_config_path",
+ default_value=PathJoinSubstitution(
+ [FindPackageShare("panther_docking"), "config", "panther_docking_server.yaml"]
+ ),
+ description=("Path to docking server configuration file."),
)
namespace = LaunchConfiguration("namespace")
@@ -41,13 +42,20 @@ def generate_launch_description():
description="Add namespace to all launched nodes.",
)
- docking_server_config_path = LaunchConfiguration("docking_server_config_path")
- declare_docking_server_config_path_arg = DeclareLaunchArgument(
- "docking_server_config_path",
- default_value=PathJoinSubstitution(
- [FindPackageShare("panther_docking"), "config", "panther_docking_server.yaml"]
- ),
- description=("Path to docking server configuration file."),
+ use_docking = LaunchConfiguration("use_docking")
+ declare_use_docking_arg = DeclareLaunchArgument(
+ "use_docking",
+ default_value="True",
+ description="Enable docking server.",
+ choices=["True", "False", "true", "false"],
+ )
+
+ use_sim = LaunchConfiguration("use_sim")
+ declare_use_sim_arg = DeclareLaunchArgument(
+ "use_sim",
+ default_value="False",
+ description="Whether simulation is used.",
+ choices=["True", "False", "true", "false"],
)
namespaced_docking_server_config = ReplaceString(
@@ -58,18 +66,21 @@ def generate_launch_description():
docking_server_node = Node(
package="opennav_docking",
executable="opennav_docking",
+ namespace=namespace,
parameters=[
namespaced_docking_server_config,
{"use_sim_time": use_sim},
],
- namespace=namespace,
+ remappings=[("~/transition_event", "~/_transition_event")],
emulate_tty=True,
+ condition=IfCondition(use_docking),
)
docking_server_activate_node = Node(
package="nav2_lifecycle_manager",
executable="lifecycle_manager",
name="nav2_docking_lifecycle_manager",
+ namespace=namespace,
parameters=[
{
"autostart": True,
@@ -79,28 +90,15 @@ def generate_launch_description():
"use_sim_time": use_sim,
},
],
- namespace=namespace,
- )
-
- station_launch = IncludeLaunchDescription(
- PythonLaunchDescriptionSource(
- PathJoinSubstitution(
- [
- FindPackageShare("panther_docking"),
- "launch",
- "station.launch.py",
- ]
- ),
- ),
- launch_arguments={"namespace": namespace}.items(),
+ condition=IfCondition(use_docking),
)
return LaunchDescription(
[
- declare_use_sim_arg,
- declare_namespace_arg,
declare_docking_server_config_path_arg,
- station_launch,
+ declare_namespace_arg,
+ declare_use_docking_arg,
+ declare_use_sim_arg,
docking_server_node,
docking_server_activate_node,
]
diff --git a/panther_gazebo/launch/simulate_robot.launch.py b/panther_gazebo/launch/simulate_robot.launch.py
index ad7252e7..aa55478a 100644
--- a/panther_gazebo/launch/simulate_robot.launch.py
+++ b/panther_gazebo/launch/simulate_robot.launch.py
@@ -185,6 +185,19 @@ def generate_launch_description():
emulate_tty=True,
)
+ docking_launch = IncludeLaunchDescription(
+ PythonLaunchDescriptionSource(
+ PathJoinSubstitution(
+ [
+ FindPackageShare("panther_docking"),
+ "launch",
+ "docking.launch.py",
+ ]
+ ),
+ ),
+ launch_arguments={"namespace": namespace, "use_sim": "True"}.items(),
+ )
+
return LaunchDescription(
[
declare_battery_config_path_arg,
@@ -200,5 +213,6 @@ def generate_launch_description():
ekf_launch,
simulate_components,
gz_bridge,
+ docking_launch,
]
)
diff --git a/panther_gazebo/package.xml b/panther_gazebo/package.xml
index 89e7baaa..184e07c1 100644
--- a/panther_gazebo/package.xml
+++ b/panther_gazebo/package.xml
@@ -34,6 +34,7 @@
nav2_common
panther_controller
panther_description
+ panther_docking
panther_lights
panther_localization
panther_manager
diff --git a/panther_manager/CMakeLists.txt b/panther_manager/CMakeLists.txt
index 1f7bcfb9..1ba4ddde 100644
--- a/panther_manager/CMakeLists.txt
+++ b/panther_manager/CMakeLists.txt
@@ -11,14 +11,17 @@ set(PACKAGE_DEPENDENCIES
behaviortree_cpp
behaviortree_ros2
libssh
+ geometry_msgs
+ opennav_docking_msgs
panther_msgs
panther_utils
rclcpp
rclcpp_action
sensor_msgs
+ std_msgs
std_srvs
- yaml-cpp
- opennav_docking_msgs)
+ tf2_geometry_msgs
+ yaml-cpp)
foreach(PACKAGE IN ITEMS ${PACKAGE_DEPENDENCIES})
find_package(${PACKAGE} REQUIRED)
@@ -59,9 +62,13 @@ add_library(undock_robot_bt_node SHARED
src/plugins/action/undock_robot_node.cpp)
list(APPEND plugin_libs undock_robot_bt_node)
-add_library(are_buttons_pressed_bt_node SHARED
- src/plugins/condition/are_buttons_pressed.cpp)
-list(APPEND plugin_libs are_buttons_pressed_bt_node)
+add_library(check_bool_msg_bt_node SHARED
+ src/plugins/condition/check_bool_msg.cpp)
+list(APPEND plugin_libs check_bool_msg_bt_node)
+
+add_library(check_joy_msg_bt_node SHARED
+ src/plugins/condition/check_joy_msg.cpp)
+list(APPEND plugin_libs check_joy_msg_bt_node)
add_library(tick_after_timeout_bt_node SHARED
src/plugins/decorator/tick_after_timeout_node.cpp)
@@ -75,32 +82,25 @@ endforeach()
add_executable(
safety_manager_node src/safety_manager_node_main.cpp
src/safety_manager_node.cpp src/behavior_tree_manager.cpp)
-ament_target_dependencies(
- safety_manager_node
- behaviortree_ros2
- panther_msgs
- panther_utils
- rclcpp
- sensor_msgs
- std_msgs)
+ament_target_dependencies(safety_manager_node ${PACKAGE_DEPENDENCIES})
target_link_libraries(safety_manager_node ${plugin_libs})
add_executable(
lights_manager_node src/lights_manager_node_main.cpp
src/lights_manager_node.cpp src/behavior_tree_manager.cpp)
-ament_target_dependencies(
- lights_manager_node
- behaviortree_ros2
- panther_msgs
- panther_utils
- rclcpp
- sensor_msgs
- std_msgs)
+ament_target_dependencies(lights_manager_node ${PACKAGE_DEPENDENCIES})
target_link_libraries(lights_manager_node ${plugin_libs})
+add_executable(
+ docking_manager_node
+ src/docking_manager_node_main.cpp src/docking_manager_node.cpp
+ src/behavior_tree_manager.cpp)
+ament_target_dependencies(docking_manager_node ${PACKAGE_DEPENDENCIES})
+target_link_libraries(docking_manager_node ${plugin_libs})
+
install(TARGETS ${plugin_libs} DESTINATION lib)
-install(TARGETS safety_manager_node lights_manager_node
+install(TARGETS safety_manager_node lights_manager_node docking_manager_node
DESTINATION lib/${PROJECT_NAME})
install(DIRECTORY behavior_trees config launch
@@ -161,10 +161,16 @@ if(BUILD_TESTING)
list(APPEND plugin_tests ${PROJECT_NAME}_test_undock_robot_node)
ament_add_gtest(
- ${PROJECT_NAME}_test_are_buttons_pressed
- test/plugins/condition/test_are_buttons_pressed.cpp
- src/plugins/condition/are_buttons_pressed.cpp)
- list(APPEND plugin_tests ${PROJECT_NAME}_test_are_buttons_pressed)
+ ${PROJECT_NAME}_test_check_bool_msg
+ test/plugins/condition/test_check_bool_msg.cpp
+ src/plugins/condition/check_bool_msg.cpp)
+ list(APPEND plugin_tests ${PROJECT_NAME}_test_check_bool_msg)
+
+ ament_add_gtest(
+ ${PROJECT_NAME}_test_check_joy_msg
+ test/plugins/condition/test_check_joy_msg.cpp
+ src/plugins/condition/check_joy_msg.cpp)
+ list(APPEND plugin_tests ${PROJECT_NAME}_test_check_joy_msg)
ament_add_gtest(
${PROJECT_NAME}_test_tick_after_timeout_node
@@ -198,7 +204,7 @@ if(BUILD_TESTING)
PUBLIC $
$)
ament_target_dependencies(${PROJECT_NAME}_test_behavior_tree_utils
- behaviortree_cpp behaviortree_ros2 panther_utils)
+ ${PACKAGE_DEPENDENCIES})
ament_add_gtest(
${PROJECT_NAME}_test_behavior_tree_manager
@@ -217,15 +223,8 @@ if(BUILD_TESTING)
${PROJECT_NAME}_test_lights_manager_node
PUBLIC $
$)
- ament_target_dependencies(
- ${PROJECT_NAME}_test_lights_manager_node
- behaviortree_cpp
- behaviortree_ros2
- panther_msgs
- panther_utils
- rclcpp
- sensor_msgs
- std_msgs)
+ ament_target_dependencies(${PROJECT_NAME}_test_lights_manager_node
+ ${PACKAGE_DEPENDENCIES})
ament_add_gtest(
${PROJECT_NAME}_test_lights_behavior_tree
@@ -235,15 +234,8 @@ if(BUILD_TESTING)
${PROJECT_NAME}_test_lights_behavior_tree
PUBLIC $
$)
- ament_target_dependencies(
- ${PROJECT_NAME}_test_lights_behavior_tree
- behaviortree_cpp
- behaviortree_ros2
- panther_msgs
- panther_utils
- rclcpp
- sensor_msgs
- std_msgs)
+ ament_target_dependencies(${PROJECT_NAME}_test_lights_behavior_tree
+ ${PACKAGE_DEPENDENCIES})
ament_add_gtest(
${PROJECT_NAME}_test_safety_manager_node test/test_safety_manager_node.cpp
@@ -252,15 +244,8 @@ if(BUILD_TESTING)
${PROJECT_NAME}_test_safety_manager_node
PUBLIC $
$)
- ament_target_dependencies(
- ${PROJECT_NAME}_test_safety_manager_node
- behaviortree_cpp
- behaviortree_ros2
- panther_msgs
- panther_utils
- rclcpp
- sensor_msgs
- std_msgs)
+ ament_target_dependencies(${PROJECT_NAME}_test_safety_manager_node
+ ${PACKAGE_DEPENDENCIES})
ament_add_gtest(
${PROJECT_NAME}_test_safety_behavior_tree
@@ -270,16 +255,8 @@ if(BUILD_TESTING)
${PROJECT_NAME}_test_safety_behavior_tree
PUBLIC $
$)
- ament_target_dependencies(
- ${PROJECT_NAME}_test_safety_behavior_tree
- behaviortree_cpp
- behaviortree_ros2
- panther_msgs
- panther_utils
- rclcpp
- sensor_msgs
- std_msgs
- std_srvs)
+ ament_target_dependencies(${PROJECT_NAME}_test_safety_behavior_tree
+ ${PACKAGE_DEPENDENCIES})
endif()
ament_package()
diff --git a/panther_manager/CONFIGURATION.md b/panther_manager/CONFIGURATION.md
index 3317e43a..a0a5beb0 100644
--- a/panther_manager/CONFIGURATION.md
+++ b/panther_manager/CONFIGURATION.md
@@ -93,6 +93,14 @@ For a BehaviorTree project to work correctly, it must contain a tree with correc
### Trees
+#### Docking
+
+A tree responsible for waiting for the joystick command and trigger `Docking`/`Undocking` action.
+
+
+
+
+
#### Lights
A tree responsible for scheduling animations displayed on the Bumper Lights based on the Husarion Panther robot's system state.
@@ -206,6 +214,7 @@ To use your customized project, you can modify the `bt_project_file` ROS paramet
Groot2 also provides a real-time visualization tool that allows you to see and debug actively running trees. To use this tool with trees launched with the `panther_manager` package, you need to specify the port associated with the tree you want to visualize. The ports for each tree are listed below:
+- Docking tree: `10.15.20.2:4444`
- Lights tree: `10.15.20.2:5555`
- Safety tree: `10.15.20.2:6666`
- Shutdown tree: `10.15.20.2:7777`
diff --git a/panther_manager/behavior_trees/DockingBT.btproj b/panther_manager/behavior_trees/DockingBT.btproj
new file mode 100644
index 00000000..2752c0d3
--- /dev/null
+++ b/panther_manager/behavior_trees/DockingBT.btproj
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+Topic name for sensor_msgs/Joy message type
+ Max timeout to accept the msg
+ Vector of provided axis inputs
+ Vector of provided button inputs
+
+
+ bool value indicating whether to use dock ID
+ dock ID
+ type of the dock
+ maximum staging time
+ bool value indicating whether to navigate to
+ staging pose
+ action name to call
+
+
+ type of the dock
+ maximum time to get back to the staging pose
+ action name to call
+
+
+
diff --git a/panther_manager/behavior_trees/docking.xml b/panther_manager/behavior_trees/docking.xml
new file mode 100644
index 00000000..1118dc10
--- /dev/null
+++ b/panther_manager/behavior_trees/docking.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Topic name for sensor_msgs/Joy message type
+ Max timeout to accept the msg
+ Vector of provided axis inputs
+ Vector of provided button inputs
+
+
+ bool value indicating whether to use dock ID
+ dock ID
+ type of the dock
+ maximum staging time
+ bool value indicating whether to navigate to
staging pose
+ action name to call
+
+
+ type of the dock
+ maximum time to get back to the staging pose
+ action name to call
+
+
+
+
diff --git a/panther_manager/config/docking_manager.yaml b/panther_manager/config/docking_manager.yaml
new file mode 100644
index 00000000..28879a8b
--- /dev/null
+++ b/panther_manager/config/docking_manager.yaml
@@ -0,0 +1,12 @@
+/**:
+ docking_manager:
+ ros__parameters:
+ timer_frequency: 50.0
+ bt_server_port: 4444
+ ros_communication_timeout:
+ availability: 2.0
+ response: 1.0
+ ros_plugin_libs:
+ - check_joy_msg_bt_node
+ - dock_robot_bt_node
+ - undock_robot_bt_node
diff --git a/panther_manager/config/lights_manager.yaml b/panther_manager/config/lights_manager.yaml
index cea2a5e4..f9033f68 100644
--- a/panther_manager/config/lights_manager.yaml
+++ b/panther_manager/config/lights_manager.yaml
@@ -2,6 +2,7 @@
lights_manager:
ros__parameters:
timer_frequency: 10.0
+ bt_server_port: 5555
battery:
percent:
window_len: 6
diff --git a/panther_manager/include/panther_manager/behavior_tree_utils.hpp b/panther_manager/include/panther_manager/behavior_tree_utils.hpp
index 5ee2331e..db7f3212 100644
--- a/panther_manager/include/panther_manager/behavior_tree_utils.hpp
+++ b/panther_manager/include/panther_manager/behavior_tree_utils.hpp
@@ -26,6 +26,9 @@
#include "behaviortree_cpp/utils/shared_library.h"
#include "behaviortree_ros2/plugins.hpp"
+#include
+#include
+
namespace panther_manager::behavior_tree_utils
{
@@ -93,28 +96,75 @@ inline std::string GetLoggerPrefix(const std::string & bt_node_name)
namespace BT
{
/**
- * @brief Converts a string to a vector of integers.
+ * @brief Converts a string to a vector of float.
*
* @param str The string to convert.
- * @return std::vector The vector of integers.
+ * @return std::vector The vector of float.
*
- * @throw BT::RuntimeError Throws when there is no input or cannot parse int.
+ * @throw BT::RuntimeError Throws when there is no input or cannot parse float.
*/
template <>
-inline std::vector convertFromString>(StringView str)
+inline std::vector convertFromString>(StringView str)
{
- auto parts = BT::splitString(str, ';');
- if (!parts.size()) {
- throw BT::RuntimeError("invalid input");
- } else {
- std::vector result;
- for (auto & part : parts) {
- result.push_back(convertFromString(part));
- }
-
- return result;
+ auto parts = splitString(str, ';');
+ std::vector output;
+ output.reserve(parts.size());
+ for (const StringView & part : parts) {
+ output.push_back(convertFromString(part));
}
+ return output;
}
+
+/**
+ * @brief Converts a string to a PoseStamped message.
+ *
+ * The string format should be "x;y;z;roll;pitch;yaw;frame_id" where:
+ * - x, y, z: Position coordinates.
+ * - roll, pitch, yaw: Rotation around axes XYZ.
+ * - frame_id: Coordinate frame ID (string).
+ *
+ * @param str The string to convert.
+ * @return geometry_msgs::msg::PoseStamped The converted PoseStamped message.
+ *
+ * @throw BT::RuntimeError Throws if the input is invalid or cannot be parsed.
+ */
+template <>
+inline geometry_msgs::msg::PoseStamped convertFromString(
+ StringView str)
+{
+ constexpr std::size_t expected_parts_size = 7;
+
+ auto parts = splitString(str, ';');
+ if (parts.size() != expected_parts_size) {
+ throw BT::RuntimeError(
+ "Invalid input for PoseStamped. Expected " + std::to_string(expected_parts_size) +
+ " values: x;y;z;roll;pitch;yaw;frame_id");
+ }
+
+ geometry_msgs::msg::PoseStamped pose_stamped;
+
+ try {
+ pose_stamped.pose.position.x = convertFromString(parts[0]);
+ pose_stamped.pose.position.y = convertFromString(parts[1]);
+ pose_stamped.pose.position.z = convertFromString(parts[2]);
+
+ const auto roll = convertFromString(parts[3]);
+ const auto pitch = convertFromString(parts[4]);
+ const auto yaw = convertFromString(parts[5]);
+ tf2::Quaternion quaternion;
+ quaternion.setRPY(roll, pitch, yaw);
+ pose_stamped.pose.orientation = tf2::toMsg(quaternion);
+
+ pose_stamped.header.frame_id = convertFromString(parts[6]);
+ pose_stamped.header.stamp = rclcpp::Clock().now();
+
+ } catch (const std::exception & e) {
+ throw BT::RuntimeError("Failed to convert string to PoseStamped: " + std::string(e.what()));
+ }
+
+ return pose_stamped;
+}
+
} // namespace BT
#endif // PANTHER_MANAGER_BEHAVIOR_TREE_UTILS_HPP_
diff --git a/panther_manager/include/panther_manager/docking_manager_node.hpp b/panther_manager/include/panther_manager/docking_manager_node.hpp
new file mode 100644
index 00000000..7c311b75
--- /dev/null
+++ b/panther_manager/include/panther_manager/docking_manager_node.hpp
@@ -0,0 +1,67 @@
+// Copyright 2024 Husarion sp. z o.o.
+//
+// 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 PANTHER_MANAGER_DOCKING_MANAGER_NODE_HPP_
+#define PANTHER_MANAGER_DOCKING_MANAGER_NODE_HPP_
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "panther_manager/behavior_tree_manager.hpp"
+#include "panther_utils/moving_average.hpp"
+
+namespace panther_manager
+{
+
+using BoolMsg = std_msgs::msg::Bool;
+
+/**
+ * @brief This class is responsible for creating a BehaviorTree responsible for docking management,
+ * spinning it, and updating blackboard entries based on subscribed topics.
+ */
+class DockingManagerNode : public rclcpp::Node
+{
+public:
+ DockingManagerNode(
+ const std::string & node_name, const rclcpp::NodeOptions & options = rclcpp::NodeOptions());
+ ~DockingManagerNode() = default;
+
+ /**
+ * @brief Initializes the docking manager, setting up parameters and behavior tree.
+ * @throws std::runtime_error if initialization fails
+ */
+ void Initialize();
+
+protected:
+ void DeclareParameters();
+ void RegisterBehaviorTree();
+
+ std::unique_ptr docking_tree_manager_;
+
+private:
+ void TimerCB();
+
+ rclcpp::TimerBase::SharedPtr docking_tree_timer_;
+
+ BT::BehaviorTreeFactory factory_;
+};
+
+} // namespace panther_manager
+
+#endif // PANTHER_MANAGER_DOCKING_MANAGER_NODE_HPP_
diff --git a/panther_manager/include/panther_manager/plugins/action/call_set_bool_service_node.hpp b/panther_manager/include/panther_manager/plugins/action/call_set_bool_service_node.hpp
index adafe1d4..96f40482 100644
--- a/panther_manager/include/panther_manager/plugins/action/call_set_bool_service_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/action/call_set_bool_service_node.hpp
@@ -36,7 +36,8 @@ class CallSetBoolService : public BT::RosServiceNode
static BT::PortsList providedPorts()
{
- return providedBasicPorts({BT::InputPort("data", "true / false value")});
+ return providedBasicPorts(
+ {BT::InputPort("data", "Boolean value to send with the service request.")});
}
virtual bool setRequest(typename Request::SharedPtr & request) override;
diff --git a/panther_manager/include/panther_manager/plugins/action/call_set_led_animation_service_node.hpp b/panther_manager/include/panther_manager/plugins/action/call_set_led_animation_service_node.hpp
index 38a915a5..a0dcff1e 100644
--- a/panther_manager/include/panther_manager/plugins/action/call_set_led_animation_service_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/action/call_set_led_animation_service_node.hpp
@@ -36,11 +36,11 @@ class CallSetLedAnimationService : public BT::RosServiceNode("id", "animation ID"),
- BT::InputPort("param", "optional parameter"),
- BT::InputPort("repeating", "indicates if animation should repeat"),
- });
+ return providedBasicPorts(
+ {BT::InputPort("id", "Animation ID to trigger."),
+ BT::InputPort("param", "Optional animation parameter."),
+ BT::InputPort(
+ "repeating", "Specifies whether the animation should repeated continuously.")});
}
virtual bool setRequest(typename Request::SharedPtr & request) override;
diff --git a/panther_manager/include/panther_manager/plugins/action/dock_robot_node.hpp b/panther_manager/include/panther_manager/plugins/action/dock_robot_node.hpp
index 2e4a5c03..7793bd21 100644
--- a/panther_manager/include/panther_manager/plugins/action/dock_robot_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/action/dock_robot_node.hpp
@@ -48,22 +48,31 @@ class DockRobot : public BT::RosActionNode("use_dock_id", true, "Whether to use the dock's ID or dock pose fields"),
- BT::InputPort("dock_id", "Dock ID or name to use"),
- BT::InputPort("dock_type", "The dock plugin type, if using dock pose"),
- BT::InputPort(
- "max_staging_time", 1000.0, "Maximum time to navigate to the staging pose"),
- BT::InputPort(
- "navigate_to_staging_pose", true, "Whether to autonomously navigate to staging pose"),
+ return providedBasicPorts(
+ {BT::InputPort(
+ "use_dock_id", true, "Determines whether to use the dock's ID or dock pose fields."),
+ BT::InputPort(
+ "dock_id",
+ "Specifies the dock's ID or name from the dock database (used if 'use_dock_id' is true)."),
+ BT::InputPort(
+ "dock_pose",
+ "Specifies the dock's pose (used if 'use_dock_id' is false). Format: "
+ "\"x;y;z;roll;pitch;yaw;frame_id\""),
+ BT::InputPort(
+ "dock_type",
+ "Defines the type of dock being used when docking via pose. Not needed if only one dock "
+ "type is available."),
+ BT::InputPort(
+ "max_staging_time", 120.0,
+ "Maximum time allowed (in seconds) for navigating to the dock's staging pose."),
+ BT::InputPort(
+ "navigate_to_staging_pose", true,
+ "Specifies whether the robot should autonomously navigate to the staging pose."),
- BT::OutputPort(
- "success", "If the action was successful"),
- BT::OutputPort(
- "error_code", "Contextual error code, if any"),
- BT::OutputPort(
- "num_retries", "Number of retries attempted"),
- });
+ BT::OutputPort(
+ "error_code", "Returns an error code indicating the reason for failure, if any."),
+ BT::OutputPort(
+ "num_retries", "Reports the number of retry attempts made during the docking process.")});
}
};
diff --git a/panther_manager/include/panther_manager/plugins/action/shutdown_hosts_from_file_node.hpp b/panther_manager/include/panther_manager/plugins/action/shutdown_hosts_from_file_node.hpp
index 949565f6..c9eaa79e 100644
--- a/panther_manager/include/panther_manager/plugins/action/shutdown_hosts_from_file_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/action/shutdown_hosts_from_file_node.hpp
@@ -39,10 +39,8 @@ class ShutdownHostsFromFile : public ShutdownHosts
static BT::PortsList providedPorts()
{
- return {
- BT::InputPort(
- "shutdown_hosts_file", "global path to YAML file with hosts to shutdown"),
- };
+ return {BT::InputPort(
+ "shutdown_hosts_file", "Absolute path to a YAML file listing the hosts to shut down.")};
}
private:
diff --git a/panther_manager/include/panther_manager/plugins/action/shutdown_single_host_node.hpp b/panther_manager/include/panther_manager/plugins/action/shutdown_single_host_node.hpp
index 630db650..006ac53a 100644
--- a/panther_manager/include/panther_manager/plugins/action/shutdown_single_host_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/action/shutdown_single_host_node.hpp
@@ -38,14 +38,17 @@ class ShutdownSingleHost : public ShutdownHosts
static BT::PortsList providedPorts()
{
return {
- BT::InputPort("ip", "ip of the host to shutdown"),
- BT::InputPort("username", "user to log into while executing shutdown command"),
- BT::InputPort("port", "SSH communication port"),
- BT::InputPort("command", "command to execute on shutdown"),
- BT::InputPort("timeout", "time in seconds to wait for host to shutdown"),
+ BT::InputPort("ip", "IP address of the host to shut down."),
+ BT::InputPort(
+ "username", "Username to use for logging in and executing the shutdown command."),
+ BT::InputPort("port", "SSH port used for communication (default is usually 22)."),
+ BT::InputPort("command", "A command to execute on the remote host."),
+ BT::InputPort(
+ "timeout", "Maximum time (in seconds) to wait for the host to shut down."),
BT::InputPort(
- "ping_for_success", "ping host until it is not available or timeout is reached"),
- };
+ "ping_for_success",
+ "Whether to continuously ping the host until it becomes unreachable or the timeout is "
+ "reached.")};
}
private:
diff --git a/panther_manager/include/panther_manager/plugins/action/signal_shutdown_node.hpp b/panther_manager/include/panther_manager/plugins/action/signal_shutdown_node.hpp
index 7bc9709d..5eedaf7c 100644
--- a/panther_manager/include/panther_manager/plugins/action/signal_shutdown_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/action/signal_shutdown_node.hpp
@@ -35,7 +35,7 @@ class SignalShutdown : public BT::SyncActionNode
static BT::PortsList providedPorts()
{
return {
- BT::InputPort("reason", "", "reason to shutdown robot"),
+ BT::InputPort("reason", "", "A reason to shutdown a robot."),
};
}
diff --git a/panther_manager/include/panther_manager/plugins/action/undock_robot_node.hpp b/panther_manager/include/panther_manager/plugins/action/undock_robot_node.hpp
index ade7380f..24589118 100644
--- a/panther_manager/include/panther_manager/plugins/action/undock_robot_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/action/undock_robot_node.hpp
@@ -49,16 +49,15 @@ class UndockRobot : public BT::RosActionNode(
- "dock_type", "The dock plugin type, if not previous instance used for docking"),
- BT::InputPort(
- "max_undocking_time", 30.0, "Maximum time to get back to the staging pose"),
+ return providedBasicPorts(
+ {BT::InputPort(
+ "dock_type", "Specifies the dock plugin type to use for undocking."),
+ BT::InputPort(
+ "max_undocking_time", 30.0,
+ "Maximum allowable time (in seconds) to undock and return to the staging pose."),
- BT::OutputPort(
- "success", "If the action was successful"),
- BT::OutputPort("error_code", "Error code"),
- });
+ BT::OutputPort(
+ "error_code", "Returns an error code if the undocking process fails.")});
}
};
diff --git a/panther_manager/include/panther_manager/plugins/condition/are_buttons_pressed.hpp b/panther_manager/include/panther_manager/plugins/condition/check_bool_msg.hpp
similarity index 61%
rename from panther_manager/include/panther_manager/plugins/condition/are_buttons_pressed.hpp
rename to panther_manager/include/panther_manager/plugins/condition/check_bool_msg.hpp
index 8b0534b5..fbe52a88 100644
--- a/panther_manager/include/panther_manager/plugins/condition/are_buttons_pressed.hpp
+++ b/panther_manager/include/panther_manager/plugins/condition/check_bool_msg.hpp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef PANTHER_MANAGER_PLUGINS_CONDITION_ARE_BUTTONS_PRESSED_HPP_
-#define PANTHER_MANAGER_PLUGINS_CONDITION_ARE_BUTTONS_PRESSED_HPP_
+#ifndef PANTHER_MANAGER_PLUGINS_CONDITION_CHECK_BOOL_MSG_HPP_
+#define PANTHER_MANAGER_PLUGINS_CONDITION_CHECK_BOOL_MSG_HPP_
#include
#include
@@ -22,34 +22,34 @@
#include
#include
-#include
+#include
#include "panther_manager/behavior_tree_utils.hpp"
namespace panther_manager
{
-class AreButtonsPressed : public BT::RosTopicSubNode
+// FIXME: There is no possibility to set QoS profile. Add it in the future to subscribe e_stop.
+class CheckBoolMsg : public BT::RosTopicSubNode
{
+ using BoolMsg = std_msgs::msg::Bool;
+
public:
- AreButtonsPressed(
+ CheckBoolMsg(
const std::string & name, const BT::NodeConfig & conf, const BT::RosNodeParams & params)
- : BT::RosTopicSubNode(name, conf, params)
+ : BT::RosTopicSubNode(name, conf, params)
{
}
- BT::NodeStatus onTick(const std::shared_ptr & last_msg);
+ BT::NodeStatus onTick(const BoolMsg::SharedPtr & last_msg);
static BT::PortsList providedPorts()
{
return providedBasicPorts(
- {BT::InputPort>("buttons", "state of buttons to accept a condition")});
+ {BT::InputPort("data", "Specifies the expected state of the data field.")});
}
-
-private:
- std::vector buttons_;
};
} // namespace panther_manager
-#endif // PANTHER_MANAGER_PLUGINS_CONDITION_ARE_BUTTONS_PRESSED_HPP_
+#endif // PANTHER_MANAGER_PLUGINS_CONDITION_CHECK_BOOL_MSG_HPP_
diff --git a/panther_manager/include/panther_manager/plugins/condition/check_joy_msg.hpp b/panther_manager/include/panther_manager/plugins/condition/check_joy_msg.hpp
new file mode 100644
index 00000000..a7966482
--- /dev/null
+++ b/panther_manager/include/panther_manager/plugins/condition/check_joy_msg.hpp
@@ -0,0 +1,68 @@
+// Copyright 2024 Husarion sp. z o.o.
+//
+// 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 PANTHER_MANAGER_PLUGINS_CONDITION_CHECK_JOY_MSG_HPP_
+#define PANTHER_MANAGER_PLUGINS_CONDITION_CHECK_JOY_MSG_HPP_
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "panther_manager/behavior_tree_utils.hpp"
+
+namespace panther_manager
+{
+
+class CheckJoyMsg : public BT::RosTopicSubNode
+{
+ using JoyMsg = sensor_msgs::msg::Joy;
+
+public:
+ CheckJoyMsg(
+ const std::string & name, const BT::NodeConfig & conf, const BT::RosNodeParams & params)
+ : BT::RosTopicSubNode(name, conf, params)
+ {
+ }
+
+ BT::NodeStatus onTick(const JoyMsg::SharedPtr & last_msg);
+
+ static BT::PortsList providedPorts()
+ {
+ return providedBasicPorts(
+ {BT::InputPort>(
+ "axes", "",
+ "Specifies the expected state of the axes field. An empty string (\"\") means the values "
+ "are ignored."),
+ BT::InputPort>(
+ "buttons", "",
+ "Specifies the expected state of the buttons field. An empty string (\"\") means values "
+ "are ignored."),
+ BT::InputPort(
+ "timeout", 0.0, "Maximum allowable time delay to accept the condition.")});
+ }
+
+private:
+ bool checkAxes(const JoyMsg::SharedPtr & last_msg);
+ bool checkButtons(const JoyMsg::SharedPtr & last_msg);
+ bool checkTimeout(const JoyMsg::SharedPtr & last_msg);
+};
+
+} // namespace panther_manager
+
+#endif // PANTHER_MANAGER_PLUGINS_CONDITION_CHECK_JOY_MSG_HPP_
diff --git a/panther_manager/include/panther_manager/plugins/decorator/tick_after_timeout_node.hpp b/panther_manager/include/panther_manager/plugins/decorator/tick_after_timeout_node.hpp
index 20a273e5..af58ec3b 100644
--- a/panther_manager/include/panther_manager/plugins/decorator/tick_after_timeout_node.hpp
+++ b/panther_manager/include/panther_manager/plugins/decorator/tick_after_timeout_node.hpp
@@ -31,7 +31,8 @@ class TickAfterTimeout : public BT::DecoratorNode
static BT::PortsList providedPorts()
{
- return {BT::InputPort("timeout", "time in s to wait before ticking child again")};
+ return {BT::InputPort(
+ "timeout", "Time in seconds to wait before ticking the child node again.")};
}
private:
diff --git a/panther_manager/launch/manager.launch.py b/panther_manager/launch/manager.launch.py
index 14f4c8c7..c2ab3b18 100644
--- a/panther_manager/launch/manager.launch.py
+++ b/panther_manager/launch/manager.launch.py
@@ -32,6 +32,15 @@ def generate_launch_description():
panther_version = EnvironmentVariable(name="PANTHER_ROBOT_VERSION", default_value="1.0")
panther_manager_dir = FindPackageShare("panther_manager")
+ docking_bt_project_path = LaunchConfiguration("docking_bt_project_path")
+ declare_docking_bt_project_path_arg = DeclareLaunchArgument(
+ "docking_bt_project_path",
+ default_value=PathJoinSubstitution(
+ [panther_manager_dir, "behavior_trees", "DockingBT.btproj"]
+ ),
+ description="Path to BehaviorTree project file, responsible for docking management.",
+ )
+
lights_bt_project_path = LaunchConfiguration("lights_bt_project_path")
declare_lights_bt_project_path_arg = DeclareLaunchArgument(
"lights_bt_project_path",
@@ -78,6 +87,18 @@ def generate_launch_description():
description="Whether simulation is used",
)
+ docking_manager_node = Node(
+ package="panther_manager",
+ executable="docking_manager_node",
+ name="docking_manager",
+ parameters=[
+ PathJoinSubstitution([panther_manager_dir, "config", "docking_manager.yaml"]),
+ {"bt_project_path": docking_bt_project_path},
+ ],
+ namespace=namespace,
+ emulate_tty=True,
+ )
+
lights_manager_node = Node(
package="panther_manager",
executable="lights_manager_node",
@@ -107,11 +128,13 @@ def generate_launch_description():
)
actions = [
+ declare_docking_bt_project_path_arg,
declare_lights_bt_project_path_arg,
declare_safety_bt_project_path_arg,
declare_namespace_arg,
declare_shutdown_hosts_config_path_arg,
declare_use_sim_arg,
+ docking_manager_node,
lights_manager_node,
safety_manager_node,
]
diff --git a/panther_manager/package.xml b/panther_manager/package.xml
index 6da23d97..a9cd5f76 100644
--- a/panther_manager/package.xml
+++ b/panther_manager/package.xml
@@ -19,15 +19,18 @@
behaviortree_cpp
behaviortree_ros2
+ geometry_msgs
iputils-ping
libboost-dev
libssh-dev
+ opennav_docking_msgs
panther_msgs
panther_utils
rclcpp
rclcpp_action
sensor_msgs
std_srvs
+ tf2_geometry_msgs
yaml-cpp
ament_lint_auto
diff --git a/panther_manager/src/docking_manager_node.cpp b/panther_manager/src/docking_manager_node.cpp
new file mode 100644
index 00000000..8cd485f3
--- /dev/null
+++ b/panther_manager/src/docking_manager_node.cpp
@@ -0,0 +1,122 @@
+// Copyright 2024 Husarion sp. z o.o.
+//
+// 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 "panther_manager/docking_manager_node.hpp"
+
+#include
+#include
+#include
+#include