|
| 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 | +::: |
0 commit comments