Monday, May 3, 2010

Arduino Email Manager - Part 2 - The Preprocessor

I freely admit that I am not the greatest programmer in the world. Never having been formally trained, my programs tend to be rather loopy and don't include all the error checking they should. This PHP script that I have written is a case in point. It will work with my POP email provider (Rogers in Canada), but it may NOT work with your provider! It seems like there are minor variations in the way some POP servers will respond to the standard commands and these can throw off the script slightly. The best bet is to log into your POP server via telnet and carefully watch the messages back and forth.

Also note that this will support SSL (if you have it set up with your PHP installation) just by putting "ssl:/" in front of the host name and using whatever port number has been assigned - usually 995.You can manually log into an SSL-enabled account using the OpenSSL client available from OpenSSL.org instead of telnet.

At this point, the script does not support Gmail, so don't write to me about that! I have been trying to get it to work and you can definitely log in, but it seems to give inconsistent results and the mail total includes both the inbox and sent folder somehow (which doesn't make sense to me). If anyone out there knows the trick with Gmail, please let me know. I see that there are some PHP classes available for accessing Gmail via IMAP and I will investigate these and post revised code when I can.

So, how does this script work? The script needs to run on a server with the current version of PHP running. This could be a Mac or a Linux/Windows box or it could be running on a remote webserver - assuming you have all the networking and firewall issues dealt with. There is a new project called Yaler that may help with the networking issues if your script is remotely hosted - check it out here. You need to start the script before pressing the "Connect" (or Select) button on the Arduino.

When running, the Preprocessor is a "host" for the requests from the Arduino, but is in turn acting as a "client" to the POP server. It maintains two separate PHP sockets - one to the Arduino and one to the POP server.



The script implements a very simple protocol with the Arduino:

Arduino Sends...
Preprocessor returns...
Arduino connects to IP/portthe ASCII "C"
NCurrent number of emails on the POP server.
S.x (where x is an integer)The from/subject information for email number "x" prefixed with MSG.
D.x (where x is an integer)Deletes email number "x".
EKills the socket and ends session - currently not implemented.

The script also provides the following error messages back (although I am not currently using these on the Arduino):

  • X.1 - Could not open socket to POP server
  • X.2 - Error from server
  • X.3 - Authentication failure
  • X.4 - Bad connection

I tend to prefer one letter protocols with the Arduino since it simplifies the text handling on the Arduino side.

And, without further ado, here is the code...

<?php

/*
*  PHP Pre-processor script for Arduino POP Mail Manager
*
* this is the pre-processor script for use with the Arduino email
* manager described on my blog. Complete description at:
* http://opensourceprojects-torchris.blogspot.com/
*
* This script can be used with SSL enabled POP services by putting
* "ssl:/" infront of the host name. It does NOT currently work with
* GMail POP service.
*
* This code is in the public domain. Please provide credit if it is used
* in another project.
*
* written by Chris Armour, Arpil 30th, 2010
*
*/

//=============================IP, Port, User Info=================//
//Modify to suit your network.

define("HOST_POP", "your.popserver..com");
define("PORT_POP", "110");
define("USER_POP", "user.name");
define("PASS_POP", "YourPassword");
//Server settings
$host_ard = "192.168.0.171"; //This is the IP of the server running the script.
$port_ard = "12345"; //Port number being used by the Arduino


//==========================Functions===================//

//GetMailCount grabs the number of emails in the mailbox using the STAT command
function GetMailCount()
{
$fp_pop = fsockopen (HOST_POP, PORT_POP, $errno, $errstr);
    // if a handle is not returned
    ob_implicit_flush();
    if (!$fp_pop)
        {
        echo("Error: could not open socket connection\n");
        return("X.1");
        }
    else
        {
        // get the welcome message
        $welcome = fgets ($fp_pop, 150);
        // check for success code
        if (substr($welcome, 0, 3) == "+OK")
        {
        // send username and read response
    fputs ($fp_pop, "user " . USER_POP . "\n");
    //fgets($fp_pop, 50);
    // send password and read response
    fputs ($fp_pop, "pass " . PASS_POP . "\n");
    $ack = fgets($fp_pop, 50);
    // check for success code
    if (substr($ack, 0, 3) == "+OK")
        {
        // send status request and read response
        fputs ($fp_pop, "STAT\n");
        $status = fgets($fp_pop, 50);
    if (substr($status, 0, 3) == "+OK")
        {
        // shut down connection
        fputs ($fp_pop, "QUIT\n");
        fclose ($fp_pop);
        }
// error getting status
    else  {
        echo ("Error - server said: $status");
        return("X.2");
        }
        }
    // auth failure
    else  {
        echo ("Error - server said: $ack");
        return("X.3");
        }
        }
        // bad welcome message
    else {
        echo ("Error - bad connection string\n");
        return("X.4");
        }
// get status string
// split by spaces
$arr = explode(" ", $status);
// the second element contains the total number of messages
echo $arr[3] . " messages in mailbox\n";
$GotMail = $arr[3];
return $GotMail;
}
}

//GetFromSubj grabs the content of the email MailNumber then passes this back to the main loop for extraction of the From & subject
//You may need to check the output from your POP3 server using telnet to check on the responses. This seems to vary from POP server to POP
//server.
function GetFromSubj($MailNumber){
$fp_pop = fsockopen (HOST_POP, PORT_POP, $errno, $errstr);
    // if a handle is not returned
    ob_implicit_flush();
    if (!$fp_pop)
        {
        echo("Error: could not open socket connection\n");
        return("X.1");
        }
    else
        {
        // get the welcome message
        $welcome = fgets ($fp_pop, 150);
        // check for success code
        if (substr($welcome, 0, 3) == "+OK")
        {
        // send username and read response
    fputs ($fp_pop, "user " . USER_POP . "\n");
    fgets($fp_pop);
    // send password and read response
    fputs ($fp_pop, "pass " . PASS_POP . "\n");
   $ack = fgets($fp_pop);
    // check for success code
    if (substr($ack, 0, 3) == "+OK")
       {
        // send request for email content & read response

        fputs ($fp_pop, "retr " . $MailNumber . "\n");
        $EmailContent = fread($fp_pop, 4096);
//        echo $EmailContent;
    if (substr($EmailContent, 0, 3) == "+OK")
        {
        // shut down connection
        return $EmailContent;
        fputs ($fp_pop, "QUIT\n");
        fclose ($fp_pop);
        }
// error getting status
    else
        {
        echo ("Error - Server said: $EmailContent");
        return("X.2");
        }
        }
    // auth failure
    else
        {
        echo ("Error - Server said: $ack");
        return("X.3");
        }
        }
        // bad welcome message
    else
        {
        echo ("Error - Bad connection string\n");
        return("X.4");
        }
}
}

//MsgDelete delets message # MailNumber using the dele command
function MsgDelete($MailNumber){

$fp_pop = fsockopen (HOST_POP, PORT_POP, $errno, $errstr);
    // if a handle is not returned
    ob_implicit_flush();
    if (!$fp_pop)
        {
        echo("Error: could not open socket connection\n");
        return("X.1");
        }
    else
        {
        // get the welcome message
        $welcome = fgets ($fp_pop, 150);
        // check for success code
        if (substr($welcome, 0, 3) == "+OK")
        {
        // send username and read response
    fputs ($fp_pop, "user " . USER_POP . "\n");
    fgets($fp_pop);
    // send password and read response
    fputs ($fp_pop, "pass " . PASS_POP . "\n");
   $ack = fgets($fp_pop);
    // check for success code
    if (substr($ack, 0, 3) == "+OK")
       {
        // send delete command

        fputs ($fp_pop, "dele " . $MailNumber . "\n");
        $DeleteAck = fgets($fp_pop);
//        echo $EmailContent;
    if (substr($DeleteAck, 0, 3) == "+OK")
        {
        // shut down connection
        echo ("Message " . $MailNumber . " deleted. \n");
        fputs ($fp_pop, "QUIT\n");
        fclose ($fp_pop);
        }
// error getting status
   else
        {
        echo ("Error - Server said: $EmailContent");
        return ("X.2");
        }
        }
    // auth failure
    else
        {
        echo ("Error - Server said: $ack");
        return("X.3");
        }
        }
        // bad welcome message
    else
        {
        echo ("Error - Bad connection string\n");
        return("X.4");
        }
        }
}

//=====================Create Socket to listen for Arduino======================//

ob_implicit_flush();

//Open socket to listen for Arduino
$socket_ard = socket_create(AF_INET, SOCK_STREAM, 0) or die ("Could not bind to socket\n");
$result_ard = socket_bind($socket_ard, $host_ard, $port_ard) or die("Could not bind to socket\n");

// start listening for connections
$result_ard = socket_listen($socket_ard, 3) or die("Could not set up socket listener\n");
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket_ard) or die("Could not accept incoming connection\n");
// read client input
socket_write($spawn,"C\n");
echo "Device connected.\n";

//=====================Main Socket loop======================//
do {

$input = socket_read($spawn, 2048, PHP_NORMAL_READ) or die("Could not read input\n");

echo $input;

if (trim($input[0]) == "N" || trim($input[0]) == "S" || trim($input[0]) == "D" || trim($input[0]) == "E" || trim($input[0]) == "\r\n") {
//Only do anything if N, S, D or E received.

    if (trim($input) == "N"){
        // This gets the mailcount using the GetMailCount function.
        $MailCount = GetMailCount();
        socket_write($spawn, "Total Number of Messages:" . $MailCount . "@");
        }

    if (trim($input[0]) == "S") {
        //This gets the from/subject info is an S.num is received.
       $MsgNum = explode (".",$input);
       //Use explode to break the info from the Arduino into an array.
        $MsgNumber = $MsgNum[1];
        //Get the Message number from the array.
        echo ("Value of MsgNumber= " . $MsgNumber . "\n");
        $MsgFromSubj = GetFromSubj($MsgNumber);
        //run the function to get the info from the POP server
            if ($MsgFromSubj[0] == "X")
            {
            //If there's an error, write back the server error text.
                socket_write($spawn,$MsgFromSubj);
            }
        else
            {
            $MsgFromLocn = strpos($MsgFromSubj, "From: ");
            $MsgFromName = substr($MsgFromSubj, ($MsgFromLocn + 6), 14);
            print ( "MSG". "F:" . $MsgFromName );
            $MsgSubjLocn = strpos($MsgFromSubj, "Subject: ");
            $MsgSubj = substr($MsgFromSubj, ($MsgSubjLocn + 9), 14);
            echo ("S:" . $MsgSubj );
            usleep(20000);
            socket_write ($spawn,  "MSG" . "F:" . $MsgFromName . "S:" . $MsgSubj . "\n");
            }
        }

    if (trim($input[0]) == "D") {
    //This sends the command to delete an email.
       $MsgNum = explode (".",$input);
        $MsgNumber = $MsgNum[1];
        $MsgDelRet = MsgDelete($MsgNumber);
        if ($MsgDelRet[0] == "X")
            {
                socket_write($spawn,$MsgDelRet ."\n");
            }
        else
            {
        socket_write($spawn, "D." . $MsgNum[1]);
        }
    }

    if (trim($input) == "E"){
  //This isn't actually currently used by the Arduino.
        socket_shutdown($spawn, 2);
        usleep(1000);
        socket_close($spawn);
        socket_shutdown($socket_ard, 2);
        usleep(1000);
        socket_close($socket_ard);
        echo "Sockets terminated\n";
 //       break;
        }
}

} while(true);

?>

Note that this code does not provide good handling of disconnect/reconnect nor can it handle multiple connections simultaneously. In other words, if the Arduino is reset, then the script needs to be restarted. Also, if multiple connection requests are received, it will just die. If anyone can improve on this, please make the suggestions.

Next up will be the Arduino code!

Saturday, May 1, 2010

Arduino Email Manager - Part 1 - Overview

I always seem to start every blog entry moaning about how long it's been since the last project I posted and this one is no exception. I think writing this is pushing me to do more complex projects and what with having a life and all, it just takes a long time to get everything done. This project in particular turned out to be quite a bit more difficult than I thought it would be and it has ended up taking me months and months to work out all the kinks. Because of that, I will be breaking up the project description into a couple of entries. This first one will just introduce the project.

First the obligatory video!



As explained in the video, this project uses three easily available Arduino components to allow you to:

  • See how many emails you have in your POP3 email account
  • Review the "from" and "subject" of your email
  • Delete unwanted emails

Here is what it looks like assembled:





The system is a sandwich of..

  • Arduino Duemilanova
  • Arduino Ethernet Shield
  • DFRobot LCD/button shield (available here from Robotshop among others)

I also used some Shield Stacking Headers (available from Adafruit) since the LCD shield wouldn't clear the Ethernet jack on the network shield. Here it is disassembled:





Getting the LCD Shield to work with the Ethernet Shield was a time consuming process. Initially, it looked like there would be no pin conflicts, since the Ethernet Shield uses pins 10, 11, 12 & 13 and the LCD Shield in theory uses 5,6,7,8 and 9, but for whatever reason I just couldn't make it work. I did finally find a blog posting by David Delabassee (here) that pointed out that, in fact, the LCD Shield uses more pins than is documented and shows how to modify LCD4Bit_mod.cpp to remap the pins slightly. Very useful, but it still seemed to blank out for some reason.

So, I ended up testing every single pin combination (which took hours) and I finally determined that if the LCD Shield was on digital pin 13, it just wouldn't work for whatever reason (even though, in theory, that pin is not used by the shield). So, just bending back that leg on the LCD Shield took pin 13 out of the circuit and it now works fine.

I had also wanted to add in one or two LEDs to signal the message count or connected state, but for whatever reason again when I added them in, it just wouldn't work consistently. If anyone has any ideas on how to fix that it would be appreciated!

As explained in the video, I have used the five buttons available on the LCD shield to page through the emails and delete any that I don't want.




I will post the software in subsequent entries, but for now I will just explain that I decided to go with using a mail "pre-processor" application written in PHP. Originally I wanted to do everything on the Arduino so it would be a complete, stand-alone solution, but, alas, it just proved to be too hard for the Arduino's limited text processing abilities and my small brain. Basically, even with the Duemilanova based on the ATMEGA328, you really can't load a string array with more than a couple of hundred characters before the Arduino locks up. Unfortunately, you need to look through at least the first 1,500 - 2,000 characters to get the "from" and "subject" info I wanted. I looking into using PROGMEM, but I just couldn't get my head around it (looks like all that fancy "pointer" stuff I can never figure out!). Then there's the Arduiniana Flash library, but it seems limited to strings you load at the beginning, rather than dynamic strings.

Finally, I just decided to go with a pre-processor written in PHP. I already know enough PHP to be functional and it is excellent for text processing. When I went to figure out how to do sockets programming with PHP, the first tutorial I found was on writing a script to access a POP3 email server (check it out)! Using a pre-processor isn't cheating too much. Tom Igoe uses one in Making Things Talk for his "Networked Air Quality Meter" project. Of course, on a much vaster scale, that is essentially how the RIM Blackberry email system works - emails are routed through their preprocessor software which compresses and reroutes them them down to the smartphone.

That is enough for now. Next up will be the Arduino software & PHP script.

Thursday, January 21, 2010

Arduino Motion Control over Ethernet

Watching the numbers on Google Analytics definitely tells me my reading public doesn't care about my welding projects! So, let's get back to the Arduino.
When I set up to do my POP3 project, I ended up buying an Arduino Ethernet shield and an Adafruit Ethernet shield plus a Lantronix Xport. Having both, I figured it would be a good challenge to get both talking to each other and the result is this fairly simple project which actually ended up taking a lot of thought. It is loosely based on "Networked Game" project in Tom Igoe's indispensable book "Making Things Talk", but Tom's example does the much harder job of writing everything in the low-level serial commands to the Xport while I am lazy and used the published libraries! The challenge here is that the two network shields have two different Arduino libraries which really don't work quite the same way. Also, the Adafruit library is pretty light on explanation and the examples provided have no comments in the code!
Here is the basic setup of this project, basically the accelerometer on the "server" controls two servos on the "client":

The servos, of course, could be hooked up to any number of things like the X-Y axis of a camera mount or a motion base for a game of some kind. Conceptually, of course, through the magic of the Internet and with the right networking setup, the client could be in New York and the server in Instanbul. Also, through the miracle of standard IP protocols I can use one make of shield to successfully communicate with another using two totally different libraries!
Here is a quick video of the rig in action:
Note that the servos jitter slightly when they are hooked up because of slight variations of the analog readings on the accelerometer. I could probably do some averaging to smooth out the readings to eliminate that jitter.
The Server
The server is actually very simple. I used the Adafruit ADXL335 accelerometer (info) that is hooked up to the first three analog pins on the Arduino Diecimilia. The Arduino reads and sends out the X, Y and Z axis, but the client only uses the X and Y values because I only have two servos. It would be pretty easy to build support in for all three axes on the client. Apart from the accelerometer, the only other component is the LED that indicates connected or not connected.




The code is equally simple. It reads the accelerometer and when it receives a "g" from the client it prints out the X, Y & Z readings. When it receives an "x" it ends the session. That's it! Note that this uses the Ethernet.h library distributed with the Arduino software.

* Simple Ethernet Server
*
* A simple server that shows the value of the analog input pins 0 - 2 
* which are connected to an ADXL335 Accelerometer.

by Chris Armour, Jan 2010
*/

#include 

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //Setting the MAC address
byte ip[] = { 192, 168, 0, 177 }; //IP address of the server
int XPin = 0;
int YPin = 1;
int ZPin = 2;
int ValX = 0;
int ValY = 0;
int ValZ = 0;
int ledPin = 9;
char c;

Server server(54321); //This is the port the server listens on.

//==============Setup pins, server & serial ===================//

void setup()
{
Ethernet.begin(mac, ip);
server.begin();
Serial.begin(9600);
pinMode(ledPin, OUTPUT); 
digitalWrite(ledPin, LOW);
}

//=====================Main loop =============================//

void loop()
{
digitalWrite(ledPin, LOW); //If there is no client connected the LED is off.
Client client = server.available();

while (client.connected()) {

if (client.available()) {
digitalWrite(ledPin, HIGH);  
char c = client.read(); //Read one character at a time.
Serial.print("Value received:  ");
Serial.println(c); 

if (c == 'g') { //"g means "get"
ValX = analogRead(XPin);
ValY = analogRead(YPin);
ValZ = analogRead(ZPin);
Serial.print("Value sent:  ");
Serial.print(ValX);
Serial.print(",");
Serial.print(ValY);
Serial.print(",");
Serial.println(ValZ);
client.print(">");
client.print(ValX);
client.print(",");
client.print(ValY);
client.print(",");
client.println(ValZ);
break;
}
if (c == 'x'){ //x means kill the session.
digitalWrite(ledPin, LOW); //turn off the LED
client.flush();
client.stop();
}
}
}
delay(50);
}

The Client

The client is a slightly more complex beast in that it has a switch to initiate a connection, an LED to indicate the connection state and the servos:



The code is also somewhat more involved. Part of that is because of using the AF_Xport library from Adafruit which takes a bit more fiddling, but also because the client needs the extra logic to initiate and disengage the connection. The main problem area is on resetting the Xport which doesn't always seem to want to connect on the first try so I had to build a loop in to retry the reset until it connects. This is a bit inelegant, but it looks like others have had this problem too.

/*
A network client based on Adafruit Ethernet Shield using the 
Xport ethernet-to-serial adapter. It moves servos based on analog
input from a server with an ADXL335 Accelerometer.

by Chris Armour, Jan 2010
*/

#include 
#include 
#include 
#define XPORT_RXPIN 2
#define XPORT_TXPIN 3
#define XPORT_RESETPIN 4
#define XPORT_DTRPIN 5
#define XPORT_CTSPIN 6
#define XPORT_RTSPIN 7
#define IPADDR "192.168.0.177" //IP Address of the Arduino Server
#define PORT 54321 //IP port of the server

AF_XPort xport = AF_XPort(XPORT_RXPIN, XPORT_TXPIN, XPORT_RESETPIN, XPORT_DTRPIN, XPORT_RTSPIN, XPORT_CTSPIN);

uint8_t ret; //The return variable needs to be formated as a unsigned integer of length 8 bits 
int Xval = 0;
int Yval = 0;
int Xservo = 0;
int Yservo = 0;
int buttonPin = 11;
int buttonWas = 0;
int buttonIs = 1;
int ledState = 0; //I believe these are actually flipped 0 = On 1 = off
int ledPin = 13;
boolean ConnectState = false;
char linebuffer[16]; //Very small line buffer because we just need the X-Y readings.
Servo Xservobj;
Servo Yservobj;
int loopCount = 0;

//===============Setup pins, servo, xport ==========//
void setup()  
{
 pinMode(buttonPin, INPUT);
 pinMode(ledPin, OUTPUT);
 Serial.begin(9600);
 xport.begin(9600);
 delay(300);
 Serial.println("Finished Setup...");
 Xservobj.attach(9);
 Yservobj.attach(8);
 buttonIs = digitalRead(buttonPin);
}

//===============Functions===================//

void getButton() { 
  buttonWas = buttonIs; // Set the old state of the button to be the current state since we're creating a new current state. 
  buttonIs = digitalRead(buttonPin); //Read the buttong state.
}

void errorBlink(){ //Flash 4 times for an error
     for (int x=0; x <=3; x++){  
   digitalWrite(ledPin, HIGH);  
    delay(100);  
    digitalWrite(ledPin,LOW);  
    delay(100);  
   }  
}

char * resetXport(){ //Handles the regular reset of the Xport, returns reset errors
        ret = xport.reset();
       switch (ret) {
          case  ERROR_TIMEDOUT: {
           Serial.println("Timed out on reset!");
           errorBlink();
         return 0;
      }
      case ERROR_BADRESP:  {
         Serial.println("Bad response on reset!");
         errorBlink();
         return 0;
    }
  case ERROR_NONE: {
     Serial.println("Reset OK!");
     break;
    }
    default:
      Serial.println("Unknown error");
      errorBlink();
      return 0;
       }
  delay(250);
}


char * ConnectToggle(){ //This function turns the connection on or off
  
  if (ledState == 1){ //if the LED is off, then the client is not connected.
  resetXport(); //run the reset function
  ret = xport.connect(IPADDR, PORT);
  switch (ret) { //swtich case handles various error states
    case  ERROR_TIMEDOUT: {
     Serial.println("Timed out on connect");
      ConnectState = false;
      errorBlink();
     return 0;
  }
  case ERROR_BADRESP:  {
     Serial.println("Failed to connect");
      ConnectState = false;
      loopCount++;
      Serial.print("Loop count =");
      Serial.println(loopCount);
      ConnectToggle();
      if (loopCount >  2){  //For reasons I have not been able to figure out, it usually takes two tries to connect    
         errorBlink();
         ConnectState = false;
         break;
  }
  }
  case ERROR_NONE: {
    Serial.println("Connected..."); 
    ConnectState = true;
    Serial.println(ConnectState);
    digitalWrite(ledPin, HIGH);
    ledState = 0;
    loopCount = 0;
    break;
  }
  default:
    Serial.println("Unknown error");
     ConnectState = false;
     errorBlink();
    return 0;
 }
 }
  else { //Toggle off connection
    ledState = 1;
    digitalWrite(ledPin, LOW); //turn OFF the LED
    xport.println("x"); //Send the x command that kills the session.
    delay(100); 
    xport.disconnect(); 
    Serial.println("Disconnected.");
    ConnectState = false;
  }
}

void fetchStuff() { //Gets the linebuffer
   xport.flush(100);
   xport.println("g"); 
   ret=xport.readline_timeout(linebuffer, 16, 200); // get first line
   while(ret!=0){
     ret=xport.readline_timeout(linebuffer,16,200);
  }
}

void moveServos(){ //Note that the server sends out the X, Y & Z values, but Z is not used. It could be.
   Xval = (((linebuffer[1] - 48) * 100) + ((linebuffer[2] - 48) * 10) + (linebuffer[3] - 48)); //Extract X value & convert the ASCII to integers
//  Serial.print("Xval:  ");
//  Serial.println(Xval, DEC); 
  
  Xservo = map(Xval, 275, 425, 0, 180); //Map the range of X values from the server to the servos
   Serial.print("Xservo:  ");
  Serial.println(Xservo, DEC);
  Xservobj.write(Xservo);
  delay(15);  
   
   Yval = (((linebuffer[5] - 48) * 100) + ((linebuffer[6] - 48) * 10) + (linebuffer[7] - 48));//Extract Y value & convert the ASCII to integers
//   Serial.print("Yval:  ");
//   Serial.println(Yval, DEC); 

  Yservo = map(Yval, 275, 425, 0, 180); //Map the range of Y values from the server to the servos
   Serial.print("Yservo:  ");
  Serial.println(Yservo, DEC);
  Yservobj.write(Yservo);
  delay(15);     
}
  
//==============Main loop==================//

void loop()   { // run over and over again

getButton(); //Run to check if button has been pressed.

if((buttonIs == 1) && (buttonWas == 0)){
  ConnectToggle(); //If there is a change in the button state, toggle the connection on or off.
}

if (ConnectState == true){ //If the client is connected, do some work!!
  fetchStuff();
  moveServos();
  }
}

Further work
The system needs a way to detect dropped connections - possibly using "millis()" to determine if a response or query has taken too long. As well, I really should smooth out those analog readings so the servos don't jitter! As well, I might just build a motion ase of some sort to hook up to the servos so they can do something slightly more cool that just flap their arms.
So, that's my first Arduino project in a few months! Thanks for the comments and questions. The site has apparently had over 11,000 hits, which completely amazes me. Please keep the comments and suggestions coming. I think next up will be another Chinese knock-off phone review.


Monday, December 14, 2009

Gianttech Plasma Cutter

As mentioned in the previous post, I have bought a plasma cutter a short while ago from the good folks at http://www.plasmametalcutter.com/. Since I only have 110 service in the garage, I had to opt for the Cut40D model (which is confusingly called the Slice40D on the face of the unit). This model features auto-switching between 110 and 220. It comes with a 220 plug on the end, but it is easy enough to switch it for a 110 style plug. I opted for the 110 20 AMP style plug.

All in all, it is a very good study unit. It slices through sheet metal like it isn't even there and so far does fine up to at least 1/4" mild steel. I haven't yet tried it out on thicker stock, but I'm not sure if it could go to a full 1/2" or not. Most of my projects are with 1/8" angle iron stock and it blasts through that with no problem. Like welding, you need to watch the safety precautions and it takes some practise to make steady cuts - especially straight lines.

The Gianttech folks I bought the unit off of were very helpful, however shipping up here to Canada took quite a while, but as a hobbyist I wasn't in a huge hurry. I also bought the package of extra consumables available for the unit since I read that these can be used up quickly. I have had to change the tip once, but I think that is because I fried it when I was learning how to use the unit. Now that I have more practise, I am not noticing much deterioration of the tip or other consumables.

I also had to upgrade my air compressor to an 8 gallon 2+ HP unit. I ended up buy this unit from Boss Tools. It is a very sturdy compressor that seems to deliver loads of pressure! While the Cut40D comes with a combination air regulator and filter, on the advice of my welding teacher, I also added in an extra filter (this item). Apparently, the drier and cleaner the air, the better the cutting and the longer the consumables will last.

Here is a quick video of the cutter in action (note that I keep calling it the "Slice40D" since that is what the face of the unit says):



I only had a couple of small issues with the unit. Like many Chinese tools, the manual was laughably short. My Lincoln Electric MIG welder came with an encyclopedia compared to the Gianttech cutter! However, what was there was adequate to get started.

Another issue was that I initially got a lot of air leakage from the hoses connecting the regulator/filter unit to the cutter. First, I replaced the hose clamps and that mostly fixed it, then I replaced the 1/4" NPT-hose barb fitting off of the regulator and that fixed it. Again, pretty small stuff, and I suppose typical of the small "fit and finish" items you find on Chinese tools (my lathe & milling machine also needed minor tweaks). For the money, I am frankly amazed with how well it works. If I were running a full welding shop, I would probably opt for a heavy duty Miller machine or something, but for a "weekend warrior" hobbyist like me it works great!

Plasma Cutting Table

Plasma Cutting Table

Maintaining my blistering pace of a posting every month or so, here is another project write-up along the metal working lines. I recently bought a Gianttech plasma cutter from the good people at http://www.plasmametalcutter.com (which I will post about shortly). It became obvious pretty quickly that just cutting things on the edge of the welding table wouldn't work very well - and risked damaging my beautiful 3/16 steel top for the welding table. So, the answer was to build a simple plasma cutting table.

At it's most basic, a plasma cutting table is just a set of steel slats turned on their end that conduct electricity to the workpiece, but won't interfere with the cutting action because of their thin profile. I decided that the most reasonable design was to go for 1 1/5" slats of 1/8" thick mild steel. I also figured that the grating part of the table would take a lot of abuse from cutting so it would be good to make it so it could be easily turned over and eventually replaced. The basic idea then was to build the grate as one unit, then have it be able to be set onto the base frame to make the completed table. The base frame is made from good ol' 1 1/2" x 1/8" angle iron. The table surface area is 2' x 2'.





The first parts that I made (which I didn't take pictures of) were two angle iron squares. One makes up the top frame and the other is the cross brace for the legs.

Here is the construction process for the grate - I just used corner clamps to keep adding in more and more slats. They are positioned just slightly over 1 1/2" apart so they space out evenly:



When it was done - and with a bit of grinding and fitting - the grate fit perfectly into the top frame:



Here are the grate, squares and legs waiting for assembly:




...and here is the completed unit:



Ah, the astute observer will notice, why isn't the grate nestled neatly in the top frame the way it was designed? Because i managed to weld it together upside down! Arrgghh! Another lesson that WELDING IS PERMANENT! Double check everything before reaching for the welding gun. However, I was able to weld some extra angle iron onto the top frame to hold the grate. So, it ends up being an inch or so higher than I might have liked, but otherwise is very usable and the top is still easily replaceable:




It's all stores up nice and compact and when I need to work, I can just swing the welder and cutter out on their trolley.

Monday, November 16, 2009

My Welding Cart

Having finished up my welding table, the next step was to have something to actually put my welder on rather than having it sit on the floor. So, I built the following which is based on a plan from "Welding Complete" from Creative Publishing International (available from Amazon here). However, I needed to modify the original plan to make it a bit wider so my plasma cutter would have a place to stay.

Here is the drawing- which omits the wheels which were just purchased from the local home center:


I won't bother going through all the build since it was basically the same as the welding table, but one thing I forgot to get a picture of was the correct way to align the upright components for welding, which is like this:




Use a carpenter's square to ensure the uprights are at a perfect 90 degrees before welding! I missed this crucial step with one of the legs on my welding table and it will be ever so slightly out of square forever now. Welding is definitely a measure THREE times, cut once, measure TWO MORE TIMES then weld type of process.

Here is the whole frame before painting. The hooks are to hang cables off of, but I am a bit worried I will be catching my knees on them.



Finally, a good thick coat of tractor green paint covers a multitude of sins! Actually, we have a pool pump in the same garage as the welding gear and occasionally small amounts of chlorine gas seep out and rust steel instantly, so I really need to paint everything to preserve it. I also put the rubber matting on the help protect the finish and provide some extra electrical insulation.




Here is the whole team! Note that the welding cart is extra wide so the plasma cutter can go beside it.



Next up... Bringing some order to my chaotic garage and workshop, which is hardly a project worth blogging about! I will be welding up some shelves and cabinets as part of the process and I will post that later. I also promise to get back to the Arduino soon. I have another Ethernet shield I haven't yet got assembled and I really want to look at networking two Arduinos together and having them do something halfway useful!

Thursday, November 5, 2009

Welding Table Construction

In honour of Monty Python's 40th Anniversary... And now for something completely different!

I believe way back in the original start of the blog, I explained that I also did a lot of machining including designing & building steam engines a few years ago. I had always meant to take a welding course, and on a whim I decided to finally do that this fall. So, the last few Saturdays I have been struggling out of bed at 6:30 AM to get into to weld with a huge stick welder (Shielded Metal Arc Welding - SWAM) process. Naturally, I have gotten totally obsessed and decided to get a welder for myself!

Originally, I wanted to get a 240 VAC stick welder, but my friendly neighborhood electrician told me the garage wiring just wasn't up to it, and this is hardly something I want to do inside the house! After some research, I settled on a Lincoln Electric MIG-Pak 140 unit which runs off of regular 120 VAC (similar to this) that does Metal Inert Gas arc welding (aka GMAW - Gas-shielded Metal Arc Welding). Fortuitously, it went on a good sale and I picked up a bottle of C02/Argon shielding gas, a leather welders coat and an auto-darkening welding helmet and I was set!

The technique and setup for the MIG welding is quite different from the big Hobart industrial units I am using in class, but MIG welding is pretty easy to at least pick up the basics of. The good thing with getting used to using the big welder in class is it gives you a very healthy respect for all the safety precautions and you get all the good theory on how everything is supposed to work and the various types of welds as well as the good advice of an experienced instructor.

So, after fooling around with my welder to get a feel for how it performs with various thicknesses of metal and so on, I decided the first traditional project for a starting welder is to build a metal welding table. I need the extra surface space in the shop and I definitely need a metal surface table for arc welding.

Step 1 - I worked up a design to get the rough dimensions and the shopping list for the metal store:




This used 1 1/2 inch square tubing for the legs, 1 1/2 angle iron for the frame and 3/16 thick sheet for the table top.

Step 2 - I bought the table top already cut to size and then cut down the frame and leg pieces from the ten foot lengths I bought. Here are the parts laid out before welding:





Step 2 - First I welded the frame that supports the top. The parts were cut mitered and then I put them on some firebricks on the top itself - on the assumption that the top is more level that the old floor of my garage!



Step 3 - With the top frame done, then I welded the plates for the caster wheels to the bottom of the legs:




Not too bad MIG welds considering I am just starting out!



Step 4 - I welded the leg assemblies to the frame assemblies. I wish I had captured the proper way of lining up the legs perfectly perpendicular to the frame! I actually messed up the first leg and it went on slightly out of true, but the other three legs went on perfectly. You will see later that it's not too bad and the one leg being slightly out won't be too big an impact. Once the legs are welded onto the frame, I needed to grind down the welds on the top of the frame so it would mate properly to the table top:




Step 5 - The frame and leg assembly was welded to the top. Here I use an intermittent rather than a continuous weld:



Step 6 - Roll it out of the shop and paint it! The slats are 1 1/2 inch wide 1/8 thick strapping I added to make a shelf for storing stock and other bits & pieces. Can you tell which leg is slightly out of alignment?



Here it is with good double coat of primer:




Finally, it got a good heavy coat of Tremclad basic green glossy paint so it looks like a tractor!





A nice substantial first welding project and something very useful for the shop! Next up will be a cart to put the welder on and my new plasma cutter which I should get next week.

Some day, I will combine the Arduino, welding and maching stuff into one project, promise!