diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/RyABI.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/RyABI.java index 9b9c798..6f1c78c 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/RyABI.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/RyABI.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi; import lejos.nxt.Button; @@ -25,6 +38,11 @@ import ve.ucv.ciens.cicore.icaro.ryabi.sensors.FeatureDetectionListener; import ve.ucv.ciens.cicore.icaro.ryabi.sensors.LightFeatureDetector; import ve.ucv.ciens.cicore.icaro.ryabi.utils.QuitButtonListener; +/** + * This class starts the execution of the program. + * + * @author Miguel Angel Astor Romero. + */ @SuppressWarnings("deprecation") public class RyABI { private static final float WHEEL_DIAMETER = 56.0f; @@ -43,6 +61,9 @@ public class RyABI { private static FeatureDetectionListener featureListener; private static FeatureDetectorsHandler detectorHandler; + /** + * Main method of the program. + */ public static void main(String[] args) { boolean invertLightDetector; /* Create the sensors. */ @@ -100,11 +121,17 @@ public class RyABI { arbitrator.start(); } + /** + * Asks the user to select the light feature detection mode. + * + * @return True if the user wants to invert the light detector (report when the robot passes from a dark area to a light area). + */ private static boolean invertLightDetector() { int btnID; boolean invertSensor = false, done = false; while(!done) { + /* Show the prompt on the screen. */ LCD.clear(); System.out.println("Invert l. sens:"); if(invertSensor) @@ -114,17 +141,21 @@ public class RyABI { System.out.println("Press ENTER"); System.out.println("to set."); + /* Wait for any button press. */ btnID = Button.waitForAnyPress(); switch(btnID) { case Button.ID_LEFT: case Button.ID_RIGHT: + /* If the user pressed any direction button then toggle the sensor. */ invertSensor = !invertSensor; break; case Button.ID_ENTER: + /* If the user pressed enter then end the loop. */ done = true; break; default: + /* If the user pressed escape then quit. */ System.exit(1); } } diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/AvoidObstaclesBehavior.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/AvoidObstaclesBehavior.java index 3863f9d..333a980 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/AvoidObstaclesBehavior.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/AvoidObstaclesBehavior.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.behaviors; import lejos.nxt.LightSensor; @@ -11,10 +24,19 @@ import ve.ucv.ciens.cicore.icaro.ryabi.utils.RobotStateSingleton; import ve.ucv.ciens.cicore.icaro.ryabi.utils.Rotations; import ve.ucv.ciens.cicore.icaro.ryabi.utils.States; +/** + * This class implements a {@link BaseBehavior} that attempts to evade obstacles detected by the {@link TouchSensor} by moving + * a bit to the right. + * + * @author Miguel Angel Astor Romero. + */ public class AvoidObstaclesBehavior extends BaseBehavior { private RobotStateSingleton state; private SensorEventsQueue queue; + /** + * Creates a new {@link AvoidObstaclesBehavior}. + */ public AvoidObstaclesBehavior(ArcRotateMoveController pilot, UltrasonicSensor sonar, TouchSensor touch, LightSensor light, CompassHTSensor compass, float wheelRadius, float trackWidth) { super(pilot, sonar, touch, light, compass, wheelRadius, trackWidth); this.state = RobotStateSingleton.getInstance(); diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/BaseBehavior.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/BaseBehavior.java index 3dec5ff..7c1a3ae 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/BaseBehavior.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/BaseBehavior.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.behaviors; import lejos.nxt.LightSensor; @@ -7,6 +20,11 @@ import lejos.nxt.addon.CompassHTSensor; import lejos.robotics.navigation.ArcRotateMoveController; import lejos.robotics.subsumption.Behavior; +/** + * Base class for {@link Behavior} implementations that need to use multiple sensors and a pilot. + * + * @author Miguel Angel Astor Romero. + */ public abstract class BaseBehavior implements Behavior { protected ArcRotateMoveController pilot; protected UltrasonicSensor sonar; @@ -16,6 +34,17 @@ public abstract class BaseBehavior implements Behavior { protected float wheelDiameter; protected float trackWidth; + /** + * Creates a new {@link BaseBehavior}. Has to be called by subclasses. + * + * @param pilot A differential pilot that implements {@link ArcRotateMoveController} + * @param sonar A range finder sensor. + * @param touch A touch sensor. + * @param light A monochromatic light sensor. + * @param compass A HiTechnic compass sensor. + * @param wheelDiameter The diameter of the active wheels. Assumes both wheels are the same size. + * @param trackWidth The distance between the center of both active wheels. + */ public BaseBehavior(ArcRotateMoveController pilot, UltrasonicSensor sonar, TouchSensor touch, LightSensor light, CompassHTSensor compass, float wheelDiameter, float trackWidth) { this.pilot = pilot; this.sonar = sonar; diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/CatchBallBehavior.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/CatchBallBehavior.java index af19785..4da7884 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/CatchBallBehavior.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/CatchBallBehavior.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.behaviors; import lejos.nxt.LightSensor; @@ -10,9 +23,24 @@ import ve.ucv.ciens.cicore.icaro.ryabi.utils.RobotStateSingleton; import ve.ucv.ciens.cicore.icaro.ryabi.utils.Rotations; import ve.ucv.ciens.cicore.icaro.ryabi.utils.States; +/** + * This class implements a {@link BaseBehavior} that just closes the B {@link Motor} in order to catch the ball after it has been found. + * + * @author Miguel Angel Astor Romero. + */ public class CatchBallBehavior extends BaseBehavior { RobotStateSingleton state; + /** + * Creates a new {@link CatchBallBehavior}. + * @param pilot + * @param sonar + * @param touch + * @param light + * @param compass + * @param wheelDiameter + * @param trackWidth + */ public CatchBallBehavior(ArcRotateMoveController pilot, UltrasonicSensor sonar, TouchSensor touch, LightSensor light, CompassHTSensor compass, float wheelDiameter, float trackWidth) { super(pilot, sonar, touch, light, compass, wheelDiameter, trackWidth); this.state = RobotStateSingleton.getInstance(); @@ -28,6 +56,7 @@ public class CatchBallBehavior extends BaseBehavior { Motor.B.forward(); try { Thread.sleep(2000); } catch(InterruptedException e) { }; + /* Turn towards the start line and start moving. */ Rotations.rotate180(compass, pilot); state.setState(States.WANDER); } diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SearchBallBehavior.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SearchBallBehavior.java index 877bb31..7629b89 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SearchBallBehavior.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SearchBallBehavior.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.behaviors; import lejos.nxt.LightSensor; @@ -11,6 +24,16 @@ import ve.ucv.ciens.cicore.icaro.ryabi.utils.RobotStateSingleton; import ve.ucv.ciens.cicore.icaro.ryabi.utils.Rotations; import ve.ucv.ciens.cicore.icaro.ryabi.utils.States; +/** + * This class implements a {@link BaseBehavior} that searches slowly to the left and right of the robot for the pedestal where the ball + * should be in. It first searches to the left of the robot until it hits an obstacle. Then it will search to the right of the robot + * until it hits another obstacle. + * + * If the ball is not found after searching on both sides then the robot will make a 180 degrees turn and will start moving back + * to the start line. + * + * @author Miguel Angel Astor Romero. + */ public class SearchBallBehavior extends BaseBehavior { private SensorEventsQueue queue; private boolean ballFound; @@ -18,6 +41,16 @@ public class SearchBallBehavior extends BaseBehavior { private RobotStateSingleton state; private boolean turnLeft; + /** + * Creates a new {@link SearchBallBehavior}. + * @param pilot + * @param sonar + * @param touch + * @param light + * @param compass + * @param wheelDiameter + * @param trackWidth + */ public SearchBallBehavior(ArcRotateMoveController pilot, UltrasonicSensor sonar, TouchSensor touch, LightSensor light, CompassHTSensor compass, float wheelDiameter, float trackWidth) { super(pilot, sonar, touch, light, compass, wheelDiameter, trackWidth); this.queue = SensorEventsQueue.getInstance(); @@ -29,18 +62,23 @@ public class SearchBallBehavior extends BaseBehavior { @Override public boolean takeControl() { + /* If the ball has already been found then this behavior should not take control again. */ if(ballFound) return false; + /* If the current state is SEARCH_BALL then set the detectors and take control. */ if(state.getState() == States.SEARCH_BALL) { setDetectors(); return true; } + /* If the state is not SEARCH_BALL but there is at least one light feature detected + * indicating that the finish line has been reached then set the detectors and take control. */ if(queue.hasNextLightSensorEvent()) { state.setState(States.SEARCH_BALL); setDetectors(); + /* Discard unneeded detected light features. */ while(queue.hasNextLightSensorEvent()) queue.getNextLightSensorEvent(); @@ -54,25 +92,30 @@ public class SearchBallBehavior extends BaseBehavior { @Override public void action() { if(queue.hasNextRangeSensorEvent()) { - + /* If the pedestal has been found then stop the robot and set the state to BALL_FOUND. */ if(pilot.isMoving()) pilot.stop(); ballFound = true; state.setState(States.BALL_FOUND); + /* Discard unneeded range features. */ while(queue.hasNextRangeSensorEvent()) queue.getNextRangeSensorEvent(); } else { if(turnLeft) { + /* Search to the left of the robot. */ Rotations.rotateM90(compass, pilot); pilot.travel(50); if(queue.hasNextTouchSensorEvent()) { + /* If an obstacle is found while searching then start searching + * to the opposite side. */ pilot.travel(-100); turnLeft = false; + /* Discard unneeded touch events. */ while(queue.hasNextTouchSensorEvent()) queue.getNextTouchSensorEvent(); @@ -82,15 +125,19 @@ public class SearchBallBehavior extends BaseBehavior { Rotations.rotate90(compass, pilot); } else { + /* Search to the right of the robot. */ Rotations.rotate90(compass, pilot); pilot.travel(50); if(queue.hasNextTouchSensorEvent()) { + /* If an obstacle is found while searching then give up and go back + * to the start line. */ pilot.travel(-100); state.setState(States.WANDER); ballFound = true; + /* Discard unneeded touch events. */ while(queue.hasNextTouchSensorEvent()) queue.getNextTouchSensorEvent(); @@ -99,9 +146,9 @@ public class SearchBallBehavior extends BaseBehavior { Rotations.rotateM90(compass, pilot); - if(ballFound) { + /* If the ball was found or the robot gave up then turn around towards the start line. */ + if(ballFound) Rotations.rotate180(compass, pilot); - } } } } @@ -112,6 +159,9 @@ public class SearchBallBehavior extends BaseBehavior { pilot.stop(); } + /** + * Enables the touch and range feature detectors and disables the light feature detector. + */ private void setDetectors() { detectorHandler.enableTouchDetector(); detectorHandler.disableLightDetector(); diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SensorCalibrationBehavior.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SensorCalibrationBehavior.java index a3ac395..917bd41 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SensorCalibrationBehavior.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/SensorCalibrationBehavior.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.behaviors; import lejos.nxt.Button; @@ -8,9 +21,24 @@ import lejos.nxt.UltrasonicSensor; import lejos.nxt.addon.CompassHTSensor; import lejos.robotics.navigation.DifferentialPilot; +/** + * This class implements a {@link BaseBehavior} that performs automatic calibration of the {@link CompassHTSensor} and {@link LightSensor}. + * + * @author Miguel Angel Astor Romero. + */ public class SensorCalibrationBehavior extends BaseBehavior { private boolean sensorsCalibrated; + /** + * Creates a new {@link SensorCalibrationBehavior} + * + * @param sonar + * @param touch + * @param light + * @param compass + * @param wheelRadius + * @param trackWidth + */ public SensorCalibrationBehavior(UltrasonicSensor sonar, TouchSensor touch, LightSensor light, CompassHTSensor compass, float wheelRadius, float trackWidth) { super(null, sonar, touch, light, compass, wheelRadius, trackWidth); sensorsCalibrated = false; @@ -23,6 +51,7 @@ public class SensorCalibrationBehavior extends BaseBehavior { @Override public void action() { + /* Calibrate the compass by turning slowly by 720 degrees. */ System.out.println("Calib. compass"); DifferentialPilot p = new DifferentialPilot(wheelDiameter, trackWidth, Motor.A, Motor.C); p.setRotateSpeed(25); @@ -30,6 +59,7 @@ public class SensorCalibrationBehavior extends BaseBehavior { p.rotate(720, false); compass.stopCalibration(); + /* Ask the user for input in calibrating the light sensor. */ System.out.println("Calib. light s."); light.setFloodlight(true); System.out.println("Point at dark\nand press ENTER"); diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/VictoryBehavior.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/VictoryBehavior.java index 00d71ce..70f5d8e 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/VictoryBehavior.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/VictoryBehavior.java @@ -1,48 +1,99 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.behaviors; +import java.awt.Point; + import lejos.nxt.Sound; +import lejos.robotics.subsumption.Behavior; import ve.ucv.ciens.cicore.icaro.ryabi.sensors.FeatureDetectorsHandler; import ve.ucv.ciens.cicore.icaro.ryabi.sensors.SensorEventsQueue; import ve.ucv.ciens.cicore.icaro.ryabi.utils.RobotStateSingleton; import ve.ucv.ciens.cicore.icaro.ryabi.utils.States; +/** + * This class implements a {@link Behavior} that plays some music when the robot has completed it's objective. + * + * @author Miguel Angel Astor Romero. + */ @SuppressWarnings("unused") -public class VictoryBehavior extends BaseBehavior { - private static final int C = 262; - private static final int D = 287; - private static final int E = 320; - private static final int F = 349; - private static final int G = 392; - private static final int A = 440; - private static final int B = 494; +public class VictoryBehavior implements Behavior { + private static final int C = 262; + private static final int D = 287; + private static final int E = 320; + private static final int F = 349; + private static final int G = 392; + private static final int A = 440; + private static final int B = 494; + private static final int ROUND = 1000; + private static final int WHITE = 500; + private static final int BLACK = 250; + private static final int QUARTER = 125; + private Point[] score; private RobotStateSingleton state; private SensorEventsQueue queue; private FeatureDetectorsHandler detectorHandler; + /** + * Creates a new {@link VictoryBehavior}. + */ public VictoryBehavior() { - super(null, null, null, null, null, 0.0f, 0.0f); state = RobotStateSingleton.getInstance(); this.queue = SensorEventsQueue.getInstance(); this.detectorHandler = FeatureDetectorsHandler.getInstance(); + + this.score = new Point[17]; + score[0] = new Point(B, BLACK); + score[1] = new Point(A, BLACK); + score[2] = new Point(G, WHITE); + score[3] = new Point(B, BLACK); + score[4] = new Point(A, BLACK); + score[5] = new Point(G, WHITE); + score[6] = new Point(G, QUARTER); + score[7] = new Point(G, QUARTER); + score[8] = new Point(G, QUARTER); + score[9] = new Point(G, QUARTER); + score[10] = new Point(A, QUARTER); + score[11] = new Point(A, QUARTER); + score[12] = new Point(A, QUARTER); + score[13] = new Point(A, QUARTER); + score[14] = new Point(B, BLACK); + score[15] = new Point(A, BLACK); + score[16] = new Point(G, WHITE); } @Override public boolean takeControl() { + /* Check if the current state is VICTORY. */ if(state.getState() == States.VICTORY) { detectorHandler.disableAllDetectors(); return true; } + /* If the state is not VICTORY, then check if there is a light sensor + * event indicating that the goal line has been found. */ if(queue.hasNextLightSensorEvent()) { + /* Set the state to VICTORY and disable sensors. */ state.setState(States.VICTORY); detectorHandler.disableAllDetectors(); + /* Discard extraneous light events. */ while(queue.hasNextLightSensorEvent()) queue.getNextLightSensorEvent(); return true; - } return false; @@ -50,30 +101,27 @@ public class VictoryBehavior extends BaseBehavior { @Override public void action() { - playToneDuration(B, 250); - playToneDuration(A, 250); - playToneDuration(G, 500); - playToneDuration(B, 250); - playToneDuration(A, 250); - playToneDuration(G, 500); - playToneDuration(G, 125); - playToneDuration(G, 125); - playToneDuration(G, 125); - playToneDuration(G, 125); - playToneDuration(A, 125); - playToneDuration(A, 125); - playToneDuration(A, 125); - playToneDuration(A, 125); - playToneDuration(B, 250); - playToneDuration(A, 250); - playToneDuration(G, 500); + /* Play some music! */ + playMusic(score); + + /* Set the final state. */ state.setState(States.DONE); } @Override public void suppress() { } + private void playMusic(Point[] score) { + for(Point note: score) + playToneDuration(note.x, note.y); + } + /** + * Plays the given tone for the specified time given in milliseconds. + * + * @param tone + * @param milis + */ private void playToneDuration(int tone, int milis) { Sound.playTone(tone, milis); try { Thread.sleep(milis); } catch(InterruptedException ie) {} diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/WanderBehavior.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/WanderBehavior.java index 2c5edc6..e96cf73 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/WanderBehavior.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/behaviors/WanderBehavior.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.behaviors; import lejos.nxt.LightSensor; @@ -9,10 +22,26 @@ import ve.ucv.ciens.cicore.icaro.ryabi.sensors.FeatureDetectorsHandler; import ve.ucv.ciens.cicore.icaro.ryabi.utils.RobotStateSingleton; import ve.ucv.ciens.cicore.icaro.ryabi.utils.States; +/** + * This class implements a {@link BaseBehavior} that wanders in a straight line. + * + * @author Miguel Angel Astor Romero. + */ public class WanderBehavior extends BaseBehavior { private RobotStateSingleton state; private FeatureDetectorsHandler detectorHandler; + /** + * Create a new {@link WanderBehavior}. + * + * @param pilot + * @param sonar + * @param touch + * @param light + * @param compass + * @param wheelDiameter + * @param trackWidth + */ public WanderBehavior(ArcRotateMoveController pilot, UltrasonicSensor sonar, TouchSensor touch, LightSensor light, CompassHTSensor compass, float wheelDiameter, float trackWidth) { super(pilot, sonar, touch, light, compass, wheelDiameter, trackWidth); state = RobotStateSingleton.getInstance(); @@ -21,6 +50,7 @@ public class WanderBehavior extends BaseBehavior { @Override public boolean takeControl() { + /* Check if the state is wander. If it is, then set the sensors and return true. */ if(state.getState() == States.WANDER) { detectorHandler.enableTouchDetector(); detectorHandler.enableLightDetector(); diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectionListener.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectionListener.java index 78484b4..7432a96 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectionListener.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectionListener.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.sensors; import lejos.nxt.Sound; @@ -5,9 +18,18 @@ import lejos.robotics.objectdetection.Feature; import lejos.robotics.objectdetection.FeatureDetector; import lejos.robotics.objectdetection.FeatureListener; +/** + * A {@link FeatureListener} implementation that just plays a beep when any feature is detected and stores said feature at the + * global {@link SensorEventsQueue}. + * + * @author Miguel Angel Astor Romero. + */ public class FeatureDetectionListener implements FeatureListener { private SensorEventsQueue eventsQueue; + /** + * Creates a new {@link FeatureDetectionListener}. + */ public FeatureDetectionListener() { this.eventsQueue = SensorEventsQueue.getInstance(); } diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectorsHandler.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectorsHandler.java index c5d7f03..a0d4623 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectorsHandler.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/FeatureDetectorsHandler.java @@ -1,8 +1,28 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.sensors; import lejos.robotics.objectdetection.RangeFeatureDetector; import lejos.robotics.objectdetection.TouchFeatureDetector; +import lejos.robotics.subsumption.Behavior; +/** + * Singleton class that holds all the feature detectors in one place so that the different {@link Behavior} implementations + * can operate on them. + * + * @author Miguel Angel Astor Romero. + */ public final class FeatureDetectorsHandler { private RangeFeatureDetector rangeDetector; private TouchFeatureDetector touchDetector; @@ -18,6 +38,11 @@ public final class FeatureDetectorsHandler { private static final FeatureDetectorsHandler INSTANCE = new FeatureDetectorsHandler(); } + /** + * Gets the singleton instance of this class. + * + * @return the instacne. + */ public static FeatureDetectorsHandler getInstance() { return SingletonHolder.INSTANCE; } diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/LightFeatureDetector.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/LightFeatureDetector.java index 5f981f5..e1fcb53 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/LightFeatureDetector.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/LightFeatureDetector.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.sensors; import lejos.geom.Point; @@ -6,7 +19,39 @@ import lejos.robotics.RangeReading; import lejos.robotics.objectdetection.Feature; import lejos.robotics.objectdetection.FeatureDetectorAdapter; import lejos.robotics.objectdetection.RangeFeature; +import lejos.robotics.objectdetection.TouchFeatureDetector; +/** + *
A {@link FeatureDetectorAdapter} subclass that reports events detected by the light sensor every 50 milliseconds. It is based + * on the {@link TouchFeatureDetector} class.
+ * + *The detector can take into account the position of the light sensor with respect to the rotation center of the robot. + * Use the following guide to calculate the x offset and y offset of the sensor:
+ * + *+-----------------++ *
| y----L |+ *
| | | |+ *
|W C----x W|+ *
| |+ *
| |+ *
| |+ *
| |+ *
| |+ *
+-----------------++ * + *
Where:
+ * + *The front of the robot is at the top of the diagram.
+ * + * @author Miguel Angel Astor Romero. + */ public class LightFeatureDetector extends FeatureDetectorAdapter { private static final int DELAY = 50; @@ -16,37 +61,111 @@ public class LightFeatureDetector extends FeatureDetectorAdapter { private float angle = 0; private float range = 0; + /** + * Creates a new {@link LightFeatureDetector} using the given light sensor. The detection threshold is + * set to 50% and it assumes the sensor is at the rotation center of the robot. The detector will report events + * when the light measurement is less than 50%. + * + * @param lightSensor the light sensor to use. + */ public LightFeatureDetector(LightSensor lightSensor) { this(lightSensor, 50, false, 0, 0); } + /** + * Creates a new {@link LightFeatureDetector} using the given light sensor and the given threshold. It assumes the sensor is at + * the rotation center of the robot. The detector will report events when the light measurement is less than the threshold. + * + * @param lightSensor the light sensor to use. + * @param threshold the detection threshold. It will be clamped to [0, 100]. + */ public LightFeatureDetector(LightSensor lightSensor, int threshold) { this(lightSensor, threshold, false, 0, 0); } + /** + * Creates a new {@link LightFeatureDetector} using the given light sensor. The detection threshold is + * set to 50% and it assumes the sensor is at the rotation center of the robot. The detector will report events + * when the light measurement is more than or equal to 50% if invert is true. + * + * @param lightSensor the light sensor to use. + * @param invert + */ public LightFeatureDetector(LightSensor lightSensor, boolean invert) { this(lightSensor, 50, invert, 0, 0); } + /** + * Creates a new {@link LightFeatureDetector} using the given light sensor. The detection threshold is + * set to 50%. The offsets determine the position of the sensor with respect to the center of the robot. + * The detector will report events when the light measurement is less than 50%. + * + * To calculate the offsets use the following guide: + * + * @param lightSensor the light sensor to use. + * @param xOffset distance of the sensor to the rotation center of the robot. + * @param yOffset distance of the sensor to the rotation center of the robot. + */ public LightFeatureDetector(LightSensor lightSensor, double xOffset, double yOffset) { this(lightSensor, 50, false, xOffset, yOffset); } + /** + * Creates a new {@link LightFeatureDetector} using the given light sensor. The detection threshold is + * set to the given threshold. The offsets determine the position of the sensor with respect to the center of the robot. + * The detector will report events when the light measurement is less than the given threshold. + * + * To calculate the offsets use the following guide: + * + * @param lightSensor the light sensor to use. + * @param threshold the detection threshold. It will be clamped to [0, 100]. + * @param xOffset distance of the sensor to the rotation center of the robot. + * @param yOffset distance of the sensor to the rotation center of the robot. + */ public LightFeatureDetector(LightSensor lightSensor, int threshold, double xOffset, double yOffset) { this(lightSensor, threshold, false, xOffset, yOffset); } + /** + * Creates a new {@link LightFeatureDetector} using the given light sensor. The detection threshold is + * set to 50%. The offsets determine the position of the sensor with respect to the center of the robot. + * The detector will report events when the light measurement is more than or equal to 50% if invert is true. + * + * To calculate the offsets use the following guide: + * + * @param lightSensor the light sensor to use. + * @param invert + * @param xOffset distance of the sensor to the rotation center of the robot. + * @param yOffset distance of the sensor to the rotation center of the robot. + */ public LightFeatureDetector(LightSensor lightSensor, boolean invert, double xOffset, double yOffset) { this(lightSensor, 50, invert, xOffset, yOffset); } + /** + * Creates a new {@link LightFeatureDetector} using the given light sensor. The detection threshold is + * set to the given threshold. The offsets determine the position of the sensor with respect to the center of the robot. + * The detector will report events when the light measurement is more than the given threshold if invert is true. + * + * To calculate the offsets use the following guide: + * + * @param lightSensor the light sensor to use. + * @param threshold the detection threshold. It will be clamped to [0, 100]. + * @param invert + * @param xOffset distance of the sensor to the rotation center of the robot. + * @param yOffset distance of the sensor to the rotation center of the robot. + */ public LightFeatureDetector(LightSensor lightSensor, int threshold, boolean invert, double xOffset, double yOffset) { super(DELAY); this.lightSensor = lightSensor; this.threshold = threshold; this.invert = invert; - // Calculate angle and distance of light sensor from center: + /* Clamp the detection threshold. */ + this.threshold = (this.threshold > 100) ? 100 : this.threshold; + this.threshold = (this.threshold < 0) ? 0 : this.threshold; + + /* Calculate angle and distance of light sensor from center. */ Point robot_center = new Point(0, 0); Point bumper_p = new Point((float)xOffset, (float)yOffset); range = (float)robot_center.distance(xOffset, yOffset); @@ -56,6 +175,9 @@ public class LightFeatureDetector extends FeatureDetectorAdapter { @Override public Feature scan() { RangeFeature rf = null; + + /* Calculate the distance and angle of the feature and return it. Take into + * account if the detection factor is inverted. */ if(invert) { if(lightSensor.getLightValue() >= threshold) { RangeReading rr = new RangeReading(angle, range); @@ -74,6 +196,8 @@ public class LightFeatureDetector extends FeatureDetectorAdapter { protected void notifyListeners(Feature feature) { super.notifyListeners(feature); + /* Stall the detector until the detection ends to avoid notifying the listeners + * multiple times for the same feature. */ if(invert) { while(lightSensor.getLightValue() >= threshold); } else { diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEvent.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEvent.java index 394e536..d9afb24 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEvent.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEvent.java @@ -1,12 +1,43 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.sensors; import lejos.robotics.objectdetection.Feature; import lejos.robotics.objectdetection.FeatureDetector; +/** + * Container class that aggregates a detected {@link Feature} and the {@link FeatureDetector} that found it. + * + * @author Miguel Angel Astor Romero. + */ public class SensorEvent { + /** + * A detected feature. + */ public Feature feature; + + /** + * The detector responsible for finding the feature. + */ public FeatureDetector detector; + /** + * Commodity constructor. + * + * @param feature the detected feature. + * @param detector the respective detector. + */ public SensorEvent(Feature feature, FeatureDetector detector) { this.feature = feature; this.detector = detector; diff --git a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEventsQueue.java b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEventsQueue.java index 8b826bd..62a99cc 100644 --- a/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEventsQueue.java +++ b/src/ve/ucv/ciens/cicore/icaro/ryabi/sensors/SensorEventsQueue.java @@ -1,3 +1,16 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. 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. + * + * See the LICENSE file for more details. + */ + package ve.ucv.ciens.cicore.icaro.ryabi.sensors; import java.util.Queue; @@ -7,6 +20,11 @@ import lejos.robotics.objectdetection.FeatureDetector; import lejos.robotics.objectdetection.RangeFeatureDetector; import lejos.robotics.objectdetection.TouchFeatureDetector; +/** + * A singleton {@link Queue} holder that keeps track of the different events detected by the sensors in FIFO order. + * + * @author Miguel Angel Astor Romero. + */ public final class SensorEventsQueue { private Queue