Go to Post Meh, wear safety glasses. - Mike Schreiber [more]
Home
Go Back   Chief Delphi > Technical > Programming
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Closed Thread
Thread Tools Rate Thread Display Modes
  #1   Spotlight this post!  
Unread 13-03-2013, 00:38
joelg236 joelg236 is offline
4334 Retired Mentor & Alumni
AKA: Joel Gallant
no team
Team Role: Mentor
 
Join Date: Dec 2011
Rookie Year: 2012
Location: Calgary
Posts: 733
joelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond reputejoelg236 has a reputation beyond repute
Turning autonomously

I'm trying to make turning in autonomous accurate and consistent. I've tried a PID (P and PD) solution and had little success. I've tried simple while loops but they overshoot (and with compensation they end up completely inconsistent). What kind of algorithm / way of doing turning is the most consistent and successful? In the WPIlib, would RobotDrive.drive() work better than RobotDrive.arcadeDrive()? If so how would I make it turn more on a dime than it does by default?

Just generally, what's the best way to turn consistently and accurately turn to any angle?

*Using a gyro and 6WD
**Assuming we are only turning and not going forwards
__________________
All opinions are my own.
  #2   Spotlight this post!  
Unread 13-03-2013, 01:16
gerberduffy gerberduffy is offline
Registered User
FRC #0192
 
Join Date: Jun 2011
Location: California
Posts: 8
gerberduffy is an unknown quantity at this point
Re: Turning autonomously

Here at 192, we've found that the most consistent way to turn is with PID control on a gyro.

Basically our turn-on-a-dime is something like this:

Here is our code for turning (we created our own custom Macro class that serves to execute a single piece of code. It's good for creating modular controllers like in autonomous mode where all action can be broken down into simple actions):

Code:
package macro;

import core.GRTMacro;
import edu.wpi.first.wpilibj.PIDController;
import edu.wpi.first.wpilibj.PIDOutput;
import edu.wpi.first.wpilibj.PIDSource;
import mechanism.GRTDriveTrain;
import sensor.GRTGyro;

/**
 * Macro that automatically turns the robot a certain angle.
 *
 */
public class MacroTurn extends GRTMacro {

    private double targetAngle;
    private double currentAngle;
    private final double turnAngle;
    private GRTGyro gyro;
    private GRTDriveTrain dt;
    private PIDController controller;
    private static final double P = 1.0;
    private static final double I = 0.0;
    private static final double D = 0.0;
    private static final double F = 0.0;
    private static final double POLL_TIME = 0.05;

    private PIDSource pidSource = new PIDSource() {
        public double pidGet() {
            return gyro.getAngle();
        }
    };
    private PIDOutput pidOutput = new PIDOutput() {
        public void pidWrite(double output) {
            logInfo("Drive left: " + output + " drive right: " + -output);
            dt.setMotorSpeeds(output, -output);
        }
    };
    
    /**
     * Creates a new turning macro, that turns a set number of degrees.
     * 
     * @param turnAngle angle to turn, in degrees
     * @param gyro gyroscope to track robot movement
     * @param dt drivetrain to command
     */
    public MacroTurn(GRTDriveTrain dt, GRTGyro gyro, double turnAngle, int timeout) {
        super("Turn Macro", timeout, 50);
        
        this.turnAngle = turnAngle;
        this.gyro = gyro;
        controller = new PIDController(P, I, D, F, pidSource, pidOutput, POLL_TIME);
        controller.setOutputRange(-1, 1);
        
        controller.setAbsoluteTolerance(3.0);
    }

    protected void perform() {
        if (controller.onTarget())
            hasCompletedExecution = true;
    }

    public void die() {
        controller.disable();
        controller.free();
    }
    
    public void initialize() {
        currentAngle = gyro.getAngle();
        targetAngle = currentAngle + turnAngle;
        controller.setSetpoint(targetAngle);
        controller.enable();
    }
}
We created a wrapper class for WPILib's Gyro for our own purposes, but the .getAngle() call is analagous.

The most important parts of our class are a) That we create a PIDController which gets input from the gyro angle, and that b) it's output is on a scale from -1 to 1, and drives the left and right drivetrains in opposite directions.

With this code, we're able to get within about 2º of our target angle. Hope this helps a little!

Last edited by gerberduffy : 13-03-2013 at 01:19.
  #3   Spotlight this post!  
Unread 13-03-2013, 01:18
gerberduffy gerberduffy is offline
Registered User
FRC #0192
 
Join Date: Jun 2011
Location: California
Posts: 8
gerberduffy is an unknown quantity at this point
Re: Turning autonomously

Lol, I just found this the second after I submitted my last reply: http://wpilib.screenstepslive.com/s/...ving-direction
  #4   Spotlight this post!  
Unread 13-03-2013, 08:00
Tom Line's Avatar
Tom Line Tom Line is offline
Raptors can't turn doorknobs.
FRC #1718 (The Fighting Pi)
Team Role: Mentor
 
Join Date: Jan 2007
Rookie Year: 1999
Location: Armada, Michigan
Posts: 2,554
Tom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond reputeTom Line has a reputation beyond repute
Re: Turning autonomously

We use what we call a PID-cheat.

First, we determine experimentally what input is required to the just barely turn the drivetrain consistently.

We then tune our PID proportional term to get us close at multiple angles (but never overshooting). We then put the PID cheat code after the PID, so that if the drivetrain is ever sent a drive value below the cheat, it will change it to the minimum value so that it will turn the robot.

For example:

Try to turn 30 degrees.
Robot turns 25 degrees. At this point the PID P term becomes small and can't turn the robot. The PID cheat sees the drive command that is too small, and coerces it to the minimum value to turn so that you reach the requested angle.

We've found this system to be much easier than trying to tune a perfect PID. It's much more forgiving of changes from robot to robot, match to match.
  #5   Spotlight this post!  
Unread 13-03-2013, 09:30
apalrd's Avatar
apalrd apalrd is offline
More Torque!
AKA: Andrew Palardy (Most people call me Palardy)
VRC #3333
Team Role: College Student
 
Join Date: Mar 2009
Rookie Year: 2009
Location: Auburn Hills, MI
Posts: 1,347
apalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond reputeapalrd has a reputation beyond repute
Re: Turning autonomously

We have always gotten 'close enough' in the turn, using turn-in-place (differential steer) and slightly more accurate turn almost in place (driving only one side while holding the other) depending on desired accuracy, and compensated for whatever angular error is in the next straight move.

Our 2011 code has all of this, it's not as neat as more recent code but it all works.

As for the 'cheat' system, we occasionally overshoot the target given to the PID controller (e.g. add 5degrees * sign of angle) to help it along. We always do this with the distance-based controllers, by up to 2 feet (I believe we're currently running 18" of distance bias).
__________________
Kettering University - Computer Engineering
Kettering Motorsports
Williams International - Commercial Engines - Controls and Accessories
FRC 33 - The Killer Bees - 2009-2012 Student, 2013-2014 Advisor
VEX IQ 3333 - The Bumble Bees - 2014+ Mentor

"Sometimes, the elegant implementation is a function. Not a method. Not a class. Not a framework. Just a function." ~ John Carmack
  #6   Spotlight this post!  
Unread 13-03-2013, 09:43
Tom Bottiglieri Tom Bottiglieri is offline
Registered User
FRC #0254 (The Cheesy Poofs)
Team Role: Engineer
 
Join Date: Jan 2004
Rookie Year: 2003
Location: San Francisco, CA
Posts: 3,188
Tom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond reputeTom Bottiglieri has a reputation beyond repute
Re: Turning autonomously

I think it depends what you are trying to do. When the desired motion is to turn in place THEN drive somewhere, we're pretty happy to let the turn in place motion overshoot or undershoot as the drive motion should straighten it out (so long as the turn controller is running in parallel with the "drive straight" controller).

If you are trying to turn in place then shoot a ball or a frisbee, I think a bunch of your issues can be taken out by an I term that only applies at low error. Basically:
Code:
out = err*kp + (err-last_err)*kd;
if (err < 5 degrees) {
  sum += err;
  out += sum*ki;
} else {
  sum = 0;
}
To tune this controller, increase KP until the robot is just overshooting, then increase KD until it stops a bit faster with less overshoot. At this point you should settle within a few degrees of your target and you can increase KI (this should be an order of magnitude or 2 smaller than KP) until it snaps into place.
  #7   Spotlight this post!  
Unread 13-03-2013, 10:41
DallonF DallonF is offline
Registered User
FRC #2403 (Plasma Robotics)
Team Role: Mentor
 
Join Date: Jan 2012
Rookie Year: 2012
Location: Mesa, AZ
Posts: 11
DallonF is a jewel in the roughDallonF is a jewel in the roughDallonF is a jewel in the roughDallonF is a jewel in the rough
Re: Turning autonomously

At Plasma Robotics, we use a sort of "ghetto-PID" with a gyro - basically, we have a loop that turns the robot, slows it down once it's close, and stops once it's within an acceptable range. It then waits for a few milliseconds to make sure it doesn't overshoot - if it does, we start the process again.

It's not quite as accurate as a PID, but it's easier to understand and debug. That is, unless you do it in LabVIEW like we did and have wire-spaghetti all over the place
  #8   Spotlight this post!  
Unread 13-03-2013, 11:06
MrRoboSteve MrRoboSteve is offline
Mentor
AKA: Steve Peterson
FRC #3081 (Kennedy RoboEagles)
Team Role: Mentor
 
Join Date: Mar 2012
Rookie Year: 2011
Location: Bloomington, MN
Posts: 582
MrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond reputeMrRoboSteve has a reputation beyond repute
Re: Turning autonomously

Here's the guts of our autonomous turning code from last year's robot. The values assigned to turnRate were determined experimentally.

Code:
// If we're within this # of degrees to target, then we're good.

#define DEGREES_PRECISION 2


/*
 * This command turns the number of degrees specified in the dashboard field.
 */
TurnSpecifiedDegreesCommand::TurnSpecifiedDegreesCommand(float degreesToTurn) 
	: CommandBase("TurnSpecifiedDegreesCommand") {
	Requires(chassis);
	this->degreesToTurn = degreesToTurn;
}

void TurnSpecifiedDegreesCommand::Initialize() {
	this->finished = false;
	this->startingAngle = sensorSubsystem->GetYawGyroAngle();
	this->goalAngle = startingAngle + this->degreesToTurn;
	printf("TurnSpecifiedDegreesCommand %f\n", this->degreesToTurn);
}

void TurnSpecifiedDegreesCommand::Execute() {
	float currentAngle = sensorSubsystem->GetYawGyroAngle();
	float angleDifference = goalAngle - currentAngle;
	
	float turnRate = 0;
	
	if (fabs(angleDifference) < DEGREES_PRECISION) {
		chassis->stop();
		finished = true;
	} else {
		// We slow our rate of turn as we get close to the angle we want.
		// These values are guesses.  A PID would be better here.
		if (angleDifference > 10 || angleDifference < -10) {
			turnRate = 0.7;
		} else {
			// Look at changing this at competition
			turnRate = 0.6;
		}
		
		if (angleDifference > 0) {
			chassis->turnLeft(turnRate);
		} else {
			chassis->turnRight(turnRate);
		}
	}
}

// Make this return true when this Command no longer needs to run execute()
bool TurnSpecifiedDegreesCommand::IsFinished() {
	return finished;	
}

// Called once after isFinished returns true
void TurnSpecifiedDegreesCommand::End() {
	printf("TurnSpecifiedDegreesCommand completed.\n");
	chassis->stop();
}

// Called when another command which requires one or more of the same
// subsystems is scheduled to run
void TurnSpecifiedDegreesCommand::Interrupted() {
	printf("TurnSpecifiedDegreesCommand interrupted.\n");
	chassis->stop();
}
Closed Thread


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:27.

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