Skip to content

Commit

Permalink
use annotations for hardware! great idea
Browse files Browse the repository at this point in the history
  • Loading branch information
penguinencounter committed Jul 3, 2024
1 parent 20478ae commit a9b08ac
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 51 deletions.
35 changes: 15 additions & 20 deletions TeamCode/src/main/java/org/firstinspires/ftc/teamcode/Hardware.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.HardwareMap;

import org.firstinspires.ftc.teamcode.hardware.AutoClearEncoder;
import org.firstinspires.ftc.teamcode.hardware.HardwareMapper;
import org.firstinspires.ftc.teamcode.hardware.HardwareName;
import org.firstinspires.ftc.teamcode.hardware.Reversed;
import org.firstinspires.ftc.teamcode.hardware.ZeroPower;

public class Hardware extends HardwareMapper {
// left = left motor = exp 0 frontLeft
Expand All @@ -13,43 +16,35 @@ public class Hardware extends HardwareMapper {

@HardwareName("frontLeft")
@Reversed
@ZeroPower(DcMotor.ZeroPowerBehavior.BRAKE)
public DcMotor frontLeft;

@HardwareName("frontRight")
@ZeroPower(DcMotor.ZeroPowerBehavior.BRAKE)
public DcMotor frontRight;

@HardwareName("backLeft")
@ZeroPower(DcMotor.ZeroPowerBehavior.BRAKE)
@Reversed
public DcMotor backLeft;

@HardwareName("backRight")
@ZeroPower(DcMotor.ZeroPowerBehavior.BRAKE)
public DcMotor backRight;

@HardwareName("frontLeft")
@AutoClearEncoder
public DcMotor encoderLeft;

@HardwareName("intake")
@AutoClearEncoder
public DcMotor encoderCenter;

@HardwareName("frontRight")
@AutoClearEncoder
public DcMotor encoderRight;

private void resetEncoder(DcMotor target) {
DcMotor.RunMode mode = target.getMode();
target.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
target.setMode(mode);
}

public Hardware(HardwareMap hwMap) {
super(hwMap);
frontLeft = hwMap.dcMotor.get("frontLeft");
frontRight = hwMap.dcMotor.get("frontRight");
backLeft = hwMap.dcMotor.get("backLeft");
backRight = hwMap.dcMotor.get("backRight");

encoderLeft = hwMap.dcMotor.get("frontLeft");
encoderCenter = hwMap.dcMotor.get("intake");
encoderRight = hwMap.dcMotor.get("frontRight");

frontLeft.setDirection(DcMotor.Direction.REVERSE);
backLeft.setDirection(DcMotor.Direction.REVERSE);
resetEncoder(encoderLeft);
resetEncoder(encoderCenter);
resetEncoder(encoderRight);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.firstinspires.ftc.teamcode.hardware;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Specifies that an encoder should be cleared when the robot is initialized.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AutoClearEncoder { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.firstinspires.ftc.teamcode.hardware;

import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.hardware.HardwareMap;

import java.lang.reflect.Field;

/**
* Annotation processor for hardware map things.
*/
public abstract class HardwareMapper {
public HardwareMapper(HardwareMap map) {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
boolean accessible = field.isAccessible();
if (!accessible) field.setAccessible(true);
try {
Class<?> targetType = field.getType();
HardwareName annotation = field.getAnnotation(HardwareName.class);
if (annotation == null) continue;
Object result = map.tryGet(targetType, field.getName());

if (result == null) {
throw new RuntimeException(
"Hardware: '" +
field.getName() + "' not found, expected type " +
targetType.getName() + " for field " +
field.getName() + " in " + this.getClass().getName()
);
}
try {
field.set(this, result);
} catch (IllegalAccessException e) {
throw new RuntimeException("Field " + field.getName() + " assign failed: " + result.getClass().getName() + " to " + field.getType().getName());
}

if (field.isAnnotationPresent(Reversed.class)) {
if (targetType.isAssignableFrom(DcMotorSimple.class)) {
DcMotorSimple motor = (DcMotorSimple) result;
motor.setDirection(DcMotorSimple.Direction.REVERSE);
} else {
throw new RuntimeException("@Reversed annotation can only be used on DcMotorSimple (or subclasses)");
}
}
if (field.isAnnotationPresent(ZeroPower.class)) {
if (targetType.isAssignableFrom(DcMotor.class)) {
DcMotor motor = (DcMotor) result;
ZeroPower zeroPower = field.getAnnotation(ZeroPower.class);
if (zeroPower == null) throw new RuntimeException("ZeroPower annotation is null?!");
motor.setZeroPowerBehavior(zeroPower.value());
} else {
throw new RuntimeException("@ZeroPower annotation can only be used on DcMotor (or subclasses)");
}
}
if (field.isAnnotationPresent(AutoClearEncoder.class)) {
if (targetType.isAssignableFrom(DcMotor.class)) {
DcMotor motor = (DcMotor) result;
DcMotor.RunMode current = motor.getMode();
motor.setMode(DcMotor.RunMode.STOP_AND_RESET_ENCODER);
motor.setMode(current);
} else {
throw new RuntimeException("@AutoClearEncoder annotation can only be used on DcMotor (or subclasses)");
}
}
} catch (IllegalArgumentException e) {
throw new RuntimeException("Field " + field.getName() + " typecast failed");
} finally {
// lock the field back if it was locked
field.setAccessible(accessible);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package org.firstinspires.ftc.teamcode.hardware;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface HardwareName {
String value();
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package org.firstinspires.ftc.teamcode.hardware;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Specifies that a motor should start with its direction reversed.
* The annotated field must be a DcMotorSimple or subclass.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface Reversed {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.firstinspires.ftc.teamcode.hardware;

import com.qualcomm.robotcore.hardware.DcMotor;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Defiles the zero power behavior of a motor.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ZeroPower {
DcMotor.ZeroPowerBehavior value();
}
6 changes: 5 additions & 1 deletion build.dependencies.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
repositories {
mavenCentral()
google() // Needed for androidx

maven {
url = 'https://maven.brott.dev/'
}
}

dependencies {
Expand All @@ -21,5 +23,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation 'com.acmerobotics.dashboard:dashboard:0.4.15'
}

0 comments on commit a9b08ac

Please sign in to comment.