I was asked to demonstrate the use of an iPhone in Engineering at Saturday's alumni open day. I demonstrated
AutoDesk ForceEffect Motion (which is pretty good fun) on the iPad rather than iPhone, but also demonstrated using the iPad to send tweets to the department's Twitter account (
@le_engineering), which was more fun for me to do. I had a Python program running on my Linux netbook, which checked Twitter for mentions of @le_engineering, and then searched the rest of the text for the characters R, G, r, g, b and 1 or 0. These characters were sent via USB to an Arduino, which interpreted them as commands to light (uppercase) or turn off (lowercase) a red and green LED, sound a buzzer, or move a servo to 90 or 0 degrees.
Code for Python on Linux.
I used the OpenAuth keys generated
here. I hadn't appreciated how great
pickle is until now. Because of Twitter's limits on API calls, and the fact that I wasn't expecting vast numbers of tweets (in the event, I was the only person who used this), I got the program to check the feed once every minute, and to stop after ten minutes. Needs to be run under sudo, or you need to add your own account to the dialout group (
sudo adduser $USER dialout) to be able to write to the serial port. Obviously, you need to change the port device (currently
/dev/ttyACM0) if that isn't the serial port your Arduino is attached to.
#!/usr/bin/python
import twitter, serial, sys, time, pickle
try:
ser = serial.Serial(port="/dev/ttyACM0", baudrate=9600, timeout=0)
# Allow the port to wake up, if using this in non-interactive mode
time.sleep(0.5)
except:
print "Failed to open port."
# Load the times of tweets that have already been dealt with (into a set).
times_seen = pickle.load(open("times-seen.dat"))
oauth_file = open("access_token.txt", "r")
akey = oauth_file.readline().rstrip()
asec = oauth_file.readline().rstrip()
consumer_file = open("consumer_keys.txt", "r")
ckey = consumer_file.readline().rstrip()
csec = consumer_file.readline().rstrip()
try:
api = twitter.Api(consumer_key=ckey, consumer_secret=csec,
access_token_key=akey, access_token_secret=asec)
except Exception as e:
print e
else:
for i in range(10):
# Check the twitter feed every minute for ten minutes
# (API limit is 100 calls per hour)
print "Minute {0}/10".format(i)
try:
mentions = api.GetMentions()
for m in mentions:
t = m.GetCreatedAt()
if t in times_seen: continue
times_seen.add(t)
print "{0}: {1}".format(m.GetUser().name, m.text)
text = m.text.replace("@le_engineering", "")
for c in text:
try:
if c in "rgRG10b":
print c,
ser.write(c)
time.sleep(1)
except:
pass
print
except twitter.TwitterError as te:
print te.message
time.sleep(60)
# Save the time of tweets already dealt with.
pickle.dump(times_seen, open("times-seen.dat", "w"))
print "Done."
Arduino code.
Not much to say about this. The playTone function is ripped off from
Oomlout, but all this program really does is check for incoming characters on the serial port, and perform an action if a valid character is found.
#include <servo.h>
Servo myservo;
int green_led = 7;
int red_led = 6;
int speaker = 5;
int servo_pin = 3;
void playTone(int tone, int duration) {
for (long i = 0; i < duration * 1000L; i += tone * 2) {
digitalWrite(speaker, HIGH);
delayMicroseconds(tone);
digitalWrite(speaker, LOW);
delayMicroseconds(tone);
}
}
void setup() {
pinMode(green_led, OUTPUT);
pinMode(red_led, OUTPUT);
pinMode(speaker, OUTPUT);
myservo.attach(servo_pin);
myservo.write(0);
playTone(1000, 500);
Serial.begin(9600);
}
void loop() {
byte command;
int i;
if (Serial.available())
{
command = Serial.read();
Serial.write(command);
switch (command)
{
case 'G': digitalWrite(green_led, HIGH); break;
case 'R': digitalWrite(red_led, HIGH); break;
case 'g': digitalWrite(green_led, LOW); break;
case 'r': digitalWrite(red_led, LOW); break;
case 'b': playTone(2000, 500); break;
case '0': myservo.write(0); break;
case '1': myservo.write(90); break;
default: break;
}
}
}
Hardware
Thanks to
Fritzing,which I found thanks to
John Boxall's book
Arduino Workshop. The capacitor linked to the reset pin is in there because in an earlier iteration of this, I was attaching it to a web server rather than sending it instructions from a Python program. Without the capacitor, the system reset every time a new serial connection was made, which wasn't the behaviour I wanted.
This explains why, and how to fix it.
just to let you know where it says #include the s in servo has to be a capital
ReplyDelete