SMACC2
Loading...
Searching...
No Matches
cb_move_end_effector_trajectory.hpp
Go to the documentation of this file.
1// Copyright 2025 Robosoft 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#pragma once
22
23#include <tf2/transform_datatypes.h>
24#include <tf2_ros/transform_listener.h>
33#include <moveit_msgs/srv/get_position_ik.hpp>
35#include <visualization_msgs/msg/marker_array.hpp>
36
37using namespace std::chrono_literals;
38
39namespace cl_moveit2z
40{
41template <typename AsyncCB, typename Orthogonal>
42struct EvJointDiscontinuity : sc::event<EvJointDiscontinuity<AsyncCB, Orthogonal>>
43{
44 moveit_msgs::msg::RobotTrajectory trajectory;
45};
46
47template <typename AsyncCB, typename Orthogonal>
48struct EvIncorrectInitialPosition : sc::event<EvIncorrectInitialPosition<AsyncCB, Orthogonal>>
49{
50 moveit_msgs::msg::RobotTrajectory trajectory;
51};
52
59
60// this is a base behavior to define any kind of parameterized family of trajectories or motions
62{
63public:
64 // std::string tip_link_;
65 std::optional<std::string> group_;
66
67 std::optional<std::string> tipLink_;
68
70
71 CbMoveEndEffectorTrajectory(std::optional<std::string> tipLink = std::nullopt) : tipLink_(tipLink)
72 {
73 }
74
76 const std::vector<geometry_msgs::msg::PoseStamped> & endEffectorTrajectory,
77 std::optional<std::string> tipLink = std::nullopt)
78 : tipLink_(tipLink), endEffectorTrajectory_(endEffectorTrajectory)
79 {
80 }
81
82 template <typename TOrthogonal, typename TSourceObject>
84 {
85 this->initializeROS();
86
88
89 postJointDiscontinuityEvent = [this](auto traj)
90 {
92 ev->trajectory = traj;
93 this->postEvent(ev);
94 };
95
96 postIncorrectInitialStateEvent = [this](auto traj)
97 {
99 ev->trajectory = traj;
100 this->postEvent(ev);
101 };
102
104 {
105 RCLCPP_INFO_STREAM(getLogger(), "[" << this->getName() << "] motion execution failed");
108 };
109 }
110
111 virtual void onEntry() override
112 {
114
115 // Get optional components for visualization
116 CpTrajectoryVisualizer * trajectoryVisualizer = nullptr;
117 this->requiresComponent(
118 trajectoryVisualizer, smacc2::ComponentRequirement::SOFT); // Optional component
119
120 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] Generating end effector trajectory");
121
122 this->generateTrajectory();
123
124 if (this->endEffectorTrajectory_.size() == 0)
125 {
126 RCLCPP_WARN_STREAM(
127 getLogger(), "[" << smacc2::demangleSymbol(typeid(*this).name())
128 << "] No points in the trajectory. Skipping behavior.");
129 return;
130 }
131
132 // Use CpTrajectoryVisualizer if available, otherwise use legacy marker system
133 if (trajectoryVisualizer != nullptr)
134 {
135 RCLCPP_INFO_STREAM(
136 getLogger(),
137 "[" << getName() << "] Setting trajectory visualization using CpTrajectoryVisualizer.");
138 trajectoryVisualizer->setTrajectory(this->endEffectorTrajectory_, "trajectory");
139 }
140 else
141 {
142 RCLCPP_INFO_STREAM(
143 getLogger(), "[" << getName()
144 << "] Creating markers (legacy mode - consider adding "
145 "CpTrajectoryVisualizer component).");
146 this->createMarkers();
147 }
148
149 moveit_msgs::msg::RobotTrajectory computedTrajectory;
150
151 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] Computing joint space trajectory.");
152
153 auto errorcode = computeJointSpaceTrajectory(computedTrajectory);
154
155 bool trajectoryGenerationSuccess = errorcode == ComputeJointTrajectoryErrorCode::SUCCESS;
156
157 CpTrajectoryHistory * trajectoryHistory;
158 this->requiresComponent(trajectoryHistory);
159
160 if (!trajectoryGenerationSuccess)
161 {
162 RCLCPP_INFO_STREAM(
163 getLogger(), "[" << this->getName() << "] Incorrect trajectory. Posting failure event.");
164 if (trajectoryHistory != nullptr)
165 {
166 moveit_msgs::msg::MoveItErrorCodes error;
167 error.val = moveit_msgs::msg::MoveItErrorCodes::NO_IK_SOLUTION;
168 trajectoryHistory->pushTrajectory(this->getName(), computedTrajectory, error);
169 }
170
172 this->postFailureEvent();
173
175 {
176 this->postJointDiscontinuityEvent(computedTrajectory);
177 }
179 {
180 this->postIncorrectInitialStateEvent(computedTrajectory);
181 }
182 return;
183 }
184 else
185 {
186 if (trajectoryHistory != nullptr)
187 {
188 moveit_msgs::msg::MoveItErrorCodes error;
189 error.val = moveit_msgs::msg::MoveItErrorCodes::SUCCESS;
190 trajectoryHistory->pushTrajectory(this->getName(), computedTrajectory, error);
191 }
192
193 this->executeJointSpaceTrajectory(computedTrajectory);
194 }
195
196 // handle finishing events
197 }
198
199 // onExit removed - requiresComponent() during state disposal causes deadlock
200 // Components and markers are automatically cleaned up when state is destroyed
201 // If manual cleanup needed in future, use empty onExit like CbMoveJoints
202 virtual void onExit() override {}
203
204protected:
206 moveit_msgs::msg::RobotTrajectory & computedJointTrajectory)
207 {
208 // Try to use CpJointSpaceTrajectoryPlanner component (preferred)
209 CpJointSpaceTrajectoryPlanner * trajectoryPlanner = nullptr;
210 this->requiresComponent(
211 trajectoryPlanner, smacc2::ComponentRequirement::SOFT); // Optional component
212
213 if (trajectoryPlanner != nullptr)
214 {
215 // Use component-based trajectory planner (preferred)
216 RCLCPP_INFO(
217 getLogger(),
218 "[CbMoveEndEffectorTrajectory] Using CpJointSpaceTrajectoryPlanner component for IK "
219 "trajectory generation");
220
222 if (tipLink_ && !tipLink_->empty())
223 {
224 options.tipLink = *tipLink_;
225 }
227 {
229 }
230
231 auto result = trajectoryPlanner->planFromWaypoints(endEffectorTrajectory_, options);
232
233 if (result.success)
234 {
235 computedJointTrajectory = result.trajectory;
236 RCLCPP_INFO(
237 getLogger(),
238 "[CbMoveEndEffectorTrajectory] IK trajectory generation succeeded (via "
239 "CpJointSpaceTrajectoryPlanner)");
241 }
242 else
243 {
244 computedJointTrajectory = result.trajectory; // Still return partial trajectory
245 RCLCPP_WARN(
246 getLogger(),
247 "[CbMoveEndEffectorTrajectory] IK trajectory generation failed (via "
248 "CpJointSpaceTrajectoryPlanner): %s",
249 result.errorMessage.c_str());
250
251 // Map error codes
252 switch (result.errorCode)
253 {
258 default:
260 }
261 }
262 }
263 else
264 {
265 // Fallback to legacy IK trajectory generation
266 RCLCPP_WARN(
267 getLogger(),
268 "[CbMoveEndEffectorTrajectory] CpJointSpaceTrajectoryPlanner component not available, "
269 "using legacy IK trajectory generation (consider adding CpJointSpaceTrajectoryPlanner "
270 "component)");
271
272 // LEGACY IMPLEMENTATION (keep for backward compatibility)
273 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] getting current state.. waiting");
274
275 auto currentState = cpMoveGroup_->moveGroupClientInterface->getCurrentState(100);
276 auto groupname = cpMoveGroup_->moveGroupClientInterface->getName();
277
278 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] getting joint names");
279 auto currentjointnames =
280 currentState->getJointModelGroup(groupname)->getActiveJointModelNames();
281
282 if (!tipLink_ || *tipLink_ == "")
283 {
284 tipLink_ = cpMoveGroup_->moveGroupClientInterface->getEndEffectorLink();
285 }
286
287 std::vector<double> jointPositions;
288 currentState->copyJointGroupPositions(groupname, jointPositions);
289
290 std::vector<std::vector<double>> trajectory;
291 std::vector<rclcpp::Duration> trajectoryTimeStamps;
292
293 trajectory.push_back(jointPositions);
294 trajectoryTimeStamps.push_back(rclcpp::Duration(0s));
295
296 auto & first = endEffectorTrajectory_.front();
297 rclcpp::Time referenceTime(first.header.stamp);
298
299 std::vector<int> discontinuityIndexes;
300
301 int ikAttempts = 4;
302 for (size_t k = 0; k < this->endEffectorTrajectory_.size(); k++)
303 {
304 auto & pose = this->endEffectorTrajectory_[k];
305 auto req = std::make_shared<moveit_msgs::srv::GetPositionIK::Request>();
306
307 req->ik_request.ik_link_name = *tipLink_;
308 req->ik_request.robot_state.joint_state.name = currentjointnames;
309 req->ik_request.robot_state.joint_state.position = jointPositions;
310 req->ik_request.group_name = groupname;
311 req->ik_request.avoid_collisions = true;
312 req->ik_request.pose_stamped = pose;
313
314 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] IK request: " << k << " " << *req);
315
316 auto resfut = iksrv_->async_send_request(req);
317 auto status = resfut.wait_for(3s);
318
319 if (status == std::future_status::ready)
320 {
321 auto & prevtrajpoint = trajectory.back();
322 auto res = resfut.get();
323
324 std::stringstream ss;
325 for (size_t j = 0; j < res->solution.joint_state.position.size(); j++)
326 {
327 auto & jointname = res->solution.joint_state.name[j];
328 auto it = std::find(currentjointnames.begin(), currentjointnames.end(), jointname);
329 if (it != currentjointnames.end())
330 {
331 int index = std::distance(currentjointnames.begin(), it);
332 jointPositions[index] = res->solution.joint_state.position[j];
333 ss << jointname << "(" << index << "): " << jointPositions[index] << std::endl;
334 }
335 }
336
337 // Continuity check
338 size_t jointindex = 0;
339 int discontinuityJointIndex = -1;
340 double discontinuityDeltaJointIndex = -1;
341 double deltajoint;
342
343 bool check = k > 0 || !allowInitialTrajectoryStateJointDiscontinuity_ ||
345 !(*allowInitialTrajectoryStateJointDiscontinuity_));
346 if (check)
347 {
348 for (jointindex = 0; jointindex < jointPositions.size(); jointindex++)
349 {
350 deltajoint = jointPositions[jointindex] - prevtrajpoint[jointindex];
351 if (fabs(deltajoint) > 0.3)
352 {
353 discontinuityDeltaJointIndex = deltajoint;
354 discontinuityJointIndex = jointindex;
355 }
356 }
357 }
358
359 if (ikAttempts > 0 && discontinuityJointIndex != -1)
360 {
361 k--;
362 ikAttempts--;
363 continue;
364 }
365 else
366 {
367 bool discontinuity = false;
368 if (ikAttempts == 0)
369 {
370 discontinuityIndexes.push_back(k);
371 discontinuity = true;
372 }
373
374 ikAttempts = 4;
375
376 if (discontinuity && discontinuityJointIndex != -1)
377 {
378 std::stringstream ss;
379 ss << "Traj[" << k << "/" << endEffectorTrajectory_.size() << "] "
380 << currentjointnames[discontinuityJointIndex]
381 << " IK discontinuity : " << discontinuityDeltaJointIndex << std::endl
382 << "prev joint value: " << prevtrajpoint[discontinuityJointIndex] << std::endl
383 << "current joint value: " << jointPositions[discontinuityJointIndex] << std::endl;
384
385 ss << std::endl;
386 for (size_t ji = 0; ji < jointPositions.size(); ji++)
387 {
388 ss << currentjointnames[ji] << ": " << jointPositions[ji] << std::endl;
389 }
390
391 for (size_t kindex = 0; kindex < trajectory.size(); kindex++)
392 {
393 ss << "[" << kindex << "]: " << trajectory[kindex][discontinuityJointIndex]
394 << std::endl;
395 }
396
397 if (k == 0)
398 {
399 ss
400 << "This is the first posture of the trajectory. Maybe the robot initial posture "
401 "is "
402 "not coincident to the initial posture of the generated joint trajectory."
403 << std::endl;
404 }
405
406 RCLCPP_ERROR_STREAM(getLogger(), ss.str());
407
408 trajectory.push_back(jointPositions);
409 rclcpp::Duration durationFromStart = rclcpp::Time(pose.header.stamp) - referenceTime;
410 trajectoryTimeStamps.push_back(durationFromStart);
411 continue;
412 }
413 else
414 {
415 trajectory.push_back(jointPositions);
416 rclcpp::Duration durationFromStart = rclcpp::Time(pose.header.stamp) - referenceTime;
417 trajectoryTimeStamps.push_back(durationFromStart);
418
419 RCLCPP_DEBUG_STREAM(getLogger(), "IK solution: " << res->solution.joint_state);
420 RCLCPP_DEBUG_STREAM(getLogger(), "trajpoint: " << std::endl << ss.str());
421 }
422 }
423 }
424 else
425 {
426 RCLCPP_ERROR_STREAM(getLogger(), "[" << getName() << "] wrong IK call");
427 }
428 }
429
430 computedJointTrajectory.joint_trajectory.joint_names = currentjointnames;
431 int i = 0;
432 for (auto & p : trajectory)
433 {
434 if (i == 0) // Skip current state
435 {
436 i++;
437 continue;
438 }
439
440 trajectory_msgs::msg::JointTrajectoryPoint jp;
441 jp.positions = p;
442 jp.time_from_start = trajectoryTimeStamps[i];
443 computedJointTrajectory.joint_trajectory.points.push_back(jp);
444 i++;
445 }
446
447 if (discontinuityIndexes.size())
448 {
449 if (discontinuityIndexes[0] == 0)
451 else
453 }
454
456 }
457 }
458
460 const moveit_msgs::msg::RobotTrajectory & computedJointTrajectory)
461 {
462 RCLCPP_INFO_STREAM(getLogger(), "[" << this->getName() << "] Executing joint trajectory");
463
464 // Try to use CpTrajectoryExecutor component (preferred)
465 CpTrajectoryExecutor * trajectoryExecutor = nullptr;
466 this->requiresComponent(
467 trajectoryExecutor, smacc2::ComponentRequirement::SOFT); // Optional component
468
469 bool executionSuccess = false;
470
471 if (trajectoryExecutor != nullptr)
472 {
473 // Use component-based trajectory executor (preferred)
474 RCLCPP_INFO(
475 getLogger(),
476 "[CbMoveEndEffectorTrajectory] Using CpTrajectoryExecutor component for execution");
477
478 ExecutionOptions execOptions;
479 execOptions.trajectoryName = this->getName();
480
481 auto execResult = trajectoryExecutor->execute(computedJointTrajectory, execOptions);
482 executionSuccess = execResult.success;
483
484 if (executionSuccess)
485 {
486 RCLCPP_INFO(
487 getLogger(),
488 "[CbMoveEndEffectorTrajectory] Execution succeeded (via CpTrajectoryExecutor)");
489 }
490 else
491 {
492 RCLCPP_WARN(
493 getLogger(),
494 "[CbMoveEndEffectorTrajectory] Execution failed (via CpTrajectoryExecutor): %s",
495 execResult.errorMessage.c_str());
496 }
497 }
498 else
499 {
500 // Fallback to legacy direct execution
501 RCLCPP_WARN(
502 getLogger(),
503 "[CbMoveEndEffectorTrajectory] CpTrajectoryExecutor component not available, using legacy "
504 "execution (consider adding CpTrajectoryExecutor component)");
505
506 auto executionResult =
507 this->cpMoveGroup_->moveGroupClientInterface->execute(computedJointTrajectory);
508 executionSuccess = (executionResult == moveit_msgs::msg::MoveItErrorCodes::SUCCESS);
509
510 RCLCPP_INFO(
511 getLogger(), "[CbMoveEndEffectorTrajectory] Execution %s (legacy mode)",
512 executionSuccess ? "succeeded" : "failed");
513 }
514
515 // Post events
516 if (executionSuccess)
517 {
518 RCLCPP_INFO_STREAM(getLogger(), "[" << this->getName() << "] motion execution succeeded");
520 this->postSuccessEvent();
521 }
522 else
523 {
525 this->postFailureEvent();
526 }
527 }
528
529 virtual void generateTrajectory()
530 {
531 // bypass current trajectory, overridden in derived classes
532 // this->endEffectorTrajectory_ = ...
533 }
534
535 virtual void createMarkers()
536 {
537 tf2::Transform localdirection;
538 localdirection.setIdentity();
539 localdirection.setOrigin(tf2::Vector3(0.05, 0, 0));
540 auto frameid = this->endEffectorTrajectory_.front().header.frame_id;
541
542 for (auto & pose : this->endEffectorTrajectory_)
543 {
544 visualization_msgs::msg::Marker marker;
545 marker.header.frame_id = frameid;
546 marker.header.stamp = getNode()->now();
547 marker.ns = "trajectory";
548 marker.id = this->beahiorMarkers_.markers.size();
549 marker.type = visualization_msgs::msg::Marker::ARROW;
550 marker.action = visualization_msgs::msg::Marker::ADD;
551 marker.scale.x = 0.005;
552 marker.scale.y = 0.01;
553 marker.scale.z = 0.01;
554 marker.color.a = 0.8;
555 marker.color.r = 1.0;
556 marker.color.g = 0;
557 marker.color.b = 0;
558
559 geometry_msgs::msg::Point start, end;
560 start.x = 0;
561 start.y = 0;
562 start.z = 0;
563
564 tf2::Transform basetransform;
565 tf2::fromMsg(pose.pose, basetransform);
566 // tf2::Transform endarrow = localdirection * basetransform;
567
568 end.x = localdirection.getOrigin().x();
569 end.y = localdirection.getOrigin().y();
570 end.z = localdirection.getOrigin().z();
571
572 marker.pose.position = pose.pose.position;
573 marker.pose.orientation = pose.pose.orientation;
574 marker.points.push_back(start);
575 marker.points.push_back(end);
576
577 beahiorMarkers_.markers.push_back(marker);
578 }
579 }
580
581 std::vector<geometry_msgs::msg::PoseStamped> endEffectorTrajectory_;
582
584
585 visualization_msgs::msg::MarkerArray beahiorMarkers_;
586
588 std::string globalFrame, tf2::Stamped<tf2::Transform> & currentEndEffectorTransform)
589 {
590 // Use CpTfListener component for transform lookups
591 CpTfListener * tfListener = nullptr;
592 this->requiresComponent(tfListener, smacc2::ComponentRequirement::SOFT); // Optional component
593
594 try
595 {
596 if (!tipLink_ || *tipLink_ == "")
597 {
598 tipLink_ = this->cpMoveGroup_->moveGroupClientInterface->getEndEffectorLink();
599 }
600
601 if (tfListener != nullptr)
602 {
603 // Use component-based TF listener (preferred)
604 auto transformOpt = tfListener->lookupTransform(globalFrame, *tipLink_, rclcpp::Time(0));
605 if (transformOpt)
606 {
607 tf2::fromMsg(transformOpt.value(), currentEndEffectorTransform);
608 }
609 else
610 {
611 RCLCPP_ERROR_STREAM(
612 getLogger(), "[" << getName() << "] Failed to lookup transform from " << *tipLink_
613 << " to " << globalFrame);
614 }
615 }
616 else
617 {
618 // Fallback to legacy TF2 usage if component not available
619 RCLCPP_WARN_STREAM(
620 getLogger(), "[" << getName()
621 << "] CpTfListener component not available, using legacy TF2 (consider "
622 "adding CpTfListener component)");
623 tf2_ros::Buffer tfBuffer(getNode()->get_clock());
624 tf2_ros::TransformListener tfListenerLegacy(tfBuffer);
625
626 tf2::fromMsg(
627 tfBuffer.lookupTransform(globalFrame, *tipLink_, rclcpp::Time(0), rclcpp::Duration(10s)),
628 currentEndEffectorTransform);
629 }
630 }
631 catch (const std::exception & e)
632 {
633 RCLCPP_ERROR_STREAM(
634 getLogger(), "[" << getName() << "] Exception in getCurrentEndEffectorPose: " << e.what());
635 }
636 }
637
638private:
640 {
641 RCLCPP_INFO_STREAM(getLogger(), "[" << getName() << "] initializing ros");
642
643 auto nh = this->getNode();
644
645 // Only create marker publisher for legacy mode (when CpTrajectoryVisualizer is not used)
646 markersPub_ = nh->create_publisher<visualization_msgs::msg::MarkerArray>(
647 "trajectory_markers", rclcpp::QoS(1));
648
649 iksrv_ = nh->create_client<moveit_msgs::srv::GetPositionIK>("/compute_ik");
650 }
651
652 rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr markersPub_;
653
654 rclcpp::Client<moveit_msgs::srv::GetPositionIK>::SharedPtr iksrv_;
655
656 std::mutex m_mutex_;
657
658 std::function<void(moveit_msgs::msg::RobotTrajectory &)> postJointDiscontinuityEvent;
659 std::function<void(moveit_msgs::msg::RobotTrajectory &)> postIncorrectInitialStateEvent;
660
661 std::function<void()> postMotionExecutionFailureEvents;
662
663 bool autocleanmarkers = false;
664};
665} // 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)
CbMoveEndEffectorTrajectory(const std::vector< geometry_msgs::msg::PoseStamped > &endEffectorTrajectory, std::optional< std::string > tipLink=std::nullopt)
rclcpp::Client< moveit_msgs::srv::GetPositionIK >::SharedPtr iksrv_
Component for joint space trajectory generation from Cartesian waypoints.
JointTrajectoryResult planFromWaypoints(const std::vector< geometry_msgs::msg::PoseStamped > &waypoints, const JointTrajectoryOptions &options={})
Compute joint space trajectory from Cartesian waypoints.
std::shared_ptr< moveit::planning_interface::MoveGroupInterface > moveGroupClientInterface
Component for shared TF2 transform management across all behaviors.
std::optional< geometry_msgs::msg::TransformStamped > lookupTransform(const std::string &target_frame, const std::string &source_frame, const rclcpp::Time &time=rclcpp::Time(0))
Thread-safe transform lookup.
Component for centralized trajectory execution.
ExecutionResult execute(const moveit_msgs::msg::RobotTrajectory &trajectory, const ExecutionOptions &options={})
Execute a trajectory synchronously.
void pushTrajectory(std::string name, const moveit_msgs::msg::RobotTrajectory &trajectory, moveit_msgs::msg::MoveItErrorCodes result)
Component for visualizing trajectories as RViz markers.
void setTrajectory(const std::vector< geometry_msgs::msg::PoseStamped > &poses, const std::string &ns="trajectory")
Set trajectory to visualize.
virtual rclcpp::Logger getLogger() const
virtual rclcpp::Node::SharedPtr getNode() const
void requiresComponent(SmaccComponentType *&storage, ComponentRequirement requirementType=ComponentRequirement::SOFT)
std::string demangleSymbol()
Configuration options for trajectory execution.
std::optional< std::string > trajectoryName
Configuration options for joint space trajectory planning.