View Single Post
  #4   Spotlight this post!  
Unread 05-04-2010, 11:47
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 with PIDController Help

Quote:
Originally Posted by Jared341 View Post
Your understanding of PIDController seems to be correct - it takes PIDSources, crunches the numbers in a separate thread, and asynchronously writes to PIDOutputs.

What makes this tricky is that the WPILib PIDController writes its output to a PIDOutput, but RobotDrive does not implement PIDOutput. Likewise, Encoder doesn't implement PIDSource (because it would be ambiguous to do so - do you want to measure speed or distance?).

There are several possible solutions to this problem.

First, we need to turn the encoder's distance measurement into a PIDSource. You could re-write the WPILib Encoder class, but in general I try not to mess with a library unless I absolutely need to. Instead, how about a wrapper class?

Code:
class DistanceEncoder extends PIDSource
{
public:
  DistanceEncoder(Encoder *baseEncoder)
  {
    m_baseEncoder = baseEncoder;
  {

  double pidGet()
  {
    return m_baseEncoder->GetDistance();
  }

private:
  Encoder* m_baseEncoder;
};
Similarly, you can wrap RobotDrive in another PIDOutput class:

Code:
class RobotDriveOutput extends PIDOutput
{
public:
  RobotDriveOutput(RobotDrive* baseDrive)
  {
    m_baseDrive = baseDrive;
  }

  void pidWrite(double output)
  {
    m_baseDrive->Drive(output, 0.0);
  }

private:
  RobotDrive* m_baseDrive;
};
Then you can put it all together like you said.

*Note: there are many ways to do this; this is only one. Also, I banged out the above code from memory, so there might be syntax and/or API errors, but you should get the point.
Yikes, I thought for sure with 1800+ teams all wanting encoder driven robots there would have been an easier way. I have the basics of C down but everytime someone starts breaking out wrappers and stuff my brain just shuts down. I can handle the canned libraries and subroutines I write myself using old school subroutine and function practices but all these additional wrappers and classes and stuff is a different way of thinking. I will dig into the above code and see what I can do with it and see if I can understand it, but while thinking of this problem I realized another problem.

Seeing as I have both a left and a right encoder and RobotDrive controls all motors how do I keep two PIDControllers based on the different encoders from getting into a fist fight with each other? One will be telling RobotDrive to do one thing and the other another and I suspect only the last controller will actually have the power. I guess I will have to tie the two left motors controls and the two right motors controls into some sort of combination and use separate controllers for each side. Can I somehow wrap two Victors or Jaguars to be controlled by the same PIDController?

If I have to add all this code anyway instead of being able to just call a simple library function I may be better off just writing my own PID subroutine that is specific to my needs. At least then I might understand what everything is doing when it comes time to debug.

I think that I am not the only one that wants this information so thanks everyone and keep the info coming. I will continue to post my progress as I try to get this stuff working in the hopes it helps someone as much as me.
Reply With Quote