Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/McGreen' into McGreen
Browse files Browse the repository at this point in the history
  • Loading branch information
BudsterGaming committed Dec 30, 2023
2 parents d24ac3b + 2cca0af commit 0aad72b
Show file tree
Hide file tree
Showing 21 changed files with 822 additions and 67 deletions.
33 changes: 33 additions & 0 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Bug Report
description: File a bug report
body:
- type: input
id: version
attributes:
label: RR FTC Version
description: Open `TeamCode/build.gradle` and read the version from the
`implementation "com.acmerobotics.roadrunner:ftc:LIBRARY_VERSION_HERE"`
line
placeholder: 0.1.8
validations:
required: true
- type: textarea
id: repro
attributes:
label: Observed Behavior
validations:
required: true
- type: textarea
id: tuning
attributes:
label: Tuning Files
description: Click the "Download" button on the tuning page and attach the file
(if applicable)
- type: textarea
id: logs
attributes:
label: Robot Logs
description: Download the relevant logs from `http://192.168.43.1:8080/logs` and
attach them here


14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# FTC WIRES Autonomous based on Road Runner 1.8
For instructions and documentation, please register at https://forms.gle/mBFYMgsE5pH3QBXa9
Details at http://www.ftcwires.org/softwareplatform
# FTC WIRES Autonomous based on Road Runner 1.10
For instructions and documentation, please register at https://forms.gle/mBFYMgsE5pH3QBXa9
For details, check out http://www.ftcwires.org/softwareplatform

Update 11/13/2023
Upgraded RoadRunner version to 1.8
Step 11.1 introduced - Only for Dead Wheel Encoders, Need to update tick count for parallel and perp encoder position.
Update 12/26/2023
Upgraded RoadRunner version to 1.10
Added “FTC Wires Auto Open CV Vision” Autonomous Mode that includes Vision Processor using Open CV for Team Element Detection.


2 changes: 1 addition & 1 deletion TeamCode/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dependencies {
implementation project(':FtcRobotController')
annotationProcessor files('lib/OpModeAnnotationProcessor.jar')

implementation "com.acmerobotics.roadrunner:ftc:0.1.8"
implementation "com.acmerobotics.roadrunner:ftc:0.1.10"
implementation "com.acmerobotics.dashboard:dashboard:0.4.14"
implementation "org.openftc:easyopencv:1.5.1"
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
/**
* FTC WIRES Autonomous Example for only vision detection using tensorflow and park
*/
//@Autonomous(name = "FTC Wires Autonomous Mode", group = "00-Autonomous", preselectTeleOp = "FTC Wires TeleOp")
public class FTCWiresAutonomous extends LinearOpMode {
@Autonomous(name = "FTC Wires Auto Tensor Flow Vision", group = "00-Autonomous", preselectTeleOp = "FTC Wires TeleOp")
public class FTCWiresAutoVisionTFOD extends LinearOpMode {

public static String TEAM_NAME = "EDIT TEAM NAME"; //TODO: Enter team Name
public static int TEAM_NUMBER = 0; //TODO: Enter team Number
Expand Down Expand Up @@ -87,17 +87,24 @@ public void runOpMode() throws InterruptedException {
initTfod();

// Wait for the DS start button to be touched.
telemetry.addLine("Vision Tensor Flow for White Pixel Detection");
telemetry.addData("DS preview on/off", "3 dots, Camera Stream");
telemetry.addLine("The starting point of the robot is assumed to be on the starting tile, " +
"and along the edge farther from the truss legs. ");
telemetry.addLine("You should also have a webcam connected and positioned in a way to see " +
"the middle spike mark and the spike mark away from the truss (and ideally nothing else). " +
"We assumed the camera to be in the center of the robot. ");
telemetry.addData(">", "Touch Play to start OpMode");
telemetry.update();
//waitForStart();

while (!isStopRequested() && !opModeIsActive()) {
telemetry.addData("Selected Starting Position", startPosition);

//Run Vuforia Tensor Flow and keep watching for the identifier in the Signal Cone.
//Run Vuforia Tensor Flow and keep watching for the White Pixel on the spike mark.
runTfodTensorFlow();
telemetry.addData("Vision identified Parking Location", identifiedSpikeMarkLocation);
telemetry.addLine("Vision Tensor Flow for White Pixel Detection");
telemetry.addData("Identified Parking Location", identifiedSpikeMarkLocation);
telemetry.update();
}

Expand Down Expand Up @@ -283,6 +290,7 @@ public void selectStartingPosition() {
telemetry.addData("Initializing FTC Wires (ftcwires.org) Autonomous adopted for Team:",
TEAM_NAME, " ", TEAM_NUMBER);
telemetry.addData("---------------------------------------","");
telemetry.addLine("This Auto program uses Vision Tensor Flow for White pixel detection");
telemetry.addData("Select Starting Position using XYAB on Logitech (or ▢ΔOX on Playstayion) on gamepad 1:","");
telemetry.addData(" Blue Left ", "(X / ▢)");
telemetry.addData(" Blue Right ", "(Y / Δ)");
Expand Down Expand Up @@ -374,7 +382,7 @@ private void runTfodTensorFlow() {
}
} else { //RED_RIGHT or BLUE_RIGHT
if (recognition.getLabel() == "Pixel") {
if (x < 200) {
if (x < 350) {
identifiedSpikeMarkLocation = IDENTIFIED_SPIKE_MARK_LOCATION.MIDDLE;
} else {
identifiedSpikeMarkLocation = IDENTIFIED_SPIKE_MARK_LOCATION.RIGHT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.acmerobotics.roadrunner.Twist2dDual;
import com.acmerobotics.roadrunner.Vector2d;
import com.acmerobotics.roadrunner.VelConstraint;
import com.acmerobotics.roadrunner.ftc.DownsampledWriter;
import com.acmerobotics.roadrunner.ftc.Encoder;
import com.acmerobotics.roadrunner.ftc.FlightRecorder;
import com.acmerobotics.roadrunner.ftc.LynxFirmware;
Expand All @@ -38,6 +39,10 @@
import com.qualcomm.robotcore.hardware.VoltageSensor;

import org.firstinspires.ftc.robotcore.external.navigation.AngleUnit;
import org.firstinspires.ftc.teamcode.messages.DriveCommandMessage;
import org.firstinspires.ftc.teamcode.messages.MecanumCommandMessage;
import org.firstinspires.ftc.teamcode.messages.MecanumEncodersMessage;
import org.firstinspires.ftc.teamcode.messages.PoseMessage;

import java.lang.Math;
import java.util.Arrays;
Expand All @@ -47,6 +52,14 @@
@Config
public final class MecanumDrive {
public static class Params {
// IMU orientation
//TODO Step 2 : Update direction of IMU by updating orientation of Driver Hub below
// see https://ftc-docs.firstinspires.org/en/latest/programming_resources/imu/imu.html?highlight=imu#physical-hub-mounting
public RevHubOrientationOnRobot.LogoFacingDirection logoFacingDirection =
RevHubOrientationOnRobot.LogoFacingDirection.RIGHT;
public RevHubOrientationOnRobot.UsbFacingDirection usbFacingDirection =
RevHubOrientationOnRobot.UsbFacingDirection.UP;

// drive model parameters
//TODO Step 5 Set value of inPerTick after running ForwardPushTest
//TODO Step 14 Make value of inPerTick accurate after running LocalizationTest
Expand All @@ -68,7 +81,8 @@ public static class Params {
public double kS = 0.8923115403108404;
public double kV = 0.0005909106389939235;

//TODO Step 12 Set value of kA after running ManualFeedforwardTuner. In this emperical process update value in increments of 0.0001
//TODO Step 12 Set value of kA after running ManualFeedforwardTuner.
// In this emperical process update value in increments of 0.0001 for drive encoders and 0.00001 for dead-wheel encoders
public double kA = 0.0001;

// path profile parameters (in inches)
Expand Down Expand Up @@ -118,6 +132,11 @@ kinematics.new WheelVelConstraint(PARAMS.maxWheelVel),

private final LinkedList<Pose2d> poseHistory = new LinkedList<>();

private final DownsampledWriter estimatedPoseWriter = new DownsampledWriter("ESTIMATED_POSE", 50_000_000);
private final DownsampledWriter targetPoseWriter = new DownsampledWriter("TARGET_POSE", 50_000_000);
private final DownsampledWriter driveCommandWriter = new DownsampledWriter("DRIVE_COMMAND", 50_000_000);
private final DownsampledWriter mecanumCommandWriter = new DownsampledWriter("MECANUM_COMMAND", 50_000_000);

public class DriveLocalizer implements Localizer {
public final Encoder leftFront, leftBack, rightBack, rightFront;

Expand Down Expand Up @@ -153,6 +172,9 @@ public Twist2dDual<Time> update() {
PositionVelocityPair rightBackPosVel = rightBack.getPositionAndVelocity();
PositionVelocityPair rightFrontPosVel = rightFront.getPositionAndVelocity();

FlightRecorder.write("MECANUM_ENCODERS", new MecanumEncodersMessage(
leftFrontPosVel, leftBackPosVel, rightBackPosVel, rightFrontPosVel));

Rotation2d heading = Rotation2d.exp(imu.getRobotYawPitchRollAngles().getYaw(AngleUnit.RADIANS));
double headingDelta = heading.minus(lastHeading);

Expand Down Expand Up @@ -199,6 +221,7 @@ public MecanumDrive(HardwareMap hardwareMap, Pose2d pose) {
}

//TODO Step 1 Drive Classes : get basic hardware configured. Update motor names to what is used in robot configuration
// see https://ftc-docs.firstinspires.org/en/latest/hardware_and_software_configuration/configuring/index.html
leftFront = hardwareMap.get(DcMotorEx.class, "leftFront");
leftBack = hardwareMap.get(DcMotorEx.class, "leftBack");
rightBack = hardwareMap.get(DcMotorEx.class, "rightBack");
Expand All @@ -212,6 +235,11 @@ public MecanumDrive(HardwareMap hardwareMap, Pose2d pose) {

//TODO End Step 1

leftFront.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
leftBack.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
rightBack.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
rightFront.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);

//TODO Step 4.1 Run MecanumDirectionDebugger Tuning OpMode to set motor direction correctly
//Uncomment the lines for which the motorDirection need to be reversed to ensure all motors run forward in test
leftFront.setDirection(DcMotorEx.Direction.REVERSE);
Expand All @@ -221,19 +249,12 @@ public MecanumDrive(HardwareMap hardwareMap, Pose2d pose) {
//TODO Make the same update in DriveLocalizer() function. Search for Step 4.2
//TODO End Step 4.1


leftFront.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
leftBack.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
rightBack.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
rightFront.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);

// TODO: make sure your config has an IMU with this name (can be BNO or BHI)
// see https://ftc-docs.firstinspires.org/en/latest/hardware_and_software_configuration/configuring/index.html
imu = hardwareMap.get(IMU.class, "imu");
//TODO Step 2 : Update direction of IMU by updating orientation of Driver Hub below
IMU.Parameters parameters = new IMU.Parameters(new RevHubOrientationOnRobot(
RevHubOrientationOnRobot.LogoFacingDirection.RIGHT, // Change to UP / DOWN / LEFT / RIGHT / FORWARD / BACKWARD as in robot
RevHubOrientationOnRobot.UsbFacingDirection.UP)); //Change to UP / DOWN / LEFT / RIGHT / FORWARD / BACKWARD
PARAMS.logoFacingDirection, PARAMS.usbFacingDirection));
imu.initialize(parameters);
//TODO End Step 2

voltageSensor = hardwareMap.voltageSensor.iterator().next();

Expand Down Expand Up @@ -306,6 +327,7 @@ public boolean run(@NonNull TelemetryPacket p) {
}

Pose2dDual<Time> txWorldTarget = timeTrajectory.get(t);
targetPoseWriter.write(new PoseMessage(txWorldTarget.value()));

PoseVelocity2d robotVelRobot = updatePoseEstimate();

Expand All @@ -314,26 +336,34 @@ public boolean run(@NonNull TelemetryPacket p) {
PARAMS.axialVelGain, PARAMS.lateralVelGain, PARAMS.headingVelGain
)
.compute(txWorldTarget, pose, robotVelRobot);
driveCommandWriter.write(new DriveCommandMessage(command));

MecanumKinematics.WheelVelocities<Time> wheelVels = kinematics.inverse(command);
double voltage = voltageSensor.getVoltage();

final MotorFeedforward feedforward = new MotorFeedforward(PARAMS.kS, PARAMS.kV / PARAMS.inPerTick, PARAMS.kA / PARAMS.inPerTick);
leftFront.setPower(feedforward.compute(wheelVels.leftFront) / voltage);
leftBack.setPower(feedforward.compute(wheelVels.leftBack) / voltage);
rightBack.setPower(feedforward.compute(wheelVels.rightBack) / voltage);
rightFront.setPower(feedforward.compute(wheelVels.rightFront) / voltage);
final MotorFeedforward feedforward = new MotorFeedforward(PARAMS.kS,
PARAMS.kV / PARAMS.inPerTick, PARAMS.kA / PARAMS.inPerTick);
double leftFrontPower = feedforward.compute(wheelVels.leftFront) / voltage;
double leftBackPower = feedforward.compute(wheelVels.leftBack) / voltage;
double rightBackPower = feedforward.compute(wheelVels.rightBack) / voltage;
double rightFrontPower = feedforward.compute(wheelVels.rightFront) / voltage;
mecanumCommandWriter.write(new MecanumCommandMessage(
voltage, leftFrontPower, leftBackPower, rightBackPower, rightFrontPower
));

FlightRecorder.write("TARGET_POSE", new PoseMessage(txWorldTarget.value()));
leftFront.setPower(leftFrontPower);
leftBack.setPower(leftBackPower);
rightBack.setPower(rightBackPower);
rightFront.setPower(rightFrontPower);

p.put("x", pose.position.x);
p.put("y", pose.position.y);
p.put("heading (deg)", Math.toDegrees(pose.heading.log()));
p.put("heading (deg)", Math.toDegrees(pose.heading.toDouble()));

Pose2d error = txWorldTarget.value().minusExp(pose);
p.put("xError", error.position.x);
p.put("yError", error.position.y);
p.put("headingError (deg)", Math.toDegrees(error.heading.log()));
p.put("headingError (deg)", Math.toDegrees(error.heading.toDouble()));

// only draw when active; only one drive action should be active at a time
Canvas c = p.fieldOverlay();
Expand Down Expand Up @@ -389,6 +419,7 @@ public boolean run(@NonNull TelemetryPacket p) {
}

Pose2dDual<Time> txWorldTarget = turn.get(t);
targetPoseWriter.write(new PoseMessage(txWorldTarget.value()));

PoseVelocity2d robotVelRobot = updatePoseEstimate();

Expand All @@ -397,17 +428,25 @@ public boolean run(@NonNull TelemetryPacket p) {
PARAMS.axialVelGain, PARAMS.lateralVelGain, PARAMS.headingVelGain
)
.compute(txWorldTarget, pose, robotVelRobot);
driveCommandWriter.write(new DriveCommandMessage(command));

MecanumKinematics.WheelVelocities<Time> wheelVels = kinematics.inverse(command);
double voltage = voltageSensor.getVoltage();
final MotorFeedforward feedforward = new MotorFeedforward(PARAMS.kS, PARAMS.kV / PARAMS.inPerTick, PARAMS.kA / PARAMS.inPerTick);
final MotorFeedforward feedforward = new MotorFeedforward(PARAMS.kS,
PARAMS.kV / PARAMS.inPerTick, PARAMS.kA / PARAMS.inPerTick);
double leftFrontPower = feedforward.compute(wheelVels.leftFront) / voltage;
double leftBackPower = feedforward.compute(wheelVels.leftBack) / voltage;
double rightBackPower = feedforward.compute(wheelVels.rightBack) / voltage;
double rightFrontPower = feedforward.compute(wheelVels.rightFront) / voltage;
mecanumCommandWriter.write(new MecanumCommandMessage(
voltage, leftFrontPower, leftBackPower, rightBackPower, rightFrontPower
));

leftFront.setPower(feedforward.compute(wheelVels.leftFront) / voltage);
leftBack.setPower(feedforward.compute(wheelVels.leftBack) / voltage);
rightBack.setPower(feedforward.compute(wheelVels.rightBack) / voltage);
rightFront.setPower(feedforward.compute(wheelVels.rightFront) / voltage);

FlightRecorder.write("TARGET_POSE", new PoseMessage(txWorldTarget.value()));

Canvas c = p.fieldOverlay();
drawPoseHistory(c);

Expand Down Expand Up @@ -439,7 +478,7 @@ public PoseVelocity2d updatePoseEstimate() {
poseHistory.removeFirst();
}

FlightRecorder.write("ESTIMATED_POSE", new PoseMessage(pose));
estimatedPoseWriter.write(new PoseMessage(pose));

return twist.velocity().value();
}
Expand Down Expand Up @@ -483,4 +522,4 @@ public TrajectoryActionBuilder actionBuilder(Pose2d beginPose) {
0.25, 0.1
);
}
}
}
Loading

0 comments on commit 0aad72b

Please sign in to comment.