Some Small preparations for Java Class && the County Fair Demo stuff

This commit is contained in:
Nathaniel Palme
2021-08-03 17:40:35 -05:00
parent 93fcfef1c6
commit 3fdbbb7832
29 changed files with 1346 additions and 171 deletions

2
.idea/compiler.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" /> <bytecodeTargetLevel target="1.8" />
</component> </component>
</project> </project>

2
.idea/misc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@@ -150,7 +150,7 @@ public abstract class CyberarmEngine extends OpMode {
* Recursively stop states * Recursively stop states
* @param state State to stop * @param state State to stop
*/ */
private void stopState(CyberarmState state) { public void stopState(CyberarmState state) {
state.setHasFinished(true); state.setHasFinished(true);
state.stop(); state.stop();

View File

@@ -1,10 +1,11 @@
package org.timecrafters.UltimateGoal.Calibration; package org.timecrafters.UltimateGoal.Calibration;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp; import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import org.cyberarm.engine.V2.CyberarmEngine; import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Competition.Robot; import org.timecrafters.UltimateGoal.Competition.Robot;
@Disabled
@TeleOp (name = "Calibration", group = "test") @TeleOp (name = "Calibration", group = "test")
public class CalibrationEngine extends CyberarmEngine { public class CalibrationEngine extends CyberarmEngine {
private Robot robot; private Robot robot;

View File

@@ -35,7 +35,7 @@ public class AutoEngine extends CyberarmEngine {
// since we've preloaded three rings, the ring belt stage is set to account for this; // since we've preloaded three rings, the ring belt stage is set to account for this;
robot.ringBeltStage = 3; robot.ringBeltStage = 3;
//Autonomous specific Variables //Autonomous specific Configuration Variables
float rotation = robot.stateConfiguration.variable("system", "startPos", "direction").value(); float rotation = robot.stateConfiguration.variable("system", "startPos", "direction").value();
double locationX = robot.inchesToTicks((double) robot.stateConfiguration.variable("system", "startPos", "x").value()); double locationX = robot.inchesToTicks((double) robot.stateConfiguration.variable("system", "startPos", "x").value());
double locationY = robot.inchesToTicks((double) robot.stateConfiguration.variable("system", "startPos", "y").value()); double locationY = robot.inchesToTicks((double) robot.stateConfiguration.variable("system", "startPos", "y").value());

View File

@@ -1,5 +1,9 @@
package org.timecrafters.UltimateGoal.Competition.Autonomous; package org.timecrafters.UltimateGoal.Competition.Autonomous;
/*
The FindWobbleGoal state is used in teleOp and Autonomous to aid in capturing the wobble goal.
*/
import org.cyberarm.engine.V2.CyberarmState; import org.cyberarm.engine.V2.CyberarmState;
import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit; import org.firstinspires.ftc.robotcore.external.navigation.DistanceUnit;
import org.timecrafters.UltimateGoal.Competition.Robot; import org.timecrafters.UltimateGoal.Competition.Robot;
@@ -47,6 +51,7 @@ public class FindWobbleGoal extends CyberarmState {
robot.updateLocation(); robot.updateLocation();
double sensorValue = robot.wobbleColorSensor.getDistance(DistanceUnit.MM); double sensorValue = robot.wobbleColorSensor.getDistance(DistanceUnit.MM);
//Stage 1: scan back and forth untile the sensor is in line with the wobble goal.
if (sensorValue > turnCheck) { if (sensorValue > turnCheck) {
float rotation = robot.getRelativeAngle(startRotation,robot.getRotation()); float rotation = robot.getRelativeAngle(startRotation,robot.getRotation());
@@ -65,18 +70,23 @@ public class FindWobbleGoal extends CyberarmState {
ccCheckPrev = ccCheck; ccCheckPrev = ccCheck;
} else { } else {
//Stage 2: drive toward wobble goal until it's close enough to grab
if (sensorValue > driveCheck) { if (sensorValue > driveCheck) {
if (!foundGoalRotation) { if (!foundGoalRotation) {
foundGoalRotation = true; foundGoalRotation = true;
wobbleGoalRotation = robot.getRotation(); wobbleGoalRotation = robot.getRotation();
} }
double[] powers = robot.getMecanumPowers(wobbleGoalRotation - 90, power*2 , wobbleGoalRotation); double[] powers = robot.getMecanumPowers(
wobbleGoalRotation - 90,
power*2 , wobbleGoalRotation);
robot.setDrivePower(powers[0],powers[1],powers[2],powers[3]); robot.setDrivePower(powers[0],powers[1],powers[2],powers[3]);
} else { } else {
//stage 3: grab the wobble goal && finish the state
endSearch(); endSearch();
} }
} }
//if the search takes too long, the robot grabs and finishes the state
if (runTime() > timeLimit) { if (runTime() > timeLimit) {
endSearch(); endSearch();
} }

View File

@@ -1,39 +0,0 @@
package org.timecrafters.UltimateGoal.Competition.Demo;
import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.UltimateGoal.Competition.Robot;
import org.timecrafters.UltimateGoal.Competition.TeleOp.Player1;
import org.timecrafters.UltimateGoal.Competition.TeleOp.Player2;
public class DemoControl extends CyberarmState {
private Robot robot;
public DemoControl(Robot robot) {
this.robot = robot;
}
@Override
public void start() {
// addParallelState(new Demo1(robot));
// addParallelState(new Demo2(robot));
}
@Override
public void exec() {
}
@Override
public void telemetry() {
engine.telemetry.addLine("Location");
engine.telemetry.addData("Position ","("+round(robot.ticksToInches(robot.getLocationX()),0.1)+","+round(robot.ticksToInches(robot.getLocationY()),0.1)+")");
engine.telemetry.addData("Rotation ", robot.getRotation());
}
private float round(double number,double unit) {
return (float) (Math.floor(number/unit) * unit);
}
}

View File

@@ -1,14 +1,12 @@
package org.timecrafters.UltimateGoal.Competition.Demo; package org.timecrafters.UltimateGoal.Competition.Demo;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp; import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import org.cyberarm.engine.V2.CyberarmEngine; import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Competition.Robot; import org.timecrafters.UltimateGoal.Competition.Robot;
import org.timecrafters.UltimateGoal.Competition.TeleOp.TeleOpState; import org.timecrafters.UltimateGoal.Competition.TeleOp.TeleOpState;
@Disabled @TeleOp (name = "Demo: Game",group = "demo")
@TeleOp (name = "Demo")
public class DemoEngine extends CyberarmEngine { public class DemoEngine extends CyberarmEngine {
private Robot robot; private Robot robot;
@@ -17,14 +15,14 @@ public class DemoEngine extends CyberarmEngine {
public void init() { public void init() {
robot = new Robot(hardwareMap); robot = new Robot(hardwareMap);
robot.initHardware(); robot.initHardware();
robot.wobbleGrabServo.setPosition(0); robot.wobbleGrabServo.setPosition(Robot.WOBBLE_SERVO_CLOSED);
robot.webCamServo.setPosition(0); robot.webCamServo.setPosition(0);
super.init(); super.init();
} }
@Override @Override
public void setup() { public void setup() {
addState(new DemoControl(robot)); addState(new DemoState(robot));
} }
@Override @Override

View File

@@ -0,0 +1,33 @@
package org.timecrafters.UltimateGoal.Competition.Demo;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Competition.Robot;
@TeleOp (name = "Demo: Tank",group = "demo")
public class DemoEngineTank extends CyberarmEngine {
private Robot robot;
@Override
public void init() {
robot = new Robot(hardwareMap);
robot.initHardware();
robot.wobbleGrabServo.setPosition(Robot.WOBBLE_SERVO_CLOSED);
robot.webCamServo.setPosition(0);
super.init();
}
@Override
public void setup() {
addState(new DemoStateTank(robot));
}
@Override
public void stop() {
robot.deactivateVuforia();
robot.saveRecording();
super.stop();
}
}

View File

@@ -0,0 +1,194 @@
package org.timecrafters.UltimateGoal.Competition.Demo;
/*
The Player1 state has all the controls for player one. The Player One and Player Two controls are
kept in separate states so that the childrenHaveFinished() method can be used to easily stop things
from running at the same time that shouldn't be.
*/
import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.Gamepad;
import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.UltimateGoal.Competition.Autonomous.FindWobbleGoal;
import org.timecrafters.UltimateGoal.Competition.Robot;
import org.timecrafters.UltimateGoal.Competition.TeleOp.powerShotsControl;
public class DemoState extends CyberarmState {
private Robot robot;
//normal drive control
private float leftJoystickDegrees;
private double leftJoystickMagnitude;
private float rightJoystickDegrees;
private double rightJoystickMagnitude;
private double rightJoystickMagnitudePrevious;
private double faceControlThreshold;
private float cardinalSnapping;
private float pairSnapping;
private float faceDirection = 0;
private double[] powers = {0,0,0,0};
private double drivePower = 1;
private boolean lbPrev;
private double refinePower;
public DemoState(Robot robot) {
this.robot = robot;
}
@Override
public void init() {
cardinalSnapping = robot.stateConfiguration.variable(
"tele","control", "cardinalSnapping").value();
pairSnapping = robot.stateConfiguration.variable(
"tele","control", "pairSnapping").value();
faceControlThreshold = robot.stateConfiguration.variable(
"tele","control", "faceControlT").value();
refinePower = robot.stateConfiguration.variable(
"tele","control", "refPower").value();
}
@Override
public void start() {
faceDirection = robot.getRotation();
}
@Override
public void exec() {
robot.updateLocation();
Gamepad gamepad = engine.gamepad1;
if (engine.gamepad2.right_trigger != 0) {
gamepad = engine.gamepad2;
}
//toggle for drive speed
boolean lb = engine.gamepad2.left_stick_button;
if (lb && !lbPrev) {
if (drivePower == 1) {
drivePower = 0.5;
} else {
drivePower = 1;
}
}
lbPrev = lb;
//Calculate Joystick Vector
double leftJoystickX = gamepad.left_stick_x;
double leftJoystickY = gamepad.left_stick_y;
leftJoystickDegrees = robot.getRelativeAngle(0,
(float) Math.toDegrees(Math.atan2(leftJoystickX, -leftJoystickY)));
leftJoystickMagnitude = Math.hypot(leftJoystickX, leftJoystickY);
double rightJoystickX = gamepad.right_stick_x;
double rightJoystickY = gamepad.right_stick_y;
rightJoystickDegrees = robot.getRelativeAngle(0,
(float) Math.toDegrees(Math.atan2(rightJoystickX, -rightJoystickY)));
rightJoystickMagnitude = Math.hypot(rightJoystickX, rightJoystickY);
//allows the the driver to indicate which direction the robot is currently looking
//so that the controller and robot can be re-synced in the event of a bad initial
//rotation.
if (gamepad.back) {
float newRotation = 0;
if (rightJoystickMagnitude != 0) {
newRotation = rightJoystickDegrees;
}
robot.setLocalization(newRotation, robot.getLocationX(), robot.getLocationY());
faceDirection = newRotation;
}
//if the driver is letting go of the face joystick, the robot should maintain it's
//current face direction.
if (rightJoystickMagnitude > faceControlThreshold ||
rightJoystickMagnitude - rightJoystickMagnitudePrevious > 0) {
//if the joystick is close to one of the cardinal directions, it is set to exactly
// the cardinal direction
faceDirection = snapToCardinal(rightJoystickDegrees, cardinalSnapping, 0);
}
rightJoystickMagnitudePrevious = rightJoystickMagnitude;
//The D-pad is used if the drivers need to get a more precise angle than they can get
//using the face joystick
if (gamepad.dpad_right) {
powers = new double[]{refinePower, -refinePower, refinePower, -refinePower};
faceDirection = robot.getRotation();
} else if (gamepad.dpad_left) {
powers = new double[]{-refinePower, refinePower, -refinePower, refinePower};
faceDirection = robot.getRotation();
} else if (leftJoystickMagnitude == 0) {
double[] facePowers = robot.getFacePowers(faceDirection, 0.4);
powers = new double[]{facePowers[0], facePowers[1], facePowers[0], facePowers[1]};
} else {
//drives the robot in the direction of the move joystick while facing the direction
//of the look joystick. if the move direction is almost aligned/perpendicular to the
//look joystick,
powers = robot.getMecanumPowers(
snapToCardinal(leftJoystickDegrees, pairSnapping, faceDirection),
drivePower, faceDirection);
}
robot.setDrivePower(powers[0], powers[1], powers[2], powers[3]);
//LED feedback control
double ringBeltPower = robot.ringBeltMotor.getPower();
if (ringBeltPower > 0 && Math.abs(robot.ringBeltMotor.getTargetPosition() -
robot.ringBeltMotor.getCurrentPosition()) > 10) {
robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.HEARTBEAT_BLUE );
} else if (ringBeltPower < 0) {
robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.HEARTBEAT_RED);
} else {
if (drivePower == 1) {
robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.DARK_GREEN);
} else {
robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.GOLD);
}
}
}
@Override
public void telemetry() {
engine.telemetry.addLine("Controler Directions");
engine.telemetry.addData("Right", rightJoystickDegrees);
engine.telemetry.addData("Left", leftJoystickDegrees);
engine.telemetry.addData("face", faceDirection);
engine.telemetry.addData("Player 1 children", childrenHaveFinished());
for (CyberarmState state : children) {
if (!state.getHasFinished()) {
engine.telemetry.addLine("" + state.getClass());
}
}
}
//This just checks if the wobble arm runmode is already the desired mode before setting it.
//I don't know if this is actually helpful
private void setArmMode(DcMotor.RunMode runMode) {
if (robot.wobbleArmMotor.getMode() != runMode) {
robot.wobbleArmMotor.setMode(runMode);
}
}
private float snapToCardinal(float angle, float snapping, float offset) {
int o = (int) offset + 180;
o %= 90;
for (int cardinal = o-180; (cardinal <= 180+o && cardinal != angle); cardinal += 90) {
if (angle >= cardinal-snapping && angle <= cardinal+snapping) {
angle = cardinal;
}
}
return angle;
}
}

View File

@@ -0,0 +1,55 @@
package org.timecrafters.UltimateGoal.Competition.Demo;
/*
The Player1 state has all the controls for player one. The Player One and Player Two controls are
kept in separate states so that the childrenHaveFinished() method can be used to easily stop things
from running at the same time that shouldn't be.
*/
import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.Gamepad;
import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.UltimateGoal.Competition.Autonomous.FindWobbleGoal;
import org.timecrafters.UltimateGoal.Competition.Robot;
import org.timecrafters.UltimateGoal.Competition.TeleOp.powerShotsControl;
public class DemoStateTank extends CyberarmState {
private Robot robot;
private double drivePower = 1;
private boolean lbPrev;
public DemoStateTank(Robot robot) {
this.robot = robot;
}
@Override
public void exec() {
robot.updateLocation();
Gamepad gamepad = engine.gamepad1;
if (engine.gamepad2.right_bumper) {
gamepad = engine.gamepad2;
}
//toggle for drive speed
boolean lb = engine.gamepad2.left_stick_button;
if (lb && !lbPrev) {
if (drivePower == 1) {
drivePower = 0.5;
} else {
drivePower = 1;
}
}
lbPrev = lb;
double left = -drivePower * gamepad.left_stick_y;
double right = -drivePower * gamepad.right_stick_y;
robot.setDrivePower(left,right,left,right);
}
}

View File

@@ -1,6 +1,10 @@
package org.timecrafters.UltimateGoal.Competition; package org.timecrafters.UltimateGoal.Competition;
import com.qualcomm.hardware.rev.RevBlinkinLedDriver; /*
The Launch state is used in teleOp and Autonomous. In addition to launching any rings by cycling the
ring belt, this state returns the ring belt to the starting position
*/
import com.qualcomm.robotcore.hardware.DcMotor; import com.qualcomm.robotcore.hardware.DcMotor;
import org.cyberarm.engine.V2.CyberarmState; import org.cyberarm.engine.V2.CyberarmState;
@@ -45,10 +49,7 @@ public class Launch extends CyberarmState {
@Override @Override
public void exec() { public void exec() {
//detect when limit switch is initially triggered //jam counter measures
boolean detectingPass = robot.limitSwitch.isPressed();
int beltPos = robot.ringBeltMotor.getCurrentPosition();
if (robot.beltIsStuck() && childrenHaveFinished()) { if (robot.beltIsStuck() && childrenHaveFinished()) {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (stuckStartTime == 0) { if (stuckStartTime == 0) {
@@ -60,6 +61,9 @@ public class Launch extends CyberarmState {
stuckStartTime = 0; stuckStartTime = 0;
} }
//detect when limit switch is initially triggered
boolean detectingPass = robot.limitSwitch.isPressed();
int beltPos = robot.ringBeltMotor.getCurrentPosition();
if (detectingPass && !detectedPass) { if (detectingPass && !detectedPass) {
//finish once the ring belt has cycled all the way through and then returned to //finish once the ring belt has cycled all the way through and then returned to
//the first receiving position. //the first receiving position.

View File

@@ -16,7 +16,7 @@ public class Pause extends CyberarmState {
this.actionName = actionName; this.actionName = actionName;
} }
public Pause(Robot robot, boolean open, long waitTime) { public Pause(Robot robot, long waitTime) {
this.robot = robot; this.robot = robot;
this.waitTime = waitTime; this.waitTime = waitTime;
} }

View File

@@ -1,10 +1,11 @@
package org.timecrafters.UltimateGoal.Competition.PreInit; package org.timecrafters.UltimateGoal.Competition.PreInit;
import com.qualcomm.robotcore.eventloop.opmode.Autonomous; import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import org.cyberarm.engine.V2.CyberarmEngine; import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Competition.Robot; import org.timecrafters.UltimateGoal.Competition.Robot;
@Disabled
@Autonomous (name = "Load Rings") @Autonomous (name = "Load Rings")
public class PreInitEngine extends CyberarmEngine { public class PreInitEngine extends CyberarmEngine {

View File

@@ -1,8 +1,11 @@
package org.timecrafters.UltimateGoal.Competition; package org.timecrafters.UltimateGoal.Competition;
/*
The ProgressRingBelt state is used in teleOp to automatically move the ring belt.
*/
import com.qualcomm.hardware.rev.RevBlinkinLedDriver; import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import com.qualcomm.robotcore.hardware.DcMotor; import com.qualcomm.robotcore.hardware.DcMotor;
import org.cyberarm.engine.V2.CyberarmState; import org.cyberarm.engine.V2.CyberarmState;
public class ProgressRingBelt extends CyberarmState { public class ProgressRingBelt extends CyberarmState {
@@ -27,13 +30,20 @@ public class ProgressRingBelt extends CyberarmState {
@Override @Override
public void start() { public void start() {
int currentPos = robot.ringBeltMotor.getCurrentPosition(); int currentPos = robot.ringBeltMotor.getCurrentPosition();
//The first two progressions should move to preprare for another ring.
if (robot.ringBeltStage < 2) { if (robot.ringBeltStage < 2) {
targetPos = currentPos + robot.ringBeltGap; targetPos = currentPos + robot.ringBeltGap;
prep(); prep();
//The third progression needs to only move forward enought to block the ring from
//falling out
} else if (robot.ringBeltStage == 2) { } else if (robot.ringBeltStage == 2) {
targetPos = currentPos + 150; targetPos = currentPos + 150;
prep(); prep();
prepLaunch = !robot.initLauncher; prepLaunch = !robot.initLauncher;
//If the ring belt is already full, It does allow another progression
} else if (robot.ringBeltStage > 2) { } else if (robot.ringBeltStage > 2) {
setHasFinished(true); setHasFinished(true);
} }
@@ -44,6 +54,7 @@ public class ProgressRingBelt extends CyberarmState {
@Override @Override
public void exec() { public void exec() {
//finished state when the target position is reached
int currentPos = robot.ringBeltMotor.getCurrentPosition(); int currentPos = robot.ringBeltMotor.getCurrentPosition();
if (currentPos >= targetPos) { if (currentPos >= targetPos) {
if(prepLaunch) { if(prepLaunch) {
@@ -53,6 +64,7 @@ public class ProgressRingBelt extends CyberarmState {
setHasFinished(true); setHasFinished(true);
} }
//belt jam mitigation
if (robot.beltIsStuck() && childrenHaveFinished()) { if (robot.beltIsStuck() && childrenHaveFinished()) {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (stuckStartTime == 0) { if (stuckStartTime == 0) {

View File

@@ -1,4 +1,4 @@
package org.timecrafters.UltimateGoal.Competition; package org.timecrafters.UltimateGoal.Competition;
/* /*
The robot object contains all the hardware and functions that are used in both teleOp and The robot object contains all the hardware and functions that are used in both teleOp and
@@ -14,6 +14,7 @@ import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import com.qualcomm.hardware.rev.RevColorSensorV3; import com.qualcomm.hardware.rev.RevColorSensorV3;
import com.qualcomm.hardware.rev.RevTouchSensor; import com.qualcomm.hardware.rev.RevTouchSensor;
import com.qualcomm.robotcore.hardware.DcMotor; import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorEx;
import com.qualcomm.robotcore.hardware.DcMotorSimple; import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.hardware.HardwareMap; import com.qualcomm.robotcore.hardware.HardwareMap;
import com.qualcomm.robotcore.hardware.Servo; import com.qualcomm.robotcore.hardware.Servo;
@@ -53,7 +54,8 @@ public class Robot {
} }
//The TimeCraftersConfiguration is part of a debugging and tuning tool that allows us to edit //The TimeCraftersConfiguration is part of a debugging and tuning tool that allows us to edit
//variables saved on the phone, without having to re-download the whole program. //variables saved on the phone, without having to re-download the whole program. This is
//especially useful for autonomous route tuning
public TimeCraftersConfiguration stateConfiguration = new TimeCraftersConfiguration(); public TimeCraftersConfiguration stateConfiguration = new TimeCraftersConfiguration();
//We use the IMU to get reliable rotation and angular velocity information. Experimentation has //We use the IMU to get reliable rotation and angular velocity information. Experimentation has
@@ -74,6 +76,12 @@ public class Robot {
public DcMotor encoderBack; public DcMotor encoderBack;
//Motion Constants //Motion Constants
//related graphs
//https://www.desmos.com/calculator/gndnkjndu9
//https://www.desmos.com/calculator/w0rebnftvg
//https://www.desmos.com/calculator/qxa1rq8hrv
static final double CUBIC_CORRECTION = 0.035; static final double CUBIC_CORRECTION = 0.035;
static final double FACE_CUBIC_CORRECTION = 0.025; static final double FACE_CUBIC_CORRECTION = 0.025;
static final double LINEAR_CORRECTION = 0.055; static final double LINEAR_CORRECTION = 0.055;
@@ -81,10 +89,12 @@ public class Robot {
static final double FACE_LINEAR_CORRECTION = 0.025; static final double FACE_LINEAR_CORRECTION = 0.025;
static final double MOMENTUM_CORRECTION = 1.05; static final double MOMENTUM_CORRECTION = 1.05;
static final double MOMENTUM_MAX_CORRECTION = 1.4; static final double MOMENTUM_MAX_CORRECTION = 1.4;
static final double MOMENTUM_HORIZONTAL_CORRECTION = -(Math.log10(MOMENTUM_MAX_CORRECTION-1)/Math.log10(MOMENTUM_CORRECTION)); static final double MOMENTUM_HORIZONTAL_CORRECTION =
-(Math.log10(MOMENTUM_MAX_CORRECTION-1) / Math.log10(MOMENTUM_CORRECTION));
static final double FACE_MOMENTUM_MAX_CORRECTION = 1.1; static final double FACE_MOMENTUM_MAX_CORRECTION = 1.1;
static final double FACE_MOMENTUM_CORRECTION = 1.06; static final double FACE_MOMENTUM_CORRECTION = 1.06;
static final double FACE_MOMENTUM_HORIZONTAL_CORRECTION = -(Math.log10(FACE_MOMENTUM_MAX_CORRECTION-1)/Math.log10(FACE_MOMENTUM_CORRECTION)); static final double FACE_MOMENTUM_HORIZONTAL_CORRECTION =
-(Math.log10(FACE_MOMENTUM_MAX_CORRECTION-1) / Math.log10(FACE_MOMENTUM_CORRECTION));
static final double ZERO_POWER_THRESHOLD = 0.25; static final double ZERO_POWER_THRESHOLD = 0.25;
//Unit Conversion Constants //Unit Conversion Constants
@@ -107,7 +117,7 @@ public class Robot {
private float rotationPrevious = 0; private float rotationPrevious = 0;
public float angularVelocity; public float angularVelocity;
//vuforia navigation //vuforia && tensorFlow Stuff
private WebcamName webcam; private WebcamName webcam;
private VuforiaLocalizer vuforia; private VuforiaLocalizer vuforia;
@@ -118,8 +128,10 @@ public class Robot {
// Inches Left of axis of rotation // Inches Left of axis of rotation
static final float CAMERA_LEFT_DISPLACEMENT = 4f; static final float CAMERA_LEFT_DISPLACEMENT = 4f;
static final double CAMERA_DISPLACEMENT_MAG = Math.hypot(CAMERA_FORWARD_DISPLACEMENT,CAMERA_LEFT_DISPLACEMENT); static final double CAMERA_DISPLACEMENT_MAG =
static final float CAMERA_DISPLACEMENT_DIRECTION = (float) -Math.atan(CAMERA_LEFT_DISPLACEMENT/CAMERA_FORWARD_DISPLACEMENT); Math.hypot(CAMERA_FORWARD_DISPLACEMENT,CAMERA_LEFT_DISPLACEMENT);
static final float CAMERA_DISPLACEMENT_DIRECTION =
(float) -Math.atan(CAMERA_LEFT_DISPLACEMENT/CAMERA_FORWARD_DISPLACEMENT);
public boolean trackableVisible; public boolean trackableVisible;
private VuforiaTrackables targetsUltimateGoal; private VuforiaTrackables targetsUltimateGoal;
@@ -145,6 +157,7 @@ public class Robot {
public static final double LAUNCH_POWER = 0.715; public static final double LAUNCH_POWER = 0.715;
private static final long LAUNCH_ACCEL_TIME = 500; private static final long LAUNCH_ACCEL_TIME = 500;
//These variables were originally going to be used in both autonomous and teleOp
public double launchPositionX; public double launchPositionX;
public double launchPositionY; public double launchPositionY;
public float launchRotation; public float launchRotation;
@@ -182,22 +195,17 @@ public class Robot {
//Debugging //Debugging
public double totalV; public double totalV;
public double visionX; private String TestingRecord = "Raw IMU, Delta, Saved";
public double visionY;
public double visionZ;
public float rawAngle;
private String TestingRecord = "x,y";
public double forwardVector; public double forwardVector;
public double sidewaysVector; public double sidewaysVector;
public double traveledForward = 0; public double traveledForward = 0;
public double traveledRight; public DcMotorEx motorAmpsTest;
//All our hardware initialization in one place, for everything that is the same in TeleOp and
//Autonomous
public void initHardware() { public void initHardware() {
limitSwitch = hardwareMap.get(RevTouchSensor.class, "magLim"); //drive motors
driveFrontLeft = hardwareMap.dcMotor.get("driveFrontLeft"); driveFrontLeft = hardwareMap.dcMotor.get("driveFrontLeft");
driveFrontRight = hardwareMap.dcMotor.get("driveFrontRight"); driveFrontRight = hardwareMap.dcMotor.get("driveFrontRight");
driveBackLeft = hardwareMap.dcMotor.get("driveBackLeft"); driveBackLeft = hardwareMap.dcMotor.get("driveBackLeft");
@@ -226,9 +234,12 @@ public class Robot {
wobbleArmMotor.setTargetPosition(0); wobbleArmMotor.setTargetPosition(0);
wobbleArmMotor.setMode(DcMotor.RunMode.RUN_TO_POSITION); wobbleArmMotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
wobbleUpPos = stateConfiguration.variable("system","arm", "up").value(); wobbleUpPos = stateConfiguration.variable(
wobbleDownPos = stateConfiguration.variable("system","arm", "down").value(); "system","arm", "up").value();
wobbleDropPos = stateConfiguration.variable("system","arm", "drop").value(); wobbleDownPos = stateConfiguration.variable(
"system","arm", "down").value();
wobbleDropPos = stateConfiguration.variable(
"system","arm", "drop").value();
wobbleGrabServo = hardwareMap.servo.get("wobbleGrab"); wobbleGrabServo = hardwareMap.servo.get("wobbleGrab");
@@ -236,7 +247,7 @@ public class Robot {
wobbleTouchSensor = hardwareMap.get(RevTouchSensor.class, "touch"); wobbleTouchSensor = hardwareMap.get(RevTouchSensor.class, "touch");
//init ring belt //init collection motor
collectionMotor = hardwareMap.dcMotor.get("collect"); collectionMotor = hardwareMap.dcMotor.get("collect");
collectionMotor.setDirection(DcMotorSimple.Direction.REVERSE); collectionMotor.setDirection(DcMotorSimple.Direction.REVERSE);
@@ -244,10 +255,17 @@ public class Robot {
ringBeltMotor = hardwareMap.dcMotor.get("belt"); ringBeltMotor = hardwareMap.dcMotor.get("belt");
ringBeltMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER); ringBeltMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
ringBeltMotor .setMode(DcMotor.RunMode.RUN_USING_ENCODER); ringBeltMotor .setMode(DcMotor.RunMode.RUN_USING_ENCODER);
beltMaxStopTime = stateConfiguration.variable("system","belt", "maxStopTime").value();
beltMaxStopTicks = stateConfiguration.variable("system","belt", "maxStopTicks").value(); limitSwitch = hardwareMap.get(RevTouchSensor.class, "magLim");
beltReverseTicks = stateConfiguration.variable("system","belt", "reverseTicks").value();
ringBeltGap = stateConfiguration.variable("system","belt","gap").value(); beltMaxStopTime = stateConfiguration.variable(
"system","belt", "maxStopTime").value();
beltMaxStopTicks = stateConfiguration.variable(
"system","belt", "maxStopTicks").value();
beltReverseTicks = stateConfiguration.variable(
"system","belt", "reverseTicks").value();
ringBeltGap = stateConfiguration.variable(
"system","belt","gap").value();
//init IMU //init IMU
imu = hardwareMap.get(BNO055IMU.class, "imu"); imu = hardwareMap.get(BNO055IMU.class, "imu");
@@ -279,9 +297,12 @@ public class Robot {
webCamServo = hardwareMap.servo.get("look"); webCamServo = hardwareMap.servo.get("look");
webCamServo.setDirection(Servo.Direction.REVERSE ); webCamServo.setDirection(Servo.Direction.REVERSE );
minCheckVelocity =stateConfiguration.variable("system", "camera", "minCheckV").value(); minCheckVelocity =stateConfiguration.variable(
vuforiaRotationCull = stateConfiguration.variable("system", "camera", "rCull").value(); "system", "camera", "minCheckV").value();
minCheckDurationMs =stateConfiguration.variable("system", "camera", "minCheckMS").value(); vuforiaRotationCull = stateConfiguration.variable(
"system", "camera", "rCull").value();
minCheckDurationMs =stateConfiguration.variable(
"system", "camera", "minCheckMS").value();
//Init Launch Motor //Init Launch Motor
DcMotor launcher = hardwareMap.dcMotor.get("launcher"); DcMotor launcher = hardwareMap.dcMotor.get("launcher");
@@ -296,8 +317,12 @@ public class Robot {
launchMotor.setMode(DcMotor.RunMode.RUN_USING_ENCODER); launchMotor.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
launchMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT); launchMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);
initLauncher = stateConfiguration.action("system","initLauncher").enabled; //This is a debugging option that automatically turns on the launch wheel during init.
reduceLaunchPos = stateConfiguration.variable("system", "launchPos", "reducePower").value(); //This can be disabled using a variable in the TimeCraftersConfiguration
initLauncher = stateConfiguration.action(
"system","initLauncher").enabled;
reduceLaunchPos = stateConfiguration.variable(
"system", "launchPos", "reducePower").value();
if (initLauncher) { if (initLauncher) {
double launcherPower = 0; double launcherPower = 0;
@@ -307,10 +332,13 @@ public class Robot {
launchMotor.setPower(launcherPower); launchMotor.setPower(launcherPower);
} }
} }
//
launchPositionX = inchesToTicks((double) stateConfiguration.variable("system", "launchPos","x").value()); launchPositionX = inchesToTicks((double) stateConfiguration.variable(
launchPositionY = inchesToTicks((double) stateConfiguration.variable("system", "launchPos","y").value()); "system", "launchPos","x").value());
launchRotation = stateConfiguration.variable("system", "launchPos","rot").value(); launchPositionY = inchesToTicks((double) stateConfiguration.variable(
"system", "launchPos","y").value());
launchRotation = stateConfiguration.variable(
"system", "launchPos","rot").value();
initTensorFlow(); initTensorFlow();
@@ -319,8 +347,10 @@ public class Robot {
private void initVuforia() { private void initVuforia() {
int cameraMonitorViewId = hardwareMap.appContext.getResources().getIdentifier("cameraMonitorViewId", "id", hardwareMap.appContext.getPackageName()); int cameraMonitorViewId = hardwareMap.appContext.getResources().getIdentifier(
VuforiaLocalizer.Parameters parameters = new VuforiaLocalizer.Parameters(cameraMonitorViewId); "cameraMonitorViewId", "id", hardwareMap.appContext.getPackageName());
VuforiaLocalizer.Parameters parameters =
new VuforiaLocalizer.Parameters(cameraMonitorViewId);
parameters.vuforiaLicenseKey = "Abmu1jv/////AAABmYzrcgDEi014nv+wD6PkEPVnOlV2pI3S9sGUMMR/X7hF72x20rP1JcVtsU0nI6VK0yUlYbCSA2k+yMo4hQmPDBvrqeqAgXKa57ilPhW5e1cB3BEevP+9VoJ9QYFhKA3JJTiuFS50WQeuFy3dp0gOPoqHL3XClRFZWbhzihyNnLXgXlKiq+i5GbfONECucQU2DgiuuxYlCaeNdUHl1X5C2pO80zZ6y7PYAp3p0ciXJxqfBoVAklhd69avaAE5Z84ctKscvcbxCS16lq81X7XgIFjshLoD/vpWa300llDG83+Y777q7b5v7gsUCZ6FiuK152Rd272HLuBRhoTXAt0ug9Baq5cz3sn0sAIEzSHX1nah"; parameters.vuforiaLicenseKey = "Abmu1jv/////AAABmYzrcgDEi014nv+wD6PkEPVnOlV2pI3S9sGUMMR/X7hF72x20rP1JcVtsU0nI6VK0yUlYbCSA2k+yMo4hQmPDBvrqeqAgXKa57ilPhW5e1cB3BEevP+9VoJ9QYFhKA3JJTiuFS50WQeuFy3dp0gOPoqHL3XClRFZWbhzihyNnLXgXlKiq+i5GbfONECucQU2DgiuuxYlCaeNdUHl1X5C2pO80zZ6y7PYAp3p0ciXJxqfBoVAklhd69avaAE5Z84ctKscvcbxCS16lq81X7XgIFjshLoD/vpWa300llDG83+Y777q7b5v7gsUCZ6FiuK152Rd272HLuBRhoTXAt0ug9Baq5cz3sn0sAIEzSHX1nah";
parameters.cameraName = webcam; parameters.cameraName = webcam;
@@ -346,20 +376,27 @@ public class Robot {
redAllianceTarget.setLocation(OpenGLMatrix redAllianceTarget.setLocation(OpenGLMatrix
.translation(0, -halfField, mmTargetHeight) .translation(0, -halfField, mmTargetHeight)
.multiplied(Orientation.getRotationMatrix(EXTRINSIC, XYZ, DEGREES, 90, 0, 180))); .multiplied(Orientation.getRotationMatrix(
EXTRINSIC, XYZ, DEGREES, 90, 0, 180)));
frontWallTarget.setLocation(OpenGLMatrix frontWallTarget.setLocation(OpenGLMatrix
.translation(-halfField, 0, mmTargetHeight) .translation(-halfField, 0, mmTargetHeight)
.multiplied(Orientation.getRotationMatrix(EXTRINSIC, XYZ, DEGREES, 90, 0 , 90))); .multiplied(Orientation.getRotationMatrix(
EXTRINSIC, XYZ, DEGREES, 90, 0 , 90)));
redTowerGoalTarget.setLocation(OpenGLMatrix redTowerGoalTarget.setLocation(OpenGLMatrix
.translation(halfField, -quadField, mmTargetHeight) .translation(halfField, -quadField, mmTargetHeight)
.multiplied(Orientation.getRotationMatrix(EXTRINSIC, XYZ, DEGREES, 90, 0, -90))); .multiplied(Orientation.getRotationMatrix(
EXTRINSIC, XYZ, DEGREES, 90, 0, -90)));
OpenGLMatrix robotFromCamera = OpenGLMatrix OpenGLMatrix robotFromCamera = OpenGLMatrix
.translation(CAMERA_FORWARD_DISPLACEMENT * mmPerInch, CAMERA_LEFT_DISPLACEMENT * mmPerInch, CAMERA_VERTICAL_DISPLACEMENT * mmPerInch) .translation(CAMERA_FORWARD_DISPLACEMENT * mmPerInch,
.multiplied(Orientation.getRotationMatrix(EXTRINSIC, YZX, DEGREES, -90, 0, 0)); CAMERA_LEFT_DISPLACEMENT * mmPerInch,
CAMERA_VERTICAL_DISPLACEMENT * mmPerInch)
.multiplied(Orientation.getRotationMatrix(
EXTRINSIC, YZX, DEGREES, -90, 0, 0));
for (VuforiaTrackable trackable : trackables) { for (VuforiaTrackable trackable : trackables) {
((VuforiaTrackableDefaultListener) trackable.getListener()).setPhoneInformation(robotFromCamera, parameters.cameraDirection); ((VuforiaTrackableDefaultListener) trackable.getListener())
.setPhoneInformation(robotFromCamera, parameters.cameraDirection);
} }
targetsUltimateGoal.activate(); targetsUltimateGoal.activate();
@@ -373,11 +410,15 @@ public class Robot {
int tfodMonitorViewId = hardwareMap.appContext.getResources().getIdentifier( int tfodMonitorViewId = hardwareMap.appContext.getResources().getIdentifier(
"tfodMonitorViewId", "id", hardwareMap.appContext.getPackageName()); "tfodMonitorViewId", "id", hardwareMap.appContext.getPackageName());
TFObjectDetector.Parameters parameters = new TFObjectDetector.Parameters(tfodMonitorViewId); TFObjectDetector.Parameters parameters = new TFObjectDetector.Parameters(tfodMonitorViewId);
parameters.minResultConfidence = stateConfiguration.variable("system", "camera", "minConfidence").value(); parameters.minResultConfidence = stateConfiguration.variable(
"system", "camera", "minConfidence").value();
tfObjectDetector = ClassFactory.getInstance().createTFObjectDetector(parameters, vuforia); tfObjectDetector = ClassFactory.getInstance().createTFObjectDetector(parameters, vuforia);
tfObjectDetector.loadModelFromAsset("UltimateGoal.tflite", "Quad", "Single"); tfObjectDetector.loadModelFromAsset(
"UltimateGoal.tflite", "Quad", "Single");
} }
//Localization Function! This function is represented in a flow diagram, earlier in the
//software section
//run this in every exec to track the robot's location. //run this in every exec to track the robot's location.
public void updateLocation(){ public void updateLocation(){
@@ -417,13 +458,15 @@ public class Robot {
ticksPerDegreeForward = TICKS_PER_ROBOT_DEGREE_CLOCKWISE_FORWARD; ticksPerDegreeForward = TICKS_PER_ROBOT_DEGREE_CLOCKWISE_FORWARD;
} }
forwardVector = ((encoderLeftChange+encoderRightChange)/2) - (rotationChange* ticksPerDegreeForward); forwardVector = ((encoderLeftChange+encoderRightChange)/2) -
(rotationChange* ticksPerDegreeForward);
traveledForward += forwardVector; traveledForward += forwardVector;
sidewaysVector = encoderBackChange + (rotationChange * ticksPerDegreeSideways); sidewaysVector = encoderBackChange + (rotationChange * ticksPerDegreeSideways);
double magnitude = Math.sqrt((forwardVector*forwardVector) + (sidewaysVector*sidewaysVector)); double magnitude = Math.sqrt((forwardVector*forwardVector) + (sidewaysVector*sidewaysVector));
double direction = Math.toRadians(Robot.rotation + (rotationChange/2)) + Math.atan2(sidewaysVector,forwardVector); double direction = Math.toRadians(Robot.rotation + (rotationChange/2)) +
Math.atan2(sidewaysVector,forwardVector);
double xChange = magnitude * (Math.sin(direction)); double xChange = magnitude * (Math.sin(direction));
double yChange = magnitude * (Math.cos(direction)); double yChange = magnitude * (Math.cos(direction));
@@ -434,11 +477,15 @@ public class Robot {
Robot.rotation += rotationChange; Robot.rotation += rotationChange;
Robot.rotation = scaleAngleRange(Robot.rotation); Robot.rotation = scaleAngleRange(Robot.rotation);
totalV = Math.abs(encoderLeftChange) + Math.abs(encoderRightChange) + Math.abs(encoderBackChange); totalV = Math.abs(encoderLeftChange) + Math.abs(encoderRightChange) +
Math.abs(encoderBackChange);
// record(""+System.currentTimeMillis()+", "+imuAngle);
} }
//Experimentation has demonstrated that Vuforia dosen't provide good data while the camera
//is moving or rotating. This function detects if conditions are appropriate to run vuforia and
//get more accurate results
public void syncIfStationary() { public void syncIfStationary() {
if (totalV < minCheckVelocity) { if (totalV < minCheckVelocity) {
long timeCurrent = System.currentTimeMillis(); long timeCurrent = System.currentTimeMillis();
@@ -459,7 +506,9 @@ public class Robot {
trackableVisible = false; trackableVisible = false;
for (VuforiaTrackable trackable : trackables) { for (VuforiaTrackable trackable : trackables) {
if (((VuforiaTrackableDefaultListener)trackable.getListener()).isVisible()) { if (((VuforiaTrackableDefaultListener)trackable.getListener()).isVisible()) {
OpenGLMatrix robotLocation = ((VuforiaTrackableDefaultListener)trackable.getListener()).getUpdatedRobotLocation(); OpenGLMatrix robotLocation =
((VuforiaTrackableDefaultListener)trackable.getListener())
.getUpdatedRobotLocation();
//this is used for debugging purposes. //this is used for debugging purposes.
trackableVisible = true; trackableVisible = true;
@@ -470,7 +519,8 @@ public class Robot {
//For our tournament, it makes sense to make zero degrees towards the goal. //For our tournament, it makes sense to make zero degrees towards the goal.
//Orientation is inverted to have clockwise be positive. //Orientation is inverted to have clockwise be positive.
Orientation orientation = Orientation.getOrientation(lastConfirmendLocation, EXTRINSIC, XYZ, DEGREES); Orientation orientation =
Orientation.getOrientation(lastConfirmendLocation, EXTRINSIC, XYZ, DEGREES);
float vuforiaRotation = 90-orientation.thirdAngle; float vuforiaRotation = 90-orientation.thirdAngle;
if (vuforiaRotation > 180) { if (vuforiaRotation > 180) {
@@ -484,8 +534,10 @@ public class Robot {
double camX = -translation.get(1) / mmPerInch; double camX = -translation.get(1) / mmPerInch;
double camY = translation.get(0) / mmPerInch; double camY = translation.get(0) / mmPerInch;
double displaceX = CAMERA_DISPLACEMENT_MAG * Math.sin(Robot.rotation + 180 - CAMERA_DISPLACEMENT_DIRECTION); double displaceX = CAMERA_DISPLACEMENT_MAG *
double displaceY = CAMERA_DISPLACEMENT_MAG * Math.cos(Robot.rotation + 180 - CAMERA_DISPLACEMENT_DIRECTION); Math.sin(Robot.rotation + 180 - CAMERA_DISPLACEMENT_DIRECTION);
double displaceY = CAMERA_DISPLACEMENT_MAG *
Math.cos(Robot.rotation + 180 - CAMERA_DISPLACEMENT_DIRECTION);
locationX = inchesToTicks(camX - displaceX); locationX = inchesToTicks(camX - displaceX);
locationY = inchesToTicks(camY - displaceY); locationY = inchesToTicks(camY - displaceY);
@@ -508,18 +560,13 @@ public class Robot {
return Robot.locationY; return Robot.locationY;
} }
//This is meant to only be used to indicate starting positions and to reorient the robot.
public void setLocalization(float rotation, double x, double y) { public void setLocalization(float rotation, double x, double y) {
Robot.rotation = rotation; Robot.rotation = rotation;
Robot.locationX = x; Robot.locationX = x;
Robot.locationY = y; Robot.locationY = y;
} }
//Manually set the position of the robot on the field.
public void setCurrentPosition(float rotation, double x, double y) {
Robot.rotation = rotation;
Robot.locationX = x;
Robot.locationY = y;
}
//returns the angle from the robot's current position to the given target position. //returns the angle from the robot's current position to the given target position.
public float getAngleToPosition (double x, double y) { public float getAngleToPosition (double x, double y) {
@@ -531,7 +578,7 @@ public class Robot {
} }
//Unit conversion //Unit conversions
public double ticksToInches(double ticks) { public double ticksToInches(double ticks) {
return ticks * (ENCODER_CIRCUMFERENCE / COUNTS_PER_REVOLUTION); return ticks * (ENCODER_CIRCUMFERENCE / COUNTS_PER_REVOLUTION);
} }
@@ -541,26 +588,28 @@ public class Robot {
} }
//Returns the angle between two angles, with positive angles indicating that the reference is //Returns the shortest angle between two directions, with positive angles indicating that the
//to the right (clockwise) of the current. Negative angles indicate that the reference is to the // reference is to the right (clockwise) of the current. Negative angles indicate that the
//left. // reference is to the left.
public float getRelativeAngle(float reference, float current) { public float getRelativeAngle(float reference, float current) {
return scaleAngleRange(current - reference); return scaleAngleRange(current - reference);
} }
//Drive Functions //Drive Functions
public void setDrivePower(double powerFrontLeft, double powerFrontRight, double powerBackLeft, double powerBackRight){ public void setDrivePower(double powerFrontLeft, double powerFrontRight,
double powerBackLeft, double powerBackRight){
driveFrontLeft.setPower(powerFrontLeft); driveFrontLeft.setPower(powerFrontLeft);
driveFrontRight.setPower(powerFrontRight); driveFrontRight.setPower(powerFrontRight);
driveBackLeft.setPower(powerBackLeft); driveBackLeft.setPower(powerBackLeft);
driveBackRight.setPower(powerBackRight); driveBackRight.setPower(powerBackRight);
} }
//returns an array of the powers necessary to execute the provided motion. "degreesDirectionMotion" //returns an array of the powers necessary to execute the provided motion.
//is the angle relative to the field that the robot should drive at. "degreesDirectionFace" is //"degreesDirectionMotion" is the angle relative to the field that the robot should drive at.
//the angle the robot should face relative to the field. The order of the output powers is //"degreesDirectionFace" is the angle the robot should face relative to the field. The order of
//is ForwardLeft, ForwardRight, BackLeft, BackRight //the output powers is ForwardLeft, ForwardRight, BackLeft, BackRight
public double[] getMecanumPowers(float degreesDirectionMotion, double scalar, float degreesDirectionFace) { public double[] getMecanumPowers(float degreesDirectionMotion, double scalar,
float degreesDirectionFace) {
angularVelocity = imu.getAngularVelocity().xRotationRate; angularVelocity = imu.getAngularVelocity().xRotationRate;
//calculating the base mecanum powers so that the robot drives along the degreesDirectionMotion //calculating the base mecanum powers so that the robot drives along the degreesDirectionMotion
@@ -582,12 +631,14 @@ public class Robot {
LINEAR_CORRECTION * relativeRotation; LINEAR_CORRECTION * relativeRotation;
if (relativeRotation != 0) { if (relativeRotation != 0) {
double momentumRelative = angularVelocity * (relativeRotation / Math.abs(relativeRotation)); double momentumRelative = angularVelocity *
double exponential = Math.pow(MOMENTUM_CORRECTION, MOMENTUM_HORIZONTAL_CORRECTION-momentumRelative); (relativeRotation / Math.abs(relativeRotation));
double exponential =
Math.pow(MOMENTUM_CORRECTION, MOMENTUM_HORIZONTAL_CORRECTION-momentumRelative);
double momentumCorrection = (MOMENTUM_MAX_CORRECTION*exponential)/(1+exponential); double momentumCorrection = (MOMENTUM_MAX_CORRECTION*exponential)/(1+exponential);
//reduces concern for momentum when the angle is far away from target //reduces concern for momentum when the angle is far away from target
turnCorrection *= momentumCorrection + ((Math.abs(relativeRotation) * (1 - momentumCorrection)) / 180 ); turnCorrection *= momentumCorrection + ((Math.abs(relativeRotation) *
// turnCorrection *= momentumCorrection; (1 - momentumCorrection)) / 180 );
} }
double powerForwardRight = scalar * (q + turnCorrection); double powerForwardRight = scalar * (q + turnCorrection);
@@ -660,6 +711,7 @@ public class Robot {
return powers; return powers;
} }
//Used to for automated jam countermeasures
public boolean beltIsStuck() { public boolean beltIsStuck() {
int ringBeltPos = ringBeltMotor.getCurrentPosition(); int ringBeltPos = ringBeltMotor.getCurrentPosition();
boolean notMoved = (ringBeltPos - ringBeltPrev <= beltMaxStopTicks); boolean notMoved = (ringBeltPos - ringBeltPrev <= beltMaxStopTicks);
@@ -677,6 +729,7 @@ public class Robot {
return angle; return angle;
} }
//Debugging tools
public void record(String record) { public void record(String record) {
TestingRecord+="\n"+record; TestingRecord+="\n"+record;
} }

View File

@@ -17,7 +17,6 @@ public class LaunchControl extends CyberarmState {
@Override @Override
public void start() { public void start() {
robot.launchMotor.setPower(Robot.LAUNCH_POWER);
if (robot.ringBeltStage > 2) { if (robot.ringBeltStage > 2) {
if (robot.ringBeltStage > 4) { if (robot.ringBeltStage > 4) {

View File

@@ -1,5 +1,11 @@
package org.timecrafters.UltimateGoal.Competition.TeleOp; package org.timecrafters.UltimateGoal.Competition.TeleOp;
/*
The Player1 state has all the controls for player one. The Player One and Player Two controls are
kept in separate states so that the childrenHaveFinished() method can be used to easily stop things
from running at the same time that shouldn't be.
*/
import com.qualcomm.hardware.rev.RevBlinkinLedDriver; import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import org.cyberarm.engine.V2.CyberarmState; import org.cyberarm.engine.V2.CyberarmState;
@@ -40,6 +46,7 @@ public class Player1 extends CyberarmState {
private double endGameX; private double endGameX;
private double endGameY; private double endGameY;
private float endGameRot; private float endGameRot;
private int loopCount;
private double refinePower; private double refinePower;
@@ -49,14 +56,21 @@ public class Player1 extends CyberarmState {
@Override @Override
public void init() { public void init() {
cardinalSnapping = robot.stateConfiguration.variable("tele","control", "cardinalSnapping").value(); cardinalSnapping = robot.stateConfiguration.variable(
pairSnapping = robot.stateConfiguration.variable("tele","control", "pairSnapping").value(); "tele","control", "cardinalSnapping").value();
faceControlThreshold = robot.stateConfiguration.variable("tele","control", "faceControlT").value(); pairSnapping = robot.stateConfiguration.variable(
refinePower = robot.stateConfiguration.variable("tele","control", "refPower").value(); "tele","control", "pairSnapping").value();
faceControlThreshold = robot.stateConfiguration.variable(
"tele","control", "faceControlT").value();
refinePower = robot.stateConfiguration.variable(
"tele","control", "refPower").value();
endGameX = robot.stateConfiguration.variable("tele","_endGameStart","x").value(); endGameX = robot.stateConfiguration.variable(
endGameY = robot.stateConfiguration.variable("tele","_endGameStart","y").value(); "tele","_endGameStart","x").value();
endGameRot = robot.stateConfiguration.variable("tele","_endGameStart", "r").value(); endGameY = robot.stateConfiguration.variable(
"tele","_endGameStart","y").value();
endGameRot = robot.stateConfiguration.variable(
"tele","_endGameStart", "r").value();
} }
@Override @Override
@@ -66,8 +80,11 @@ public class Player1 extends CyberarmState {
@Override @Override
public void exec() { public void exec() {
loopCount+=1;
robot.record(""+runTime()+", "+loopCount+", "+robot.getRotation());
robot.updateLocation(); robot.updateLocation();
//toggle for drive speed
boolean lb = engine.gamepad1.left_stick_button; boolean lb = engine.gamepad1.left_stick_button;
if (lb && !lbPrev) { if (lb && !lbPrev) {
if (drivePower == 1) { if (drivePower == 1) {
@@ -78,7 +95,9 @@ public class Player1 extends CyberarmState {
} }
lbPrev = lb; lbPrev = lb;
//This Runs the FindWobbleGoal state as long as the button is pressed. When it's released,
//the state is interrupted. If the state finishes while the button is still pressed,
//it waits until the button is released before running the state again
runNextFindWobble = (findWobbleGoal == null || findWobbleGoal.getHasFinished()); runNextFindWobble = (findWobbleGoal == null || findWobbleGoal.getHasFinished());
boolean findWobbleInput = engine.gamepad1.x; boolean findWobbleInput = engine.gamepad1.x;
@@ -89,7 +108,8 @@ public class Player1 extends CyberarmState {
faceDirection = robot.getRotation(); faceDirection = robot.getRotation();
if (runNextFindWobble && !findWobbleInputPrev) { if (runNextFindWobble && !findWobbleInputPrev) {
findWobbleGoal = new FindWobbleGoal(robot, "auto", "08_0"); findWobbleGoal =
new FindWobbleGoal(robot, "auto", "08_0");
addParallelState(findWobbleGoal); addParallelState(findWobbleGoal);
} }
//if the claw is closed, open the claw. //if the claw is closed, open the claw.
@@ -113,6 +133,8 @@ public class Player1 extends CyberarmState {
} }
aPrev = a; aPrev = a;
//This logic works the same as the stuff above, accept instead of autonomous wobble grab,
//it
runNextDriveToLaunch = (powerShots == null || powerShots.getHasFinished()); runNextDriveToLaunch = (powerShots == null || powerShots.getHasFinished());
boolean driveToLaunchInput = engine.gamepad1.y && !findWobbleInput; boolean driveToLaunchInput = engine.gamepad1.y && !findWobbleInput;
@@ -127,29 +149,27 @@ public class Player1 extends CyberarmState {
} }
driveToLaunchInputPrev = driveToLaunchInput; driveToLaunchInputPrev = driveToLaunchInput;
// if (engine.gamepad1.y) { //Normal Driver Controls
// robot.setLocalization(endGameRot,endGameX,endGameY);
// setHasFinished(true);
// }
if (childrenHaveFinished()) { if (childrenHaveFinished()) {
//Normal Driver Controls
double leftJoystickX = engine.gamepad1.left_stick_x; double leftJoystickX = engine.gamepad1.left_stick_x;
double leftJoystickY = engine.gamepad1.left_stick_y; double leftJoystickY = engine.gamepad1.left_stick_y;
leftJoystickDegrees = robot.getRelativeAngle(90, (float) Math.toDegrees(Math.atan2(leftJoystickX, -leftJoystickY))); leftJoystickDegrees = robot.getRelativeAngle(90,
(float) Math.toDegrees(Math.atan2(leftJoystickX, -leftJoystickY)));
leftJoystickMagnitude = Math.hypot(leftJoystickX, leftJoystickY); leftJoystickMagnitude = Math.hypot(leftJoystickX, leftJoystickY);
double rightJoystickX = engine.gamepad1.right_stick_x; double rightJoystickX = engine.gamepad1.right_stick_x;
double rightJoystickY = engine.gamepad1.right_stick_y; double rightJoystickY = engine.gamepad1.right_stick_y;
rightJoystickDegrees = robot.getRelativeAngle(90, (float) Math.toDegrees(Math.atan2(rightJoystickX, -rightJoystickY))); rightJoystickDegrees = robot.getRelativeAngle(90,
(float) Math.toDegrees(Math.atan2(rightJoystickX, -rightJoystickY)));
rightJoystickMagnitude = Math.hypot(rightJoystickX, rightJoystickY); rightJoystickMagnitude = Math.hypot(rightJoystickX, rightJoystickY);
//allows the the driver to indicate which direction the robot is currently looking //allows the the driver to indicate which direction the robot is currently looking
//so that the controller and robot can be re-synced in the event of a bad initial //so that the controller and robot can be re-synced in the event of a bad initial
//position. //rotation.
if (engine.gamepad1.back) { if (engine.gamepad1.back) {
float newRotation = 0; float newRotation = 0;
@@ -161,14 +181,19 @@ public class Player1 extends CyberarmState {
faceDirection = newRotation; faceDirection = newRotation;
} }
//if the driver is letting go of the face joystick, the robot should maintain it's current face direction. //if the driver is letting go of the face joystick, the robot should maintain it's
if (rightJoystickMagnitude > faceControlThreshold || rightJoystickMagnitude - rightJoystickMagnitudePrevious > 0) { //current face direction.
if (rightJoystickMagnitude > faceControlThreshold ||
rightJoystickMagnitude - rightJoystickMagnitudePrevious > 0) {
//if the joystick is close to one of the cardinal directions, it is set to exactly the cardinal direction //if the joystick is close to one of the cardinal directions, it is set to exactly
// the cardinal direction
faceDirection = snapToCardinal(rightJoystickDegrees, cardinalSnapping, 0); faceDirection = snapToCardinal(rightJoystickDegrees, cardinalSnapping, 0);
} }
rightJoystickMagnitudePrevious = rightJoystickMagnitude; rightJoystickMagnitudePrevious = rightJoystickMagnitude;
//The D-pad is used if the drivers need to get a more precise angle than they can get
//using the face joystick
if (engine.gamepad1.dpad_right) { if (engine.gamepad1.dpad_right) {
powers = new double[]{refinePower, -refinePower, refinePower, -refinePower}; powers = new double[]{refinePower, -refinePower, refinePower, -refinePower};
faceDirection = robot.getRotation(); faceDirection = robot.getRotation();
@@ -182,7 +207,9 @@ public class Player1 extends CyberarmState {
//drives the robot in the direction of the move joystick while facing the direction //drives the robot in the direction of the move joystick while facing the direction
//of the look joystick. if the move direction is almost aligned/perpendicular to the //of the look joystick. if the move direction is almost aligned/perpendicular to the
//look joystick, //look joystick,
powers = robot.getMecanumPowers(snapToCardinal(leftJoystickDegrees, pairSnapping, faceDirection), drivePower, faceDirection); powers = robot.getMecanumPowers(
snapToCardinal(leftJoystickDegrees, pairSnapping, faceDirection),
drivePower, faceDirection);
} }
robot.setDrivePower(powers[0], powers[1], powers[2], powers[3]); robot.setDrivePower(powers[0], powers[1], powers[2], powers[3]);
@@ -190,7 +217,8 @@ public class Player1 extends CyberarmState {
//LED feedback control //LED feedback control
double ringBeltPower = robot.ringBeltMotor.getPower(); double ringBeltPower = robot.ringBeltMotor.getPower();
if (ringBeltPower > 0 && Math.abs(robot.ringBeltMotor.getTargetPosition() - robot.ringBeltMotor.getCurrentPosition()) > 10) { if (ringBeltPower > 0 && Math.abs(robot.ringBeltMotor.getTargetPosition() -
robot.ringBeltMotor.getCurrentPosition()) > 10) {
robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.HEARTBEAT_BLUE ); robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.HEARTBEAT_BLUE );
} else if (ringBeltPower < 0) { } else if (ringBeltPower < 0) {
robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.HEARTBEAT_RED); robot.ledDriver.setPattern(RevBlinkinLedDriver.BlinkinPattern.HEARTBEAT_RED);

View File

@@ -1,9 +1,15 @@
package org.timecrafters.UltimateGoal.Competition.TeleOp; package org.timecrafters.UltimateGoal.Competition.TeleOp;
/*
The Player2 state has all the controls for player two. This includes a lot of automation and
emergency features, for if the driver wants to take control unexpectedly
*/
import com.qualcomm.hardware.rev.RevBlinkinLedDriver; import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import com.qualcomm.robotcore.hardware.DcMotor; import com.qualcomm.robotcore.hardware.DcMotor;
import org.cyberarm.engine.V2.CyberarmState; import org.cyberarm.engine.V2.CyberarmState;
import org.firstinspires.ftc.robotcore.external.navigation.CurrentUnit;
import org.timecrafters.UltimateGoal.Competition.Launch; import org.timecrafters.UltimateGoal.Competition.Launch;
import org.timecrafters.UltimateGoal.Competition.ProgressRingBelt; import org.timecrafters.UltimateGoal.Competition.ProgressRingBelt;
import org.timecrafters.UltimateGoal.Competition.Robot; import org.timecrafters.UltimateGoal.Competition.Robot;
@@ -22,6 +28,7 @@ public class Player2 extends CyberarmState {
private DcMotor.RunMode runModePrev; private DcMotor.RunMode runModePrev;
private boolean lbPrev; private boolean lbPrev;
private boolean manualArmHold; private boolean manualArmHold;
private int loops = 0;
@@ -45,9 +52,10 @@ public class Player2 extends CyberarmState {
@Override @Override
public void exec() { public void exec() {
// loops+=1;
// robot.record(""+runTime()+", "+loops+", "+robot.getRotation());
//Collector control //Collector control
double rt = engine.gamepad2.right_trigger; double rt = engine.gamepad2.right_trigger;
double lt = engine.gamepad2.left_trigger; double lt = engine.gamepad2.left_trigger;
if (rt < lt) { if (rt < lt) {
@@ -58,6 +66,8 @@ public class Player2 extends CyberarmState {
robot.collectionMotor.setPower(0); robot.collectionMotor.setPower(0);
} }
//The childrenHaveFinished() method tracks if there are parallel states that are still
//running.
if (childrenHaveFinished()) { if (childrenHaveFinished()) {
//belt progression control //belt progression control
boolean rb = engine.gamepad2.right_bumper; boolean rb = engine.gamepad2.right_bumper;
@@ -140,33 +150,40 @@ public class Player2 extends CyberarmState {
} }
lbPrev = lb; lbPrev = lb;
// if (engine.gamepad1.y) { if (engine.gamepad2.back) {
// setHasFinished(true); for (CyberarmState state : children) {
// } engine.stopState(state);
}
}
} }
//This just checks if the wobble arm runmode is already the desired mode before setting it.
//I don't know if this is actually helpful
private void setArmMode(DcMotor.RunMode runMode) { private void setArmMode(DcMotor.RunMode runMode) {
if (robot.wobbleArmMotor.getMode() != runMode) { if (robot.wobbleArmMotor.getMode() != runMode) {
robot.wobbleArmMotor.setMode(runMode); robot.wobbleArmMotor.setMode(runMode);
} }
} }
@Override @Override
public void telemetry() { public void telemetry() {
// engine.telemetry.addLine("belt"); // engine.telemetry.addLine("belt");
// engine.telemetry.addData("power", robot.ringBeltMotor.getPower()); // engine.telemetry.addData("power", robot.ringBeltMotor.getPower());
// engine.telemetry.addData("pos", robot.ringBeltMotor.getCurrentPosition()); // engine.telemetry.addData("pos", robot.ringBeltMotor.getCurrentPosition());
// engine.telemetry.addData("target", robot.ringBeltMotor.getTargetPosition()); // engine.telemetry.addData("target", robot.ringBeltMotor.getTargetPosition());
//
// engine.telemetry.addData("ring belt stage", robot.ringBeltStage); // engine.telemetry.addData("ring belt stage", robot.ringBeltStage);
// engine.telemetry.addData("Touch Sensor Pressed", robot.wobbleTouchSensor.isPressed()); // engine.telemetry.addData("Touch Sensor Pressed", robot.wobbleTouchSensor.isPressed());
// engine.telemetry.addData(" Sensor value", robot.wobbleTouchSensor.getValue()); // engine.telemetry.addData(" Sensor value", robot.wobbleTouchSensor.getValue());
// engine.telemetry.addData("Player 2 children", childrenHaveFinished()); engine.telemetry.addData("Player 2 children", childrenHaveFinished());
// for (CyberarmState state : children) { for (CyberarmState state : children) {
// if (!state.getHasFinished()) { if (!state.getHasFinished()) {
// engine.telemetry.addLine("" + state.getClass()); engine.telemetry.addLine("" + state.getClass());
// } }
// } }
} }
} }

View File

@@ -1,12 +1,13 @@
package org.timecrafters.UltimateGoal.Competition.TeleOp; package org.timecrafters.UltimateGoal.Competition.TeleOp;
import com.qualcomm.robotcore.eventloop.opmode.Disabled;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp; import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import org.cyberarm.engine.V2.CyberarmEngine; import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Competition.Autonomous.DriveToCoordinates; import org.timecrafters.UltimateGoal.Competition.Autonomous.DriveToCoordinates;
import org.timecrafters.UltimateGoal.Competition.Autonomous.Face; import org.timecrafters.UltimateGoal.Competition.Autonomous.Face;
import org.timecrafters.UltimateGoal.Competition.Robot; import org.timecrafters.UltimateGoal.Competition.Robot;
@Disabled
@TeleOp (name = "TeleOp",group = "comp") @TeleOp (name = "TeleOp",group = "comp")
public class TeleOpEngine extends CyberarmEngine { public class TeleOpEngine extends CyberarmEngine {

View File

@@ -3,6 +3,7 @@ package org.timecrafters.UltimateGoal.Competition.TeleOp;
import org.cyberarm.engine.V2.CyberarmState; import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.UltimateGoal.Competition.Autonomous.DriveToCoordinates; import org.timecrafters.UltimateGoal.Competition.Autonomous.DriveToCoordinates;
import org.timecrafters.UltimateGoal.Competition.Autonomous.Face; import org.timecrafters.UltimateGoal.Competition.Autonomous.Face;
import org.timecrafters.UltimateGoal.Competition.Pause;
import org.timecrafters.UltimateGoal.Competition.Robot; import org.timecrafters.UltimateGoal.Competition.Robot;
import java.util.ArrayList; import java.util.ArrayList;
@@ -15,6 +16,8 @@ public class powerShotsControl extends CyberarmState {
private double endGameY; private double endGameY;
private float endGameRot; private float endGameRot;
private double endGamePower;
private int nextState = 0; private int nextState = 0;
private ArrayList<CyberarmState> states = new ArrayList<CyberarmState>(); private ArrayList<CyberarmState> states = new ArrayList<CyberarmState>();
@@ -28,11 +31,13 @@ public class powerShotsControl extends CyberarmState {
endGameX = robot.stateConfiguration.variable("tele","_endGameStart","x").value(); endGameX = robot.stateConfiguration.variable("tele","_endGameStart","x").value();
endGameY = robot.stateConfiguration.variable("tele","_endGameStart","y").value(); endGameY = robot.stateConfiguration.variable("tele","_endGameStart","y").value();
endGameRot = robot.stateConfiguration.variable("tele","_endGameStart", "r").value(); endGameRot = robot.stateConfiguration.variable("tele","_endGameStart", "r").value();
endGamePower = robot.stateConfiguration.variable("tele","_endGameStart", "power").value();
endGameX = robot.inchesToTicks(endGameX); endGameX = robot.inchesToTicks(endGameX);
endGameY = robot.inchesToTicks(endGameY); endGameY = robot.inchesToTicks(endGameY);
endGameRot = (float) robot.inchesToTicks(endGameRot); endGameRot = (float) robot.inchesToTicks(endGameRot);
states.add(new Pause(robot, "tele","_endGameStart"));
states.add(new DriveToCoordinates(robot, "tele", "_pow1")); states.add(new DriveToCoordinates(robot, "tele", "_pow1"));
states.add(new Face(robot,"tele","_faceZero")); states.add(new Face(robot,"tele","_faceZero"));
states.add(new LaunchControl(robot)); states.add(new LaunchControl(robot));
@@ -47,7 +52,7 @@ public class powerShotsControl extends CyberarmState {
@Override @Override
public void start() { public void start() {
robot.setLocalization(endGameRot,endGameX,endGameY); robot.setLocalization(endGameRot,endGameX,endGameY);
robot.launchMotor.setPower(Robot.LAUNCH_POWER); robot.launchMotor.setPower(endGamePower);
} }
@Override @Override

View File

@@ -0,0 +1,22 @@
package org.timecrafters.javaClass.aubrey;
import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.javaClass.samples.SampleRobot;
public class AubreyFirstState extends CyberarmState {
//here, you'll find some of your variables. you can add more as you need them.
private SampleRobot robot;
//This is the constructor. It lets other code bits run use the code you put here
public AubreyFirstState(SampleRobot robot) {
this.robot = robot;
}
//This is a method. methods are bits of code that can be run elsewhere.
//This one is set up to repeat every few milliseconds
@Override
public void exec() {
}
}

View File

@@ -0,0 +1,26 @@
package org.timecrafters.javaClass.samples;
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Competition.Robot;
import org.timecrafters.javaClass.aubrey.AubreyFirstState;
@Autonomous(name = "Aubrey: First Program", group = "aubrey")
public class AubreyFirstEngine extends CyberarmEngine {
SampleRobot robot;
@Override
public void init() {
robot = new SampleRobot(hardwareMap);
robot.initHardware();
robot.wobbleGrabServo.setPosition(Robot.WOBBLE_SERVO_CLOSED);
super.init();
}
@Override
public void setup() {
addState(new AubreyFirstState(robot));
}
}

View File

@@ -0,0 +1,191 @@
package org.timecrafters.javaClass.samples;
/*
The robot object contains all the hardware and functions that are used in both teleOp and
Autonomous. This includes drive functions, localization functions, shared constants, and a few
general calculations and debugging tools.
*/
import android.os.Environment;
import android.util.Log;
import com.qualcomm.hardware.bosch.BNO055IMU;
import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import com.qualcomm.hardware.rev.RevColorSensorV3;
import com.qualcomm.hardware.rev.RevTouchSensor;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorEx;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.hardware.HardwareMap;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
import org.firstinspires.ftc.robotcore.external.ClassFactory;
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.robotcore.external.matrices.OpenGLMatrix;
import org.firstinspires.ftc.robotcore.external.matrices.VectorF;
import org.firstinspires.ftc.robotcore.external.navigation.Orientation;
import org.firstinspires.ftc.robotcore.external.navigation.Position;
import org.firstinspires.ftc.robotcore.external.navigation.Velocity;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaLocalizer;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackable;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackableDefaultListener;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackables;
import org.firstinspires.ftc.robotcore.external.tfod.TFObjectDetector;
import org.timecrafters.TimeCraftersConfigurationTool.TimeCraftersConfiguration;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.firstinspires.ftc.robotcore.external.navigation.AngleUnit.DEGREES;
import static org.firstinspires.ftc.robotcore.external.navigation.AxesOrder.XYZ;
import static org.firstinspires.ftc.robotcore.external.navigation.AxesOrder.YZX;
import static org.firstinspires.ftc.robotcore.external.navigation.AxesReference.EXTRINSIC;
public class SampleRobot {
private HardwareMap hardwareMap;
public SampleRobot(HardwareMap hardwareMap) {
this.hardwareMap = hardwareMap;
}
//The TimeCraftersConfiguration is part of a debugging and tuning tool that allows us to edit
//variables saved on the phone, without having to re-download the whole program. This is
//especially useful for autonomous route tuning
public TimeCraftersConfiguration stateConfiguration = new TimeCraftersConfiguration();
//We use the IMU to get reliable rotation and angular velocity information. Experimentation has
//demonstrated that the accelerometer and related integrations aren't as accurate.
public BNO055IMU imu;
//The LEDs are used to provide driver feedback and for looking beautiful
public RevBlinkinLedDriver ledDriver;
//drive and dead-wheal hardware
public DcMotor driveFrontLeft;
public DcMotor driveBackLeft;
public DcMotor driveFrontRight;
public DcMotor driveBackRight;
public DcMotor encoderLeft;
public DcMotor encoderRight;
public DcMotor encoderBack;
//Unit Conversion Constants
static final double ENCODER_CIRCUMFERENCE = Math.PI * 2.3622;
static final int COUNTS_PER_REVOLUTION = 8192;
//Launcher
public DcMotor launchMotor;
public static final double LAUNCH_POWER = 0.715;
//Ring Intake
public DcMotor collectionMotor;
//Ring Belt
public DcMotor ringBeltMotor;
public RevTouchSensor limitSwitch;
//Wobble Goal Arm & Grabber
public DcMotor wobbleArmMotor;
public Servo wobbleGrabServo;
public RevColorSensorV3 wobbleColorSensor;
public RevTouchSensor wobbleTouchSensor;
//All our hardware initialization in one place, for everything that is the same in TeleOp and
//Autonomous
public void initHardware() {
//drive motors
driveFrontLeft = hardwareMap.dcMotor.get("driveFrontLeft");
driveFrontRight = hardwareMap.dcMotor.get("driveFrontRight");
driveBackLeft = hardwareMap.dcMotor.get("driveBackLeft");
driveBackRight = hardwareMap.dcMotor.get("driveBackRight");
driveFrontLeft.setDirection(DcMotorSimple.Direction.FORWARD);
driveFrontRight.setDirection(DcMotorSimple.Direction.REVERSE);
driveBackLeft.setDirection(DcMotorSimple.Direction.FORWARD);
driveBackRight.setDirection(DcMotorSimple.Direction.REVERSE);
//Localization encoders
encoderRight = hardwareMap.dcMotor.get("driveFrontRight");
encoderBack = hardwareMap.dcMotor.get("driveFrontLeft");
encoderLeft = hardwareMap.dcMotor.get("collect");
encoderRight.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
encoderRight.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
encoderBack.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
encoderBack.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
encoderLeft.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
encoderLeft.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
//init wobble arm
wobbleArmMotor = hardwareMap.dcMotor.get("wobbleArm");
wobbleArmMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
wobbleArmMotor.setTargetPosition(0);
wobbleArmMotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
wobbleGrabServo = hardwareMap.servo.get("wobbleGrab");
wobbleColorSensor = hardwareMap.get(RevColorSensorV3.class, "color");
wobbleTouchSensor = hardwareMap.get(RevTouchSensor.class, "touch");
//init collection motor
collectionMotor = hardwareMap.dcMotor.get("collect");
collectionMotor.setDirection(DcMotorSimple.Direction.REVERSE);
//init ring belt
ringBeltMotor = hardwareMap.dcMotor.get("belt");
ringBeltMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
ringBeltMotor .setMode(DcMotor.RunMode.RUN_USING_ENCODER);
limitSwitch = hardwareMap.get(RevTouchSensor.class, "magLim");
//init IMU
imu = hardwareMap.get(BNO055IMU.class, "imu");
BNO055IMU.Parameters parameters = new BNO055IMU.Parameters();
parameters.mode = BNO055IMU.SensorMode.IMU;
parameters.angleUnit = BNO055IMU.AngleUnit.DEGREES;
parameters.accelUnit = BNO055IMU.AccelUnit.METERS_PERSEC_PERSEC;
parameters.loggingEnabled = false;
imu.initialize(parameters);
//Init Launch Motor
DcMotor launcher = hardwareMap.dcMotor.get("launcher");
MotorConfigurationType launchMotorType = launcher.getMotorType();
launchMotorType.setGearing(3);
launchMotorType.setTicksPerRev(84);
launchMotorType.setMaxRPM(2400);
launchMotor = launcher;
launchMotor.setMotorType(launchMotorType);
launchMotor.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
launchMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);
ledDriver = hardwareMap.get(RevBlinkinLedDriver.class, "leds");
}
public float getIMURotation() {
return imu.getAngularOrientation().firstAngle;
}
//Unit conversions
public double ticksToInches(double ticks) {
return ticks * (ENCODER_CIRCUMFERENCE / COUNTS_PER_REVOLUTION);
}
public double inchesToTicks(double inches) {
return inches * (COUNTS_PER_REVOLUTION / ENCODER_CIRCUMFERENCE);
}
}

View File

@@ -0,0 +1,515 @@
package org.timecrafters.javaClass.samples;
/*
The robot object contains all the hardware and functions that are used in both teleOp and
Autonomous. This includes drive functions, localization functions, shared constants, and a few
general calculations and debugging tools.
*/
import com.qualcomm.hardware.bosch.BNO055IMU;
import com.qualcomm.hardware.rev.RevBlinkinLedDriver;
import com.qualcomm.hardware.rev.RevColorSensorV3;
import com.qualcomm.hardware.rev.RevTouchSensor;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorEx;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.hardware.HardwareMap;
import com.qualcomm.robotcore.hardware.Servo;
import com.qualcomm.robotcore.hardware.configuration.typecontainers.MotorConfigurationType;
import org.firstinspires.ftc.robotcore.external.hardware.camera.WebcamName;
import org.firstinspires.ftc.robotcore.external.matrices.OpenGLMatrix;
import org.firstinspires.ftc.robotcore.external.navigation.Position;
import org.firstinspires.ftc.robotcore.external.navigation.Velocity;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaLocalizer;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackable;
import org.firstinspires.ftc.robotcore.external.navigation.VuforiaTrackables;
import org.firstinspires.ftc.robotcore.external.tfod.TFObjectDetector;
import org.timecrafters.TimeCraftersConfigurationTool.TimeCraftersConfiguration;
import org.timecrafters.UltimateGoal.Competition.Robot;
import java.util.ArrayList;
import java.util.List;
public class SampleRobotEx {
private HardwareMap hardwareMap;
public SampleRobotEx(HardwareMap hardwareMap) {
this.hardwareMap = hardwareMap;
}
//The TimeCraftersConfiguration is part of a debugging and tuning tool that allows us to edit
//variables saved on the phone, without having to re-download the whole program. This is
//especially useful for autonomous route tuning
public TimeCraftersConfiguration stateConfiguration = new TimeCraftersConfiguration();
//We use the IMU to get reliable rotation and angular velocity information. Experimentation has
//demonstrated that the accelerometer and related integrations aren't as accurate.
public BNO055IMU imu;
//The LEDs are used to provide driver feedback and for looking beautiful
public RevBlinkinLedDriver ledDriver;
//drive and dead-wheal hardware
public DcMotor driveFrontLeft;
public DcMotor driveBackLeft;
public DcMotor driveFrontRight;
public DcMotor driveBackRight;
public DcMotor encoderLeft;
public DcMotor encoderRight;
public DcMotor encoderBack;
//Motion Constants
static final double CUBIC_CORRECTION = 0.035;
static final double FACE_CUBIC_CORRECTION = 0.025;
static final double LINEAR_CORRECTION = 0.055;
static final double FACE_MIN_CORRECTION = 0.2;
static final double FACE_LINEAR_CORRECTION = 0.025;
static final double MOMENTUM_CORRECTION = 1.05;
static final double MOMENTUM_MAX_CORRECTION = 1.4;
static final double MOMENTUM_HORIZONTAL_CORRECTION =
-(Math.log10(MOMENTUM_MAX_CORRECTION-1) / Math.log10(MOMENTUM_CORRECTION));
static final double FACE_MOMENTUM_MAX_CORRECTION = 1.1;
static final double FACE_MOMENTUM_CORRECTION = 1.06;
static final double FACE_MOMENTUM_HORIZONTAL_CORRECTION =
-(Math.log10(FACE_MOMENTUM_MAX_CORRECTION-1) / Math.log10(FACE_MOMENTUM_CORRECTION));
static final double ZERO_POWER_THRESHOLD = 0.25;
//Unit Conversion Constants
static final double ENCODER_CIRCUMFERENCE = Math.PI * 2.3622;
static final int COUNTS_PER_REVOLUTION = 8192;
static final float mmPerInch = 25.4f;
static final double TICKS_PER_ROBOT_DEGREE_CLOCKWISE_FORWARD = 12.3;
static final double TICKS_PER_ROBOT_DEGREE_COUNTERCLOCKWISE_FORWARD = 18.8;
static final double TICKS_PER_ROBOT_DEGREE_CLOCKWISE = 8.4;
static final double TICKS_PER_ROBOT_DEGREE_COUNTERCLOCKWISE = 8.6;
//Robot Localization
private static double locationX;
private static double locationY;
private static float rotation;
private int encoderLeftPrevious = 0;
private int encoderBackPrevious = 0;
private int encoderRightPrevious = 0;
private float rotationPrevious = 0;
public float angularVelocity;
public double forwardVector;
public double sidewaysVector;
//vuforia && tensorFlow Stuff
private WebcamName webcam;
private VuforiaLocalizer vuforia;
// Inches Forward of axis of rotation
static final float CAMERA_FORWARD_DISPLACEMENT = 8f;
// Inches above Ground
static final float CAMERA_VERTICAL_DISPLACEMENT = 9.5f;
// Inches Left of axis of rotation
static final float CAMERA_LEFT_DISPLACEMENT = 4f;
static final double CAMERA_DISPLACEMENT_MAG =
Math.hypot(CAMERA_FORWARD_DISPLACEMENT,CAMERA_LEFT_DISPLACEMENT);
static final float CAMERA_DISPLACEMENT_DIRECTION =
(float) -Math.atan(CAMERA_LEFT_DISPLACEMENT/CAMERA_FORWARD_DISPLACEMENT);
public boolean trackableVisible;
private VuforiaTrackables targetsUltimateGoal;
private List<VuforiaTrackable> trackables = new ArrayList<VuforiaTrackable>();
private OpenGLMatrix lastConfirmendLocation;
private long timeStartZeroVelocity = 0;
private long minCheckDurationMs = 500;
private int minCheckVelocity = 1;
private float vuforiaRotationCull;
//The servo mount for our camera allows us to look down for ideal TensorFlow and look up for
//ideal Vuforia Navigation
public Servo webCamServo;
public static final double CAM_SERVO_DOWN = 0.15;
//TensorFlow Object Detection
public TFObjectDetector tfObjectDetector;
private static final float MINIMUM_CONFIDENCE = 0.8f;
//Launcher
public DcMotor launchMotor;
public static final double LAUNCH_POWER = 0.715;
private static final long LAUNCH_ACCEL_TIME = 500;
//These variables were originally going to be used in both autonomous and teleOp
public double launchPositionX;
public double launchPositionY;
public float launchRotation;
public int reduceLaunchPos;
public boolean initLauncher;
//Ring Intake
public DcMotor collectionMotor;
//Ring Belt
public DcMotor ringBeltMotor;
public RevTouchSensor limitSwitch;
public int ringBeltStage;
public int ringBeltGap = 700;
public static final double RING_BELT_SLOW_POWER = 0.2;
public static final double RING_BELT_NORMAL_POWER = 0.6;
private int ringBeltPrev;
public long beltMaxStopTime;
public int beltReverseTicks;
public int beltMaxStopTicks;
//Wobble Goal Arm & Grabber
public DcMotor wobbleArmMotor;
public Servo wobbleGrabServo;
public int wobbleDownPos;
public int wobbleUpPos;
public int wobbleDropPos;
public static final double WOBBLE_SERVO_OPEN = 0;
public static final double WOBBLE_SERVO_CLOSED = 1;
public RevColorSensorV3 wobbleColorSensor;
public double wobbleScoreX;
public double wobbleScoreY;
public RevTouchSensor wobbleTouchSensor;
//Debugging
public double totalV;
private String TestingRecord = "Raw IMU, Delta, Saved";
public double traveledForward = 0;
public DcMotorEx motorAmpsTest;
//All our hardware initialization in one place, for everything that is the same in TeleOp and
//Autonomous
public void initHardware() {
//drive motors
driveFrontLeft = hardwareMap.dcMotor.get("driveFrontLeft");
driveFrontRight = hardwareMap.dcMotor.get("driveFrontRight");
driveBackLeft = hardwareMap.dcMotor.get("driveBackLeft");
driveBackRight = hardwareMap.dcMotor.get("driveBackRight");
driveFrontLeft.setDirection(DcMotorSimple.Direction.FORWARD);
driveFrontRight.setDirection(DcMotorSimple.Direction.REVERSE);
driveBackLeft.setDirection(DcMotorSimple.Direction.FORWARD);
driveBackRight.setDirection(DcMotorSimple.Direction.REVERSE);
//Localization encoders
encoderRight = hardwareMap.dcMotor.get("driveFrontRight");
encoderBack = hardwareMap.dcMotor.get("driveFrontLeft");
encoderLeft = hardwareMap.dcMotor.get("collect");
encoderRight.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
encoderRight.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
encoderBack.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
encoderBack.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
encoderLeft.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
encoderLeft.setMode(DcMotor.RunMode.RUN_WITHOUT_ENCODER);
//init wobble arm
wobbleArmMotor = hardwareMap.dcMotor.get("wobbleArm");
wobbleArmMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
wobbleArmMotor.setTargetPosition(0);
wobbleArmMotor.setMode(DcMotor.RunMode.RUN_TO_POSITION);
wobbleGrabServo = hardwareMap.servo.get("wobbleGrab");
wobbleColorSensor = hardwareMap.get(RevColorSensorV3.class, "color");
wobbleTouchSensor = hardwareMap.get(RevTouchSensor.class, "touch");
//init collection motor
collectionMotor = hardwareMap.dcMotor.get("collect");
collectionMotor.setDirection(DcMotorSimple.Direction.REVERSE);
//init ring belt
ringBeltMotor = hardwareMap.dcMotor.get("belt");
ringBeltMotor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
ringBeltMotor .setMode(DcMotor.RunMode.RUN_USING_ENCODER);
limitSwitch = hardwareMap.get(RevTouchSensor.class, "magLim");
//init IMU
imu = hardwareMap.get(BNO055IMU.class, "imu");
BNO055IMU.Parameters parameters = new BNO055IMU.Parameters();
parameters.mode = BNO055IMU.SensorMode.IMU;
parameters.angleUnit = BNO055IMU.AngleUnit.DEGREES;
parameters.accelUnit = BNO055IMU.AccelUnit.METERS_PERSEC_PERSEC;
parameters.loggingEnabled = false;
imu.initialize(parameters);
Velocity startVelocity = new Velocity();
startVelocity.xVeloc = 0;
startVelocity.yVeloc = 0;
startVelocity.zVeloc = 0;
Position startPosition = new Position();
startPosition.x = 0;
startPosition.y = 0;
startPosition.z = 0;
imu.startAccelerationIntegration(startPosition,startVelocity, 10);
//Init Launch Motor
DcMotor launcher = hardwareMap.dcMotor.get("launcher");
MotorConfigurationType launchMotorType = launcher.getMotorType();
launchMotorType.setGearing(3);
launchMotorType.setTicksPerRev(84);
launchMotorType.setMaxRPM(2400);
launchMotor = launcher;
launchMotor.setMotorType(launchMotorType);
launchMotor.setMode(DcMotor.RunMode.RUN_USING_ENCODER);
launchMotor.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.FLOAT);
ledDriver = hardwareMap.get(RevBlinkinLedDriver.class, "leds");
}
//Localization Function! This function is represented in a flow diagram, earlier in the
//software section
//run this in every exec to track the robot's location.
public void updateLocation(){
// orientation is inverted to have clockwise be positive.
float imuAngle = -imu.getAngularOrientation().firstAngle;
double rotationChange = getRelativeAngle(rotationPrevious, imuAngle);
int encoderLeftCurrent = -encoderLeft.getCurrentPosition();
int encoderRightCurrent = encoderRight.getCurrentPosition();
int encoderBackCurrent = encoderBack.getCurrentPosition();
double encoderLeftChange = encoderLeftCurrent - encoderLeftPrevious;
double encoderRightChange = encoderRightCurrent - encoderRightPrevious;
double encoderBackChange = encoderBackCurrent - encoderBackPrevious;
encoderLeftPrevious = encoderLeftCurrent;
encoderRightPrevious = encoderRightCurrent;
encoderBackPrevious = encoderBackCurrent;
rotationPrevious = imuAngle;
//The forward Vector has the luxury of having an odometer on both sides of the robot.
//This allows us to reduce the unwanted influence of turning the robot by averaging
//the two. unfortunatly we the current positioning of the odometers
//Since there isn't a second wheel to remove the influence of robot rotation, we have to
//instead do this by approximating the number of ticks that were removed due to rotation
//based on a separate calibration program.
double ticksPerDegreeForward;
double ticksPerDegreeSideways;
if (rotationChange < 0) {
ticksPerDegreeSideways = TICKS_PER_ROBOT_DEGREE_COUNTERCLOCKWISE;
ticksPerDegreeForward = TICKS_PER_ROBOT_DEGREE_COUNTERCLOCKWISE_FORWARD;
} else {
ticksPerDegreeSideways = TICKS_PER_ROBOT_DEGREE_CLOCKWISE;
ticksPerDegreeForward = TICKS_PER_ROBOT_DEGREE_CLOCKWISE_FORWARD;
}
forwardVector = ((encoderLeftChange+encoderRightChange)/2) -
(rotationChange* ticksPerDegreeForward);
sidewaysVector = encoderBackChange + (rotationChange * ticksPerDegreeSideways);
double magnitude = Math.sqrt((forwardVector*forwardVector) + (sidewaysVector*sidewaysVector));
double direction = Math.toRadians(SampleRobotEx.rotation + (rotationChange/2)) +
Math.atan2(sidewaysVector,forwardVector);
double xChange = magnitude * (Math.sin(direction));
double yChange = magnitude * (Math.cos(direction));
locationX += xChange;
locationY += yChange;
SampleRobotEx.rotation += rotationChange;
SampleRobotEx.rotation = scaleAngleRange(SampleRobotEx.rotation);
}
public float getRotation() {
return SampleRobotEx.rotation;
}
public double getLocationX() {
return SampleRobotEx.locationX;
}
public double getLocationY() {
return SampleRobotEx.locationY;
}
//This is meant to only be used to indicate starting positions and to reorient the robot.
public void setLocalization(float rotation, double x, double y) {
SampleRobotEx.rotation = rotation;
SampleRobotEx.locationX = x;
SampleRobotEx.locationY = y;
}
//returns the angle from the robot's current position to the given target position.
public float getAngleToPosition (double x, double y) {
double differenceX = x- getLocationX();
double differenceY = y- getLocationY();
double angle = Math.toDegrees(Math.atan2(differenceX, differenceY ));
return (float) angle;
}
//Unit conversions
public double ticksToInches(double ticks) {
return ticks * (ENCODER_CIRCUMFERENCE / COUNTS_PER_REVOLUTION);
}
public double inchesToTicks(double inches) {
return inches * (COUNTS_PER_REVOLUTION / ENCODER_CIRCUMFERENCE);
}
//Returns the shortest angle between two directions, with positive angles indicating that the
// reference is to the right (clockwise) of the current. Negative angles indicate that the
// reference is to the left.
public float getRelativeAngle(float reference, float current) {
return scaleAngleRange(current - reference);
}
//Drive Functions
public void setDrivePower(double powerFrontLeft, double powerFrontRight,
double powerBackLeft, double powerBackRight){
driveFrontLeft.setPower(powerFrontLeft);
driveFrontRight.setPower(powerFrontRight);
driveBackLeft.setPower(powerBackLeft);
driveBackRight.setPower(powerBackRight);
}
public void setDrivePower(double[] powers){
driveFrontLeft.setPower(powers[0]);
driveFrontRight.setPower(powers[1]);
driveBackLeft.setPower(powers[2]);
driveBackRight.setPower(powers[3]);
}
//returns an array of the powers necessary to execute the provided motion.
//"degreesDirectionMotion" is the angle relative to the field that the robot should drive at.
//"degreesDirectionFace" is the angle the robot should face relative to the field. The order of
//the output powers is ForwardLeft, ForwardRight, BackLeft, BackRight
public double[] getMecanumPowers(float degreesDirectionMotion, double scalar,
float degreesDirectionFace) {
angularVelocity = imu.getAngularVelocity().xRotationRate;
//calculating the base mecanum powers so that the robot drives along the degreesDirectionMotion
//once it is pointed towards the degreesDirectionFace
double rad = Math.toRadians(getRelativeAngle(degreesDirectionFace,degreesDirectionMotion));
double y = Math.cos(rad);
double x = Math.sin(rad);
double p = y + x;
double q = y - x;
//calculating correction needed to steer the robot towards the degreesDirectionFace
float relativeRotation =
getRelativeAngle(degreesDirectionFace, SampleRobotEx.rotation);
double turnCorrection =
Math.pow(CUBIC_CORRECTION * relativeRotation, 3) +
LINEAR_CORRECTION * relativeRotation;
if (relativeRotation != 0) {
double momentumRelative = angularVelocity *
(relativeRotation / Math.abs(relativeRotation));
double exponential =
Math.pow(MOMENTUM_CORRECTION, MOMENTUM_HORIZONTAL_CORRECTION-momentumRelative);
double momentumCorrection = (MOMENTUM_MAX_CORRECTION*exponential)/(1+exponential);
//reduces concern for momentum when the angle is far away from target
turnCorrection *= momentumCorrection + ((Math.abs(relativeRotation) *
(1 - momentumCorrection)) / 180 );
}
double powerForwardRight = scalar * (q + turnCorrection);
double powerForwardLeft = scalar * (p - turnCorrection);
double powerBackRight = scalar * (p + turnCorrection);
double powerBackLeft = scalar * (q - turnCorrection);
// The "extreme" is the power value that is furthest from zero. When this values exceed the
// -1 to 1 power range, dividing the powers by the "extreme" scales everything back into the
// workable range without altering the final motion vector.
double extreme = Math.max(
Math.max(Math.abs(powerForwardRight),Math.abs(powerForwardLeft)),
Math.max(Math.abs(powerBackRight),Math.abs(powerBackLeft)));
if (extreme > 1) {
powerForwardRight = powerForwardRight/extreme;
powerForwardLeft = powerForwardLeft/extreme;
powerBackRight = powerBackRight/extreme;
powerBackLeft = powerBackLeft/extreme;
}
double[] powers = {powerForwardLeft, powerForwardRight, powerBackLeft, powerBackRight};
double totalPower = Math.abs(powerForwardLeft) +
Math.abs(powerForwardRight) +
Math.abs(powerBackLeft) +
Math.abs(powerBackRight);
if (totalPower < ZERO_POWER_THRESHOLD) {
powers = new double[] {0,0,0,0};
}
return powers;
}
//Outputs the power necessary to turn and face a provided direction
public double[] getFacePowers(float direction, double power) {
angularVelocity = imu.getAngularVelocity().xRotationRate;
double relativeAngle = getRelativeAngle(direction, SampleRobotEx.rotation);
double scaler = Math.pow(FACE_CUBIC_CORRECTION * relativeAngle, 3) +
FACE_LINEAR_CORRECTION * relativeAngle;
if (relativeAngle > 0.5) {
scaler += FACE_MIN_CORRECTION;
} else if (relativeAngle < -0.5) {
scaler -= FACE_MIN_CORRECTION;
}
if (relativeAngle != 0) {
double momentumRelative = angularVelocity * (relativeAngle / Math.abs(relativeAngle));
double exponential = Math.pow(FACE_MOMENTUM_CORRECTION,
FACE_MOMENTUM_HORIZONTAL_CORRECTION-momentumRelative);
double momentumCorrection = (MOMENTUM_MAX_CORRECTION*exponential)/(1+exponential);
scaler *= momentumCorrection;
}
double left = -power * scaler;
double right = power *scaler;
double[] powers = {left,right};
double totalPower = 2 * (Math.abs(left) + Math.abs(right));
if (totalPower < ZERO_POWER_THRESHOLD) {
powers = new double[] {0,0};
}
return powers;
}
public float scaleAngleRange(float angle) {
if (angle < -180) {
angle += 360;
}
if (angle > 180) {
angle -= 360;
}
return angle;
}
}

View File

@@ -0,0 +1,27 @@
package org.timecrafters.javaClass.samples;
import com.qualcomm.robotcore.eventloop.opmode.Autonomous;
import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Competition.Robot;
import org.timecrafters.javaClass.aubrey.AubreyFirstState;
import org.timecrafters.javaClass.spencer.SpencerFirstState;
@Autonomous (name = "Spencer: First Program", group = "spencer")
public class SpencerFirstEngine extends CyberarmEngine {
SampleRobot robot;
@Override
public void init() {
robot = new SampleRobot(hardwareMap);
robot.initHardware();
robot.wobbleGrabServo.setPosition(Robot.WOBBLE_SERVO_CLOSED);
super.init();
}
@Override
public void setup() {
addState(new SpencerFirstState(robot));
}
}

View File

@@ -0,0 +1,22 @@
package org.timecrafters.javaClass.spencer;
import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.javaClass.samples.SampleRobot;
public class SpencerFirstState extends CyberarmState {
//here, you'll find some of your variables. you can add more as you need them.
private SampleRobot robot;
//This is the constructor. It lets other code bits run use the code you put here
public SpencerFirstState(SampleRobot robot) {
this.robot = robot;
}
//This is a method. methods are bits of code that can be run elsewhere.
//This one is set up to repeat every few milliseconds
@Override
public void exec() {
}
}

View File

@@ -15,7 +15,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.0.1' classpath 'com.android.tools.build:gradle:4.1.2'
} }
} }

View File

@@ -1,6 +1,6 @@
#Fri Jul 24 14:30:03 PDT 2020 #Sat Jul 24 09:32:10 CDT 2021
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip