@@ -86,7 +86,7 @@ geometry_msgs::TransformStamped convertIsometryToTransform(const Eigen::Isometry
86
86
// Constructor for the class that handles servoing calculations
87
87
ServoCalcs::ServoCalcs (ros::NodeHandle& nh, ServoParameters& parameters,
88
88
const planning_scene_monitor::PlanningSceneMonitorPtr& planning_scene_monitor)
89
- : nh_(nh), parameters_(parameters), planning_scene_monitor_(planning_scene_monitor), period_(parameters.publish_period )
89
+ : nh_(nh), parameters_(parameters), planning_scene_monitor_(planning_scene_monitor), stop_requested_( true )
90
90
{
91
91
// MoveIt Setup
92
92
current_state_ = planning_scene_monitor_->getStateMonitor ()->getCurrentState ();
@@ -150,8 +150,16 @@ ServoCalcs::ServoCalcs(ros::NodeHandle& nh, ServoParameters& parameters,
150
150
tf_moveit_to_robot_cmd_frame_ = empty_matrix;
151
151
}
152
152
153
+ ServoCalcs::~ServoCalcs ()
154
+ {
155
+ stop ();
156
+ }
157
+
153
158
void ServoCalcs::start ()
154
159
{
160
+ // Stop the thread if we are currently running
161
+ stop ();
162
+
155
163
// We will update last_sent_command_ every time we start servo
156
164
auto initial_joint_trajectory = moveit::util::make_shared_from_pool<trajectory_msgs::JointTrajectory>();
157
165
@@ -188,19 +196,78 @@ void ServoCalcs::start()
188
196
tf_moveit_to_robot_cmd_frame_ = current_state_->getGlobalLinkTransform (parameters_.planning_frame ).inverse () *
189
197
current_state_->getGlobalLinkTransform (parameters_.robot_link_command_frame );
190
198
191
- timer_ = nh_.createTimer (period_, &ServoCalcs::run, this );
199
+ stop_requested_ = false ;
200
+ thread_ = std::thread ([this ] { mainCalcLoop (); });
201
+ new_input_cmd_ = false ;
192
202
}
193
203
194
- void ServoCalcs::run ( const ros::TimerEvent& timer_event )
204
+ void ServoCalcs::stop ( )
195
205
{
196
- // Log warning when the last loop duration was longer than the period
197
- if (timer_event.profile .last_duration .toSec () > period_.toSec ())
206
+ // Request stop
207
+ stop_requested_ = true ;
208
+
209
+ // Notify condition variable in case the thread is blocked on it
198
210
{
199
- ROS_WARN_STREAM_THROTTLE_NAMED (ROS_LOG_THROTTLE_PERIOD, LOGNAME,
200
- " last_duration: " << timer_event.profile .last_duration .toSec () << " ("
201
- << period_.toSec () << " )" );
211
+ // scope so the mutex is unlocked after so the thread can continue
212
+ // and therefore be joinable
213
+ const std::lock_guard<std::mutex> lock (input_mutex_);
214
+ new_input_cmd_ = false ;
215
+ input_cv_.notify_all ();
216
+ }
217
+
218
+ // Join the thread
219
+ if (thread_.joinable ())
220
+ {
221
+ thread_.join ();
222
+ }
223
+ }
224
+
225
+ void ServoCalcs::mainCalcLoop ()
226
+ {
227
+ ros::Rate rate (1.0 / parameters_.publish_period );
228
+
229
+ while (ros::ok () && !stop_requested_)
230
+ {
231
+ // lock the input state mutex
232
+ std::unique_lock<std::mutex> input_lock (input_mutex_);
233
+
234
+ // low latency mode
235
+ if (parameters_.low_latency_mode )
236
+ {
237
+ input_cv_.wait (input_lock, [this ] { return (new_input_cmd_ || stop_requested_); });
238
+
239
+ // break out of the loop if stop was requested
240
+ if (stop_requested_)
241
+ break ;
242
+ }
243
+
244
+ // reset new_input_cmd_ flag
245
+ new_input_cmd_ = false ;
246
+
247
+ // run servo calcs
248
+ const auto start_time = ros::Time::now ();
249
+ calculateSingleIteration ();
250
+ const auto run_duration = ros::Time::now () - start_time;
251
+
252
+ // Log warning when the run duration was longer than the period
253
+ if (run_duration.toSec () > parameters_.publish_period )
254
+ {
255
+ ROS_WARN_STREAM_THROTTLE_NAMED (ROS_LOG_THROTTLE_PERIOD, LOGNAME,
256
+ " run_duration: " << run_duration.toSec () << " (" << parameters_.publish_period
257
+ << " )" );
258
+ }
259
+
260
+ // normal mode, unlock input mutex and wait for the period of the loop
261
+ if (!parameters_.low_latency_mode )
262
+ {
263
+ input_lock.unlock ();
264
+ rate.sleep ();
265
+ }
202
266
}
267
+ }
203
268
269
+ void ServoCalcs::calculateSingleIteration ()
270
+ {
204
271
// Publish status each loop iteration
205
272
auto status_msg = moveit::util::make_shared_from_pool<std_msgs::Int8>();
206
273
status_msg->data = static_cast <int8_t >(status_);
@@ -213,22 +280,20 @@ void ServoCalcs::run(const ros::TimerEvent& timer_event)
213
280
214
281
// Update from latest state
215
282
current_state_ = planning_scene_monitor_->getStateMonitor ()->getCurrentState ();
216
- {
217
- const std::lock_guard<std::mutex> lock (latest_state_mutex_);
218
- if (latest_twist_stamped_)
219
- twist_stamped_cmd_ = *latest_twist_stamped_;
220
- if (latest_joint_cmd_)
221
- joint_servo_cmd_ = *latest_joint_cmd_;
222
-
223
- // Check for stale cmds
224
- twist_command_is_stale_ =
225
- ((ros::Time::now () - latest_twist_command_stamp_) >= ros::Duration (parameters_.incoming_command_timeout ));
226
- joint_command_is_stale_ =
227
- ((ros::Time::now () - latest_joint_command_stamp_) >= ros::Duration (parameters_.incoming_command_timeout ));
228
-
229
- have_nonzero_twist_stamped_ = latest_nonzero_twist_stamped_;
230
- have_nonzero_joint_command_ = latest_nonzero_joint_cmd_;
231
- }
283
+
284
+ if (latest_twist_stamped_)
285
+ twist_stamped_cmd_ = *latest_twist_stamped_;
286
+ if (latest_joint_cmd_)
287
+ joint_servo_cmd_ = *latest_joint_cmd_;
288
+
289
+ // Check for stale cmds
290
+ twist_command_is_stale_ =
291
+ ((ros::Time::now () - latest_twist_command_stamp_) >= ros::Duration (parameters_.incoming_command_timeout ));
292
+ joint_command_is_stale_ =
293
+ ((ros::Time::now () - latest_joint_command_stamp_) >= ros::Duration (parameters_.incoming_command_timeout ));
294
+
295
+ have_nonzero_twist_stamped_ = latest_nonzero_twist_stamped_;
296
+ have_nonzero_joint_command_ = latest_nonzero_joint_cmd_;
232
297
233
298
// Get the transform from MoveIt planning frame to servoing command frame
234
299
// Calculate this transform to ensure it is available via C++ API
@@ -980,7 +1045,7 @@ void ServoCalcs::removeDimension(Eigen::MatrixXd& jacobian, Eigen::VectorXd& del
980
1045
981
1046
bool ServoCalcs::getCommandFrameTransform (Eigen::Isometry3d& transform)
982
1047
{
983
- const std::lock_guard<std::mutex> lock (latest_state_mutex_ );
1048
+ const std::lock_guard<std::mutex> lock (input_mutex_ );
984
1049
transform = tf_moveit_to_robot_cmd_frame_;
985
1050
986
1051
// All zeros means the transform wasn't initialized, so return false
@@ -989,7 +1054,7 @@ bool ServoCalcs::getCommandFrameTransform(Eigen::Isometry3d& transform)
989
1054
990
1055
bool ServoCalcs::getCommandFrameTransform (geometry_msgs::TransformStamped& transform)
991
1056
{
992
- const std::lock_guard<std::mutex> lock (latest_state_mutex_ );
1057
+ const std::lock_guard<std::mutex> lock (input_mutex_ );
993
1058
// All zeros means the transform wasn't initialized, so return false
994
1059
if (tf_moveit_to_robot_cmd_frame_.matrix ().isZero (0 ))
995
1060
{
@@ -1003,7 +1068,7 @@ bool ServoCalcs::getCommandFrameTransform(geometry_msgs::TransformStamped& trans
1003
1068
1004
1069
bool ServoCalcs::getEEFrameTransform (Eigen::Isometry3d& transform)
1005
1070
{
1006
- const std::lock_guard<std::mutex> lock (latest_state_mutex_ );
1071
+ const std::lock_guard<std::mutex> lock (input_mutex_ );
1007
1072
transform = tf_moveit_to_ee_frame_;
1008
1073
1009
1074
// All zeros means the transform wasn't initialized, so return false
@@ -1012,7 +1077,7 @@ bool ServoCalcs::getEEFrameTransform(Eigen::Isometry3d& transform)
1012
1077
1013
1078
bool ServoCalcs::getEEFrameTransform (geometry_msgs::TransformStamped& transform)
1014
1079
{
1015
- const std::lock_guard<std::mutex> lock (latest_state_mutex_ );
1080
+ const std::lock_guard<std::mutex> lock (input_mutex_ );
1016
1081
// All zeros means the transform wasn't initialized, so return false
1017
1082
if (tf_moveit_to_ee_frame_.matrix ().isZero (0 ))
1018
1083
{
@@ -1025,22 +1090,30 @@ bool ServoCalcs::getEEFrameTransform(geometry_msgs::TransformStamped& transform)
1025
1090
1026
1091
void ServoCalcs::twistStampedCB (const geometry_msgs::TwistStampedConstPtr& msg)
1027
1092
{
1028
- const std::lock_guard<std::mutex> lock (latest_state_mutex_ );
1093
+ const std::lock_guard<std::mutex> lock (input_mutex_ );
1029
1094
latest_twist_stamped_ = msg;
1030
1095
latest_nonzero_twist_stamped_ = isNonZero (*latest_twist_stamped_);
1031
1096
1032
1097
if (msg->header .stamp != ros::Time (0 .))
1033
1098
latest_twist_command_stamp_ = msg->header .stamp ;
1099
+
1100
+ // notify that we have a new input
1101
+ new_input_cmd_ = true ;
1102
+ input_cv_.notify_all ();
1034
1103
}
1035
1104
1036
1105
void ServoCalcs::jointCmdCB (const control_msgs::JointJogConstPtr& msg)
1037
1106
{
1038
- const std::lock_guard<std::mutex> lock (latest_state_mutex_ );
1107
+ const std::lock_guard<std::mutex> lock (input_mutex_ );
1039
1108
latest_joint_cmd_ = msg;
1040
1109
latest_nonzero_joint_cmd_ = isNonZero (*latest_joint_cmd_);
1041
1110
1042
1111
if (msg->header .stamp != ros::Time (0 .))
1043
1112
latest_joint_command_stamp_ = msg->header .stamp ;
1113
+
1114
+ // notify that we have a new input
1115
+ new_input_cmd_ = true ;
1116
+ input_cv_.notify_all ();
1044
1117
}
1045
1118
1046
1119
void ServoCalcs::collisionVelocityScaleCB (const std_msgs::Float64ConstPtr& msg)
0 commit comments