From 017795cd4a55aa2a32bce815a6a22a1dff40e82f Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Sat, 14 Mar 2026 18:34:08 +0100 Subject: [PATCH 1/4] broadcaster for magnetic field values from a magnetometer --- magnetometer_broadcaster/CMakeLists.txt | 58 +++++++ .../magnetometer_broadcaster.xml | 10 ++ magnetometer_broadcaster/package.xml | 41 +++++ .../src/magnetometer_broadcaster.cpp | 147 ++++++++++++++++++ .../magnetometer_broadcaster_parameters.yaml | 29 ++++ ros2_controllers/package.xml | 1 + 6 files changed, 286 insertions(+) create mode 100644 magnetometer_broadcaster/CMakeLists.txt create mode 100644 magnetometer_broadcaster/magnetometer_broadcaster.xml create mode 100644 magnetometer_broadcaster/package.xml create mode 100644 magnetometer_broadcaster/src/magnetometer_broadcaster.cpp create mode 100644 magnetometer_broadcaster/src/magnetometer_broadcaster_parameters.yaml diff --git a/magnetometer_broadcaster/CMakeLists.txt b/magnetometer_broadcaster/CMakeLists.txt new file mode 100644 index 0000000000..f75434d9e2 --- /dev/null +++ b/magnetometer_broadcaster/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.16) +project(magnetometer_broadcaster) + +find_package(ros2_control_cmake REQUIRED) +set_compiler_options() +export_windows_symbols() + +set(THIS_PACKAGE_INCLUDE_DEPENDS + controller_interface + generate_parameter_library + hardware_interface + pluginlib + rclcpp + rclcpp_lifecycle + realtime_tools + sensor_msgs +) + +find_package(ament_cmake REQUIRED) +find_package(backward_ros REQUIRED) +foreach(Dependency IN ITEMS ${THIS_PACKAGE_INCLUDE_DEPENDS}) + find_package(${Dependency} REQUIRED) +endforeach() + +generate_parameter_library(magnetometer_broadcaster_parameters + src/magnetometer_broadcaster_parameters.yaml +) + +add_library(magnetometer_broadcaster SHARED + src/magnetometer_broadcaster.cpp +) +target_compile_features(magnetometer_broadcaster PUBLIC cxx_std_20) +target_link_libraries(magnetometer_broadcaster PUBLIC + magnetometer_broadcaster_parameters + controller_interface::controller_interface + hardware_interface::hardware_interface + pluginlib::pluginlib + rclcpp::rclcpp + rclcpp_lifecycle::rclcpp_lifecycle + realtime_tools::realtime_tools + ${sensor_msgs_TARGETS}) + +pluginlib_export_plugin_description_file( + controller_interface magnetometer_broadcaster.xml) + +install( + TARGETS + magnetometer_broadcaster + magnetometer_broadcaster_parameters + EXPORT export_magnetometer_broadcaster + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib +) + +ament_export_targets(export_magnetometer_broadcaster HAS_LIBRARY_TARGET) +ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS}) +ament_package() diff --git a/magnetometer_broadcaster/magnetometer_broadcaster.xml b/magnetometer_broadcaster/magnetometer_broadcaster.xml new file mode 100644 index 0000000000..0e2214e395 --- /dev/null +++ b/magnetometer_broadcaster/magnetometer_broadcaster.xml @@ -0,0 +1,10 @@ + + + + This controller publishes the readings of a magnetometer as sensor_msgs/msg/MagneticField message. + + + diff --git a/magnetometer_broadcaster/package.xml b/magnetometer_broadcaster/package.xml new file mode 100644 index 0000000000..ba77d36be3 --- /dev/null +++ b/magnetometer_broadcaster/package.xml @@ -0,0 +1,41 @@ + + + + magnetometer_broadcaster + 6.4.0 + Controller to publish readings of a magnetometer. + + Bence Magyar + Denis Štogl + Christoph Froehlich + Sai Kishor Kothakota + + Apache License 2.0 + + https://control.ros.org + https://github.com/ros-controls/ros2_controllers/issues + https://github.com/ros-controls/ros2_controllers/ + + Christian Rauch + + ament_cmake + + ros2_control_cmake + + backward_ros + controller_interface + eigen + generate_parameter_library + hardware_interface + pluginlib + rclcpp + rclcpp_lifecycle + realtime_tools + sensor_msgs + + + ament_cmake + + diff --git a/magnetometer_broadcaster/src/magnetometer_broadcaster.cpp b/magnetometer_broadcaster/src/magnetometer_broadcaster.cpp new file mode 100644 index 0000000000..ec27082cc7 --- /dev/null +++ b/magnetometer_broadcaster/src/magnetometer_broadcaster.cpp @@ -0,0 +1,147 @@ +// Copyright 2026 Christian Rauch +// Copyright 2021 PAL Robotics SL. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* + * Authors: Christian Rauch, Subhas Das, Denis Stogl, Victor Lopez + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace magnetometer_broadcaster +{ + +class MagnetometerBroadcaster : public controller_interface::ControllerInterface +{ +public: + controller_interface::InterfaceConfiguration command_interface_configuration() const override + { + return {.type = controller_interface::interface_configuration_type::NONE}; + } + + controller_interface::InterfaceConfiguration state_interface_configuration() const override + { + return { + .type = controller_interface::interface_configuration_type::INDIVIDUAL, + .names = magnetometer_->get_state_interface_names(), + }; + } + + controller_interface::CallbackReturn on_init() override + { + try + { + param_listener_ = std::make_shared(get_node()); + } + catch (const std::exception & e) + { + RCLCPP_ERROR_STREAM( + get_node()->get_logger(), "Exception thrown during init stage with message: " << e.what()); + return CallbackReturn::ERROR; + } + + return CallbackReturn::SUCCESS; + } + + controller_interface::CallbackReturn on_configure( + const rclcpp_lifecycle::State & /*previous_state*/) override + { + try + { + params_ = param_listener_->get_params(); + } + catch (const std::exception & e) + { + RCLCPP_ERROR_STREAM( + get_node()->get_logger(), + "Exception thrown during config stage with message: " << e.what()); + return CallbackReturn::ERROR; + } + + magnetometer_ = std::make_unique(params_.sensor_name); + try + { + sensor_state_publisher_ = get_node()->create_publisher( + "~/magnetic_field", rclcpp::SystemDefaultsQoS()); + realtime_publisher_ = std::make_unique(sensor_state_publisher_); + } + catch (const std::exception & e) + { + RCLCPP_ERROR_STREAM( + get_node()->get_logger(), + "Exception thrown during publisher creation at configure stage with message: " << e.what()); + return CallbackReturn::ERROR; + } + + state_message_.header.frame_id = params_.frame_id; + std::copy( + params_.static_covariance.begin(), params_.static_covariance.end(), + state_message_.magnetic_field_covariance.begin()); + + return CallbackReturn::SUCCESS; + } + + controller_interface::CallbackReturn on_activate( + const rclcpp_lifecycle::State & /*previous_state*/) override + { + magnetometer_->assign_loaned_state_interfaces(state_interfaces_); + return CallbackReturn::SUCCESS; + } + + controller_interface::CallbackReturn on_deactivate( + const rclcpp_lifecycle::State & /*previous_state*/) override + { + magnetometer_->release_interfaces(); + return CallbackReturn::SUCCESS; + } + + controller_interface::return_type update( + const rclcpp::Time & time, const rclcpp::Duration & /*period*/) override + { + magnetometer_->get_values_as_message(state_message_); + + if (realtime_publisher_) + { + state_message_.header.stamp = time; + realtime_publisher_->try_publish(state_message_); + } + + return controller_interface::return_type::OK; + } + +protected: + std::shared_ptr param_listener_; + Params params_; + + std::unique_ptr magnetometer_; + + using StatePublisher = realtime_tools::RealtimePublisher; + rclcpp::Publisher::SharedPtr sensor_state_publisher_; + std::unique_ptr realtime_publisher_; + sensor_msgs::msg::MagneticField state_message_; +}; + +} // namespace magnetometer_broadcaster + +PLUGINLIB_EXPORT_CLASS( + magnetometer_broadcaster::MagnetometerBroadcaster, controller_interface::ControllerInterface) diff --git a/magnetometer_broadcaster/src/magnetometer_broadcaster_parameters.yaml b/magnetometer_broadcaster/src/magnetometer_broadcaster_parameters.yaml new file mode 100644 index 0000000000..d52e3c1dc9 --- /dev/null +++ b/magnetometer_broadcaster/src/magnetometer_broadcaster_parameters.yaml @@ -0,0 +1,29 @@ +magnetometer_broadcaster: + sensor_name: { + type: string, + default_value: "", + read_only: true, + description: "Defines sensor name used as prefix for its interfaces. + Interface names are: ``/magnetic_field.x, /magnetic_field.x, /magnetic_field.z.``", + validation: { + not_empty<>: null + } + } + frame_id: { + type: string, + default_value: "", + read_only: true, + description: "Sensor's frame_id in which values are published.", + validation: { + not_empty<>: null + } + } + static_covariance: { + type: double_array, + default_value: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + read_only: true, + description: "Static covariance. Row major about x, y, z axes", + validation: { + fixed_size<>: [9], + } + } diff --git a/ros2_controllers/package.xml b/ros2_controllers/package.xml index ca21a5b27e..a1c0a06d30 100644 --- a/ros2_controllers/package.xml +++ b/ros2_controllers/package.xml @@ -30,6 +30,7 @@ imu_sensor_broadcaster joint_state_broadcaster joint_trajectory_controller + magnetometer_broadcaster mecanum_drive_controller motion_primitives_controllers omni_wheel_drive_controller From 414ff43846dc0745dd712d7a9fab4f40741f186e Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Mon, 16 Mar 2026 23:51:03 +0100 Subject: [PATCH 2/4] add tests for magnetometer_broadcaster/MagnetometerBroadcaster --- magnetometer_broadcaster/CMakeLists.txt | 27 +++ magnetometer_broadcaster/package.xml | 4 + .../test/magnetometer_broadcaster_params.yaml | 4 + .../test_load_magnetometer_broadcaster.cpp | 46 ++++ .../test/test_magnetometer_broadcaster.cpp | 204 ++++++++++++++++++ 5 files changed, 285 insertions(+) create mode 100644 magnetometer_broadcaster/test/magnetometer_broadcaster_params.yaml create mode 100644 magnetometer_broadcaster/test/test_load_magnetometer_broadcaster.cpp create mode 100644 magnetometer_broadcaster/test/test_magnetometer_broadcaster.cpp diff --git a/magnetometer_broadcaster/CMakeLists.txt b/magnetometer_broadcaster/CMakeLists.txt index f75434d9e2..8266a487f8 100644 --- a/magnetometer_broadcaster/CMakeLists.txt +++ b/magnetometer_broadcaster/CMakeLists.txt @@ -43,6 +43,33 @@ target_link_libraries(magnetometer_broadcaster PUBLIC pluginlib_export_plugin_description_file( controller_interface magnetometer_broadcaster.xml) +if(BUILD_TESTING) + find_package(ament_cmake_gmock REQUIRED) + find_package(controller_manager REQUIRED) + find_package(hardware_interface REQUIRED) + find_package(ros2_control_test_assets REQUIRED) + + add_definitions(-DTEST_FILES_DIRECTORY="${CMAKE_CURRENT_SOURCE_DIR}/test") + ament_add_gmock(test_load_magnetometer_broadcaster + test/test_load_magnetometer_broadcaster.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/magnetometer_broadcaster_params.yaml) + target_include_directories(test_load_magnetometer_broadcaster PRIVATE include) + target_link_libraries(test_load_magnetometer_broadcaster + magnetometer_broadcaster + controller_manager::controller_manager + ros2_control_test_assets::ros2_control_test_assets + ) + + ament_add_gmock(test_magnetometer_broadcaster + test/test_magnetometer_broadcaster.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/magnetometer_broadcaster_params.yaml) + target_link_libraries(test_magnetometer_broadcaster + magnetometer_broadcaster + ros2_control_test_assets::ros2_control_test_assets + magnetometer_broadcaster + ) +endif() + install( TARGETS magnetometer_broadcaster diff --git a/magnetometer_broadcaster/package.xml b/magnetometer_broadcaster/package.xml index ba77d36be3..469d492e5b 100644 --- a/magnetometer_broadcaster/package.xml +++ b/magnetometer_broadcaster/package.xml @@ -35,6 +35,10 @@ realtime_tools sensor_msgs + ament_cmake_gmock + controller_manager + ros2_control_test_assets + ament_cmake diff --git a/magnetometer_broadcaster/test/magnetometer_broadcaster_params.yaml b/magnetometer_broadcaster/test/magnetometer_broadcaster_params.yaml new file mode 100644 index 0000000000..6efe0a9b5c --- /dev/null +++ b/magnetometer_broadcaster/test/magnetometer_broadcaster_params.yaml @@ -0,0 +1,4 @@ +test_magnetometer_broadcaster: + ros__parameters: + sensor_name: magnetometer + frame_id: magnetometer_frame diff --git a/magnetometer_broadcaster/test/test_load_magnetometer_broadcaster.cpp b/magnetometer_broadcaster/test/test_load_magnetometer_broadcaster.cpp new file mode 100644 index 0000000000..087c39d7f5 --- /dev/null +++ b/magnetometer_broadcaster/test/test_load_magnetometer_broadcaster.cpp @@ -0,0 +1,46 @@ +// Copyright 2026 ros2_control development team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* + * Authors: Christian Rauch, Wiktor Bajor, Jakub Delicat + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +TEST(TestLoadMagnetometerBroadcaster, load_controller) +{ + rclcpp::init(0, nullptr); + std::shared_ptr executor = + std::make_shared(); + + controller_manager::ControllerManager cm( + executor, ros2_control_test_assets::minimal_robot_urdf, true, "test_controller_manager"); + const std::string test_file_path = + std::string(TEST_FILES_DIRECTORY) + "/magnetometer_broadcaster_params.yaml"; + + cm.set_parameter({"test_magnetometer_broadcaster.params_file", test_file_path}); + cm.set_parameter( + {"test_magnetometer_broadcaster.type", "magnetometer_broadcaster/MagnetometerBroadcaster"}); + + ASSERT_NE(cm.load_controller("test_magnetometer_broadcaster"), nullptr); + rclcpp::shutdown(); +} diff --git a/magnetometer_broadcaster/test/test_magnetometer_broadcaster.cpp b/magnetometer_broadcaster/test/test_magnetometer_broadcaster.cpp new file mode 100644 index 0000000000..61782ddf56 --- /dev/null +++ b/magnetometer_broadcaster/test/test_magnetometer_broadcaster.cpp @@ -0,0 +1,204 @@ +// Copyright 2026 ros2_control development team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/* + * Authors: Christian Rauch, Wiktor Bajor, Jakub Delicat + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using callback_return_type = + rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn; + +namespace +{ +rclcpp::WaitResultKind wait_for(std::shared_ptr subscription) +{ + rclcpp::WaitSet wait_set; + wait_set.add_subscription(subscription); + return wait_set.wait().kind(); +} + +rclcpp::NodeOptions create_node_options_with_overriden_parameters( + std::vector parameters) +{ + auto node_options = rclcpp::NodeOptions(); + node_options.parameter_overrides(parameters); + return node_options; +} +} // namespace + +class MagnetometerBroadcasterTest : public ::testing::Test +{ +public: + MagnetometerBroadcasterTest() { rclcpp::init(0, nullptr); } + + ~MagnetometerBroadcasterTest() { rclcpp::shutdown(); } + + void SetUp() + { + broadcaster = loader->createInstance( + "magnetometer_broadcaster::MagnetometerBroadcaster"); + } + + void TearDown() { broadcaster.reset(); } + + void setup_broadcaster() + { + std::vector state_ifs; + state_ifs.emplace_back(magnetic_field_x, nullptr); + state_ifs.emplace_back(magnetic_field_y, nullptr); + state_ifs.emplace_back(magnetic_field_z, nullptr); + + broadcaster->assign_interfaces({}, std::move(state_ifs)); + } + + sensor_msgs::msg::MagneticField subscribe_and_get_message() + { + rclcpp::Node test_subscription_node("test_subscription_node"); + auto subscription = test_subscription_node.create_subscription( + "/test_magnetometer_broadcaster/magnetic_field", 10, + [](const sensor_msgs::msg::MagneticField::SharedPtr) {}); + broadcaster->update(rclcpp::Time{}, rclcpp::Duration::from_seconds(0)); + wait_for(subscription); + + rclcpp::MessageInfo msg_info; + sensor_msgs::msg::MagneticField msg; + subscription->take(msg, msg_info); + return msg; + } + + controller_interface::ControllerInterfaceParams create_ctrl_params( + const rclcpp::NodeOptions & node_options, const std::string & robot_description = "") + { + controller_interface::ControllerInterfaceParams params; + params.controller_name = "test_magnetometer_broadcaster"; + params.robot_description = robot_description; + params.update_rate = 0; + params.node_namespace = ""; + params.node_options = node_options; + return params; + } + +protected: + const std::string sensor_name_ = "magnetometer"; + const rclcpp::Parameter sensor_name_param_ = rclcpp::Parameter("sensor_name", sensor_name_); + const std::string frame_id_ = "magnetometer_frame"; + const rclcpp::Parameter frame_id_param_ = rclcpp::Parameter("frame_id", frame_id_); + + std::array sensor_values_ = {{20e-6, 30e-6, 40e-6}}; + hardware_interface::StateInterface::SharedPtr magnetic_field_x = + std::make_shared( + sensor_name_, "magnetic_field.x", &sensor_values_[0]); + hardware_interface::StateInterface::SharedPtr magnetic_field_y = + std::make_shared( + sensor_name_, "magnetic_field.y", &sensor_values_[1]); + hardware_interface::StateInterface::SharedPtr magnetic_field_z = + std::make_shared( + sensor_name_, "magnetic_field.z", &sensor_values_[2]); + + std::unique_ptr loader = + std::make_unique(std::string{}); + + controller_interface::ControllerInterfaceSharedPtr broadcaster = nullptr; +}; + +TEST_F(MagnetometerBroadcasterTest, whenNoParamsAreSetThenInitShouldFail) +{ + const auto result = broadcaster->init(create_ctrl_params( + broadcaster->define_custom_node_options(), ros2_control_test_assets::minimal_robot_urdf)); + ASSERT_EQ(result, controller_interface::return_type::ERROR); +} + +TEST_F(MagnetometerBroadcasterTest, whenOnlySensorNameIsSetThenInitShouldFail) +{ + const auto node_options = create_node_options_with_overriden_parameters({sensor_name_param_}); + const auto result = broadcaster->init( + create_ctrl_params(node_options, ros2_control_test_assets::minimal_robot_urdf)); + ASSERT_EQ(result, controller_interface::return_type::ERROR); +} + +TEST_F( + MagnetometerBroadcasterTest, + whenAllRequiredArgumentsAreSetThenInitConfigureAndActivationShouldSucceed) +{ + const auto node_options = + create_node_options_with_overriden_parameters({sensor_name_param_, frame_id_param_}); + const auto result = broadcaster->init( + create_ctrl_params(node_options, ros2_control_test_assets::minimal_robot_urdf)); + ASSERT_EQ(result, controller_interface::return_type::OK); + ASSERT_EQ(broadcaster->on_configure(rclcpp_lifecycle::State()), callback_return_type::SUCCESS); + ASSERT_EQ(broadcaster->on_activate(rclcpp_lifecycle::State()), callback_return_type::SUCCESS); +} + +TEST_F(MagnetometerBroadcasterTest, whenBroadcasterIsActiveShouldPublishWithCovarianceSetToZero) +{ + const auto node_options = + create_node_options_with_overriden_parameters({sensor_name_param_, frame_id_param_}); + const auto result = broadcaster->init( + create_ctrl_params(node_options, ros2_control_test_assets::minimal_robot_urdf)); + ASSERT_EQ(result, controller_interface::return_type::OK); + ASSERT_EQ(broadcaster->on_configure(rclcpp_lifecycle::State()), callback_return_type::SUCCESS); + setup_broadcaster(); + ASSERT_EQ(broadcaster->on_activate(rclcpp_lifecycle::State()), callback_return_type::SUCCESS); + + const auto msg = subscribe_and_get_message(); + EXPECT_EQ(msg.header.frame_id, frame_id_); + EXPECT_EQ(msg.magnetic_field.x, sensor_values_[0]); + EXPECT_EQ(msg.magnetic_field.y, sensor_values_[1]); + EXPECT_EQ(msg.magnetic_field.z, sensor_values_[2]); + + const std::array expected_covariance = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; + ASSERT_THAT(msg.magnetic_field_covariance, ::testing::ElementsAreArray(expected_covariance)); +} + +TEST_F( + MagnetometerBroadcasterTest, + whenBroadcasterIsActiveAndStaticCovarianceShouldPublishWithStaticCovariance) +{ + const std::array static_covariance = {{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}}; + const auto node_options = create_node_options_with_overriden_parameters( + {sensor_name_param_, + frame_id_param_, + {"static_covariance", + std::vector{static_covariance.begin(), static_covariance.end()}}}); + const auto result = broadcaster->init( + create_ctrl_params(node_options, ros2_control_test_assets::minimal_robot_urdf)); + ASSERT_EQ(result, controller_interface::return_type::OK); + ASSERT_EQ(broadcaster->on_configure(rclcpp_lifecycle::State()), callback_return_type::SUCCESS); + setup_broadcaster(); + ASSERT_EQ(broadcaster->on_activate(rclcpp_lifecycle::State()), callback_return_type::SUCCESS); + + const auto msg = subscribe_and_get_message(); + EXPECT_EQ(msg.header.frame_id, frame_id_); + EXPECT_EQ(msg.magnetic_field.x, sensor_values_[0]); + EXPECT_EQ(msg.magnetic_field.y, sensor_values_[1]); + EXPECT_EQ(msg.magnetic_field.z, sensor_values_[2]); + + ASSERT_THAT(msg.magnetic_field_covariance, ::testing::ElementsAreArray(static_covariance)); +} From f65e964951f36d34a74294af7b00950d67e50430 Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Mon, 30 Mar 2026 23:10:46 +0200 Subject: [PATCH 3/4] add documentation for Magnetometer Broadcaster --- doc/controllers_index.rst | 1 + magnetometer_broadcaster/doc/userdoc.rst | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 magnetometer_broadcaster/doc/userdoc.rst diff --git a/doc/controllers_index.rst b/doc/controllers_index.rst index b8e9f8a8ca..1a68bd9ec2 100644 --- a/doc/controllers_index.rst +++ b/doc/controllers_index.rst @@ -66,6 +66,7 @@ In the sense of ros2_control, broadcasters are still controllers using the same Pose Broadcaster <../pose_broadcaster/doc/userdoc.rst> GPS Sensor Broadcaster <../gps_sensor_broadcaster/doc/userdoc.rst> State Interfaces Broadcaster <../state_interfaces_broadcaster/doc/userdoc.rst> + Magnetometer Broadcaster <../magnetometer_broadcaster/doc/userdoc.rst> Filters ********************** diff --git a/magnetometer_broadcaster/doc/userdoc.rst b/magnetometer_broadcaster/doc/userdoc.rst new file mode 100644 index 0000000000..7568d7b0bd --- /dev/null +++ b/magnetometer_broadcaster/doc/userdoc.rst @@ -0,0 +1,24 @@ +:github_url: https://github.com/ros-controls/ros2_controllers/blob/{REPOS_FILE_BRANCH}/magnetometer_broadcaster/doc/userdoc.rst + +.. _magnetometer_broadcaster_userdoc: + +Magnetometer Broadcaster +-------------------------------- +Broadcaster for magnetometer messages (type: ``sensor_msgs/msg/MagneticField``), using the ``semantic_components::MagneticFieldSensor``. + +Parameters +^^^^^^^^^^^ +This controller uses the `generate_parameter_library `_ to handle its parameters. The parameter `definition file located in the src folder `_ contains descriptions for all the parameters used by the controller. + +List of parameters +========================= +.. generate_parameter_library_details:: ../src/magnetometer_broadcaster_parameters.yaml + + +An example parameter file +========================= + +An example parameter file for this controller can be found in `the test directory `_: + +.. literalinclude:: ../test/magnetometer_broadcaster_params.yaml + :language: yaml From 847321317045832bc1988291a144bf43e3084cd6 Mon Sep 17 00:00:00 2001 From: Christian Rauch Date: Mon, 30 Mar 2026 23:16:19 +0200 Subject: [PATCH 4/4] add new package magnetometer_broadcaster to change log --- doc/release_notes.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 6cbbbe06c6..a38ca858b6 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -54,3 +54,7 @@ steering_controllers_library ***************************** * Parameter ``tf_frame_prefix`` added with the similar functionality to other controllers. (`#2080 `_). * Set odometry service added to be used at runtime. (`#2244 `_). + +magnetometer_broadcaster +************************ +New package to broadcast ``sensor_msgs/msg/MagneticField`` from state interfaces defined by the ``semantic_components::MagneticFieldSensor``.