Point-to-Point Motion Planning
PointToPointPathService.Plan (client.point_to_point_path) plans a
collision-free motion through a sequence of goals and saves the result as a
config of type CONFIG_TYPE_P2P_PATH. Read it back with
ConfigService.Get.
Note
PointToPointPathService requires the point_to_point_path license
(Activate Licenses).
Request
Field |
Description |
|---|---|
|
Required. Name under which the planned path is saved. |
|
Required. A saved collision configuration (Collision Configurations). |
|
One of. |
|
One of. |
Result
point_to_point_path.Path (output only):
header: the path name;system_name,tcp_name,collision_config_name;cartesian_waypoints: TCP poses of the goals (always present);joint_waypoints: the planned joint trajectory (present when planning succeeded);tcp_to_attach_object,object_grasp_pose: used when carrying an object.
Planning between joint configurations
From examples/python/point_to_point_path_example.py:
print("Running point-to-point path planning queries...")
def run_plan(path_name, system_name, tcp_name, collision_config_name, joint_waypoints):
req = PointToPointPathRequest(
path_name=path_name,
collision_config_name=collision_config_name,
joint_waypoints=PTPJointWaypoints(
system_name=system_name,
tcp_name=tcp_name,
joint_waypoints=joint_waypoints,
),
)
try:
resp = client.point_to_point_path.stub.Plan(req)
print("")
if (resp.status.code == 0):
print(f"Plan successful")
get_resp = client.config.stub.Get(
TypeNameConfigRequest(name=path_name, type=CONFIG_TYPE_P2P_PATH)
)
if get_resp.status.code == 0 and get_resp.HasField("p2p_path"):
path = get_resp.p2p_path
print(f" Cartesian waypoints ({len(path.cartesian_waypoints)}):")
for i, wp in enumerate(path.cartesian_waypoints):
p = wp.pose.position
q = wp.pose.rotation
print(f" [{i}] pos=({p.x:.4f}, {p.y:.4f}, {p.z:.4f}) "
f"rot=({q.x:.4f}, {q.y:.4f}, {q.z:.4f}, {q.w:.4f})")
print(f" Joint waypoints ({len(path.joint_waypoints)}):")
for i, wp in enumerate(path.joint_waypoints):
joints = ", ".join(f"{v:.4f}" for v in wp.position)
print(f" [{i}] [{joints}]")
else:
print(f" Failed to retrieve path: {get_resp.status.message}")
else:
print(f"Plan failed with status code {resp.status.code}: {resp.status.message}")
except grpc.RpcError as e:
print(f"Plan failed: {e}")
from flexiv.pdk.spatial.waypoint_pb2 import JointWaypoint
import math
kDegToRad = math.pi / 180.0
# 1. No collision
run_plan(
"ptp_path_1", "system_1", "system_1.arm.flange", "default_collision_config",
[
JointWaypoint(position=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]),
JointWaypoint(position=[0.0, -40.0 * kDegToRad, 0.0, 90.0 * kDegToRad, 0.0, 40.0 * kDegToRad, 0.0])
]
)
The example prints grpc.RpcError instead of raising it. Production code
should check both layers; see Error Handling.
Attach an object to the flange (by parenting it to system_1.arm.flange) and
it moves with the robot and is collision-checked along the path. The example
does this with box_4.
Planning between saved system poses
A system pose (scene.TargetWaypoint) stores a TCP name together with a
Cartesian pose and the joint configuration that reaches it. Save poses once,
then plan between them by name. From examples/python/system_pose_example.py:
print("Saving system pose object to the scene...")
system_pose_object = TargetWaypoint(
header=make_header("system_pose_1", parent="system_1"),
tcp_name="system_1.arm.flange",
cartesian=CartesianWaypoint(
pose=fk_pose_1,
),
joint=JointWaypoint(
position=joint_configuration_1
)
)
try:
client.config.stub.Save(SaveConfigRequest(system_pose=system_pose_object))
except grpc.RpcError as e:
print(f"Save system pose object failed: {e}")
print("Running point-to-point path plan using the system pose target waypoints...")
try:
plan_response = client.point_to_point_path.stub.Plan(PointToPointPathRequest(
path_name="ptp_path_system_pose_1",
collision_config_name="default_collision_config",
target_waypoints=PTPTargetWaypoints(
target_waypoint_names=["system_pose_1", "system_pose_2"]
)
))
if plan_response.status.code == 0:
print("Point-to-point path plan successful")
else:
print(f"Point-to-point path plan failed: {plan_response.status.message}")
except grpc.RpcError as e:
print(f"Point-to-point path plan failed: {e}")
C++
examples/cpp/src/point_to_point_path_example.cpp does the same in C++
(kDegToRad is defined in the example as π / 180):
std::cout << "Running point-to-point path planning queries..." << std::endl;
const std::vector<double> home = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
const std::vector<double> clear_goal
= {0.0, -40.0 * kDegToRad, 0.0, 90.0 * kDegToRad, 0.0, 40.0 * kDegToRad, 0.0};
const std::vector<double> box_1_goal = {13.24 * kDegToRad, -69.97 * kDegToRad, 0.06 * kDegToRad,
112.91 * kDegToRad, 1.03 * kDegToRad, 92.89 * kDegToRad, 12.23 * kDegToRad};
// 1. No collision
RunPlan(client, "ptp_path_1", "system_1", "system_1.arm.flange", "default_collision_config",
{home, clear_goal});
// 2. With collision (between system_1.arm and box_1)
RunPlan(client, "ptp_path_2", "system_1", "system_1.arm.flange", "default_collision_config",
{home, box_1_goal});
// 3. With collision (between box_4 and box_1)
RunPlan(client, "ptp_path_3", "system_1", "system_1.arm.flange", "collision_config_without_box_1",
{home, box_1_goal});
// 4. No collision
RunPlan(client, "ptp_path_4", "system_1", "system_1.arm.flange",
"collision_config_without_box_1_and_box_4", {home, box_1_goal});
RunPlan fills the joint waypoints, calls Plan and reads the saved path
back:
void RunPlan(Client& client, const std::string& path_name, const std::string& system_name,
const std::string& tcp_name, const std::string& collision_config_name,
const std::vector<std::vector<double>>& joint_waypoints)
{
flexiv::pdk::point_to_point_path::PointToPointPathRequest request;
request.set_path_name(path_name);
request.set_collision_config_name(collision_config_name);
auto* waypoints = request.mutable_joint_waypoints();
waypoints->set_system_name(system_name);
waypoints->set_tcp_name(tcp_name);
for (const auto& positions : joint_waypoints) {
auto* waypoint = waypoints->add_joint_waypoints();
for (double position : positions) {
waypoint->add_position(position);
}
}
grpc::ClientContext context;
flexiv::pdk::point_to_point_path::PointToPointPathResponse response;
const grpc::Status status = client.point_to_point_path().stub->Plan(&context, request, &response);
if (!status.ok()) {
std::cerr << "Plan failed: " << status.error_message() << std::endl;
return;
}
std::cout << std::endl;
if (response.status().code() == Status::OK) {
std::cout << "Plan successful" << std::endl;
PrintPath(client, path_name);
} else {
std::cout << "Plan failed with status code " << response.status().code() << ": "
<< response.status().message() << std::endl;
}
}
The ROS 2 package in examples/ros builds the same source:
PDK_SERVER_ADDR=192.168.1.100:50052 ros2 run pdk_cpp_examples point_to_point_path_example