Skip to content

Commit 1b9c2b1

Browse files
committed
add: examples index
Signed-off-by: Zach Harel <zach.harel42@gmail.com>
1 parent 06814ec commit 1b9c2b1

4 files changed

Lines changed: 315 additions & 9 deletions

File tree

.idea/workspace.xml

Lines changed: 12 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.vitepress/sidebar/control.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ export default [
1818
{
1919
text: "Examples",
2020
items: [
21+
{
22+
text: "Index",
23+
link: "/control/examples/",
24+
},
2125
{
2226
text: "Linear Slides",
2327
link: "/control/examples/slides",

src/control/examples/index.md

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# Examples
2+
3+
This section contains some examples on creating and using NextControl `ControlSystem`s.
4+
5+
::: tabs key:code
6+
7+
== Kotlin
8+
9+
```kotlin
10+
/**
11+
* Basic Example: Simple position PID controller
12+
*
13+
* This example demonstrates how to create a basic position PID controller
14+
* for a simple system like a motor.
15+
*/
16+
fun basicPositionPIDExample() {
17+
// Create a simple position PID controller with kP=0.5
18+
val controller = ControlSystem.builder()
19+
.posPid(0.5) // Only using proportional control
20+
.build()
21+
22+
// Set the goal position to 100
23+
controller.goal = KineticState(position = 100.0)
24+
25+
// In a loop (simulated here), you would:
26+
val currentPosition = 50.0 // This would come from a sensor
27+
val power = controller.calculate(KineticState(position = currentPosition))
28+
29+
// Apply power to your motor
30+
println("Power to apply: $power")
31+
32+
// Check if we've reached the goal
33+
val withinTolerance = controller.isWithinTolerance(KineticState(position = 2.0))
34+
println("Within tolerance: $withinTolerance")
35+
}
36+
37+
/**
38+
* Intermediate Example: Velocity control with feedforward
39+
*
40+
* This example demonstrates a velocity controller with PID feedback
41+
* and basic feedforward for better performance.
42+
*/
43+
fun velocityControlWithFeedforwardExample() {
44+
// Create a velocity controller with PID and feedforward
45+
val controller = ControlSystem.builder()
46+
.velPid(kP = 0.1, kI = 0.01, kD = 0.05) // Velocity PID
47+
.basicFF(kV = 0.02, kS = 0.01) // Basic feedforward with velocity and static friction compensation
48+
.build()
49+
50+
// Set the goal velocity to 500 units per second
51+
controller.goal = KineticState(velocity = 500.0)
52+
53+
// In a loop (simulated here), you would:
54+
val currentState = KineticState(
55+
position = 1000.0, // Current position
56+
velocity = 450.0 // Current velocity
57+
)
58+
59+
val power = controller.calculate(currentState)
60+
61+
// Apply power to your motor
62+
println("Power to apply: $power")
63+
}
64+
65+
/**
66+
* Advanced Example: Elevator control with gravity compensation
67+
*
68+
* This example demonstrates a more complex control system for an elevator
69+
* with gravity compensation, filtering, and smooth interpolation.
70+
*/
71+
fun elevatorControlExample() {
72+
// Create an elevator controller with position PID, gravity compensation, filtering, and interpolation
73+
val controller = controlSystem {
74+
// Position PID with higher derivative gain to prevent oscillation
75+
posPid(kP = 0.8, kI = 0.0, kD = 0.2)
76+
77+
// Elevator feedforward with gravity compensation
78+
elevatorFF(kG = 0.05, kV = 0.01, kA = 0.002, kS = 0.01)
79+
80+
// Low-pass filter for position measurements to reduce noise
81+
posFilter { lowPass(alpha = 0.2) }
82+
}
83+
84+
// Set the goal position for the elevator
85+
controller.goal = KineticState(position = 1500.0)
86+
87+
// In a loop (simulated here), you would:
88+
val currentState = KineticState(
89+
position = 1200.0, // Current position
90+
velocity = 100.0 // Current velocity
91+
)
92+
93+
val power = controller.calculate(currentState)
94+
95+
// Apply power to your elevator motor
96+
println("Power to apply: $power")
97+
98+
// Check if we've reached the goal with tight tolerance
99+
val tolerance = KineticState(position = 5.0, velocity = 10.0)
100+
val withinTolerance = controller.isWithinTolerance(tolerance)
101+
println("Within tolerance: $withinTolerance")
102+
}
103+
104+
/**
105+
* Expert Example: Arm control with angle wrapping and custom components
106+
*
107+
* This example demonstrates a sophisticated control system for a robot arm
108+
* with angle wrapping, custom filters, and complex motion profiles.
109+
*/
110+
fun robotArmControlExample() {
111+
// Create a sophisticated arm controller
112+
val controller = controlSystem {
113+
// Angular PID for position control with angle wrapping (in radians)
114+
angular(AngleType.RADIANS) {
115+
posPid(kP = 1.2, kI = 0.05, kD = 0.3)
116+
}
117+
118+
// Arm feedforward with gravity compensation
119+
armFF(kG = 0.12, kV = 0.02, kA = 0.005, kS = 0.03)
120+
121+
// adding multiple filters chains them together
122+
posFilter {
123+
lowPass(alpha = 0.3)
124+
lowPass(alpha = 0.5)
125+
}
126+
127+
velFilter {
128+
lowPass(alpha = 0.2)
129+
}
130+
131+
// EMA interpolator for smooth motion
132+
emaInterpolator(FirstOrderEMAParameters(
133+
alpha = 0.2,
134+
startingReference = KineticState(
135+
position = 0.0,
136+
velocity = 0.0,
137+
acceleration = 0.0
138+
)
139+
))
140+
}
141+
142+
// Set the goal position in radians
143+
controller.goal = KineticState(position = Math.PI / 2) // 90 degrees
144+
145+
// In a loop (simulated here), you would:
146+
val currentState = KineticState(
147+
position = Math.PI / 4, // Current position (45 degrees)
148+
velocity = 0.1 // Current velocity
149+
)
150+
151+
val power = controller.calculate(currentState)
152+
153+
// Apply power to your arm motor
154+
println("Power to apply: $power")
155+
156+
// Reset the controller if needed (e.g., after an emergency stop)
157+
controller.reset()
158+
}
159+
```
160+
161+
== Java
162+
163+
```java
164+
/**
165+
* Basic Example: Simple position PID controller
166+
* <p>
167+
* This example demonstrates how to create a basic position PID controller
168+
* for a simple system like a motor.
169+
*/
170+
public static void basicPositionPIDExample() {
171+
// Create a simple position PID controller with kP=0.5
172+
ControlSystem controller = ControlSystem.builder()
173+
.posPid(0.5) // Only using proportional control
174+
.build();
175+
176+
// Set the goal position to 100
177+
controller.setGoal(new KineticState(100.0, 0.0, 0.0));
178+
179+
// In a loop (simulated here), you would:
180+
double currentPosition = 50.0; // This would come from a sensor
181+
double power = controller.calculate(new KineticState(currentPosition, 0.0, 0.0));
182+
183+
// Apply power to your motor
184+
System.out.println("Power to apply: " + power);
185+
186+
// Check if we've reached the goal
187+
boolean withinTolerance = controller.isWithinTolerance(new KineticState(2.0, 0.0, 0.0));
188+
System.out.println("Within tolerance: " + withinTolerance);
189+
}
190+
191+
/**
192+
* Intermediate Example: Velocity control with feedforward
193+
* <p>
194+
* This example demonstrates a velocity controller with PID feedback
195+
* and basic feedforward for better performance.
196+
*/
197+
public static void velocityControlWithFeedforwardExample() {
198+
// Create a velocity controller with PID and feedforward
199+
ControlSystem controller = ControlSystem.builder()
200+
.velPid(0.1, 0.01, 0.05) // Velocity PID with kP=0.1, kI=0.01, kD=0.05
201+
.basicFF(0.02, 0.0, 0.01) // Basic feedforward with kV=0.02, kA=0.0, kS=0.01
202+
.build();
203+
204+
// Set the goal velocity to 500 units per second
205+
controller.setGoal(new KineticState(0.0, 500.0, 0.0));
206+
207+
// In a loop (simulated here), you would:
208+
// Create a KineticState with current position and velocity
209+
KineticState currentState = new KineticState(1000.0, 450.0, 0.0);
210+
211+
double power = controller.calculate(currentState);
212+
213+
// Apply power to your motor
214+
System.out.println("Power to apply: " + power);
215+
}
216+
217+
/**
218+
* Advanced Example: Elevator control with gravity compensation.
219+
* <p>
220+
* This example demonstrates a more complex control system for an elevator
221+
* with gravity compensation, filtering, and smooth interpolation.
222+
*/
223+
public static void elevatorControlExample() {
224+
// Create an elevator controller with position PID, gravity compensation, and filtering
225+
ControlSystem controller = ControlSystem.builder()
226+
// Position PID with higher derivative gain to prevent oscillation
227+
.posPid(0.8, 0.0, 0.2)
228+
// Elevator feedforward with gravity compensation
229+
.elevatorFF(0.05, 0.01, 0.002, 0.01)
230+
// Low-pass filter for position measurements to reduce noise
231+
.posFilter(filterBuilder -> filterBuilder.lowPass(0.2))
232+
.build();
233+
234+
235+
// Set the goal position for the elevator
236+
controller.setGoal(new KineticState(1500.0, 0.0, 0.0));
237+
238+
// In a loop (simulated here), you would:
239+
KineticState currentState = new KineticState(1200.0, 100.0, 0.0);
240+
241+
double power = controller.calculate(currentState);
242+
243+
// Apply power to your elevator motor
244+
System.out.println("Power to apply: " + power);
245+
246+
// Check if we've reached the goal with tight tolerance
247+
KineticState tolerance = new KineticState(5.0, 10.0, 0.0);
248+
boolean withinTolerance = controller.isWithinTolerance(tolerance);
249+
System.out.println("Within tolerance: " + withinTolerance);
250+
}
251+
252+
/**
253+
* Expert Example: Arm control with angle wrapping and custom components
254+
* <p>
255+
* This example demonstrates a sophisticated control system for a robot arm
256+
* with angle wrapping, custom filters, and complex motion profiles.
257+
*/
258+
public static void robotArmControlExample() {
259+
// Create a sophisticated arm controller
260+
ControlSystemBuilder builder = ControlSystem.builder();
261+
262+
// Angular PID for position control with angle wrapping (in radians)
263+
builder.angular(AngleType.RADIANS, feedbackBuilder -> feedbackBuilder.posPid(1.2, 0.05, 0.3));
264+
265+
// Arm feedforward with gravity compensation
266+
builder.armFF(0.12, 0.02, 0.005, 0.03); // kG=0.12, kV=0.02, kA=0.005, kS=0.03
267+
268+
// Chained filters for better noise reduction
269+
builder.posFilter(filterBuilder ->
270+
filterBuilder.lowPass(0.3)
271+
.lowPass(0.5)
272+
);
273+
274+
builder.velFilter(filterBuilder -> filterBuilder.lowPass(0.2));
275+
276+
// Custom interpolator for smooth motion
277+
FirstOrderEMAParameters emaParams = new FirstOrderEMAParameters(0.2, new KineticState());
278+
builder.emaInterpolator(emaParams);
279+
280+
ControlSystem controller = builder.build();
281+
282+
// Set the goal position in radians
283+
controller.setGoal(new KineticState(Math.PI / 2, 0.0, 0.0)); // 90 degrees
284+
285+
// In a loop (simulated here), you would:
286+
KineticState currentState = new KineticState(Math.PI / 4, 0.1, 0.0); // 45 degrees
287+
288+
double power = controller.calculate(currentState);
289+
290+
// Apply power to your arm motor
291+
System.out.println("Power to apply: " + power);
292+
293+
// Reset the controller if needed (e.g., after an emergency stop)
294+
// controller.reset();
295+
}
296+
```
297+
298+
:::

src/control/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
NextControl is our robust control library that uses the "Four Elements"
44
of control systems to model actuated systems.
55

6-
Some examples are featured in the [examples folder](/control/examples],
6+
Some examples are featured in the [examples folder](/examples/),
77
and all components have thorough javadoc/kdoc documentation.
88

99
## The Four Elements

0 commit comments

Comments
 (0)