TOPP2-RA¶
TOPP2-RA is the recommended first solver to try. It solves a time-optimal second-order problem and returns the node profile
\[a(s) = \dot{s}^2.\]
The example uses an analytic Lissajous path, samples it on N stations, adds
symmetric velocity and acceleration limits, and solves with boundary values
a(0)=0 and a(1)=0.
Key Calls¶
Path.from_evaluator_2nd wraps a Python object that provides
evaluate_up_to_2nd(s) -> (q, dq, ddq). Robot.set_q_from_path_2nd stores
those derivatives in the constraint buffer. Robot.add_velocity_limits and
Robot.add_acceleration_limits convert physical axis limits into sampled
path-domain rows.
After solving, s_to_t_topp2 computes the arrival-time profile and
t_to_s_topp2_uniform samples s(t) at a controller-friendly time step.
Runnable Example¶
1"""Use TOPP2-RA to convert a JAX-defined path into a second-order time-optimal trajectory.
2
3The example constrains each axis by velocity and acceleration limits in
4``[-1, 1]``, then converts the returned ``a(s)`` profile into ``t(s)`` and
5uniform ``s(t)`` samples.
6"""
7
8import numpy as np
9
10import copp_py as copp
11
12
13def main() -> None:
14 try:
15 import jax
16 import jax.numpy as jnp
17 except ImportError as exc:
18 raise SystemExit(
19 'Install JAX to run this example: python -m pip install "copp-py[jax]"'
20 ) from exc
21
22 jax.config.update("jax_enable_x64", True)
23
24 dim = 3
25 n = 1001
26 dt = 1.0e-3
27
28 # 1) Define q(s). Path.from_jax differentiates it up to third order.
29 def q_fn(s):
30 freq = jnp.array([2.0 * jnp.pi, 3.0 * jnp.pi, 5.0 * jnp.pi], dtype=jnp.float64)
31 phase = jnp.array([0.0, 0.3, 0.7], dtype=jnp.float64)
32 return jnp.sin(freq * s + phase)
33
34 path = copp.Path.from_jax(q_fn, 0.0, 1.0)
35 s = np.linspace(0.0, 1.0, n, dtype=np.float64)
36
37 # 2) Build robot constraints (3-axis), then apply symmetric limits
38 # velocity/acceleration = [-1, 1].
39 robot = copp.Robot(dim, capacity=n)
40 robot.append_s(s)
41 robot.set_q_from_path_2nd(path, 0, n)
42
43 upper = np.ones(dim, dtype=np.float64)
44 lower = -upper
45 robot.add_velocity_limits(upper, lower, start_idx_s=0, length=n)
46 robot.add_acceleration_limits(upper, lower, start_idx_s=0, length=n)
47
48 # 3) Solve TOPP2-RA with boundary values a(0) = 0 and a(1) = 0.
49 problem = copp.solver.topp2_ra.Problem(
50 robot.constraints,
51 idx_s_interval=(0, n - 1),
52 a_boundary=(0.0, 0.0),
53 )
54 options = copp.solver.topp2_ra.Options()
55 a_ra = copp.solver.topp2_ra.solve(problem, options)
56
57 # 4) Post-process TOPP2-RA results: a(s) -> t(s) -> s(t).
58 t_final, t_s = copp.interpolation.s_to_t_topp2(s, a_ra, 0.0)
59 s_t = copp.interpolation.t_to_s_topp2_uniform(
60 s,
61 a_ra,
62 t_s,
63 dt,
64 t0=0.0,
65 include_final=True,
66 )
67
68 # 5) Print the tutorial summary.
69 print("TOPP2-RA done.")
70 print(f"dim = {dim}, N = {n}")
71 print(f"t_final = {t_final:.6f} s")
72 print(f"a_profile.len() = {len(a_ra)}")
73 print(f"s(t) samples = {len(s_t)}")
74
75
76if __name__ == "__main__":
77 main()