Skip to content

Commit d398ea7

Browse files
authored
Merge branch 'master' into integrate/pal_statistics
2 parents 5f91488 + b329679 commit d398ea7

26 files changed

+2958
-196
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ repos:
3737

3838
# Python hooks
3939
- repo: https://github.com/asottile/pyupgrade
40-
rev: v3.19.0
40+
rev: v3.19.1
4141
hooks:
4242
- id: pyupgrade
4343
args: [--py36-plus]
@@ -63,7 +63,7 @@ repos:
6363

6464
# CPP hooks
6565
- repo: https://github.com/pre-commit/mirrors-clang-format
66-
rev: v19.1.4
66+
rev: v19.1.5
6767
hooks:
6868
- id: clang-format
6969
args: ['-fallback-style=none', '-i']

controller_interface/include/controller_interface/controller_interface_base.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class ControllerInterfaceBase : public rclcpp_lifecycle::node_interfaces::Lifecy
100100
public:
101101
ControllerInterfaceBase() = default;
102102

103-
virtual ~ControllerInterfaceBase() = default;
103+
virtual ~ControllerInterfaceBase();
104104

105105
/// Get configuration for controller's required command interfaces.
106106
/**

controller_interface/src/controller_interface_base.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@
2323

2424
namespace controller_interface
2525
{
26+
ControllerInterfaceBase::~ControllerInterfaceBase()
27+
{
28+
// check if node is initialized and we still have a valid context
29+
if (
30+
node_.get() &&
31+
get_lifecycle_state().id() != lifecycle_msgs::msg::State::PRIMARY_STATE_FINALIZED &&
32+
rclcpp::ok())
33+
{
34+
RCLCPP_DEBUG(
35+
get_node()->get_logger(),
36+
"Calling shutdown transition of controller node '%s' due to destruction.",
37+
get_node()->get_name());
38+
node_->shutdown();
39+
}
40+
}
41+
2642
return_type ControllerInterfaceBase::init(
2743
const std::string & controller_name, const std::string & urdf, unsigned int cm_update_rate,
2844
const std::string & node_namespace, const rclcpp::NodeOptions & node_options)
@@ -53,6 +69,11 @@ return_type ControllerInterfaceBase::init(
5369
break;
5470
case LifecycleNodeInterface::CallbackReturn::ERROR:
5571
case LifecycleNodeInterface::CallbackReturn::FAILURE:
72+
RCLCPP_DEBUG(
73+
get_node()->get_logger(),
74+
"Calling shutdown transition of controller node '%s' due to init failure.",
75+
get_node()->get_name());
76+
node_->shutdown();
5677
return return_type::ERROR;
5778
}
5879

@@ -169,6 +190,10 @@ void ControllerInterfaceBase::release_interfaces()
169190

170191
const rclcpp_lifecycle::State & ControllerInterfaceBase::get_lifecycle_state() const
171192
{
193+
if (!node_.get())
194+
{
195+
throw std::runtime_error("Lifecycle node hasn't been initialized yet!");
196+
}
172197
return node_->get_current_state();
173198
}
174199

controller_interface/test/test_controller_interface.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,21 @@ TEST(TestableControllerInterface, init)
3636
rclcpp::init(argc, argv);
3737

3838
TestableControllerInterface controller;
39+
const TestableControllerInterface & const_controller = controller;
3940

4041
// try to get node when not initialized
4142
ASSERT_THROW(controller.get_node(), std::runtime_error);
43+
ASSERT_THROW(const_controller.get_node(), std::runtime_error);
44+
ASSERT_THROW(controller.get_lifecycle_state(), std::runtime_error);
4245

4346
// initialize, create node
4447
const auto node_options = controller.define_custom_node_options();
4548
ASSERT_EQ(
4649
controller.init(TEST_CONTROLLER_NAME, "", 10.0, "", node_options),
4750
controller_interface::return_type::OK);
4851
ASSERT_NO_THROW(controller.get_node());
52+
ASSERT_NO_THROW(const_controller.get_node());
53+
ASSERT_NO_THROW(controller.get_lifecycle_state());
4954

5055
// update_rate is set to controller_manager's rate
5156
ASSERT_EQ(controller.get_update_rate(), 10u);
@@ -54,6 +59,7 @@ TEST(TestableControllerInterface, init)
5459
controller.configure();
5560
ASSERT_EQ(controller.get_update_rate(), 10u);
5661

62+
controller.get_node()->shutdown();
5763
rclcpp::shutdown();
5864
}
5965

@@ -80,6 +86,8 @@ TEST(TestableControllerInterface, setting_negative_update_rate_in_configure)
8086
// The configure should fail and the update rate should stay the same
8187
ASSERT_EQ(controller.configure().id(), lifecycle_msgs::msg::State::PRIMARY_STATE_UNCONFIGURED);
8288
ASSERT_EQ(controller.get_update_rate(), 1000u);
89+
90+
controller.get_node()->shutdown();
8391
rclcpp::shutdown();
8492
}
8593

@@ -149,6 +157,7 @@ TEST(TestableControllerInterface, setting_update_rate_in_configure)
149157
ASSERT_EQ(controller.get_update_rate(), 623u);
150158

151159
executor->cancel();
160+
controller.get_node()->shutdown();
152161
rclcpp::shutdown();
153162
}
154163

@@ -166,6 +175,8 @@ TEST(TestableControllerInterfaceInitError, init_with_error)
166175
controller.init(TEST_CONTROLLER_NAME, "", 100.0, "", node_options),
167176
controller_interface::return_type::ERROR);
168177

178+
ASSERT_EQ(
179+
controller.get_lifecycle_state().id(), lifecycle_msgs::msg::State::PRIMARY_STATE_FINALIZED);
169180
rclcpp::shutdown();
170181
}
171182

@@ -183,6 +194,8 @@ TEST(TestableControllerInterfaceInitFailure, init_with_failure)
183194
controller.init(TEST_CONTROLLER_NAME, "", 50.0, "", node_options),
184195
controller_interface::return_type::ERROR);
185196

197+
ASSERT_EQ(
198+
controller.get_lifecycle_state().id(), lifecycle_msgs::msg::State::PRIMARY_STATE_FINALIZED);
186199
rclcpp::shutdown();
187200
}
188201

controller_interface/test/test_controller_with_options.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ TEST(ControllerWithOption, init_with_overrides)
4141
rclcpp::init(argc, argv);
4242
// creates the controller
4343
FriendControllerWithOptions controller;
44-
EXPECT_EQ(
44+
ASSERT_EQ(
4545
controller.init("controller_name", "", 50.0, "", controller.define_custom_node_options()),
4646
controller_interface::return_type::OK);
4747
// checks that the node options have been updated
@@ -54,6 +54,8 @@ TEST(ControllerWithOption, init_with_overrides)
5454
EXPECT_EQ(controller.params["parameter1"], 1.);
5555
EXPECT_EQ(controller.params["parameter2"], 2.);
5656
EXPECT_EQ(controller.params["parameter3"], 3.);
57+
58+
controller.get_node()->shutdown();
5759
rclcpp::shutdown();
5860
}
5961

@@ -68,7 +70,7 @@ TEST(ControllerWithOption, init_with_node_options_arguments_parameters)
6870
controller_node_options.arguments(
6971
{"--ros-args", "-p", "parameter_list.parameter1:=1.", "-p", "parameter_list.parameter2:=2.",
7072
"-p", "parameter_list.parameter3:=3."});
71-
EXPECT_EQ(
73+
ASSERT_EQ(
7274
controller.init("controller_name", "", 50.0, "", controller_node_options),
7375
controller_interface::return_type::OK);
7476
// checks that the node options have been updated
@@ -81,6 +83,8 @@ TEST(ControllerWithOption, init_with_node_options_arguments_parameters)
8183
EXPECT_EQ(controller.params["parameter1"], 1.);
8284
EXPECT_EQ(controller.params["parameter2"], 2.);
8385
EXPECT_EQ(controller.params["parameter3"], 3.);
86+
87+
controller.get_node()->shutdown();
8488
rclcpp::shutdown();
8589
}
8690

@@ -96,7 +100,7 @@ TEST(ControllerWithOption, init_with_node_options_arguments_parameters_file)
96100
std::cerr << params_file_path << std::endl;
97101
auto controller_node_options = controller.define_custom_node_options();
98102
controller_node_options.arguments({"--ros-args", "--params-file", params_file_path});
99-
EXPECT_EQ(
103+
ASSERT_EQ(
100104
controller.init("controller_name", "", 50.0, "", controller_node_options),
101105
controller_interface::return_type::OK);
102106
// checks that the node options have been updated
@@ -112,6 +116,8 @@ TEST(ControllerWithOption, init_with_node_options_arguments_parameters_file)
112116
bool use_sim_time(true);
113117
controller.get_node()->get_parameter_or("use_sim_time", use_sim_time, false);
114118
ASSERT_FALSE(use_sim_time);
119+
120+
controller.get_node()->shutdown();
115121
rclcpp::shutdown();
116122
}
117123

@@ -130,7 +136,7 @@ TEST(
130136
controller_node_options.arguments(
131137
{"--ros-args", "--params-file", params_file_path, "-p", "parameter_list.parameter1:=562.785",
132138
"-p", "use_sim_time:=true"});
133-
EXPECT_EQ(
139+
ASSERT_EQ(
134140
controller.init("controller_name", "", 50.0, "", controller_node_options),
135141
controller_interface::return_type::OK);
136142
// checks that the node options have been updated
@@ -146,6 +152,8 @@ TEST(
146152
bool use_sim_time(false);
147153
controller.get_node()->get_parameter_or("use_sim_time", use_sim_time, false);
148154
ASSERT_TRUE(use_sim_time);
155+
156+
controller.get_node()->shutdown();
149157
rclcpp::shutdown();
150158
}
151159

@@ -157,7 +165,7 @@ TEST(ControllerWithOption, init_without_overrides)
157165
rclcpp::init(argc, argv);
158166
// creates the controller
159167
FriendControllerWithOptions controller;
160-
EXPECT_EQ(
168+
ASSERT_EQ(
161169
controller.init("controller_name", "", 50.0, "", controller.define_custom_node_options()),
162170
controller_interface::return_type::ERROR);
163171
// checks that the node options have been updated
@@ -166,5 +174,6 @@ TEST(ControllerWithOption, init_without_overrides)
166174
EXPECT_TRUE(node_options.automatically_declare_parameters_from_overrides());
167175
// checks that no parameter has been declared from overrides
168176
EXPECT_EQ(controller.params.size(), 0u);
177+
169178
rclcpp::shutdown();
170179
}

controller_manager/src/controller_manager.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,8 @@ ControllerManager::ControllerManager(
256256
chainable_loader_(
257257
std::make_shared<pluginlib::ClassLoader<controller_interface::ChainableControllerInterface>>(
258258
kControllerInterfaceNamespace, kChainableControllerInterfaceClassName)),
259-
cm_node_options_(options)
259+
cm_node_options_(options),
260+
robot_description_(urdf)
260261
{
261262
initialize_parameters();
262263
resource_manager_ = std::make_unique<hardware_interface::ResourceManager>(

hardware_interface/doc/writing_new_hardware_component.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@ The following is a step-by-step guide to create source files, basic tests, and c
2222
After creating the package, you should have at least ``CMakeLists.txt`` and ``package.xml`` files in it.
2323
Create also ``include/<PACKAGE_NAME>/`` and ``src`` folders if they do not already exist.
2424
In ``include/<PACKAGE_NAME>/`` folder add ``<robot_hardware_interface_name>.hpp`` and ``<robot_hardware_interface_name>.cpp`` in the ``src`` folder.
25-
Optionally add ``visibility_control.h`` with the definition of export rules for Windows.
26-
You can copy this file from an existing controller package and change the name prefix to the ``<PACKAGE_NAME>``.
2725

2826
#. **Adding declarations into header file (.hpp)**
2927

3028
1. Take care that you use header guards. ROS2-style is using ``#ifndef`` and ``#define`` preprocessor directives. (For more information on this, a search engine is your friend :) ).
3129

32-
2. Include ``"hardware_interface/$interface_type$_interface.hpp"`` and ``visibility_control.h`` if you are using one.
30+
2. Include ``"hardware_interface/$interface_type$_interface.hpp"``.
3331
``$interface_type$`` can be ``Actuator``, ``Sensor`` or ``System`` depending on the type of hardware you are using. for more details about each type check :ref:`Hardware Components description <overview_hardware_components>`.
3432

3533
3. Define a unique namespace for your hardware_interface. This is usually the package name written in ``snake_case``.

hardware_interface/src/component_parser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@
2020
#include <unordered_map>
2121
#include <vector>
2222

23+
#include "rclcpp/version.h"
24+
#if RCLCPP_VERSION_GTE(29, 0, 0)
25+
#include "urdf/model.hpp"
26+
#else
2327
#include "urdf/model.h"
28+
#endif
2429

2530
#include "hardware_interface/component_parser.hpp"
2631
#include "hardware_interface/hardware_info.hpp"

joint_limits/CMakeLists.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,28 @@ target_include_directories(joint_limiter_interface PUBLIC
4444
)
4545
ament_target_dependencies(joint_limiter_interface PUBLIC ${THIS_PACKAGE_INCLUDE_DEPENDS})
4646

47+
add_library(joint_limits_helpers SHARED
48+
src/joint_limits_helpers.cpp
49+
)
50+
target_compile_features(joint_limits_helpers PUBLIC cxx_std_17)
51+
target_include_directories(joint_limits_helpers PUBLIC
52+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
53+
$<INSTALL_INTERFACE:include/joint_limits>
54+
)
55+
ament_target_dependencies(joint_limits_helpers PUBLIC ${THIS_PACKAGE_INCLUDE_DEPENDS})
56+
4757
add_library(joint_saturation_limiter SHARED
4858
src/joint_saturation_limiter.cpp
59+
src/joint_range_limiter.cpp
60+
src/joint_soft_limiter.cpp
4961
)
5062
target_compile_features(joint_saturation_limiter PUBLIC cxx_std_17)
5163
target_include_directories(joint_saturation_limiter PUBLIC
5264
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
5365
$<INSTALL_INTERFACE:include/joint_limits>
5466
)
67+
target_link_libraries(joint_saturation_limiter PUBLIC joint_limits_helpers)
68+
5569
ament_target_dependencies(joint_saturation_limiter PUBLIC ${THIS_PACKAGE_INCLUDE_DEPENDS})
5670

5771
pluginlib_export_plugin_description_file(joint_limits joint_limiters.xml)
@@ -91,6 +105,24 @@ if(BUILD_TESTING)
91105
rclcpp
92106
)
93107

108+
ament_add_gmock(test_joint_range_limiter test/test_joint_range_limiter.cpp)
109+
target_include_directories(test_joint_range_limiter PRIVATE include)
110+
target_link_libraries(test_joint_range_limiter joint_limiter_interface)
111+
ament_target_dependencies(
112+
test_joint_range_limiter
113+
pluginlib
114+
rclcpp
115+
)
116+
117+
ament_add_gmock(test_joint_soft_limiter test/test_joint_soft_limiter.cpp)
118+
target_include_directories(test_joint_soft_limiter PRIVATE include)
119+
target_link_libraries(test_joint_soft_limiter joint_limiter_interface)
120+
ament_target_dependencies(
121+
test_joint_soft_limiter
122+
pluginlib
123+
rclcpp
124+
)
125+
94126
endif()
95127

96128
install(
@@ -101,6 +133,7 @@ install(TARGETS
101133
joint_limits
102134
joint_limiter_interface
103135
joint_saturation_limiter
136+
joint_limits_helpers
104137
EXPORT export_joint_limits
105138
ARCHIVE DESTINATION lib
106139
LIBRARY DESTINATION lib
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2024 PAL Robotics S.L.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/// \author Sai Kishor Kothakota
16+
17+
#ifndef JOINT_LIMITS__DATA_STRUCTURES_HPP_
18+
#define JOINT_LIMITS__DATA_STRUCTURES_HPP_
19+
20+
#include <memory>
21+
#include <optional>
22+
#include <string>
23+
24+
namespace joint_limits
25+
{
26+
27+
struct JointControlInterfacesData
28+
{
29+
std::string joint_name;
30+
std::optional<double> position = std::nullopt;
31+
std::optional<double> velocity = std::nullopt;
32+
std::optional<double> effort = std::nullopt;
33+
std::optional<double> acceleration = std::nullopt;
34+
std::optional<double> jerk = std::nullopt;
35+
36+
bool has_data() const
37+
{
38+
return has_position() || has_velocity() || has_effort() || has_acceleration() || has_jerk();
39+
}
40+
41+
bool has_position() const { return position.has_value(); }
42+
43+
bool has_velocity() const { return velocity.has_value(); }
44+
45+
bool has_effort() const { return effort.has_value(); }
46+
47+
bool has_acceleration() const { return acceleration.has_value(); }
48+
49+
bool has_jerk() const { return jerk.has_value(); }
50+
};
51+
52+
struct JointInterfacesCommandLimiterData
53+
{
54+
std::string joint_name;
55+
JointControlInterfacesData actual;
56+
JointControlInterfacesData command;
57+
JointControlInterfacesData prev_command;
58+
JointControlInterfacesData limited;
59+
60+
bool has_actual_data() const { return actual.has_data(); }
61+
62+
bool has_command_data() const { return command.has_data(); }
63+
};
64+
65+
} // namespace joint_limits
66+
#endif // JOINT_LIMITS__DATA_STRUCTURES_HPP_

0 commit comments

Comments
 (0)