Updated to Ultimate Goal

This commit is contained in:
Nathaniel Palme
2020-09-24 19:18:04 -05:00
parent 7ab38611f7
commit 07678cb0af
34 changed files with 1761 additions and 121 deletions

View File

@@ -0,0 +1,141 @@
package org.cyberarm.NeXT;
import java.util.HashMap;
public class DataStruct {
public String name;
public boolean enabled;
/*
Hash of Strings mapped to Strings, those strings are various types mapped to stings:
Boolean -> "Bxfalse"
Integer -> "Ix100"
Integer -> "Lx123456789"
Double -> "Dx0.1"
Float -> "Fx10.1"
String -> "SxWords can go here."
DataStruct.valueOf(Hash.get("distanceToDrive")) -> 100
*/
private HashMap<String, String> variables;
public DataStruct() {
this.variables = new HashMap<>();
}
public DataStruct(String name, boolean enabled, HashMap<String, String> variables) {
this.name = name;
this.enabled = enabled;
this.variables = variables;
}
public String name() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean enabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public HashMap<String, String> variables(String power) {
return variables;
}
public <T> T variable(String key) throws NullPointerException {
if (variables.get(key.trim()) == null) {
throw(new NullPointerException("Action \""+ name +"\" has no Variable called \""+ key.trim() +"\""));
}
return valueOf(variables.get(key.trim()));
}
@SuppressWarnings("unchecked")
public static <T> T valueOf(String value) {
String[] split = value.split("x");
switch (split[0]) {
case "B": {
return (T) Boolean.valueOf(split[(split.length-1)]);
}
case "D": {
return (T) Double.valueOf(split[(split.length-1)]);
}
case "F": {
return (T) Float.valueOf(split[(split.length-1)]);
}
case "I": {
return (T) Integer.valueOf(split[(split.length-1)]);
}
case "L": {
return (T) Long.valueOf(split[(split.length-1)]);
}
case "S": {
return (T) String.valueOf(split[(split.length-1)]);
}
default: {
return null;
}
}
}
public static String typeOf(String value) {
String[] split = value.split("x");
switch (split[0]) {
case "B": {
return "Boolean";
}
case "D": {
return "Double";
}
case "F": {
return "Float";
}
case "I": {
return "Integer";
}
case "L": {
return "Long";
}
case "S": {
return "String";
}
default: {
return "=!UNKNOWN!=";
}
}
}
public static String encodeValue(String type, String value) {
switch (type) {
case "Boolean": {
return "Bx"+value;
}
case "Double": {
return "Dx"+value;
}
case "Float": {
return "Fx"+value;
}
case "Integer": {
return "Ix"+value;
}
case "Long": {
return "Lx"+value;
}
case "String": {
return "Sx"+value;
}
default: {
return "=!UNKNOWN!=";
}
}
}
}

View File

@@ -0,0 +1,92 @@
package org.cyberarm.NeXT;
import android.os.Environment;
import android.util.Log;
import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public class StateConfiguration {
private boolean loadSuccessful = false;
private ArrayList<DataStruct> dataStructs;
private HashMap<String, DataStruct> actions;
public StateConfiguration() {
dataStructs = new ArrayList<>();
actions = new HashMap<>();
// Load configuration file.
if (loadJSON()) {
Log.i("TC_CONFIG", "Successfully loaded configuration file.");
for (DataStruct dataStruct : dataStructs) {
actions.put(dataStruct.name.trim(), dataStruct);
}
} else {
Log.e("TC_CONFIG", "FAILED TO LOAD CONFIGURATION FILE!");
}
}
public DataStruct get(String key) throws NullPointerException {
if (actions.get(key.trim()) == null) {
throw(new NullPointerException("Config has no Action called \""+ key.trim() +"\""));
}
return actions.get(key.trim());
}
public boolean allow(String key) throws NullPointerException {
if (get(key.trim()) == null) {
throw(new NullPointerException("Config has no Action called \""+ key.trim() +"\""));
}
return get(key.trim()).enabled;
}
private boolean loadJSON() {
boolean loadSuccessful = false;
File file = new File(getDirectory() + File.separator + "config.json");
StringBuilder text = new StringBuilder();
if (file.exists()) {
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
Gson gson = new Gson();
DataStruct[] array = gson.fromJson(text.toString(), DataStruct[].class);
this.dataStructs = new ArrayList<>(Arrays.asList(array));
loadSuccessful = true;
} catch (IOException e) {
System.out.println(e);
// TODO: handle this
}
}
this.loadSuccessful = loadSuccessful;
return loadSuccessful;
}
private String getDirectory() {
return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "FIRST_TC_CONFIG";
}
public boolean wasLoadSuccessful() { return loadSuccessful; }
}

View File

@@ -0,0 +1,58 @@
package org.cyberarm.container;
import android.util.Log;
import com.qualcomm.robotcore.hardware.Gamepad;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
public class InputChecker {
private Gamepad gamepad;
private HashMap<String, Byte> buttons;
private ArrayList<String> buttonList;
private byte NULL = 0,
PRESSED = 1,
RELEASED= 2;
public InputChecker(Gamepad gamepad) {
this.gamepad = gamepad;
buttons = new HashMap<>();
buttonList = new ArrayList<>();
buttonList.add("a"); buttonList.add("b"); buttonList.add("x"); buttonList.add("y");
buttonList.add("start"); buttonList.add("guide"); buttonList.add("back");
buttonList.add("left_bumper"); buttonList.add("right_bumper");
buttonList.add("left_stick_button"); buttonList.add("right_stick_button");
buttonList.add("dpad_left"); buttonList.add("dpad_right");
buttonList.add("dpad_up"); buttonList.add("dpad_down");
}
public void update() {
for (int i = 0; i < buttonList.size(); i++) {
try {
Field field = gamepad.getClass().getDeclaredField(buttonList.get(i));
if (field.getBoolean(gamepad)) {
buttons.put(buttonList.get(i), PRESSED);
} else {
if (buttons.get(buttonList.get(i)) != null && buttons.get(buttonList.get(i)) == PRESSED) {
buttons.put(buttonList.get(i), RELEASED);
}
}
} catch (NoSuchFieldException|IllegalAccessException e) {
e.printStackTrace();
}
}
}
public boolean check(String button) {
boolean state = false;
if (buttons.containsKey(button) && buttons.get(button) == RELEASED) {
Log.d("InputChecker","button \""+button+"\" has been released on \"gamepad"+gamepad.getGamepadId()+"\"");
state = true;
buttons.put(button, NULL);
}
return state;
}
}

View File

@@ -0,0 +1,220 @@
package org.cyberarm.engine.V2;
import android.util.Log;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import java.util.ArrayList;
/**
* CyberarmEngine Version 2.0 | October 26th 2018
* AN Experimental reimplementation of GoldfishPi's original Engine system.
* Designed to be easily maintainable, extensible, and easy to understand.
*/
public abstract class CyberarmEngine extends OpMode {
public static CyberarmEngine instance;
//Array To Hold States
private ArrayList<CyberarmState> cyberarmStates = new ArrayList<>();
private int activeStateIndex = 0;
private boolean isRunning;
private static String TAG = "PROGRAM.ENGINE: ";
/**
* Called when INIT button on Driver Station is pushed
* ENSURE to call super.init() if you override this method
*/
public void init() {
CyberarmEngine.instance = this;
isRunning = false;
setup();
isRunning = true;
for (CyberarmState state: cyberarmStates) {
initState(state);
}
}
/**
* Setup states for engine to use
* For example:
* <pre>
* @<code>
* public void setup() {
* addState(new TestState());
* addState(new AnotherState(100, 500));
* }
* </code>
* </pre>
*/
public abstract void setup();
/**
* Called when START button on Driver Station is pushed
* ENSURE to call super.start() if you override this method
*/
public void start() {
if (cyberarmStates.size() > 0) {
runState(cyberarmStates.get(0));
}
}
/**
* Engine main loop
* ENSURE to call super.loop() if you override this method
*/
public void loop() {
CyberarmState state;
// Try to set state to the current state, if it fails assume that there are no states to run
try {
state = cyberarmStates.get(activeStateIndex);
} catch(IndexOutOfBoundsException e) {
// The engine is now out of states.
stop();
telemetry.addLine("" + this.getClass().getSimpleName() + " is out of states to run!");
telemetry.addLine();
return;
}
// Add telemetry to show currently running state
telemetry.addLine("Running state: " +state.getClass().getSimpleName() + ". State: " + activeStateIndex + " of " + (cyberarmStates.size()-1));
telemetry.addLine();
if (state.getHasFinished() && state.childrenHaveFinished()) {
activeStateIndex++;
try {
state = cyberarmStates.get(activeStateIndex);
runState(state);
} catch(IndexOutOfBoundsException e) { /* loop will handle this in a few milliseconds */ }
} else {
stateTelemetry(state);
}
}
/**
* Stops every known state
*/
@Override
public void stop() {
for (CyberarmState state: cyberarmStates) {
stopState(state);
}
}
/**
* Recursively calls telemetry() on states
* @param state State to get telemetry
*/
private void stateTelemetry(CyberarmState state) {
if (!state.getHasFinished()) {
state.telemetry();
}
for(CyberarmState childState : state.children) {
if (!childState.getHasFinished()) {
stateTelemetry(childState);
}
}
}
/**
* Called when INIT button on Driver Station is pressed
* Recursively initiates states
* @param state State to initiate
*/
private void initState(CyberarmState state) {
state.init();
for(CyberarmState childState : state.children) {
initState(childState);
}
}
/**
* Called when programs ends or STOP button on Driver Station is pressed
* Recursively stop states
* @param state State to stop
*/
private void stopState(CyberarmState state) {
state.setHasFinished(true);
state.stop();
for(CyberarmState childState : state.children) {
stopState(childState);
}
}
/**
* Recursively start up states
* @param state State to run
*/
protected void runState(CyberarmState state) {
final CyberarmState finalState = state;
// if (state.isRunning()) { return; } // Assume that we have already started running this state
new Thread(new Runnable() {
@Override
public void run() {
finalState.start();
finalState.startTime = System.currentTimeMillis();
finalState.run();
}
}).start();
for (CyberarmState kid : state.children) {
runState(kid);
}
}
/**
* Add state to queue, will call init() on state if engine is running
* @param state State to add to queue
*/
public CyberarmState addState(CyberarmState state) {
Log.i(TAG, "Adding cyberarmState "+ state.getClass());
cyberarmStates.add(state);
if (isRunning()) { initState(state); }
return state;
}
/**
* Inserts state after the query state plus an offset to ensure logical insertion
* @param query State to add state after
* @param state State to be inserted
* @return
*/
public CyberarmState insertState(CyberarmState query, CyberarmState state) {
int index = cyberarmStates.indexOf(query) + query.insertOffset;
cyberarmStates.add(index, state);
query.insertOffset++;
if (isRunning()) { initState(state); }
return state;
}
/**
* This will return false while Engine.setup() is executing, and be true after.
* @return Whether the engine main loop is running
*/
public boolean isRunning() {
return isRunning;
}
/**
*
* @return The index used to lookup the current state from cyberarmStates
*/
public int getActiveStateIndex() {
return activeStateIndex;
}
}

View File

@@ -0,0 +1,206 @@
package org.cyberarm.engine.V2;
import android.util.Log;
import java.util.ArrayList;
/**
* A State for use with CyberarmEngineV2
*/
public abstract class CyberarmState implements Runnable {
private volatile boolean isRunning, hasFinished;
public static String TAG = "PROGRAM.STATE";
public CyberarmEngine engine = CyberarmEngine.instance;
public ArrayList<CyberarmState> children = new ArrayList<>();
public long startTime = 0;
public int insertOffset = 1;
/**
* Called when INIT button on Driver Station is pushed
*/
public void init() {
}
/**
* Called when state has begin to run
*/
public void start() {
}
/**
* Called while State is running
*/
public abstract void exec();
/**
* State's main loop, calls exec() until hasFinished is true
* DO NO OVERRIDE
*/
@Override
public void run() {
isRunning = true;
while (!hasFinished) {
exec();
}
isRunning = false;
}
/**
* Place telemetry calls in here instead of inside exec() to have them displayed correctly on the Driver Station
* (States update thousands of times per second, resulting in missing or weirdly formatted telemetry if telemetry is added in exec())
*/
public void telemetry() {
}
/**
* Called when Engine is finished
*/
public void stop() {
}
/**
* Add a state which runs in parallel with this one
*/
public CyberarmState addParallelState(CyberarmState state) {
Log.i(TAG, "Adding " + state.getClass() + " to " + this.getClass());
children.add(state);
if (isRunning()) { state.init(); engine.runState(state); }
return state;
}
/**
* Add a state to engine which will run after this one finishes
*/
public CyberarmState addState(CyberarmState state) {
engine.insertState(this, state);
return state;
}
/**
* Returns whether or not state has children
* @return True if state has children, false otherwise
*/
public boolean hasChildren() {
return (children.size() > 0);
}
/**
* Have all of the states children finished running themselves?
* @return Wether or not all children have finished running
*/
public boolean childrenHaveFinished() {
return childrenHaveFinished(children);
}
/**
* Have all of the states children finished running themselves?
* @param kids ArrayList of children to check for hasFinished()
* @return Whether or not all children have finished running
*/
public boolean childrenHaveFinished(ArrayList<CyberarmState> kids) {
boolean allDone = true;
for (CyberarmState state : kids) {
if (!state.hasFinished) {
allDone = false;
break;
} else {
if (!state.childrenHaveFinished()) {
allDone = false;
break;
}
}
}
return allDone;
}
/**
*
* @return The number of milliseconds this state has been running for
*/
public double runTime() {
return (System.currentTimeMillis() - startTime);
}
/**
* Set whether state has finished or not
* @param value
*/
public void setHasFinished(boolean value) {
hasFinished = value;
}
/**
*
* @return Get value of hasFinished
*/
public boolean getHasFinished() {
return hasFinished;
}
/**
*
* @return Get value of isRunning
*/
public boolean isRunning() {
return isRunning;
}
/**
*
* @param timems How long to sleep in milliseconds
*/
public void sleep(long timems) {
try {
Thread.sleep(timems);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
*
* @param width How many characters wide to be
* @param percentCompleted Number between 0.0 and 100.0
* @param bar What character to draw the completion bar with
* @param padding What character to draw non-completed bar with
* @return A string
*/
public String progressBar(int width, double percentCompleted, String bar, String padding) {
String percentCompletedString = "" + Math.round(percentCompleted) + "%";
double activeWidth = (width - 2) - percentCompletedString.length();
String string = "[";
double completed = (percentCompleted / 100.0) * activeWidth;
for (int i = 0; i <= ((int) activeWidth); i++) {
if (i == ((int) activeWidth) / 2) {
string += percentCompletedString;
} else {
if (i <= (int) completed && (int) completed > 0) {
string += bar;
} else {
string += padding;
}
}
}
string += "]";
return string;
}
/**
*
* @param width How many characters wide to be
* @param percentCompleted Number between 0.0 and 100.0
* @return A string
*/
public String progressBar(int width, double percentCompleted) {
return progressBar(width, percentCompleted, "=", " ");
}
}

View File

@@ -0,0 +1,28 @@
CyberarmEngine V2 Architecture
Engine
-> [States]
-> [ParallelStates]
Start with an Engine and override setup():
public class Engine extends CyberarmEngineV2 {
public void setup() {
addState(new State(arguments));
}
}
NOTE: states do not need to be passed the instance of Engine as they have a field 'cyberarmEngine'
which is set to CyberarmEngineV2.instance when they are created.
States can have 'children' which are also States, which run in parallel with their parent. There is
no fixed limit to how many grandchildren can exist (Children themselves can have children.):
public class State extends CyberarmEngineStateV2 {
public init() {
addParallelState(new ParallelState(arguments));
}
public exec() {
}
}

View File

@@ -1,121 +0,0 @@
## TeamCode Module
Welcome!
This module, TeamCode, is the place where you will write/paste the code for your team's
robot controller App. This module is currently empty (a clean slate) but the
process for adding OpModes is straightforward.
## Creating your own OpModes
The easiest way to create your own OpMode is to copy a Sample OpMode and make it your own.
Sample opmodes exist in the FtcRobotController module.
To locate these samples, find the FtcRobotController module in the "Project/Android" tab.
Expand the following tree elements:
FtcRobotController / java / org.firstinspires.ftc.robotcontroller / external / samples
A range of different samples classes can be seen in this folder.
The class names follow a naming convention which indicates the purpose of each class.
The full description of this convention is found in the samples/sample_convention.md file.
A brief synopsis of the naming convention is given here:
The prefix of the name will be one of the following:
* Basic: This is a minimally functional OpMode used to illustrate the skeleton/structure
of a particular style of OpMode. These are bare bones examples.
* Sensor: This is a Sample OpMode that shows how to use a specific sensor.
It is not intended as a functioning robot, it is simply showing the minimal code
required to read and display the sensor values.
* Hardware: This is not an actual OpMode, but a helper class that is used to describe
one particular robot's hardware devices: eg: for a Pushbot. Look at any
Pushbot sample to see how this can be used in an OpMode.
Teams can copy one of these to create their own robot definition.
* Pushbot: This is a Sample OpMode that uses the Pushbot robot structure as a base.
* Concept: This is a sample OpMode that illustrates performing a specific function or concept.
These may be complex, but their operation should be explained clearly in the comments,
or the header should reference an external doc, guide or tutorial.
* Library: This is a class, or set of classes used to implement some strategy.
These will typically NOT implement a full OpMode. Instead they will be included
by an OpMode to provide some stand-alone capability.
Once you are familiar with the range of samples available, you can choose one to be the
basis for your own robot. In all cases, the desired sample(s) needs to be copied into
your TeamCode module to be used.
This is done inside Android Studio directly, using the following steps:
1) Locate the desired sample class in the Project/Android tree.
2) Right click on the sample class and select "Copy"
3) Expand the TeamCode / java folder
4) Right click on the org.firstinspires.ftc.teamcode folder and select "Paste"
5) You will be prompted for a class name for the copy.
Choose something meaningful based on the purpose of this class.
Start with a capital letter, and remember that there may be more similar classes later.
Once your copy has been created, you should prepare it for use on your robot.
This is done by adjusting the OpMode's name, and enabling it to be displayed on the
Driver Station's OpMode list.
Each OpMode sample class begins with several lines of code like the ones shown below:
```
@TeleOp(name="Template: Linear OpMode", group="Linear Opmode")
@Disabled
```
The name that will appear on the driver station's "opmode list" is defined by the code:
``name="Template: Linear OpMode"``
You can change what appears between the quotes to better describe your opmode.
The "group=" portion of the code can be used to help organize your list of OpModes.
As shown, the current OpMode will NOT appear on the driver station's OpMode list because of the
``@Disabled`` annotation which has been included.
This line can simply be deleted , or commented out, to make the OpMode visible.
## ADVANCED Multi-Team App management: Cloning the TeamCode Module
In some situations, you have multiple teams in your club and you want them to all share
a common code organization, with each being able to *see* the others code but each having
their own team module with their own code that they maintain themselves.
In this situation, you might wish to clone the TeamCode module, once for each of these teams.
Each of the clones would then appear along side each other in the Android Studio module list,
together with the FtcRobotController module (and the original TeamCode module).
Selective Team phones can then be programmed by selecting the desired Module from the pulldown list
prior to clicking to the green Run arrow.
Warning: This is not for the inexperienced Software developer.
You will need to be comfortable with File manipulations and managing Android Studio Modules.
These changes are performed OUTSIDE of Android Studios, so close Android Studios before you do this.
Also.. Make a full project backup before you start this :)
To clone TeamCode, do the following:
Note: Some names start with "Team" and others start with "team". This is intentional.
1) Using your operating system file management tools, copy the whole "TeamCode"
folder to a sibling folder with a corresponding new name, eg: "Team0417".
2) In the new Team0417 folder, delete the TeamCode.iml file.
3) the new Team0417 folder, rename the "src/main/java/org/firstinspires/ftc/teamcode" folder
to a matching name with a lowercase 'team' eg: "team0417".
4) In the new Team0417/src/main folder, edit the "AndroidManifest.xml" file, change the line that contains
package="org.firstinspires.ftc.teamcode"
to be
package="org.firstinspires.ftc.team0417"
5) Add: include ':Team0417' to the "/settings.gradle" file.
6) Open up Android Studios and clean out any old files by using the menu to "Build/Clean Project""

View File

@@ -0,0 +1,150 @@
package org.timecrafters.TimeCraftersConfigurationTool;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.timecrafters.TimeCraftersConfigurationTool.backend.Config;
import org.timecrafters.TimeCraftersConfigurationTool.backend.Settings;
import org.timecrafters.TimeCraftersConfigurationTool.backend.TAC;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ActionDeserializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ActionSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigDeserializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigurationDeserializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.ConfigurationSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.GroupDeserializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.GroupSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.PresetsDeserializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.PresetsSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.SettingsDeserializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.SettingsSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.VariableDeserializer;
import org.timecrafters.TimeCraftersConfigurationTool.serializers.VariableSerializer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class TimeCraftersConfiguration {
private static final String TAG = "TCT|TCConfig";
private Config config;
public TimeCraftersConfiguration() {
Settings settings = loadSettings();
this.config = loadConfig(settings.config);
}
public TimeCraftersConfiguration(String configName) {
this.config = loadConfig(configName);
}
public Config getConfig() {
return config;
}
public Group group(String groupName) {
for (final Group group : config.getGroups()) {
if (group.name.trim().equals(groupName.trim())) {
return group;
}
}
throw(new RuntimeException("Failed to find a group named:\"" + groupName.trim() + "\" in config \"" + config.getName() + "\""));
}
public Action action(String groupName, String actionName) {
final Group group = group(groupName);
for (Action action : group.getActions()) {
if (action.name.trim().equals(actionName.trim())) {
return action;
}
}
throw(new RuntimeException("Failed to find an action named:\"" + actionName.trim() + "\" in group \"" + groupName.trim() + "\" in config \"" + config.getName() + "\""));
}
public Variable variable(String groupName, String actionName, String variableName) {
final Action action = action(groupName, groupName);
for (Variable variable : action.getVariables()) {
if (variable.name.trim().equals(variableName.trim())) {
return variable;
}
}
throw(new RuntimeException("Failed to find a variable named \"" + variableName.trim() + "\" in action:\"" + actionName.trim() +
"\" in group \"" + groupName.trim() + "\" in config \"" + config.getName() + "\""));
}
private Settings loadSettings() {
File settingsFile = new File(TAC.SETTINGS_PATH);
if (!settingsFile.exists()) {
throw( new RuntimeException("Unable to load settings.json, file does not exist!") );
}
try {
return gsonForSettings().fromJson(new FileReader(settingsFile), Settings.class);
} catch (FileNotFoundException e) {
throw( new RuntimeException("Unable to load settings.json") );
}
}
private Config loadConfig(String name) {
if (name.equals("")) {
throw(new RuntimeException("Cannot load a config with an empty name!"));
}
String path = TAC.CONFIGS_PATH + File.separator + name + ".json";
File configFile = new File(path);
if (configFile.exists() && configFile.isFile()) {
try {
Config config = gsonForConfig().fromJson(new FileReader(configFile), Config.class);
config.setName(name);
return config;
} catch (FileNotFoundException e) {
e.printStackTrace();
throw(new RuntimeException("Unable to find a config file named \"" + name + "\""));
}
} else {
throw(new RuntimeException("Unable to find a config file named \"" + name + "\""));
}
}
private Gson gsonForSettings() {
return new GsonBuilder()
.registerTypeAdapter(Settings.class, new SettingsSerializer())
.registerTypeAdapter(Settings.class, new SettingsDeserializer())
.create();
}
public Gson gsonForConfig() {
return new GsonBuilder()
.registerTypeAdapter(Config.class, new ConfigSerializer())
.registerTypeAdapter(Config.class, new ConfigDeserializer())
.registerTypeAdapter(Configuration.class, new ConfigurationSerializer())
.registerTypeAdapter(Configuration.class, new ConfigurationDeserializer())
.registerTypeAdapter(Group.class, new GroupSerializer())
.registerTypeAdapter(Group.class, new GroupDeserializer())
.registerTypeAdapter(Action.class, new ActionSerializer())
.registerTypeAdapter(Action.class, new ActionDeserializer())
.registerTypeAdapter(Variable.class, new VariableSerializer())
.registerTypeAdapter(Variable.class, new VariableDeserializer())
.registerTypeAdapter(Presets.class, new PresetsSerializer())
.registerTypeAdapter(Presets.class, new PresetsDeserializer())
.create();
}
}

View File

@@ -0,0 +1,44 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
import java.util.ArrayList;
import java.util.Date;
public class Config {
private String name;
private Configuration configuration;
private ArrayList<Group> groups;
private Presets presets;
public Config(String name) {
this.name = name;
this.configuration = new Configuration(new Date(), new Date(), TAC.CONFIG_SPEC_VERSION, 0);
groups = new ArrayList<>();
presets = new Presets(new ArrayList<Group>(), new ArrayList<Action>());
}
public Config(Configuration configuration, ArrayList<Group> groups, Presets presets) {
this.configuration = configuration;
this.groups = groups;
this.presets = presets;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Configuration getConfiguration() {
return configuration;
}
public Presets getPresets() {
return presets;
}
public ArrayList<Group> getGroups() {
return groups;
}
}

View File

@@ -0,0 +1,12 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend;
public class Settings {
public String hostname, config;
public int port;
public Settings(String hostname, int port, String config) {
this.hostname = hostname;
this.port = port;
this.config = config;
}
}

View File

@@ -0,0 +1,14 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend;
import android.os.Environment;
import java.io.File;
public class TAC {
// TODO: Update filesystem handling
public static final String ROOT_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "TimeCrafters_Configuration_Tool",
CONFIGS_PATH = ROOT_PATH + File.separator + "/configs",
SETTINGS_PATH = ROOT_PATH + File.separator + "settings.json";
public static final int CONFIG_SPEC_VERSION = 2;
}

View File

@@ -0,0 +1,18 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
import java.util.ArrayList;
public class Action {
public String name, comment;
public boolean enabled;
private ArrayList<Variable> variables;
public Action(String name, String comment, boolean enabled, ArrayList<Variable> variables) {
this.name = name;
this.comment = comment;
this.enabled = enabled;
this.variables = variables;
}
public ArrayList<Variable> getVariables() { return variables; }
}

View File

@@ -0,0 +1,20 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
import java.util.Date;
public class Configuration {
public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss Z";
public Date createdAt, updatedAt;
private int specVersion;
public int revision;
public Configuration(Date createdAt, Date updatedAt, int specVersion, int revision) {
this.createdAt = createdAt;
this.updatedAt = updatedAt;
this.specVersion = specVersion;
this.revision = revision;
}
public int getSpecVersion() { return specVersion; }
}

View File

@@ -0,0 +1,27 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
import java.util.ArrayList;
public class Group {
public String name;
private ArrayList<Action> actions;
public Group(String name, ArrayList<Action> actions) {
this.name = name;
this.actions = actions;
}
public static boolean nameIsUnique(ArrayList<Group> groups, String name) {
for (Group group: groups) {
if (group.name.equals(name)) {
return false;
}
}
return true;
}
public ArrayList<Action> getActions() {
return actions;
}
}

View File

@@ -0,0 +1,22 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
import java.util.ArrayList;
public class Presets {
private ArrayList<Group> groups;
private ArrayList<Action> actions;
public Presets(ArrayList<Group> groups, ArrayList<Action> actions) {
this.groups = groups;
this.actions = actions;
}
public ArrayList<Group> getGroups() {
return groups;
}
public ArrayList<Action> getActions() {
return actions;
}
}

View File

@@ -0,0 +1,88 @@
package org.timecrafters.TimeCraftersConfigurationTool.backend.config;
public class Variable {
public String name;
private String value;
public Variable(String name, String value) {
this.name = name;
this.value = value;
}
public String rawValue() {
return value;
}
public <T> T value() {
return valueOf(value);
}
public void setValue(String value) {
this.value = value;
}
@SuppressWarnings("unchecked")
static public <T> T valueOf(String value) {
String[] split = value.split("x", 2);
// Log.d("Variable", "valueOf split: " + Arrays.toString(split));
switch (split[0]) {
case "B": {
return (T) Boolean.valueOf(split[(split.length-1)]);
}
case "D": {
return (T) Double.valueOf(split[(split.length-1)]);
}
case "F": {
return (T) Float.valueOf(split[(split.length-1)]);
}
case "I": {
return (T) Integer.valueOf(split[(split.length-1)]);
}
case "L": {
return (T) Long.valueOf(split[(split.length-1)]);
}
case "S": {
String string = "";
int i = 0;
for(String str : split) {
if (i == 0) { i++; continue; }
string += str;
}
return (T) string;
}
default: {
return null;
}
}
}
static public String typeOf(String value) {
String[] split = value.split("x");
switch (split[0]) {
case "B": {
return "Boolean";
}
case "D": {
return "Double";
}
case "F": {
return "Float";
}
case "I": {
return "Integer";
}
case "L": {
return "Long";
}
case "S": {
return "String";
}
default: {
return "=!UNKNOWN!=";
}
}
}
}

View File

@@ -0,0 +1,32 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ActionDeserializer implements JsonDeserializer<Action> {
@Override
public Action deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
final String name = jsonObject.get("name").getAsString();
final String comment = jsonObject.get("comment").getAsString();
final boolean enabled = jsonObject.get("enabled").getAsBoolean();
Variable[] variablesArray = context.deserialize(jsonObject.get("variables"), Variable[].class);
List<Variable> variablesList = Arrays.asList(variablesArray);
ArrayList<Variable> variables = new ArrayList<>(variablesList);
return new Action(name, comment, enabled, variables);
}
}

View File

@@ -0,0 +1,26 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
import java.lang.reflect.Type;
public class ActionSerializer implements JsonSerializer<Action> {
@Override
public JsonElement serialize(Action action, Type type, JsonSerializationContext context) {
JsonObject container = new JsonObject();
container.add("name", new JsonPrimitive(action.name));
container.add("comment", new JsonPrimitive(action.comment));
container.add("enabled", new JsonPrimitive(action.enabled));
container.add("variables", context.serialize(action.getVariables().toArray(), Variable[].class));
return container;
}
}

View File

@@ -0,0 +1,34 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.timecrafters.TimeCraftersConfigurationTool.backend.Config;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ConfigDeserializer implements JsonDeserializer<Config> {
@Override
public Config deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
JsonObject data = jsonObject.get("data").getAsJsonObject();
Configuration configuration = context.deserialize(jsonObject.get("config"), Configuration.class);
Group[] groupsArray = context.deserialize(data.get("groups"), Group[].class);
List<Group> groupsList = Arrays.asList(groupsArray);
ArrayList<Group> groups = new ArrayList<>(groupsList);
Presets presets = context.deserialize(data.get("presets"), Presets.class);
return new Config(configuration, groups, presets);
}
}

View File

@@ -0,0 +1,32 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.backend.Config;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import java.lang.reflect.Type;
public class ConfigSerializer implements JsonSerializer<Config> {
@Override
public JsonElement serialize(Config config, Type type, JsonSerializationContext context) {
JsonObject container = new JsonObject();
JsonObject result = new JsonObject();
JsonObject presets = new JsonObject();
container.add("config", context.serialize(config.getConfiguration(), Configuration.class));
result.add("groups", context.serialize(config.getGroups().toArray(), Group[].class));
presets.add("groups", context.serialize(config.getPresets().getGroups().toArray(), Group[].class));
presets.add("actions", context.serialize(config.getPresets().getActions().toArray(), Action[].class));
result.add("presets", presets);
container.add("data", result);
return container;
}
}

View File

@@ -0,0 +1,36 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ConfigurationDeserializer implements JsonDeserializer<Configuration> {
@Override
public Configuration deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject config = json.getAsJsonObject();
SimpleDateFormat dateFormat = new SimpleDateFormat(Configuration.DATE_FORMAT);
Date createdAt = new Date();
Date updatedAt = new Date();
try {
createdAt = dateFormat.parse(config.get("created_at").getAsString());
updatedAt = dateFormat.parse(config.get("updated_at").getAsString());
} catch (ParseException e) {
e.printStackTrace();
}
final int spec_version = config.get("spec_version").getAsInt();
final int revision = config.get("revision").getAsInt();
return new Configuration(createdAt, updatedAt, spec_version, revision);
}
}

View File

@@ -0,0 +1,28 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Configuration;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
public class ConfigurationSerializer implements JsonSerializer<Configuration> {
@Override
public JsonElement serialize(Configuration configuration, Type type, JsonSerializationContext context) {
JsonObject container = new JsonObject();
SimpleDateFormat dateFormat = new SimpleDateFormat(Configuration.DATE_FORMAT);
container.add("created_at", new JsonPrimitive(dateFormat.format(configuration.createdAt)));
container.add("updated_at", new JsonPrimitive(dateFormat.format(configuration.updatedAt)));
container.add("spec_version", new JsonPrimitive(configuration.getSpecVersion()));
container.add("revision", new JsonPrimitive(configuration.revision));
return container;
}
}

View File

@@ -0,0 +1,30 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GroupDeserializer implements JsonDeserializer<Group> {
@Override
public Group deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
final String name = jsonObject.get("name").getAsString();
Action[] actionsArray = context.deserialize(jsonObject.get("actions"), Action[].class);
List<Action> actionsList = Arrays.asList(actionsArray);
ArrayList<Action> actions = new ArrayList<>(actionsList);
return new Group(name, actions);
}
}

View File

@@ -0,0 +1,24 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import java.lang.reflect.Type;
public class GroupSerializer implements JsonSerializer<Group> {
@Override
public JsonElement serialize(Group group, Type type, JsonSerializationContext context) {
JsonObject container = new JsonObject();
container.add("name", new JsonPrimitive(group.name));
container.add("actions", context.serialize(group.getActions().toArray(), Action[].class));
return container;
}
}

View File

@@ -0,0 +1,33 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PresetsDeserializer implements JsonDeserializer<Presets> {
@Override
public Presets deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
Group[] GroupsArray = context.deserialize(jsonObject.get("groups"), Group[].class);
Action[] actionsArray = context.deserialize(jsonObject.get("actions"), Action[].class);
List<Group> groupsList = Arrays.asList(GroupsArray);
ArrayList<Group> groups = new ArrayList<>(groupsList);
List<Action> actionsList = Arrays.asList(actionsArray);
ArrayList<Action> actions = new ArrayList<>(actionsList);
return new Presets(groups, actions);
}
}

View File

@@ -0,0 +1,24 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Action;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Group;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Presets;
import java.lang.reflect.Type;
public class PresetsSerializer implements JsonSerializer<Presets> {
@Override
public JsonElement serialize(Presets presets, Type type, JsonSerializationContext context) {
JsonObject container = new JsonObject();
container.add("groups", context.serialize(presets.getGroups().toArray(), Group[].class));
container.add("actions", context.serialize(presets.getActions().toArray(), Action[].class));
return container;
}
}

View File

@@ -0,0 +1,25 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.timecrafters.TimeCraftersConfigurationTool.backend.Settings;
import java.lang.reflect.Type;
public class SettingsDeserializer implements JsonDeserializer<Settings> {
@Override
public Settings deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
JsonObject data = jsonObject.get("data").getAsJsonObject();
return new Settings(
data.get("hostname").getAsString(),
data.get("port").getAsInt(),
data.get("config").getAsString()
);
}
}

View File

@@ -0,0 +1,27 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.backend.Settings;
import java.lang.reflect.Type;
public class SettingsSerializer implements JsonSerializer<Settings> {
@Override
public JsonElement serialize(Settings settings, Type type, JsonSerializationContext context) {
JsonObject container = new JsonObject();
JsonObject result = new JsonObject();
result.add("hostname", new JsonPrimitive(settings.hostname));
result.add("port", new JsonPrimitive(settings.port));
result.add("config", new JsonPrimitive(settings.config));
container.add("data", result);
return container;
}
}

View File

@@ -0,0 +1,23 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
import java.lang.reflect.Type;
public class VariableDeserializer implements JsonDeserializer<Variable> {
@Override
public Variable deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
final String name = jsonObject.get("name").getAsString();
final String value = jsonObject.get("value").getAsString();
return new Variable(name, value);
}
}

View File

@@ -0,0 +1,23 @@
package org.timecrafters.TimeCraftersConfigurationTool.serializers;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.timecrafters.TimeCraftersConfigurationTool.backend.config.Variable;
import java.lang.reflect.Type;
public class VariableSerializer implements JsonSerializer<Variable> {
@Override
public JsonElement serialize(Variable variable, Type type, JsonSerializationContext context) {
JsonObject container = new JsonObject();
container.add("name", new JsonPrimitive(variable.name));
container.add("value", new JsonPrimitive(variable.rawValue()));
return container;
}
}

View File

@@ -0,0 +1,27 @@
package org.timecrafters.UltimateGoal.HardwareTesting;
import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.UltimateGoal.Robot;
public class ControlHubTest extends CyberarmState {
private Robot robot;
private float angle = 0;
public ControlHubTest(Robot robot) {
this.robot = robot;
}
@Override
public void exec() {
angle = robot.imu.getAngularOrientation().firstAngle;
}
@Override
public void telemetry() {
engine.telemetry.addLine("Greetings");
engine.telemetry.addData("Angle", angle);
}
}

View File

@@ -0,0 +1,66 @@
package org.timecrafters.UltimateGoal.HardwareTesting;
import org.cyberarm.engine.V2.CyberarmState;
import org.timecrafters.UltimateGoal.Robot;
public class EncoderTest extends CyberarmState {
private Robot robot;
private int ticksLeft;
private int ticksRight;
private double biasLeft = 0;
private double biasRight = 0;
public EncoderTest(Robot robot) {
this.robot = robot;
}
@Override
public void exec() {
robot.updateLocation();
if (runTime() < 3000) {
robot.setDrivePower(0.5, 0.5);
ticksLeft=robot.encoderLeft.getCurrentPosition();
ticksRight=robot.encoderRight.getCurrentPosition();
} else {
robot.encoderLeft.setPower(0.0);
robot.encoderRight.setPower(0.0);
double ticksExtreme;
if (Math.abs(ticksLeft) < Math.abs(ticksRight)) {
ticksExtreme = ticksLeft;
} else {
ticksExtreme = ticksRight;
}
biasLeft = ticksExtreme/ticksLeft;
biasRight = ticksExtreme/ticksRight;
}
}
@Override
public void telemetry() {
engine.telemetry.addLine("Biases");
engine.telemetry.addData("Left", biasLeft);
engine.telemetry.addData("Right", biasRight);
engine.telemetry.addLine();
engine.telemetry.addLine("Latency Values");
engine.telemetry.addData("Y", robot.getLocationY());
engine.telemetry.addData("X", robot.getLocationX());
engine.telemetry.addLine();
engine.telemetry.addData("Rotation", robot.getRotation());
engine.telemetry.addLine();
engine.telemetry.addLine("Actual Values");
engine.telemetry.addData("Left", ticksLeft);
engine.telemetry.addData("Right", ticksRight);
// engine.telemetry.addLine("");
// engine.telemetry.addData("Front", robot.encoderFront);
// engine.telemetry.addData("Back", robot.encoderBack);
}
}

View File

@@ -0,0 +1,28 @@
package org.timecrafters.UltimateGoal.HardwareTesting;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import org.cyberarm.engine.V2.CyberarmEngine;
import org.timecrafters.UltimateGoal.Robot;
@TeleOp (name = "Encoder test", group = "test")
public class TestingEngine extends CyberarmEngine {
private Robot robot;
@Override
public void init() {
robot = new Robot(hardwareMap);
robot.initHardware();
super.init();
}
@Override
public void setup() {
addState(new EncoderTest(robot));
}
}

View File

@@ -0,0 +1,103 @@
package org.timecrafters.UltimateGoal;
import com.qualcomm.hardware.bosch.BNO055IMU;
import com.qualcomm.robotcore.hardware.DcMotor;
import com.qualcomm.robotcore.hardware.DcMotorSimple;
import com.qualcomm.robotcore.hardware.HardwareMap;
import org.cyberarm.NeXT.StateConfiguration;
public class Robot {
private HardwareMap hardwareMap;
public Robot(HardwareMap hardwareMap) {
this.hardwareMap = hardwareMap;
}
public StateConfiguration stateConfiguration = new StateConfiguration();
public BNO055IMU imu;
//drive system
public DcMotor encoderFront;
public DcMotor encoderLeft;
public DcMotor encoderBack;
public DcMotor encoderRight;
double BIAS_LEFT = 1.0;
double BIAS_RIGHT = 0.6815;
//Robot Localizatoin
private double locationX;
private double locationY;
private float rotation;
private int encoderFrontPrevious = 0;
private int encoderLeftPrevious = 0;
private int encoderBackPrevious = 0;
private int encoderRightPrevious = 0;
private float rotationPrevious = 0;
public void initHardware() {
imu = hardwareMap.get(BNO055IMU.class, "imu");
// encoderFront = hardwareMap.dcMotor.get("encoderFront");
encoderLeft = hardwareMap.dcMotor.get("encoderLeft");
// encoderBack = hardwareMap.dcMotor.get("encoderBack");
encoderRight = hardwareMap.dcMotor.get("encoderRight");
encoderLeft.setDirection(DcMotorSimple.Direction.REVERSE);
encoderLeft.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
encoderRight.setZeroPowerBehavior(DcMotor.ZeroPowerBehavior.BRAKE);
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);
}
public void setDrivePower(double powerLeft, double powerRight){
encoderLeft.setPower(powerLeft * BIAS_LEFT);
encoderRight.setPower(powerRight * BIAS_RIGHT);
}
public void updateLocation(){
rotation = imu.getAngularOrientation().firstAngle;
float rotationChange = rotation - rotationPrevious;
int encoderLeftCurrent = encoderLeft.getCurrentPosition();
int encoderRightCurrent = encoderRight.getCurrentPosition();
double encoderLeftChange = encoderLeftCurrent - encoderLeftPrevious;
double encoderRightChange = encoderRightCurrent - encoderRightPrevious;
encoderLeftPrevious = encoderLeftCurrent;
encoderRightPrevious = encoderRightCurrent;
rotationPrevious = rotation;
double average = (encoderLeftChange+encoderRightChange)/2;
double xChange = average * (Math.sin(Math.toRadians(rotationChange)));
double yChange = average * (Math.cos(Math.toRadians(rotationChange)));
locationX += xChange;
locationY += yChange;
}
public double getRotation() {
return rotation;
}
public double getLocationX() {
return locationX;
}
public double getLocationY() {
return locationY;
}
}