diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000000..1b2e1b63c4
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,44 @@
+{
+ "name": "moveit2_tutorials_devcontainer",
+ "dockerComposeFile": ["../.docker/docker-compose.yml"],
+ "service": "gpu",
+ "shutdownAction": "stopCompose",
+ "workspaceFolder": "/root/ws_moveit",
+ "remoteUser": "root",
+ "mounts": [
+ "source=/tmp/.X11-unix,target=/tmp/.X11-unix,type=bind,consistency=cached",
+ "source=${localEnv:HOME}/.Xauthority,target=/home/root/.Xauthority,type=bind",
+ "source=${localWorkspaceFolder},target=/root/ws_moveit/src/moveit2_tutorials,type=bind,consistency=cached"
+ ],
+ "remoteEnv": {
+ "ROS_DISTRO": "jazzy"
+ },
+ "containerEnv": {
+ "RCUTILS_COLORIZED_OUTPUT": "1",
+ "RCUTILS_CONSOLE_OUTPUT_FORMAT": "[{severity} {time}] [{name}]: {message} ({function_name}() at {file_name}:{line_number})",
+ "DISPLAY": "${localEnv:DISPLAY}",
+ "LIBGL_ALWAYS_SOFTWARE": "1"
+ },
+ "initializeCommand": "bash .devcontainer/initializeCommand.sh",
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "ms-python.python",
+ "ms-python.autopep8",
+ "skellock.just",
+ "cheshirekow.cmake-format",
+ "ms-vscode.cmake-tools",
+ "redhat.vscode-xml",
+ "redhat.vscode-yaml",
+ "llvm-vs-code-extensions.vscode-clangd",
+ "lextudio.restructuredtext-pack",
+ "bbenoist.Doxygen",
+ "ms-vscode.live-server",
+ "esbenp.prettier-vscode",
+ "EditorConfig.EditorConfig",
+ "DavidAnson.vscode-markdownlint",
+ "mine.cpplint"
+ ]
+ }
+ }
+}
diff --git a/.devcontainer/initializeCommand.sh b/.devcontainer/initializeCommand.sh
new file mode 100644
index 0000000000..1b1091d923
--- /dev/null
+++ b/.devcontainer/initializeCommand.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+xhost +local:root >/dev/null 2>&1
diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml
index a0f1b3e2c2..d1de774f8b 100644
--- a/.docker/docker-compose.yml
+++ b/.docker/docker-compose.yml
@@ -1,28 +1,31 @@
# Example command:
-# Humble on a NVIDIA system:
-# DOCKER_IMAGE=humble-humble-tutorial-source docker compose run gpu
# Rolling without discrete graphics:
# DOCKER_IMAGE=main-rolling-tutorial-source compose run cpu
+x-common: &common-service
+ #image: moveit/moveit2:main-jazzy-tutorial-source
+ image: d130s/ros:moveit2-main-jazzy-tutorial-source # TEMPORARY dev
+ privileged: true
+ network_mode: host
+ command: /bin/bash
+ tty: true
+ volumes:
+ - /tmp/.X11-unix:/tmp/.X11-unix
+ - $XAUTHORITY:/root/.Xauthority
+ environment:
+ &common-env
+ QT_X11_NO_MITSHM: 1
+ DISPLAY: $DISPLAY
+
services:
cpu:
- image: moveit/moveit2:${DOCKER_IMAGE}
- container_name: moveit2_container
- privileged: true
- network_mode: host
- command: /bin/bash
- volumes:
- - /tmp/.X11-unix:/tmp/.X11-unix
- - $XAUTHORITY:/root/.Xauthority
- environment:
- QT_X11_NO_MITSHM: 1
- DISPLAY: $DISPLAY
+ <<: *common-service
+ container_name: moveit2_container_cpu
+ profiles:
+ - cpu
gpu:
- image: moveit/moveit2:${DOCKER_IMAGE}
- container_name: moveit2_container
- privileged: true
- network_mode: host
- command: /bin/bash
+ <<: *common-service
+ container_name: moveit2_container_gpu
deploy:
resources:
reservations:
@@ -30,11 +33,7 @@ services:
- driver: nvidia
count: 1
capabilities: [gpu]
- volumes:
- - /tmp/.X11-unix:/tmp/.X11-unix
- - $XAUTHORITY:/root/.Xauthority
environment:
- QT_X11_NO_MITSHM: 1
- DISPLAY: $DISPLAY
+ <<: *common-env
NVIDIA_VISIBLE_DEVICES: all
NVIDIA_DRIVER_CAPABILITIES: all
diff --git a/.github/upstream_jazzy.repos b/.github/upstream_jazzy.repos
new file mode 100644
index 0000000000..489db06273
--- /dev/null
+++ b/.github/upstream_jazzy.repos
@@ -0,0 +1,8 @@
+repositories:
+ # MoveIt msgs containing POLYLINE planner message definitions (e.g. smoothness_level).
+ # Required on pre-Kilted ROS distros (e.g. Jazzy) where debian packages lack these definitions.
+ # TODO: Remove once moveit_msgs with POLYLINE fields is released into targeted distros.
+ moveit_msgs:
+ type: git
+ url: https://github.com/moveit/moveit_msgs.git
+ version: 2.7.2
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 4ad001b68d..11df8df687 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -32,7 +32,7 @@ jobs:
UNDERLAY: ${{ endsWith(matrix.env.IMAGE, '-source') && '/root/ws_moveit/install' || '' }}
UPSTREAM_WORKSPACE: .github/upstream.repos
BEFORE_SETUP_UPSTREAM_WORKSPACE: git config --global --add safe.directory "*"
- AFTER_SETUP_UPSTREAM_WORKSPACE: vcs pull $BASEDIR/upstream_ws/src
+ AFTER_SETUP_UPSTREAM_WORKSPACE: IMAGE="${{ matrix.env.IMAGE }}"; for f in ".github/upstream_${IMAGE}.repos" ".github/upstream_${IMAGE%-*}.repos"; do test -f "$f" && vcs import $BASEDIR/upstream_ws/src < "$f"; done; vcs pull $BASEDIR/upstream_ws/src
TARGET_CMAKE_ARGS: -DCMAKE_BUILD_TYPE=Release
CCACHE_DIR: ${{ github.workspace }}/.ccache
BASEDIR: ${{ github.workspace }}/.work
@@ -51,7 +51,7 @@ jobs:
restore-keys: ${{ env.CACHE_PREFIX }}
env:
GHA_CACHE_SAVE: always
- CACHE_PREFIX: upstream_ws-${{ matrix.env.IMAGE }}-${{ hashFiles('.github/upstream.repos') }}
+ CACHE_PREFIX: upstream_ws-${{ matrix.env.IMAGE }}-${{ hashFiles('.github/upstream.repos', '.github/upstream_*.repos') }}
# The target directory cache doesn't include the source directory because
# that comes from the checkout. See "prepare target_ws for cache" task below
- name: cache target_ws
diff --git a/doc/how_to_guides/pilz_industrial_motion_planner/launch/pilz_moveit.launch.xml b/doc/how_to_guides/pilz_industrial_motion_planner/launch/pilz_moveit.launch.xml
new file mode 100644
index 0000000000..f3d5298117
--- /dev/null
+++ b/doc/how_to_guides/pilz_industrial_motion_planner/launch/pilz_moveit.launch.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/how_to_guides/pilz_industrial_motion_planner/pilz_industrial_motion_planner.rst b/doc/how_to_guides/pilz_industrial_motion_planner/pilz_industrial_motion_planner.rst
index 54f4ee6cc3..c367305d96 100644
--- a/doc/how_to_guides/pilz_industrial_motion_planner/pilz_industrial_motion_planner.rst
+++ b/doc/how_to_guides/pilz_industrial_motion_planner/pilz_industrial_motion_planner.rst
@@ -39,7 +39,7 @@ strictest combination of all limits as a common limit for all joints.
Cartesian Limits
----------------
-For Cartesian trajectory generation (LIN/CIRC), the planner needs
+For Cartesian trajectory generation (LIN/CIRC/POLYLINE), the planner needs
information about the maximum speed in 3D Cartesian space. Namely,
translational/rotational velocity/acceleration/deceleration need to be
set in the node parameters like this:
@@ -60,6 +60,9 @@ rotational trapezoidal shapes. The rotational acceleration is
calculated as ``max_trans_acc / max_trans_vel * max_rot_vel``
(and for deceleration accordingly).
+You can set different max_trans_vel using ``MotionPlanRequest`` by setting
+the field ``max_cartesian_speed`` and the field ``cartesian_speed_limited_link``.
+
Planning Interface
------------------
@@ -70,7 +73,7 @@ are explained below.
For a general introduction on how to fill a ``MotionPlanRequest``, see
:ref:`move_group_interface-planning-to-pose-goal`.
-You can specify ``"PTP"``, ``"LIN"`` or ``"CIRC"`` as the ``planner_id`` of the ``MotionPlanRequest``.
+You can specify ``"PTP"``, ``"LIN"``, ``"CIRC"`` or ``"POLYLINE"`` as the ``planner_id`` of the ``MotionPlanRequest``.
The PTP motion command
----------------------
@@ -144,6 +147,7 @@ LIN Input Parameters in ``moveit_msgs::MotionPlanRequest``
translational/rotational velocity
- ``max_acceleration_scaling_factor``: scaling factor of maximal
Cartesian translational/rotational acceleration/deceleration
+- ``max_cartesian_speed``: maximal Cartesian speed for this motion (replaces the max_trans_vel parameter)
- ``start_state/joint_state/(name, position and velocity``: joint
name/position of the start state.
- ``goal_constraints`` (goal can be given in joint space or Cartesian
@@ -215,6 +219,7 @@ CIRC Input Parameters in ``moveit_msgs::MotionPlanRequest``
translational/rotational velocity
- ``max_acceleration_scaling_factor``: scaling factor of maximal
Cartesian translational/rotational acceleration/deceleration
+- ``max_cartesian_speed``: maximal Cartesian speed for this motion (replaces the max_trans_vel parameter)
- ``start_state/joint_state/(name, position and velocity``: joint
name/position of the start state.
- ``goal_constraints`` (goal can be given in joint space or Cartesian
@@ -260,6 +265,50 @@ CIRC Planning Result in ``moveit_msg::MotionPlanResponse``
- ``group_name``: the name of the planning group
- ``error_code/val``: error code of the motion planning
+The POLYLINE motion command
+---------------------------
+
+.. note::
+
+ The ``POLYLINE`` planner and its parameters (e.g. ``smoothness_level`` in `moveit_msgs/msg/MotionPlanRequest `_) are natively available in binary releases for ROS 2 Kilted and newer. On earlier ROS 2 distributions (such as Jazzy), building ``moveit_msgs`` (version >= 2.7.2) from source is required.
+
+This planner generates a continuous Cartesian trajectory passing through a sequence of waypoints.
+The generated path is a combination of linear segments connected by
+circular arcs to smooth the transitions between consecutive lines. A smoothness level scaling factor is used to
+determine smoothness by scaling the max possible rounding radius.
+The planner automatically filters waypoints that are positioned too closely;
+however, the user must ensure the angle between consecutive segments is
+sufficiently large to avoid violating minimum rounding constraints.
+The planner uses Cartesian limits to generate a trapezoidal
+velocity profile in Cartesian space. This planner only accepts a
+start state with zero velocity. The planning result is a joint trajectory. The user needs to adapt
+the Cartesian velocity/acceleration scaling factor if the motion plan fails due to violation of cartesian limits.
+The planner will fail if three or more consecutive waypoints are collinear.
+
+POLYLINE Input Parameters in ``moveit_msgs::MotionPlanRequest``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``planner_id``: ``"POLYLINE"``
+- ``group_name``: the name of the planning group
+- ``max_velocity_scaling_factor``: scaling factor of maximal Cartesian
+ translational/rotational velocity
+- ``max_acceleration_scaling_factor``: scaling factor of maximal
+ Cartesian translational/rotational acceleration/deceleration
+- ``max_cartesian_speed``: maximal Cartesian speed for this motion (replaces the max_trans_vel parameter)
+- ``start_state/joint_state/(name, position and velocity``: joint
+ name/position of the start state.
+- ``path_constraints``: a list of position constraints to be followed in
+ Cartesian space. Each waypoint is defined as a ``moveit_msgs::msg::PositionConstraint``
+
+ - ``path_constraints/position_constraints/constraint_region/primitive_poses/point``:
+ pose of the point
+- ``goal_constraints`` (the last goal point)
+ - ``goal_constraints/position_constraints/header/frame_id``:
+ frame this data is associated with
+ - ``goal_constraints/position_constraints/link_name``: target
+ link name
+- ``smoothness_level``: scaling factor for the maximum possible rounding radius
+
Examples
--------
@@ -424,8 +473,8 @@ is used instead:
}
The
-:codedir:`pilz_sequence.cpp file `
-creates two target poses that will be reached sequentially.
+:codedir:`pilz_sequence.cpp file `
+creates a sequence of three commands.
::
@@ -435,6 +484,8 @@ creates two target poses that will be reached sequentially.
// Set pose blend radius
item1.blend_radius = 0.1;
+ // Set max_cartesian_speed (overwrite the max_trans_vel)
+ item1.req.max_cartesian_speed = 0.5;
// MotionSequenceItem configuration
item1.req.group_name = PLANNING_GROUP;
@@ -461,7 +512,7 @@ creates two target poses that will be reached sequentially.
msg.pose.orientation.w = 0.0;
return msg;
} ();
- item1.req.goal_constraints.push_back(kinematic_constraints::constructGoalConstraints("panda_link8", target_pose_item1));
+ item1.req.goal_constraints.push_back(kinematic_constraints::constructGoalConstraints("panda_hand", target_pose_item1));
The service client needs to be initialized:
@@ -485,6 +536,7 @@ Then, the request is created:
auto service_request = std::make_shared();
service_request->request.items.push_back(item1);
service_request->request.items.push_back(item2);
+ service_request->request.items.push_back(item3);
Once the service call is completed, the method ``future.wait_for(timeout_duration)`` blocks until
a specified ``timeout_duration`` has elapsed or the result becomes available, whichever comes
@@ -546,9 +598,9 @@ The future response is read with the ``future.get()`` method.
return 0;
}
-In this case, the planned trajectory is drawn. Here is a comparison of a blend radius of 0 and 0.1 for the first and second trajectory, respectively.
+In this case, the planned trajectory is drawn. Here is a comparison of a blend radius of 0, 0.1, 0.05 for the first, second, and third trajectory (line, line, ellipse), respectively.
-.. figure:: trajectory_comparison.jpeg
+.. figure:: trajectory_comparison.png
:alt: trajectory comparison
Action interface
@@ -588,6 +640,7 @@ Then, the request is created:
moveit_msgs::msg::MotionSequenceRequest sequence_request;
sequence_request.items.push_back(item1);
sequence_request.items.push_back(item2);
+ sequence_request.items.push_back(item3);
The goal and planning options are configured. A goal response callback and result callback can be included as well.
diff --git a/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_move_group.cpp b/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_move_group.cpp
index 6e58f9abcc..93e1218f00 100644
--- a/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_move_group.cpp
+++ b/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_move_group.cpp
@@ -170,6 +170,74 @@ int main(int argc, char* argv[])
plan_and_execute("[CIRC] Turn");
}
+ {
+ auto const goal_pose = [] {
+ geometry_msgs::msg::PoseStamped msg;
+ msg.header.frame_id = "world";
+ msg.pose.orientation.x = 1.0;
+ msg.pose.orientation.y = 0.0;
+ msg.pose.orientation.z = 0.0;
+ msg.pose.orientation.w = 0.0;
+ msg.pose.position.x = 0.3;
+ msg.pose.position.y = 0.0;
+ msg.pose.position.z = 0.6;
+ return msg;
+ }();
+ // Move back home using the PTP planner.
+ move_group_interface.setPlannerId("PTP");
+ move_group_interface.setPoseTarget(goal_pose, "panda_hand");
+ plan_and_execute("[PTP] Return");
+ }
+ // Clear Marker to show polyline path clearly
+ moveit_visual_tools.deleteAllMarkers();
+ moveit_visual_tools.trigger();
+ {
+ // Move in a heart-shaped Cartesian path using the POLYLINE.
+ move_group_interface.setPlannerId("POLYLINE");
+ // To prevent failure due to exceeding cartesian limits.
+ move_group_interface.setMaxVelocityScalingFactor(0.05);
+ move_group_interface.setMaxAccelerationScalingFactor(0.05);
+ // Define Heart Shape Parametric Equation to collect waypoints
+ auto heart_eq = [](double t) -> Eigen::Vector3d {
+ Eigen::Vector3d p;
+ p.x() = 0.3 + 0.0068 * (17 + 13 * std::cos(t) - 5 * std::cos(2 * t) - 2 * std::cos(3 * t) - cos(4 * t));
+ p.y() = 0.0068 * (16.0 * std::pow(std::sin(t), 3));
+ p.z() = 0.6;
+ return p;
+ };
+
+ geometry_msgs::msg::PoseStamped msg;
+ msg.header.frame_id = "world";
+ moveit_msgs::msg::Constraints path_constraints;
+ const int num_points = 40;
+ for (int i = 0; i <= num_points; ++i)
+ {
+ // Get waypoint from parametric equation of heart shape
+ double t = M_PI + 2.0 * i * M_PI / float(num_points);
+ Eigen::Vector3d p = heart_eq(t);
+ msg.pose.position.x = p.x();
+ msg.pose.position.y = p.y();
+ msg.pose.position.z = p.z();
+ msg.pose.orientation.x = 1.0;
+ msg.pose.orientation.y = 0.0;
+ msg.pose.orientation.z = 0.0;
+ msg.pose.orientation.w = 0.0;
+ // Add waypoint as position constraint
+ moveit_msgs::msg::PositionConstraint pos_constraint;
+ pos_constraint.header.frame_id = "world";
+ pos_constraint.link_name = "panda_hand";
+ pos_constraint.constraint_region.primitive_poses.resize(1);
+ pos_constraint.constraint_region.primitive_poses[0] = msg.pose;
+ pos_constraint.weight = 1.0;
+ path_constraints.position_constraints.push_back(pos_constraint);
+ }
+ // Set all position constraints as path constraints
+ move_group_interface.setPathConstraints(path_constraints);
+ // Set the last pose as goal
+ move_group_interface.setPoseTarget(msg, "panda_hand");
+ plan_and_execute("[POLYLINE] Heart");
+ }
+
{
// Move back home using the PTP planner.
move_group_interface.setPlannerId("PTP");
diff --git a/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_sequence.cpp b/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_sequence.cpp
index 45f210b80d..a458420a79 100644
--- a/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_sequence.cpp
+++ b/doc/how_to_guides/pilz_industrial_motion_planner/src/pilz_sequence.cpp
@@ -71,7 +71,9 @@ int main(int argc, char** argv)
moveit_msgs::msg::MotionSequenceItem item1;
// Set pose blend radius
- item1.blend_radius = 0.1;
+ item1.blend_radius = 0.05;
+ // Set max_cartesian_speed (overwrite the max_trans_vel)
+ item1.req.max_cartesian_speed = 0.5;
// MotionSequenceItem configuration
item1.req.group_name = PLANNING_GROUP;
@@ -92,22 +94,22 @@ int main(int argc, char** argv)
msg.pose.position.x = 0.3;
msg.pose.position.y = -0.2;
msg.pose.position.z = 0.6;
- msg.pose.orientation.x = 1.0;
- msg.pose.orientation.y = 0.0;
+ msg.pose.orientation.x = 0.924;
+ msg.pose.orientation.y = -0.380;
msg.pose.orientation.z = 0.0;
msg.pose.orientation.w = 0.0;
return msg;
}();
- item1.req.goal_constraints.push_back(
- kinematic_constraints::constructGoalConstraints("panda_link8", target_pose_item1));
+ item1.req.goal_constraints.push_back(kinematic_constraints::constructGoalConstraints("panda_hand", target_pose_item1));
// ----- Motion Sequence Item 2
// Create a MotionSequenceItem
moveit_msgs::msg::MotionSequenceItem item2;
// Set pose blend radius
- // For the last pose, it must be 0!
- item2.blend_radius = 0.0;
+ item2.blend_radius = 0.05;
+ // set max_cartesian_speed (overwrite the max_trans_vel)
+ item2.req.max_cartesian_speed = 1.2;
// MotionSequenceItem configuration
item2.req.group_name = PLANNING_GROUP;
@@ -123,14 +125,71 @@ int main(int argc, char** argv)
msg.pose.position.x = 0.3;
msg.pose.position.y = -0.2;
msg.pose.position.z = 0.8;
- msg.pose.orientation.x = 1.0;
- msg.pose.orientation.y = 0.0;
+ msg.pose.orientation.x = 0.924;
+ msg.pose.orientation.y = -0.380;
msg.pose.orientation.z = 0.0;
msg.pose.orientation.w = 0.0;
return msg;
}();
- item2.req.goal_constraints.push_back(
- kinematic_constraints::constructGoalConstraints("panda_link8", target_pose_item2));
+ item2.req.goal_constraints.push_back(kinematic_constraints::constructGoalConstraints("panda_hand", target_pose_item2));
+
+ // -------- Motion Sequence Items 3
+ moveit_msgs::msg::MotionSequenceItem item3;
+
+ // MotionSequenceItem configuration
+ item3.req.group_name = PLANNING_GROUP;
+ item3.req.planner_id = "POLYLINE";
+ item3.req.allowed_planning_time = 5.0;
+ item3.req.max_velocity_scaling_factor = 0.1;
+ item3.req.max_acceleration_scaling_factor = 0.1;
+
+ // For the last pose, the blending radius must be 0!
+ item3.blend_radius = 0.0;
+ // Set max_cartesian_speed (overwrite the max_trans_vel)
+ item3.req.max_cartesian_speed = 0.1;
+
+ // Extract waypoints along an ellipse
+ auto ellipse = [](double t) -> Eigen::Vector3d {
+ Eigen::Vector3d p;
+ p.x() = 0.3;
+ p.y() = -0.2 + 0.2 * std::sin(t);
+ p.z() = 0.6 + 0.2 * std::cos(t);
+ return p;
+ };
+
+ geometry_msgs::msg::PoseStamped msg;
+ msg.header.frame_id = "world";
+ moveit_msgs::msg::Constraints path_constraints;
+ const int num_points = 20;
+ for (int i = 0; i <= num_points; ++i)
+ {
+ // Get waypoint from parametric equation of ellipse
+ double t = i * (M_PI / 2.0) / float(num_points);
+ Eigen::Vector3d p = ellipse(t);
+ msg.pose.position.x = p.x();
+ msg.pose.position.y = p.y();
+ msg.pose.position.z = p.z();
+ msg.pose.orientation.x = std::cos(M_PI / 8.0 - t / 4.0);
+ msg.pose.orientation.y = -std::sin(M_PI / 8.0 - t / 4.0);
+ msg.pose.orientation.z = 0.0;
+ msg.pose.orientation.w = 0.0;
+ // Add waypoint as position constraint
+ moveit_msgs::msg::PositionConstraint pos_constraint;
+ pos_constraint.header.frame_id = "world";
+ pos_constraint.link_name = "panda_hand";
+ pos_constraint.constraint_region.primitive_poses.resize(1);
+ pos_constraint.constraint_region.primitive_poses[0] = msg.pose;
+ pos_constraint.weight = 1.0;
+ item3.req.path_constraints.position_constraints.push_back(pos_constraint);
+ }
+ // Set smoothness_level if supported by the message definition (e.g. ROS 2 Kilted+ or moveit_msgs >= 2.7.2)
+ auto set_smoothness_level = [](auto& req, double level) {
+ if constexpr (requires { req.smoothness_level = level; })
+ {
+ req.smoothness_level = level;
+ }
+ };
+ set_smoothness_level(item3.req, 0.3);
// [ --------------------------------------------------------------- ]
// [ ------------------ MoveGroupSequence Service ------------------ ]
@@ -151,6 +210,7 @@ int main(int argc, char** argv)
auto service_request = std::make_shared();
service_request->request.items.push_back(item1);
service_request->request.items.push_back(item2);
+ service_request->request.items.push_back(item3);
// Call the service and process the result
auto service_future = service_client->async_send_request(service_request);
@@ -223,6 +283,7 @@ int main(int argc, char** argv)
moveit_msgs::msg::MotionSequenceRequest sequence_request;
sequence_request.items.push_back(item1);
sequence_request.items.push_back(item2);
+ sequence_request.items.push_back(item3);
// Create action goal
auto goal_msg = MoveGroupSequence::Goal();
diff --git a/doc/how_to_guides/pilz_industrial_motion_planner/trajectory_comparison.jpeg b/doc/how_to_guides/pilz_industrial_motion_planner/trajectory_comparison.jpeg
deleted file mode 100644
index b0821bc895..0000000000
Binary files a/doc/how_to_guides/pilz_industrial_motion_planner/trajectory_comparison.jpeg and /dev/null differ
diff --git a/doc/how_to_guides/pilz_industrial_motion_planner/trajectory_comparison.png b/doc/how_to_guides/pilz_industrial_motion_planner/trajectory_comparison.png
new file mode 100644
index 0000000000..1a4d7545b9
Binary files /dev/null and b/doc/how_to_guides/pilz_industrial_motion_planner/trajectory_comparison.png differ