Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds VisionSubsystem to code base #60

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Added functionality to VisionSubsystem to determine if we can see the…
… inner target, modified VisionRotateToTargetCommand to get the proper angle to the target.
king-shak committed Feb 8, 2020
commit 53c3a370aae92faf7478090e196d9cae65ebb64f
Original file line number Diff line number Diff line change
@@ -4,25 +4,27 @@
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj2.command.CommandBase;
import org.frcteam2910.c2020.subsystems.DrivetrainSubsystem;
import org.frcteam2910.c2020.subsystems.VisionSubsystem;
import org.frcteam2910.common.control.PidConstants;
import org.frcteam2910.common.control.PidController;
import org.frcteam2910.common.math.Vector2;
import org.frcteam2910.common.robot.drivers.Limelight;

public class VisionRotateToTargetCommand extends CommandBase {
private static final PidConstants PID_CONSTANTS = new PidConstants(0.0, 0.0, 0.0);
private static final String LIMELIGHT_NAME = "limelight";
private static final Limelight LIMELIGHT = new Limelight(NetworkTableInstance.getDefault().getTable(LIMELIGHT_NAME));
private static final Limelight LIMELIGHT = new Limelight();


private final DrivetrainSubsystem drivetrain;
private final VisionSubsystem visionSubsystem;
private PidController controller = new PidController(PID_CONSTANTS);
private double lastTime = 0.0;

public VisionRotateToTargetCommand(DrivetrainSubsystem drivetrain) {
public VisionRotateToTargetCommand(DrivetrainSubsystem drivetrain, VisionSubsystem visionSubsystem) {
this.drivetrain = drivetrain;

this.visionSubsystem = visionSubsystem;
addRequirements(drivetrain);
addRequirements(visionSubsystem);
}

@Override
@@ -40,7 +42,7 @@ public void execute() {

if(LIMELIGHT.hasTarget()) {
double currentAngle = drivetrain.getPose().rotation.toRadians();
double targetAngle = drivetrain.getPoseAtTime(time - LIMELIGHT.getPipelineLatency() / 1000.0).rotation.toRadians() - LIMELIGHT.getTargetPosition().x;
double targetAngle = drivetrain.getPoseAtTime(time - LIMELIGHT.getPipelineLatency() / 1000.0).rotation.toRadians() - visionSubsystem.getAngleToTarget().getAsDouble();
controller.setSetpoint(targetAngle);
double rotationalVelocity = controller.calculate(currentAngle, dt);
drivetrain.drive(Vector2.ZERO, rotationalVelocity, false);
63 changes: 50 additions & 13 deletions src/main/java/org/frcteam2910/c2020/subsystems/VisionSubsystem.java
Original file line number Diff line number Diff line change
@@ -1,53 +1,90 @@
package org.frcteam2910.c2020.subsystems;

import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab;
import edu.wpi.first.wpilibj2.command.Subsystem;
import org.frcteam2910.common.math.MathUtils;
import org.frcteam2910.common.math.Vector2;
import org.frcteam2910.common.robot.drivers.Limelight;

import java.util.OptionalDouble;

public class VisionSubsystem implements Subsystem {
private static final double TARGET_HEIGHT = 98.25;
// TODO: Put the actual height of the Limelight
private static final double LIMELIGHT_HEIGHT = 20.0;
// TODO: Put the actual angle the Limelight is mounted at
private static final double LIMELIGHT_MOUNTING_ANGLE = Math.toRadians(20.0);
private static final double TARGET_HEIGHT = 46.25;
private static final double LIMELIGHT_HEIGHT = 5.5;

private final Limelight limelight = new Limelight();
private static final double INNER_TARGET_DEPTH = 29.25;

private static final double LIMELIGHT_MOUNTING_ANGLE = Math.toRadians(32.2);
private static final double INNER_TARGET_RANGE_ANGLE = Math.toRadians(16.2);

private static final Limelight LIMELIGHT = new Limelight();

private final NetworkTableEntry distanceToTargetEntry;
private final NetworkTableEntry canSeeInnerTargetEntry;

private OptionalDouble distanceToTarget;
private OptionalDouble angleToTarget;
private boolean canSeeInnerTarget;

public VisionSubsystem() {
ShuffleboardTab tab = Shuffleboard.getTab("Vision");
distanceToTargetEntry = tab.add("distance to target", 0.0)
.withPosition(0, 0)
.withSize(1, 1)
.getEntry();
canSeeInnerTargetEntry = tab.add("can see inner target", false)
.withPosition(0, 0)
.withSize(1, 1)
.getEntry();
}

public OptionalDouble getDistanceToTarget() {
return distanceToTarget;
}

public OptionalDouble getAngleToTarget() {
return angleToTarget;
}

public boolean isInnerTargetVisible() {
return canSeeInnerTarget;
}

@Override
public void periodic() {
// Determine whether the Limelight has a target or not
if (limelight.hasTarget()) {
// If so, get the target position and calculate the distance to it
Vector2 targetPosition = limelight.getTargetPosition();
if (LIMELIGHT.hasTarget()) {
// Calculate the distance to the outer target
Vector2 targetPosition = LIMELIGHT.getTargetPosition();
double theta = LIMELIGHT_MOUNTING_ANGLE + targetPosition.y;
distanceToTarget = OptionalDouble.of((TARGET_HEIGHT - LIMELIGHT_HEIGHT) / Math.tan(theta));
distanceToTargetEntry.setDouble(distanceToTarget.getAsDouble());
double distanceToOuterTarget = (TARGET_HEIGHT - LIMELIGHT_HEIGHT) / Math.tan(theta);
double dYOuter = distanceToOuterTarget * Math.sin(targetPosition.x);
double dXOuter = Math.sqrt(Math.pow(distanceToOuterTarget, 2) - Math.pow(dYOuter, 2));

// Calculate the distance to the inner target
double dXInner = dXOuter + INNER_TARGET_DEPTH;
double distanceToInnerTarget = Math.hypot(dXInner, dYOuter);
double alpha = Math.asin(dYOuter / dXInner);

// Bring to light whether we can see the inner target
canSeeInnerTarget = MathUtils.isInRange(-INNER_TARGET_RANGE_ANGLE, INNER_TARGET_RANGE_ANGLE, alpha);
if (canSeeInnerTarget) {
distanceToTarget = OptionalDouble.of(distanceToInnerTarget);
angleToTarget = OptionalDouble.of(alpha);
} else {
distanceToTarget = OptionalDouble.of(distanceToOuterTarget);
angleToTarget = OptionalDouble.of(targetPosition.x);
}
} else {
// Else, set distanceToTarget to an empty OptionalDouble
distanceToTarget = OptionalDouble.empty();
angleToTarget = OptionalDouble.empty();
canSeeInnerTarget = false;

// Update shuffleboard
distanceToTargetEntry.setDouble(-1.0);
canSeeInnerTargetEntry.setBoolean(canSeeInnerTarget);
}
}
}