@@ -45,7 +45,7 @@ using hardware_interface::HW_IF_POSITION;
45
45
using hardware_interface::HW_IF_VELOCITY;
46
46
using lifecycle_msgs::msg::State;
47
47
48
- DiffDriveController::DiffDriveController () : controller_interface::ControllerInterface () {}
48
+ DiffDriveController::DiffDriveController () : controller_interface::ChainableControllerInterface () {}
49
49
50
50
const char * DiffDriveController::feedback_type () const
51
51
{
@@ -97,8 +97,8 @@ InterfaceConfiguration DiffDriveController::state_interface_configuration() cons
97
97
return {interface_configuration_type::INDIVIDUAL, conf_names};
98
98
}
99
99
100
- controller_interface::return_type DiffDriveController::update (
101
- const rclcpp::Time & time, const rclcpp::Duration & period)
100
+ controller_interface::return_type DiffDriveController::update_reference_from_subscribers (
101
+ const rclcpp::Time & time, const rclcpp::Duration & /* period*/ )
102
102
{
103
103
auto logger = get_node ()->get_logger ();
104
104
if (get_lifecycle_state ().id () == State::PRIMARY_STATE_INACTIVE)
@@ -111,31 +111,64 @@ controller_interface::return_type DiffDriveController::update(
111
111
return controller_interface::return_type::OK;
112
112
}
113
113
114
- // if the mutex is unable to lock, last_command_msg_ won't be updated
115
- received_velocity_msg_ptr_.try_get ([this ](const std::shared_ptr<TwistStamped> & msg)
116
- { last_command_msg_ = msg; });
114
+ const std::shared_ptr<TwistStamped> command_msg_ptr = *(received_velocity_msg_ptr_.readFromRT ());
117
115
118
- if (last_command_msg_ == nullptr )
116
+ if (command_msg_ptr == nullptr )
119
117
{
120
118
RCLCPP_WARN (logger, " Velocity message received was a nullptr." );
121
119
return controller_interface::return_type::ERROR;
122
120
}
123
121
124
- const auto age_of_last_command = time - last_command_msg_ ->header .stamp ;
122
+ const auto age_of_last_command = time - command_msg_ptr ->header .stamp ;
125
123
// Brake if cmd_vel has timeout, override the stored command
126
124
if (age_of_last_command > cmd_vel_timeout_)
127
125
{
128
- last_command_msg_->twist .linear .x = 0.0 ;
129
- last_command_msg_->twist .angular .z = 0.0 ;
126
+ reference_interfaces_[0 ] = 0.0 ;
127
+ reference_interfaces_[1 ] = 0.0 ;
128
+ }
129
+ else if (
130
+ std::isfinite (command_msg_ptr->twist .linear .x ) &&
131
+ std::isfinite (command_msg_ptr->twist .angular .z ))
132
+ {
133
+ reference_interfaces_[0 ] = command_msg_ptr->twist .linear .x ;
134
+ reference_interfaces_[1 ] = command_msg_ptr->twist .angular .z ;
135
+ }
136
+ else
137
+ {
138
+ RCLCPP_WARN_SKIPFIRST_THROTTLE (
139
+ logger, *get_node ()->get_clock (), cmd_vel_timeout_.seconds () * 1000 ,
140
+ " Command message contains NaNs. Not updating reference interfaces." );
141
+ }
142
+
143
+ previous_update_timestamp_ = time;
144
+
145
+ return controller_interface::return_type::OK;
146
+ }
147
+
148
+ controller_interface::return_type DiffDriveController::update_and_write_commands (
149
+ const rclcpp::Time & time, const rclcpp::Duration & period)
150
+ {
151
+ auto logger = get_node ()->get_logger ();
152
+ if (get_lifecycle_state ().id () == State::PRIMARY_STATE_INACTIVE)
153
+ {
154
+ if (!is_halted)
155
+ {
156
+ halt ();
157
+ is_halted = true ;
158
+ }
159
+ return controller_interface::return_type::OK;
130
160
}
131
161
132
162
// command may be limited further by SpeedLimit,
133
163
// without affecting the stored twist command
134
- TwistStamped command = *last_command_msg_;
135
- double & linear_command = command.twist .linear .x ;
136
- double & angular_command = command.twist .angular .z ;
164
+ double linear_command = reference_interfaces_[0 ];
165
+ double angular_command = reference_interfaces_[1 ];
137
166
138
- previous_update_timestamp_ = time;
167
+ if (!std::isfinite (linear_command) || !std::isfinite (angular_command))
168
+ {
169
+ // NaNs occur on initialization when the reference interfaces are not yet set
170
+ return controller_interface::return_type::OK;
171
+ }
139
172
140
173
// Apply (possibly new) multipliers:
141
174
const double wheel_separation = params_.wheel_separation_multiplier * params_.wheel_separation ;
@@ -232,22 +265,27 @@ controller_interface::return_type DiffDriveController::update(
232
265
}
233
266
}
234
267
235
- auto & last_command = previous_commands_.back ().twist ;
236
- auto & second_to_last_command = previous_commands_.front ().twist ;
237
- limiter_linear_->limit (
238
- linear_command, last_command.linear .x , second_to_last_command.linear .x , period.seconds ());
239
- limiter_angular_->limit (
240
- angular_command, last_command.angular .z , second_to_last_command.angular .z , period.seconds ());
268
+ double & last_linear = previous_two_commands_.back ()[0 ];
269
+ double & second_to_last_linear = previous_two_commands_.front ()[0 ];
270
+ double & last_angular = previous_two_commands_.back ()[1 ];
271
+ double & second_to_last_angular = previous_two_commands_.front ()[1 ];
241
272
242
- previous_commands_.pop ();
243
- previous_commands_.emplace (command);
273
+ limiter_linear_->limit (linear_command, last_linear, second_to_last_linear, period.seconds ());
274
+ limiter_angular_->limit (angular_command, last_angular, second_to_last_angular, period.seconds ());
275
+ previous_two_commands_.pop ();
276
+ previous_two_commands_.push ({{linear_command, angular_command}});
244
277
245
278
// Publish limited velocity
246
279
if (publish_limited_velocity_ && realtime_limited_velocity_publisher_->trylock ())
247
280
{
248
281
auto & limited_velocity_command = realtime_limited_velocity_publisher_->msg_ ;
249
282
limited_velocity_command.header .stamp = time;
250
- limited_velocity_command.twist = command.twist ;
283
+ limited_velocity_command.twist .linear .x = linear_command;
284
+ limited_velocity_command.twist .linear .y = 0.0 ;
285
+ limited_velocity_command.twist .linear .z = 0.0 ;
286
+ limited_velocity_command.twist .angular .x = 0.0 ;
287
+ limited_velocity_command.twist .angular .y = 0.0 ;
288
+ limited_velocity_command.twist .angular .z = angular_command;
251
289
realtime_limited_velocity_publisher_->unlockAndPublish ();
252
290
}
253
291
@@ -294,7 +332,7 @@ controller_interface::CallbackReturn DiffDriveController::on_configure(
294
332
odometry_.setWheelParams (wheel_separation, left_wheel_radius, right_wheel_radius);
295
333
odometry_.setVelocityRollingWindowSize (static_cast <size_t >(params_.velocity_rolling_window_size ));
296
334
297
- cmd_vel_timeout_ = std::chrono::milliseconds{ static_cast < int > (params_.cmd_vel_timeout * 1000.0 )} ;
335
+ cmd_vel_timeout_ = rclcpp::Duration::from_seconds (params_.cmd_vel_timeout ) ;
298
336
publish_limited_velocity_ = params_.publish_limited_velocity ;
299
337
300
338
// TODO(christophfroehlich) remove deprecated parameters
@@ -387,13 +425,6 @@ controller_interface::CallbackReturn DiffDriveController::on_configure(
387
425
limited_velocity_publisher_);
388
426
}
389
427
390
- last_command_msg_ = std::make_shared<TwistStamped>();
391
- received_velocity_msg_ptr_.set ([this ](std::shared_ptr<TwistStamped> & stored_value)
392
- { stored_value = last_command_msg_; });
393
- // Fill last two commands with default constructed commands
394
- previous_commands_.emplace (*last_command_msg_);
395
- previous_commands_.emplace (*last_command_msg_);
396
-
397
428
// initialize command subscriber
398
429
velocity_command_subscriber_ = get_node ()->create_subscription <TwistStamped>(
399
430
DEFAULT_COMMAND_TOPIC, rclcpp::SystemDefaultsQoS (),
@@ -410,10 +441,26 @@ controller_interface::CallbackReturn DiffDriveController::on_configure(
410
441
get_node ()->get_logger (),
411
442
" Received TwistStamped with zero timestamp, setting it to current "
412
443
" time, this message will only be shown once" );
413
- msg->header .stamp = get_node ()->get_clock ()->now ();
444
+ msg->header .stamp = get_node ()->now ();
445
+ }
446
+
447
+ const auto current_time_diff = get_node ()->now () - msg->header .stamp ;
448
+
449
+ if (
450
+ cmd_vel_timeout_ == rclcpp::Duration::from_seconds (0.0 ) ||
451
+ current_time_diff < cmd_vel_timeout_)
452
+ {
453
+ received_velocity_msg_ptr_.writeFromNonRT (msg);
454
+ }
455
+ else
456
+ {
457
+ RCLCPP_WARN (
458
+ get_node ()->get_logger (),
459
+ " Ignoring the received message (timestamp %.10f) because it is older than "
460
+ " the current time by %.10f seconds, which exceeds the allowed timeout (%.4f)" ,
461
+ rclcpp::Time (msg->header .stamp ).seconds (), current_time_diff.seconds (),
462
+ cmd_vel_timeout_.seconds ());
414
463
}
415
- received_velocity_msg_ptr_.set ([msg](std::shared_ptr<TwistStamped> & stored_value)
416
- { stored_value = std::move (msg); });
417
464
});
418
465
419
466
// initialize odometry publisher and message
@@ -527,6 +574,7 @@ controller_interface::CallbackReturn DiffDriveController::on_deactivate(
527
574
halt ();
528
575
is_halted = true ;
529
576
}
577
+ reset_buffers ();
530
578
registered_left_wheel_handles_.clear ();
531
579
registered_right_wheel_handles_.clear ();
532
580
return controller_interface::CallbackReturn::SUCCESS;
@@ -556,21 +604,41 @@ bool DiffDriveController::reset()
556
604
{
557
605
odometry_.resetOdometry ();
558
606
559
- // release the old queue
560
- std::queue<TwistStamped> empty;
561
- std::swap (previous_commands_, empty);
607
+ reset_buffers ();
562
608
563
609
registered_left_wheel_handles_.clear ();
564
610
registered_right_wheel_handles_.clear ();
565
611
566
612
subscriber_is_active_ = false ;
567
613
velocity_command_subscriber_.reset ();
568
614
569
- received_velocity_msg_ptr_.set (nullptr );
570
615
is_halted = false ;
571
616
return true ;
572
617
}
573
618
619
+ void DiffDriveController::reset_buffers ()
620
+ {
621
+ reference_interfaces_ = std::vector<double >(2 , std::numeric_limits<double >::quiet_NaN ());
622
+ // Empty out the old queue. Fill with zeros (not NaN) to catch early accelerations.
623
+ std::queue<std::array<double , 2 >> empty;
624
+ std::swap (previous_two_commands_, empty);
625
+ previous_two_commands_.push ({{0.0 , 0.0 }});
626
+ previous_two_commands_.push ({{0.0 , 0.0 }});
627
+
628
+ // Fill RealtimeBuffer with NaNs so it will contain a known value
629
+ // but still indicate that no command has yet been sent.
630
+ received_velocity_msg_ptr_.reset ();
631
+ std::shared_ptr<TwistStamped> empty_msg_ptr = std::make_shared<TwistStamped>();
632
+ empty_msg_ptr->header .stamp = get_node ()->now ();
633
+ empty_msg_ptr->twist .linear .x = std::numeric_limits<double >::quiet_NaN ();
634
+ empty_msg_ptr->twist .linear .y = std::numeric_limits<double >::quiet_NaN ();
635
+ empty_msg_ptr->twist .linear .z = std::numeric_limits<double >::quiet_NaN ();
636
+ empty_msg_ptr->twist .angular .x = std::numeric_limits<double >::quiet_NaN ();
637
+ empty_msg_ptr->twist .angular .y = std::numeric_limits<double >::quiet_NaN ();
638
+ empty_msg_ptr->twist .angular .z = std::numeric_limits<double >::quiet_NaN ();
639
+ received_velocity_msg_ptr_.writeFromNonRT (empty_msg_ptr);
640
+ }
641
+
574
642
void DiffDriveController::halt ()
575
643
{
576
644
const auto halt_wheels = [](auto & wheel_handles)
@@ -636,9 +704,35 @@ controller_interface::CallbackReturn DiffDriveController::configure_side(
636
704
637
705
return controller_interface::CallbackReturn::SUCCESS;
638
706
}
707
+
708
+ bool DiffDriveController::on_set_chained_mode (bool chained_mode)
709
+ {
710
+ // Always accept switch to/from chained mode (without linting type-cast error)
711
+ return true || chained_mode;
712
+ }
713
+
714
+ std::vector<hardware_interface::CommandInterface>
715
+ DiffDriveController::on_export_reference_interfaces ()
716
+ {
717
+ const int nr_ref_itfs = 2 ;
718
+ reference_interfaces_.resize (nr_ref_itfs, std::numeric_limits<double >::quiet_NaN ());
719
+ std::vector<hardware_interface::CommandInterface> reference_interfaces;
720
+ reference_interfaces.reserve (nr_ref_itfs);
721
+
722
+ reference_interfaces.push_back (hardware_interface::CommandInterface (
723
+ get_node ()->get_name (), std::string (" linear/" ) + hardware_interface::HW_IF_VELOCITY,
724
+ &reference_interfaces_[0 ]));
725
+
726
+ reference_interfaces.push_back (hardware_interface::CommandInterface (
727
+ get_node ()->get_name (), std::string (" angular/" ) + hardware_interface::HW_IF_VELOCITY,
728
+ &reference_interfaces_[1 ]));
729
+
730
+ return reference_interfaces;
731
+ }
732
+
639
733
} // namespace diff_drive_controller
640
734
641
735
#include " class_loader/register_macro.hpp"
642
736
643
737
CLASS_LOADER_REGISTER_CLASS (
644
- diff_drive_controller::DiffDriveController, controller_interface::ControllerInterface )
738
+ diff_drive_controller::DiffDriveController, controller_interface::ChainableControllerInterface )
0 commit comments