How we do it is this:
- Pass manipulator commands in as parameters in the script.
a) If you have feedback controlled appendages (for example, the elevator and arm on our 2011 robot), the manipulator commands would be desired positions (see #2 below).
b) If you have an appendage that’s NOT feedback controlled (for example, the roller claw on our 2011 robot), the manipulator command is just the motor command (-1.0 to 1.0)
For feedback controlled appendages:
Put your PID code for closed loop control in PeriodicTasks.vi (see the code samples for an example).
Define global variables for “Desired Position” and “Actual Position” (i.e. set-point and process variable, if you use the lingo defined in LabVIEW).
In your autonomous case structure, set the DesiredPostion global to the parameter being passed in from the script. The PID controller will then control your manipulator in parallel to the autonomous code.
In your autonomous case structure, use abs(DesiredPosition - ActualPosition) as an exit condition IF YOU NEED TO. (That’s why you make ActualPosition a global - so you can use it in the autonomous code as an exit condition if needed.)
The PID in PeriodicTasks.vi can be extremely simple. Just wire DesiredPosition into the setpoint and wire your sensor value (encoder or pot) to the process variable AND the ActualPosition global. Then wire the output of the PID into your manipulator motor “set” block from the WPI library.
So, how should the autonomous side of the code be set up?
With a little thought, it’s not that complicated. In certain cases in the case structure, take the absolute value of the manipulator error (i.e. abs(ActualPosition - DesiredPosition) and when the error drops below a set threshold, then the manipulator porition of the exit condition is TRUE. Use AND logic (or maybe OR logic, depending on what you’re trying to accomplish) with your other exit conditions.
Another question: when would you use the manipulator in the exit condition (and when would you NOT use it)?
Answer: that is always up to you, but here is some guidance.
If your drivetrain continues to move until the exit condition, you should NOT use the manipulator as an exit condition. Primitive #1 (drive straight - constant speed) in the sample code is a good example. If you use the manipulator as an exit, there’s a good chance you’ll go blowing past your desired distance waiting for the arm to finish what it is doing.
If your drivetrain will hold a position (by position, I mean a small spot on the floor), then using the manipulator in the exit condition can be a good idea. Primitive #3 (drive straight, gradual approach) in the sample code is a good example. With primitive #3, if your manipulator isn’t quite finished when you get to your desired distance, the robot will slow down and wait at the desired distance setpoint until the arm finishes. This is safe.
Define a “Hold Position” primitive. Hold Position is a primitive that actively holds the robot’s position using a PID for heading and a PID for distance. It is basically the same code as #3 in the sample code, but the exit is different - usually the exit is time, and the exit condition can be AND’d or OR’d with a manipulator-based exit condition. Hold Position is great for keeping the robot drivetrain still while you score with your manipulator.
One final note: if you plan to use feedback control on your manipulator during autonomous, but do NOT want to use it during teleop, then you can put the PID controllers in autonomousIndependent.vi. I’m assuming that if you’re using feedback control you would want to do it in teleop as well, which is why I suggest putting the PIDs in periodicTasks.vi - that way you can use the same code for both auton and teleop.
If any of this isn’t clear (which it probably isn’t) or there are any more questions, please let me know.