Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Diagnostics] Add diagnostics of execution time and periodicity of the controllers and controller_manager #1871

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5627796
add MovingAverageStatistics to ControllerSpec
saikishor Sep 25, 2024
d7e9bbd
Use `ControllerUpdateStatus` object to return trigger_update status w…
saikishor Nov 6, 2024
1bcc7be
add stats of execution time and the periodicity of the controllers
saikishor Nov 6, 2024
1d8f32a
Add periodicity stats to the controller manager
saikishor Nov 6, 2024
c5c8776
update the diagnostics of the controller manager with periodicity inf…
saikishor Nov 6, 2024
6da2bb0
make execution time in the ControllerUpdateStatus optional for async …
saikishor Nov 7, 2024
e8b362d
adapt periodicity statistics for async controllers
saikishor Nov 7, 2024
71dbd03
Add controller statistics diagnostics
saikishor Nov 7, 2024
bb4a93c
use current trigger time from AsyncFunctionHandler to calculate the r…
saikishor Nov 8, 2024
986bbd0
Update the logic to use the period from ControllerUpdateStatus
saikishor Nov 8, 2024
46016ae
Only publish the diagnostics stats for the active controllers
saikishor Nov 8, 2024
1d4e4b3
fix CM periodicity stat
saikishor Nov 8, 2024
4759316
Fix the tests by initializing the pointers on construction
saikishor Nov 8, 2024
21796d2
Don't add the initial periodicity upon activation
saikishor Nov 9, 2024
cd56f82
set the first update period to zero and do not count for periodicity
saikishor Nov 9, 2024
b4ff424
pass current_time to the trigger_update method
saikishor Nov 9, 2024
f470129
Fix the test and add tests of the statistics
saikishor Nov 9, 2024
abdfe36
Add some reasonable checks about the execution time
saikishor Nov 9, 2024
bb1b975
Add more statistics tests
saikishor Nov 9, 2024
c161017
Publish periodicity only if it is an async controller
saikishor Nov 10, 2024
719d1f9
Add an initial way to retrieve threshold parameters from paramserver
saikishor Nov 10, 2024
9b1b95f
Don't use const reference as it is going to be changed in different t…
saikishor Nov 10, 2024
a570ca8
Update async test to check if the first period is set to zero or not
saikishor Nov 10, 2024
22da2b7
Update the tests to also check for the Min and Max of the periodicity
saikishor Nov 10, 2024
0c3fecd
Add tests to check for the async update with different rate with stats
saikishor Nov 10, 2024
7a62366
Add first version of the statistics information
saikishor Nov 10, 2024
24605bf
use the direct error and std dev instead of the percentage way
saikishor Nov 10, 2024
b5175a4
Change the parameter to mean_error
saikishor Nov 10, 2024
3d7e244
Apply the statistics to the controller manager periodicity
saikishor Nov 10, 2024
0f2af8d
Use from a variable instead of calling methods everytime
saikishor Nov 10, 2024
32d7475
add first version of the documentation
saikishor Nov 11, 2024
12efdef
Update documentation
saikishor Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ struct ControllerUpdateStats
unsigned int total_triggers;
unsigned int failed_triggers;
};

struct ControllerUpdateStatus
{
bool ok = true;
return_type result = return_type::OK;
std::optional<std::chrono::nanoseconds> execution_time = std::nullopt;
std::optional<rclcpp::Duration> period = std::nullopt;
};

/**
* Base interface class for an controller. The interface may not be used to implement a controller.
* The class provides definitions for `ControllerInterface` and `ChainableControllerInterface`
Expand Down Expand Up @@ -175,13 +184,11 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
*
* \param[in] time The time at the start of this control loop iteration
* \param[in] period The measured time taken by the last control loop iteration
* \returns A pair with the first element being a boolean indicating if the async callback method
* was triggered and the second element being the last return value of the async function. For
* more details check the AsyncFunctionHandler implementation in `realtime_tools` package.
* \returns ControllerUpdateStatus. The status contains information if the update was triggered
* successfully, the result of the update method and the execution duration of the update method.
*/
CONTROLLER_INTERFACE_PUBLIC
std::pair<bool, return_type> trigger_update(
const rclcpp::Time & time, const rclcpp::Duration & period);
ControllerUpdateStatus trigger_update(const rclcpp::Time & time, const rclcpp::Duration & period);

CONTROLLER_INTERFACE_PUBLIC
std::shared_ptr<rclcpp_lifecycle::LifecycleNode> get_node();
Expand Down
24 changes: 21 additions & 3 deletions controller_interface/src/controller_interface_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,14 @@ const rclcpp_lifecycle::State & ControllerInterfaceBase::get_lifecycle_state() c
return node_->get_current_state();
}

std::pair<bool, return_type> ControllerInterfaceBase::trigger_update(
ControllerUpdateStatus ControllerInterfaceBase::trigger_update(
const rclcpp::Time & time, const rclcpp::Duration & period)
{
ControllerUpdateStatus status;
trigger_stats_.total_triggers++;
if (is_async())
{
const rclcpp::Time last_trigger_time = async_handler_->get_current_callback_time();
const auto result = async_handler_->trigger_async_callback(time, period);
if (!result.first)
{
Expand All @@ -174,12 +176,28 @@ std::pair<bool, return_type> ControllerInterfaceBase::trigger_update(
"The controller missed %u update cycles out of %u total triggers.",
trigger_stats_.failed_triggers, trigger_stats_.total_triggers);
}
return result;
status.ok = result.first;
status.result = result.second;
const auto execution_time = async_handler_->get_last_execution_time();
if (execution_time.count() > 0)
{
status.execution_time = execution_time;
}
if (last_trigger_time.get_clock_type() != RCL_CLOCK_UNINITIALIZED)
{
status.period = time - last_trigger_time;
}
}
else
{
return std::make_pair(true, update(time, period));
const auto start_time = std::chrono::steady_clock::now();
status.ok = true;
status.result = update(time, period);
status.execution_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::steady_clock::now() - start_time);
status.period = period;
}
return status;
}

std::shared_ptr<rclcpp_lifecycle::LifecycleNode> ControllerInterfaceBase::get_node()
Expand Down
1 change: 1 addition & 0 deletions controller_manager/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ set(THIS_PACKAGE_INCLUDE_DEPENDS
rclcpp
realtime_tools
std_msgs
libstatistics_collector
)

find_package(ament_cmake REQUIRED)
Expand Down
53 changes: 53 additions & 0 deletions controller_manager/doc/userdoc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,59 @@ update_rate (mandatory; integer)
The fallback controllers activation is subject to the availability of the state and command interfaces at the time of activation.
It is recommended to test the fallback strategy in simulation before deploying it on the real robot.

diagnostics.threshold.controller_manager.periodicity.mean_error.warn
The warning threshold for the mean error of the controller manager's periodicity.
If the mean error exceeds this threshold, a warning diagnostic will be published.

diagnostics.threshold.controller_manager.periodicity.mean_error.error
The error threshold for the mean error of the controller manager's periodicity.
If the mean error exceeds this threshold, an error diagnostic will be published.

diagnostics.threshold.controller_manager.periodicity.standard_deviation.warn
The warning threshold for the standard deviation of the controller manager's periodicity.
If the standard deviation exceeds this threshold, a warning diagnostic will be published.

diagnostics.threshold.controller_manager.periodicity.standard_deviation.error
The error threshold for the standard deviation of the controller manager's periodicity.
If the standard deviation exceeds this threshold, an error diagnostic will be published.

diagnostics.threshold.controllers.periodicity.mean_error.warn
The warning threshold for the mean error of the controller update loop.
If the mean error exceeds this threshold, a warning diagnostic will be published.

diagnostics.threshold.controllers.periodicity.mean_error.error
The error threshold for the mean error of the controller update loop.
If the mean error exceeds this threshold, an error diagnostic will be published.

diagnostics.threshold.controllers.periodicity.standard_deviation.warn
The warning threshold for the standard deviation of the controller update loop.
If the standard deviation exceeds this threshold, a warning diagnostic will be published.

diagnostics.threshold.controllers.periodicity.standard_deviation.error
The error threshold for the standard deviation of the controller update loop.
If the standard deviation exceeds this threshold, an error diagnostic will be published.

diagnostics.threshold.controllers.execution_time.mean_error.warn
The warning threshold for the mean error of the controller execution time.
If the mean error exceeds this threshold, a warning diagnostic will be published.

diagnostics.threshold.controllers.execution_time.mean_error.error
The error threshold for the mean error of the controller execution time.
If the mean error exceeds this threshold, an error diagnostic will be published.

diagnostics.threshold.controllers.execution_time.standard_deviation.warn
The warning threshold for the standard deviation of the controller execution time.
If the standard deviation exceeds this threshold, a warning diagnostic will be published.

diagnostics.threshold.controllers.execution_time.standard_deviation.error
The error threshold for the standard deviation of the controller execution time.
If the standard deviation exceeds this threshold, an error diagnostic will be published.

.. note::
The ``periodicity`` diagnostics will be published only for the asynchronous controllers, because any affect to the synchronous controllers will be reflected directly in the controller manager's periodicity.

The ``execution_time`` diagnostics will be published for all controllers. The ``mean_error`` for a synchronous controller will be computed against zero, as it should be as low as possible. However, the ``mean_error`` for an asynchronous controller will be computed against the controller's desired update period, as the controller can take a maximum of the desired period cycle to execute it's update cycle.

Handling Multiple Controller Managers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ class ControllerManager : public rclcpp::Node
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr robot_description_subscription_;
rclcpp::TimerBase::SharedPtr robot_description_notification_timer_;

controller_manager::MovingAverageStatistics periodicity_stats_;

struct SwitchParams
{
void reset()
Expand Down
13 changes: 13 additions & 0 deletions controller_manager/include/controller_manager/controller_spec.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@
#include <vector>
#include "controller_interface/controller_interface_base.hpp"
#include "hardware_interface/controller_info.hpp"
#include "libstatistics_collector/moving_average_statistics/moving_average.hpp"

namespace controller_manager
{

using MovingAverageStatistics =
libstatistics_collector::moving_average_statistics::MovingAverageStatistics;
/// Controller Specification
/**
* This struct contains both a pointer to a given controller, \ref c, as well
Expand All @@ -35,9 +39,18 @@ namespace controller_manager
*/
struct ControllerSpec
{
ControllerSpec()
{
last_update_cycle_time = std::make_shared<rclcpp::Time>(0, 0, RCL_CLOCK_UNINITIALIZED);
execution_time_statistics = std::make_shared<MovingAverageStatistics>();
periodicity_statistics = std::make_shared<MovingAverageStatistics>();
}

hardware_interface::ControllerInfo info;
controller_interface::ControllerInterfaceBaseSharedPtr c;
std::shared_ptr<rclcpp::Time> last_update_cycle_time;
std::shared_ptr<MovingAverageStatistics> execution_time_statistics;
std::shared_ptr<MovingAverageStatistics> periodicity_statistics;
};

struct ControllerChainSpec
Expand Down
1 change: 1 addition & 0 deletions controller_manager/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<depend>ros2param</depend>
<depend>ros2run</depend>
<depend>std_msgs</depend>
<depend>libstatistics_collector</depend>

<test_depend>ament_cmake_gmock</test_depend>
<test_depend>ament_cmake_pytest</test_depend>
Expand Down
Loading
Loading