Let’s say you have a Spark core with both a Spark variable and a Spark function. In my case, I have the world’s simplest servo control sketch, using the nice miniature servo in the Spark Maker Kit. Using these parts, we will build a servo that you can control from a web page anywhere and monitor the position of the servo too!
Here’s a preview of the finished tutorial:
There is a coarse adjust slider, two fine adjust buttons, and the current position of the servo is displayed. That thing on the right, is the servo with a white control arm; it is being held in a small vise in front of screen.
The Wiring
Servos are easy to interface to and the Spark core has the servo library built-in, so there is no need to include a library. The servos that we use mostly come from the model airplane, helicopter, and boat world and are designed to work on a 4.8V battery pack. So you need to use a +5V supply for the servo, which is close enough. If you only have one small servo to drive, you don’t need a separate supply, but big servos can draw a lot of current and the motors can be electrically noisy, so use a separate power supply in that case and just tie the grounds together.
Servos are controlled using a PWM signal that always has the same frequency but varies in term of duty-cycle. The more time the control signal is high (greater dut-cycle), the more the servo will move in one direction. When the duty-cycle is lower and the control spends less time high, the more the servo will move in the other direction.
Servos generally run from 0 to 180 degrees with 90 degrees being the neutral, or mid-point. As we shall see, the servo stops are not always perfectly at 0 and 180 and you might some testing per servo. The servo library has a way to deal with that, if you need it.
Here is how we wire it up:
And a wider shot showing the actual servo with a white control arm stuck on it:
A +5V supply voltage comes in from the top of the picture and is connected to the power rails on the bread board. The core VIN pin is wired to +5V (Warning: don’t connect that to any other pin or you will damage your core!). A core ground pin is connected to the ground or negative supply rail.
Now for the servo, we can use that standard Maker Kit jumper wires to connect to it and just push the pins into the servo connector. Use a red jumper wire to connect the +5V rail to the middle red wire on the servo connector. Use a black jumper wire to connect the bread board ground rail and the brown outside wire on the servo connector. Finally use a white jumper wire to connect core pin A0 the remaining yellow wire on the servo connector. Note that only certain pins on the Spark core can run servos since making the PWM waveform the control input to the servo requires a timer on the core; see the documentation for the details. The servo will work fine with a 3.3V control signal, so no need for a level shifter.
That completes the wiring. Two power wires for the core, two for servo, and one control wire–pretty simple.
(moors7: A0 won’t work for the Photon, use any of the following and change the code accordingly: D0, D1, D2, D3, A4, A5, WKP, RX, and TX. See these docs.)
The Code
This may be the shortest sketch I have ever written. By using a Spark function to set the servo position and a Spark variable to report the servo position, there is not a lot of core to write:
Servo myservo; // create servo object to control a servo
int pos = 0; // variable to store the servo position
void setup()
{
myservo.attach(A0); // attaches the servo on the A0 pin to the servo object
Spark.function("setpos", setPosition);
Spark.variable("getpos", &pos, INT);
}
void loop()
{
}
int setPosition(String posValue) {
pos = posValue.toInt();
myservo.write(pos);
return 0;
}
A few things to note here. The loop() function does nothing in this sketch, all the work is done by the Spark function and variable. We are using a int
for the datatype of the position, just because that is easier to declare as a Spark variable. Note that we could have read the servo position from the myservo
object, but it would be the same value we just wrote anyway. The servo position in these small servos is not read back in any way, you just tell the servo where you want it to be. There are some more expensive servos where you can read the actual position back in the processor, and we would need an analog input to read that as voltage if we had one of those.
Also the myservo.write(pos)
function limits the possible values to 0 to 180 by default, so we don’t have to do any bounds checking or limiting on the position variable.
Since a Spark function always takes a String argument, we use the String toInt()
method to convert it to a number. The return value is set to zero here and not really used, but generally the return value of a Spark function should be used to indicate success or error of the command.
Notice that I have named by function and variable set
and get
, just like an object method.
The Web Side
So far, things have been really easy, but now things are going to pick up a bit. First a word of friendly advice: don’t expect video game type interactivity from the Spark cloud. You can get good performance, but you can only go so far. As I have said before, my house is over an 1/8 of second away from the Spark cloud in my testing, so you should expect near real-time, not hard real-time control to be possible here. Ok, that’s out of the way!
Remember, we are going to put our access token in the HTML file, so keep it private. I like to put mine on a service like Dropbox so I can access them from many computers and even my phone, but I never put the file on the public internet.
Here’s the code:
<!DOCTYPE HTML>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<body>
<P>Set Servo Position:<br><br>
<input type="range" name="degBox" id="degBoxId" min="0" max="180" step="1" value="90" list="myData" onchange="setValue(this)">
<!-- This adds the tick marks to the range but does not in Safari -->
<datalist id="myData">
<option value="0">
<option value="30">
<option value="60">
<option value="90">
<option value="120">
<option value="150">
<option value="180">
</datalist>
<br><br>
<button id="minusbutton" onclick="fineAdjust(-5)">⇐ -5 °</button>
<button id="plusbutton" onclick="fineAdjust(+5)">+5 ° ⇒</button>
<br><br>
<P>Current Position: <span id="curPos"></span><br>
<script type="text/javascript">
var deviceID = "<< device id >>";
var accessToken = "<< access token >>";
var setFunc = "setpos";
var getFunc = "getpos";
window.setInterval(function() {
requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + getFunc + "/?access_token=" + accessToken;
$.getJSON(requestURL, function(json) {
document.getElementById("curPos").innerHTML = json.result + "°";
document.getElementById("curPos").style.fontSize = "28px";
document.getElementById("degBoxId").value = parseInt(json.result);
});
}, 1000);
function setValue(obj) {
var newValue = document.getElementById('degBoxId').value;
sparkSetPos(newValue);
}
function fineAdjust(value) {
var currentValue = parseInt(document.getElementById('curPos').innerHTML);
var setValue = value + currentValue;
sparkSetPos(setValue);
document.getElementById("degBoxId").value = setValue;
}
function sparkSetPos(newValue) {
var requestURL = "https://api.spark.io/v1/devices/" +deviceID + "/" + setFunc + "/";
$.post( requestURL, { params: newValue, access_token: accessToken });
}
</script>
</body>
</html>
OK, so we are using AJAX and jquery again to do HTTP GET and POST request to the Spark cloud, so we load up the jquery library. Then we define an input range selector. This can look different in different browsers but it is generally rendered as a slider control. The datalist
markup command is new in HTML5 and lets you have an enumerated value or in our case adds little tick marks to the slider scale and makes the slider want to “snap” to those values. You can hit values between the tick marks, but if you are close, it will try snap to the grid we have setup. Note that the datalist
markup does not work in Safari or mobile Safari–you just don’t see the tick marks at all.
Then there are two buttons for fine adjustments that add or subract 5 degrees from the current angle. Finally we have a span that represent the current value of the servo position, based on the last setting we sent down.
The next section is the Javascript code that does all the real work. First we assign some variables with our device ID and access token (don’t forget to edit these in) and then names of our Spark function and variable, in case your want to change them later.
Now we have window.setInterval()
javascript function with 1 second interval that gets the value of the Spark variable from the core and does two things with it. First it displays the value in the span we set up for that, but then it finds the slider input control and forces the current vale to be value got back from the core.
This has good and bad effects! First off, we can now be sure that whenever we reload the web page, the slider starts in the right position relative to the current servo position. Any time we click to update the slider, the slider will move to the actual set position of the servo in no more than one second. But the down side is that if we drag the slider around quickly, this forces a jumpy and sometime awkward motion of the slider.
Next up we have the setValue
function which just gets called when the value of the slide control changes. It calls a helper sparkSetPos
that does the actual command to POST the Spark function on the core.
We also have the fine adjust function that is called for both of the fine adjust buttons with either a +5 or -5 argument. I tried setting that to +/- 1 degree but it was hard to see how much it moved!
So on the web side, we have $.getJSON
to read the Spark variable and $.post
to call the Spark function.
So, How Does it Work?
It works great! You can click on the slider and move quickly to any position. You can click and hold the slider and it might jump around a bit, but it will eventually land where you let go. You can use the fine adjust buttons to move +/- 5 degrees and the servo and the slider are both updated.
I have not had any luck making movies that are small enough to upload here and yet have enough detail to read, so I have a series of photos showing both the screen and the servo held up in a small vise in front of the screen. The servo is held sideways, so 90 degrees is straight up and down. I probably should have flipped it over in the vise since greater angles move the top of the arm to left in the photos.
Now click on the 150 mark, moving the top of the arm to the left:
Now click on the 180 mark, moving the arm again to left horizontally.
Now back the other way to 60 degrees:
And then all the way to zero, but notice that 0 degrees is past horizontal–we can correct for this in the attach() call on the core:
Now back to 90 and we try to fine adjust buttons:
Wrapping it up
So now I just have to think of something as clever as the Facebook Like’s Push-up Monitor to use this for! You can think of your applications as well, and not just for servos. Anytime you need to set and get values using the Spark cloud.
Now we have a complete set of tutorials: you can read Spark published values in plain and JSON format, you can monitor Spark variables either on command or continuously, and now you can both control things via Spark functions and monitor them via Spark variables, all from your own Javascript/AJAX web pages. Go have fun!