###XP Summary
Today we are going to look at a servo. In particular, we are going to look at how a servo can deliver us chocolate. (Here is a link to my favorite song about chocolate — Warning: not for the weak. And here are the lyrics)
A servo is a motor that can turn a specific number of degrees. For example, we can tell a servo to move exactly 45 degrees and then change direction and move 10 degrees. There are many uses of servos including
We are going to use a servo in its most important role: Delivering M&M candies!
Before you continue make sure to put an arm on the servo. It just makes it more fun!
#include <Servo.h>
Servo myservo;
int button = 2;
int servoPin = 16;
int pos = 0; //variable to keep track of the servo's position
bool flag = 1; //variable to keep track of the button presses
void setup() {
pinMode(button, INPUT_PULLUP);
Serial.begin(115200);
myservo.attach(servoPin); //Initialize the servo attached to pin 16
myservo.write(180); //set servo to furthest position
delay(500); //delay to give the servo time to move to its position
myservo.detach(); //detach the servo to prevent it from jittering
}
void loop() {
if(digitalRead(button) == LOW) //if a button press has been detected...
{
//This is known a s state machine.
//It will move the servo to the opposite end from where it's set currently
if(flag == 1)
pos = 0;
if(flag == 0)
pos = 180;
myservo.attach(servoPin);
myservo.write(pos);
delay(500); //debounce and give servo time to move
myservo.detach();
flag = !flag; //set flag to the opposite of what it's currently set to
Serial.println(pos); //prints to the serial port to keep track of the position
}
}
When you first upload the code, give it a few seconds, then you should see the motor move to the 180° position. Once there, it will stay until the button is pressed. Press the button to move it to 0°. Press the button again and it will move back to the first position. The purpose of this code it to give you an idea for the full range of motion for the servo motor and to help you plan out your M&M Feeder. The code above is my slightly modified version of code written by the folks at Sparkfun. (Sparkfun, in addition to having super nice people, has a wide assortment of really cool electronic gizmos – check it out). Anyway, the software developer in me never was 100% happy with that code. I don’t like this bit:
if(flag == 1)
pos = 0;
if(flag == 0)
pos = 180;
So here is my reworked version:
#include <Servo.h>
Servo myservo;
int button = 2;
int servoPin = 16;
int pos = 0; //variable to keep track of the servo's position
int max_position = 360;
void setup() {
pinMode(button, INPUT_PULLUP);
Serial.begin(115200);
myservo.attach(servoPin); //Initialize the servo attached to pin 16
myservo.write(180); //set servo to furthest position
delay(500); //delay to give the servo time to move to its position
myservo.detach(); //detach the servo to prevent it from jittering
}
void loop() {
if(digitalRead(button) == LOW) //if a button press has been detected...
{
myservo.attach(servoPin);
myservo.write(pos);
delay(500); //debounce and give servo time to move
myservo.detach();
Serial.println(pos); //prints to the serial port to keep track of the position
pos = (pos + 180) % max_position;
}
}
Anyone who know me knows I love, love, love the modulo operator, % that we see in this line:
pos = (pos + 180) % max_position;
The modulo operator gives us the reminder when we divide the first number by the second (think grade school math). So
4 % 2
is 0
because there is no remainder when we divide 4 by 2.
4 % 3
is 1 because when we divide 4 by 3 we have 1 left over and
26 % 5
is also 1 because when we divide 26 by 5 we have a remainder of 1. Finally,
5 % 25
is 5 because no 25s go into 5 so we have 5 left over.
So far so good.
So look at the code above and see what the values are of
pos
max_position
Take the time to actually look at the code while I count to 10
Okay, so
pos = 0
max_position = 360
One other thing I should mention. The maximum degrees our servo can turn is 180.
So our servo starts at 180 degrees. The first time we press the button we want it to move to 0. The second time we press the button we want it to move to 180. The third time 0, the fourth 180 and so on. pos
is initially zero so
myservo.write(pos);
is the same as
myservo.write(0);
and the servo moves to position 0. Good so far.
Then we execute my favorite line.
pos = (pos + 180) % 360;
So since pos is currently 0 this is the same as
pos = (0 + 180) % 360;
so that is 180 % 360
which is 180.
The next time we press the button and execute:
myservo.write(pos);
we go to position 180 and then execute our favorite:
pos = (pos + 180) % 360;
Since our current value of pos is 180 that equals (180 + 180) % 360
which equals 0. There is no remainder when we divide 360 by 360. So this line of our code makes the value of pos alternate between 0 and 180. Cool. Let’s say we want our button presses to do the following
So pos is initially zero. Each time we press we don’t want
pos = (pos + 180) % 360;
We are going to have to change that 180 and, especially important we need to change 360 because the servo can only move to 180 max.
Can you implement this?
If you do this (and understand it) you get the Modulo Merit Badge
For this you need to find a drink cap which you screw onto the arm of your servo.
![] (pics/cap00.png) photos by Sparkfun
Now load the original button code (the one that goes from 0 to 180). You will need to attach the cap arm assembly to the servo so that in the initial position the cap is upright and can hold an M&M, but when you press the button it dispenses the candy. You will need to alter the code so that when the button is pressed and the M&M delivered it, automatically resets back to the initial upright position.
You may want to put the servo assembly at the edge of a table weighed down by a book and test that it dispenses an M&M! Or, for creative xp you can construct a simple M&M delivery device! (this can also be your final project)
Let’s first setup things on the Adafruit IO side. Log into adafruit.io. You can use an existing dashboard or a new one. Add a new block to your dashboard
selecting the Momentary Button Block (the picture with the RESET button). On the Choose Feed panel create a new feed (I called mine MM).
On the Block Settings panel
Change the button text to something you like (in the above I did “M&M Please”) and change the color to something you like. The end result is:
.
The template for your code is in a zip file called deliverMM_template.zip. Then open it up in the Arduino IDE. You first need to change the config file. You need to change
#define IO_USERNAME "Your Username"
#define IO_KEY "Your key"
#define WIFI_SSID "ChangeMe"
#define WIFI_PASS "ChangeMe"
The code as is does the following. When you press the button on your dashboard, the number 1 is printed on the Serial Monitor. When you release the button, the number 0 is printed. Not very exciting. You need to add code to an M&M is dispensed when you press the button!
Instead of an edge of the table dispenser, can you make a more interesting one? 25xp for some device. 35 more for best dispenser in class, 25 for second, and 15 for third.
1: Tutorials are CC BY-SA 4.0. Original page at Sparkfun Inventor’s Kit for Photon. This chocolate remix by Ron Zacharski