import josx.platform.rcx.*; /** * There is only one Slug. It is the robot. * * */ public class Slug implements Segment, SensorConstants { static int minimumLightLevel, maximumLightLevel, thresholdLightLevel; static boolean foundKey = false; static boolean foundEdge = false; static boolean foundBlack = false; static int noofFingerTouches = 0; static final Sensor LIGHT_SENSOR = Sensor.S3; static final Sensor BUMPER = Sensor.S1; static final Sensor FINGER_SENSOR = Sensor.S2; static final Motor FINGER_MOTOR = Motor.A; static final Motor BASE_MOTOR = Motor.C; static final int BASE_POWER = 2; /* * The base has to move slowly so it * doesn't miss lines */ static final int FINGER_POWER = 7; //The finger should move fast static final int THRESHOLD_CALCULATING_POWER = 2; /* Don't go too fast when * calculating the * threshold */ static final boolean DEBUG = true; static final int TIME_BEFORE_STOP = 0; //This was not effective... static final int TIME_BETWEEN_STEPS = 100; /* * This ensures that the bot * doesn't move too fast. */ //Can we make the finger fix itself? static int noofTimesRotated = 0; static int totalTimeRotating = 0; /* * The robot will sample light spaces, to calculate a threshold * value. It will also use it for moving around (i.e. keep it small) */ static int SAMPLE = 1; static int lastDownTime = 0; static int lastUpTime = 0; /** * Unit test: * setup() * play(300) * then 3*( move(1), play(100) ) * then 3*( move(-2), play(200) ) * then move(3), play(300) * finally, beepSequence * (The last note should be the same as the first) */ public static void main(String args[]) { Keyboard k = new Keyboard('C', 4); setup(); move(-7, k); play(300); move(1, k); play(100); move(1, k); play(100); move(1, k); play(100); move(-2, k); play(200); move(-2, k); play(200); move(-2, k); play(200); move(3, k); play(300); Sound.beepSequence(); } /** * Move the bot by keys on the keyboard * @param steps > 0 meaning move right, < 0 meaning move left * */ static boolean move(int distance, Keyboard kbrd) { BASE_MOTOR.setPower(BASE_POWER); //Setup for right vs. left int countBy; if (distance > 0) { countBy = 1; } else if (distance < 0) { countBy = -1; } else return true; // for (int i = 0 ; i != distance ; i += countBy) { if (countBy == 1) BASE_MOTOR.forward(); else BASE_MOTOR.backward(); do { wait(SAMPLE); } while (!foundKey&&!foundEdge); if (DEBUG) Sound.beep(); kbrd.moved(countBy); foundKey = false; if (foundEdge) { if (DEBUG) Sound.buzz(); foundEdge = false; kbrd.atEdge(countBy == 1); BASE_MOTOR.stop(); return false; } BASE_MOTOR.stop(); wait(TIME_BETWEEN_STEPS); } wait(TIME_BEFORE_STOP); BASE_MOTOR.stop(); return true; } static void fingerDown() { long startTime = System.currentTimeMillis(); int tmp = noofFingerTouches; //put finger down FINGER_MOTOR.setPower(FINGER_POWER); FINGER_MOTOR.backward(); while (noofFingerTouches == tmp) { wait(SAMPLE); } FINGER_MOTOR.stop(); long endTime = System.currentTimeMillis(); int time = (int)endTime - (int)startTime; if (lastDownTime == 0) lastDownTime = time; if ((time > 1.5*lastDownTime)||(lastDownTime > 1.5*time)) { Sound.buzz(); //fingerDown(); } lastDownTime = time; } static void fingerUp() { long startTime = System.currentTimeMillis(); int tmp = noofFingerTouches; //pull finger up FINGER_MOTOR.backward(); while (noofFingerTouches == tmp) { wait(SAMPLE); } FINGER_MOTOR.stop(); long endTime = System.currentTimeMillis(); int time = (int)endTime - (int)startTime; if (lastUpTime == 0) lastUpTime = time; if ((time > 1.5*lastUpTime)||(lastUpTime > 1.5*time)) { Sound.buzz(); //fingerUp(); } lastUpTime = time; } /*when the robot starts, finger is up*/ static void play(int msecs) { fingerDown(); wait(msecs); fingerUp(); } static void wait(int msecs) { try { Thread.sleep(msecs); } catch (InterruptedException exc) { return; } } /** * First thing, setup. */ static void setup() { //Start up the light sensor: startLightSensor(); //Start up the finger: startFingerSensor(); //start up the bumper startBumper(); Sound.beepSequence(); //find the threshold numbers calculateThresholdLightValue(); displayLightValues(); Sound.beepSequence(); //Other startup stuff goes here: } /** * show the values if you'd like * */ static void displayLightValues() { LCD.showNumber(minimumLightLevel); try { Thread.sleep(1000); } catch (InterruptedException exc) { } LCD.showNumber(maximumLightLevel); try { Thread.sleep(1000); } catch (InterruptedException exc) { } LCD.showNumber(thresholdLightLevel); } /** * To start a light sensor, we first set the type and mode, then add * a sensor listener (inner class), then activate the sensor. */ static void startLightSensor() { LIGHT_SENSOR.setTypeAndMode(SENSOR_TYPE_LIGHT, SENSOR_MODE_PCT); LIGHT_SENSOR.addSensorListener(new SensorListener() { public void stateChanged(Sensor source, int oldValue, int newValue) { if (oldValue < thresholdLightLevel) { foundBlack = true; } else if ( (foundBlack) && (newValue >= thresholdLightLevel) ) { foundKey = true; foundBlack = false; } } }); LIGHT_SENSOR.activate(); } /** * To start a bumper, we first set the type and mode, then add * a sensor listener (inner class), then activate the sensor. */ static void startBumper() { BUMPER.setTypeAndMode(SENSOR_TYPE_TOUCH, SENSOR_MODE_BOOL); BUMPER.addSensorListener(new SensorListener() { public void stateChanged(Sensor source, int oldValue, int newValue) { if (oldValue == 0&&newValue == 1) { foundEdge = true; } } }); BUMPER.activate(); } /** * To start a light sensor, we first set the type and mode, then add * a sensor listener (inner class), then activate the sensor. */ static void startFingerSensor() { FINGER_SENSOR.setTypeAndMode(SENSOR_TYPE_TOUCH, SENSOR_MODE_BOOL); noofFingerTouches = 0; FINGER_SENSOR.addSensorListener(new SensorListener() { public void stateChanged(Sensor source, int oldValue, int newValue) { if (oldValue == 0&&newValue == 1) { noofFingerTouches++; } } }); FINGER_SENSOR.activate(); } /** * NOTE: place the Slug at the right side for this to work * correctly. Slug should end up on top C * * read the light sensor for milliseconds, checking for a * minimum and maximum value. * * * preconditions: startLightSensor must be called first. * */ static void calculateThresholdLightValue() { minimumLightLevel = 100; maximumLightLevel = 1; int lightSample; LCD.showNumber(666); wait(100); boolean forward = true; int count = 0; BASE_MOTOR.setPower(THRESHOLD_CALCULATING_POWER); //Move backward until the end. BASE_MOTOR.backward(); while (!foundEdge) { evaluateNewSample(LIGHT_SENSOR.readValue() ); wait(SAMPLE); } foundEdge = false; //Now move forward until the end BASE_MOTOR.forward(); while (!foundEdge) { evaluateNewSample(LIGHT_SENSOR.readValue() ); wait(SAMPLE); } foundEdge = false; BASE_MOTOR.stop(); // assume there will be a significant difference, and hopefully a // gap around the average of the hightest and the lowest light levels // (assuming the robot saw ANY dark and light areas during it's //"fact-gathering" above thresholdLightLevel = (maximumLightLevel + minimumLightLevel)/2; LCD.showNumber(999); wait(500); } static void evaluateNewSample(int lightSample ) { LCD.showNumber(lightSample); if (maximumLightLevel < lightSample) { maximumLightLevel = lightSample; } if (minimumLightLevel > lightSample) { minimumLightLevel = lightSample; } wait(SAMPLE); } /** * Goal: if * start and end is: * |---X-----| * -321012345+ * Where 0 the "middle" of the keyboard (middle C?) * And X starts at 0. */ static void findKeyboard(int start, Keyboard keyboard) { for (int dirConst = 1 ; dirConst >= -1 ; dirConst -= 2) { int current = start; foundEdge = false; // while you are still able to move (i.e. not hitting the // end of the keyboard) while (move(dirConst, keyboard)) LCD.showNumber(dirConst * keyboard.getCurrentKey()); wait(50); foundEdge = false; keyboard.moved(dirConst); } } }