Making a stamp from Sugru and a 3D printer

This evening my local MakerSpace is doing a Sugru challenge where we come up with fun and different uses for Sugru.

Sugru is a pliable substance that sets like silicone rubber at room temperature in a short time which means that it remains flexible once dry.

For my challenge entry I decided to do a rubber stamp using a 3D printer, open source software and Sugru.

My stamp is constrained by physical size – I could only source a small round stamp pad rather than the rectangular ones I am used to seeing and using. This meant that any design must fit within a circle with a radius of 3 centimetres (6 centimetres across).

I needed to get the software to design the stamp. I chose InkScape and a plugin for InkScape to convert the design to my preferred 3D design software.

My favourite 3D design software is OpenSCAD so I needed to get a plugin for InkScape to export in SCAD format. The plugin I use is called Paths to OpenSCAD which can take a vector image and convert it ready to be rendered to a STL (Standard Tessellation Language) file.

The 3D printers in MakerSpace are all set up to use PrintRun (PronterFace) which is a nice piece of software, if a tad slow when it comes to generating the models.

I’ll wait while you install everything.

Back so soon? Let’s continue.

Firstly, let’s design a stamp. This can be an elephant, a flower, a name, whatever. Be creative!

My stamp is going to be some text and a logo:
make it better
Simple enough but perfect for tonight’s challenge.

An issue you may need to plan ahead for when designing your own stamps is that any text or image must be large enough to be able to squeeze Sugru into. If using text, consider using a bold font.

Stage one: Create the stamp in InkScape

Don’t forget to draw a shape around the stamp so you know how large the stamp will be. It can be done later in OpenSCAD but is much easier to do here.

Having created your masterpiece you need to jump through a couple of hoops before it is ready to be converted for the next stage. It won’t take long.
We need to convert everything to vector format.
Click on the Edit menu, Select All
Click on the Path menu, Object to Path
Click on the Extensions menu, Modify Path, Flatten Beziers
Click Apply on the dialogue box.

Save your work.

Now we need to use the plugin Paths to OpenSCAD.
Click on Extensions, Paths to OpenSCAD.
In the dialogue box that appears, change the filename and save location if required. I chose stamp.scad
You can leave the other two alone, they can be changed later on in OpenSCAD.

Stage two: Import the stamp into OpenSCAD

Start OpenSCAD
Click on the File menu, Open
In the dialogue box that appears, find the SCAD file you just exported to (stamp.scad) and click the Open button.
On the left hand side of the page is the SCAD file you just loaded, the right hand side of the page will be blank apart from some intersecting lines.
Press F5 to render the stamp and the image will appear on the right after a short time.
If all you can see is the shape that surrounds the stamp, don’t worry – that is intentional.
If you can see the stamp but nothing surrounding it you forgot to add a shape around the outside of the stamp. Go back to InkScape, add one, go through the instructions above again and continue until you get back to here.

The code on the left hand side of OpenSCAD is not pretty. We need to determine the name of the shape surrounding the stamp. It’s easy to find.
Go back to the InkScape window and right click on the shape surrounding the stamp. In the menu that pops up, select “Object properties”. You will see a number such as g3013.
Go back to the OpenSCAD window, click in the left window and scroll down to the bottom of the page.
You will see a number of lines starting poly_path{something}(5);
Look for the one that is the same as the one above (in my case poly_path3013(5);).
We need to move that line so it is at the top of the list. Here is my list, yours will be different.

poly_path3011(5);
poly_path30330(5);
poly_path3013(5);
poly_path3015(5);
poly_path3017(5);
poly_path3019(5);
poly_path3021(5);
poly_path3023(5);
poly_path3025(5);
poly_path3027(5);
poly_path3005(5);
poly_path3029(5);
poly_path3007(5);
poly_path3009(5);
poly_path3033(5);

When I move the line, it now becomes

poly_path3013(5);
poly_path3011(5);
poly_path30330(5);
poly_path3015(5);
poly_path3017(5);
poly_path3019(5);
poly_path3021(5);
poly_path3023(5);
poly_path3025(5);
poly_path3027(5);
poly_path3005(5);
poly_path3029(5);
poly_path3007(5);
poly_path3009(5);
poly_path3033(5);

To make sure everything is OK, press F5 again. The picture should not change.
If you get an error, Click on the File menu, Reload. This will reload the file so you can try again. Do not save until everything works as intended.

Now we have the bounding box at the top of the list we are going to cut out the letters. We achieve this using the difference() command. We also need to move the letters up slightly, we achieve this using the translate() command.

Here goes:
Using the above as an example, change the code in the following way

difference()
{
poly_path3013(5);
translate([0, 0, 1])
{
poly_path3011(5);
poly_path30330(5);
poly_path3015(5);
poly_path3017(5);
poly_path3019(5);
poly_path3021(5);
poly_path3023(5);
poly_path3025(5);
poly_path3027(5);
poly_path3005(5);
poly_path3029(5);
poly_path3007(5);
poly_path3009(5);
poly_path3033(5);
}
}

Broken down step by step:
Before the first line that you moved to the top of the list earlier, add

difference()
{

After the first line that you moved to the top of the list earlier, add

translate([0, 0, 1])
{

At the end of the block, add

}
}

Press F5 to see the design. You should see the image something like this:
make it better-openscad
If you can, excellent work, you just created the guts of your first 3D printed stamp. High five!
If not, read the instructions again and if you’re stuck feel free to contact me. I read every comment and will happily try to help.

Save the OpenSCAD file.

Press F6 to render the file. This will turn it from a rough design into a nice 3D design ready for the next step.
When the image has finished rendering, click on the Design menu, Export as STL. If you see the message “Nothing to export!”, press F6 and try again. This will take a little time depending on the speed of your system. As you can see the image looks a lot nicer than the previous one.
make it better-openscad-rendered

Now we have the file converted to STL it can be loaded into the 3D printing software ready to print. In Pronterface you click the button marked “Load file” at the top centre of the screen and select the STL file generated above. Be prepared to wait a little while once you pressed the button, converting a STL file to GCODE (the language 3D printers use) is quite time consuming on some software.

Once the design has printed it is time to make the stamp itself.
Put some soapy water on the mould to prevent it sticking when the Sugru sets.
Get some Sugru and knead it for about a minute or so to soften it. When it is pliable put the printed design on a clean flat work surface (stamp facing up) and push the sugru into the gaps and over the printed stamp.
Turn the stamp over and place the sugru side down onto the table on top of some cling film. Press firmly but lightly on the plastic side so you have a flat rear side and the sugru pushed into all the nooks and crannies.
Gently peel the Sugru from the table, ensuring it stays in the mould.

Leave the Sugru for about 10 minutes to begin the hardening process and then gently peel the Sugru off the mould. If all went well the Sugru should come out as a mirror image of the original design. Let it set somewhere and then using your new stamp and a stamp pad begin claiming ownership of everything within arm’s reach. Except expensive stuff obviously. That’s mine. In fact, stick to paper and cardboard.

If you come up with a stamp you are super proud of, feel free to contact me and send me a stampout – I might even make a featured post out of it!

Adding custom commands to octoprint

To follow on from my last post about controlling a PSU with a transistor on a 3D printer running OctoPrint on a Sanguinololu board I have created a few custom buttons to increase the functionality of the software with these new features.

If not specified via the commandline, the configfile config.yaml for OctoPrint is expected in its settings folder, which is located at ~/.octoprint on Linux, at %APPDATA%/OctoPrint on Windows and at ~/Library/Application Support/OctoPrint on MacOS.

I added the following custom commands:
Turn PSU on
Turn PSU off
Get Position
Set Z10
Goto Z10

Shutdown octoprint, add this to the end of config.yaml and restart octoprint. note that the spacings are important.

controls:
  - name: Get Position
    type: feedback_command
    command: M114
    regex: "X:([0-9.-]+)Y:([0-9.-]+)Z:([0-9.-]+)E:([0-9.-]+)"
    template: "Position: X={0}, Y={1}, Z={2}, E={3}"
  - name: Power
    type: section
    children:
    - name: Turn on PSU
      type: command
      command: M42 S255 P30
    - name: Turn off PSU
      type: command
      command: M42 S0 P30
  - name: Z Commands
    type: section
    children:
    - name: Set Z10
      type: command
      command: G92 Z10
    - name: Goto Z10
      type: command
      command: G0 Z10

Controlling an ATX power supply (PSU) with a transistor

I have recently built a 3D printer. Yay me!

It is running OctoPrint which allows my 3D printer to be web accessible.

This is great except that as it stands I need to telephone my good lady Wife should I need to print anything while I am out – which surprisingly happens quite frequently – so she can turn on the PSU to allow me to print.

I use a standard ATX power supply to run my printer and wondered if I could use my printer’s control board (a sanguinololu) and a spare pin to turn on the PSU. It turns out that I can.
M42
Example: M42 P7 S255
M42 switches a general purpose I/O pin. Use M42 Px Sy to set pin x to value y, when omitting Px the LEDPIN will be used.

I have connected the control wire to pin A1 on the sanguinololu board, so to turn on and off the PSU I send:
To turn on:

M42 S255 P30

To turn off:

M42 S0 P30

The circuit I am using to turn the PSU on is as follows:
BC184L NPN Transistor

  []
 /|\
1 2 3
1 Emitter
2 Collector
3 Base

Connect Emitter (Pin 1) to Ground
Connect Collector (pin 2) to PS_ON (Green wire on ATX PSU)
Connect Base (Pin 3) to the pin you will be using on your control board via a 1KOhm resistor
[EMITTER>—GND
[COLLECTOR>---<PS_ON]
[DATA_PIN>—[1K]—[BASE>
I have colour coded the wires on my version to make identification easier:
Data pin: Blue wire
Emitter: Black wire
Collector: Green wire

Once you have soldered up your transistor and heatshrinked the legs for protection you can test the circuit just using the PSU by connecting the green and black wires as normal and using the 5VSB (purple) line to emulate the data line.
Connect the blue wire to the purple wire and the PSU should power up. Remove the blue wire and the PSU should power down.

Some PSUs require a load on the 5V line before they will power up, just connect a CD-ROM or (my preferred method) rewire a 12 volt fan so it is connected to the 5v line instead of the 12v line and plug that in.

212.3.208.65

I hope you are enjoying #algorithm :)

I guess you got here because you searched for the IP address 212.3.208.65 while watching algorithm.

What do you think so far?

Will they get together or has he spent too long in the Friend Zone?

Did you spot the camera crew in the black room reflected in the lightshade before it was turned on or in the aluminium foil in the same location?

Feel free to leave your comments about the movie :)

ArachnidLabs MiniShift arduino – the coding continues

So far I have modified my code to use control codes:
~b: display byte eg ~bf0 to show 11110000 on the display
~c: display character eg ~c41 to show ‘A’ (ASCII character 0x41) on the display
~i: invert data sent to the display eg ~i1
~m: display bytes in MSB or LSB order eg ~m0
~s: set speed between bytes sent eg ~s30 to leave a 30ms gap between bytes
~ : add trailing space after message eg ~ 1 to add trailing space
~~: display ~ character eg ~~

The serial port is set to run at 115200bps in this code to ensure data is transmitted in a timely manner.

As always, this is a work in progress and will grow as I think of more features.
file: minishift_text.ino

//Sample code to display text on the @ArachnidLabs minishift
// Written by Gregory Fenton, http://labby.co.uk

/*
Wiring:
 latchPin connected to CS   (pin 4) of minishift
 clockPin connected to SCK  (pin 3) of minishift
 dataPin  connected to MOSI (pin 5) of minishift
 */

#include "ascii8x8.c" // 8x8 font from PC

byte latchPin = 4;//53;
byte clockPin = 3;//52;
byte dataPin = 5;//51;

byte invert = 0;
byte interCharDelay = 50;
byte msb = 1;
byte showSpace = 0;

char s[257] =  { "~s32~b01~b02~b04~b08~b10~b20~b40~b80~b40~b20~b10~b08~b04~b02" }; //"ArachnidLabs minishift example by Gregory Fenton, labby.co.uk";

int hexToNybble(byte b)
{
        int p;
        if((b < '0' || b > '9') && (b < 'A' || b > 'F') && (b < 'a' || b > 'f'))
                return 0;
                
        p = b - 48;
        if(p > 9)
        {
                p -= 7;
                if(p > 15)
                        p -= 32;
        }
        return p;
}

void displayByte(byte b)
{
        digitalWrite(latchPin, LOW);
        shiftOut(dataPin, clockPin, msb == 0 ? LSBFIRST : MSBFIRST, b);
        digitalWrite(latchPin, HIGH);
}

void displayChar(byte c)
{
        byte i;
        for(i = 0 ; i < 8; i++)
        {
                displayByte(invert ? 255 - pgm_read_byte(font+(c * 8) + i) : pgm_read_byte(font+(c * 8) + i));
                delay(interCharDelay);
        }
}

void setup() {
        Serial.begin(115200);
        int i;
        //set pins to output because they are addressed in the main loop
        pinMode(latchPin, OUTPUT);
        pinMode(clockPin, OUTPUT);
        pinMode(dataPin, OUTPUT);

        //clear display by sending 256 blank bytes
        //256 is arbitrary and should be changed to the number of
        //columns in your display
        //sprintf(s, "Greg");
}

void loop() {
        int i = 0, l;
        byte m, n, o, p;
        char c;

        while(Serial.available())
        {
                c = Serial.read();
                s[i++] = c;
                if(!Serial.available() || i == 256)
                {

                        Serial.flush();
                        s[i++] = 0;
                        Serial.println(s);
                }
        }

        for(i = 0; s[i] != 0 && i < 256; i++);
        l = i - 1;

        for(i = 0; i <= l; i++)
        {
                o = 255;
                if(s[i] == '~')
                {       
                        if(i < l - 1)
                        {
                                m = s[i + 1];
                                n = s[i + 2];
                                switch(m)
                                {
                                case ' ': //Show trailing space
                                        showSpace = n & 1;
                                        o = 0;
                                        break;
                                case 'S': //set speed
                                case 's':
                                        o = s[i + 3];
                                        i++;
                                        interCharDelay = hexToNybble(n) * 16 + hexToNybble(o);
                                        o = 0;
                                        break;
                                case 'I': //invert
                                case 'i':
                                        invert = n & 1;
                                        o = 0;
                                        break;
                                case 'M': //MSB
                                case 'm':
                                        msb = n & 1;
                                        o = 0;
                                        break;
                                case '~': //Display ~ character
                                        displayChar(s[i--]);
                                        o = 0;
                                        break;
                                case 'C': // Display character
                                case 'c':
                                        o = s[i + 3];
                                        i++;
                                        if(((n >= '0' && n <= '9') || (n >= 'A' && n <= 'F') || (n >= 'a' && n <= 'f')) && ((o >= '0' && o <= '9') || (o >= 'A' && o <= 'F') || (o >= 'a' && o <= 'f')))
                                        {
                                                p = hexToNybble(n) * 16 + hexToNybble(o);
                                                displayChar(p);
                                        }
                                        o = 0;
                                        break;
                                case 'B': // Display byte
                                case 'b':
                                        o = s[i + 3];
                                        i++;
                                        if(((n >= '0' && n <= '9') || (n >= 'A' && n <= 'F') || (n >= 'a' && n <= 'f')) && ((o >= '0' && o <= '9') || (o >= 'A' && o <= 'F') || (o >= 'a' && o <= 'f')))
                                        {
                                                p = hexToNybble(n) * 16 + hexToNybble(o);
                                                displayByte(p);
                                                delay(interCharDelay);
                                        }
                                        o = 0;
                                        break;
                                }
                        }
                        if(i >= l)
                                i = 0;
                }
                if(o == 255)
                        displayChar(s[i]);
                else
                        i += 2;
                if(Serial.available())
                        break;
        }
        if(showSpace)
                displayChar(' ');
}

File: ascii8x8.c

#ifndef FONT8X8_H
#define FONT8X8_H

#ifdef __AVR__
 #include <avr/io.h>
 #include <avr/pgmspace.h>
#else
 #define PROGMEM
#endif

// Standard ASCII 8x8 font

static const unsigned char font[] PROGMEM = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
	0x7E, 0x81, 0x95, 0xB1, 0xB1, 0x95, 0x81, 0x7E,
	0x7E, 0xFF, 0xEB, 0xCF, 0xCF, 0xEB, 0xFF, 0x7E,
	0x0E, 0x1F, 0x3F, 0x7E, 0x3F, 0x1F, 0x0E, 0x00,
	0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00,
	0x38, 0x3A, 0x9F, 0xFF, 0x9F, 0x3A, 0x38, 0x00,
	0x10, 0x38, 0xBC, 0xFF, 0xBC, 0x38, 0x10, 0x00,
	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
	0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
	0x70, 0xF8, 0x88, 0x88, 0xFD, 0x7F, 0x07, 0x0F,
	0x00, 0x4E, 0x5F, 0xF1, 0xF1, 0x5F, 0x4E, 0x00,
	0xC0, 0xE0, 0xFF, 0x7F, 0x05, 0x05, 0x07, 0x07,
	0xC0, 0xFF, 0x7F, 0x05, 0x05, 0x65, 0x7F, 0x3F,
	0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
	0x7F, 0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00,
	0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x7F, 0x00,
	0x00, 0x24, 0x66, 0xFF, 0xFF, 0x66, 0x24, 0x00,
	0x00, 0x5F, 0x5F, 0x00, 0x00, 0x5F, 0x5F, 0x00,
	0x06, 0x0F, 0x09, 0x7F, 0x7F, 0x01, 0x7F, 0x7F,
	0xDA, 0xBF, 0xA5, 0xA5, 0xFD, 0x59, 0x03, 0x02,
	0x00, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x00,
	0x80, 0x94, 0xB6, 0xFF, 0xFF, 0xB6, 0x94, 0x80,
	0x00, 0x04, 0x06, 0x7F, 0x7F, 0x06, 0x04, 0x00,
	0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00,
	0x08, 0x08, 0x08, 0x2A, 0x3E, 0x1C, 0x08, 0x00,
	0x08, 0x1C, 0x3E, 0x2A, 0x08, 0x08, 0x08, 0x00,
	0x3C, 0x3C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
	0x08, 0x1C, 0x3E, 0x08, 0x08, 0x3E, 0x1C, 0x08,
	0x30, 0x38, 0x3C, 0x3E, 0x3E, 0x3C, 0x38, 0x30,
	0x06, 0x0E, 0x1E, 0x3E, 0x3E, 0x1E, 0x0E, 0x06,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32 ' '
	0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00, 0x00,
	0x00, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, 0x00,
	0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00,
	0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00,
	0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00,
	0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00,
	0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00,
	0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00,
	0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08,
	0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00,
	0x00, 0xA0, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00,
	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
	0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
	0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00,
	0x3E, 0x7F, 0x59, 0x4D, 0x7F, 0x3E, 0x00, 0x00,
	0x42, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00,
	0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00,
	0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00,
	0x18, 0x1C, 0x16, 0x13, 0x7F, 0x7F, 0x10, 0x00,
	0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00,
	0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00,
	0x03, 0x63, 0x71, 0x19, 0x0F, 0x07, 0x00, 0x00,
	0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00,
	0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00,
	0x00, 0x00, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
	0x00, 0xA0, 0xEC, 0x6C, 0x00, 0x00, 0x00, 0x00,
	0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00,
	0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00,
	0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00,
	0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00,
	0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00, // 64
	0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00, // 65 'A'
	0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00,
	0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00,
	0x41, 0x7F, 0x7F, 0x41, 0x63, 0x7F, 0x1C, 0x00,
	0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00,
	0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00,
	0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00,
	0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
	0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00,
	0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00,
	0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00,
	0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00,
	0x7F, 0x7F, 0x06, 0x0C, 0x06, 0x7F, 0x7F, 0x00,
	0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00,
	0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00,
	0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00,
	0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00,
	0x41, 0x7F, 0x7F, 0x19, 0x39, 0x6F, 0x46, 0x00,
	0x26, 0x67, 0x4D, 0x59, 0x7B, 0x32, 0x00, 0x00,
	0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00,
	0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00,
	0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00,
	0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00,
	0x63, 0x77, 0x1C, 0x08, 0x1C, 0x77, 0x63, 0x00,
	0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00,
	0x67, 0x73, 0x59, 0x4D, 0x47, 0x63, 0x71, 0x00,
	0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00,
	0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00,
	0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00,
	0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00,
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
	0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00,
	0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00,
	0x41, 0x3F, 0x7F, 0x44, 0x44, 0x7C, 0x38, 0x00,
	0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00,
	0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00,
	0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00,
	0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00,
	0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00,
	0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00,
	0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00,
	0x40, 0xC4, 0x84, 0xFD, 0x7D, 0x00, 0x00, 0x00,
	0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00,
	0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00,
	0x7C, 0x7C, 0x0C, 0x18, 0x0C, 0x7C, 0x78, 0x00,
	0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00,
	0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00,
	0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00,
	0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00,
	0x44, 0x7C, 0x78, 0x44, 0x1C, 0x18, 0x00, 0x00,
	0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00,
	0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00,
	0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00,
	0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00,
	0x3C, 0x7C, 0x60, 0x30, 0x60, 0x7C, 0x3C, 0x00,
	0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00,
	0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00,
	0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00,
	0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00,
	0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00,
	0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00,
	0x78, 0x7C, 0x46, 0x43, 0x46, 0x7C, 0x78, 0x00,
	0x0E, 0x9F, 0x91, 0xB1, 0xFB, 0x4A, 0x00, 0x00,
	0x3A, 0x7A, 0x40, 0x40, 0x7A, 0x7A, 0x40, 0x00,
	0x38, 0x7C, 0x54, 0x55, 0x5D, 0x19, 0x00, 0x00,
	0x02, 0x23, 0x75, 0x55, 0x55, 0x7D, 0x7B, 0x42,
	0x21, 0x75, 0x54, 0x54, 0x7D, 0x79, 0x40, 0x00,
	0x21, 0x75, 0x55, 0x54, 0x7C, 0x78, 0x40, 0x00,
	0x20, 0x74, 0x57, 0x57, 0x7C, 0x78, 0x40, 0x00,
	0x18, 0x3C, 0xA4, 0xA4, 0xA4, 0xE4, 0x40, 0x00,
	0x02, 0x3B, 0x7D, 0x55, 0x55, 0x5D, 0x1B, 0x02,
	0x39, 0x7D, 0x54, 0x54, 0x5D, 0x19, 0x00, 0x00,
	0x39, 0x7D, 0x55, 0x54, 0x5C, 0x18, 0x00, 0x00,
	0x01, 0x45, 0x7C, 0x7C, 0x41, 0x01, 0x00, 0x00,
	0x02, 0x03, 0x45, 0x7D, 0x7D, 0x43, 0x02, 0x00,
	0x01, 0x45, 0x7D, 0x7C, 0x40, 0x00, 0x00, 0x00,
	0x79, 0x7D, 0x26, 0x26, 0x7D, 0x79, 0x00, 0x00,
	0x70, 0x78, 0x2B, 0x2B, 0x78, 0x70, 0x00, 0x00,
	0x44, 0x7C, 0x7C, 0x55, 0x55, 0x45, 0x00, 0x00,
	0x20, 0x74, 0x54, 0x54, 0x7C, 0x7C, 0x54, 0x54,
	0x7C, 0x7E, 0x0B, 0x09, 0x7F, 0x7F, 0x49, 0x00,
	0x32, 0x7B, 0x49, 0x49, 0x7B, 0x32, 0x00, 0x00,
	0x32, 0x7A, 0x48, 0x48, 0x7A, 0x32, 0x00, 0x00,
	0x32, 0x7A, 0x4A, 0x48, 0x78, 0x30, 0x00, 0x00,
	0x3A, 0x7B, 0x41, 0x41, 0x7B, 0x7A, 0x40, 0x00,
	0x3A, 0x7A, 0x42, 0x40, 0x78, 0x78, 0x40, 0x00,
	0xBA, 0xBA, 0xA0, 0xA0, 0xFA, 0x7A, 0x00, 0x00,
	0x19, 0x3D, 0x66, 0x66, 0x66, 0x3D, 0x19, 0x00,
	0x3D, 0x7D, 0x40, 0x40, 0x7D, 0x3D, 0x00, 0x00,
	0x18, 0x3C, 0x24, 0xE7, 0xE7, 0x24, 0x24, 0x00,
	0x68, 0x7E, 0x7F, 0x49, 0x43, 0x66, 0x20, 0x00,
	0x2B, 0x2F, 0x7C, 0x7C, 0x2F, 0x2B, 0x00, 0x00,
	0x7F, 0x7F, 0x09, 0x2F, 0xF6, 0xF8, 0xA0, 0x00,
	0x40, 0xC8, 0x88, 0xFE, 0x7F, 0x09, 0x0B, 0x02,
	0x20, 0x74, 0x54, 0x55, 0x7D, 0x79, 0x40, 0x00,
	0x00, 0x44, 0x7D, 0x7D, 0x41, 0x00, 0x00, 0x00,
	0x30, 0x78, 0x48, 0x4A, 0x7A, 0x32, 0x00, 0x00,
	0x38, 0x78, 0x40, 0x42, 0x7A, 0x7A, 0x40, 0x00,
	0x7A, 0x7A, 0x0A, 0x0A, 0x7A, 0x70, 0x00, 0x00,
	0x7D, 0x7D, 0x19, 0x31, 0x7D, 0x7D, 0x00, 0x00,
	0x00, 0x26, 0x2F, 0x29, 0x2F, 0x2F, 0x28, 0x00,
	0x00, 0x26, 0x2F, 0x29, 0x29, 0x2F, 0x26, 0x00,
	0x30, 0x78, 0x4D, 0x45, 0x60, 0x20, 0x00, 0x00,
	0x38, 0x38, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
	0x08, 0x08, 0x08, 0x08, 0x38, 0x38, 0x00, 0x00,
	0x67, 0x37, 0x18, 0xCC, 0xEE, 0xAB, 0xB9, 0x90,
	0x6F, 0x3F, 0x18, 0x4C, 0x66, 0x73, 0xF9, 0xF8,
	0x00, 0x00, 0x60, 0xFA, 0xFA, 0x60, 0x00, 0x00,
	0x08, 0x1C, 0x36, 0x22, 0x08, 0x1C, 0x36, 0x22,
	0x22, 0x36, 0x1C, 0x08, 0x22, 0x36, 0x1C, 0x08,
	0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00,
	0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
	0x55, 0xFF, 0xAA, 0xFF, 0x55, 0xFF, 0xAA, 0x00,
	0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
	0x10, 0x10, 0x10, 0xFF, 0xFF, 0x00, 0x00, 0x00,
	0x14, 0x14, 0x14, 0xFF, 0xFF, 0x00, 0x00, 0x00,
	0x10, 0x10, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
	0x10, 0x10, 0xF0, 0xF0, 0x10, 0xF0, 0xF0, 0x00,
	0x14, 0x14, 0x14, 0xFC, 0xFC, 0x00, 0x00, 0x00,
	0x14, 0x14, 0xF7, 0xF7, 0x00, 0xFF, 0xFF, 0x00,
	0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
	0x14, 0x14, 0xF4, 0xF4, 0x04, 0xFC, 0xFC, 0x00,
	0x14, 0x14, 0x17, 0x17, 0x10, 0x1F, 0x1F, 0x00,
	0x10, 0x10, 0x1F, 0x1F, 0x10, 0x1F, 0x1F, 0x00,
	0x14, 0x14, 0x14, 0x1F, 0x1F, 0x00, 0x00, 0x00,
	0x10, 0x10, 0x10, 0xF0, 0xF0, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x1F, 0x1F, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0xF0, 0xF0, 0x10, 0x10, 0x10,
	0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0xFF, 0xFF, 0x10, 0x10, 0x10,
	0x00, 0x00, 0x00, 0xFF, 0xFF, 0x14, 0x14, 0x14,
	0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x10,
	0x00, 0x00, 0x1F, 0x1F, 0x10, 0x17, 0x17, 0x14,
	0x00, 0x00, 0xFC, 0xFC, 0x04, 0xF4, 0xF4, 0x14,
	0x14, 0x14, 0x17, 0x17, 0x10, 0x17, 0x17, 0x14,
	0x14, 0x14, 0xF4, 0xF4, 0x04, 0xF4, 0xF4, 0x14,
	0x00, 0x00, 0xFF, 0xFF, 0x00, 0xF7, 0xF7, 0x14,
	0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
	0x14, 0x14, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0x14,
	0x14, 0x14, 0x14, 0x17, 0x17, 0x14, 0x14, 0x14,
	0x10, 0x10, 0x1F, 0x1F, 0x10, 0x1F, 0x1F, 0x10,
	0x14, 0x14, 0x14, 0xF4, 0xF4, 0x14, 0x14, 0x14,
	0x10, 0x10, 0xF0, 0xF0, 0x10, 0xF0, 0xF0, 0x10,
	0x00, 0x00, 0x1F, 0x1F, 0x10, 0x1F, 0x1F, 0x10,
	0x00, 0x00, 0x00, 0x1F, 0x1F, 0x14, 0x14, 0x14,
	0x00, 0x00, 0x00, 0xFC, 0xFC, 0x14, 0x14, 0x14,
	0x00, 0x00, 0xF0, 0xF0, 0x10, 0xF0, 0xF0, 0x10,
	0x10, 0x10, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x10,
	0x14, 0x14, 0x14, 0xF7, 0xF7, 0x14, 0x14, 0x14,
	0x10, 0x10, 0x10, 0x1F, 0x1F, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0xF0, 0xF0, 0x10, 0x10, 0x10,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
	0x38, 0x7C, 0x44, 0x6C, 0x38, 0x6C, 0x44, 0x00,
	0xFC, 0xFE, 0x2A, 0x2A, 0x3E, 0x14, 0x00, 0x00,
	0x7E, 0x7E, 0x02, 0x02, 0x02, 0x06, 0x06, 0x00,
	0x02, 0x7E, 0x7E, 0x02, 0x7E, 0x7E, 0x02, 0x00,
	0x41, 0x63, 0x77, 0x5D, 0x49, 0x63, 0x63, 0x00,
	0x38, 0x7C, 0x44, 0x44, 0x7C, 0x3C, 0x04, 0x00,
	0x80, 0xFE, 0x7E, 0x20, 0x20, 0x3E, 0x1E, 0x00,
	0x04, 0x06, 0x02, 0x7E, 0x7C, 0x06, 0x02, 0x00,
	0x99, 0xBD, 0xE7, 0xE7, 0xBD, 0x99, 0x00, 0x00,
	0x1C, 0x3E, 0x6B, 0x49, 0x6B, 0x3E, 0x1C, 0x00,
	0x4C, 0x7E, 0x73, 0x01, 0x73, 0x7E, 0x4C, 0x00,
	0x30, 0x78, 0x4A, 0x4F, 0x7D, 0x39, 0x00, 0x00,
	0x18, 0x3C, 0x24, 0x3C, 0x3C, 0x24, 0x3C, 0x18,
	0x98, 0xFC, 0x64, 0x3C, 0x3E, 0x27, 0x3D, 0x18,
	0x1C, 0x3E, 0x6B, 0x49, 0x49, 0x49, 0x00, 0x00,
	0x7E, 0x7F, 0x01, 0x01, 0x7F, 0x7E, 0x00, 0x00,
	0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00,
	0x44, 0x44, 0x5F, 0x5F, 0x44, 0x44, 0x00, 0x00,
	0x40, 0x51, 0x5B, 0x4E, 0x44, 0x40, 0x00, 0x00,
	0x40, 0x44, 0x4E, 0x5B, 0x51, 0x40, 0x00, 0x00,
	0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x07, 0x06,
	0x60, 0xE0, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0x00,
	0x08, 0x08, 0x6B, 0x6B, 0x08, 0x08, 0x00, 0x00,
	0x24, 0x12, 0x12, 0x36, 0x24, 0x24, 0x12, 0x00,
	0x00, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,
	0x10, 0x30, 0x70, 0xC0, 0xFF, 0xFF, 0x01, 0x01,
	0x00, 0x1F, 0x1F, 0x01, 0x1F, 0x1E, 0x00, 0x00,
	0x00, 0x19, 0x1D, 0x15, 0x17, 0x12, 0x00, 0x00,
	0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
#endif

ArachnidLabs minishift arduino example scrolling text

As an addon from my last post, I have made a scrolling text display system.

It is a work in process and I think I have the logic backwards. I definitely need more boards to stack so I can see it to full effect!
You need to grab Adafruit’s glcdfont.c from https://github.com/adafruit/Adafruit-GFX-Library/raw/master/glcdfont.c

See it running at http://youtu.be/baRenpdT_Ew

edit: Silly me, I had coded it with the board upside down! No wonder my scroll was going the wrong way :P
The code below has been corrected.

file: minishift_text.pde

//Sample code to display text on the @ArachnidLabs minishift
// Written by Gregory Fenton, http://labby.co.uk

/*
Wiring:
latchPin connected to CS   (pin 4) of minishift
clockPin connected to SCK  (pin 3) of minishift
dataPin  connected to MOSI (pin 5) of minishift
*/

#include "glcdfont.c" // Adafruit glcdfont

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

char s[256] = "ArachnidLabs minishift example by Gregory Fenton, labby.co.uk";

void displayByte(int b)
{
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, b);
    digitalWrite(latchPin, HIGH);
}

void displayChar(int c)
{
  int i;
  if(c > 31 && c < 127)
  {
    for(i = 0; i < 5; i++)
    {
      displayByte(pgm_read_byte(font+(c * 5) + i));
      delay(50);
    }
    displayByte(0);
  }
}

void setup() {
  Serial.begin(9600);
  int i;
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  //clear display by sending 256 blank bytes
  //256 is arbitrary and should be changed to the number of
  //columns in your display
  for(i = 0; i < 256; i++)
  {
    displayByte(0);
  }
}

void loop() {
  // Display the numbers 0 to 255 in binary
  int i = 0, l;
  char c;
  
  while(Serial.available())
  {
    c = Serial.read();
    s[i++] = c;
    if(!Serial.available())
    {
      
      Serial.flush();
      s[i++] = 0;
      Serial.println(s);
    }
  }
  
  for(i = 0; s[i] != 0; i++);
  l = i;
  
  for(i = 0; i < l; i++)
  {
    displayChar(s[i]);
    if(Serial.available())
      break;
  }
  displayChar(' ');
}

ArachnidLabs minishift arduino example

The ArachnidLabs minishift is a great little board that I purchased from the UK Maker Faire 2014 from their stand.

I could not find much online about the board, but here is a basic example to show the wiring and display some scrolling binary.

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

http://creativecommons.org/licenses/by-nc-sa/4.0/

Filename: minishift.pde

/*
Sample code to display binary 0..255 on the @ArachnidLabs minishift
Written by Gregory Fenton, http://labby.co.uk
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

http://creativecommons.org/licenses/by-nc-sa/4.0/

Wiring:
5v (or 3.3v) connected to 5v  (pin 1) of minishift
gnd connected to gnd  (pin 2) of minishift
clockPin connected to SCK  (pin 3) of minishift
latchPin connected to CS   (pin 4) of minishift
dataPin  connected to MOSI (pin 5) of minishift
*/

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

void displayByte(int b)
{
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, b);
    digitalWrite(latchPin, HIGH);
}

void setup() {
  int i;
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  //clear display by sending 256 blank bytes
  //256 is arbitrary and should be changed to the number of
  //columns in your display
  for(i = 0; i < 256; i++)
  {
    displayByte(0);
  }
}

void loop() {
  // Display the numbers 0 to 255 in binary
  int i;
  
  for (i = 0; i < 256; i++)
  {
    displayByte(i);
    delay(50);
  }
} 

PIC18F25K50 breadboard programming under linux

Hi all

This week I have been programming PICs (peripheral interface controller), a small microcontroller. You may have heard of the most popular at the moment, the Arduino.

The PIC I have been working with is the PIC18F25K50 and the low power version of that chip, the PIC18LF25K50.

These chips have onboard USB support, however the software to use the USB stack is currently not working. This will change over time I am sure.

Back to the point of the post.

I have successfully programmed one on a breadboard using the Pickit 3. No doubt I will retask the breadboard and completely forget the schematic which took me the best part of a day to work out.

Here’s the breadboard schematic, including 4 LEDs connected from pins A0-A3:
pic18f25k50 breadboard with 4 LEDs on A0-A3_bb

Be aware that you need to connect pin 1 of the Pickit 3 to the yellow side of the 6-pin header and that pin 6 is not connected.

I have a sketch that flashes the LEDs, if you want me to post the code then let me know.

Twitter API 1.1 update for the candy machine

**************************************
Author’s note:
PLEASE NOTE THAT I NOW USE AN L293 MOTOR DRIVER IC RATHER THAN JUST A TRANSISTOR
PLEASE DO NOT RUN THIS CODE WITHOUT MODIFYING YOUR CIRCUIT TO MATCH

I do this so that I can move the motor forwards for 2 seconds to dispense the candy and then reverse for 1 second which pulls any candy that has not yet fell back inside the machine so it can be moved safely without the candy falling out everywhere.
I will include an updated schematic, as well as the current version of my code in the next day or so. If I forget, feel free to remind me :)
The updated version is pretty cool – it telnets to a networked HP printer and updates the LCD display on the printer with the name of whoever tweeted me :D
A silly but fun hack that could easily be extended or retasked for other uses.
**************************************

I realised that I have not yet updated my blog to show how I have managed to get around the recent change to the way the Twitter API 1.1 works.

The 1.1 API strictly enforces authorization (I know, I spell it authorisation) before you can do a twitter search, previously you could do a basic authentication and it would work.

The way I got around it was to let the candy machine ask my server for the latest tweet and on my server use the ‘t’ package by Erik Michaels-Ober, a utility that allows you to do twitter 1.1 API calls from the command line.

To install t you must first install the prerequisites, which will only take a moment or two.
Once you have the prerequisites installed, you can simply type gem install t and begin the authorisation process.

When you have completed this stage you are almost done. Soon the sweet, sweet taste of Skittles (try the sour ones, the purple ones are out of this world!) will be but a tweet away :)

One thing I had to change is that the www-data user cannot run ‘t’ as $HOME is unset for security which means that there is nowhere for the config file to go. If you use the -P flag you can set the profile location which neatly sidesteps this issue t -P /var/www/.trc (mine isn’t there!)

So for clarity, the process is:
The Arduino asks my server for a web page containing the latest tweet
My server authenticates and queries twitter
If there has been a recent tweet it gets converted to a simple version the Arduino can understand and returned to the Arduino. If not, my server returns

The Arduino parses the returned string, first by size (the returned will be more than 3 characters long if there has been a tweet).
If the string is less than 12 characters long then the Arduino just goes back to the start after a delay.
If the string is 12 or more characters long then we have a tweet.
The first character is always < so we can safely skip that one.
The complete line is composed of the tweet ID, character 0x07 (bell in ASCII, Ctrl-G) the sender eg @gregoryfenton, character 0x07 and the contents of the tweet followed by character 0x7F to mark the end of the line.
I split the string and separate the parts into individual variables so I can do other stuff such as display the sender and message if required.

The server code is:
file: parsetwitter.php

<?php
$needle = "maker_space AND candy";
$tmpfile = "/var/www/lasttweet.php";

@include($tmpfile);

// lasttweet.php will set up the following variables:
// $tID  : ID of last tweet
// $tFrom: twitter ID of sender
// $tMsg : message
if(!isset($tID))
  $tID = "0";
if(!isset($tFrom))
  $tFrom = "";
if(!isset($tMsg))
  $tMsg = "";

$t = "`which t`";

exec("$t -P /var/www/.trc search all \"$needle\" -n 1 -l", $tweets);

$tweet = explode("  ", $tweets[0]);

if($tweet[0] != $tID)
{
    $r = str_replace("\\","\\\\",$tweet);
    $r = str_replace("\"","\\\"",$r);
    $r = str_replace("\$","\\\$",$r);
    $r = str_replace("\`","\\\`",$r);
    $data = "<?php
	      \$tID = \"$r[0]\";
	      \$tFrom = \"$r[2]\";
	      \$tMsg = \"$r[3]\";
	    ?>";
    printf ("<$r[0]%c$r[2]%c$r[3]%c%c", 7, 7, 7, 0x7f);
    file_put_contents($tmpfile, $data);
}
else
{
    printf ("<!%c", 0x7f);
}
?>

Still with me? Here is the Arduino code:

#include <avr/wdt.h>
#include <Ethernet.h>
#include <SPI.h>

////////////////////////////////////////////////////////////////////////
//CONFIGURE
////////////////////////////////////////////////////////////////////////
char server[] = "example.com"; //domain name of the server you will connect to

//The location to go to on the server
//make sure to keep HTTP/1.0 at the end, this is telling it what type of file it is
String location = "/parsetwitter.php HTTP/1.0";


// if need to change the MAC address (Very Rare)
byte mac[] =
{
	0xDE, 0xAD, 0xFA, 0xCE, 0xFA, 0xDE
};
////////////////////////////////////////////////////////////////////////

EthernetClient client;

int tweetPinA = 8, tweetPinB = 9, LED = 13;

char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

void setup()
{
	wdt_disable();
	Ethernet.begin(mac);
	Serial.begin(9600);
	pinMode(tweetPinA, OUTPUT);
	digitalWrite(tweetPinA, LOW);
	pinMode(tweetPinB, OUTPUT);
	digitalWrite(tweetPinB, LOW);
	pinMode(LED, OUTPUT);
	digitalWrite(LED, LOW);
	wdt_enable(WDTO_8S);
}

void loop()
{
	int i = 0;
	String pageValue = connectAndRead(); //connect to the server and read the output

	Serial.println(pageValue); //print out the findings.
	
	for(i = 0; i < 3; i++)
	{
		wdt_reset();
		delay(5000); //wait (5x6) seconds before connecting again
	}
}

String connectAndRead()
{
	//connect to the server
	Serial.println("connecting...");

	//port 80 is typical of a www page
	if (client.connect(server, 80))
	{
		wdt_reset();

		Serial.println("connected");
		client.print("GET ");
		client.println(location);
		client.print("HOST: ");
		client.println(server);
		client.println("User-Agent: Candy Machine Tweet Scanner/1.0.1");
		client.println("Connection: close");
		client.println();

		//Connected - Read the page
		wdt_reset();
		return readPage(); //go and read the output
	}
	else
	{
		wdt_reset();
		return "connection failed";
	}

}

String readPage()
{
	//read the page, and capture & return everything between '<' and '>'

	stringPos = 0;
	memset( &inString, 0, 32 ); //clear inString memory

	while(true)
	{
		if (client.available())
		{
			wdt_reset();
			char c = client.read();

			if (c == '<' )
			{
				//'<' is our begining character
				startRead = true; //Ready to start reading the part
			}
			else if(startRead)
			{
				if(c != '>' && stringPos < 16)
				{
					//'>' is our ending character
					inString[stringPos] = c;
					stringPos ++;
				}
				else
				{
					//got what we need here! We can disconnect now
					wdt_reset();
					startRead = false;
					client.stop();
					client.flush();
					Serial.println("disconnecting.");
					if(stringPos > 12) // someone tweeted us!!!
					{
						wdt_reset();
						digitalWrite(LED, HIGH);
						Serial.println("We have received a tweet!");
						digitalWrite(tweetPinA, HIGH);
						digitalWrite(tweetPinB, LOW);
						delay(2000);
						wdt_reset();
						digitalWrite(tweetPinA, LOW);
						digitalWrite(tweetPinB, HIGH);
						delay(1000);
						wdt_reset();
						digitalWrite(tweetPinA, LOW);
						digitalWrite(tweetPinB, LOW);
						digitalWrite(LED, LOW);
					}
					return inString;
				}
			}
		}

	}
}

Just another WordPress site

© 2009-2014 labby.co.uk All Rights Reserved -- Copyright notice by Blog Copyright