Go to Post I guess nobody on the GDC has ever been whacked with a pool noodle. - Joe Ross [more]
Home
Go Back   Chief Delphi > Technical > Programming > C/C++
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Reply
Thread Tools Rate Thread Display Modes
  #1   Spotlight this post!  
Unread 22-01-2011, 11:24
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
Encoder as PIDSource

WPILib question.

Is there a reason that the Encoder class doesn't implement the PIDSource interface? I see that it includes the header file but it doesn't actually inherit from PIDSource. Is this just a "TODO" for the lib or is there something fundamental that prevents using an encoder as PIDSource?

I'm asking because I was thinking we might want to use a PIDController to control the position of a "elevator" on our robot. Example, I might have a victor (the PIDOutput) that controls a motor for a chain drive that moves the elevator up and down and an encoder that tells me when i have reached my desired position.
Reply With Quote
  #2   Spotlight this post!  
Unread 22-01-2011, 11:35
Joe Ross's Avatar Unsung FIRST Hero
Joe Ross Joe Ross is offline
Registered User
FRC #0330 (Beachbots)
Team Role: Engineer
 
Join Date: Jun 2001
Rookie Year: 1997
Location: Los Angeles, CA
Posts: 8,576
Joe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond reputeJoe Ross has a reputation beyond repute
Re: Encoder as PIDSource

Maybe the reason it wasn't implemented is because one person what might want to use position as the PIDSource and another would want to use the rate as the PIDSource.
Reply With Quote
  #3   Spotlight this post!  
Unread 22-01-2011, 12:48
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
Re: Encoder as PIDSource

ya that's a good point. Any suggestions on how to control the position of my elevator? I think I want some kind of feedback control. I'd rather not just run the motor at a specific speed for a specific time.
Reply With Quote
  #4   Spotlight this post!  
Unread 22-01-2011, 18:48
BugByte's Avatar
BugByte BugByte is offline
Registered User
AKA: Blair Chisholm
FRC #2537 (Space RAIDers)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: MD
Posts: 46
BugByte is an unknown quantity at this point
Re: Encoder as PIDSource

We just ran into this problem a couple hours ago. Does anyone know how to use the encoder as a PID source?
Reply With Quote
  #5   Spotlight this post!  
Unread 22-01-2011, 19:29
Alexander Meyer Alexander Meyer is offline
Registered User
FRC #2358 (Bearbotics)
Team Role: Mentor
 
Join Date: Jan 2010
Rookie Year: 2010
Location: Lake Zurich, Illinois
Posts: 36
Alexander Meyer is on a distinguished road
Re: Encoder as PIDSource

For position control, the GetRaw() and/or GetDistance() methods will probably provide the data you need. As far as how to do it, a simple subclass of both Encoder and PIDSource that implements the PidGet method should do the trick.
Reply With Quote
  #6   Spotlight this post!  
Unread 23-01-2011, 10:11
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
Re: Encoder as PIDSource

Thanks for the help everyone. I put together the subclass that Alexander described and will post it here in case it helps anyone else. It does compile but hasn't been tested in any way.

PIDEncoder.h

Code:
#include "Encoder.h"
#include "PIDSource.h"

class PIDEncoder : public Encoder, PIDSource
{
public:
	//constructor
	PIDEncoder(UINT32 aSlot, UINT32 aChannel,
			UINT32 bSlot, UINT32 bChannel,
			bool reverseDirection, EncodingType encodingType);
	
	//destructor
	~PIDEncoder();
	
	//virtual from PIDSource
	double PIDGet();
	
private:
	
};

PIDEncoder.cpp

Code:
#include "PIDEncoder.h"

//constructor
PIDEncoder::PIDEncoder(UINT32 aSlot, UINT32 aChannel,
		UINT32 bSlot, UINT32 bChannel,
		bool reverseDirection, EncodingType encodingType) : Encoder(aSlot,aChannel,bSlot,bChannel,reverseDirection,encodingType)
{

}
	
//destructor
PIDEncoder::~PIDEncoder()
{
	
}
	
//virtual from PIDSource
double PIDEncoder::PIDGet()
{
	return this->GetDistance();
}
Reply With Quote
  #7   Spotlight this post!  
Unread 24-01-2011, 08:41
sircedric4's Avatar
sircedric4 sircedric4 is offline
Registered User
AKA: Darren
no team (The SS Prometheus)
Team Role: Mentor
 
Join Date: Jan 2008
Rookie Year: 2006
Location: Lousiana
Posts: 245
sircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond repute
Re: Encoder as PIDSource

Quote:
Originally Posted by jwakeman View Post
Thanks for the help everyone. I put together the subclass that Alexander described and will post it here in case it helps anyone else. It does compile but hasn't been tested in any way. ...
You just described what I want to do this year with our robot. We are also going to use an elevator and we want to use the Distance function of the Encoder for a PIDSource.

I have tried for 2 years to use the PIDSource class to drive our robot a certain distance with the encoders and failed each time. I always run out of time, and I, still after 2 years of beating through the C++ code, do not understand classes completely. I muddle through.

This year me and the students HAVE to figure this out in order for the robot they designed to work correctly, so needless to say, I am very interested in this thread.

How do you use your above PIDEncoder in the robot main code to get the elevator to stop at the correct distance? I see the class and that looks nice but I don't know how to use it. If you want to PM me to keep "spoilers" away that's fine, though honestly I guarantee you there are many students and mentors out there running into the same problems.
Reply With Quote
  #8   Spotlight this post!  
Unread 24-01-2011, 09:34
Alexander Meyer Alexander Meyer is offline
Registered User
FRC #2358 (Bearbotics)
Team Role: Mentor
 
Join Date: Jan 2010
Rookie Year: 2010
Location: Lake Zurich, Illinois
Posts: 36
Alexander Meyer is on a distinguished road
Re: Encoder as PIDSource

cplusplus.com has a good guide if you want to solidify your knowledge of C++.

To use the class that jwakeman posted, you need to make use of PIDController. Basically, initialize a PIDController with P, I, and D values, a PIDSource, and a PIDOutput in your constructor.

So, say you use a victor to drive your elevator and an encoder to measure distance, you might have something like this:

Code:
Victor *ap_elevatorDrive;
PIDEncoder *ap_elevatorEncoder;
PIDController *ap_elevatorControl;

Constructor()
{
    ap_elevatorDrive = new Victor(args);
    ap_elevatorEncoder = new PIDEncoder(args);
    ap_elevatorControl = new PIDController(1.0, 0.0, 0.0, ap_elevatorEncoder, ap_elevatorDrive);
}
Then, in your mainloop, you'd call the PIDController's SetSetpoint() method with whatever distance you want the elevator to travel to; the units are wholly dependent on the values returned by PIDEncoder's PidGet() method.

The WPILib User's Guide has a complete example of position control with a PIDController and a potentiometer.

Hope that helped,
-Alexander
Reply With Quote
  #9   Spotlight this post!  
Unread 24-01-2011, 15:09
sircedric4's Avatar
sircedric4 sircedric4 is offline
Registered User
AKA: Darren
no team (The SS Prometheus)
Team Role: Mentor
 
Join Date: Jan 2008
Rookie Year: 2006
Location: Lousiana
Posts: 245
sircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond repute
Re: Encoder as PIDSource

Quote:
Originally Posted by Alexander Meyer View Post
cplusplus.com has a good guide if you want to solidify your knowledge of C++.

To use the class that jwakeman posted, you need to make use of PIDController. Basically, initialize a PIDController with P, I, and D values, a PIDSource, and a PIDOutput in your constructor.

So, say you use a victor to drive your elevator and an encoder to measure distance, you might have something like this:

Then, in your mainloop, you'd call the PIDController's SetSetpoint() method with whatever distance you want the elevator to travel to; the units are wholly dependent on the values returned by PIDEncoder's PidGet() method.

The WPILib User's Guide has a complete example of position control with a PIDController and a potentiometer.

Hope that helped,
-Alexander
This did help, I have read the example you mention in the User's Guide and finally got it to mostly work with a potentiometer last year, but didn't know how to get it to work with an encoder. jwakeman's sub-class was apparantly the magic I needed, and I wasn't sure how to use it. Between your post and his I should be able to beat it into submission now.

Our goal this week is to get some sort of prototype setup so we can work on encoders since they have become mandatory for us this year with the design we want. Thanks everyone.

(P.S. I will read that tutorial you hyperlinked since I still have a hard time figuring out when to use *, &, ::, ., -> and all the other heiroglyphics in C++. If there was one simple use throughout for calling classes and such I could get it. The Getting Started with C++ guide from the FIRST website made an attempt to explain these differences in pointers and references and I am getting closer, but it could do with some full sample code examples instead of just snippets)
Reply With Quote
  #10   Spotlight this post!  
Unread 24-01-2011, 16:07
jwakeman jwakeman is offline
Registered User
FRC #0063 (Red Barons)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2010
Location: 16510
Posts: 182
jwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nicejwakeman is just really nice
Re: Encoder as PIDSource

The example Alexander gave is probably a little simpler but here is a class we are working on to represent the elevator controller. Basically this class inherits from PIDController (it "is" a PIDController) and contains the victor and encoder objects that are required for PIDOputput and PIDSource. It is still under construction but it compiles and illustrates the concept I think. Also, our team is hosting an open source project for our development efforts on google code (http://code.google.com/p/first-team63/). Can't guarantee when/what will get posted here but I will try to keep it updated as we make progress. Here the elevator class as it stands now:

ElevatorController.h:
Code:
#include "PIDController.h"
#include "Victor.h"
#include "PIDEncoder.h"

class ElevatorController : public PIDController
{
public:
	ElevatorController(float p, float i, float d,float period = 0.05);
	
	~ElevatorController();
	
	void SetHeight(double dHeight);
	
private:
	Victor *motorController;
	
	PIDEncoder *encoder;
	
};

ElevatorController.cpp:
Code:
#include "ElevatorController.h"

ElevatorController::ElevatorController(float p, float i, float d, float period)
: PIDController(p,i,d,this->encoder, this->motorController, period)
{
	this->encoder = new PIDEncoder(1, 1, 1, 1, false, CounterBase::k1X); //pass proper parameters here later
	this->motorController = new Victor(1,1); //and here
	this->PIDController::SetInputRange(0.0,0.0);//and here
}
	
ElevatorController::~ElevatorController()
{
	
}
	
void ElevatorController::SetHeight(double dHeight)
{
	this->PIDController::Reset();
	this->PIDController::SetSetpoint(dHeight);
	this->PIDController::Enable();
}
Reply With Quote
  #11   Spotlight this post!  
Unread 25-01-2011, 02:03
jhersh jhersh is offline
National Instruments
AKA: Joe Hershberger
FRC #2468 (Appreciate)
Team Role: Mentor
 
Join Date: May 2008
Rookie Year: 1997
Location: Austin, TX
Posts: 1,006
jhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond repute
Re: Encoder as PIDSource

Quote:
Originally Posted by jwakeman View Post
WPILib question.

Is there a reason that the Encoder class doesn't implement the PIDSource interface? I see that it includes the header file but it doesn't actually inherit from PIDSource. Is this just a "TODO" for the lib or is there something fundamental that prevents using an encoder as PIDSource?
This is (was) a TODO... it will be implemented in the next update.

There is a new SetPIDSourceParameter() method that lets you pick which one is your process variable.

-Joe
Reply With Quote
  #12   Spotlight this post!  
Unread 25-01-2011, 10:22
sircedric4's Avatar
sircedric4 sircedric4 is offline
Registered User
AKA: Darren
no team (The SS Prometheus)
Team Role: Mentor
 
Join Date: Jan 2008
Rookie Year: 2006
Location: Lousiana
Posts: 245
sircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond repute
Angry Re: Encoder as PIDSource

I just tried to implement what you guys have been giving me into my code and when I try to compile I get the following error:

C:/WindRiver/Team2992_2011_Code_1/IterativeDemo.cpp:150: error: `PIDSource' is an inaccessible base of `PIDEncoder'

and it highlights in red the line from my code below "elevatorControl = new PIDController(0.1, 0.01, 0.001, elevatorEncoder, elevatorMotor);"


I did tweak jwakeman's PIDEncoder.h and ".cpp to below because I prefer to do without the slot designation for the cRio.

PIDEncoder.h
Code:
#include "Encoder.h"
#include "PIDSource.h"

class PIDEncoder : public Encoder, PIDSource
{
public:
	//constructor
	PIDEncoder(UINT32 aChannel,UINT32 bChannel,
			bool reverseDirection, EncodingType encodingType);
	
	PIDEncoder(UINT32 aSlot, UINT32 aChannel,
			UINT32 bSlot, UINT32 bChannel,
			bool reverseDirection, EncodingType encodingType);
	
	//destructor
	~PIDEncoder();
	
	//virtual from PIDSource
	double PIDGet();
	
private:
	
};
PIDEncoder.cpp
Code:
#include "PIDEncoder.h"

//constructor

PIDEncoder::PIDEncoder(UINT32 aChannel, UINT32 bChannel,
		bool reverseDirection, EncodingType encodingType) : 
		Encoder(aChannel,bChannel,reverseDirection,encodingType)
{

}

PIDEncoder::PIDEncoder(UINT32 aSlot, UINT32 aChannel,
		UINT32 bSlot, UINT32 bChannel,
		bool reverseDirection, EncodingType encodingType) : Encoder(aSlot,aChannel,bSlot,bChannel,reverseDirection,encodingType)
{

}
	
//destructor
PIDEncoder::~PIDEncoder()
{
	
}
	
//virtual from PIDSource
double PIDEncoder::PIDGet()
{
	return this->GetDistance();
}
And here is what I put in my IterativeRobot code:

Under Iterative Robot Class:

Code:
PIDEncoder *elevatorEncoder;
PIDController *elevatorControl;
Victor *elevatorMotor;
Inside Constructor:

Code:
elevatorEncoder = new PIDEncoder(11,12,true,Encoder::k4X);
elevatorEncoder->SetDistancePerPulse(0.04318);	//inches	//UPDATE!!
elevatorEncoder->Start();

elevatorMotor = new Victor(5);

elevatorControl = new PIDController(0.1, 0.01, 0.001, elevatorEncoder, elevatorMotor);
Did I do a boneheaded thing when tweaking jwakeman's code, or did I not understand how to call the stuff correctly in my IterativeRobot code? Can you guys help me debug this issue?
Reply With Quote
  #13   Spotlight this post!  
Unread 25-01-2011, 10:56
Alexander Meyer Alexander Meyer is offline
Registered User
FRC #2358 (Bearbotics)
Team Role: Mentor
 
Join Date: Jan 2010
Rookie Year: 2010
Location: Lake Zurich, Illinois
Posts: 36
Alexander Meyer is on a distinguished road
Re: Encoder as PIDSource

Instead of

Code:
class PIDEncoder : public Encoder, PIDSource
explicitly declare both superclasses as public, like this:

Code:
class PIDEncoder : public Encoder, public PIDSource
Reply With Quote
  #14   Spotlight this post!  
Unread 04-02-2011, 23:54
sircedric4's Avatar
sircedric4 sircedric4 is offline
Registered User
AKA: Darren
no team (The SS Prometheus)
Team Role: Mentor
 
Join Date: Jan 2008
Rookie Year: 2006
Location: Lousiana
Posts: 245
sircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond reputesircedric4 has a reputation beyond repute
Re: Encoder as PIDSource

Dang it! We had used the information that you guys had given us and finally had our robot working and PIDing with the encoders and then the WPI Library got updated with a mandatory update and broke it all again! I get a wall of red from redundant PIDSources or some such thing.

Grr, can someone please help me get set back up, now using the default, updated PIDController class that has the encoders as a source now. Specifically can someone help me figure out how to tell the encoder to use distance as its source?

So instead of constructing my encoders with the nice subclasses from earlier in the thread, I do:


Code:
Encoder *elevatorEncoder;
PIDController *elevatorControl;

//constructor
elevatorEncoder = new Encoder(11,12,true,Encoder::k4X);
elevatorEncoder->SetDistancePerPulse(0.009);	//inches	//UPDATE!!
elevatorEncoder->Start();

elevatorControl = new PIDController(0.1, 0.01, 0.001, elevatorEncoder, elevatorMotor);

//periodic
elevatorControl->Enable();
elevatorControl->SetPID(((leftStick->GetThrottle()+1)/2)*0.1,
	((rightStick->GetThrottle()+1)/2)*0.01,0.0);	//tuning
elevatorControl->SetSetpoint(ElevatorPosition);
I assume somewhere in the constructor I use
"void Encoder::SetPIDSourceParameter ( PIDSourceParameter pidSource )" from the help file, but I can't find the list of variables which denotes distance. Can someone help me figure out how to get setup correctly?
Reply With Quote
  #15   Spotlight this post!  
Unread 05-02-2011, 06:31
jhersh jhersh is offline
National Instruments
AKA: Joe Hershberger
FRC #2468 (Appreciate)
Team Role: Mentor
 
Join Date: May 2008
Rookie Year: 1997
Location: Austin, TX
Posts: 1,006
jhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond reputejhersh has a reputation beyond repute
Re: Encoder as PIDSource

Just add the call to SetPIDSourceParameter in your constructor. The PIDSourceParameter enum is defined in the Encoder header file and in the doxygen help.

-Joe
Reply With Quote
Reply


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump


All times are GMT -5. The time now is 03:23.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


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