Showing posts with label arduino. Show all posts
Showing posts with label arduino. Show all posts

Tuesday, July 30, 2013

Twitter, again


Using the Arduino ethernet shield on the Mega 2560 Arduino, this displays tweets.  But not directly - Twitter's new API requires SSL, and the Arduino isn't up to doing that.  So I set up a CGI program on my desktop computer which checks a twitter feed, and returns a plain text version of the username and message.  Code for the CGI program:

#!/usr/bin/python

import twitter, sys, time, pickle

class Timeline:
    def __init__ (self):
        self.seen = set()
        self.cache = []

    def add_to_cache (self, statuses):
        for d in [s.AsDict() for s in statuses]:
            if d["id"] not in self.seen:
                self.seen.add(d["id"])
                self.cache.append(d)

    def __iter__ (self):
        return self

    def next (self):
        if len(self.cache) == 0:
            raise StopIteration
        else:
            return self.cache.pop()
 
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:
    try:
        timeline = pickle.load(open("timeline.dat"))
    except:
        timeline = Timeline()

    timeline.add_to_cache(api.GetUserTimeline("LE17RH"))

    print "Content-type: text/plain\n"
    try:
        x = timeline.next()
        print x["user"]["screen_name"]
        print x["text"]
    except StopIteration:
        pass

    pickle.dump(timeline, open("timeline.dat", "w"))

The Timeline class is an iterator because in an earlier incarnation I was loading a lot of tweets and wanting to iterate over them, it isn't necessary for this program which just returns a plain text rendition of one username and message.

Code for the Arduino:

#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>

byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0x7F, 0xB6 };
const IPAddress ip(143,210,109,74);
const IPAddress dnsserver(143,210,12,154);
const IPAddress server(143,210,108,92);
const char get_header[] = "GET /cgi-bin/twittino.cgi";
const char server_header[] = "Host: 143.210.108.92 80";

EthernetClient client;
LiquidCrystal lcd(8, 9, 17, 16, 15, 14);

const int SDSELECT = 4;
const int PIN_G    = 21; // Pins on Mega board!
const int PIN_R    = 20;
const int PIN_B    = 19;

void setup() {
  pinMode(PIN_R, OUTPUT);
  pinMode(PIN_G, OUTPUT);
  pinMode(PIN_B, OUTPUT);
  pinMode(SDSELECT, OUTPUT);
  digitalWrite(PIN_R, HIGH);
  digitalWrite(PIN_G, LOW);
  digitalWrite(PIN_B, HIGH);
  digitalWrite(SDSELECT, LOW);
  Serial.begin(9600);  
  lcd.begin(16, 2);
  Ethernet.begin(mac, ip, dnsserver);
  delay(1000);
  digitalWrite(SDSELECT, HIGH);
  Serial.println(Ethernet.localIP());
  digitalWrite(PIN_G, HIGH);
}

void loop()
{
  static int counter = 1;
  char username[30];
  char tweet[141];
  
  Serial.println(counter++);
  
  if (client.connect(server, 80)) 
  {
    // Serial.println("Connected");
    // Make a HTTP request:
    client.println(get_header);
    client.println(server_header);
    client.println("Connection: close");
    client.println();
    int ulen = 0;
    int tlen = 0;
    boolean username_found = false;
    while (client.connected())
    {  
      if (client.available()) 
      {
        char c = client.read();
        if (!username_found)
        {
          if (c == '\n')
          {
            username_found = true;
            username[ulen] = '\0';
          }
          else
          {
            if (c != '\n') username[ulen++] = c;
          }
        }
        else
        {
          if (c == '\n') 
          {
            tweet[tlen++] = ' ';
          }
          else
          {
            tweet[tlen++] = c;
          }
          switch(c)
          {
            case 'R' : digitalWrite(PIN_R, LOW); break;
            case 'G' : digitalWrite(PIN_G, LOW); break;
            case 'B' : digitalWrite(PIN_B, LOW); break;
            case 'r' : digitalWrite(PIN_R, HIGH); break;
            case 'g' : digitalWrite(PIN_G, HIGH); break;
            case 'b' : digitalWrite(PIN_B, HIGH); break;
          }
        }
      }
    }
    client.stop();
    // Serial.println("Disconnected");
    tweet[tlen] = '\0';
    if (ulen != 0 && tlen != 0)
    {
      Serial.print("Username : ");
      Serial.println(username);
      Serial.print("Tweet    :\n");
      Serial.println(tweet);
      lcd.setCursor(0, 0);
      for (int i=0; i < ulen; i++)
      {
        lcd.print(username[i]);
      }
      for (int i=0; i <= tlen; i++)
      {
        lcd.setCursor(0, 1);
        for (int j=0; j < 16; j++)
        {
          if (j + i < tlen) lcd.print(tweet[j+i]);
        }
        lcd.print(' ');
        delay(500);
      }
    }
    else
    {
      Serial.println("Nothing.");
    }
  } 
  else 
  {
    Serial.println("Connection failed.");
  }
  delay(10000); // Check every 10 seconds
  lcd.clear();
}

Things to note: the SD card, if present, needs to be deactivated (by setting SD_SELECT, pin 4, to LOW) before setting up the ethernet connection.  In addition to the LCD panel, I have one of my RGB LED units connected, and if there is a capital R, G or B in the tweet, the appropriate colour is displayed (the lowercase equivalents turn the colour off).  The username is displayed on the top row of the LCD panel, and the tweet scrolls along the bottom row.

 

Friday, July 26, 2013

Shift Registers

I bought a "Nano 3.0 for Arduino" for eight quid - a neat little thing that reminds me of the Hexbug Nanos I bought my niece and nephew for Christmas a couple of years ago, but is rather more interesting for grownups.  It fits directly into a breadboard, and is powered and programmed through a USB lead (standard "mini A" connector).


The pins are:

Top row: digital pins D12 to D2 (D2 is just above the TX LED), ground, reset, RX and TX (RX and TX are D0 and D1 on an Arduino Uno).

Bottom row: digital 13, 3.3 V, REF (analogue reference, labelled AREF on bigger boards), analogue inputs A0 to A7 (two more than on the Uno, A7 is just below the LED), 5 V, reset, ground, and input voltage (VIN).

This is almost, but not quite, the same layout as the official Arduino Nano, and considerably cheaper.  I stuck it on a breadboard with a couple of shift register chips (74HC595), and used it to control some RGB LED units.

The RGB units have three LEDs with a common anode, so controlling four of them requires twelve bits.  I've used two shift registers, so that gives sixteen bits to play with.

A diagram is below.

Things to note: the board shown in the diagram doesn't have the same pin order as mine, and my breadboard (see below) has a very different layout but the circuit is the same.  The connections from the board are: 5V pin to the top power rail (which is then linked to the lower power rail in the middle, and the bottom power rail), ground pin to the top ground rail (similarly linked to the middle and bottom), and the SPI connection to the first shift register: blue wire links D2 to the data pin on the 74HC595, green wire links D4 to the latch pin, and yellow wire links D3 to the clock pin.

The two 74HC595 chips have the clock and latch pins linked (horizontal green and yellow wires), and the serial output from the first goes to the data pin on the second (horizontal blue wire below the yellow one).  This means that when two bytes are sent into the first chip, the first byte is displaced into the second chip (you can chain these things even further - so if you had four linked chips and sent four bytes into the first one, the fourth chip would contain the first byte sent, the third chip the second byte, the second chip the third byte and the first chip the fourth byte).

I have only shown the connections for one of the LED units - the horizontal red, blue and green wires connect from pins Q3, Q2 and Q1 of the first 74HC595 to the cathodes of one of the LED units.  Pins Q7-Q5 of the first 74HC595 go to the RGB cathodes of the second unit, and the third and fourth units are connected to the same pins on the second 74HC595.  On my breadboard (see below) there are no wires making these connections - I just bridged the pins of the 74HC595 chips to the LED units with resistors (270 Ω).

I'm not using pins Q0 or Q4 on either 74HC595 - they aren't needed (and Q0 is in a slightly inconvenient position, on the other side of the chip to the other seven output pins, next to the data pin).


Code:

const int latchPin = 4;
const int clockPin = 3;
const int dataPin  = 2;

const byte red     = 0x08;
const byte green   = 0x02;
const byte blue    = 0x04;
const byte yellow  = red   | green;
const byte magenta = red   | blue;
const byte cyan    = green | blue;
const byte white   = red   | green | blue;
const byte black   = 0x00;

const byte sequence[8] = {black, red, yellow, green, 
  cyan, blue, magenta, white};

void put_four_leds(byte leds[4])
{
    byte a = leds[0] | (leds[1] << 4);
    byte b = leds[2] | (leds[3] << 4);
    
    digitalWrite(latchPin, LOW);
    // Flip bits because low is on, high is off
    // Second pair goes first because that byte is shifted
    // through to the second shift register. 
    shiftOut(dataPin, clockPin, MSBFIRST, ~b);
    shiftOut(dataPin, clockPin, MSBFIRST, ~a);
    digitalWrite(latchPin, HIGH);
}

void setup() 
{
  //set pins to output so you can control the shift register
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() 
{
  byte led_array[4];
  int  i, j;
  
  for (i=0; i<8; i++)
  {
    for (j=0; j<4; j++)
    {
      led_array[j] = sequence[(i + j) % 8];
    }
    put_four_leds(led_array);
    delay(500);
  }
}
 
 

Monday, July 1, 2013

Open Day, Part II

The main things I learned from the open day:
  1. It is possible to mull over these things for a few weeks when you are too busy to do anything serious, and then put in a few hours' work late on a Friday afternoon and come up with something working.
  2. iPads are fun, and there are some great apps to do serious engineering, but you can't hack those apps, and you can't do much to hack the iPad.  You get to do what Apple, and Apple-approved developers, allow you to do.  Which is a great deal, but it's not the sort of activity that engineers find really satisfying (and despite the fact that I'm an ex-geochemist with a master's degree in philosophy, I still consider myself a kind of engineer).
  3. On Friday afternoon, I needed the python-twitter library to check the twitter feed from Python.  Downloading and installing it via apt-get from the Ubuntu repository took a few seconds. When I realised I needed a newer version to cope with changes in Twitter's API, it took a couple of minutes to find the newer version, download it and install it.  If I had been using the locked-down campus version of Windows, it would not have been that trivial. Perhaps not even possible. Linux makes it much, much easier to do this sort of thing.
  4. I enjoyed myself more late on Friday afternoon than I had done for weeks doing more "important" things.  It really fired my enthusiasm for using these things in next year's programmable electronics module (I have sixty kits sitting in a cupboard), and encouraging students to play around with them and see what they can do.
  5. I thought I had fried the GPIO port on my Raspberry Pi.  A morning sitting in a room with disappointingly few visitors meant I had time to do some troubleshooting with a multimeter, and it turned out to be a broken connection on the ground rail of one of my breadboards, which was a relief.  I love my multimeter.
  6. To some visitors, sending a tweet to turn on an LED was like magic.  To some, it was deeply unimpressive.  Only colleagues were able to grasp how much was really going on between pressing the send button on the iPad, and the red and green lights coming on.

Open Day, Part I

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.

Friday, December 16, 2011

A stack on the Arduino



 I have put together a collection of Python scripts which allow me to build proper C++ programs for the Arduino Uno and Mega 2560 from the command line, and upload them all in one go. At the moment, these are only working in Linux but I think I know enough now that in principle I could get this going on Windows, possibly within Dev-C++ - a project for after Christmas, I think.

Wednesday, December 14, 2011

Home Made

I used to be really, really terrible at soldering things. Thank goodness for instructional videos on YouTube. The board was programmed by the method described in the previous post.

Bypassing the IDE

A colleague has objected, justifiably, that the Arduino can't be used for teaching C/C++ as it stands because of the way the environment works (hiding the main function, and confusing issues of scope, global variables, etc).  Judging by a conversation I had this afternoon there is probably no money in the equipment budget to buy fifty of the things for next year's programming course anyway, but it would be nice to try.  There are various tutorials on the web dealing with using the avr-gcc compiler directly, mainly reliant on using modified makefiles.  The Arduino 1.0 release seems to have broken these (some of the files are now in different directories, some have disappeared), so I tried looking at the output if you ask the Arduino environment to give detailed output on compilation and upload (in File / Preferences).

Friday, December 9, 2011

Arduino classes

Underneath the Arduino programming environment is C++, but I didn't think I'd be trying to find my copy of Leendert Ammeraal's C++ for Programmers this Friday afternoon (I have Stroustrup, of course, but it's not a book to find a quick and easy solution in).  I hooked up four of the RGB LED units to the Arduino Mega's 12 PWM pins, and wanted to implement a little algorithm I had run with one unit earlier in the week - set a random "target" value for the RGB values, gradually increase (or decrease) the intensity to reach the target, and then set a new random target.  The effect is to gradually change the colour and intensity of each unit, but in a pleasant drifting manner rather than jumping around all over the place.  Once I had written the code, I looked for ways to make it simpler - first using a struct, but there are difficulties writing functions for the Arduino which take a struct as a parameter (as I understand it, the pre-processor shuffles the code around so that your function ends up before the struct declaration, which means the compiler doesn't recognise the struct when it comes to compile the function).  The answer was to go straight to writing a C++ class, which turned out to be fairly simple (though I did try writing a proper constructor function, and was reminded what a complete bloody nightmare that can be especially on a Friday afternoon in a very warm office when you haven't written any O-O C++ code for about a decade - once you start dabbling in constructors, you need to think hard about copy constructors, destructors, deep and shallow copies, all that stuff).


Arduino Mega and ethernet shield

I bought an Arduino Mega 2560 to reward myself for doing well in a philosophy module.  To connect it to the ethernet shield, the solution in the Arduino forum works - connect pins 11, 12 and 13 on the ethernet shield to 51, 50 and 52  on the Mega (in that order, of course).

Edit: the Mega sorted out the problems I'd been having with getting a web server to read off the SD card - with the Arduino Uno it kept falling over and resetting the board, with the same code on the Mega I was able to run a slow, but quite usable, server.

Thursday, December 8, 2011

Scrolling text with shift registers

Using a couple of 74HC595 shift registers, I have done away with most of the wires leading from the Arduino to the breadboard. This also simplifies the code - simply send a couple of bytes to the first shift register, and the data sorts itself out (the first byte is displaced by the second one and flows into the second shift register - I will probably add a third to the chain, to control the green LEDs).  The text is now proportionally-spaced, rather than using 8 pixels per character.

Edit: adding a third shift register to the chain worked, but at the price of making the display rather dim (because of the time spent transferring all the data, I suspect).  The green LEDs aren't as bright as the red ones, which made the effect worse - the red ones were just about acceptable.

Wednesday, December 7, 2011

Space invaders!


This is heavily adapted from the code on the Oomlout web site. I'm defining "sprites" called invader1, invader2 and blank, then in the loop() function I have an array of pointers to these sprites. There is an array led_state which stores the current state of the LED array, and at each cycle I am shifting every row rightwards and overwriting with the relevant portion of the next sprite. There is a lot of bit-masking and shifting going on. The next project is to replace the unwieldy wiring by using the shift register chips which are visible on the bottom right of the video - as described on the Arduino website.

Friday, December 2, 2011

Another web server

Still not much of a server - it is simply sending back the same page whatever the client requests.  But I have set it up so that the values of the three potentiometers change the colour of the background of the page, and it displays the values of the temperature sensor and light sensor. Apologies for the blurriness of some of this - the Flip camera doesn't do close-ups very well (or maybe I haven't worked out how to make it do close-ups).


My own web server

This is adapted to some extent from the web server and SD code examples. As with the web server example, this is currently interpreting any HTTP request as GET / HTTP/1.1 - the twist is that it is reading index.htm from the SD card, and serving that. If it can't open and read index.htm, it sends a 404 response. I've also written a function which reads in the request headers one line at a time, and the server then prints them to the serial console (a little like the error log on a full-sized server, and I'm intending to try to use that information later on).

Thursday, December 1, 2011

Arduino web server


Considering I had no experience using these things this morning (although I read Massimo Banzi's Getting Started with Arduino while on strike yesterday), I think this is pretty good.

LED matrix

What the life of man is like in the state of nature according to Thomas Hobbes. I had to make minor modifications to the code (renaming a variable from A3 to A33), but this is entirely from http://oomlout.com/LEDMS including the wiring. I am impressed that I managed to wire it all up correctly first time, though. Hobbes's life was none of these things, of course.
Thomas Hobbes's Grave
Here are buried the bones of Thomas Hobbes of Malmesbury who for many years served the two Earls of Devonshire, father and son. A sound man and well known at home and abroad for the renown of his learning. He died in the year of our lord 1679 on the 4th day of the month of December in the 91st year of his age.

Arduino



Not the most impressive program I have ever written, but considering the Arduino only arrived this morning it's not a bad start (I also have an 8x8 LED array which I will be playing around with later). Setting up the Arduino development environment on Linux was simple: downloaded and unzipped the IDE, installed the gcc-avr and avr-libc packages, and added myself to the dialout group (sudo usermod -aG dialout nja) as described on this page. [Edit: on my home netbook, running Ubuntu 11.10 rather than Linux Mint, I had to edit /hardware/arduino/cores/arduino/wiring.h and comment out the line starting #define round (line 79), as described here]

const int RED_LED = 9;
const int AMBER_LED = 10;
const int GREEN_LED = 11;
const int ON = 0xFF;
const int OFF = 0x00;

void setup()
{
  pinMode(RED_LED, OUTPUT);
  pinMode(GREEN_LED, OUTPUT);
  pinMode(AMBER_LED, OUTPUT);
}

void loop()
{
  analogWrite(AMBER_LED, OFF);
  analogWrite(RED_LED, ON);
  delay(1000);
  analogWrite(AMBER_LED, ON);
  delay(1000);
  analogWrite(RED_LED, OFF);
  analogWrite(AMBER_LED, OFF);
  analogWrite(GREEN_LED, ON);
  delay(1000);
  analogWrite(AMBER_LED, ON);
  analogWrite(GREEN_LED, OFF);
  delay(1000);  
}