I am having a similar problem to the one found in this http://www.chiefdelphi.com/forums/showthread.php?t=114061 thread; I want to be able to run multiple different PID loops from the same subsystem. Does anyone know a relatively modular way to create as many PID loops as you want? I’m not sure if it’s as straightforward as this:
Create a PIDController object, handing it the proper P,I, and D values, as well as instances of the following two classes:
Create a class extending PIDSource and hand it the value of the controller in PIDget()
Create a class extending PIDOutput and have it change some value inside of PIDWrite()
Use the output of the controllers as needed
I’m struggling to find much documentation or examples regarding these classes and methods, and I’m not sure if that’s actually what they do, I’ll admit it’s basically a guess as to what they are. If anyone could let me know if I’m thinking along the right lines or if I’m misunderstanding these functions that would be great. I may need to implement as many as 3 different PID loops to control the same hardware depending on the scenario, some of them combined with others. Thanks.
EDIT: I ended up just wrapping PIDOutput in a class I called PIDHandler which simply returns the output of the controller in a getValue() method as the “output”. I then was able to use those raw outputs in my calculations.
Can you explain what exactly you’re trying to accomplish? There might be a better way then chaining 3 different PIDs.
In that thread the use-case is to have one PID control driving a distance (encoders) and another PID control heading(gyro). They sum nicely by adding/subtracting the heading correction on top of the distance-PID.
Hi ozrien,
To start, I’d like to be able to do pretty much exactly what is described in that thread:
I’d like to drive forward to a setpoint using an encoder (the first input).
I’d like to simultaneously be able to correct that movement for drift using a gyro reading (the second input).
Then, I’d like to be able to stop using that system entirely, and literally switch to using some frontal omni wheels as my output, using a separate encoder on those wheels as my new input (the third possible input).
I apologize for not giving a description of the actual goal in the original post. The biggest thing that I’m interested in knowing is whether or not the way I described in the original post is the actual way PID control with WPILib works. Thanks so much for the help!
Yes your description is correct. Common sensors such as encoder and gyros implement PIDSource, so you would not need to create your own PIDSource unless you want to monkey with the values from them. Since you described a complex output, you would need to implement your own PIDOutput.
Our library does that for years. We combined multiple PID controllers. The goal was to do PID control on a subsystem level, not on a motor level. For example, we have a driveBase.setTarget method that can specify the X, Y, and Turn targets. So on a mecanum drive base, autonomous can set an X, Y position as well as a heading, the robot will execute it. This is achieved by combining three PID controllers, one for X, one for Y and one for TURN. The input sources for X and Y are encoders and gyro for TURN. In fact, our library allows you to combine any PID controllers for the drive base. For example, we used it quite often in FTC where we do line following using driveBase.setTarget by specifying a Y PID controller using Ultrasonic sensor as the PIDInput and light sensor as the TURN PID controller’s PIDInput.
I just want to address items 2 and 3 of this. If you do decide to go your own route. The PIDSource and PIDoutput are small classes that need to be extended. The controller will send the output to the PIDOutput. It will call the PIDWrite(), and so you would presumably use this to write to the motors.
The PIDSource is a bit trickier. The pidGet() method should just return the sensor data. All in all they’re both just wrappers of data that allow the PIDController class a fixed class to interact with. You may also want to just consider anonymous classes. They simplify your overall project structure.