Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   C/C++ (http://www.chiefdelphi.com/forums/forumdisplay.php?f=183)
-   -   WPILib PID controller object (http://www.chiefdelphi.com/forums/showthread.php?t=72918)

Phoenix Spud 01-25-2009 02:45 PM

WPILib PID controller object
 
Has anyone used the PIDController object? How well did it work? We are looking at implementing the PIDController object and were wondering if anyone had any words of wisdom before we start.

Thanks!

wt200999 01-25-2009 02:56 PM

Re: WPILib PID controller object
 
http://www.chiefdelphi.com/forums/sh...ad.php?t=71781

no example has been posted as far as I know though

Jared Russell 01-25-2009 08:24 PM

Re: WPILib PID controller object
 
I'm not a huge fan of the design paradigm WPI used for their PIDController class (requiring you to implement the PIDSource and PIDOutput interfaces) so I rolled my own. I made it so you call a "calculate()" method synchronously inside your Teleop_Periodic() function, passing in sensor readings and getting output values as well. It just makes more sense to me.

BradAMiller 01-25-2009 08:38 PM

Re: WPILib PID controller object
 
Here's an excerpt from the Users Guide that will publish in an update in the next day or so (the formatting will be better in the document)...

PID controllers are a powerful and widely used implementation of closed loop control. The PIDController class allows for a PID control loop to be created easily and runs the control loop in a separate thread at consistent intervals. The PIDController automatically checks a PIDSource for feedback and writes to a PIDOutput every loop. Sensors suitable for use with PIDController in WPILib are already subclasses of PIDSource. Additional sensors and custom feedback methods are supported through creating new subclasses of PIDSource. Jaguars and Victors are already configured as subclasses of PIDOutput, and custom outputs may also be created by sub-classing PIDOutput.
The following example shows how to create a PIDController to set the position of a turret to a position related to the x-axis on a joystick using a single motor on a Jaguar and a potentiometer for angle feedback. As the joystick X value changes, the motor should drive to a position related to that new value. The PIDController class will ensure that the motion is smooth and stops at the right point.
A potentiometer that turns with the turret will provide feedback of the turret angle. The potentiometer is connected to an analog input and will return values ranging from 0-5V from full clockwise to full counterclockwise motion of the turret. The joystick X-axis returns values from -1.0 to 1.0 for full left to full right. We need to scale the joystick values to match the 0-5V values from the potentiometer. This can be done with the following expression:
Code:

(turretStick.GetX() + 1.0) * 2.5
The scaled value can then be used to change the setpoint of the control loop as the joystick is moved.
The 0.1, 0.001, and 0.0 values are the Proportional, Integral, and Differential coefficients respectively. The AnalogChannel object is already a subclass of PIDSource and returns the voltage as the control value and the Jaguar object is a subclass of PIDOutput.
Code:

        Joystick turretStick(1);
        Jaguar turretMotor(1);
        AnalogChannel turretPot(1);
        PIDController turretControl(0.1, 0.001, 0.0, &turretPot, &turretMotor);
       
        turretControl.Enable();  // start calculating PIDOutput values

        while(IsOperator())
  {
                turretControl.SetSetpoint((turretStick.GetX() + 1.0) * 2.5);
                Wait(.02);                // wait for new joystick values
        }

The PIDController object will automatically (in the background):
• Read the PIDSource object, in this case the turretPot analog input
• Compute the new result value
• Set the PIDOutput object, in this case the turretMotor
This will be repeated periodically in the background by the PIDController. The default repeat rate is 50ms although this can be changed by adding a parameter with the time to the end of the PIDController argument list. See the reference document for details.

Kruuzr 01-26-2009 09:05 AM

Re: WPILib PID controller object
 
Hi Brad...

This approach works great if your source is already pre-defined to be a PID source, but what about the situation ( such as an autotracking turret) where the source value will be an X offset from the middle of the image? Do we have to derive a new PIDSource object and implement any/all needed functions? The effort is compounded by the fact that the image offset is a relative number and would be hard to relate to an absolute turret positioning value.

Steve C

Daniel Jones 01-27-2009 12:19 PM

Re: WPILib PID controller object
 
The update posted last night has many of the sensors in WPILib defined as PIDSources, and Victors and Jaguars as PIDOutputs. Make sure to re-image the cRIO with the latest image before using the update.

heydowns 01-27-2009 01:46 PM

Re: WPILib PID controller object
 
We've been using the PIDController for a few weeks now, with pretty good results. It is very nice in the aspect that all the control happens in the background using a separate task.

The only issue we have noticed is some instability when using the "Debug"/Load to RAM functionality in Workbench. Specifically, when repeatedly unloading and loading subsequently newer versions of our program, sometimes PID tasks will not function properly at all. Other times, the system will refuse to take and run the new image, citing all sorts of resource allocation issues on the console.

This instability may NOT be caused by PIDController usage, however -- we haven't done sufficient testing yet to say one way or another.

We haven't applied the newest update yet -- will likely do that tonight.

Phoenix Spud 02-02-2009 06:46 PM

Re: WPILib PID controller object
 
Quote:

Originally Posted by heydowns (Post 808951)
We haven't applied the newest update yet -- will likely do that tonight.

How did it work once you had both downloaded the code and got the code to rebuild?

heydowns 02-02-2009 11:08 PM

Re: WPILib PID controller object
 
Worked no differently in Update 3 than it did in Update 2.

PIDController, and the Notifier class that it is built on, has some issues if you start deleting them (or letting C++ clean them up if one falls out of scope). Those issues are being worked on, though, and exist in both Update 2 and 3.

sircedric4 02-03-2009 07:36 AM

Re: WPILib PID controller object
 
I have been trying to get the PIDController to work with my robot the last few days without any luck. What we want to do is exactly like the example above. We have a turret and a potentiometer that we want to use and everytime I include the PIDController calls in my program, the cRIO just locks up and goes to its disabled mode. (All my Jaguars and Victors flashing)

I have an error message that was outputted when it crashes, does anyone know what is going on, or what this means?

---------------------------------------------------------------------
eclipse.buildId=20080514-1211
java.version=1.5.0_11
java.vendor=Sun Microsystems Inc.
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US
Command-line arguments: -os win32 -ws win32 -arch x86

Info
Mon Feb 02 17:19:12 CST 2009
Target Exception: Vector 0x600 : Alignment Exception status=0x134CE7C on VxWorks6x_10.29.92.2 in Kernel Task FRC_RobotTask:0xc7b6c8
at pc=0x134CE98 in SetSetpoint()
---------------------------------------------------------------------

For further information I am using the Iterative Robot example and here is the pertinant code: I already have a bunch of code written and like the Iterative over the Simple Robot so any changes from the example code you see, I had to do to get the program to compile.

************************************************** ****
In my .h file:
Jaguar *TurretPIDMotor;
AnalogChannel *TurretPIDPot;
PIDController *turretControl;

In my .cpp file:

In TeleopInit()
Jaguar TurretPIDMotor(3);
AnalogChannel TurretPIDPot(1);
PIDController turretControl(0.1,0.001,0.0, &TurretPIDPot, &TurretPIDMotor);
turretControl.Enable();

In TeleopPeriodic()
TurretGoto is being set from 0-5 using an equation and it is float defined
turretControl->SetSetPoint(TurretGoto);

************************************************** **

I tried putting the stuff in TeleopInit up in the top of the code before any functions are called and where most of my other variables are set or initalized but it wouldn't compile. The code compiles with everything above. I also tried using "turretControl.SetSetPoint" as was shown in the example, but I had to use "->" to get it to compile. (This is an issue I am always having, I don't know what all the ".", "->", "&", "*" and stuff means or why some times one works and one doesn't)

I am almost to the point where I am thinking of just writing my own subroutine so that I can at least know what the code I am using is doing. The PIDController looks like an awesome shortcut though so I would rather try to get it to work first. The above code compiles fine but when I run the robot it doesn't work.

I am using a 10-turn potentiometer as the sensor and a window motor as the motor driving the sensor.

Can anyone give me some pointers or have you already solved this problem and can tell me how you fixed it?

Mike Mahar 02-03-2009 07:48 AM

Re: WPILib PID controller object
 
Quote:

Originally Posted by sircedric4 (Post 813268)
************************************************** ****
In my .h file:
Jaguar *TurretPIDMotor;
AnalogChannel *TurretPIDPot;
PIDController *turretControl;

In my .cpp file:

In TeleopInit()
Jaguar TurretPIDMotor(3);
AnalogChannel TurretPIDPot(1);
PIDController turretControl(0.1,0.001,0.0, &TurretPIDPot, &TurretPIDMotor);
turretControl.Enable();

In TeleopPeriodic()
TurretGoto is being set from 0-5 using an equation and it is float defined
turretControl->SetSetPoint(TurretGoto);

************************************************** **

Change the lines in TeleopInit to:
Code:

turretPIDMotor = new Jaguar(3);
turretPIDPot = new AnalogChannel(1);
turretControl = new PIDController(0,1, 0.001, 0.0, turretPIDPot, turretPIDMotor);
turretControl->Enable();

Note that the ampersands (&) are no long on the 4th and 5th arguments to PIDController.

You were declaring a pointer to all of these classes and then allocating local versions in TeleopInit. The local version were being deleted when TeleopInit returned and the pointers you had in TeleopPeriodic were NULL and causing your program to crash.

Jared Russell 02-03-2009 08:03 AM

Re: WPILib PID controller object
 
Quote:

Originally Posted by sircedric4 (Post 813268)
I have been trying to get the PIDController to work with my robot the last few days without any luck. What we want to do is exactly like the example above. We have a turret and a potentiometer that we want to use and everytime I include the PIDController calls in my program, the cRIO just locks up and goes to its disabled mode. (All my Jaguars and Victors flashing)

I have an error message that was outputted when it crashes, does anyone know what is going on, or what this means?

---------------------------------------------------------------------
eclipse.buildId=20080514-1211
java.version=1.5.0_11
java.vendor=Sun Microsystems Inc.
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US
Command-line arguments: -os win32 -ws win32 -arch x86

Info
Mon Feb 02 17:19:12 CST 2009
Target Exception: Vector 0x600 : Alignment Exception status=0x134CE7C on VxWorks6x_10.29.92.2 in Kernel Task FRC_RobotTask:0xc7b6c8
at pc=0x134CE98 in SetSetpoint()
---------------------------------------------------------------------

For further information I am using the Iterative Robot example and here is the pertinant code: I already have a bunch of code written and like the Iterative over the Simple Robot so any changes from the example code you see, I had to do to get the program to compile.

************************************************** ****
In my .h file:
Jaguar *TurretPIDMotor;
AnalogChannel *TurretPIDPot;
PIDController *turretControl;

In my .cpp file:

In TeleopInit()
Jaguar TurretPIDMotor(3);
AnalogChannel TurretPIDPot(1);
PIDController turretControl(0.1,0.001,0.0, &TurretPIDPot, &TurretPIDMotor);
turretControl.Enable();

In TeleopPeriodic()
TurretGoto is being set from 0-5 using an equation and it is float defined
turretControl->SetSetPoint(TurretGoto);

************************************************** **

I tried putting the stuff in TeleopInit up in the top of the code before any functions are called and where most of my other variables are set or initalized but it wouldn't compile. The code compiles with everything above. I also tried using "turretControl.SetSetPoint" as was shown in the example, but I had to use "->" to get it to compile. (This is an issue I am always having, I don't know what all the ".", "->", "&", "*" and stuff means or why some times one works and one doesn't)

I am almost to the point where I am thinking of just writing my own subroutine so that I can at least know what the code I am using is doing. The PIDController looks like an awesome shortcut though so I would rather try to get it to work first. The above code compiles fine but when I run the robot it doesn't work.

I am using a 10-turn potentiometer as the sensor and a window motor as the motor driving the sensor.

Can anyone give me some pointers or have you already solved this problem and can tell me how you fixed it?

This looks to be a scope issue. You have declared your variables as types "Jaguar *", "AnalogChannel *", and "PIDController *". These are POINTERS to objects of the given class types. Then, in TeleopInit(), you declare NEW variables of type "Jaguar", "AnalogChannel", and "PIDController". These are not pointers, but rather the objects themselves. Since the types are different, you are actually declaring completely different variables in TeleopInit(). And, since they are declared in a function, after the function is done the variables are out of scope and can no longer be used.

In order to have everything work properly, you need to reconcile the differences. Try putting this in TeleopInit():

Code:

In TeleopInit()
TurretPIDMotor = new Jaguar(3);
TurretPIDPot = new AnalogChannel(1);
turretControl = new PIDController(0.1,0.001,0.0, TurretPIDPot, TurretPIDMotor);
turretControl->Enable();

When you have variables of type "class_name *", they are pointers and you must create something for them to point to. Hence, the "new" operator. Now, actual objects (without the *) can have their members referenced with the dot (.) operator. But class pointers have their members referenced with the arrow (->) operator. You have pointers, so we use the arrow.

Also, since everything is now a pointer, you don't need the "&" in front of the two variables you pass to the PIDController constructor. The "&" is like an "anti-pointer". If something is a pointer, putting "&" in front of it will get you the actual object.

Example:

Code:

MyClass* myPointer = new MyClass();
myPointer->SomeFunction(); // Legal
myPointer.SomeFunction(); // Illegal!

MyClass myObject();
myObject->SomeFunction(); // Illegal!
myObject.SomeFunction(); // Legal

(&myPointer).SomeFunction(); // Legal, since (&myPointer) is now an object

Now in TeleopPeriodic, you can use the pointers from the header file to do the following:

Code:

In TeleopPeriodic()
TurretGoto is being set from 0-5 using an equation and it is float defined
turretControl->SetSetpoint(TurretGoto);

Let me know if you have any more problems. Yes, the differences between values, pointers, and references can be very tricky to understand. Try this page for a brief explanation - but know that understanding these sometimes subtle differences takes time!

sircedric4 02-03-2009 08:08 AM

Re: WPILib PID controller object
 
Quote:

You were declaring a pointer to all of these classes and then allocating local versions in TeleopInit. The local version were being deleted when TeleopInit returned and the pointers you had in TeleopPeriodic were NULL and causing your program to crash.
Thanks! I have run into similar problems before when I tried to translate what code supposedly works in the SimpleRobot class examples to work in the IterativeRobot class with header files. Can you point me to some website or something that explains what all these pointers and local versions and such are? I only learned enough C to make the old control system work and that was extremely straightforward but this object oriented stuff for the new system is just hard for an old school VB programmer. I spend all my time fighting nomenclature because I don't understand it instead of programming good stuff.

Anyway, the program compiled with the changes above but I'll have to wait till tonight to see if I'll get the good old crash of death. Thanks again, I owe you a drink of your choice somehow. :-)

Edited:
Wow, as I was typing one thank you, a class on what I was doing wrong showed up! Thanks to Abwehr as well in some instruction. I hope my ignorance helps some other teams out there that are just coding through the monkey-see monkey do steal from examples type of coding I am doing.

Jared Russell 02-03-2009 08:11 AM

Re: WPILib PID controller object
 
Quote:

Originally Posted by sircedric4 (Post 813281)
Thanks! I have run into similar problems before when I tried to translate what code supposedly works in the SimpleRobot class examples to work in the IterativeRobot class with header files. Can you point me to some website or something that explains what all these pointers and local versions and such are? I only learned enough C to make the old control system work and that was extremely straightforward but this object oriented stuff for the new system is just hard for an old school VB programmer. I spend all my time fighting nomenclature because I don't understand it instead of programming good stuff.

Anyway, the program compiled with the changes above but I'll have to wait till tonight to see if I'll get the good old crash of death. Thanks again, I owe you a drink of your choice somehow. :-)

This page is a good start: http://www.cplusplus.com/doc/tutorial/pointers.html

sircedric4 02-04-2009 07:18 AM

Re: WPILib PID controller object
 
Success! Thanks everyone for the tips on what it takes to get the PIDController not to crash when I put it on the cRIO.

I did run into some problems when trying to get the PIDController to drive towards my setpoint. The example from WPI above seemed to indicate I need to set my input to 0-5 for a potentiometer. After banging my head for a while and then figuring out how to output PIDController->GetError() to my dashboard I figured out that it is really looking for 0-1024 at least in my application. If you are having trouble getting your PIDController to make sense to you, you might check to see what numbers it is based on for your application.

Does anyone know what it would take to drive the PIDController based on the averagevoltage of the analog input? Would I set it up like:

turretControl = new PIDController(P,I,D, turretPot->GetAverageVoltage, turretMotor)

Or do I have to do something with the other PIDController sub-classes/functions?


All times are GMT -5. The time now is 09:24 AM.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi