diff --git a/.gitignore b/.gitignore index f42d579a3..ac9f2a85e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -devel/ -logs/ build/ +log/ +install/ bin/ lib/ msg_gen/ @@ -13,8 +13,6 @@ msg/*Feedback.msg msg/*Goal.msg msg/*Result.msg msg/_*.py -build_isolated/ -devel_isolated/ # Generated by dynamic reconfigure *.cfgc diff --git a/README.md b/README.md index da2a5affc..f141f4b5b 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Launch arguments are largely common to both simulation and physical robot. Howev | --- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 🖥️ | `add_wheel_joints` | Flag enabling joint_state_publisher to publish information about the wheel position. Should be false when there is a controller that sends this information.
***bool:*** `False` | | 🖥️ | `add_world_transform` | Adds a world frame that connects the tf trees of individual robots (useful when running multiple robots).
***bool:*** `False` | +| 🤖🖥️ | `animations_config_path` | Path to a YAML file with a description of led configuration. This file includes definition of robot panels, virtual segments and default animations.
***string:*** [`{robot_model}_animations.yaml`](./panther_lights/config) | | 🖥️ | `battery_config_path` | Path to the Ignition LinearBatteryPlugin configuration file. This configuration is intended for use in simulations only.
***string:*** `None` | | 🤖🖥️ | `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/) | @@ -95,7 +96,6 @@ Launch arguments are largely common to both simulation and physical robot. Howev | 🖥️ | `gz_log_level` | Adjust the level of console output.
***int:*** `1` (choices: `0`, `1`, `2`, `3`, `4`) | | 🖥️ | `gz_world` | Absolute path to SDF world file.
***string:*** [`husarion_world.sdf`](https://github.com/husarion/husarion_gz_worlds/blob/main/worlds/husarion_world.sdf) | | 🤖 | `launch_nmea_gps` | Whether to launch the NMEA NavSat driver node. Advisable when the robot is equipped with the [ANT02](https://husarion.com/manuals/panther/panther-options/#ant02---wi-fi--lte--gps).
***bool:*** `False` | -| 🤖🖥️ | `led_config_file` | Path to a YAML file with a description of led configuration. This file includes definition of robot panels, virtual segments and default animations.
***string:*** [`led_config.yaml`](./panther_lights/config/led_config.yaml) | | 🤖🖥️ | `lights_bt_project_path` | Path to BehaviorTree project file, responsible for lights management.
***string:*** [`PantherLightsBT.btproj`](./panther_manager/behavior_trees/PantherLightsBT.btproj) | | 🤖🖥️ | `localization_config_path` | Specify the path to the localization configuration file.
***string:*** [`relative_localization.yaml`](./panther_localization/config/relative_localization.yaml) | | 🤖🖥️ | `localization_mode` | Specifies the localization mode:
- 'relative' `odometry/filtered` data is relative to the initial position and orientation.
- 'enu' `odometry/filtered` data is relative to initial position and ENU (East North Up) orientation.
***string:*** `relative` (choices: `relative`, `enu`) | @@ -103,10 +103,10 @@ Launch arguments are largely common to both simulation and physical robot. Howev | 🤖🖥️ | `publish_robot_state` | Whether to publish the default Panther robot description.
***bool:*** `True` | | 🖥️ | `robot_model` | Specify robot model type.
***string:*** `env(ROBOT_MODEL)` if not specified `panther` (choices: `lynx`, `panther`) | | 🤖🖥️ | `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) | +| 🤖🖥️ | `shutdown_hosts_config_path` | Path to file with list of hosts to request shutdown.
***string:*** [`shutdown_hosts.yaml`](./panther_manager/config/shutdown_hosts.yaml) | | 🤖🖥️ | `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:*** `''` | +| 🤖🖥️ | `user_led_animations_path` | Path to a YAML file with a description of the user-defined animations.
***string:*** `''` | | 🤖🖥️ | `wheel_config_path` | Path to wheel configuration file.
***string:*** [`{wheel_type}.yaml`](./panther_description/config) | | 🤖🖥️ | `wheel_type` | Specify the wheel type. If the selected wheel type is not 'custom', the wheel_config_path and controller_config_path arguments will be automatically adjusted and can be omitted.
***string:*** `WH01` (for Panther), `WH05` (for Lynx) (choices: `WH01`, `WH02`, `WH04`, `WH05`, `custom`) | | 🖥️ | `x` | Initial robot position in the global 'x' axis.
***float:*** `0.0` | diff --git a/panther_gazebo/CONFIGURATION.md b/panther_gazebo/CONFIGURATION.md index c41cc924c..d83baf523 100644 --- a/panther_gazebo/CONFIGURATION.md +++ b/panther_gazebo/CONFIGURATION.md @@ -33,7 +33,7 @@ To obtain GPS data in Ignition, follow these steps: ## Linear Battery Plugin -It is possible to simulate the battery operation of the Panther robot. By default, this feature is disabled, but you can enable it by setting the `simulate_discharging` parameter to `true` in the `battery_plugin_config.yaml` file or in the file pointed to by the `battery_config_path` parameter. Below, you will find the plugin parameters that enable battery simulation. +It is possible to simulate the battery operation of the Panther robot. By default, this feature is disabled, but you can enable it by setting the `simulate_discharging` parameter to `true` in the `battery_plugin.yaml` file or in the file pointed to by the `battery_config_path` parameter. Below, you will find the plugin parameters that enable battery simulation. - `simulate_discharging` [*bool*, default: **false**]: Enables battery simulation. If set to `true`, the battery will discharge **at a constant rate** (regardless of joint torque), and if it depletes completely, the robot will stop moving. When set to `false`, the battery will not discharge, but the battery status information will still be published on the `battery/battery_status` topic. - `initial_charge_percentage` [*float*, default: **70.0**]: Sets the initial charge percentage of the battery. diff --git a/panther_gazebo/README.md b/panther_gazebo/README.md index a4d3bb85a..7a8189153 100644 --- a/panther_gazebo/README.md +++ b/panther_gazebo/README.md @@ -11,7 +11,7 @@ The package contains a launch file and source files used to run the robot simula ## Configuration Files -- [`battery_plugin_config.yaml`](./config/battery_plugin_config.yaml): Simulated LinearBatteryPlugin configuration. +- [`battery_plugin.yaml`](./config/battery_plugin.yaml): Simulated LinearBatteryPlugin configuration. - [`gz_bridge.yaml`](./config/gz_bridge.yaml): Specify data to exchange between ROS and Gazebo simulation. - [`teleop_with_estop.config`](./config/teleop_with_estop.config): Gazebo layout configuration file, which adds E-Stop and Teleop widgets. diff --git a/panther_gazebo/config/battery_plugin_config.yaml b/panther_gazebo/config/battery_plugin.yaml similarity index 100% rename from panther_gazebo/config/battery_plugin_config.yaml rename to panther_gazebo/config/battery_plugin.yaml diff --git a/panther_gazebo/launch/simulate_robot.launch.py b/panther_gazebo/launch/simulate_robot.launch.py index cf2829481..2bd4f822b 100644 --- a/panther_gazebo/launch/simulate_robot.launch.py +++ b/panther_gazebo/launch/simulate_robot.launch.py @@ -51,7 +51,7 @@ def generate_launch_description(): "This configuration is intended for use in simulations only." ), default_value=PathJoinSubstitution( - [FindPackageShare("panther_gazebo"), "config", "battery_plugin_config.yaml"] + [FindPackageShare("panther_gazebo"), "config", "battery_plugin.yaml"] ), ) diff --git a/panther_lights/CMakeLists.txt b/panther_lights/CMakeLists.txt index 070bd8c17..482023e35 100644 --- a/panther_lights/CMakeLists.txt +++ b/panther_lights/CMakeLists.txt @@ -85,7 +85,8 @@ install( install(TARGETS panther_animation_plugins LIBRARY DESTINATION lib) -install(DIRECTORY animations config launch DESTINATION share/${PROJECT_NAME}) +install(DIRECTORY animations config launch test + DESTINATION share/${PROJECT_NAME}) if(BUILD_TESTING) find_package(ament_cmake_gtest REQUIRED) diff --git a/panther_lights/CONFIGURATION.md b/panther_lights/CONFIGURATION.md index 75f1d4345..df53c7dcd 100644 --- a/panther_lights/CONFIGURATION.md +++ b/panther_lights/CONFIGURATION.md @@ -2,7 +2,7 @@ ## LED Animations -Basic led configuration is loaded from [`led_config.yaml`](config/led_config.yaml) file. It includes definition of robot panels, virtual segments and default animations. Default animations can be found in the table below: +Basic led configuration is loaded from [`{robot_model}_animations.yaml`](config) file. It includes definition of robot panels, virtual segments and default animations. Default animations can be found in the table below: | ID | NAME | PRIORITY | ANIMATION | | :---: | ----------------- | :------: | -------------------------------------------------- | @@ -121,7 +121,7 @@ user_animations: - type: panther_lights::ImageAnimation segments: all animation: - image: $(find my_custom_animation_package)/animations/custom_image.png + image: $(find custom_pkg)/animations/custom_image.png duration: 3 repeat: 1 @@ -133,22 +133,21 @@ user_animations: - type: panther_lights::ImageAnimation segments: front animation: - image: $(find panther_lights)/animations/triangle01_blue.png + image: $(find custom_pkg)/animations/front_custom_image.png duration: 2 repeat: 2 - type: panther_lights::ImageAnimation segments: rear animation: - image: $(find panther_lights)/animations/triangle01_red.png + image: $(find custom_pkg)/animations/rear_custom_image.png duration: 3 repeat: 1 ``` -> [!NOTE] -> ID numbers from 0 to 19 are reserved for system animations. - -> [!NOTE] -> Priority **1** is reserved for crucial system animations. Users can only define animations with priority **2** and **3**. +> [!IMPORTANT] +> +> - ID numbers from 0 to 19 are reserved for system animations. +> - Priority **1** is reserved for crucial system animations. Users can only define animations with priority **2** and **3**. Remember to modify launch command to use user animations: diff --git a/panther_lights/README.md b/panther_lights/README.md index 8c1a7331f..548b04033 100644 --- a/panther_lights/README.md +++ b/panther_lights/README.md @@ -10,7 +10,8 @@ This package contains: ## Configuration Files -- [`led_config.yaml`](./config/led_config.yaml): Defines and describes the appearance and parameters of the animations. +- [`{robot_model}_animations.yaml`](./config): Defines and describes the appearance and parameters of the animations for specific robot. +- [`{robot_model}_driver.yaml`](./config): Defines and describes specific hardware configuration for specific robot. ## ROS Nodes @@ -29,9 +30,9 @@ This node is of type rclcpp_components is responsible for processing animations #### Parameters +- `~animations_config_path` [*string*, default: **$(find panther_lights)/panther_lights/config/{robot_model}_animations.yaml**]: Path to a YAML file with a description of led configuration. This file includes definition of robot panels, virtual segments and default animations. - `~controller_frequency` [*float*, default: **50.0**]: Frequency [Hz] at which the lights controller node will process animations. -- `~led_config_file` [*string*, default: **$(find panther_lights)/panther_lights/config/led_config.yaml**]: Path to a YAML file with a description of led configuration. This file includes definition of robot panels, virtual segments and default animations. -- `~user_led_animations_file` [*string*, default: **None**]: Path to a YAML file with a description of the user defined animations. +- `~user_led_animations_path` [*string*, default: **None**]: Path to a YAML file with a description of the user defined animations. ### LightsDriverNode diff --git a/panther_lights/config/lynx_led_config.yaml b/panther_lights/config/lynx_animations.yaml similarity index 99% rename from panther_lights/config/lynx_led_config.yaml rename to panther_lights/config/lynx_animations.yaml index 0d6b36b67..44f9e2d11 100644 --- a/panther_lights/config/lynx_led_config.yaml +++ b/panther_lights/config/lynx_animations.yaml @@ -18,7 +18,6 @@ segments: channel: 2 led_range: 21-11 - segments_map: all: [fl, fr, rl, rr] front: [fl, fr] diff --git a/panther_lights/config/lynx_driver.yaml b/panther_lights/config/lynx_driver.yaml new file mode 100644 index 000000000..1dc9dca72 --- /dev/null +++ b/panther_lights/config/lynx_driver.yaml @@ -0,0 +1,5 @@ +/**: + lights_driver: + ros__parameters: + channel_1_num_led: 22 + channel_2_num_led: 22 diff --git a/panther_lights/config/panther_led_config.yaml b/panther_lights/config/panther_animations.yaml similarity index 100% rename from panther_lights/config/panther_led_config.yaml rename to panther_lights/config/panther_animations.yaml diff --git a/panther_lights/config/panther_driver.yaml b/panther_lights/config/panther_driver.yaml new file mode 100644 index 000000000..404dfbabf --- /dev/null +++ b/panther_lights/config/panther_driver.yaml @@ -0,0 +1,5 @@ +/**: + lights_driver: + ros__parameters: + channel_1_num_led: 46 + channel_2_num_led: 46 diff --git a/panther_lights/include/panther_lights/lights_controller_node.hpp b/panther_lights/include/panther_lights/lights_controller_node.hpp index ef051bd3a..eb98f16f9 100644 --- a/panther_lights/include/panther_lights/lights_controller_node.hpp +++ b/panther_lights/include/panther_lights/lights_controller_node.hpp @@ -90,9 +90,9 @@ class LightsControllerNode : public rclcpp::Node /** * @brief Adds animations to an unordered map with animations * - * @param user_led_animations_file path to YAML file with user animations description + * @param user_led_animations_path path to YAML file with user animations description */ - void LoadUserAnimations(const std::string & user_led_animations_file); + void LoadUserAnimations(const std::string & user_led_animations_path); /** * @brief Adds animation to an unordered map with animations diff --git a/panther_lights/include/panther_lights/lights_driver_node.hpp b/panther_lights/include/panther_lights/lights_driver_node.hpp index 094dc091a..f1a4b5b5c 100644 --- a/panther_lights/include/panther_lights/lights_driver_node.hpp +++ b/panther_lights/include/panther_lights/lights_driver_node.hpp @@ -83,7 +83,8 @@ class LightsDriverNode : public rclcpp::Node */ void PanelThrottleWarnLog(const std::string panel_name, const std::string message); - int num_led_; + int channel_1_num_led_; + int channel_2_num_led_; double frame_timeout_; bool led_control_granted_; bool led_control_pending_; diff --git a/panther_lights/launch/lights.launch.py b/panther_lights/launch/lights.launch.py index 2f741faa8..9a97853f1 100644 --- a/panther_lights/launch/lights.launch.py +++ b/panther_lights/launch/lights.launch.py @@ -33,13 +33,14 @@ def generate_launch_description(): robot_model = LaunchConfiguration("robot_model") - robot_led_config = PythonExpression(["'", robot_model, "_config.yaml'"]) - led_config_file = LaunchConfiguration("led_config_file") - declare_led_config_file_arg = DeclareLaunchArgument( - "led_config_file", - default_value=PathJoinSubstitution( - [FindPackageShare("panther_lights"), "config", robot_led_config] - ), + lights_pkg = FindPackageShare("panther_lights") + animations_file = PythonExpression(["'", robot_model, "_animation.yaml'"]) + default_animations_path = PathJoinSubstitution([lights_pkg, "config", animations_file]) + + animations_config_path = LaunchConfiguration("animations_config_path") + declare_animations_config_path_arg = DeclareLaunchArgument( + "animations_config_path", + default_value=default_animations_path, description="Path to a YAML file with a description of led configuration.", ) @@ -66,13 +67,15 @@ def generate_launch_description(): description="Whether simulation is used", ) - user_led_animations_file = LaunchConfiguration("user_led_animations_file") - declare_user_led_animations_file_arg = DeclareLaunchArgument( - "user_led_animations_file", + user_led_animations_path = LaunchConfiguration("user_led_animations_path") + declare_user_led_animations_path_arg = DeclareLaunchArgument( + "user_led_animations_path", default_value="", description="Path to a YAML file with a description of the user defined animations.", ) + driver_file = PythonExpression(["'", robot_model, "_driver.yaml'"]) + driver_path = PathJoinSubstitution([lights_pkg, "config", driver_file]) lights_container = ComposableNodeContainer( package="rclcpp_components", name="lights_container", @@ -85,6 +88,7 @@ def generate_launch_description(): name="lights_driver", namespace=namespace, remappings=[("/diagnostics", "diagnostics")], + parameters=[driver_path], extra_arguments=[ {"use_intra_process_comms": True}, ], @@ -96,8 +100,8 @@ def generate_launch_description(): name="lights_controller", namespace=namespace, parameters=[ - {"led_config_file": led_config_file}, - {"user_led_animations_file": user_led_animations_file}, + {"animations_config_path": animations_config_path}, + {"user_led_animations_path": user_led_animations_path}, ], extra_arguments=[ {"use_intra_process_comms": True}, @@ -109,11 +113,11 @@ def generate_launch_description(): ) actions = [ - declare_robot_model_arg, # robot_model is used by led_config_file - declare_led_config_file_arg, + declare_robot_model_arg, # robot_model is used by animations_config_path + declare_animations_config_path_arg, declare_namespace_arg, declare_use_sim_arg, - declare_user_led_animations_file_arg, + declare_user_led_animations_path_arg, lights_container, ] diff --git a/panther_lights/src/lights_controller_node.cpp b/panther_lights/src/lights_controller_node.cpp index fb2d461f5..d77443ef7 100644 --- a/panther_lights/src/lights_controller_node.cpp +++ b/panther_lights/src/lights_controller_node.cpp @@ -48,23 +48,23 @@ LightsControllerNode::LightsControllerNode(const rclcpp::NodeOptions & options) using namespace std::placeholders; - this->declare_parameter("led_config_file"); - this->declare_parameter("user_led_animations_file", ""); + this->declare_parameter("animations_config_path"); + this->declare_parameter("user_led_animations_path", ""); this->declare_parameter("controller_freq", 50.0); - const auto led_config_file = this->get_parameter("led_config_file").as_string(); - const auto user_led_animations_file = this->get_parameter("user_led_animations_file").as_string(); + const auto animations_config_path = this->get_parameter("animations_config_path").as_string(); + const auto user_led_animations_path = this->get_parameter("user_led_animations_path").as_string(); const float controller_freq = this->get_parameter("controller_freq").as_double(); - YAML::Node led_config_desc = YAML::LoadFile(led_config_file); + YAML::Node led_config_desc = YAML::LoadFile(animations_config_path); InitializeLEDPanels(led_config_desc["panels"]); InitializeLEDSegments(led_config_desc["segments"], controller_freq); InitializeLEDSegmentsMap(led_config_desc["segments_map"]); LoadDefaultAnimations(led_config_desc["led_animations"]); - if (user_led_animations_file != "") { - LoadUserAnimations(user_led_animations_file); + if (user_led_animations_path != "") { + LoadUserAnimations(user_led_animations_path); } segment_converter_ = std::make_shared(); @@ -159,12 +159,12 @@ void LightsControllerNode::LoadDefaultAnimations(const YAML::Node & animations_d RCLCPP_INFO(this->get_logger(), "Loaded default animations."); } -void LightsControllerNode::LoadUserAnimations(const std::string & user_led_animations_file) +void LightsControllerNode::LoadUserAnimations(const std::string & user_led_animations_path) { RCLCPP_DEBUG(this->get_logger(), "Loading user's animations."); try { - YAML::Node user_led_animations = YAML::LoadFile(user_led_animations_file); + YAML::Node user_led_animations = YAML::LoadFile(user_led_animations_path); auto user_animations = panther_utils::GetYAMLKeyValue>( user_led_animations, "user_animations"); diff --git a/panther_lights/src/lights_driver_node.cpp b/panther_lights/src/lights_driver_node.cpp index e014695ae..7535955c4 100644 --- a/panther_lights/src/lights_driver_node.cpp +++ b/panther_lights/src/lights_driver_node.cpp @@ -54,10 +54,12 @@ LightsDriverNode::LightsDriverNode(const rclcpp::NodeOptions & options) this->declare_parameter("global_brightness", 1.0); this->declare_parameter("frame_timeout", 0.1); - this->declare_parameter("num_led", 46); + this->declare_parameter("channel_1_num_led", 46); + this->declare_parameter("channel_2_num_led", 46); frame_timeout_ = this->get_parameter("frame_timeout").as_double(); - num_led_ = this->get_parameter("num_led").as_int(); + channel_1_num_led_ = this->get_parameter("channel_1_num_led").as_int(); + channel_2_num_led_ = this->get_parameter("channel_2_num_led").as_int(); const float global_brightness = this->get_parameter("global_brightness").as_double(); channel_1_->SetGlobalBrightness(global_brightness); @@ -133,8 +135,8 @@ void LightsDriverNode::InitializationTimerCB() void LightsDriverNode::ClearLEDs() { - channel_1_->SetPanel(std::vector(num_led_ * 4, 0)); - channel_2_->SetPanel(std::vector(num_led_ * 4, 0)); + channel_1_->SetPanel(std::vector(channel_1_num_led_ * 4, 0)); + channel_2_->SetPanel(std::vector(channel_2_num_led_ * 4, 0)); } void LightsDriverNode::ToggleLEDControl(const bool enable) @@ -211,7 +213,9 @@ void LightsDriverNode::FrameCB( message = "Incorrect image encoding ('" + msg->encoding + "')"; } else if (msg->height != 1) { message = "Incorrect image height " + std::to_string(msg->height); - } else if (msg->width != (std::uint32_t)num_led_) { + } else if ( + msg->width != + (std::uint32_t)(panel_name == "channel_1" ? channel_1_num_led_ : channel_2_num_led_)) { message = "Incorrect image width " + std::to_string(msg->width); } diff --git a/panther_lights/test/files/animation.png b/panther_lights/test/files/animation.png new file mode 100644 index 000000000..5886cfe10 Binary files /dev/null and b/panther_lights/test/files/animation.png differ diff --git a/panther_lights/test/integration/panther_lights.test.py b/panther_lights/test/integration/panther_lights.test.py index fafd6bf19..25fa0e95c 100644 --- a/panther_lights/test/integration/panther_lights.test.py +++ b/panther_lights/test/integration/panther_lights.test.py @@ -36,14 +36,15 @@ def generate_test_description(): - led_config_file = ( - PathJoinSubstitution([FindPackageShare("panther_lights"), "config", "led_config.yaml"]), + # TODO: Fix the path for specific robot model + animations_config_path = ( + PathJoinSubstitution([FindPackageShare("panther_lights"), "config", "animations.yaml"]), ) lights_controller_node = Node( package="panther_lights", executable="lights_controller_node", - parameters=[{"led_config_file": led_config_file}], + parameters=[{"animations_config_path": animations_config_path}], ) lights_driver_node = Node( diff --git a/panther_lights/test/unit/animation/test_image_animation.cpp b/panther_lights/test/unit/animation/test_image_animation.cpp index 9437bae1b..2409a30c3 100644 --- a/panther_lights/test/unit/animation/test_image_animation.cpp +++ b/panther_lights/test/unit/animation/test_image_animation.cpp @@ -94,21 +94,21 @@ TEST_F(TestImageAnimation, ParseImagePath) EXPECT_EQ(this->test_image_path, animation_->ParseImagePath(this->test_image_path)); // test ROS package path - image_path = "$(find invalid_ros_package)/animations/strip01_red.png"; + image_path = "$(find invalid_ros_package)/test/files/animation.png"; EXPECT_THROW(animation_->ParseImagePath(image_path), std::runtime_error); // invalid substitution - image_path = "$(fin panther_lights)/animations/strip01_red.png"; + image_path = "$(fin panther_lights)/test/files/animation.png"; EXPECT_THROW(animation_->ParseImagePath(image_path), std::runtime_error); - image_path = "$(find panther_lights/animations/strip01_red.png"; + image_path = "$(find panther_lights/test/files/animation.png"; EXPECT_THROW(animation_->ParseImagePath(image_path), std::runtime_error); // following ones may not work if ROS package is not build or sourced - image_path = "$(find panther_lights)/animations/strip01_red.png"; + image_path = "$(find panther_lights)/test/files/animation.png"; EXPECT_NO_THROW(animation_->ParseImagePath(image_path)); // multiple spaces after find syntax - image_path = "$(find panther_lights)/animations/strip01_red.png"; + image_path = "$(find panther_lights)/test/files/animation.png"; EXPECT_NO_THROW(animation_->ParseImagePath(image_path)); } diff --git a/panther_lights/test/unit/led_components/test_led_animation.cpp b/panther_lights/test/unit/led_components/test_led_animation.cpp index 64dd9b024..51dbc58d4 100644 --- a/panther_lights/test/unit/led_components/test_led_animation.cpp +++ b/panther_lights/test/unit/led_components/test_led_animation.cpp @@ -54,7 +54,7 @@ TestLEDAnimation::TestLEDAnimation() anim_desc.segments = {kTestSegmentName1, kTestSegmentName2}; anim_desc.type = "panther_lights::ImageAnimation"; anim_desc.animation = - YAML::Load("{image: $(find panther_lights)/animations/triangle01_red.png, duration: 2.0}"); + YAML::Load("{image: $(find panther_lights)/test/files/animation.png, duration: 2.0}"); panther_lights::LEDAnimationDescription led_anim_desc; led_anim_desc.id = 0; diff --git a/panther_lights/test/unit/led_components/test_led_animations_queue.cpp b/panther_lights/test/unit/led_components/test_led_animations_queue.cpp index bdd9386de..4eb8d8c79 100644 --- a/panther_lights/test/unit/led_components/test_led_animations_queue.cpp +++ b/panther_lights/test/unit/led_components/test_led_animations_queue.cpp @@ -61,7 +61,7 @@ panther_lights::LEDAnimation TestLEDAnimationsQueue::CreateLEDAnimation( anim_desc.segments = {"segment_1", "segment_2"}; anim_desc.type = "panther_lights::ImageAnimation"; anim_desc.animation = - YAML::Load("{image: $(find panther_lights)/animations/triangle01_red.png, duration: 2.0}"); + YAML::Load("{image: $(find panther_lights)/test/files/animation.png, duration: 2.0}"); panther_lights::LEDAnimationDescription led_anim_desc; led_anim_desc.id = 0; diff --git a/panther_lights/test/unit/led_components/test_led_segment.cpp b/panther_lights/test/unit/led_components/test_led_segment.cpp index 9e20ff0dd..82fbec3e2 100644 --- a/panther_lights/test/unit/led_components/test_led_segment.cpp +++ b/panther_lights/test/unit/led_components/test_led_segment.cpp @@ -189,7 +189,7 @@ TEST_F(TestLEDSegment, SetAnimation) { // test each known animtion type const auto image_anim_desc = YAML::Load( - "{image: $(find panther_lights)/animations/triangle01_red.png, " + "{image: $(find panther_lights)/test/files/animation.png, " "duration: 2}"); const auto charging_anim_desc = YAML::Load("{duration: 2}"); @@ -203,7 +203,7 @@ TEST_F(TestLEDSegment, SetAnimation) TEST_F(TestLEDSegment, SetAnimationRepeating) { const auto anim_desc = YAML::Load( - "{image: $(find panther_lights)/animations/triangle01_red.png, " + "{image: $(find panther_lights)/test/files/animation.png, " "duration: 2}"); ASSERT_NO_THROW(led_segment_->SetAnimation("panther_lights::ImageAnimation", anim_desc, false)); @@ -224,7 +224,7 @@ TEST_F(TestLEDSegment, UpdateAnimationAnimationNotSet) TEST_F(TestLEDSegment, UpdateAnimation) { const auto anim_desc = YAML::Load( - "{image: $(find panther_lights)/animations/triangle01_red.png, " + "{image: $(find panther_lights)/test/files/animation.png, " "duration: 2}"); ASSERT_NO_THROW(led_segment_->SetAnimation("panther_lights::ImageAnimation", anim_desc, false)); EXPECT_NO_THROW(led_segment_->UpdateAnimation()); @@ -240,7 +240,7 @@ int main(int argc, char ** argv) TEST_F(TestLEDSegment, ResetDefaultAnimationWhenNewArrive) { const auto anim_desc = YAML::Load( - "{image: $(find panther_lights)/animations/triangle01_red.png, " + "{image: $(find panther_lights)/test/files/animation.png, " "duration: 2}"); ASSERT_NO_THROW(led_segment_->SetAnimation("panther_lights::ImageAnimation", anim_desc, true)); diff --git a/panther_lights/test/unit/led_components/test_segment_converter.cpp b/panther_lights/test/unit/led_components/test_segment_converter.cpp index ef1a7747c..807f9440d 100644 --- a/panther_lights/test/unit/led_components/test_segment_converter.cpp +++ b/panther_lights/test/unit/led_components/test_segment_converter.cpp @@ -63,9 +63,7 @@ YAML::Node TestSegmentConverter::CreateSegmentDescription( YAML::Node TestSegmentConverter::CreateImageAnimationDescription() { - return YAML::Load( - "{image: $(find panther_lights)/animations/triangle01_red.png, " - "duration: 2}"); + return YAML::Load("{image: $(find panther_lights)/test/files/animation.png, duration: 2}"); } TEST_F(TestSegmentConverter, ConvertInvalidChannel) diff --git a/panther_lights/test/unit/test_lights_controller_node.cpp b/panther_lights/test/unit/test_lights_controller_node.cpp index 7a27f3a40..99b0a0690 100644 --- a/panther_lights/test/unit/test_lights_controller_node.cpp +++ b/panther_lights/test/unit/test_lights_controller_node.cpp @@ -77,18 +77,18 @@ class TestLightsControllerNode : public testing::Test static constexpr char kTestSegmentName[] = "test"; static constexpr char kTestSegmentLedRange[] = "0-9"; - std::filesystem::path led_config_file_; + std::filesystem::path animations_config_path_; std::shared_ptr lights_controller_node_; }; TestLightsControllerNode::TestLightsControllerNode() { - led_config_file_ = testing::TempDir() + "/led_config.yaml"; + animations_config_path_ = testing::TempDir() + "/animations.yaml"; - CreateLEDConfig(led_config_file_); + CreateLEDConfig(animations_config_path_); std::vector params; - params.push_back(rclcpp::Parameter("led_config_file", led_config_file_)); + params.push_back(rclcpp::Parameter("animations_config_path", animations_config_path_)); rclcpp::NodeOptions options; options.parameter_overrides(params); @@ -96,7 +96,10 @@ TestLightsControllerNode::TestLightsControllerNode() lights_controller_node_ = std::make_shared(options); } -TestLightsControllerNode::~TestLightsControllerNode() { std::filesystem::remove(led_config_file_); } +TestLightsControllerNode::~TestLightsControllerNode() +{ + std::filesystem::remove(animations_config_path_); +} void TestLightsControllerNode::CreateLEDConfig(const std::filesystem::path file_path) { @@ -113,7 +116,7 @@ void TestLightsControllerNode::CreateLEDConfig(const std::filesystem::path file_ segments_map["test"] = std::vector(1, kTestSegmentName); YAML::Node animation; - animation["image"] = "$(find panther_lights)/animations/triangle01_red.png"; + animation["image"] = "$(find panther_lights)/test/files/strip01_red.png"; animation["duration"] = 2; YAML::Node animation_desc; @@ -133,14 +136,14 @@ void TestLightsControllerNode::CreateLEDConfig(const std::filesystem::path file_ led_animations.push_back(led_animation_0); led_animations.push_back(led_animation_1); - YAML::Node led_config; - led_config["panels"] = std::vector(1, panel); - led_config["segments"] = std::vector(1, segment); - led_config["segments_map"] = segments_map; - led_config["led_animations"] = led_animations; + YAML::Node animations_config; + animations_config["panels"] = std::vector(1, panel); + animations_config["segments"] = std::vector(1, segment); + animations_config["segments_map"] = segments_map; + animations_config["led_animations"] = led_animations; YAML::Emitter out; - out << led_config; + out << animations_config; std::ofstream fout(file_path); if (fout.is_open()) { diff --git a/panther_lights/test/unit/test_lights_driver_node.cpp b/panther_lights/test/unit/test_lights_driver_node.cpp index 9a20b0f5e..09918acfd 100644 --- a/panther_lights/test/unit/test_lights_driver_node.cpp +++ b/panther_lights/test/unit/test_lights_driver_node.cpp @@ -55,7 +55,8 @@ panther_lights::LightsDriverNode::LightsDriverNode( channel_2_(channel_2), diagnostic_updater_(this) { - num_led_ = 46; + channel_1_num_led_ = 46; + channel_2_num_led_ = 46; frame_timeout_ = 0.1; }; @@ -83,7 +84,10 @@ class DriverNodeWrapper : public panther_lights::LightsDriverNode return LightsDriverNode::FrameCB(msg, panel, last_time, panel_name); } - int GetNumLed() const { return num_led_; } + int GetNumLed(const std::string & panel_name) const + { + return panel_name == "channel_1" ? channel_1_num_led_ : channel_2_num_led_; + } double GetTimeout() const { return frame_timeout_; } bool GetLedControlGranted() const { return led_control_granted_; } bool GetLedControlPending() const { return led_control_pending_; } @@ -98,7 +102,7 @@ class TestLightsDriverNode : public testing::Test TestLightsDriverNode(); ~TestLightsDriverNode() {}; - ImageMsg::UniquePtr CreateValidImageMsg(); + ImageMsg::UniquePtr CreateValidImageMsg(const std::string & panel_name); std::shared_future> CreateSetBoolSrvFuture(bool request_data, bool response_success); @@ -115,7 +119,7 @@ TestLightsDriverNode::TestLightsDriverNode() lights_driver_node_ = std::make_unique(channel_1_, channel_2_); } -ImageMsg::UniquePtr TestLightsDriverNode::CreateValidImageMsg() +ImageMsg::UniquePtr TestLightsDriverNode::CreateValidImageMsg(const std::string & panel_name) { ImageMsg::UniquePtr msg(new ImageMsg); @@ -123,7 +127,7 @@ ImageMsg::UniquePtr TestLightsDriverNode::CreateValidImageMsg() msg->header.stamp = lights_driver_node_->now(); msg->header.frame_id = "image_frame"; msg->height = 1; - msg->width = lights_driver_node_->GetNumLed(); + msg->width = lights_driver_node_->GetNumLed(panel_name); msg->encoding = sensor_msgs::image_encodings::RGBA8; msg->is_bigendian = false; msg->step = msg->width * 4; @@ -158,11 +162,13 @@ TEST_F(TestLightsDriverNode, TestInitialization) TEST_F(TestLightsDriverNode, ClearLEDs) { - auto num_led = lights_driver_node_->GetNumLed(); - std::vector zero_frame(num_led * 4, 0); + auto num_led_1 = lights_driver_node_->GetNumLed("channel_1"); + auto num_led_2 = lights_driver_node_->GetNumLed("channel_2"); + std::vector zero_frame_1(num_led_1 * 4, 0); + std::vector zero_frame_2(num_led_2 * 4, 0); - EXPECT_CALL(*channel_1_, SetPanel(zero_frame)).Times(1); - EXPECT_CALL(*channel_2_, SetPanel(zero_frame)).Times(1); + EXPECT_CALL(*channel_1_, SetPanel(zero_frame_1)).Times(1); + EXPECT_CALL(*channel_2_, SetPanel(zero_frame_2)).Times(1); lights_driver_node_->ClearLEDs(); } @@ -203,7 +209,7 @@ TEST_F(TestLightsDriverNode, ToggleLEDControlCBDisabled) TEST_F(TestLightsDriverNode, FrameCBSuccessNoControl) { - auto msg = CreateValidImageMsg(); + auto msg = CreateValidImageMsg("channel_1"); EXPECT_CALL(*channel_1_, SetPanel(testing::_)).Times(0); @@ -212,7 +218,8 @@ TEST_F(TestLightsDriverNode, FrameCBSuccessNoControl) TEST_F(TestLightsDriverNode, FrameCBSuccess) { - auto msg = CreateValidImageMsg(); + auto msg_1 = CreateValidImageMsg("channel_1"); + auto msg_2 = CreateValidImageMsg("channel_2"); auto future = CreateSetBoolSrvFuture(true, true); lights_driver_node_->ToggleLEDControlCB(std::move(future)); @@ -220,13 +227,13 @@ TEST_F(TestLightsDriverNode, FrameCBSuccess) EXPECT_CALL(*channel_1_, SetPanel(testing::_)).Times(1); EXPECT_CALL(*channel_2_, SetPanel(testing::_)).Times(1); - lights_driver_node_->FrameCB(msg, channel_1_, msg->header.stamp, "channel_1"); - lights_driver_node_->FrameCB(msg, channel_2_, msg->header.stamp, "channel_2"); + lights_driver_node_->FrameCB(msg_1, channel_1_, msg_1->header.stamp, "channel_1"); + lights_driver_node_->FrameCB(msg_2, channel_2_, msg_2->header.stamp, "channel_2"); } TEST_F(TestLightsDriverNode, FrameCBTimeout) { - auto msg = CreateValidImageMsg(); + auto msg = CreateValidImageMsg("channel_1"); auto timeout = lights_driver_node_->GetTimeout(); // Set timestamp to exceed timeout @@ -242,7 +249,7 @@ TEST_F(TestLightsDriverNode, FrameCBTimeout) TEST_F(TestLightsDriverNode, FrameCBPast) { - auto msg = CreateValidImageMsg(); + auto msg = CreateValidImageMsg("channel_1"); // Set last_time to be younger than msg timestamp auto future = CreateSetBoolSrvFuture(true, true); @@ -255,7 +262,7 @@ TEST_F(TestLightsDriverNode, FrameCBPast) TEST_F(TestLightsDriverNode, FrameCBEncoding) { - auto msg = CreateValidImageMsg(); + auto msg = CreateValidImageMsg("channel_1"); // Set incorrect encoding msg->encoding = sensor_msgs::image_encodings::RGB8; @@ -270,7 +277,7 @@ TEST_F(TestLightsDriverNode, FrameCBEncoding) TEST_F(TestLightsDriverNode, FrameCBHeight) { - auto msg = CreateValidImageMsg(); + auto msg = CreateValidImageMsg("channel_1"); // Set incorrect height msg->height = 2; @@ -285,10 +292,10 @@ TEST_F(TestLightsDriverNode, FrameCBHeight) TEST_F(TestLightsDriverNode, FrameCBWidth) { - auto msg = CreateValidImageMsg(); + auto msg = CreateValidImageMsg("channel_1"); // Set incorrect width - msg->width = lights_driver_node_->GetNumLed() + 1; + msg->width = lights_driver_node_->GetNumLed("channel_1") + 1; auto future = CreateSetBoolSrvFuture(true, true); lights_driver_node_->ToggleLEDControlCB(std::move(future)); diff --git a/panther_manager/CONFIGURATION.md b/panther_manager/CONFIGURATION.md index 3317e43a2..6454c886a 100644 --- a/panther_manager/CONFIGURATION.md +++ b/panther_manager/CONFIGURATION.md @@ -5,7 +5,7 @@ For more information regarding shutdown behavior, refer to `ShutdownSingleHost` BT node in the [Actions](#actions) section. An example of a shutdown hosts YAML file can be found below. ``` yaml -# My shutdown_hosts_config.yaml +# My shutdown_hosts.yaml hosts: # Intel NUC, user computer - ip: 10.15.20.3 diff --git a/panther_manager/README.md b/panther_manager/README.md index f58327f03..718abece8 100644 --- a/panther_manager/README.md +++ b/panther_manager/README.md @@ -17,7 +17,7 @@ This package contains: - [`shutdown.xml`](./behavior_trees/shutdown.xml): BehaviorTree for initiating shutdown procedures. - [`lights_manager.yaml`](./config/lights_manager.yaml): Contains parameters for the `lights_manager` node. - [`safety_manager.yaml`](./config/safety_manager.yaml): Contains parameters for the `safety_manager` node. -- [`shutdown_hosts_config.yaml`](./config/shutdown_hosts_config.yaml): List with all hosts to request shutdown. +- [`shutdown_hosts.yaml`](./config/shutdown_hosts.yaml): List with all hosts to request shutdown. ## ROS Nodes diff --git a/panther_manager/config/shutdown_hosts_config.yaml b/panther_manager/config/shutdown_hosts.yaml similarity index 100% rename from panther_manager/config/shutdown_hosts_config.yaml rename to panther_manager/config/shutdown_hosts.yaml diff --git a/panther_manager/launch/manager.launch.py b/panther_manager/launch/manager.launch.py index 510fb2834..0aaf5385b 100644 --- a/panther_manager/launch/manager.launch.py +++ b/panther_manager/launch/manager.launch.py @@ -62,7 +62,7 @@ def generate_launch_description(): [ FindPackageShare("panther_manager"), "config", - "shutdown_hosts_config.yaml", + "shutdown_hosts.yaml", ] ), description="Path to file with list of hosts to request shutdown.",