|
28 | 28 | #include "lifecycle_msgs/msg/state.hpp" |
29 | 29 | #include "rclcpp/logging.hpp" |
30 | 30 | #include "tf2/LinearMath/Quaternion.hpp" |
| 31 | +#include "tf2/impl/utils.hpp" |
31 | 32 |
|
32 | 33 | namespace |
33 | 34 | { |
34 | 35 | constexpr auto DEFAULT_COMMAND_TOPIC = "~/cmd_vel"; |
35 | 36 | constexpr auto DEFAULT_COMMAND_OUT_TOPIC = "~/cmd_vel_out"; |
36 | 37 | constexpr auto DEFAULT_ODOMETRY_TOPIC = "~/odom"; |
37 | 38 | constexpr auto DEFAULT_TRANSFORM_TOPIC = "/tf"; |
| 39 | +constexpr auto DEFAULT_SET_ODOM_SERVICE = "~/set_odometry"; |
38 | 40 | } // namespace |
39 | 41 |
|
40 | 42 | namespace diff_drive_controller |
@@ -161,56 +163,73 @@ controller_interface::return_type DiffDriveController::update_and_write_commands |
161 | 163 | const double left_wheel_radius = params_.left_wheel_radius_multiplier * params_.wheel_radius; |
162 | 164 | const double right_wheel_radius = params_.right_wheel_radius_multiplier * params_.wheel_radius; |
163 | 165 |
|
164 | | - // Update odometry |
165 | 166 | bool odometry_updated = false; |
166 | | - if (params_.open_loop) |
| 167 | + |
| 168 | + // check if odometry set or reset was requested by non-RT thread |
| 169 | + if (set_odom_requested_.load()) |
167 | 170 | { |
168 | | - odometry_updated = |
169 | | - odometry_.try_update_open_loop(linear_command, angular_command, period.seconds()); |
| 171 | + auto param_op = requested_odom_params_.try_get(); |
| 172 | + if (param_op.has_value()) |
| 173 | + { |
| 174 | + auto params = param_op.value(); |
| 175 | + odometry_.setOdometry(params.x, params.y, params.yaw); |
| 176 | + odometry_updated = true; |
| 177 | + set_odom_requested_.store(false); |
| 178 | + } |
170 | 179 | } |
171 | 180 | else |
172 | 181 | { |
173 | | - double left_feedback_mean = 0.0; |
174 | | - double right_feedback_mean = 0.0; |
175 | | - for (size_t index = 0; index < static_cast<size_t>(wheels_per_side_); ++index) |
| 182 | + // Update odometry |
| 183 | + if (params_.open_loop) |
176 | 184 | { |
177 | | - const auto left_feedback_op = |
178 | | - registered_left_wheel_handles_[index].feedback.value().get().get_optional(); |
179 | | - const auto right_feedback_op = |
180 | | - registered_right_wheel_handles_[index].feedback.value().get().get_optional(); |
181 | | - |
182 | | - if (!left_feedback_op.has_value() || !right_feedback_op.has_value()) |
| 185 | + odometry_updated = |
| 186 | + odometry_.try_update_open_loop(linear_command, angular_command, period.seconds()); |
| 187 | + } |
| 188 | + else |
| 189 | + { |
| 190 | + double left_feedback_mean = 0.0; |
| 191 | + double right_feedback_mean = 0.0; |
| 192 | + for (size_t index = 0; index < static_cast<size_t>(wheels_per_side_); ++index) |
183 | 193 | { |
184 | | - RCLCPP_DEBUG(logger, "Unable to retrieve the data from the left or right wheels feedback!"); |
185 | | - return controller_interface::return_type::OK; |
186 | | - } |
| 194 | + const auto left_feedback_op = |
| 195 | + registered_left_wheel_handles_[index].feedback.value().get().get_optional(); |
| 196 | + const auto right_feedback_op = |
| 197 | + registered_right_wheel_handles_[index].feedback.value().get().get_optional(); |
187 | 198 |
|
188 | | - const double left_feedback = left_feedback_op.value(); |
189 | | - const double right_feedback = right_feedback_op.value(); |
| 199 | + if (!left_feedback_op.has_value() || !right_feedback_op.has_value()) |
| 200 | + { |
| 201 | + RCLCPP_DEBUG( |
| 202 | + logger, "Unable to retrieve the data from the left or right wheels feedback!"); |
| 203 | + return controller_interface::return_type::OK; |
| 204 | + } |
190 | 205 |
|
191 | | - if (std::isnan(left_feedback) || std::isnan(right_feedback)) |
192 | | - { |
193 | | - RCLCPP_ERROR( |
194 | | - logger, "Either the left or right wheel %s is invalid for index [%zu]", feedback_type(), |
195 | | - index); |
196 | | - return controller_interface::return_type::ERROR; |
197 | | - } |
| 206 | + const double left_feedback = left_feedback_op.value(); |
| 207 | + const double right_feedback = right_feedback_op.value(); |
198 | 208 |
|
199 | | - left_feedback_mean += left_feedback; |
200 | | - right_feedback_mean += right_feedback; |
201 | | - } |
202 | | - left_feedback_mean /= static_cast<double>(wheels_per_side_); |
203 | | - right_feedback_mean /= static_cast<double>(wheels_per_side_); |
| 209 | + if (std::isnan(left_feedback) || std::isnan(right_feedback)) |
| 210 | + { |
| 211 | + RCLCPP_ERROR( |
| 212 | + logger, "Either the left or right wheel %s is invalid for index [%zu]", feedback_type(), |
| 213 | + index); |
| 214 | + return controller_interface::return_type::ERROR; |
| 215 | + } |
| 216 | + |
| 217 | + left_feedback_mean += left_feedback; |
| 218 | + right_feedback_mean += right_feedback; |
| 219 | + } |
| 220 | + left_feedback_mean /= static_cast<double>(wheels_per_side_); |
| 221 | + right_feedback_mean /= static_cast<double>(wheels_per_side_); |
204 | 222 |
|
205 | | - if (params_.position_feedback) |
206 | | - { |
207 | | - odometry_updated = |
208 | | - odometry_.update_from_pos(left_feedback_mean, right_feedback_mean, period.seconds()); |
209 | | - } |
210 | | - else |
211 | | - { |
212 | | - odometry_updated = |
213 | | - odometry_.update_from_vel(left_feedback_mean, right_feedback_mean, period.seconds()); |
| 223 | + if (params_.position_feedback) |
| 224 | + { |
| 225 | + odometry_updated = |
| 226 | + odometry_.update_from_pos(left_feedback_mean, right_feedback_mean, period.seconds()); |
| 227 | + } |
| 228 | + else |
| 229 | + { |
| 230 | + odometry_updated = |
| 231 | + odometry_.update_from_vel(left_feedback_mean, right_feedback_mean, period.seconds()); |
| 232 | + } |
214 | 233 | } |
215 | 234 | } |
216 | 235 |
|
@@ -492,6 +511,11 @@ controller_interface::CallbackReturn DiffDriveController::on_configure( |
492 | 511 | odometry_transform_message_.transforms.front().header.frame_id = odom_frame_id; |
493 | 512 | odometry_transform_message_.transforms.front().child_frame_id = base_frame_id; |
494 | 513 |
|
| 514 | + set_odom_service_ = get_node()->create_service<control_msgs::srv::SetOdometry>( |
| 515 | + DEFAULT_SET_ODOM_SERVICE, std::bind( |
| 516 | + &DiffDriveController::set_odometry, this, std::placeholders::_1, |
| 517 | + std::placeholders::_2, std::placeholders::_3)); |
| 518 | + |
495 | 519 | previous_update_timestamp_ = get_node()->get_clock()->now(); |
496 | 520 | return controller_interface::CallbackReturn::SUCCESS; |
497 | 521 | } |
@@ -556,6 +580,28 @@ controller_interface::CallbackReturn DiffDriveController::on_error(const rclcpp_ |
556 | 580 | return controller_interface::CallbackReturn::SUCCESS; |
557 | 581 | } |
558 | 582 |
|
| 583 | +void DiffDriveController::set_odometry( |
| 584 | + const std::shared_ptr<rmw_request_id_t> /*request_header*/, |
| 585 | + const std::shared_ptr<control_msgs::srv::SetOdometry::Request> req, |
| 586 | + std::shared_ptr<control_msgs::srv::SetOdometry::Response> res) |
| 587 | +{ |
| 588 | + if (get_node()->get_current_state().id() != lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE) |
| 589 | + { |
| 590 | + res->success = false; |
| 591 | + res->message = "Controller is not active"; |
| 592 | + return; |
| 593 | + } |
| 594 | + |
| 595 | + // put requested odom params into RealtimeThreadSafeBox |
| 596 | + requested_odom_params_.set(*req); |
| 597 | + |
| 598 | + // flip the flag for thread-safe odom set in the control loop |
| 599 | + set_odom_requested_.store(true); |
| 600 | + |
| 601 | + res->success = true; |
| 602 | + res->message = "Odometry set request accepted"; |
| 603 | +} |
| 604 | + |
559 | 605 | bool DiffDriveController::reset() |
560 | 606 | { |
561 | 607 | odometry_.resetOdometry(); |
|
0 commit comments