Skip to content

Commit 33bfe46

Browse files
authored
[Joint State Broadcaster] Add option to publish joint states to local topics (ros-controls#218)
* Use local topics for publishing joint states * Parameterize local namespace topics. * Unify test structure. * Use get_node() instead of node_ everywhere. * Add missing return in init method. * Update userdoc.rst
1 parent d34800c commit 33bfe46

File tree

5 files changed

+76
-16
lines changed

5 files changed

+76
-16
lines changed

joint_state_broadcaster/doc/userdoc.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@ All available *joint state interfaces* are used by this broadcaster.
1818
Parameters
1919
----------
2020

21-
extra_joints (optional; string array; default: empty)
22-
Names of extra joints to be added to ``/joint_states`` and ``/dynamic_joint_states`` with state set to 0.
21+
``use_local_topics``
22+
Optional parameter (boolean; default: ``False``) defining if ``joint_states`` and ``dynamic_joint_states`` messages should be published into local namespace, e.g., ``/my_state_broadcaster/joint_states``.
23+
24+
``extra_joints``
25+
Optional parameter (string array) with names of extra joints to be added to ``joint_states`` and ``dynamic_joint_states`` with state set to 0.

joint_state_broadcaster/include/joint_state_broadcaster/joint_state_broadcaster.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ class JointStateBroadcaster : public controller_interface::ControllerInterface
3636
JOINT_STATE_BROADCASTER_PUBLIC
3737
JointStateBroadcaster();
3838

39+
JOINT_STATE_BROADCASTER_PUBLIC
40+
controller_interface::return_type
41+
init(const std::string & controller_name) override;
42+
3943
JOINT_STATE_BROADCASTER_PUBLIC
4044
controller_interface::InterfaceConfiguration command_interface_configuration() const override;
4145

@@ -64,6 +68,8 @@ class JointStateBroadcaster : public controller_interface::ControllerInterface
6468
void init_dynamic_joint_state_msg();
6569

6670
protected:
71+
bool use_local_topics_;
72+
6773
// For the JointState message,
6874
// we store the name of joints with compatible interfaces
6975
std::vector<std::string> joint_names_;

joint_state_broadcaster/src/joint_state_broadcaster.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@ using hardware_interface::HW_IF_EFFORT;
4848
JointStateBroadcaster::JointStateBroadcaster()
4949
{}
5050

51+
controller_interface::return_type
52+
JointStateBroadcaster::init(const std::string & controller_name)
53+
{
54+
auto ret = ControllerInterface::init(controller_name);
55+
if (ret != controller_interface::return_type::OK) {
56+
return ret;
57+
}
58+
59+
try {
60+
get_node()->declare_parameter<bool>("use_local_topics", false);
61+
} catch (const std::exception & e) {
62+
fprintf(stderr, "Exception thrown during init stage with message: %s \n", e.what());
63+
return controller_interface::return_type::ERROR;
64+
}
65+
66+
return controller_interface::return_type::OK;
67+
}
68+
5169
controller_interface::InterfaceConfiguration
5270
JointStateBroadcaster::command_interface_configuration() const
5371
{
@@ -65,13 +83,17 @@ const
6583
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
6684
JointStateBroadcaster::on_configure(const rclcpp_lifecycle::State & /*previous_state*/)
6785
{
86+
use_local_topics_ = get_node()->get_parameter("use_local_topics").as_bool();
87+
6888
try {
89+
const std::string topic_name_prefix = use_local_topics_ ? "~/" : "";
90+
6991
joint_state_publisher_ = get_node()->create_publisher<sensor_msgs::msg::JointState>(
70-
"joint_states", rclcpp::SystemDefaultsQoS());
92+
topic_name_prefix + "joint_states", rclcpp::SystemDefaultsQoS());
7193

7294
dynamic_joint_state_publisher_ =
7395
get_node()->create_publisher<control_msgs::msg::DynamicJointState>(
74-
"dynamic_joint_states", rclcpp::SystemDefaultsQoS());
96+
topic_name_prefix + "dynamic_joint_states", rclcpp::SystemDefaultsQoS());
7597
} catch (const std::exception & e) {
7698
// get_node() may throw, logging raw here
7799
fprintf(stderr, "Exception thrown during init stage with message: %s \n", e.what());
@@ -209,8 +231,8 @@ JointStateBroadcaster::update()
209231
state_interface.get_value());
210232
}
211233

212-
joint_state_msg_.header.stamp = node_->get_clock()->now();
213-
dynamic_joint_state_msg_.header.stamp = node_->get_clock()->now();
234+
joint_state_msg_.header.stamp = get_node()->get_clock()->now();
235+
dynamic_joint_state_msg_.header.stamp = get_node()->get_clock()->now();
214236

215237
// update joint state message and dynamic joint state message
216238
for (auto i = 0ul; i < joint_names_.size(); ++i) {

joint_state_broadcaster/test/test_joint_state_broadcaster.cpp

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ TEST_F(JointStateBroadcasterTest, ConfigureErrorTest)
115115
ASSERT_FALSE(state_broadcaster_->dynamic_joint_state_publisher_);
116116

117117
// configure failed
118-
ASSERT_EQ(state_broadcaster_->on_configure(rclcpp_lifecycle::State()), NODE_ERROR);
118+
ASSERT_THROW(state_broadcaster_->on_configure(rclcpp_lifecycle::State()), std::exception);
119119

120120
SetUpStateBroadcaster();
121121
// check state remains unchanged
@@ -198,10 +198,8 @@ TEST_F(JointStateBroadcasterTest, UpdateTest)
198198
ASSERT_EQ(state_broadcaster_->update(), controller_interface::return_type::OK);
199199
}
200200

201-
TEST_F(JointStateBroadcasterTest, JointStatePublishTest)
201+
void JointStateBroadcasterTest::test_published_joint_state_message(const std::string & topic)
202202
{
203-
SetUpStateBroadcaster();
204-
205203
auto node_state = state_broadcaster_->configure();
206204
ASSERT_EQ(node_state.id(), lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE);
207205

@@ -213,7 +211,7 @@ TEST_F(JointStateBroadcasterTest, JointStatePublishTest)
213211
{
214212
};
215213
auto subscription = test_node.create_subscription<sensor_msgs::msg::JointState>(
216-
"joint_states",
214+
topic,
217215
10,
218216
subs_callback);
219217

@@ -238,10 +236,24 @@ TEST_F(JointStateBroadcasterTest, JointStatePublishTest)
238236
ASSERT_THAT(joint_state_msg.effort, ElementsAreArray(joint_state_msg.position));
239237
}
240238

241-
TEST_F(JointStateBroadcasterTest, DynamicJointStatePublishTest)
239+
TEST_F(JointStateBroadcasterTest, JointStatePublishTest)
240+
{
241+
SetUpStateBroadcaster();
242+
243+
test_published_joint_state_message("joint_states");
244+
}
245+
246+
TEST_F(JointStateBroadcasterTest, JointStatePublishTestLocalTopic)
242247
{
243248
SetUpStateBroadcaster();
249+
state_broadcaster_->get_node()->set_parameter({"use_local_topics", true});
250+
251+
test_published_joint_state_message("joint_state_broadcaster/joint_states");
252+
}
244253

254+
void
255+
JointStateBroadcasterTest::test_published_dynamic_joint_state_message(const std::string & topic)
256+
{
245257
auto node_state = state_broadcaster_->configure();
246258
ASSERT_EQ(node_state.id(), lifecycle_msgs::msg::State::PRIMARY_STATE_INACTIVE);
247259

@@ -253,7 +265,7 @@ TEST_F(JointStateBroadcasterTest, DynamicJointStatePublishTest)
253265
{
254266
};
255267
auto subscription = test_node.create_subscription<control_msgs::msg::DynamicJointState>(
256-
"dynamic_joint_states",
268+
topic,
257269
10,
258270
subs_callback);
259271

@@ -290,6 +302,21 @@ TEST_F(JointStateBroadcasterTest, DynamicJointStatePublishTest)
290302
}
291303
}
292304

305+
TEST_F(JointStateBroadcasterTest, DynamicJointStatePublishTest)
306+
{
307+
SetUpStateBroadcaster();
308+
309+
test_published_dynamic_joint_state_message("dynamic_joint_states");
310+
}
311+
312+
TEST_F(JointStateBroadcasterTest, DynamicJointStatePublishTestLocalTopic)
313+
{
314+
SetUpStateBroadcaster();
315+
state_broadcaster_->get_node()->set_parameter({"use_local_topics", true});
316+
317+
test_published_dynamic_joint_state_message("joint_state_broadcaster/dynamic_joint_states");
318+
}
319+
293320
TEST_F(JointStateBroadcasterTest, ExtraJointStatePublishTest)
294321
{
295322
// joint state not initialized yet
@@ -309,10 +336,8 @@ TEST_F(JointStateBroadcasterTest, ExtraJointStatePublishTest)
309336
SetUpStateBroadcaster();
310337

311338
// Add extra joints as parameters
312-
auto broadcaster_node = state_broadcaster_->get_node();
313339
const std::vector<std::string> extra_joint_names = {"extra1", "extra2", "extra3"};
314-
const rclcpp::Parameter extra_joints_parameters("extra_joints", extra_joint_names);
315-
broadcaster_node->set_parameter(extra_joints_parameters);
340+
state_broadcaster_->get_node()->set_parameter({"extra_joints", extra_joint_names});
316341

317342
// configure ok
318343
ASSERT_EQ(state_broadcaster_->on_configure(rclcpp_lifecycle::State()), NODE_SUCCESS);

joint_state_broadcaster/test/test_joint_state_broadcaster.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class JointStateBroadcasterTest : public ::testing::Test
4242

4343
void SetUpStateBroadcaster();
4444

45+
void test_published_joint_state_message(const std::string & topic);
46+
47+
void test_published_dynamic_joint_state_message(const std::string & topic);
48+
4549
protected:
4650
// dummy joint state values used for tests
4751
const std::vector<std::string> joint_names_ = {"joint1", "joint2", "joint3"};

0 commit comments

Comments
 (0)