diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/BSD_License_for_WPILib_code.txt b/BSD_License_for_WPILib_code.txt new file mode 100644 index 0000000..f7ee350 --- /dev/null +++ b/BSD_License_for_WPILib_code.txt @@ -0,0 +1,24 @@ +* Copyright (c) 2009 FIRST +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the FIRST nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY FIRST AND CONTRIBUTORS``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8cede3a --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +GRT Framework v6 +================ + +GRTFramework is an asynchronous, event-driven framework built on top of [WPILibJ](http://firstforge.wpi.edu/sf/projects/wpilib), which is provided by FIRST and includes a host of useful low-level hardware classes. + +The purpose of GRTFramework is: +* To provide a framework for rapid FRC robot development +* An asynchronous design and a focus on quality code design +* Coder happiness :) + +Please feel free to email any of the developers if you have questions about the code. + +-FRC Team 192: Gunn Robotics Team (A.K.A "GRT") diff --git a/build.properties b/build.properties new file mode 100644 index 0000000..4ea99c3 --- /dev/null +++ b/build.properties @@ -0,0 +1,10 @@ +# Properties file for a Sun Spot Application +# +# build.properties +# +# This file is the default location for user properties that over-ride the +# defaults in ${sunspot.home}/default.properties. See that file for a full +# listing of the properties that may be set. This file is minimal and contains +# only those properties that a user would generally need to set right away. +# +user.classpath=${wpilibj.home}/src diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..a8f5392 --- /dev/null +++ b/build.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..f6b0258 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,93 @@ + + + + org.netbeans.modules.ant.freeform + + + grtframeworkv6 + + ${user.home}/.sunspotfrc.properties + build.properties + ${sunspot.home}/default.properties + + + + + java + src + + + + + jar-app + + + clean + + + deploy + run + + + clean + jar-app + + + deploy + debug-run + + + javadoc + + + + folder + build + jar-app + + + + + + src + + + build.xml + + + + + + + + + + + + deploy + + + + jar-deploy + + + + + + + + + src + ${sunspot.bootclasspath} + /home/gerberduffy/sunspotfrcsdk/lib/WPILibJ/classes.jar + build + 1.4 + + + + diff --git a/resources/META-INF/MANIFEST.MF b/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..a9b02ac --- /dev/null +++ b/resources/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +MIDlet-Name: Base2012-redesign +MIDlet-Version: 1.0.0 +MIDlet-Vendor: FIRST +MIDlet-1: MainRobot, , deploy.MainRobot +MicroEdition-Profile: IMP-1.0 +MicroEdition-Configuration: CLDC-1.1 diff --git a/src/actuator/GRTLed.java b/src/actuator/GRTLed.java new file mode 100644 index 0000000..754e647 --- /dev/null +++ b/src/actuator/GRTLed.java @@ -0,0 +1,73 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package actuator; + +import core.Actuator; +import edu.wpi.first.wpilibj.PWM; + +/** + * Abstraction of a standard LED + * @author gerberduffy + */ +public class GRTLed extends Actuator { + + private static final int DEFAULT_BRIGHTNESS = 255; + private static final int HIGHEST_BRIGHTNESS = 255; + private static final int OFF_BRIGHTNESS = 0; + + + private final PWM led; //The PWM input controlling the LED + private int brightness; + + public GRTLed(int channel, String id){ + this(channel, DEFAULT_BRIGHTNESS, id); + } + + public GRTLed(int channel, int brightness, String id){ + super(id); + + this.brightness = brightness; + + led = new PWM(channel); + led.setRaw(brightness); + } + + public void setToBrightness(int bright){ + if (bright > HIGHEST_BRIGHTNESS){ + bright = HIGHEST_BRIGHTNESS; + } else if (bright < OFF_BRIGHTNESS){ + bright = OFF_BRIGHTNESS; + } + + led.setRaw(bright); + + this.brightness = bright; + } + + public void toggleState(){ + if (isOn()){ + led.setRaw(OFF_BRIGHTNESS); + brightness = OFF_BRIGHTNESS; + + } else { + led.setRaw(HIGHEST_BRIGHTNESS); + brightness = HIGHEST_BRIGHTNESS; + } + } + + public int getBrightness(){ + return this.brightness; + } + + public boolean isOn(){ + return this.brightness > OFF_BRIGHTNESS; + } + + public void executeCommand(double command) { + led.setRaw((int) command); + brightness = (int) command; + } + +} diff --git a/src/actuator/GRTRelay.java b/src/actuator/GRTRelay.java new file mode 100644 index 0000000..22dd609 --- /dev/null +++ b/src/actuator/GRTRelay.java @@ -0,0 +1,53 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package actuator; + +import edu.wpi.first.wpilibj.Relay; +import core.Actuator; + +/** + * + * @author calvin + */ +public class GRTRelay extends Actuator{ + private Relay relay; + + private static final double FORWARD = 1.0; + private static final double REVERSE = -1.0; + private static final double OFF = 0.0; + + public GRTRelay(int channel, String name){ + super(name); + relay = new Relay(channel); + } + + /** + * Sends command to relay. If the value of the command is -1.0 the relay is in reverse, + * 1.0 is forward, and 0.0 is off. + * @param c + */ + public void executeCommand(double command) { + if (command == OFF) { + relay.set(Relay.Value.kOff); + } else if(command == FORWARD) { + relay.set(Relay.Value.kForward); + } else if(command == REVERSE) { + relay.set(Relay.Value.kReverse); + } + } +/** + * SEts the state of the relay to off + */ + public void halt() { + relay.set(Relay.Value.kOff); + } +/** + * Returns String + * @return + */ + public String toString() { + return "Relay"; + } +} diff --git a/src/actuator/GRTSolenoid.java b/src/actuator/GRTSolenoid.java new file mode 100644 index 0000000..343ce6a --- /dev/null +++ b/src/actuator/GRTSolenoid.java @@ -0,0 +1,46 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package actuator; + +import core.Actuator; +import edu.wpi.first.wpilibj.Solenoid; + +/** + * + * @author gerberduffy + */ +public class GRTSolenoid extends Actuator { + + private Solenoid sol; + + public static final double ON = 1.0; + public static final double OFF = 0.0; + + public GRTSolenoid(int slot, int channel, String id) { + super(id); + + sol = new Solenoid(slot, channel); + } + + /* + * Engage or disengage the solenoid + */ + public void executeCommand(double command) { + if (command == ON) { + sol.set(true); + } else if (command == OFF) { + sol.set(false); + } + } + + +// @Override + public void halt() { + sol.set(false); + + super.halt(); + + } +} diff --git a/src/actuator/GRTVictor.java b/src/actuator/GRTVictor.java new file mode 100644 index 0000000..35d7be2 --- /dev/null +++ b/src/actuator/GRTVictor.java @@ -0,0 +1,39 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package actuator; + +import core.Actuator; +import edu.wpi.first.wpilibj.Victor; + +/** + * + * @author ajc + */ +public class GRTVictor extends Actuator implements IMotor { + + Victor victor; + + public GRTVictor(int id, String name) { + super(name); + victor = new Victor(id); + } + + public void executeCommand(double command) { + if (enabled) { + victor.set(command); + } + } + + /* + * Set the Victor's speed + * @param speed the new speed to set + */ + public void setSpeed(double speed){ + if(enabled){ + victor.set(speed); +// log(speed); + } + } +} diff --git a/src/actuator/IMotor.java b/src/actuator/IMotor.java new file mode 100644 index 0000000..6020262 --- /dev/null +++ b/src/actuator/IMotor.java @@ -0,0 +1,21 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package actuator; + +import core.IProcess; + +/** + * + * @author ajc + */ +public interface IMotor extends IProcess{ + + /** + * + * @param speed + */ + public void setSpeed(double speed); + +} diff --git a/src/balancer/BalanceController.java b/src/balancer/BalanceController.java new file mode 100644 index 0000000..c2696f2 --- /dev/null +++ b/src/balancer/BalanceController.java @@ -0,0 +1,63 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package balancer; +import balancer.RobotTiltGyro; +import core.EventController; +import event.RobotTiltListener; +import event.RobotTiltEvent; +import mechanism.GRTRobotBase; + + +/** + * + * @author calvin + */ +public class BalanceController extends EventController implements RobotTiltListener{ + + private double previousAngle; + private double currentAngle; + private double deltaAngle; + private double P_CONSTANT = .024; + private double D_CONSTANT = 0; + private final RobotTiltGyro robotTilt; + private final GRTRobotBase base; + private double DRIVE_THRESHOLD = .01; + + public BalanceController(GRTRobotBase base, RobotTiltGyro robotTilt, String name){ + super(name); + this.base = base; + this.robotTilt = robotTilt; + } + + public void startBalancing(){ + startListening(); + } + + public void stopBalancing(){ + stopListening(); + } + + protected void startListening() { + robotTilt.addRobotTiltListeners(this); + } + + protected void stopListening() { + robotTilt.removeRobotTiltListeners(this); + } + + public void RobotTiltChange(RobotTiltEvent e) { + currentAngle = e.getTilt(); + deltaAngle = currentAngle - previousAngle; + double drivePower = P_CONSTANT * currentAngle - D_CONSTANT * deltaAngle; + if(Math.abs(drivePower) >= DRIVE_THRESHOLD) + base.tankDrive(drivePower, drivePower); + else + base.tankDrive(0, 0); + System.out.println(drivePower); + } + + + +} diff --git a/src/balancer/RobotTiltAccel.java b/src/balancer/RobotTiltAccel.java new file mode 100644 index 0000000..cfbe3e5 --- /dev/null +++ b/src/balancer/RobotTiltAccel.java @@ -0,0 +1,91 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +//DO NOT USE--use robotTiltGyro instead +package balancer; + +import com.sun.squawk.util.MathUtils; +import core.Sensor; +import event.ADXL345Event; +import event.ADXL345Listener; +import event.RobotTiltEvent; +import event.RobotTiltListener; +import java.util.Vector; +import sensor.GRTADXL345; + +/** + * + * @author calvin + */ +public class RobotTiltAccel extends Sensor implements ADXL345Listener { + + private Vector robotTiltListeners; + private static final int NUM_DATA = 1;//TODO change + public static final int KEY_ANGLE = 0; + private double angle; + private double xAccel; + private double yAccel; + private double zAccel; + private final GRTADXL345 accelerometer; + + public RobotTiltAccel(GRTADXL345 accelerometer, String name) { + super(name); + this.accelerometer = accelerometer; + robotTiltListeners = new Vector(); + } + +// protected void notifyListeners(int id, double oldDatum, double newDatum) { +// RobotTiltEvent e = new RobotTiltEvent(this, id, newDatum); +// for (int i = 0; i < robotTiltListeners.size(); i++) { +// ((RobotTiltListener) robotTiltListeners.elementAt(i)).RobotTiltChange(e); +// } +// } + + private void updateAngle() { + //magnitude of vector sum of x, y accelerations + double normalDeviation = Math.sqrt(((xAccel) * (xAccel)) + + ((yAccel) * (yAccel))); +// double oldAngle = angle; + angle = MathUtils.atan(normalDeviation / zAccel); + //angle is angle between acceleration vector and z axis + notifyStateChange(KEY_ANGLE, angle); + } + + public double getTilt() { + return angle; + } + + public void addRobotTiltListeners(RobotTiltListener l) { + robotTiltListeners.addElement(l); + } + + public void removeRobotTiltListeners(RobotTiltListener l) { + robotTiltListeners.removeElement(l); + } + + //@Override + protected void startListening() { + accelerometer.addADXL345Listener(this); + } + + protected void stopListening() { + accelerometer.removeADXL345Listener(this); + } + + public void XAccelChange(ADXL345Event e) { + xAccel = e.getAcceleration(); + updateAngle(); + } + + public void YAccelChange(ADXL345Event e) { + yAccel = e.getAcceleration(); + updateAngle(); + } + + public void ZAccelChange(ADXL345Event e) { + zAccel = e.getAcceleration(); + updateAngle(); + } +} \ No newline at end of file diff --git a/src/balancer/RobotTiltGyro.java b/src/balancer/RobotTiltGyro.java new file mode 100644 index 0000000..e8a8f2b --- /dev/null +++ b/src/balancer/RobotTiltGyro.java @@ -0,0 +1,68 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package balancer; +import core.Sensor; +import sensor.GRTGyro; +import event.GyroEvent; +import event.GyroListener; +import java.util.Vector; +import event.RobotTiltEvent; +import event.RobotTiltListener; + +/** + * + * @author calvin + */ + + +public class RobotTiltGyro extends Sensor implements GyroListener{ + private Vector robotTiltListeners; + private double angle; + private double previousAngle; + private GRTGyro g; + + public RobotTiltGyro(GRTGyro g, String name){ + super(name); + this.g = g; + robotTiltListeners = new Vector(); + angle = 0; + previousAngle = 0; + } + public void angleChanged(GyroEvent e) { + updateAngle(); + } + + private void updateAngle(){ + angle += g.getAngle() - previousAngle; + previousAngle = g.getAngle(); + notifyStateChange(0, angle); + notifyListeners(0, angle); + } + + protected void notifyListeners(int id, double newDatum) { + RobotTiltEvent e = new RobotTiltEvent(this, id, newDatum); + for (int i = 0; i < robotTiltListeners.size(); i++) { + ((RobotTiltListener) robotTiltListeners.elementAt(i)).RobotTiltChange(e); + } + + + } + + public void addRobotTiltListeners(RobotTiltListener l) { + robotTiltListeners.addElement(l); + } + + public void removeRobotTiltListeners(RobotTiltListener l) { + robotTiltListeners.removeElement(l); + } + + protected void startListening() { + g.addListener(this); + } + + protected void stopListening() { + g.removeListener(this); + } +} diff --git a/src/balancer/balancePD.java b/src/balancer/balancePD.java new file mode 100644 index 0000000..46de57d --- /dev/null +++ b/src/balancer/balancePD.java @@ -0,0 +1,58 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package balancer; +import balancer.RobotTiltAccel; +import core.EventController; +import event.RobotTiltListener; +import event.RobotTiltEvent; +import mechanism.GRTRobotBase; + + +/** + * + * @author calvin + */ +public class balancePD extends EventController implements RobotTiltListener{ + + private double previousAngle; + private double currentAngle; + private double deltaAngle; + private double P_CONSTANT = 1; + private double D_CONSTANT = 0; + private final RobotTiltAccel robotTilt; + private final GRTRobotBase base; + + public balancePD(GRTRobotBase base, RobotTiltAccel robotTilt, String name){ + super(name); + this.base = base; + this.robotTilt = robotTilt; + } + +// public void startBalancing(){ +// startListening(); +// } +// +// public void stopBalancing(){ +// stopListening(); +// } + + protected void startListening() { + robotTilt.addRobotTiltListeners(this); + } + + protected void stopListening() { + robotTilt.removeRobotTiltListeners(this); + } + + public void RobotTiltChange(RobotTiltEvent e) { + currentAngle = e.getTilt(); + deltaAngle = currentAngle - previousAngle; + double drivePower = P_CONSTANT * currentAngle - D_CONSTANT * deltaAngle; + base.tankDrive(drivePower, drivePower); + } + + + +} diff --git a/src/controller/PrimaryDriver.java b/src/controller/PrimaryDriver.java new file mode 100644 index 0000000..5d93b49 --- /dev/null +++ b/src/controller/PrimaryDriver.java @@ -0,0 +1,74 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package controller; + +import core.EventController; +import edu.wpi.first.wpilibj.DriverStation; +import event.DrivingEvent; +import event.DrivingListener; +import event.DrivingProfileEvent; +import event.DrivingProfileListener; +import event.XboxJoystickEvent; +import event.XboxJoystickListener; +import mechanism.GRTDriveTrain; +import sensor.base.GRTXboxDriverStation; +import mechanism.GRTRobotBase; +import sensor.base.IDriverProfile; +import sensor.base.LinearDrive; +import sensor.GRTXBoxJoystick; +import sensor.base.GRTDriverStation; + +/** + * Robot base driving. + * + * Operates for any DriverStation + * + * @author ajc + */ +public class PrimaryDriver extends EventController implements DrivingListener, DrivingProfileListener { + + //sensor + private final GRTDriverStation ds; + //actuator + private final GRTRobotBase dt; + //drive curve + private IDriverProfile driveProfile; + //state + private double leftVelocity; + private double rightVelocity; + + public PrimaryDriver(GRTRobotBase dt, GRTDriverStation ds, IDriverProfile driveProfile, String name) { + super(name); + this.dt = dt; + this.ds = ds; + this.driveProfile = driveProfile; + } + + protected void startListening() { + ds.addDrivingListener(this); + ds.addDrivingProfileListener(this); + } + + protected void stopListening() { + ds.removeDrivingListener(this); + ds.removeDrivingProfileListener(this); + } + + public void driverLeftSpeed(DrivingEvent e) { + leftVelocity = e.getPercentSpeed(); + + dt.tankDrive(driveProfile.driveSpeed(leftVelocity), driveProfile.driveSpeed(rightVelocity)); + } + + public void driverRightSpeed(DrivingEvent e) { + rightVelocity = e.getPercentSpeed(); + + dt.tankDrive(driveProfile.driveSpeed(leftVelocity), driveProfile.driveSpeed(rightVelocity)); + } + + public void drivingProfileChanged(DrivingProfileEvent e) { + driveProfile = e.getProfile(); + } +} diff --git a/src/core/Actuator.java b/src/core/Actuator.java new file mode 100644 index 0000000..7010c78 --- /dev/null +++ b/src/core/Actuator.java @@ -0,0 +1,25 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package core; + +/** + * An actuator is a driver for low level hardware that directly influences the + * physical world. Actuators can perform actions. + * @author ajc + */ +public abstract class Actuator extends GRTLoggedProcess { + + + public Actuator(String name){ + super(name); + } + + /** + * Performs an action. Actuator must be enabled for this to succeed. + * @param command + */ + public abstract void executeCommand(double command); + +} diff --git a/src/core/EventController.java b/src/core/EventController.java new file mode 100644 index 0000000..1eae9ab --- /dev/null +++ b/src/core/EventController.java @@ -0,0 +1,39 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package core; + +/** + * An EventController describes behavior based on received events. + * @author ajc + */ +public abstract class EventController extends GRTLoggedProcess { + + public EventController(String name) { + super(name); + running = true; //TODO does this belong + } + + /** + * Adds listeners. + */ + protected abstract void startListening(); + + /** + * Removes listeners + */ + protected abstract void stopListening(); + + + public void enable() { + //enable() always works because an EventController is always running + super.enable(); + startListening(); + } + + public void disable() { + super.disable(); + stopListening(); + } +} diff --git a/src/core/GRTLoggedProcess.java b/src/core/GRTLoggedProcess.java new file mode 100644 index 0000000..3c1cb5b --- /dev/null +++ b/src/core/GRTLoggedProcess.java @@ -0,0 +1,93 @@ +package core; + +/** + * A GRTLoggedProcess is a controllable process. It can be initiated/terminated. + * + * When a GRTLoggedProcess is constructed, it is immediately run, but not enabled. + * + * @author ajc + * + */ +public abstract class GRTLoggedProcess extends Thread implements IProcess { + + protected final String name; + protected boolean enabled = false; + protected boolean running = true; + + public GRTLoggedProcess(String name) { + this.name = name; + } + + /** + * + * @param message + */ + protected void log(String message) { + System.out.println(toString() + "\t" + message); + } + + /** + * Logs in format: "[[ClassName:Id]] @name message + * @param name + * @param message + */ + protected void log(String name, String message) { + System.out.println(toString() + "\t" + name + "\t" + message); + } + + /** + * + * @param data + */ + protected void log(double data) { + System.out.println(toString() + "\t" + data); + + } + + /** + * + * @param name + * @param data + */ + protected void log(String name, double data) { + System.out.println(toString() + "\t" + name + "\t" + data); + } + + public void enable() { + enabled = true; + } + + public void disable() { + enabled = false; + } + + public boolean isEnabled() { + return enabled; + } + + public void halt() { + running = false; + disable(); + } + + public boolean isRunning() { + return running; + } + + /** + * Name + * + * @return + */ + public String getID() { + return name; + } + + /* + * To string method, returns loggable string in the formate + * [[ClassName:Id]] + */ + public String toString(){ + return "[[" + getClass().getName() + ":" + getID(); + } +} diff --git a/src/core/IProcess.java b/src/core/IProcess.java new file mode 100644 index 0000000..b38d8b4 --- /dev/null +++ b/src/core/IProcess.java @@ -0,0 +1,41 @@ +package core; + +/** + * An IProcess is a component that produces a certain behavior. + * This behavior can be enabled or disabled for a temporary pausing, or halted. + * Halting stops the behavior from ever being re-enabled again. + * + * @author ajc + * + */ +public interface IProcess { + + /** + * Enables process behavior + */ + public void enable(); + + /** + * Disables process behavior + */ + public void disable(); + + /** + * + * @return true if behavior is active + */ + public boolean isEnabled(); + + /** + * Terminates the behavior forever + */ + public void halt(); + + /** + * + * @return true if the process can be enabled + */ + public boolean isRunning(); + + +} diff --git a/src/core/PollingSensor.java b/src/core/PollingSensor.java new file mode 100644 index 0000000..969d98a --- /dev/null +++ b/src/core/PollingSensor.java @@ -0,0 +1,98 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package core; + +/** + * A PollingSensor directly obtains data through the poll() method, as opposed + * to generic sensors that could receive events. + * + * It additionally stores the state of variables, and automatically performs + * state change checks. + * + * + * @author ajc + */ +public abstract class PollingSensor extends Sensor { + + private double[] data; + private final int sleepTime; + + /** + * Construct a polling sensor. + * Subclasses need to start themselves-- make a call to start(); + * @param name name of the sensor + * @param sleepTime time between polls [ms] + * @param numData number of pieces of data + */ + public PollingSensor(String name, int sleepTime, int numData) { + super(name); + this.sleepTime = sleepTime; + data = new double[numData]; + } + + /** + * Called to poll sensor. + */ + protected abstract void poll(); + + public void run() { + running = true; + while (running) { + + //only poll, and thus only send events, if enabled + if (enabled) { + poll(); + } + + try { + Thread.sleep(sleepTime); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + } + + /** + * Stores a datum, and notifies listeners if the state of it has changed. + * + * @param id key of the data + * @param datum fresh datum + */ + protected void setState(int id, double datum) { + double previous = data[id]; + //notify self and state change listeners if the datum has changed + if (previous != datum) { + notifyListeners(id, previous, datum); + notifyStateChange(id, datum); + } + data[id] = datum; + } + + /** + * Retrieves sensor data + * @param id + * @return + */ + public double getState(int id) { + return data[id]; + } + + /** + * Calls the listener events based on what has changed + * @param id the key of the data that changed + * @param oldDatum the datum's previous value + * @param newDatum the datum's new value + */ + protected abstract void notifyListeners(int id, double oldDatum, double newDatum); + + /* + * Polling sensors do not listen to things, necesserily + */ + protected void startListening() { + } + + protected void stopListening() { + } +} diff --git a/src/core/Sensor.java b/src/core/Sensor.java new file mode 100644 index 0000000..cc75c08 --- /dev/null +++ b/src/core/Sensor.java @@ -0,0 +1,67 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package core; + +import event.SensorChangeListener; +import event.SensorEvent; +import java.util.Vector; + +/** + * A sensor sends sensor event data. They only send data when running. + * + * @author ajc + */ +public abstract class Sensor extends GRTLoggedProcess { + + //Constants + public static final double TRUE = 1.0; + public static final double FALSE = 0.0; + public static final double ERROR = -999; + + //Instance variables + private Vector listeners; //Collection of things that listen to this sensor + + public Sensor(String name) { + super(name); + listeners = new Vector(); + running = true; + } + + /** + * Adds listeners. + */ + protected abstract void startListening(); + + /** + * Removes listeners + */ + protected abstract void stopListening(); + + public void enable() { + //enable() always works because a Sensor is always running + super.enable(); + startListening(); + } + + public void disable() { + super.disable(); + stopListening(); + } + + protected void notifyStateChange(int id, double data) { + SensorEvent e = new SensorEvent(this, id, data); + for (int i = 0; i < listeners.size(); i++) { + ((SensorChangeListener) listeners.elementAt(i)).sensorStateChanged(e); + } + } + + public void addSensorStateChangeListener(SensorChangeListener l) { + listeners.addElement(l); + } + + public void removeSensorStateChangeListener(SensorChangeListener l) { + listeners.removeElement(l); + } +} diff --git a/src/deploy/GRTRobot.java b/src/deploy/GRTRobot.java new file mode 100644 index 0000000..810f06d --- /dev/null +++ b/src/deploy/GRTRobot.java @@ -0,0 +1,69 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2008. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ +package deploy; + +import core.EventController; +import edu.wpi.first.wpilibj.SimpleRobot; +import java.util.Vector; + +/** + * + * GRTRobot is the entry point. + * + * The VM is configured to automatically run this class, and to call the + * functions corresponding to each mode, as described in the SimpleRobot + * documentation. If you change the name of this class or the package after + * creating this project, you must also update the manifest file in the resource + * directory. + */ +public abstract class GRTRobot extends SimpleRobot { + + private Vector autoControllers; + private Vector teleopControllers; + + public GRTRobot() { + autoControllers = new Vector(); + teleopControllers = new Vector(); + + } + + /** + * This function is called once each time the robot enters autonomous mode. + * All Autonomous controllers are started/resumed, and all teleop controllers are paused. + */ + public void autonomous() { + for (int i = 0; i < teleopControllers.size(); i++) { + ((EventController) teleopControllers.elementAt(i)).disable(); + } + for (int i = 0; i < autoControllers.size(); i++) { + ((EventController) autoControllers.elementAt(i)).enable(); + } + + } + + /** + * This function is called once each time the robot enters operator control. + * All Teleop controllers are started/resumed, and all autonomous controllers are paused. + */ + public void operatorControl() { + for (int i = 0; i < autoControllers.size(); i++) { + ((EventController) autoControllers.elementAt(i)).disable(); + } + for (int i = 0; i < teleopControllers.size(); i++) { + ((EventController) teleopControllers.elementAt(i)).enable(); + } + + } + + public void addAutonomousController(EventController c) { + autoControllers.addElement(c); + } + + public void addTeleopController(EventController c) { + teleopControllers.addElement(c); + } +} diff --git a/src/deploy/MainRobot.java b/src/deploy/MainRobot.java new file mode 100644 index 0000000..8d6c2c9 --- /dev/null +++ b/src/deploy/MainRobot.java @@ -0,0 +1,136 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package deploy; + +import actuator.GRTVictor; +import balancer.RobotTiltAccel; +import controller.PrimaryDriver; +import mechanism.GRTDriveTrain; +import sensor.base.GRTXboxDriverStation; +import mechanism.GRTRobotBase; +import sensor.base.LinearDrive; +import sensor.base.SquareDrive; +import sensor.base.IDriverProfile; +import rpc.connection.NetworkRPC; +import rpc.telemetry.SensorLogger; +import sensor.ADXL345DigitalAccelerometer; +import sensor.GRTADXL345; +import sensor.GRTAttack3Joystick; +import sensor.GRTBatterySensor; +import sensor.GRTEncoder; +import sensor.GRTGyro; +import sensor.GRTSwitch; +import sensor.GRTXBoxJoystick; +import sensor.base.*; + +/** + * + * @author ajc + */ +public class MainRobot extends GRTRobot { + + /** + * Buttons which refer to enumerated driver curve profiles. + * First index refers to Linear drive + * Second index refers to Square drive + */ + public static final int[] DRIVER_PROFILE_KEYS = new int[] {1,2}; + public static final IDriverProfile[] DRIVER_PROFILES = new IDriverProfile[] {new LinearDrive(), new SquareDrive()}; + + + + //Global Controllers + private SensorLogger batteryLogger; + //Teleop Controllers + private PrimaryDriver driveControl; + private GRTDriverStation driverStation; + private GRTRobotBase robotBase; + private GRTADXL345 adxl; +// private final ADXL345DigitalAccelerometer primaryADXL; +// private final RobotTiltAccel tiltSensor; +// private final SensorLogger tiltLogger; + + + public MainRobot() { + + System.out.println("Running grtframeworkv6"); + + //RPC Connection + NetworkRPC rpcConn = new NetworkRPC(180); + + //Driver station components + GRTAttack3Joystick primary = new GRTAttack3Joystick(1, 12, "primary"); + GRTAttack3Joystick secondary = new GRTAttack3Joystick(2, 12, "secondary"); + primary.start(); + secondary.start(); + primary.enable(); + secondary.enable(); + System.out.println("Joysticks initialized"); + + //Battery Sensor + GRTBatterySensor batterySensor = new GRTBatterySensor(10, "battery"); + batterySensor.start(); + batterySensor.enable(); + + // PWM outputs + GRTVictor leftDT1 = new GRTVictor(2, "leftDT1"); + GRTVictor leftDT2 = new GRTVictor(3, "leftDT2"); + GRTVictor rightDT1 = new GRTVictor(8, "rightDT1"); + GRTVictor rightDT2 = new GRTVictor(9, "rightDT2"); + leftDT1.enable(); + leftDT2.enable(); + rightDT1.enable(); + rightDT2.enable(); + System.out.println("Motors initialized"); + + //Mechanisms + GRTDriveTrain dt = new GRTDriveTrain(leftDT1, leftDT2, rightDT1, rightDT2); + robotBase = new GRTRobotBase(dt, batterySensor); + driverStation = new GRTAttack3DriverStation(primary, secondary, DRIVER_PROFILE_KEYS, DRIVER_PROFILES, + "driverStation"); + driverStation.enable(); + System.out.println("Mechanisms initialized"); + + //Controllers + driveControl = new PrimaryDriver(robotBase, driverStation, new LinearDrive(), "driveControl"); + batteryLogger = new SensorLogger(batterySensor, rpcConn, new int[]{23}, "batterylogger"); + System.out.println("Controllers Initialized"); + +// adxl = new GRTADXL345(1, 25, "ADXL345"); +// adxl.enable(); +// adxl.start(); + + +// GRTGyro gyro = new GRTGyro(1, 10, "Gyro"); +// gyro.enable(); +// gyro.start(); + +// tiltSensor = new RobotTiltAccel(adxl, "TiltSensor"); +// tiltLogger = new SensorLogger(tiltSensor, rpcConn, new int[]{210}, "tiltLogger"); + + // Start/prepare controllers +// primaryADXL.enable(); +// batteryLogger.enable(); +// tiltSensor.enable(); + + addTeleopController(driveControl); +// addAutonomousController(tiltLogger); + + GRTEncoder encoder1 = new GRTEncoder(2, 1, 4.0, 10, "EncoderLeft"); + + GRTEncoder encoder2 = new GRTEncoder(3, 4, 4.0, 10, "EncoderRight"); + + + encoder1.start(); encoder1.enable(); + encoder2.start(); encoder2.enable(); + + SensorLogger encoderLogger1 = new SensorLogger(encoder1, rpcConn, new int[]{81, 82, 83}, null); + SensorLogger encoderLogger2 = new SensorLogger(encoder2, rpcConn, new int[]{84,85,86}, null); + + + encoderLogger1.enable(); + encoderLogger2.enable(); + } +} diff --git a/src/event/ADXL345Event.java b/src/event/ADXL345Event.java new file mode 100644 index 0000000..2e13e1d --- /dev/null +++ b/src/event/ADXL345Event.java @@ -0,0 +1,39 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; +import sensor.GRTADXL345; + +/** + * + * @author calvin + */ +public class ADXL345Event { + public static final int KEY_X = 0; + public static final int KEY_Y = 1; + public static final int KEY_Z = 2; + + private GRTADXL345 source; + private int id; + private double acceleration; + + public ADXL345Event(GRTADXL345 source, int id, double acceleration) { + this.source = source; + this.id = id; + this.acceleration = acceleration; + } + + //TODO what units + public double getAcceleration() { + return acceleration; + } + + public int getId() { + return id; + } + + public GRTADXL345 getSource() { + return source; + } +} diff --git a/src/event/ADXL345Listener.java b/src/event/ADXL345Listener.java new file mode 100644 index 0000000..c06f406 --- /dev/null +++ b/src/event/ADXL345Listener.java @@ -0,0 +1,18 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author calvin + */ +public interface ADXL345Listener { + + public void XAccelChange(ADXL345Event e); + + public void YAccelChange(ADXL345Event e); + + public void ZAccelChange(ADXL345Event e); +} diff --git a/src/event/Attack3JoystickEvent.java b/src/event/Attack3JoystickEvent.java new file mode 100644 index 0000000..f0feb5f --- /dev/null +++ b/src/event/Attack3JoystickEvent.java @@ -0,0 +1,31 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; +import sensor.GRTAttack3Joystick; +/** + * + * @author dan + */ +public class Attack3JoystickEvent { + public static final int DEFAULT = 0; + private int id; + private double value; + private GRTAttack3Joystick source; + + public Attack3JoystickEvent(GRTAttack3Joystick source, int id, double value){ + this.source = source; + this.id = id; + this.value = value; + } + public int getId() { + return id; + } + public GRTAttack3Joystick getSource(){ + return source; + } + public double getValue() { + return value; + } +} diff --git a/src/event/Attack3JoystickListener.java b/src/event/Attack3JoystickListener.java new file mode 100644 index 0000000..7648796 --- /dev/null +++ b/src/event/Attack3JoystickListener.java @@ -0,0 +1,15 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author dan + */ +public interface Attack3JoystickListener { + public void XAxisMoved(Attack3JoystickEvent e); + public void YAxisMoved(Attack3JoystickEvent e); + public void AngleChanged(Attack3JoystickEvent e); +} diff --git a/src/event/BatteryVoltageEvent.java b/src/event/BatteryVoltageEvent.java new file mode 100644 index 0000000..f815ccd --- /dev/null +++ b/src/event/BatteryVoltageEvent.java @@ -0,0 +1,32 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package event; + +import sensor.GRTBatterySensor; + + +/** + * + * @author ajc + */ +public class BatteryVoltageEvent { + private final GRTBatterySensor sensor; + private final double voltage; + + public BatteryVoltageEvent(GRTBatterySensor sensor, double voltage){ + this.sensor = sensor; + this.voltage = voltage; + } + + public GRTBatterySensor getSource(){ + return sensor; + } + + public double getVoltage(){ + return voltage; + } + +} diff --git a/src/event/BatteryVoltageListener.java b/src/event/BatteryVoltageListener.java new file mode 100644 index 0000000..87da8e3 --- /dev/null +++ b/src/event/BatteryVoltageListener.java @@ -0,0 +1,16 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package event; + +/** + * + * @author ajc + */ +public interface BatteryVoltageListener { + + public void batteryVoltageChanged(BatteryVoltageEvent ev); + +} diff --git a/src/event/ButtonEvent.java b/src/event/ButtonEvent.java new file mode 100644 index 0000000..1155d43 --- /dev/null +++ b/src/event/ButtonEvent.java @@ -0,0 +1,40 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import core.Sensor; + +/** + * + * @author ajc + */ +public class ButtonEvent { + private final Sensor source; + private final int id; + private final boolean pressed; + + public ButtonEvent(Sensor source, int id, boolean pressed){ + this.source = source; + this.id = id; + this.pressed = pressed; + } + + public Sensor getSource(){ + return source; + } + + public int getButtonID(){ + return id; + } + + public boolean isPressed(){ + return pressed; + } + + public boolean isReleased(){ + return !pressed; + } + +} diff --git a/src/event/ButtonListener.java b/src/event/ButtonListener.java new file mode 100644 index 0000000..63eafb1 --- /dev/null +++ b/src/event/ButtonListener.java @@ -0,0 +1,18 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package event; + + +/** + * + * @author anand + */ +public interface ButtonListener { + + public void buttonPressed(ButtonEvent e); + + public void buttonReleased(ButtonEvent e); +} diff --git a/src/event/DrivingEvent.java b/src/event/DrivingEvent.java new file mode 100644 index 0000000..7a6a157 --- /dev/null +++ b/src/event/DrivingEvent.java @@ -0,0 +1,38 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import sensor.base.GRTDriverStation; + +/** + * + * @author ajc + */ +public class DrivingEvent { + + public static final int SIDE_LEFT = 0; + public static final int SIDE_RIGHT = 1; + private final GRTDriverStation source; + private final int sideID; + private final double value; + + public DrivingEvent(GRTDriverStation source, int sideID, double value) { + this.source = source; + this.sideID = sideID; + this.value = value; + } + + public int getSide() { + return sideID; + } + + public double getPercentSpeed() { + return value; + } + + public GRTDriverStation getSource() { + return source; + } +} diff --git a/src/event/DrivingListener.java b/src/event/DrivingListener.java new file mode 100644 index 0000000..b392773 --- /dev/null +++ b/src/event/DrivingListener.java @@ -0,0 +1,25 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * A high level interface for robot driving + * @author ajc + */ +public interface DrivingListener { + + /** + * Called to set speed of left drivetrain + * @param e + */ + public void driverLeftSpeed(DrivingEvent e); + + /** + * Called to set speed of right drivetrain + * @param e + */ + public void driverRightSpeed(DrivingEvent e); + +} diff --git a/src/event/DrivingProfileEvent.java b/src/event/DrivingProfileEvent.java new file mode 100644 index 0000000..fb4b79f --- /dev/null +++ b/src/event/DrivingProfileEvent.java @@ -0,0 +1,32 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import sensor.base.GRTDriverStation; +import sensor.base.IDriverProfile; + +/** + * + * @author ajc + */ +public class DrivingProfileEvent { + + private final GRTDriverStation source; + private final IDriverProfile profile; + + public DrivingProfileEvent(GRTDriverStation source, IDriverProfile profile) { + this.source = source; + this.profile = profile; + + } + + public IDriverProfile getProfile() { + return profile; + } + + public GRTDriverStation getSource() { + return source; + } +} diff --git a/src/event/DrivingProfileListener.java b/src/event/DrivingProfileListener.java new file mode 100644 index 0000000..3e7e1a6 --- /dev/null +++ b/src/event/DrivingProfileListener.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author ajc + */ +public interface DrivingProfileListener { + + public void drivingProfileChanged(DrivingProfileEvent e); +} diff --git a/src/event/EncoderEvent.java b/src/event/EncoderEvent.java new file mode 100644 index 0000000..a144079 --- /dev/null +++ b/src/event/EncoderEvent.java @@ -0,0 +1,23 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import sensor.GRTEncoder; + +/** + * + * @author gerberduffy + */ +public class EncoderEvent { + + public static final int ROTATION_STARTED = 0; + public static final int ROTATION_STOPPED = 1; + public static final int DEGREE_CHANGE = 2; + + public EncoderEvent(GRTEncoder source){ + + } + +} diff --git a/src/event/EncoderListener.java b/src/event/EncoderListener.java new file mode 100644 index 0000000..20d98da --- /dev/null +++ b/src/event/EncoderListener.java @@ -0,0 +1,19 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author gerberduffy + */ +public interface EncoderListener { + + public void rotationStarted(EncoderEvent e); + + public void degreeChanged(EncoderEvent e); + + public void rotationStopped(EncoderEvent e); + +} diff --git a/src/event/GyroEvent.java b/src/event/GyroEvent.java new file mode 100644 index 0000000..4583ae8 --- /dev/null +++ b/src/event/GyroEvent.java @@ -0,0 +1,29 @@ +/** To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import sensor.GRTGyro; + +/** + * + * @author calvin + */ +public class GyroEvent { + + private GRTGyro source; + private double rotation; + + public GyroEvent(GRTGyro source, double rotation) { + this.source = source; + this.rotation = rotation; + } + + public double getAngle() { + return rotation; + } + + public GRTGyro getSource() { + return source; + } +} diff --git a/src/event/GyroListener.java b/src/event/GyroListener.java new file mode 100644 index 0000000..59bc691 --- /dev/null +++ b/src/event/GyroListener.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author calvin + */ +public interface GyroListener { + + public void angleChanged(GyroEvent e); +} diff --git a/src/event/PotentiometerEvent.java b/src/event/PotentiometerEvent.java new file mode 100644 index 0000000..bb57a7b --- /dev/null +++ b/src/event/PotentiometerEvent.java @@ -0,0 +1,31 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import sensor.Potentiometer; + +/** + * + * @author calvin + */ +public class PotentiometerEvent { + + private Potentiometer source; + private double value; + + public PotentiometerEvent(Potentiometer source, double value) { + this.source = source; + this.value = value; + } + + public double getAngle() { + return value; + } + + public Potentiometer getSource() { + return source; + } + +} diff --git a/src/event/PotentiometerListener.java b/src/event/PotentiometerListener.java new file mode 100644 index 0000000..0c7f49a --- /dev/null +++ b/src/event/PotentiometerListener.java @@ -0,0 +1,13 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author calvin + */ +public interface PotentiometerListener { + public void valueChanged(); +} diff --git a/src/event/RobotTiltEvent.java b/src/event/RobotTiltEvent.java new file mode 100644 index 0000000..4e0f779 --- /dev/null +++ b/src/event/RobotTiltEvent.java @@ -0,0 +1,34 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; +import balancer.RobotTiltGyro; + +/** + * + * @author calvin + */ +public class RobotTiltEvent { + private RobotTiltGyro source; + private int id; + private double tilt; + + public RobotTiltEvent(RobotTiltGyro source, int id, double tilt) { + this.source = source; + this.id = id; + this.tilt = tilt; + } + + public double getTilt() { + return tilt; + } + + public int getId() { + return id; + } + + public RobotTiltGyro getSource() { + return source; + } +} diff --git a/src/event/RobotTiltListener.java b/src/event/RobotTiltListener.java new file mode 100644 index 0000000..c443658 --- /dev/null +++ b/src/event/RobotTiltListener.java @@ -0,0 +1,13 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author calvin + */ +public interface RobotTiltListener { + public void RobotTiltChange(RobotTiltEvent e); +} diff --git a/src/event/SensorChangeListener.java b/src/event/SensorChangeListener.java new file mode 100644 index 0000000..1ae5550 --- /dev/null +++ b/src/event/SensorChangeListener.java @@ -0,0 +1,11 @@ + +package event; + +/** + * + * @author anand, ajc + */ +public interface SensorChangeListener { + + public void sensorStateChanged(SensorEvent e); +} diff --git a/src/event/SensorEvent.java b/src/event/SensorEvent.java new file mode 100644 index 0000000..08563dc --- /dev/null +++ b/src/event/SensorEvent.java @@ -0,0 +1,34 @@ +package event; + +import core.Sensor; +import java.util.Hashtable; + +/** + * + * @author anand, ajc + */ +public class SensorEvent { + + private Sensor source; + private int id; + private double data; + + public SensorEvent(Sensor source, int id, double data) { + this.source = source; + this.id = id; + this.data = data; + } + + public double getData() { + return data; + } + + public int getId() { + return id; + } + + public Sensor getSource() { + return source; + } + +} diff --git a/src/event/SwitchEvent.java b/src/event/SwitchEvent.java new file mode 100644 index 0000000..d00f730 --- /dev/null +++ b/src/event/SwitchEvent.java @@ -0,0 +1,31 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import core.PollingSensor; +import sensor.GRTSwitch; + +/** + * + * @author gerberduffy + */ +public class SwitchEvent { + + private boolean state; + private GRTSwitch sw; + + public SwitchEvent(GRTSwitch sw, double newState){ + state = newState == PollingSensor.TRUE; + this.sw = sw; + } + + public GRTSwitch getSource(){ + return this.sw; + } + + public boolean getState(){ + return this.state; + } +} diff --git a/src/event/SwitchListener.java b/src/event/SwitchListener.java new file mode 100644 index 0000000..3606e1b --- /dev/null +++ b/src/event/SwitchListener.java @@ -0,0 +1,15 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +/** + * + * @author gerberduffy + */ +public interface SwitchListener { + + public void switchStateChanged(event.SwitchEvent e); + +} diff --git a/src/event/XboxJoystickEvent.java b/src/event/XboxJoystickEvent.java new file mode 100644 index 0000000..677bd19 --- /dev/null +++ b/src/event/XboxJoystickEvent.java @@ -0,0 +1,37 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package event; + +import sensor.GRTXBoxJoystick; + +/** + * + * @author student + */ +public class XboxJoystickEvent { + + public static final int DEFAULT = 0; + private GRTXBoxJoystick source; + private int id; + private double value; + + public XboxJoystickEvent(GRTXBoxJoystick source, int id, double value) { + this.source = source; + this.id = id; + this.value = value; + } + + public int getId() { + return id; + } + + public GRTXBoxJoystick getSource() { + return source; + } + + public double getValue() { + return value; + } +} \ No newline at end of file diff --git a/src/event/XboxJoystickListener.java b/src/event/XboxJoystickListener.java new file mode 100644 index 0000000..5483c71 --- /dev/null +++ b/src/event/XboxJoystickListener.java @@ -0,0 +1,23 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package event; + +/** + * + * @author student + */ +public interface XboxJoystickListener { + public void leftXAxisMoved(XboxJoystickEvent e); + public void leftYAxisMoved(XboxJoystickEvent e); + public void leftAngleChanged(XboxJoystickEvent e); + + public void rightXAxisMoved(XboxJoystickEvent e); + public void rightYAxisMoved(XboxJoystickEvent e); + + public void padMoved(XboxJoystickEvent e); + + public void triggerMoved(XboxJoystickEvent e); +} \ No newline at end of file diff --git a/src/mechanism/GRTDriveTrain.java b/src/mechanism/GRTDriveTrain.java new file mode 100644 index 0000000..bef8fd6 --- /dev/null +++ b/src/mechanism/GRTDriveTrain.java @@ -0,0 +1,47 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package mechanism; + +import actuator.IMotor; + +/** + * Standard 4 motor drivetrain. + * @author ajc + */ +public class GRTDriveTrain { + + private final IMotor leftFront; + private final IMotor leftBack; + private final IMotor rightFront; + private final IMotor rightBack; + + /** + * + * @param leftFront left front motor + * @param leftBack left back motor + * @param rightFront right front motor + * @param rightBack right back motor + */ + public GRTDriveTrain(IMotor leftFront, IMotor leftBack, + IMotor rightFront, IMotor rightBack) { + + this.leftFront = leftFront; + this.leftBack = leftBack; + this.rightFront = rightFront; + this.rightBack = rightBack; + } + + /** + * TankDrive uses differential steering. + * @param leftVelocity + * @param rightVelocity + */ + public void tankDrive(double leftVelocity, double rightVelocity) { + leftFront.setSpeed(-leftVelocity); + leftBack.setSpeed(-leftVelocity); + rightFront.setSpeed(-rightVelocity); + rightBack.setSpeed(-rightVelocity); + } +} diff --git a/src/mechanism/GRTRobotBase.java b/src/mechanism/GRTRobotBase.java new file mode 100644 index 0000000..c6c7a72 --- /dev/null +++ b/src/mechanism/GRTRobotBase.java @@ -0,0 +1,35 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package mechanism; + +import sensor.GRTBatterySensor; + +/** + * Encapsulates all components on the robot base. + * + * @author ajc + */ +public class GRTRobotBase { + + private final GRTDriveTrain dt; + private final GRTBatterySensor s; + + public GRTRobotBase(GRTDriveTrain dt, GRTBatterySensor s) { + this.dt = dt; + this.s = s; + } + + public GRTDriveTrain getDriveTrain() { + return dt; + } + + public GRTBatterySensor getBatterySensor(){ + return s; + } + + public void tankDrive(double leftVelocity, double rightVelocity){ + dt.tankDrive(leftVelocity, rightVelocity); + } +} diff --git a/src/networking/GRTClientSocket.java b/src/networking/GRTClientSocket.java new file mode 100644 index 0000000..775c689 --- /dev/null +++ b/src/networking/GRTClientSocket.java @@ -0,0 +1,156 @@ +package networking; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Vector; + +import javax.microedition.io.Connector; + +import com.sun.squawk.io.BufferedReader; +import javax.microedition.io.SocketConnection; + +public class GRTClientSocket extends Thread implements GRTSocket { + public static final int POLL_TIME = 50; + + private String host; + private int port; + private boolean connected; + + private boolean running; + private Vector socketListeners; + private SocketConnection connection; + private BufferedReader in; + private OutputStreamWriter out; + private String lastData; + + public GRTClientSocket(String host, int port) { + this.host = host; + this.port = port; + running = connected = false; + socketListeners = new Vector(); + try { + connection = ((SocketConnection) (Connector.open("socket://" + host + + ":" + port))); + } catch (IOException e) { + e.printStackTrace(); + connection = null; + } + } + + public void run() { + running = true; + while (running) { + poll(); + try { + Thread.sleep(POLL_TIME); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public synchronized void sendData(String data) { + if (connected) { + try { + out.write(data); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + protected void poll() { + if (!connected) { + connect(); + } + try { + String latest = in.readLine(); + if (latest != null && !latest.equals("")){ + lastData = latest; + notifyListeners(); + } + } catch (Exception e) { + e.printStackTrace(); + disconnect(); + } + } + + public void connect() { + try { + in = new BufferedReader(new InputStreamReader(connection + .openInputStream())); + out = new OutputStreamWriter(connection.openOutputStream()); + connected = true; + notifyConnected(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + public boolean isConnected() { + return connected; + } + + public void stop() { + disconnect(); + this.running = false; + } + + public void disconnect() { + if (connected) { + try { + connected = false; + in.close(); + out.close(); + notifyDisconnected(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public String getLastData() { + return lastData; + } + + private void notifyListeners() { + for (int i = 0; i < socketListeners.size(); i++) { + ((SocketListener) socketListeners.elementAt(i)) + .dataRecieved(new SocketEvent(this, SocketEvent.ON_DATA, + lastData)); + } + } + + private void notifyConnected() { + for (int i = 0; i < socketListeners.size(); i++) { + ((SocketListener) socketListeners.elementAt(i)) + .dataRecieved(new SocketEvent(this, SocketEvent.ON_CONNECT, + null)); + } + } + + private void notifyDisconnected() { + for (int i = 0; i < socketListeners.size(); i++) { + ((SocketListener) socketListeners.elementAt(i)) + .dataRecieved(new SocketEvent(this, SocketEvent.ON_DISCONNECT, + null)); + } + } + + public void addSocketListener(SocketListener s) { + socketListeners.addElement(s); + } + + public void removeSocketListener(SocketListener s) { + socketListeners.removeElement(s); + } +} diff --git a/src/networking/GRTServer.java b/src/networking/GRTServer.java new file mode 100644 index 0000000..b5da4eb --- /dev/null +++ b/src/networking/GRTServer.java @@ -0,0 +1,226 @@ +package networking; + +import com.sun.squawk.io.BufferedReader; +//import com.sun.squawk.microedition.io.ServerSocketConnection; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Vector; +import javax.microedition.io.Connector; +import javax.microedition.io.ServerSocketConnection; +import javax.microedition.io.StreamConnection; + +/** + * A event driven daemon which makes multiple single client connections + * @author data, ajc + */ +public class GRTServer extends Thread implements GRTSocket { + + /** + * A single client connection to the server. + */ + private class GRTSingleConnect extends Thread implements GRTSocket { + + private StreamConnection client; + private OutputStreamWriter osw; + private BufferedReader in; +// private DataInputStream in; + InputStreamReader isr; + private OutputStreamWriter out; + private boolean running; + private boolean connected = true; + Vector serverSocketListeners; + + public GRTSingleConnect(StreamConnection client) { + try { + this.client = client; +// GRTRobot.getInstance().getLogger().write("GRTServer", client.toString()); + serverSocketListeners = new Vector(); +// isr = new InputStreamReader(client.openInputStream()); +// isr.read + in = new BufferedReader(new InputStreamReader(client.openInputStream()),1); + +// client.openDataInputStream().readUT +// in = client.openDataInputStream(); + out = new OutputStreamWriter(client.openOutputStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void run() { + running = true; + while (running) { + try { +// System.out.println("Waiting for input..."); + String text = in.readLine(); +// String text = in.readUTF(); + notifyMyListeners(text); + } catch (Exception e) { + this.disconnect(); + e.printStackTrace(); + } + + } + } + + public void stop() { + running = false; + } + + public void sendData(String data) { + try { + out.write(data + "\n"); + } catch (IOException e) { + //GRTRobot.getInstance().getLogger().write("GRTServer", "disconnected from client"); + this.disconnect(); + } catch (Exception e) { + e.printStackTrace(); + + } + + } + + public boolean isConnected() { + return connected; + } + + public void connect() { + connected = true; + } + + public void disconnect() { + try { + in.close(); + out.close(); + client.close(); + clients.removeElement(this); + running = false; + notifyMyDisconnect(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void addSocketListener(SocketListener s) { + serverSocketListeners.addElement(s); + } + + public void removeSocketListener(SocketListener s) { + serverSocketListeners.removeElement(s); + } + + private void notifyMyListeners(String text) { + if (text == null) { + return; + } + for (int i = 0; i < serverSocketListeners.size(); i++) { + SocketListener s = (SocketListener) serverSocketListeners.elementAt(i); + s.dataRecieved(new SocketEvent(this, SocketEvent.ON_DATA, text)); + } + notifyListeners(text, this); + } + + private void notifyMyDisconnect() { + for (int i = 0; i < serverSocketListeners.size(); i++) { + SocketListener s = (SocketListener) serverSocketListeners.elementAt(i); + s.onDisconnect(new SocketEvent(this, SocketEvent.ON_DISCONNECT, null)); + } + notifyDisconnect(this); + } + } + + public GRTServer(int port) { + server = null; + while (server == null) { + try { +// Connector. + server = (ServerSocketConnection) Connector.open("socket://:" + port); + } catch (IOException e) { + e.printStackTrace(); + System.out.println("Failed to open socket!!!!!!!!"); + server = null; + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + + serverSocketListeners = new Vector(); + clients = new Vector(); + + } + private ServerSocketConnection server; + private Vector clients; + private boolean running; + private Vector serverSocketListeners; + + public void sendData(String data) { + for (int i = 0; i < clients.size(); i++) { + GRTSingleConnect c = (GRTSingleConnect) clients.elementAt(i); + c.sendData(data); + } + } + + public boolean isConnected() { + return clients.size() > 0; + } + + public void connect() { + try { + StreamConnection client = server.acceptAndOpen(); + GRTSingleConnect c = new GRTSingleConnect(client); + c.start(); + clients.addElement(c); + notifyConnect(c); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public void run() { + running = true; + while (running) { + connect(); + } + } + + public void disconnect() { + for (int i = 0; i < clients.size(); i++) { + ((GRTSingleConnect) clients.elementAt(i)).stop(); + } + } + + public void addSocketListener(SocketListener s) { + serverSocketListeners.addElement(s); + } + + public void removeSocketListener(SocketListener s) { + serverSocketListeners.removeElement(s); + } + + private void notifyListeners(String text, GRTSocket source) { + for (int i = 0; i < serverSocketListeners.size(); i++) { + SocketListener s = (SocketListener) serverSocketListeners.elementAt(i); + s.dataRecieved(new SocketEvent(source, SocketEvent.ON_DATA, text)); + } + } + + private void notifyDisconnect(GRTSocket source) { + for (int i = 0; i < serverSocketListeners.size(); i++) { + SocketListener s = (SocketListener) serverSocketListeners.elementAt(i); + s.onDisconnect(new SocketEvent(source, SocketEvent.ON_DISCONNECT, null)); + } + } + + private void notifyConnect(GRTSocket source) { + for (int i = 0; i < serverSocketListeners.size(); i++) { + SocketListener s = (SocketListener) serverSocketListeners.elementAt(i); + s.onConnect(new SocketEvent(source, SocketEvent.ON_CONNECT, null)); + } + } +} diff --git a/src/networking/GRTSingleClientServer.java b/src/networking/GRTSingleClientServer.java new file mode 100644 index 0000000..28f519e --- /dev/null +++ b/src/networking/GRTSingleClientServer.java @@ -0,0 +1,149 @@ +package networking; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Vector; + +import javax.microedition.io.Connector; +import javax.microedition.io.StreamConnection; + +import com.sun.squawk.io.BufferedReader; +import javax.microedition.io.ServerSocketConnection; + +public class GRTSingleClientServer extends Thread implements GRTSocket { + public static final int POLL_TIME = 50; + + private ServerSocketConnection server; + private StreamConnection client; + private BufferedReader in; + private OutputStreamWriter out; + private boolean connected; + private Vector serverSocketListeners; + private String lastData; + + private boolean running; + + public GRTSingleClientServer(int port) { + try { + server = (ServerSocketConnection) Connector.open("socket://:" + + port); + } catch (IOException e) { + e.printStackTrace(); + server = null; + } + connected = false; + serverSocketListeners = new Vector(); + running = false; + } + + public void run() { + running = true; + while (running) { + poll(); + } + } + + public synchronized void sendData(String data) { + if (connected) { + try { + out.write(data+"\n"); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void connect() { + try { + client = server.acceptAndOpen(); + in = new BufferedReader(new InputStreamReader(client + .openInputStream())); + out = new OutputStreamWriter(client.openOutputStream()); + connected = true; + notifyConnected(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + protected void poll() { + if (!connected) { + connect(); + } + try { + String latest = in.readLine(); + if (latest != null && !latest.equals("")){ + lastData = latest; + notifyListeners(); + } + } catch (Exception e) { + e.printStackTrace(); + disconnect(); + } + } + + private void notifyListeners() { + for (int i = 0; i < serverSocketListeners.size(); i++) { + ((SocketListener) serverSocketListeners.elementAt(i)) + .dataRecieved(new SocketEvent(this, SocketEvent.ON_DATA, + lastData)); + } + } + + private void notifyConnected() { + for (int i = 0; i < serverSocketListeners.size(); i++) { + ((SocketListener) serverSocketListeners.elementAt(i)) + .dataRecieved(new SocketEvent(this, SocketEvent.ON_CONNECT, + null)); + } + } + + private void notifyDisconnected() { + for (int i = 0; i < serverSocketListeners.size(); i++) { + ((SocketListener) serverSocketListeners.elementAt(i)) + .dataRecieved(new SocketEvent(this, SocketEvent.ON_DISCONNECT, + null)); + } + } + + public boolean isConnected() { + return connected; + } + + public String getLastData() { + return lastData; + } + + public boolean isRunning() { + return running; + } + + public void stop() { + disconnect(); + this.running = false; + } + + public void disconnect() { + if (connected) { + try { + connected = false; + in.close(); + out.close(); + client.close(); + notifyDisconnected(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void addSocketListener(SocketListener s) { + serverSocketListeners.addElement(s); + } + + public void removeSocketListener(SocketListener s) { + serverSocketListeners.removeElement(s); + } + +} diff --git a/src/networking/GRTSocket.java b/src/networking/GRTSocket.java new file mode 100644 index 0000000..6334d0e --- /dev/null +++ b/src/networking/GRTSocket.java @@ -0,0 +1,15 @@ +package networking; + +public interface GRTSocket { + public void sendData(String data); + + public boolean isConnected(); + + public void connect(); + + public void disconnect(); + + public void addSocketListener(SocketListener s); + + public void removeSocketListener(SocketListener s); +} diff --git a/src/networking/SocketEvent.java b/src/networking/SocketEvent.java new file mode 100644 index 0000000..fa8b7e6 --- /dev/null +++ b/src/networking/SocketEvent.java @@ -0,0 +1,28 @@ +package networking; + +public class SocketEvent { + public static final int ON_DATA = 0; + public static final int ON_CONNECT = 1; + public static final int ON_DISCONNECT = 2; + private GRTSocket source; + private int id; + private String data; + + public SocketEvent(GRTSocket source, int id, String data) { + super(); + this.source = source; + this.id = id; + this.data = data; + } + public GRTSocket getSource() { + return source; + } + public int getId() { + return id; + } + public String getData() { + return data; + } + + +} diff --git a/src/networking/SocketListener.java b/src/networking/SocketListener.java new file mode 100644 index 0000000..d8f7206 --- /dev/null +++ b/src/networking/SocketListener.java @@ -0,0 +1,8 @@ +package networking; + +public interface SocketListener { + + public void onConnect(SocketEvent e); + public void onDisconnect(SocketEvent e); + public void dataRecieved(SocketEvent e); +} diff --git a/src/rpc/RPCConnection.java b/src/rpc/RPCConnection.java new file mode 100644 index 0000000..ce429b7 --- /dev/null +++ b/src/rpc/RPCConnection.java @@ -0,0 +1,11 @@ +package rpc; + +public interface RPCConnection { + + public void send(RPCMessage message); + + public void addMessageListener(RPCMessageListener l); + + public void removeMessageListener(RPCMessageListener l); + +} diff --git a/src/rpc/RPCMessage.java b/src/rpc/RPCMessage.java new file mode 100644 index 0000000..2f1f1ad --- /dev/null +++ b/src/rpc/RPCMessage.java @@ -0,0 +1,25 @@ +package rpc; + +public class RPCMessage { + + private final int key; + private final double data; + + public RPCMessage(int key, double data) { + this.key = key; + this.data = data; + } + + public int getKey() { + return key; + } + + public double getData() { + return data; + } + + public String toString() { + return "RPCMessage:" + key + ":" + data; + } + +} diff --git a/src/rpc/RPCMessageListener.java b/src/rpc/RPCMessageListener.java new file mode 100644 index 0000000..6540d21 --- /dev/null +++ b/src/rpc/RPCMessageListener.java @@ -0,0 +1,11 @@ +package rpc; + +/** + * + * @author ajc + * + */ +public interface RPCMessageListener { + + public void messageReceived(RPCMessage message); +} diff --git a/src/rpc/connection/NetworkRPC.java b/src/rpc/connection/NetworkRPC.java new file mode 100644 index 0000000..f6eeba2 --- /dev/null +++ b/src/rpc/connection/NetworkRPC.java @@ -0,0 +1,101 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package rpc.connection; + +import networking.GRTServer; +import networking.SocketEvent; +import networking.SocketListener; +import java.util.Enumeration; +import java.util.Vector; +import rpc.RPCConnection; +import rpc.RPCMessage; +import rpc.RPCMessageListener; + +/** + * NetworkRPC provides an Internet RPC connection. It currently receives + * messages from any connecting host, and sends messages to all connected hosts + * + * @author ajc + */ +public class NetworkRPC implements RPCConnection, SocketListener { + + private GRTServer connection; + private Vector listeners = new Vector(); + + /** + * Opens a new Network RPC connection and starts it. + * @param port + */ + public NetworkRPC(int port) { + connection = new GRTServer(port); + start(); + } + + + private void start(){ + connection.addSocketListener(this); + connection.start(); + } + + //TODO enable sending to a single host + public void send(RPCMessage message) { + connection.sendData(encode(message)); + } + + public void addMessageListener(RPCMessageListener l) { + listeners.addElement(l); + } + + public void removeMessageListener(RPCMessageListener l) { + listeners.removeElement(l); + } + + private void notifyListeners(String received) { + if (isTelemetryLine(received)) { + // RPCMessage message = new RPCMessage(getKey(received), + // getData(received)); + RPCMessage message = decode(received); +// System.out.println(message); + // TODO only notify specific 'keyed' listeners + for (Enumeration e = listeners.elements(); e.hasMoreElements();) { + ((RPCMessageListener) e.nextElement()).messageReceived(message); + } + + } + } + + private static String encode(RPCMessage m) { + // newline to flush all buffers + return ("USB" + m.getKey() + ":" + m.getData() + "\n"); + } + + private static RPCMessage decode(String received) { + return new RPCMessage(getKey(received), getData(received)); + } + + private static boolean isTelemetryLine(String line) { + return line.length() > 3 && line.substring(0, 3).equals("USB");// TODO + // MAGICNUMBERS + } + + private static int getKey(String line) { + return Integer.parseInt(line.substring(3, line.indexOf(':'))); + } + + private static double getData(String line) { + return Double.parseDouble((line.substring(line.indexOf(':') + 1))); + } + + public void onConnect(SocketEvent e) { //TODO + } + + public void onDisconnect(SocketEvent e) { //TODO + } + + public void dataRecieved(SocketEvent e) { +// System.out.println("Data received: " + e.getData()); + notifyListeners(e.getData()); + } +} diff --git a/src/rpc/connection/StreamedRPC.java b/src/rpc/connection/StreamedRPC.java new file mode 100644 index 0000000..fffe211 --- /dev/null +++ b/src/rpc/connection/StreamedRPC.java @@ -0,0 +1,122 @@ +package rpc.connection; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Vector; + +import rpc.RPCConnection; +import rpc.RPCMessage; +import rpc.RPCMessageListener; + +/** + * Reads lines from an input stream + * + * @author ajc + * + */ +public class StreamedRPC extends Thread implements RPCConnection { + + private static final int MAX_STRING_LENGTH = 1024; + // stores byteform of string until newline + private byte[] buffer = new byte[MAX_STRING_LENGTH]; + private final InputStream in; + private final OutputStream out; + private boolean running; // TODO grtobject type thing + private Vector listeners = new Vector(); + + public StreamedRPC(InputStream in, OutputStream out) { + this.in = in; + this.out = out; + } + + public void run() { + running = true; + while (running) { + poll(); + try { + Thread.sleep(1);// TODO sleeping + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + private void poll() { + int data; + try { + int len = 0; + while ((data = in.read()) > -1) { + if (data == '\n') { + break; + } + buffer[len++] = (byte) data; + } + // System.out.println("READ:\t" + new String(buffer, 0, len));// + // TODO + // selected + // debug: + // prints + notifyListeners(new String(buffer, 0, len)); + } catch (IOException e) { + e.printStackTrace(); + System.exit(-1); + } + } + + private static boolean isTelemetryLine(String line) { + return line.length() > 3 && line.substring(0, 3).equals("USB");// TODO + // MAGICNUMBERS + } + + private static int getKey(String line) { + return Integer.parseInt(line.substring(3, line.indexOf(':'))); + } + + private static double getData(String line) { + return Double.parseDouble((line.substring(line.indexOf(':') + 1))); + } + + public void addMessageListener(RPCMessageListener listener) { + listeners.addElement(listener); + } + + public void removeMessageListener(RPCMessageListener listener) { + listeners.removeElement(listener); + } + + private void notifyListeners(String received) { + if (isTelemetryLine(received)) { + // RPCMessage message = new RPCMessage(getKey(received), + // getData(received)); + RPCMessage message = decode(received); + // System.out.println(message); + // TODO only notify specific 'keyed' listeners + for (Enumeration e = listeners.elements(); e.hasMoreElements();) { + ((RPCMessageListener) e.nextElement()).messageReceived(message); + } + + } + } + + public void send(RPCMessage message) { + try { + out.write(encode(message)); + out.flush(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private static byte[] encode(RPCMessage m) { + // newline to flush all buffers + return ("USB" + m.getKey() + ":" + m.getData() + "\n").getBytes(); + } + + private static RPCMessage decode(String received) { + return new RPCMessage(getKey(received), getData(received)); + } +} diff --git a/src/rpc/telemetry/SensorLogger.java b/src/rpc/telemetry/SensorLogger.java new file mode 100644 index 0000000..a555625 --- /dev/null +++ b/src/rpc/telemetry/SensorLogger.java @@ -0,0 +1,49 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package rpc.telemetry; + +import core.EventController; +import core.Sensor; +import event.SensorChangeListener; +import event.SensorEvent; +import rpc.RPCConnection; +import rpc.RPCMessage; + +/** + * Automatically sends all data from any sensor. + * @author ajc + */ +public class SensorLogger extends EventController implements SensorChangeListener { + + private final Sensor s; + private final RPCConnection conn; + private final int[] rpcKeys; + + /** + * + * @param s sensor to read from + * @param conn connection to send data with + * @param rpcKeys rpc keys to send data with for each index of sensor + * @param name name of process + */ + public SensorLogger(Sensor s, RPCConnection conn, int[] rpcKeys, String name) { + super(name); + this.s = s; + this.conn = conn; + this.rpcKeys = rpcKeys; + } + + protected void startListening() { + s.addSensorStateChangeListener(this); + } + + protected void stopListening() { + s.removeSensorStateChangeListener(this); + } + + public void sensorStateChanged(SensorEvent e) { + conn.send(new RPCMessage(rpcKeys[e.getId()], e.getData())); + } +} diff --git a/src/sensor/ADXL345DigitalAccelerometer.java b/src/sensor/ADXL345DigitalAccelerometer.java new file mode 100644 index 0000000..e9f68b7 --- /dev/null +++ b/src/sensor/ADXL345DigitalAccelerometer.java @@ -0,0 +1,175 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2008. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package sensor; + +import edu.wpi.first.wpilibj.DigitalModule; +import edu.wpi.first.wpilibj.I2C; +import edu.wpi.first.wpilibj.SensorBase; + + + +/** + * + * digital accelerometer from the 2010 KOP + * + * this implementation just gets the 3 axis values and allows setting the range + * + * Possible enhancements: + * Add access to other features of the chip + * Add measurement of error during intialization and set channel offsets + */ +public class ADXL345DigitalAccelerometer extends SensorBase { + private I2C i2c; + // default address + private static final byte kAddress = 0x3A; + // register map from datasheet + private static final byte OFSX = 0x1E; + private static final byte OFSY = 0x1F; + private static final byte OFSZ = 0x20; + private static final byte BW_RATE = 0x2C; + private static final byte POWER_CTL = 0x2D; + private static final byte DATA_FORMAT = 0x31; + private static final byte DATAX0 = 0x32; + private static final byte DATAY0 = 0x34; + private static final byte DATAZ0 = 0x36; + private static final byte FIFO_CTL = 0x38; + private static final byte FIFO_STATUS = 0x39; + + + + + // would use enums here if we had them + // BW_RATE 0x2C + private static final byte BW_RATE_R3200B1600 = 0x0F; + private static final byte BW_RATE_R1600B0800 = 0x0E; + private static final byte BW_RATE_R0800B0400 = 0x0D; + private static final byte BW_RATE_R0400B0200 = 0x0C; + private static final byte BW_RATE_R0200B0100 = 0x0B; + private static final byte BW_RATE_R0100B0050 = 0x0A; + private static final byte BW_RATE_R0050B0025 = 0x09; + private static final byte BW_RATE_R0025B0012 = 0x08; + private static final byte BW_RATE_R0012B0006 = 0x07; + private static final byte BW_RATE_R0006B0003 = 0x06; + + private static final byte BW_RATE_LOW_POWER = 0x10; + + // POWER_CTL 0x2D + private static final byte POWER_CTL_LINK = 0x20; + private static final byte POWER_CTL_AUTO_SLEEP = 0x10; + private static final byte POWER_CTL_MEASURE = 0x08; + private static final byte POWER_CTL_SLEEP = 0x04; + private static final byte POWER_CTL_WAKEUP8 = 0x00; + private static final byte POWER_CTL_WAKEUP4 = 0x01; + private static final byte POWER_CTL_WAKEUP2 = 0x02; + private static final byte POWER_CTL_WAKEUP1 = 0x03; + + // DATA_FORMAT + public static final byte DATA_FORMAT_02G = 0x00; + public static final byte DATA_FORMAT_04G = 0x01; + public static final byte DATA_FORMAT_08G = 0x02; + public static final byte DATA_FORMAT_16G = 0x03; + + // store the current + private byte range = DATA_FORMAT_02G; + + public class ADXL345Exception extends RuntimeException { + + /** + * Create a new exception with the given message + * @param message the message to pass with the exception + */ + public ADXL345Exception(String message) { + super(message); + } + + } + + // + // constuctior with slot number parameter + // + public ADXL345DigitalAccelerometer(int slot) { + + i2c = new I2C( DigitalModule.getInstance(1), kAddress ); + } + + // initialize the sensor + public void initialize() + { + // set BW_RATE + i2c.write(BW_RATE, BW_RATE_R0100B0050); + // set POWER_CTL + i2c.write(POWER_CTL, POWER_CTL_MEASURE); + } + + // set he range (default is =/- 2g + public void setRange( byte rangeParam ) + { + if ( !( rangeParam == DATA_FORMAT_02G || + rangeParam == DATA_FORMAT_04G || + rangeParam == DATA_FORMAT_08G || + rangeParam == DATA_FORMAT_16G ) ) + { + throw new ADXL345Exception("Invalid range!"); + } + + + range = rangeParam; + + i2c.write(DATA_FORMAT, range); + } + + // get acceleration routines + public double getXAxis() + { + return getAxis( DATAX0 ); + } + + public double getYAxis() + { + return getAxis( DATAY0 ); + } + + public double getZAxis() + { + return getAxis( DATAZ0 ); + } + + protected double getAxis( byte registerParam ) + { + // setup array for our data + byte[] data = new byte[2]; + // read consecutive registers + this.i2c.read( registerParam, (byte) data.length, data); + + // convert to 2s complement integer + // [0] has low byte [1] has the high byte + // jave does not have unsigned so we have to do it this way + int intResult = ( data[0] & 0xFF ) | ( data[1] << 8 ); + + // convert to double based on 10 bit result + double returnValue = (double)intResult / 512.0 ; + + // now scale based upon our range + switch( range ) + { + case DATA_FORMAT_02G: + returnValue *= 2.0; + break; + case DATA_FORMAT_04G: + returnValue *= 4.0; + break; + case DATA_FORMAT_08G: + returnValue *= 8.0; + break; + case DATA_FORMAT_16G: + returnValue *= 16.0; + break; + } + return returnValue; + } +} diff --git a/src/sensor/GRTADXL345.java b/src/sensor/GRTADXL345.java new file mode 100644 index 0000000..04e5513 --- /dev/null +++ b/src/sensor/GRTADXL345.java @@ -0,0 +1,78 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import core.PollingSensor; +import edu.wpi.first.wpilibj.ADXL345_I2C; +import event.ADXL345Event; +import event.ADXL345Listener; +import java.util.Vector; +/** + * + * @author gerberduffy + */ +public class GRTADXL345 extends PollingSensor{ + + private ADXL345_I2C i2c; + + private static final int X_AXIS = 0; + private static final int Y_AXIS = 1; + private static final int Z_AXIS = 2; + private static final int NUM_DATA = 3; + + + + private Vector listeners; + + private ADXL345_I2C.AllAxes accelerations; + + public GRTADXL345(int slot, int pollTime, String id){ + super (id, pollTime, NUM_DATA); + i2c = new ADXL345_I2C(slot, ADXL345_I2C.DataFormat_Range.k2G); + + listeners = new Vector(); + } + + protected void poll() { + setState(X_AXIS, i2c.getAcceleration(ADXL345_I2C.Axes.kX)); + setState(Y_AXIS, i2c.getAcceleration(ADXL345_I2C.Axes.kY)); + setState(Z_AXIS, i2c.getAcceleration(ADXL345_I2C.Axes.kZ)); + + System.out.println("ADXL345:\t" + getState(X_AXIS) + "\t" + getState(Y_AXIS) + "\t" + getState(Z_AXIS)); + } + + public void addADXL345Listener(ADXL345Listener l){ + listeners.addElement(l); + } + + public void removeADXL345Listener(ADXL345Listener l){ + listeners.removeElement(l); + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + ADXL345Event e = new ADXL345Event(this, id, newDatum); + + switch (id){ + case X_AXIS: { + for (int i=0; i < listeners.size(); i++){ + ((ADXL345Listener)listeners.elementAt(i)).XAccelChange(e); + } + } + + case Y_AXIS: { + for (int i=0; i < listeners.size(); i++){ + ((ADXL345Listener)listeners.elementAt(i)).YAccelChange(e); + } + } + + case Z_AXIS: { + for (int i=0; i < listeners.size(); i++){ + ((ADXL345Listener)listeners.elementAt(i)).ZAccelChange(e); + } + } + } + } + +} diff --git a/src/sensor/GRTAttack3Joystick.java b/src/sensor/GRTAttack3Joystick.java new file mode 100644 index 0000000..b9c4760 --- /dev/null +++ b/src/sensor/GRTAttack3Joystick.java @@ -0,0 +1,107 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import core.PollingSensor; +import edu.wpi.first.wpilibj.Joystick; +import event.*; +import java.util.Vector; + +/** + * + * @author dan + */ +public class GRTAttack3Joystick extends PollingSensor { + private final Vector joystickListeners; + private final Vector buttonListeners; + private final Joystick joystick; + public static final int KEY_BUTTON_0 = 0; + public static final int KEY_BUTTON_1 = 1; + public static final int KEY_BUTTON_2 = 2; + public static final int KEY_BUTTON_3 = 3; + public static final int KEY_BUTTON_4 = 4; + public static final int KEY_BUTTON_5 = 5; + public static final int KEY_BUTTON_6 = 6; + public static final int KEY_BUTTON_7 = 7; + public static final int KEY_BUTTON_8 = 8; + public static final int KEY_BUTTON_9 = 9; + public static final int KEY_X = 10; + public static final int KEY_Y = 11; + public static final int KEY_JOYSTICK_ANGLE = 12; + private final static int NUM_OF_BUTTONS=10; + private final static int NUM_DATA=13; + public static final double PRESSED = TRUE; + public static final double RELEASED = FALSE; + + public GRTAttack3Joystick(int channel, int pollTime, String name){ + super(name, pollTime, NUM_DATA); + joystick = new Joystick(channel); + joystickListeners = new Vector(); + buttonListeners = new Vector(); + + } + + protected void poll() { + for (int i = 0; i < NUM_OF_BUTTONS; ++i){ + setState(i, joystick.getRawButton(i)?PRESSED:RELEASED); + } + setState(KEY_X, joystick.getX()); + setState(KEY_Y, joystick.getY()); + setState(KEY_JOYSTICK_ANGLE, joystick.getDirectionRadians()); + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + if (id < NUM_OF_BUTTONS) { + //ID maps directly to button ID + ButtonEvent e = new ButtonEvent(this, id, newDatum == PRESSED); + if (newDatum == PRESSED) { //true + for (int i = 0; i < buttonListeners.size(); i++) { + ((ButtonListener) buttonListeners.elementAt(i)).buttonPressed(e); + } + } else { + for (int i = 0; i < buttonListeners.size(); i++) { + ((ButtonListener) buttonListeners.elementAt(i)).buttonReleased(e); + } + } + + } else { //we are now a joystick + //only reach here if not a button + Attack3JoystickEvent e = new Attack3JoystickEvent(this, id, newDatum); + switch (id){ + case (KEY_X): + for (int i = 0; i < joystickListeners.size(); i++) { + ((Attack3JoystickListener)joystickListeners.elementAt(i)).XAxisMoved(e); + } + break; + case (KEY_Y): + for (int i = 0; i < joystickListeners.size(); i++) { + ((Attack3JoystickListener)joystickListeners.elementAt(i)).YAxisMoved(e); + } + break; + case (KEY_JOYSTICK_ANGLE): + for (int i = 0; i < joystickListeners.size(); i++) { + ((Attack3JoystickListener)joystickListeners.elementAt(i)).AngleChanged(e); + } + break; + } + } + } + public void addButtonListener(ButtonListener b) { + buttonListeners.addElement(b); + } + + public void removeButtonListener(ButtonListener b) { + buttonListeners.removeElement(b); + } + + public void addJoystickListener(Attack3JoystickListener l) { + joystickListeners.addElement(l); + } + + public void removeJoystickListener(Attack3JoystickListener l) { + joystickListeners.removeElement(l); + } + +} diff --git a/src/sensor/GRTBatterySensor.java b/src/sensor/GRTBatterySensor.java new file mode 100644 index 0000000..ed7d327 --- /dev/null +++ b/src/sensor/GRTBatterySensor.java @@ -0,0 +1,50 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import core.PollingSensor; +import edu.wpi.first.wpilibj.DriverStation; +import event.BatteryVoltageEvent; +import event.BatteryVoltageListener; +import java.util.Vector; + +/** + * A battery sensor that retrieves main battery voltage from the analog sidecar + * @author ajc + */ +public class GRTBatterySensor extends PollingSensor { + + public static final int KEY_BATTERY_VOLTAGE = 0; + + private final DriverStation ds; + private final Vector listeners; + + public GRTBatterySensor(int pollTime, String name) { + super(name, pollTime, 1); + ds = DriverStation.getInstance(); + listeners = new Vector(); + } + + protected void poll() { + setState(KEY_BATTERY_VOLTAGE, ds.getBatteryVoltage()); + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + + BatteryVoltageEvent e = new BatteryVoltageEvent(this, newDatum); + + for (int i = 0; i < listeners.size(); i++) { + ((BatteryVoltageListener) listeners.elementAt(i)).batteryVoltageChanged(e); + } + } + + public void addBatteryVoltageListener(BatteryVoltageListener l) { + listeners.addElement(l); + } + + public void removeBatteryVoltageListener(BatteryVoltageListener l) { + listeners.removeElement(l); + } +} diff --git a/src/sensor/GRTEncoder.java b/src/sensor/GRTEncoder.java new file mode 100644 index 0000000..468d569 --- /dev/null +++ b/src/sensor/GRTEncoder.java @@ -0,0 +1,45 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import core.PollingSensor; +import edu.wpi.first.wpilibj.Encoder; +import edu.wpi.first.wpilibj.PIDSource; +/** + * + * @author gerberduffy + */ +public class GRTEncoder extends PollingSensor { + + private Encoder rotaryEncoder; + private double distancePerPulse; + + public static final int DISTANCE = 0; + public static final int DEGREES = 1; + public static final int DIRECTION = 2; + + public static final int NUM_DATA = 3; + + public GRTEncoder(int channelA, int channelB, double pulseDistance, int pollTime, String id){ + super(id, pollTime, NUM_DATA); + rotaryEncoder = new Encoder(channelA, channelB); + rotaryEncoder.start(); + + distancePerPulse = pulseDistance; + } + + + protected void poll() { + setState(DISTANCE, rotaryEncoder.getDistance()); + setState(DEGREES, rotaryEncoder.getDistance()/distancePerPulse); + setState(DIRECTION, rotaryEncoder.getDirection() ? TRUE : FALSE); + + System.out.println(getState(DISTANCE) + "\t" + getState(DEGREES) + "\t" + getState(DIRECTION)); + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + } + +} diff --git a/src/sensor/GRTGyro.java b/src/sensor/GRTGyro.java new file mode 100644 index 0000000..d4661f2 --- /dev/null +++ b/src/sensor/GRTGyro.java @@ -0,0 +1,57 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import core.PollingSensor; +import edu.wpi.first.wpilibj.AnalogModule; +import edu.wpi.first.wpilibj.Gyro; +import java.util.Vector; +import event.GyroEvent; +import event.GyroListener; + +/** + * Provides angular position along a single axis through an analog sensor + * @author calvin + */ +public class GRTGyro extends PollingSensor { + + public static final int KEY_ANGLE = 0; + public static final int NUM_DATA = 1; + private Gyro gyro; + private Vector gyroListeners; + + public GRTGyro(int channel, int pollTime, String name) { + super(name, pollTime, NUM_DATA); + gyro = new Gyro(AnalogModule.getDefaultAnalogModule(), channel); + gyroListeners = new Vector(); + } + + public double getAngle(){ + return gyro.getAngle(); + } + + protected void poll() { + setState(KEY_ANGLE, gyro.getAngle()); + + System.out.println("Gyro: \t" + getState(KEY_ANGLE)); + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + if (id == KEY_ANGLE) { + GyroEvent e = new GyroEvent(this, newDatum); + for (int i = 0; i < gyroListeners.size(); i++) { + ((GyroListener) gyroListeners.elementAt(i)).angleChanged(e); + } + } + } + + public void addListener(GyroListener l) { + gyroListeners.addElement(l); + } + + public void removeListener(GyroListener l) { + gyroListeners.removeElement(l); + } +} diff --git a/src/sensor/GRTSwitch.java b/src/sensor/GRTSwitch.java new file mode 100644 index 0000000..6d9b9f0 --- /dev/null +++ b/src/sensor/GRTSwitch.java @@ -0,0 +1,54 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import core.PollingSensor; +import edu.wpi.first.wpilibj.DigitalInput; +import event.SwitchEvent; +import event.SwitchListener; +import java.util.Vector; + +/** + * + * @author gerberduffy + */ +public class GRTSwitch extends PollingSensor { + + private DigitalInput in; + + private static final int STATE = 0; + private static final int NUM_DATA = 1; + + private Vector listeners; + + public GRTSwitch(int slot, int polltime, String id){ + + super(id, polltime, NUM_DATA); + + in = new DigitalInput(slot); + + listeners = new Vector(); + } + + public boolean isOn(){ + return in.get(); + } + + protected void poll() { + setState(STATE, isOn() ? TRUE : FALSE); + System.out.println(getState(STATE)); + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + + SwitchEvent e = new SwitchEvent(this, newDatum); + + for (int i=0; i < listeners.size(); i++){ + ((SwitchListener)listeners.elementAt(i)).switchStateChanged(e); + } + } + + +} diff --git a/src/sensor/GRTXBoxJoystick.java b/src/sensor/GRTXBoxJoystick.java new file mode 100644 index 0000000..907b291 --- /dev/null +++ b/src/sensor/GRTXBoxJoystick.java @@ -0,0 +1,161 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import core.PollingSensor; +import edu.wpi.first.wpilibj.Joystick; +import event.ButtonEvent; +import event.ButtonListener; +import event.XboxJoystickEvent; +import event.XboxJoystickListener; +import java.util.Vector; + +/** + * + * @author ajc + */ +public class GRTXBoxJoystick extends PollingSensor { + + /** + * Keys of data + */ + public static final int KEY_BUTTON_0 = 0; + public static final int KEY_BUTTON_1 = 1; + public static final int KEY_BUTTON_2 = 2; + public static final int KEY_BUTTON_3 = 3; + public static final int KEY_BUTTON_4 = 4; + public static final int KEY_BUTTON_5 = 5; + public static final int KEY_BUTTON_6 = 6; + public static final int KEY_BUTTON_7 = 7; + public static final int KEY_BUTTON_8 = 8; + public static final int KEY_BUTTON_9 = 9; + public static final int KEY_LEFT_X = 10; + public static final int KEY_LEFT_Y = 11; + public static final int KEY_RIGHT_X = 12; + public static final int KEY_RIGHT_Y = 13; + public static final int KEY_JOYSTICK_ANGLE = 14; + public static final int KEY_TRIGGER = 15; + public static final int KEY_PAD = 16; + + private static final int NUM_DATA = 17; + private static final int NUM_OF_BUTTONS = 10; + + /** + * State definitions + */ + public static final double PRESSED = TRUE; + public static final double RELEASED = FALSE; + + private final Joystick joystick; + private final Vector buttonListeners; + private final Vector joystickListeners; + + public GRTXBoxJoystick(int channel, int pollTime, String name) { + super(name, pollTime, NUM_DATA); + joystick = new Joystick(channel); + + buttonListeners = new Vector(); + joystickListeners = new Vector(); + } + + protected void poll() { + for (int i = 0; i < NUM_OF_BUTTONS; i++) { + //if we measure true, this indicates pressed state + setState(i, joystick.getRawButton(i) ? PRESSED : RELEASED); + } + setState(KEY_LEFT_X, joystick.getX()); + setState(KEY_LEFT_Y, joystick.getY()); + setState(KEY_RIGHT_X, joystick.getRawAxis(4)); + setState(KEY_RIGHT_Y, joystick.getRawAxis(5)); + setState(KEY_JOYSTICK_ANGLE, joystick.getDirectionRadians()); + setState(KEY_TRIGGER, joystick.getZ()); + setState(KEY_PAD, joystick.getRawAxis(6)); + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + if (id < NUM_OF_BUTTONS) { + //ID maps directly to button ID + ButtonEvent e = new ButtonEvent(this, id, newDatum == PRESSED); + if (newDatum == PRESSED) { //true + for (int i = 0; i < buttonListeners.size(); i++) { + ((ButtonListener) buttonListeners.elementAt(i)).buttonPressed(e); + } + } else { + for (int i = 0; i < buttonListeners.size(); i++) { + ((ButtonListener) buttonListeners.elementAt(i)).buttonReleased(e); + } + } + + } else { //we are now a joystick + //only reach here if not a button + XboxJoystickEvent e = new XboxJoystickEvent(this, id, newDatum); + + //call various events based on which datum we are + switch (id) { + case KEY_LEFT_X: { + for (int i = 0; i < joystickListeners.size(); i++) { + ((XboxJoystickListener) joystickListeners.elementAt(i)).leftXAxisMoved(e); + } + + } + case KEY_LEFT_Y: { + for (int i = 0; i < joystickListeners.size(); i++) { + ((XboxJoystickListener) joystickListeners.elementAt(i)).leftYAxisMoved(e); + } + break; + } + case KEY_RIGHT_X: { + for (int i = 0; i < joystickListeners.size(); i++) { + ((XboxJoystickListener) joystickListeners.elementAt(i)).rightXAxisMoved(e); + } + break; + } + case KEY_RIGHT_Y: { + for (int i = 0; i < joystickListeners.size(); i++) { + ((XboxJoystickListener) joystickListeners.elementAt(i)).rightYAxisMoved(e); + } + break; + } + case KEY_JOYSTICK_ANGLE: { + for (int i = 0; i < joystickListeners.size(); i++) { + ((XboxJoystickListener) joystickListeners.elementAt(i)).leftAngleChanged(e); + } + break; + } + case KEY_TRIGGER: { + for (int i = 0; i < joystickListeners.size(); i++) { + ((XboxJoystickListener) joystickListeners.elementAt(i)).triggerMoved(e); + } + break; + } + case KEY_PAD: { + for (int i = 0; i < joystickListeners.size(); i++) { + ((XboxJoystickListener) joystickListeners.elementAt(i)).padMoved(e); + } + break; + } + + } + } + + + } + + public void addButtonListener(ButtonListener b) { + buttonListeners.addElement(b); + } + + public void removeButtonListener(ButtonListener b) { + buttonListeners.removeElement(b); + } + + public void addJoystickListener(XboxJoystickListener l) { + joystickListeners.addElement(l); + } + + public void removeJoystickListener(XboxJoystickListener l) { + joystickListeners.removeElement(l); + } +} diff --git a/src/sensor/Potentiometer.java b/src/sensor/Potentiometer.java new file mode 100644 index 0000000..08dc037 --- /dev/null +++ b/src/sensor/Potentiometer.java @@ -0,0 +1,53 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor; + +import edu.wpi.first.wpilibj.AnalogChannel; +import core.PollingSensor; +import event.PotentiometerEvent; +import event.PotentiometerListener; +import java.util.Vector; + +/** + * + * @author calvin + */ +public class Potentiometer extends PollingSensor{ + public static final int KEY_VALUE = 0; + public static final int NUM_DATA = 1; + + private int potentiometerType; + private AnalogChannel channel; + public static final int LINEAR = 0; + public static final int LOGARITHMIC = 1; + + public Potentiometer(AnalogChannel channel, int type, int pollTime, String name){ + super(name, pollTime, NUM_DATA); + potentiometerType = type; + this.channel = channel; + } + + protected void poll() { + setState(KEY_VALUE, updateScaledValue()); + } + + private double updateScaledValue(){ + double rawValue = channel.getVoltage(); + double scaledValue; + switch(potentiometerType){ + case LINEAR: + scaledValue = rawValue / 5; + break; + default: + scaledValue = rawValue / 5; + System.out.println("log is broken as of right now"); + } + + return scaledValue; + } + + protected void notifyListeners(int id, double oldDatum, double newDatum) { + } +} diff --git a/src/sensor/base/GRTAttack3DriverStation.java b/src/sensor/base/GRTAttack3DriverStation.java new file mode 100644 index 0000000..a1f0ad0 --- /dev/null +++ b/src/sensor/base/GRTAttack3DriverStation.java @@ -0,0 +1,78 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + +import event.Attack3JoystickEvent; +import event.Attack3JoystickListener; +import event.ButtonEvent; +import event.ButtonListener; +import sensor.GRTAttack3Joystick; + +/** + * Driver station using 2 Logitech Attack 3 Joysticks + * @author dan + */ +public class GRTAttack3DriverStation extends GRTDriverStation implements Attack3JoystickListener, ButtonListener{ + private final GRTAttack3Joystick left; + private final GRTAttack3Joystick right; + + public GRTAttack3DriverStation(GRTAttack3Joystick left, GRTAttack3Joystick right, + int[] profileButtons, IDriverProfile[] curves, String name){ + super(profileButtons, curves, name); + this.left= left; + this.right = right; + } + + protected void startListening() { + left.addJoystickListener(this); + left.addButtonListener(this); + right.addJoystickListener(this); + right.addButtonListener(this); + } + + protected void stopListening() { + left.removeJoystickListener(this); + left.removeButtonListener(this); + right.removeJoystickListener(this); + right.removeButtonListener(this); + } + + public void XAxisMoved(Attack3JoystickEvent e) { + } + + public void YAxisMoved(Attack3JoystickEvent e) { + if (e.getSource()==left){ + notifyLeftDriveSpeed(e.getValue()); + notifyStateChange(KEY_LEFT_VELOCITY, e.getValue()); + } + else if (e.getSource() ==right){ + notifyRightDriveSpeed(e.getValue()); + notifyStateChange(KEY_RIGHT_VELOCITY, e.getValue()); + } + } + + public void AngleChanged(Attack3JoystickEvent e) { + } + + public void buttonPressed(ButtonEvent e) { + } + + public void buttonReleased(ButtonEvent e) { + int profileID = getIndex(profileButtons, e.getButtonID()); + if (profileID != -1) {//meaning it exists, see #getIndex(int[], int) + notifyProfileChange(profileID); + notifyStateChange(KEY_PROFILE_ID, profileID); + } + } + private static int getIndex(int[] array, int value) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + return -1; + } + +} diff --git a/src/sensor/base/GRTDriverStation.java b/src/sensor/base/GRTDriverStation.java new file mode 100644 index 0000000..c76f89c --- /dev/null +++ b/src/sensor/base/GRTDriverStation.java @@ -0,0 +1,93 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + +import core.Sensor; +import event.DrivingEvent; +import event.DrivingListener; +import event.DrivingProfileEvent; +import event.DrivingProfileListener; +import java.util.Vector; + +/** + * Superclass for all DriverStations. + * + * Handles driver profiles.s + * @author ajc + */ +public abstract class GRTDriverStation extends Sensor { + + /* + * State Keys + */ + public static final int KEY_LEFT_VELOCITY = 0; + public static final int KEY_RIGHT_VELOCITY = 1; + public static final int KEY_PROFILE_ID = 2; + + //profiles + protected IDriverProfile[] curves; + /* + * maps the profile index to the button that should register it + * so {3 4} means button 3 will register PROFILE_LINEAR, + * while button 4 will register PROFILE_SQUARED. + */ + protected final int[] profileButtons; + //listeners + private final Vector drivingListeners; + private final Vector profileListeners; + + /** + * + * @param profileButtons + * @param curves + * @param name + */ + public GRTDriverStation(int[] profileButtons, IDriverProfile[] curves, String name) { + super(name); + this.profileButtons = profileButtons; + this.curves = curves; + + drivingListeners = new Vector(); + profileListeners = new Vector(); + } + + public void addDrivingListener(DrivingListener l) { + drivingListeners.addElement(l); + } + + public void removeDrivingListener(DrivingListener l) { + drivingListeners.removeElement(l); + } + + public void addDrivingProfileListener(DrivingProfileListener l) { + profileListeners.addElement(l); + } + + public void removeDrivingProfileListener(DrivingProfileListener l) { + profileListeners.removeElement(l); + } + + protected void notifyLeftDriveSpeed(double speed) { + DrivingEvent ev = new DrivingEvent(this, DrivingEvent.SIDE_LEFT, speed); + for (int i = 0; i < drivingListeners.size(); i++) { + ((DrivingListener) drivingListeners.elementAt(i)).driverLeftSpeed(ev); + } + } + + protected void notifyRightDriveSpeed(double speed) { + DrivingEvent ev = new DrivingEvent(this, DrivingEvent.SIDE_RIGHT, speed); + for (int i = 0; i < drivingListeners.size(); i++) { + ((DrivingListener) drivingListeners.elementAt(i)).driverRightSpeed(ev); + } + } + + protected void notifyProfileChange(int profileID) { + DrivingProfileEvent e = new DrivingProfileEvent(this, curves[profileID]); + for (int i = 0; i < profileListeners.size(); i++) { + ((DrivingProfileListener) profileListeners.elementAt(i)).drivingProfileChanged(e); + + } + } +} diff --git a/src/sensor/base/GRTXboxDriverStation.java b/src/sensor/base/GRTXboxDriverStation.java new file mode 100644 index 0000000..d5b3ed8 --- /dev/null +++ b/src/sensor/base/GRTXboxDriverStation.java @@ -0,0 +1,113 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + +import event.ButtonEvent; +import event.ButtonListener; +import event.XboxJoystickEvent; +import event.XboxJoystickListener; +import sensor.GRTXBoxJoystick; + +/** + * Driverstation using XBoxJoysticks + * + * @author ajc + */ +public class GRTXboxDriverStation extends GRTDriverStation implements XboxJoystickListener, ButtonListener { + + private final GRTXBoxJoystick primary; + private final GRTXBoxJoystick secondary; + + /** + * + * @param primary + * @param secondary + * @param profileButtons + * @param curves + * @param name + */ + public GRTXboxDriverStation(GRTXBoxJoystick primary, GRTXBoxJoystick secondary, + int[] profileButtons, IDriverProfile[] curves, String name) { + super(profileButtons, curves, name); + this.primary = primary; + this.secondary = secondary; + + } + + protected void startListening() { + primary.addJoystickListener(this); + primary.addButtonListener(this); + } + + protected void stopListening() { + primary.removeJoystickListener(this); + primary.removeButtonListener(this); + } + + /* + * JOYSTICK EVENTS + */ + public void leftXAxisMoved(XboxJoystickEvent e) { + } + + public void leftYAxisMoved(XboxJoystickEvent e) { + if (e.getSource() == primary) { + notifyLeftDriveSpeed(e.getValue()); + notifyStateChange(KEY_LEFT_VELOCITY, e.getValue()); + } + } + + public void rightXAxisMoved(XboxJoystickEvent e) { + } + + public void rightYAxisMoved(XboxJoystickEvent e) { + if (e.getSource() == primary) { + notifyRightDriveSpeed(e.getValue()); + notifyStateChange(KEY_RIGHT_VELOCITY, e.getValue()); + } + } + + public void padMoved(XboxJoystickEvent e) { + } + + public void triggerMoved(XboxJoystickEvent e) { + } + + /* + * BUTTON EVENTS + */ + public void buttonPressed(ButtonEvent e) { + } + + public void buttonReleased(ButtonEvent e) { + + //we receive the button. + //the button corresponds to an element in the profileButtons list + //we need to find the index from that array that the button ID is + int profileID = getIndex(profileButtons, e.getButtonID()); + if (profileID != -1) {//meaning it exists, see #getIndex(int[], int) + notifyProfileChange(profileID); + notifyStateChange(KEY_PROFILE_ID, profileID); + } + } + + /** + * + * @param array + * @param value + * @return + */ + private static int getIndex(int[] array, int value) { + for (int i = 0; i < array.length; i++) { + if (value == array[i]) { + return i; + } + } + return -1; + } + + public void leftAngleChanged(XboxJoystickEvent e) { + } +} diff --git a/src/sensor/base/IDriverProfile.java b/src/sensor/base/IDriverProfile.java new file mode 100644 index 0000000..173509f --- /dev/null +++ b/src/sensor/base/IDriverProfile.java @@ -0,0 +1,19 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + +/** + * + * @author ajc + */ +public interface IDriverProfile { + + /** + * + * @param joystickTiltPercent an input percent from [-1.0 - 1.0] + * @return an output from [-1.0 - 1.0] + */ + public double driveSpeed(double joystickTiltPercent); +} diff --git a/src/sensor/base/LinearDrive.java b/src/sensor/base/LinearDrive.java new file mode 100644 index 0000000..995cb24 --- /dev/null +++ b/src/sensor/base/LinearDrive.java @@ -0,0 +1,17 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + +/** + * + * @author ajc + */ +public class LinearDrive implements IDriverProfile{ + + public double driveSpeed(double joystickTiltPercent) { + return joystickTiltPercent; + } + +} diff --git a/src/sensor/base/SquareDrive.java b/src/sensor/base/SquareDrive.java new file mode 100644 index 0000000..a33ae77 --- /dev/null +++ b/src/sensor/base/SquareDrive.java @@ -0,0 +1,19 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + +/** + * + * @author ajc + */ +public class SquareDrive implements IDriverProfile { + + public double driveSpeed(double joystickTiltPercent) { + //save the sign: becomes -1 if original was negative, +1 if positive + double sign = joystickTiltPercent > 0 ? +1.0 : -1.0; + //apply sign to square to enable reverse driving + return sign * joystickTiltPercent * joystickTiltPercent; + } +} diff --git a/src/sensor/base/TestSwitch.java b/src/sensor/base/TestSwitch.java new file mode 100644 index 0000000..b3abe42 --- /dev/null +++ b/src/sensor/base/TestSwitch.java @@ -0,0 +1,22 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + +import core.Sensor; + +/** + * + * @author gerberduffy + */ +public class TestSwitch { + + + protected void startListening() { + } + + protected void stopListening() { + } + +} diff --git a/src/sensor/base/VictorDriverProfile.java b/src/sensor/base/VictorDriverProfile.java new file mode 100644 index 0000000..2e9f355 --- /dev/null +++ b/src/sensor/base/VictorDriverProfile.java @@ -0,0 +1,25 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package sensor.base; + + +/** + * + * Driver profile that transaltes joystick values + * specifically calibrated for Victors + * + * @author gerberduffy + */ +public class VictorDriverProfile implements IDriverProfile { + + public double driveSpeed(double joystickTiltPercent) { + //TODO: IMPLEMENT THE HECK OUT OF THIS. + + return 0.0; + } + + + +} diff --git a/suite/Base2012-redesign_1.0.0.jar b/suite/Base2012-redesign_1.0.0.jar new file mode 100644 index 0000000..5c5bbd9 Binary files /dev/null and b/suite/Base2012-redesign_1.0.0.jar differ