Skip to content

Commit 30625b6

Browse files
Merge branch 'master' into use/new_api/hardware_components
2 parents bb4039c + 25be71d commit 30625b6

File tree

127 files changed

+1963
-761
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+1963
-761
lines changed

.github/workflows/stale.yml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: 'Stale issues and PRs'
2+
on:
3+
workflow_dispatch:
4+
schedule:
5+
# UTC noon every workday
6+
- cron: '0 12 * * MON-FRI'
7+
8+
jobs:
9+
stale:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
issues: write
13+
pull-requests: write
14+
steps:
15+
- uses: actions/stale@v9
16+
with:
17+
stale-issue-label: 'stale'
18+
stale-pr-label: 'stale'
19+
stale-issue-message: 'This issue is being labeled as stale because it has been open 45 days with no activity. It will be automatically closed after another 45 days without follow-ups.'
20+
close-issue-message: 'This issue was closed because it has been stalled for 45 days with no activity.'
21+
stale-pr-message: 'This PR is stale because it has been open for 45 days with no activity. Please tag a maintainer for help on completing this PR, or close it if you think it has become obsolete.'
22+
days-before-stale: 45
23+
days-before-close: 45
24+
days-before-pr-close: -1
25+
exempt-all-milestones: true
26+
exempt-issue-labels: good first issue,good second issue,persistent,release,roadmap,Epic
27+
operations-per-run: 100

.pre-commit-config.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ repos:
5656
args: ["--line-length=99"]
5757

5858
- repo: https://github.com/pycqa/flake8
59-
rev: 7.1.2
59+
rev: 7.2.0
6060
hooks:
6161
- id: flake8
6262
args: ["--extend-ignore=E501"]
6363

6464
# CPP hooks
6565
- repo: https://github.com/pre-commit/mirrors-clang-format
66-
rev: v19.1.7
66+
rev: v20.1.0
6767
hooks:
6868
- id: clang-format
6969
args: ['-fallback-style=none', '-i']
@@ -133,7 +133,7 @@ repos:
133133
exclude: CHANGELOG\.rst|\.(svg|pyc|drawio)$
134134

135135
- repo: https://github.com/python-jsonschema/check-jsonschema
136-
rev: 0.31.2
136+
rev: 0.32.1
137137
hooks:
138138
- id: check-github-workflows
139139
args: ["--verbose"]

MIGRATION.md

-12
This file was deleted.

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ros2_control
22

3-
[![Licence](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
3+
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
44
[![codecov](https://codecov.io/gh/ros-controls/ros2_control/graph/badge.svg?token=idvm1zJXOf)](https://codecov.io/gh/ros-controls/ros2_control)
55

66
This package is a part of the ros2_control framework.

controller_interface/CMakeLists.txt

+3-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
cmake_minimum_required(VERSION 3.16)
22
project(controller_interface LANGUAGES CXX)
33

4-
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
5-
add_compile_options(-Wall -Wextra -Werror=conversion -Werror=unused-but-set-variable -Werror=return-type -Werror=shadow
6-
-Werror=missing-braces)
7-
endif()
8-
9-
# using this instead of visibility macros
10-
# S1 from https://github.com/ros-controls/ros2_controllers/issues/1053
11-
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
4+
find_package(ros2_control_cmake REQUIRED)
5+
set_compiler_options()
6+
export_windows_symbols()
127

138
set(THIS_PACKAGE_INCLUDE_DEPENDS
149
hardware_interface

controller_interface/include/controller_interface/controller_interface_base.hpp

+20
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,19 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
306306
*/
307307
void wait_for_trigger_update_to_finish();
308308

309+
/**
310+
* Method to prepare the controller for deactivation. This method is called by the controller
311+
* manager before deactivating the controller. The method is used to prepare the controller for
312+
* deactivation, e.g., to stop triggering the update cycles further. This method is especially
313+
* needed for controllers running in async mode and different frequency than the control manager.
314+
*
315+
* \note **The method is not real-time safe and shouldn't be called in the RT control loop.**
316+
*
317+
* If the controller is running in async mode, the method will stop the async update cycles. If
318+
* the controller is not running in async mode, the method will do nothing.
319+
*/
320+
void prepare_for_deactivation();
321+
309322
std::string get_name() const;
310323

311324
/// Enable or disable introspection of the controller.
@@ -319,11 +332,18 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
319332
std::vector<hardware_interface::LoanedStateInterface> state_interfaces_;
320333

321334
private:
335+
/**
336+
* Method to stop the async handler thread. This method is called before the controller cleanup,
337+
* error and shutdown lifecycle transitions.
338+
*/
339+
void stop_async_handler_thread();
340+
322341
std::shared_ptr<rclcpp_lifecycle::LifecycleNode> node_;
323342
std::unique_ptr<realtime_tools::AsyncFunctionHandler<return_type>> async_handler_;
324343
unsigned int update_rate_ = 0;
325344
bool is_async_ = false;
326345
std::string urdf_ = "";
346+
std::atomic_bool skip_async_triggers_ = false;
327347
ControllerUpdateStats trigger_stats_;
328348

329349
protected:

controller_interface/include/semantic_components/led_rgb_device.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ class LedRgbDevice : public SemanticComponentCommandInterface<std_msgs::msg::Col
6565
return false;
6666
}
6767
bool all_set = true;
68-
all_set &= command_interfaces_[0].get().set_value(message.r);
69-
all_set &= command_interfaces_[1].get().set_value(message.g);
70-
all_set &= command_interfaces_[2].get().set_value(message.b);
68+
all_set &= command_interfaces_[0].get().set_value(static_cast<double>(message.r));
69+
all_set &= command_interfaces_[1].get().set_value(static_cast<double>(message.g));
70+
all_set &= command_interfaces_[2].get().set_value(static_cast<double>(message.b));
7171
return all_set;
7272
}
7373
};

controller_interface/package.xml

+5-2
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33
<package format="2">
44
<name>controller_interface</name>
55
<version>4.27.0</version>
6-
<description>Description of controller_interface</description>
6+
<description>Base classes for controllers and syntax cookies for supporting common sensor types in controllers and broadcasters</description>
77
<maintainer email="[email protected]">Bence Magyar</maintainer>
88
<maintainer email="[email protected]">Denis Štogl</maintainer>
9+
<maintainer email="[email protected]">Christoph Froehlich</maintainer>
10+
<maintainer email="[email protected]">Sai Kishor Kothakota</maintainer>
911
<license>Apache License 2.0</license>
1012

1113
<buildtool_depend>ament_cmake</buildtool_depend>
1214
<buildtool_depend>ament_cmake_gen_version_h</buildtool_depend>
1315

1416
<build_depend>hardware_interface</build_depend>
15-
<build_depend>realtime_tools</build_depend>
1617
<build_depend>rclcpp_lifecycle</build_depend>
18+
<build_depend>realtime_tools</build_depend>
19+
<build_depend>ros2_control_cmake</build_depend>
1720
<build_depend>sensor_msgs</build_depend>
1821

1922
<build_export_depend>hardware_interface</build_export_depend>

controller_interface/src/chainable_controller_interface.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,9 @@ ChainableControllerInterface::on_export_reference_interfaces()
247247
std::vector<hardware_interface::CommandInterface> reference_interfaces;
248248
for (size_t i = 0; i < exported_reference_interface_names_.size(); ++i)
249249
{
250-
reference_interfaces.emplace_back(hardware_interface::CommandInterface(
251-
get_node()->get_name(), exported_reference_interface_names_[i], &reference_interfaces_[i]));
250+
reference_interfaces.emplace_back(
251+
hardware_interface::CommandInterface(
252+
get_node()->get_name(), exported_reference_interface_names_[i], &reference_interfaces_[i]));
252253
}
253254
return reference_interfaces;
254255
}

controller_interface/src/controller_interface_base.cpp

+37-6
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,14 @@ return_type ControllerInterfaceBase::init(
8686
// make sure introspection is disabled on controller cleanup as users may manually enable
8787
// it in `on_configure` and `on_deactivate` - see the docs for details
8888
enable_introspection(false);
89-
if (is_async() && async_handler_ && async_handler_->is_running())
90-
{
91-
async_handler_->stop_thread();
92-
}
89+
this->stop_async_handler_thread();
9390
return on_cleanup(previous_state);
9491
});
9592

9693
node_->register_on_activate(
9794
[this](const rclcpp_lifecycle::State & previous_state) -> CallbackReturn
9895
{
96+
skip_async_triggers_.store(false);
9997
enable_introspection(true);
10098
if (is_async() && async_handler_ && async_handler_->is_running())
10199
{
@@ -113,10 +111,22 @@ return_type ControllerInterfaceBase::init(
113111
});
114112

115113
node_->register_on_shutdown(
116-
std::bind(&ControllerInterfaceBase::on_shutdown, this, std::placeholders::_1));
114+
[this](const rclcpp_lifecycle::State & previous_state) -> CallbackReturn
115+
{
116+
this->stop_async_handler_thread();
117+
auto transition_state_status = on_shutdown(previous_state);
118+
this->release_interfaces();
119+
return transition_state_status;
120+
});
117121

118122
node_->register_on_error(
119-
std::bind(&ControllerInterfaceBase::on_error, this, std::placeholders::_1));
123+
[this](const rclcpp_lifecycle::State & previous_state) -> CallbackReturn
124+
{
125+
this->stop_async_handler_thread();
126+
auto transition_state_status = on_error(previous_state);
127+
this->release_interfaces();
128+
return transition_state_status;
129+
});
120130

121131
return return_type::OK;
122132
}
@@ -204,6 +214,13 @@ ControllerUpdateStatus ControllerInterfaceBase::trigger_update(
204214
trigger_stats_.total_triggers++;
205215
if (is_async())
206216
{
217+
if (skip_async_triggers_.load())
218+
{
219+
// Skip further async triggers if the controller is being deactivated
220+
status.successful = false;
221+
status.result = return_type::OK;
222+
return status;
223+
}
207224
const rclcpp::Time last_trigger_time = async_handler_->get_current_callback_time();
208225
const auto result = async_handler_->trigger_async_callback(time, period);
209226
if (!result.first)
@@ -270,6 +287,20 @@ void ControllerInterfaceBase::wait_for_trigger_update_to_finish()
270287
}
271288
}
272289

290+
void ControllerInterfaceBase::prepare_for_deactivation()
291+
{
292+
skip_async_triggers_.store(true);
293+
this->wait_for_trigger_update_to_finish();
294+
}
295+
296+
void ControllerInterfaceBase::stop_async_handler_thread()
297+
{
298+
if (is_async() && async_handler_ && async_handler_->is_running())
299+
{
300+
async_handler_->stop_thread();
301+
}
302+
}
303+
273304
std::string ControllerInterfaceBase::get_name() const { return get_node()->get_name(); }
274305

275306
void ControllerInterfaceBase::enable_introspection(bool enable)

controller_interface/test/test_chainable_controller_interface.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414

1515
#include "test_chainable_controller_interface.hpp"
1616

17-
#include <gmock/gmock.h>
1817
#include <memory>
1918

19+
#include "gmock/gmock.h"
20+
2021
using ::testing::IsEmpty;
2122
using ::testing::SizeIs;
2223

controller_interface/test/test_chainable_controller_interface.hpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@
1515
#ifndef TEST_CHAINABLE_CONTROLLER_INTERFACE_HPP_
1616
#define TEST_CHAINABLE_CONTROLLER_INTERFACE_HPP_
1717

18-
#include <gmock/gmock.h>
19-
2018
#include <string>
2119
#include <vector>
2220

2321
#include "controller_interface/chainable_controller_interface.hpp"
22+
#include "gmock/gmock.h"
2423
#include "hardware_interface/handle.hpp"
2524

2625
constexpr char TEST_CONTROLLER_NAME[] = "testable_chainable_controller";
@@ -71,8 +70,9 @@ class TestableChainableControllerInterface
7170
{
7271
std::vector<hardware_interface::StateInterface> state_interfaces;
7372

74-
state_interfaces.push_back(hardware_interface::StateInterface(
75-
name_prefix_of_interfaces_, "test_state", &state_interfaces_values_[0]));
73+
state_interfaces.push_back(
74+
hardware_interface::StateInterface(
75+
name_prefix_of_interfaces_, "test_state", &state_interfaces_values_[0]));
7676

7777
return state_interfaces;
7878
}
@@ -82,8 +82,9 @@ class TestableChainableControllerInterface
8282
{
8383
std::vector<hardware_interface::CommandInterface> command_interfaces;
8484

85-
command_interfaces.push_back(hardware_interface::CommandInterface(
86-
name_prefix_of_interfaces_, "test_itf", &reference_interfaces_[0]));
85+
command_interfaces.push_back(
86+
hardware_interface::CommandInterface(
87+
name_prefix_of_interfaces_, "test_itf", &reference_interfaces_[0]));
8788

8889
return command_interfaces;
8990
}

controller_interface/test/test_controller_interface.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414

1515
#include "test_controller_interface.hpp"
1616

17-
#include <gmock/gmock.h>
1817
#include <memory>
1918
#include <string>
2019
#include <vector>
2120

21+
#include "gmock/gmock.h"
2222
#include "lifecycle_msgs/msg/state.hpp"
2323
#include "rclcpp/executor_options.hpp"
2424
#include "rclcpp/executors/multi_threaded_executor.hpp"

controller_interface/test/test_controller_with_options.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414

1515
#include "test_controller_with_options.hpp"
1616

17-
#include <gtest/gtest.h>
1817
#include <string>
1918

19+
#include "gmock/gmock.h"
20+
2021
class FriendControllerWithOptions : public controller_with_options::ControllerWithOptions
2122
{
2223
FRIEND_TEST(ControllerWithOption, init_with_overrides);

controller_interface/test/test_force_torque_sensor.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ TEST_F(ForceTorqueSensorTest, validate_all_with_default_names)
3939
ASSERT_EQ(force_torque_sensor_->state_interfaces_.capacity(), size_);
4040

4141
// validate the default interface_names_
42-
ASSERT_TRUE(std::equal(
43-
force_torque_sensor_->interface_names_.begin(), force_torque_sensor_->interface_names_.end(),
44-
full_interface_names_.begin(), full_interface_names_.end()));
42+
ASSERT_TRUE(
43+
std::equal(
44+
force_torque_sensor_->interface_names_.begin(), force_torque_sensor_->interface_names_.end(),
45+
full_interface_names_.begin(), full_interface_names_.end()));
4546

4647
// get the interface names
4748
std::vector<std::string> interface_names = force_torque_sensor_->get_state_interface_names();

controller_interface/test/test_force_torque_sensor.hpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,11 @@
1919
#ifndef TEST_FORCE_TORQUE_SENSOR_HPP_
2020
#define TEST_FORCE_TORQUE_SENSOR_HPP_
2121

22-
#include <gmock/gmock.h>
23-
2422
#include <memory>
2523
#include <string>
2624
#include <vector>
2725

26+
#include "gmock/gmock.h"
2827
#include "semantic_components/force_torque_sensor.hpp"
2928

3029
// implementing and friending so we can access member variables

controller_interface/test/test_gps_sensor.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#include <gmock/gmock.h>
16-
#include <gtest/gtest.h>
1715
#include <algorithm>
1816
#include <array>
1917
#include <string>
2018
#include <vector>
19+
20+
#include "gmock/gmock.h"
2121
#include "hardware_interface/handle.hpp"
2222
#include "hardware_interface/loaned_state_interface.hpp"
2323
#include "semantic_components/gps_sensor.hpp"

controller_interface/test/test_imu_sensor.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ TEST_F(IMUSensorTest, validate_all)
3838
ASSERT_EQ(imu_sensor_->state_interfaces_.capacity(), size_);
3939

4040
// validate the default interface_names_
41-
ASSERT_TRUE(std::equal(
42-
imu_sensor_->interface_names_.begin(), imu_sensor_->interface_names_.end(),
43-
full_interface_names_.begin(), full_interface_names_.end()));
41+
ASSERT_TRUE(
42+
std::equal(
43+
imu_sensor_->interface_names_.begin(), imu_sensor_->interface_names_.end(),
44+
full_interface_names_.begin(), full_interface_names_.end()));
4445

4546
// get the interface names
4647
std::vector<std::string> interface_names = imu_sensor_->get_state_interface_names();

0 commit comments

Comments
 (0)