Introduction
I’ve managed to find some time recently to get playing with my SUN SPOTs again, so I figured I’d start by wiring up one of the servos from my ancient remote control cars to it. Although, there seems to be a lot of information about doing this on the web (mostly the wiring diagrams) I hit a snag with getting the full motion range out of my servo. So I figured I’d put something up here in case anyone else encounters the same.
Scenario
To control my servo I wrote a very quick GUI that allowed me to send float values through the connected base station to the free range SUN SPOT. That SPOT was wired up to a battery pack and servo and the servo moved when I hit the GUIs button. Simple, but a nice first step.
The Setup
I mostly copied the wiring of the servos from “Fantastic Kobe” and this offical SUN blog. There’s not a lot to the wiring, as you can see from this picture.

Shows the wiring from the battery pack and SUNSPOT to the Servo
I not going to go into detail about what connects where, because that information can easily be found on either of the above two links.
Setting the Servo Bounds
One of the things I found was using the setPosition(float p) method on Servo wasn’t giving me the full range of motion. To fix this you need to set the bounds of your particular servo. I didn’t know the ‘correct’ way to do this, so instead I went with a trial-and-error approach.
private int servoPin = EDemoBoard.H1;
private void initServo() {
servo = new Servo(EDemoBoard.getInstance().getOutputPins()[servoPin]);
// for(int i=250; i<2300; i+=10) {
// servo.setValue(i);
// out("value="+i);
// Utils.sleep(100);
// }
servo.setBounds(250, 2300);
}
In the above code, the starting value of “i” was originally zero and the end value was 10000. Then, by using changing these values so that when initServo() was called the servo didn’t groan in protect, I was able to set the bounds as shown. Having done that, servo.setValue(0.5); puts the servo in the middle as expected. With values of 0 and 1.0 taking the servo to its extremes.
I expect that most people’s servos are going to be different. Mine is a Futaba FP-S148. And now I can move a servo around, I can start to do something useful (or at least fun) with it!
The Code (Free Range SPOT)
There is only one class in the application that sits on the free range SPOT.
import java.io.IOException;
import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.peripheral.Servo;
public class MainApplication extends MIDlet {
private final String BASE_STATION_ID = "0014.4F01.0000.103E";
private int servoPin = EDemoBoard.H1;
private Servo servo;
private DatagramConnection toBaseStation = null;
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {}
protected void pauseApp() {}
protected void startApp() throws MIDletStateChangeException {
initComms();
initServo();
}
private void initComms() {
try {
toBaseStation = (DatagramConnection) Connector.open("radiogram://" + BASE_STATION_ID + ":100");
startListenerThread();
} catch (IOException ex) {
out("EXCEPTION: "+ex.getMessage());
}
}
private void initServo() {
servo = new Servo(EDemoBoard.getInstance().getOutputPins()[servoPin]);
servo.setBounds(250, 2300);
// for(int i=200; i<2300; i+=10) {
// servo.setValue(i);
// out("value="+i);
// Utils.sleep(100);
// }
}
private void startListenerThread() {
Thread t = new Thread(new Runnable() {
public void run() {
while(true) {
listenForMessage();
}
}
});
t.start();
}
private void listenForMessage() {
Datagram dgIn = null;
try {
dgIn = toBaseStation.newDatagram(toBaseStation.getMaximumLength());
toBaseStation.receive(dgIn);
handleMessage(dgIn.readUTF());
} catch (IOException ex) {
out("EXCEPTION LISTENING: "+ex.getMessage());
ex.printStackTrace();
}
}
private void handleMessage(String message) {
out("NEW MESSAGE ["+message+"]");
if(message.startsWith("SERVO:")) {
handleServoMessage(message);
} else {
handleUnknownMessage(message);
}
}
private void handleUnknownMessage(String message) {
out("UnknownMessage ["+message+"]");
sendMessage("UNKNOWN MESSAGE ["+message+"]");
}
private void handleServoMessage(String message) {
int cutAt = message.indexOf(":")+1;
String txtValue = message.substring(cutAt);
try {
float value = Float.valueOf(txtValue).floatValue();
if(value 1.0) {
sendMessage("SERVO VALUE REJECTED. OUT OF BOUNDS 0.0-1.0 ("+txtValue+")");
} else {
servo.setPosition(value);
sendMessage("SERVO: New Value Set="+servo.getValue());
}
} catch (NumberFormatException nfe) {
sendMessage("SERVO VALUE REJECTED. NOT A VALID FLOAT ("+txtValue+")");
}
}
private void sendMessage(String message) {
out("Sending: "+message);
Datagram dgOut = null;
try {
dgOut = toBaseStation.newDatagram(toBaseStation.getMaximumLength());
dgOut.writeUTF(message);
toBaseStation.send(dgOut);
} catch (IOException e) {
out("EXCEPTION SENDING TO BS: "+e.getMessage());
} finally {
if(null != dgOut) {
dgOut.reset();
}
}
}
private void out(String msg) {
System.out.println(msg);
}
}
The Code (Base Station)
The code on the base station is simple enough, in fact too simple to warrent posting and spending the time formatting it here. The only interesting bit is the following line which is one of the first lines in the public static void main(String[] args) method;
OTACommandServer.getInstance().start();
The rest of the code is either UI/Swing code or normal Java/SUN SPOT code. In fact, the initComms, sendMessage, startListenerThread and listenForMessage methods are identical to those that run on the free range SPOT. The only difference is the SPOT address that the DatagramConnection is opened with. Obviously, on the free range SPOT it is opened with the address of the base station, and the reverse for the code on the base station.
Aside
Disclaimer: Obviously, soldering is dangerous to yourself and the components you’re working on/with. Any damage or injury you sustain following this advice is entirely at your own risk and I accept no responsibilty for it.
…that being said; if you don’t have a decent breakout board for your SUN SPOTs (and you’re in the UK) then Maplin do some PCB socket connector things* that you can buy and solder into your SUN SPOT. This gives you the ability to use bread board connector cables to easily connect up different sockets from the SUN SPOT without having to do any resoldering. The soldering its self is a bit fiddly, so I recommend getting a decent magnifying glass and a soldering iron with a fine tip. I’m definitely not the worlds best solder-er but I managed it okay.
* – I forget the actual name or catalogue reference, they’re pretty cheap (less than a pound I think) and are sold in rows of about 20 or so. You just snap off two rows of 10 each and get on with it.
Posted by Tom