In some cases, you might need to retime geometic paths such the intial and final velocities are non-zero. For instance, suppose you have multiple paths and need to effectively piece them together.
This can be done in TOPP-RA by setting the sd_start
and sd_end
arguments.
The initial and final joint velocities are respectively:
We first randomly choose a joint velocity limit and a joint acceleration limit.
In [4]:
# toppra
import toppra as ta
import toppra.constraint as constraint
import toppra.algorithm as algo
import numpy as np
# misc: for plotting and measuring time
import matplotlib.pyplot as plt
import time
ta.setup_logging()
dof = 2
# Create velocity bounds, then velocity constraint object
vlim_ = np.random.rand(dof) * 20
vlim = np.vstack((-vlim_, vlim_)).T
# Create acceleration bounds, then acceleration constraint object
alim_ = np.random.rand(dof) * 100
alim = np.vstack((-alim_, alim_)).T
pc_vel = constraint.JointVelocityConstraint(vlim)
pc_acc = constraint.JointAccelerationConstraint(
alim, discretization_scheme=constraint.DiscretizationType.Interpolation)
Let us choose a random geometric path with three waypoints.
In [5]:
# Random waypoints used to obtain a random geometric path. Here,
# we use spline interpolation.
np.random.seed(0)
way_pts = np.random.randn(3, dof)
path = ta.SplineInterpolator(np.linspace(0, 1, 3), way_pts, bc_type='not-a-knot')
In [14]:
discretization = np.linspace(0, 1, 100)
plt.plot(discretization, path(discretization, 0), label="p(s): Path position")
plt.scatter(np.linspace(0, 1, 3), way_pts[:, 0])
plt.scatter(np.linspace(0, 1, 3), way_pts[:, 1])
plt.title("p(s) Path position")
plt.show()
Suppose we wish to solve the path parametrization instance so that the initial velocity and final velocity are as below.
In [24]:
qd_start = path(0, 1) * 0.2
qd_final = path(path.duration, 1) * 0.2
print("Initial joint velocity: %s\nFinal joint velocity: %s" % (qd_start, qd_final))
In [37]:
t0 = time.time()
# Setup a parametrization instance, then retime
instance = algo.TOPPRA([pc_vel, pc_acc], path, solver_wrapper='seidel')
jnt_traj, aux_traj, int_data = instance.compute_trajectory(0.2, 0.2, return_data=True)
print("Parameterization time: {:} secs".format(time.time() - t0))
print("Actual initial joint velocity: %s\nActual final joint velocity: %s" % (
jnt_traj(0, 1), jnt_traj(jnt_traj.duration, 1)
))
We can see that the actual initial and final joint velocity equal the values we set earlier. Below the full joint trajectory and velocity are plotted.
In [35]:
ts_sample = np.linspace(0, jnt_traj.get_duration(), 100)
qdds_sample = jnt_traj.evaldd(ts_sample)
qds_sample = jnt_traj.evald(ts_sample)
initial_velocities = path.evald(0) * 0.2
final_velocities = path.evald(path.duration) * 0.2
fig, axs = plt.subplots(1, 2, sharex=True, figsize=[16, 4])
for i in range(dof):
color = "C%d" % i
axs[0].plot(ts_sample, qdds_sample[:, i], label="J{:d}".format(i + 1), c=color)
axs[1].plot(ts_sample, qds_sample[:, i], label="J{:d}".format(i + 1), c=color)
axs[1].scatter([0, jnt_traj.duration],
[initial_velocities[i], final_velocities[i]], c=color)
axs[0].set_xlabel("Time (s)")
axs[0].set_ylabel("Joint acceleration (rad/s^2)")
axs[0].legend()
axs[1].legend()
axs[1].set_xlabel("Time (s)")
axs[1].set_ylabel("Joint velocity (rad/s)")
plt.show()