Exercise 6 Solution: Servo Code

  1 /*
  2 * Copyright (c) 2007 Sun Microsystems, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person
  5 * obtaining a copy of this software and associated documentation
  6 * files (the "Software"), to deal in the Software without
  7 * restriction, including without limitation the rights to use, copy,
  8 * modify, merge, publish, distribute, sublicense, and/or sell copies
  9 * of the Software, and to permit persons to whom the Software is
 10 * furnished to do so, subject to the following conditions:
 11 *
 12 * The above copyright notice and this permission notice shall be
 13 * included in all copies or substantial portions of the Software.
 14 *
 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22 * SOFTWARE.
 23 */
 24 
 25 package org.sunspotworld;
 26 
 27 import com.sun.spot.sensorboard.EDemoBoard;
 28 import com.sun.spot.sensorboard.peripheral.ISwitch;
 29 import com.sun.spot.sensorboard.peripheral.ITriColorLED;
 30 import com.sun.spot.io.j2me.radiostream.*;
 31 import com.sun.spot.io.j2me.radiogram.*;
 32 import com.sun.spot.sensorboard.peripheral.ISwitchListener;
 33 import com.sun.spot.sensorboard.peripheral.Servo;
 34 import com.sun.spot.util.*;
 35 import java.io.*;
 36 import javax.microedition.io.*;
 37 import javax.microedition.midlet.MIDlet;
 38 import javax.microedition.midlet.MIDletStateChangeException;
 39 
 40 /**
 41  * The startApp method of this class is called by the VM to start the
 42  * application.
 43  * 
 44  * The manifest specifies this class as MIDlet-1, which means it will
 45  * be selected for execution.
 46  * 
 47  * This class controls the actual Servo, and reads from another class which
 48  * controls the Radio.
 49  */
 50 public class ServoMover extends MIDlet implements ISwitchListener{
 51 
 52     private ITriColorLED[] leds = EDemoBoard.getInstance().getLEDs();
 53     private static final int CENTER = 1500;
 54     private static final int MAX = 2500;
 55     private static final int MIN = 500;
 56     private ISwitch[] switches = EDemoBoard.getInstance().getSwitches();
 57     private ServoReceiver snw;
 58     private Servo serv;
 59 
 60   /**
 61    * This is the main method called to start the MIDlet application.
 62    * @throws javax.microedition.midlet.MIDletStateChangeException Throw exception if the MIDLet fails
 63    */
 64     protected void startApp() throws MIDletStateChangeException  {
 65         new BootloaderListener().start();   // monitor the USB (if connected) and recognize commands from host
 66         switches[0].addISwitchListener(this);
 67         switches[1].addISwitchListener(this);
 68         serv = new Servo(EDemoBoard.getInstance().getOutputPins()[EDemoBoard.H0]);
 69         serv.setValue(CENTER);
 70         Utils.sleep(500);
 71         while (serv.getValue() < MAX) {
 72             int cur = serv.getValue();
 73             serv.setValue(cur + 100);
 74             Utils.sleep(250);
 75         }
 76         while (serv.getValue() > MIN) {
 77             int cur = serv.getValue();
 78             serv.setValue(cur - 100);
 79             Utils.sleep(250);
 80         }
 81 //        snw = new ServoReceiver(this);
 82 //        System.out.println("Waiting for calibration data...");
 83 //        snw.connect();
 84 //        Thread t = new Thread(snw);
 85 //        t.start();
 86     }
 87     
 88   /**
 89    * Move the servo the specified amount.
 90    * @param bendValue Value of the sensor read. Must be converted to a servo-position before use.
 91    */
 92     public void moveServo(int bendValue) {
 93         /*
 94          * the formula is, roughly: 1000 * cube-root[(value-min)/60] + 500, but since we
 95          * only do *integer* cube roots, we make the value *really* big first (10^3), then 
 96          * reduce it again ( /10 ) later. It's not perfect, but it's pretty close
 97          */
 98         int sMove = (icbrt((int) ((((double) bendValue - (double) snw.getMin()) / 60) * 1000000)) * 10) + 500;
 99         System.out.println("Read sensor value: " + bendValue + " Moving Servo to: " + sMove);
100         serv.setValue(sMove);
101 
102     }
103     
104     /**
105      * Handler called when a watched switch is pressed.
106      * @param sw the switch that was pressed
107      */
108     public void switchPressed(ISwitch sw) {
109         int switchNum = (sw == switches[0]) ? 1 : 2;
110         System.out.println("Switch " + switchNum + " closed.");
111         manualMove(switchNum);
112     }
113 
114     /**
115      * Handler called when a switch is released
116      * @param sw the switch that was released
117      */
118     public void switchReleased(ISwitch sw) {
119          int switchNum = (sw == switches[0]) ? 1 : 2;
120         System.out.println("Switch " + switchNum + " opened.");
121         manualMove(switchNum);
122     }
123     
124     /**
125      * Move a servo based on a value for direction
126      * @param dir 1 or 2, corresponds to switch 1 or 2 to move the servo
127      */
128     private void manualMove (int dir) {
129         final  int move = 25;
130         int servPos = serv.getValue();
131         if(dir == 1){
132             if(servPos - move > MIN){
133                 serv.setValue(servPos - move);
134             } else {
135                 serv.setValue(MIN);
136             }
137         } else {
138             if(servPos + move < MAX ){
139                 serv.setValue(servPos + move);
140             } else {
141                 serv.setValue(MAX);
142             }
143         }
144     }
145 
146 
147     
148   /**
149    * This is ugly code, found on the internet, for doing, basically, integer cube roots.
150    * nasty stuff, but it comes astonishingly close, so it's 'good enough'
151    * Squawk doesn't have built-in cube-root, so this is our only hope.
152    * @return Integer cube-root
153    * @param x The integer to reduce to cube-root
154    */
155     private int icbrt(int x) {
156         int s = 30;
157         int y, b;
158         y = 0;
159         while (s >= 0) {
160             y = 2 * y;
161             b = (3 * y * (y + 1) + 1) << s;
162             s = s - 3;
163             if (x >= b) {
164                 x = x - b;
165                 y = y + 1;
166             }
167         }
168         return y;
169     }
170 
171     protected void pauseApp() {
172     // This is not currently called by the Squawk VM
173     }
174 
175     /**
176    * Called if the MIDlet is terminated by the system.
177    * I.e. if startApp throws any exception other than MIDletStateChangeException,
178    * if the isolate running the MIDlet is killed with Isolate.exit(), or
179    * if VM.stopVM() is called.
180    * 
181    * It is not called if MIDlet.notifyDestroyed() was called.
182    * @param unconditional If true when this method is called, the MIDlet must
183    *    cleanup and release all resources. If false the MIDlet may throw
184    *    MIDletStateChangeException  to indicate it does not want to be destroyed
185    *    at this time.
186    * @throws javax.microedition.midlet.MIDletStateChangeException Thrown when the state of the MIDLet is changed.
187    */
188     protected void destroyApp(boolean unconditional) throws MIDletStateChangeException {
189         for (int i = 0; i < 8; i++) {
190             leds[i].setOff();
191         }
192     }
193 
194     
195     
196 }

Go to Exercise 7