Skip to content

Commit e1fd4a7

Browse files
committed
add trapezoidal profile tests
1 parent bcee015 commit e1fd4a7

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# Copyright (c) FIRST and other WPILib contributors.
2+
# Open Source Software; you can modify and/or share it under the terms of
3+
# the WPILib BSD license file in the root directory of this project.
4+
5+
6+
import math
7+
8+
from wpimath.trajectory import TrapezoidProfile
9+
10+
kDt = 0.01 # 10 ms
11+
12+
13+
def expect_near_units(val1, val2, eps):
14+
assert abs(val1 - val2) <= eps
15+
16+
17+
def expect_lt_or_near_units(val1, val2, eps):
18+
if val1 <= val2:
19+
assert val1 <= val2
20+
else:
21+
expect_near_units(val1, val2, eps)
22+
23+
24+
def test_reaches_goal():
25+
constraints = TrapezoidProfile.Constraints(1.75, 0.75)
26+
goal = TrapezoidProfile.State(3.0, 0.0)
27+
state = TrapezoidProfile.State()
28+
29+
profile = TrapezoidProfile(constraints)
30+
for _ in range(450):
31+
state = profile.calculate(kDt, state, goal)
32+
assert state == goal
33+
34+
35+
def test_pos_continuous_under_vel_change():
36+
constraints = TrapezoidProfile.Constraints(1.75, 0.75)
37+
goal = TrapezoidProfile.State(12.0, 0.0)
38+
profile = TrapezoidProfile(constraints)
39+
state = profile.calculate(kDt, TrapezoidProfile.State(), goal)
40+
41+
last_pos = state.position
42+
for i in range(1600):
43+
if i == 400:
44+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
45+
profile = TrapezoidProfile(constraints)
46+
47+
state = profile.calculate(kDt, state, goal)
48+
estimated_vel = (state.position - last_pos) / kDt
49+
50+
if i >= 400:
51+
expect_lt_or_near_units(estimated_vel, constraints.maxVelocity, 1e-4)
52+
assert state.velocity <= constraints.maxVelocity
53+
54+
last_pos = state.position
55+
56+
assert state == goal
57+
58+
59+
def test_backwards():
60+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
61+
goal = TrapezoidProfile.State(-2.0, 0.0)
62+
state = TrapezoidProfile.State()
63+
profile = TrapezoidProfile(constraints)
64+
65+
for _ in range(400):
66+
state = profile.calculate(kDt, state, goal)
67+
assert state == goal
68+
69+
70+
def test_switch_goal_in_middle():
71+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
72+
goal = TrapezoidProfile.State(-2.0, 0.0)
73+
state = TrapezoidProfile.State()
74+
profile = TrapezoidProfile(constraints)
75+
76+
for _ in range(200):
77+
state = profile.calculate(kDt, state, goal)
78+
assert state != goal
79+
80+
goal = TrapezoidProfile.State(0.0, 0.0)
81+
profile = TrapezoidProfile(constraints)
82+
for _ in range(550):
83+
state = profile.calculate(kDt, state, goal)
84+
assert state == goal
85+
86+
87+
def test_top_speed():
88+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
89+
goal = TrapezoidProfile.State(4.0, 0.0)
90+
state = TrapezoidProfile.State()
91+
profile = TrapezoidProfile(constraints)
92+
93+
for _ in range(200):
94+
state = profile.calculate(kDt, state, goal)
95+
expect_near_units(constraints.maxVelocity, state.velocity, 1e-4)
96+
97+
profile = TrapezoidProfile(constraints)
98+
for _ in range(2000):
99+
state = profile.calculate(kDt, state, goal)
100+
assert state == goal
101+
102+
103+
def test_timing_to_current():
104+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
105+
goal = TrapezoidProfile.State(2.0, 0.0)
106+
state = TrapezoidProfile.State()
107+
profile = TrapezoidProfile(constraints)
108+
109+
for _ in range(400):
110+
state = profile.calculate(kDt, state, goal)
111+
expect_near_units(profile.timeLeftUntil(state.position), 0.0, 0.02)
112+
113+
114+
def test_timing_to_goal():
115+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
116+
goal = TrapezoidProfile.State(2.0, 0.0)
117+
profile = TrapezoidProfile(constraints)
118+
119+
state = profile.calculate(kDt, goal, TrapezoidProfile.State())
120+
predicted_time_left = profile.timeLeftUntil(goal.position)
121+
122+
reached_goal = False
123+
for i in range(400):
124+
state = profile.calculate(kDt, state, goal)
125+
if not reached_goal and state == goal:
126+
assert math.isclose(predicted_time_left, i * kDt, abs_tol=0.25)
127+
reached_goal = True
128+
129+
130+
def test_timing_before_goal():
131+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
132+
goal = TrapezoidProfile.State(2.0, 0.0)
133+
profile = TrapezoidProfile(constraints)
134+
135+
state = profile.calculate(kDt, goal, TrapezoidProfile.State())
136+
predicted_time_left = profile.timeLeftUntil(1.0)
137+
138+
reached_goal = False
139+
for i in range(400):
140+
state = profile.calculate(kDt, state, goal)
141+
if not reached_goal and abs(state.velocity - 1.0) < 1e-4:
142+
assert math.isclose(predicted_time_left, i * kDt, abs_tol=0.02)
143+
reached_goal = True
144+
145+
146+
def test_timing_to_negative_goal():
147+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
148+
goal = TrapezoidProfile.State(-2.0, 0.0)
149+
profile = TrapezoidProfile(constraints)
150+
151+
state = profile.calculate(kDt, goal, TrapezoidProfile.State())
152+
predicted_time_left = profile.timeLeftUntil(goal.position)
153+
154+
reached_goal = False
155+
for i in range(400):
156+
state = profile.calculate(kDt, state, goal)
157+
if not reached_goal and state == goal:
158+
assert math.isclose(predicted_time_left, i * kDt, abs_tol=0.25)
159+
reached_goal = True
160+
161+
162+
def test_timing_before_negative_goal():
163+
constraints = TrapezoidProfile.Constraints(0.75, 0.75)
164+
goal = TrapezoidProfile.State(-2.0, 0.0)
165+
profile = TrapezoidProfile(constraints)
166+
167+
state = profile.calculate(kDt, goal, TrapezoidProfile.State())
168+
predicted_time_left = profile.timeLeftUntil(-1.0)
169+
170+
reached_goal = False
171+
for i in range(400):
172+
state = profile.calculate(kDt, state, goal)
173+
if not reached_goal and abs(state.velocity + 1.0) < 1e-4:
174+
assert math.isclose(predicted_time_left, i * kDt, abs_tol=0.02)
175+
reached_goal = True
176+
177+
178+
def test_initialization_of_current_state():
179+
constraints = TrapezoidProfile.Constraints(1.0, 1.0)
180+
profile = TrapezoidProfile(constraints)
181+
expect_near_units(profile.timeLeftUntil(0.0), 0.0, 1e-10)
182+
expect_near_units(profile.totalTime(), 0.0, 1e-10)

0 commit comments

Comments
 (0)