|
||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||
|
| |||||||||||||||||||||||||||
Servomotors | |
| We did some experiments with Sun SPOT and servomotors. We had 3 servo in our hands - two micro servomotors 'E-Sky' and one micro servo 'GWS PICO'. After some first tests we found some good things and some bad things. | |
|
NOTE: Wires color scheme of GWS servo is differ from standard (typical) color scheme of servomotors. Usually wires marked: Black is Ground Red is +5 White is Signal wire But for GWS the colors of wires a little bit differ: Dark Brown is Ground Red is +5 Orange is Signal wire |
![]() |
![]() |
|
Good things: It was very easy to connect servo to Sun SPOT. And it was easy to use them with Sun SPOT. Bad things: We found that our servomotors with Sun SPOT can rotate their shafts only about 90-100 degrees instead of 180 degrees. Another disappointed thing - the servomotors work too slow. Using our code example, you can check - how fast your servos. Our servos are not so fast. May be these servos are too cheap to be fast enough ( he-he-he). | |
Here you can see servomotor movement from minimal position to maximum position. The test algorithm is very easy: goto min position wait 1 second goto max position wait 1 second etc... As you see 1 sec is enough for full rotation from min position to max position. The angle is about 100-110 degrees. |
This photo illustrates time collision. The idea of test algorithm is the same and very easy: goto min position wait 200 milliseconds goto max position wait 200 milliseconds etc... As you see wait 200 milliseconds is NOT enough for full rotation from min position to max position. The angle is limited - it is not so wide as angle with 1000 milliseconds. With 200 milliseconds delay the angle is about 45-60 degrees. If you continue to decrease the delay, you can get less and less angle. Practically up to zero movement. |




1 /* 2 * Copyright (c) 2009, Oleg Lyubchenko (Oleg [at] RoboHobby [dot] com) 3 * 4 * www.RoboHobby.com 5 * 6 * This is first test example of the J2ME code. 7 * The idea is to test - is it possible to create balancing robot, 8 * using SunSPOT's accelerometer as source of information about 9 * robot position ('tilt') and servomotor as an execution machine for 10 * compensation tilt rotationg. 11 * 12 * See details on : 13 * http://www.robohobby.com/sun_spot_balancing_robot.jsp 14 * http://www.RoboHobby.com/sun_spot_hobby_robotics.jsp 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 */ 25 26 package com.robohobby.sunspot.BalancingRobot; 27 28 import com.sun.spot.peripheral.Spot; 29 import com.sun.spot.sensorboard.EDemoBoard; 30 import com.sun.spot.sensorboard.peripheral.ISwitch; 31 import com.sun.spot.sensorboard.peripheral.ITriColorLED; 32 import com.sun.spot.peripheral.radio.IRadioPolicyManager; 33 import com.sun.spot.io.j2me.radiostream.*; 34 import com.sun.spot.io.j2me.radiogram.*; 35 import com.sun.spot.sensorboard.peripheral.ILightSensor; 36 import com.sun.spot.sensorboard.peripheral.LIS3L02AQAccelerometer; 37 import com.sun.spot.sensorboard.peripheral.Servo; 38 import com.sun.spot.util.*; 39 40 import java.io.*; 41 import javax.microedition.io.*; 42 import javax.microedition.midlet.MIDlet; 43 import javax.microedition.midlet.MIDletStateChangeException; 44 45 /** 46 * The startApp method of this class is called by the VM to start the 47 * application. 48 * 49 * The manifest specifies this class as MIDlet-1, which means it will 50 * be selected for execution. 51 */ 52 public class SunSpotBalancingRobotApp extends MIDlet { 53 54 private static final int CENTER_VALUE = 1500; 55 private static final int MIN_VALUE = 1000; 56 private static final int MAX_VALUE = 2000; 57 58 EDemoBoard eDemoBoard = EDemoBoard.getInstance(); 59 60 Servo panServo = new Servo(eDemoBoard.getOutputPins()[EDemoBoard.H0]); 61 Servo tiltServo = new Servo(eDemoBoard.getOutputPins()[EDemoBoard.H1]); 62 63 private ITriColorLED [] leds = EDemoBoard.getInstance().getLEDs(); 64 65 public LIS3L02AQAccelerometer accelerometer; 66 67 68 protected void startApp() throws MIDletStateChangeException { 69 70 accelerometer = (LIS3L02AQAccelerometer)EDemoBoard.getInstance().getAccelerometer(); 71 accelerometer.setScale(LIS3L02AQAccelerometer.SCALE_2G); // start using 2G scale 72 73 74 ISwitch sw1 = EDemoBoard.getInstance().getSwitches()[EDemoBoard.SW1]; 75 ISwitch sw2 = EDemoBoard.getInstance().getSwitches()[EDemoBoard.SW2]; 76 77 leds[0].setRGB(0,100,0); // set color to green 78 leds[7].setRGB(0,100,0); // set color to green 79 80 boolean stop = false; 81 boolean isReady = false; 82 83 84 int initValueX = 470; 85 int initValueY = 470; 86 int initValueZ = 470; 87 88 int stepZ = 1; 89 int servoCorrectionZ = 0; 90 int deltaZ = 0; 91 92 int minDeltaZ = 800; 93 int maxDeltaZ = -800; 94 95 int minServoCorrectionZ = MAX_VALUE; 96 int maxServoCorrectionZ = 0; //MIN_VALUE; 97 98 // testServoRotation( 1000 ); 99 // testServoRotation( 200 ); 100 101 while ( !stop ) 102 { 103 104 if (sw2.isClosed()) //Go out from the application 105 { 106 stop = true; 107 } else { 108 109 if (sw1.isClosed()) { 110 if (isReady) { 111 isReady = false; 112 } else { 113 isReady = true; 114 115 try { 116 initValueZ = accelerometer.getRawZ(); 117 } catch (IOException ex) { 118 ex.printStackTrace(); 119 } 120 } 121 } 122 123 if ( !isReady ) 124 { 125 //show that we are ready to do the job: 126 leds[7].setOff(); 127 leds[0].setOn(); 128 } 129 else 130 { 131 //do the job: 132 leds[0].setOff(); 133 leds[7].setOn(); 134 135 int rawX = 0; 136 int rawY = 0; 137 int rawZ = 0; 138 139 try { 140 141 rawX = accelerometer.getRawX(); 142 rawY = accelerometer.getRawY(); 143 rawZ = accelerometer.getRawZ(); 144 145 System.out.println( 146 "initValueZ=" + initValueZ + 147 " servoCorrectionZ=" + servoCorrectionZ + 148 " rawX=" + rawX + 149 " rawY=" + rawY + 150 " rawZ=" + rawZ 151 ); 152 153 154 if ( rawZ < initValueZ ) 155 { 156 System.out.println( "Moving Plus" ); 157 if( CENTER_VALUE + servoCorrectionZ < MAX_VALUE ) 158 servoCorrectionZ += stepZ; 159 } 160 else 161 { 162 System.out.println( "Moving Minus" ); 163 if( CENTER_VALUE + servoCorrectionZ > MIN_VALUE ) 164 servoCorrectionZ -= stepZ; 165 } 166 167 System.out.println( "servoCorrectionZ(1)=" + servoCorrectionZ ); 168 169 deltaZ = initValueZ - rawZ; 170 171 172 if ( deltaZ < minDeltaZ ) 173 minDeltaZ = deltaZ; 174 175 if ( deltaZ > maxDeltaZ ) 176 maxDeltaZ = deltaZ; 177 178 System.out.println( "deltaZ=" + deltaZ + 179 " minDeltaZ=" + minDeltaZ + 180 " maxDeltaZ=" + maxDeltaZ ); 181 182 if ( servoCorrectionZ < minServoCorrectionZ ) 183 minServoCorrectionZ = servoCorrectionZ; 184 185 if ( servoCorrectionZ > maxServoCorrectionZ ) 186 maxServoCorrectionZ = servoCorrectionZ; 187 188 189 int servoPositionZ = CENTER_VALUE + servoCorrectionZ; 190 System.out.println( "servoPositionZ=" + servoPositionZ + 191 " minServoCorrectionZ=" + minServoCorrectionZ + 192 " maxServoCorrectionZ=" + maxServoCorrectionZ); 193 tiltServo.setValue( servoPositionZ ); 194 195 } 196 catch (IOException io_e) 197 { 198 System.out.println( "Error in getting rawX io_e=" + io_e ); 199 } 200 } 201 202 } 203 204 } 205 notifyDestroyed(); // cause the MIDlet to exit 206 } 207 208 private void testServoRotation( int delay ) 209 { 210 tiltServo.setValue( MIN_VALUE ); 211 Utils.sleep( delay ); // wait 212 tiltServo.setValue( MAX_VALUE ); 213 Utils.sleep( delay ); // wait 214 } 215 216 protected void pauseApp() { 217 // This is not currently called by the Squawk VM 218 } 219 220 /** 221 * Called if the MIDlet is terminated by the system. 222 * I.e. if startApp throws any exception other than MIDletStateChangeException, 223 * if the isolate running the MIDlet is killed with Isolate.exit(), or 224 * if VM.stopVM() is called. 225 * 226 * It is not called if MIDlet.notifyDestroyed() was called. 227 * 228 * @param unconditional If true when this method is called, the MIDlet must 229 * cleanup and release all resources. If false the MIDlet may throw 230 * MIDletStateChangeException to indicate it does not want to be destroyed 231 * at this time. 232 */ 233 protected void destroyApp(boolean unconditional) throws MIDletStateChangeException { 234 for (int i = 0; i < 8; i++) { 235 leds[i].setOff(); 236 } 237 } 238 } 239 240
|