SMACC2
Loading...
Searching...
No Matches
cb_move_end_effector_trajectory.cpp
Go to the documentation of this file.
1// Copyright 2021 RobosoftAI Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20
21#include <tf2/transform_datatypes.h>
22#include <tf2_ros/transform_listener.h>
23
27#include <moveit_msgs/srv/get_position_ik.hpp>
28
29#include <visualization_msgs/msg/marker_array.hpp>
30
31using namespace std::chrono_literals;
32
33namespace cl_moveit2z
34{
36: tipLink_(tipLink), markersInitialized_(false)
37{
38}
39
41 const std::vector<geometry_msgs::msg::PoseStamped> & endEffectorTrajectory,
42 std::optional<std::string> tipLink)
43: tipLink_(tipLink), endEffectorTrajectory_(endEffectorTrajectory), markersInitialized_(false)
44
45{
46}
47
49{
50 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] initializing ros");
51
52 auto nh = this->getNode();
53 markersPub_ = nh->create_publisher<visualization_msgs::msg::MarkerArray>(
54 "trajectory_markers", rclcpp::QoS(1));
55 iksrv_ = nh->create_client<moveit_msgs::srv::GetPositionIK>("/compute_ik");
56}
57
59 moveit_msgs::msg::RobotTrajectory & computedJointTrajectory)
60{
61 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] getting current state.. waiting");
62
63 // get current robot state
64 auto currentState = movegroupClient_->moveGroupClientInterface->getCurrentState(100);
65
66 // get the IK client
67 auto groupname = movegroupClient_->moveGroupClientInterface->getName();
68
69 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] getting joint names");
70 auto currentjointnames = currentState->getJointModelGroup(groupname)->getActiveJointModelNames();
71
72 if (!tipLink_ || *tipLink_ == "")
73 {
74 tipLink_ = movegroupClient_->moveGroupClientInterface->getEndEffectorLink();
75 }
76
77 std::vector<double> jointPositions;
78 currentState->copyJointGroupPositions(groupname, jointPositions);
79
80 std::vector<std::vector<double>> trajectory;
81 std::vector<rclcpp::Duration> trajectoryTimeStamps;
82
83 trajectory.push_back(jointPositions);
84 trajectoryTimeStamps.push_back(rclcpp::Duration(0s));
85
86 auto & first = endEffectorTrajectory_.front();
87 rclcpp::Time referenceTime(first.header.stamp);
88
89 std::vector<int> discontinuityIndexes;
90
91 int ikAttempts = 4;
92 for (size_t k = 0; k < this->endEffectorTrajectory_.size(); k++)
93 {
94 auto & pose = this->endEffectorTrajectory_[k];
95 auto req = std::make_shared<moveit_msgs::srv::GetPositionIK::Request>();
96 //req.ik_request.attempts = 20;
97
98 req->ik_request.ik_link_name = *tipLink_;
99 req->ik_request.robot_state.joint_state.name = currentjointnames;
100 req->ik_request.robot_state.joint_state.position = jointPositions;
101
102 req->ik_request.group_name = groupname;
103 req->ik_request.avoid_collisions = true;
104
105 //pose.header.stamp = getNode()->now();
106 req->ik_request.pose_stamped = pose;
107
108 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] IK request: " << k << " " << *req);
109
110 auto resfut = iksrv_->async_send_request(req);
111
112 auto status = resfut.wait_for(3s);
113 if (status == std::future_status::ready)
114 {
115 //if (rclcpp::spin_until_future_complete(getNode(), resfut) == rclcpp::FutureReturnCode::SUCCESS)
116 //{
117 auto & prevtrajpoint = trajectory.back();
118 //jointPositions.clear();
119
120 auto res = resfut.get();
121 std::stringstream ss;
122 for (size_t j = 0; j < res->solution.joint_state.position.size(); j++)
123 {
124 auto & jointname = res->solution.joint_state.name[j];
125 auto it = std::find(currentjointnames.begin(), currentjointnames.end(), jointname);
126 if (it != currentjointnames.end())
127 {
128 int index = std::distance(currentjointnames.begin(), it);
129 jointPositions[index] = res->solution.joint_state.position[j];
130 ss << jointname << "(" << index << "): " << jointPositions[index] << std::endl;
131 }
132 }
133
134 // continuity check
135 size_t jointindex = 0;
136 int discontinuityJointIndex = -1;
137 double discontinuityDeltaJointIndex = -1;
138 double deltajoint;
139
140 bool check = k > 0 || !allowInitialTrajectoryStateJointDiscontinuity_ ||
142 !(*allowInitialTrajectoryStateJointDiscontinuity_));
143 if (check)
144 {
145 for (jointindex = 0; jointindex < jointPositions.size(); jointindex++)
146 {
147 deltajoint = jointPositions[jointindex] - prevtrajpoint[jointindex];
148
149 if (fabs(deltajoint) > 0.3 /*2.5 deg*/)
150 {
151 discontinuityDeltaJointIndex = deltajoint;
152 discontinuityJointIndex = jointindex;
153 }
154 }
155 }
156
157 if (ikAttempts > 0 && discontinuityJointIndex != -1)
158 {
159 k--;
160 ikAttempts--;
161 continue;
162 }
163 else
164 {
165 bool discontinuity = false;
166 if (ikAttempts == 0)
167 {
168 discontinuityIndexes.push_back(k);
169 discontinuity = true;
170 }
171
172 ikAttempts = 4;
173
174 if (discontinuity && discontinuityJointIndex != -1)
175 {
176 // show a message and stop the trajectory generation && jointindex!= 7 || fabs(deltajoint) > 0.1 /*2.5 deg*/ && jointindex== 7
177 std::stringstream ss;
178 ss << "Traj[" << k << "/" << endEffectorTrajectory_.size() << "] "
179 << currentjointnames[discontinuityJointIndex]
180 << " IK discontinuity : " << discontinuityDeltaJointIndex << std::endl
181 << "prev joint value: " << prevtrajpoint[discontinuityJointIndex] << std::endl
182 << "current joint value: " << jointPositions[discontinuityJointIndex] << std::endl;
183
184 ss << std::endl;
185 for (size_t ji = 0; ji < jointPositions.size(); ji++)
186 {
187 ss << currentjointnames[ji] << ": " << jointPositions[ji] << std::endl;
188 }
189
190 for (size_t kindex = 0; kindex < trajectory.size(); kindex++)
191 {
192 ss << "[" << kindex << "]: " << trajectory[kindex][discontinuityJointIndex]
193 << std::endl;
194 }
195
196 if (k == 0)
197 {
198 ss << "This is the first posture of the trajectory. Maybe the robot initial posture is "
199 "not coincident to the initial posture of the generated joint trajectory."
200 << std::endl;
201 }
202
203 RCLCPP_ERROR_STREAM(getLogger(), ss.str());
204
205 trajectory.push_back(jointPositions);
206 rclcpp::Duration durationFromStart = rclcpp::Time(pose.header.stamp) - referenceTime;
207 trajectoryTimeStamps.push_back(durationFromStart);
208
209 continue;
210 }
211 else
212 {
213 trajectory.push_back(jointPositions);
214 rclcpp::Duration durationFromStart = rclcpp::Time(pose.header.stamp) - referenceTime;
215 trajectoryTimeStamps.push_back(durationFromStart);
216
217 RCLCPP_DEBUG_STREAM(getLogger(), "IK solution: " << res->solution.joint_state);
218 RCLCPP_DEBUG_STREAM(getLogger(), "trajpoint: " << std::endl << ss.str());
219 }
220 }
221 }
222 else
223 {
224 RCLCPP_ERROR_STREAM(getLogger(), "[" << getName() << "] wrong IK call");
225 }
226 }
227
228 // interpolate speeds?
229
230 // interpolate accelerations?
231
232 // get current robot state
233 // fill plan message
234 // computedMotionPlan.start_state_.joint_state.name = currentjointnames;
235 // computedMotionPlan.start_state_.joint_state.position = trajectory.front();
236 // computedMotionPlan.trajectory_.joint_trajectory.joint_names = currentjointnames;
237
238 computedJointTrajectory.joint_trajectory.joint_names = currentjointnames;
239 int i = 0;
240 for (auto & p : trajectory)
241 {
242 if (
243 i ==
244 0) // not copy the current state in the trajectory (used to solve discontinuity in other behaviors)
245 {
246 i++;
247 continue;
248 }
249
250 trajectory_msgs::msg::JointTrajectoryPoint jp;
251 jp.positions = p;
252 jp.time_from_start = trajectoryTimeStamps[i]; //rclcpp::Duration(t);
253 computedJointTrajectory.joint_trajectory.points.push_back(jp);
254 i++;
255 }
256
257 if (discontinuityIndexes.size())
258 {
259 if (discontinuityIndexes[0] == 0)
261 else
263 }
264
266}
267
269 const moveit_msgs::msg::RobotTrajectory & computedJointTrajectory)
270{
271 RCLCPP_INFO_STREAM(getLogger(), "[" << this->getName() << "] Executing joint trajectory");
272 // call execute
273 auto executionResult =
274 this->movegroupClient_->moveGroupClientInterface->execute(computedJointTrajectory);
275
276 if (executionResult == moveit_msgs::msg::MoveItErrorCodes::SUCCESS)
277 {
278 RCLCPP_INFO_STREAM(getLogger(), "[" << this->getName() << "] motion execution succeeded");
280 this->postSuccessEvent();
281 }
282 else
283 {
285 this->postFailureEvent();
286 }
287}
288
290{
292
293 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] Generating end effector trajectory");
294
295 this->generateTrajectory();
296
297 if (this->endEffectorTrajectory_.size() == 0)
298 {
299 RCLCPP_WARN_STREAM(
300 getLogger(), "[" << smacc2::demangleSymbol(typeid(*this).name())
301 << "] No points in the trajectory. Skipping behavior.");
302 return;
303 }
304
305 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] Creating markers.");
306
307 this->createMarkers();
308 markersInitialized_ = true;
309 moveit_msgs::msg::RobotTrajectory computedTrajectory;
310
311 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] Computing joint space trajectory.");
312
313 auto errorcode = computeJointSpaceTrajectory(computedTrajectory);
314
315 bool trajectoryGenerationSuccess = errorcode == ComputeJointTrajectoryErrorCode::SUCCESS;
316
317 CpTrajectoryHistory * trajectoryHistory;
318 this->requiresComponent(trajectoryHistory);
319
320 if (!trajectoryGenerationSuccess)
321 {
322 RCLCPP_INFO_STREAM(
323 getLogger(), "[" << this->getName() << "] Incorrect trajectory. Posting failure event.");
324 if (trajectoryHistory != nullptr)
325 {
326 moveit_msgs::msg::MoveItErrorCodes error;
327 error.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
328 trajectoryHistory->pushTrajectory(this->getName(), computedTrajectory, error);
329 }
330
332 this->postFailureEvent();
333
335 {
336 this->postJointDiscontinuityEvent(computedTrajectory);
337 }
339 {
340 this->postIncorrectInitialStateEvent(computedTrajectory);
341 }
342 return;
343 }
344 else
345 {
346 if (trajectoryHistory != nullptr)
347 {
348 moveit_msgs::msg::MoveItErrorCodes error;
349 error.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
350 trajectoryHistory->pushTrajectory(this->getName(), computedTrajectory, error);
351 }
352
353 this->executeJointSpaceTrajectory(computedTrajectory);
354 }
355
356 // handle finishing events
357} // namespace cl_moveit2z
358
360{
362 {
363 std::lock_guard<std::mutex> guard(m_mutex_);
365 }
366}
367
369{
370 markersInitialized_ = false;
371
373 {
374 std::lock_guard<std::mutex> guard(m_mutex_);
375 for (auto & marker : this->beahiorMarkers_.markers)
376 {
377 marker.header.stamp = getNode()->now();
378 marker.action = visualization_msgs::msg::Marker::DELETE;
379 }
380
382 }
383}
384
386{
387 tf2::Transform localdirection;
388 localdirection.setIdentity();
389 localdirection.setOrigin(tf2::Vector3(0.05, 0, 0));
390 auto frameid = this->endEffectorTrajectory_.front().header.frame_id;
391
392 for (auto & pose : this->endEffectorTrajectory_)
393 {
394 visualization_msgs::msg::Marker marker;
395 marker.header.frame_id = frameid;
396 marker.header.stamp = getNode()->now();
397 marker.ns = "trajectory";
398 marker.id = this->beahiorMarkers_.markers.size();
399 marker.type = visualization_msgs::msg::Marker::ARROW;
400 marker.action = visualization_msgs::msg::Marker::ADD;
401 marker.scale.x = 0.005;
402 marker.scale.y = 0.01;
403 marker.scale.z = 0.01;
404 marker.color.a = 0.8;
405 marker.color.r = 1.0;
406 marker.color.g = 0;
407 marker.color.b = 0;
408
409 geometry_msgs::msg::Point start, end;
410 start.x = 0;
411 start.y = 0;
412 start.z = 0;
413
414 tf2::Transform basetransform;
415 tf2::fromMsg(pose.pose, basetransform);
416 // tf2::Transform endarrow = localdirection * basetransform;
417
418 end.x = localdirection.getOrigin().x();
419 end.y = localdirection.getOrigin().y();
420 end.z = localdirection.getOrigin().z();
421
422 marker.pose.position = pose.pose.position;
423 marker.pose.orientation = pose.pose.orientation;
424 marker.points.push_back(start);
425 marker.points.push_back(end);
426
427 beahiorMarkers_.markers.push_back(marker);
428 }
429}
430
432{
433 // bypass current trajectory, overridden in derived classes
434 // this->endEffectorTrajectory_ = ...
435}
436
438 std::string globalFrame, tf2::Stamped<tf2::Transform> & currentEndEffectorTransform)
439{
440 tf2_ros::Buffer tfBuffer(getNode()->get_clock());
441 tf2_ros::TransformListener tfListener(tfBuffer);
442
443 try
444 {
445 if (!tipLink_ || *tipLink_ == "")
446 {
447 tipLink_ = this->movegroupClient_->moveGroupClientInterface->getEndEffectorLink();
448 }
449
450 tf2::fromMsg(
451 tfBuffer.lookupTransform(globalFrame, *tipLink_, rclcpp::Time(0), rclcpp::Duration(10s)),
452 currentEndEffectorTransform);
453
454 //tfListener.lookupTransform(globalFrame, *tipLink_, rclcpp::Time(0), currentEndEffectorTransform);
455
456 // we define here the global frame as the pivot frame id
457 // tfListener.waitForTransform(currentRobotEndEffectorPose.header.frame_id, planePivotPose_.header.frame_id, rclcpp::Time(0), rclcpp::Duration(10));
458 // tfListener.lookupTransform(currentRobotEndEffectorPose.header.frame_id, planePivotPose_.header.frame_id, rclcpp::Time(0), globalBaseLink);
459 }
460 catch (const std::exception & e)
461 {
462 std::cerr << e.what() << std::endl;
463 }
464}
465} // namespace cl_moveit2z
std::function< void(moveit_msgs::msg::RobotTrajectory &)> postJointDiscontinuityEvent
std::function< void(moveit_msgs::msg::RobotTrajectory &)> postIncorrectInitialStateEvent
std::vector< geometry_msgs::msg::PoseStamped > endEffectorTrajectory_
ComputeJointTrajectoryErrorCode computeJointSpaceTrajectory(moveit_msgs::msg::RobotTrajectory &computedJointTrajectory)
void executeJointSpaceTrajectory(const moveit_msgs::msg::RobotTrajectory &computedJointTrajectory)
CbMoveEndEffectorTrajectory(std::optional< std::string > tipLink=std::nullopt)
rclcpp::Publisher< visualization_msgs::msg::MarkerArray >::SharedPtr markersPub_
void getCurrentEndEffectorPose(std::string globalFrame, tf2::Stamped< tf2::Transform > &currentEndEffectorTransform)
rclcpp::Client< moveit_msgs::srv::GetPositionIK >::SharedPtr iksrv_
std::shared_ptr< moveit::planning_interface::MoveGroupInterface > moveGroupClientInterface
void postEventMotionExecutionSucceded()
void pushTrajectory(std::string name, const moveit_msgs::msg::RobotTrajectory &trajectory, moveit_msgs::msg::MoveItErrorCodes result)
virtual rclcpp::Logger getLogger() const
virtual rclcpp::Node::SharedPtr getNode() const
void requiresClient(SmaccClientType *&storage)
void requiresComponent(SmaccComponentType *&storage, bool throwExceptionIfNotExist=false)
std::string demangleSymbol()