Search This Blog

Saturday, February 26, 2011

Position sensor for Arduino XYZ CNC Carving Machine

This is a sub post of the larger XYZ machine post project.  This piece is about an Arduino based module that reads rotary encoders and displays on an LCD the current machine position;

A couple photos of the breadboard version.  Note the three encoders are under the display, this prototype wasn't really meant to be used for anything.  Of course the permanent version will have the encoders attached to the XYZ machine and not on a breadboard.


This picture (pardon the rotation) shows the display, you can just see one of the encoders on the breadboard below the display.  This picture was taken before I added the math to print out converted inches, it just shows the raw encoder count.





I might also later have at least one button to set the home position, or I may just rely on the Arduino reset button to set 0,0,0.  Some sort of home/limit switch setup might be nice too.


The encoders are attached to the ends of the drive screws for the platform.  I used a short piece of flexible plastic tubing from the hardware store, because I couldn't find set screw shaft couplers the right size for any reasonable price.  The hose gives me a little flex, so it should be OK.  It stretches over the encoder shaft and the drive shaft.








Using rotary encoders from sparkfun. They are inexpensive, I hope they hold up to the job over time.  They are really for human  input knobs. http://www.sparkfun.com/products/9117  
Datasheet: http://www.sparkfun.com/datasheets/Components/TW-700198.pdf
Later I swapped with some slightly different encoders from Digikey 
http://search.digikey.com/scripts/DkSearch/dksus.dll?WT.z_header=search_go&lang=en&site=us&keywords=987-1199-ND&x=20&y=18
http://www.bitechnologies.com/pdfs/en16.pdf
I changed because these didn't have detents, which tended to snap the encoders to certain values.  Also these had threaded shafts and were easier to mount.  For $1.18 why not get the best?


Some example rotary encoder code that I started with is here:
http://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino


The example code worked out of the box, I modified it to read three encoders at the same time. 
It makes use of port manipulation to read all the input simultaneously.  This page helped http://www.arduino.cc/en/Reference/PortManipulation
However, this guy must have been a programmer for a living, the program was basically 2 lines and very hard to understand.   I wrote my version with more comments and a little less pizazz.  Hopefully more understandable.


Got the three encoder code working, included it below, it was a bit tricky.   


I added the LCD readout, attempting to keep the code delays as small as possible so we don't skip and encoder positions.  The LCD is hooked up pretty much like all the Arduino examples, using 4 bit wide parallel mode.  I like to use pins 7 6 5 4 3 2 because it keeps all the LCD pins on the same Arduino connector.   You might note in the photo there is a adafruit arduino prototype board and some headers that I use to stack the LCD on top of the Arduino and map the pins.   I'm not going to repeat the LCD interfacing stuff in this post.   The Optrex display i used is cost effective but a bit quirky, it has the tendency to print garbage if you give it commands too fast.


The code is after the break:

Monday, February 21, 2011

Arduino based "crazy clock" idea

I thought of something fun to do with them, to make an analog crazy clock or backwards clock.
I have some small stepper motors from adafruit.
The arduino could keep time, and drive the steppers to move the hands in any pattern you want.
This could mimic a watch I've seen where the hours are out of order.
http://www.blogcdn.com/www.luxist.com/media/2009/05/franck-muller-crazy-hours-watch-blue.jpg

Just writing it down to come back to it later if I get bored

Sunday, February 20, 2011

Replaced the windshield washer nozzle in a 04 Sienna minivan

Ice and snow broke off the black plastic washer nozzle on the hood of my minivan.   Activating the windshield washer resulted in a fountain of spray straight up, no where near the window.  Here on the east coast, you lose your windshield washer, it is pretty much not safe to drive your car in the winter.

Looked all over the internet, and found it is really hard to buy a replacement.  None of the online auto part stores, ebay or amazon had it.   Some cars are there, but not mine.  Had to resort to going physically to the dealer and buying it.  Yuck.  But the Toyota dealer had it.

Fun part is, you open the hood and it is very tough to access the nozzle.  They have press in ears that clip them in place.  Under the hood is an insulation layer of fabric that has press in clips.  Removing it looked like a very bad idea, the clips were going to break and the fabric tear.  I pried up one edge and could sneak my hand under.  Felt around and couldn't access the back of the washer still to free it up because of the metal.

Found an easy way to do it from outside the car, that worked great.  Grabbed what remained of the nozzle with some pliers and crushed it.  That left the base in the hole, and I was able to use a small screw driver to release the clips from the top of the hood and pull it up out of the top of the hood with the hose still attached.  Pulled off the hose from the old nozzle, and put the new one on the hose.  Snapped the new nozzle into the hole and Voila!.  Took less than 5 minutes this way!

Monday, February 14, 2011

Arduino LCD Countdown Clock

Quickie project for a desktop clock that counts down to when my work project has to be done, then counts how many weeks it is late.


The design is the "raw electronics" look.  The arduino is mounted on the back of the large LCD display by nothing more than a stacked header, and hot glued to a small piece of wood for a base.

The code is built on top of the basic example for a clock that syncs from the PC, found here:
The Arduino Time Library on the Arduino Playground
http://www.arduino.cc/playground/Code/Time

When plugged into the PC and using the Arduino serial monitor, it waits for you to enter a unix timestamp.
You can generate these from web sites like these ones:
http://www.timestampgenerator.com/
http://www.unixtimestamp.com/index.php

They have the form of seconds since Jan 01 1970, type in T1297687386
Type that in the start the clock.  There are PC programs out there that run a host to send that string, like gobetwino if you want to do that to, you don't need to.  This is just a manual start.

Change this variable in the code to the unix timestamp of the event you want to count down to
signed long tapeout = 1309539600;

The hardware is nothing more than an arduino interfaced to a huge 20x4 backlit LCD module, using the 4 bit wide parallel communication mode.  The pinout is a very slight mod to the descriptions in the Arduino examples, because I like to group the pins all on one header.   This is exactly like the setup in the Arduino examples.

I use an external wall wart as power, so it doesn't have to be plugged into the PC all the time.

Here is the code




* Sketch for 4x20 LCD to display current time and date, and countdown of weeks, days, hours, min to an event
 *
 */

#include <Time.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6 , 5, 4, 3, 2);

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message
#define TIME_REQUEST  7    // ASCII bell character requests a time sync message

signed long tapeout = 1309539600;

// to make sure the display is cleared once a day
int yesterday = 0;
int weeksleft = 0;
int daysleft = 0;
int hoursleft = 0;
int minleft = 0;


void setup()  {
  lcd.begin(20, 4);
  lcd.clear();
  //backlight on pin 8
  pinMode(8, OUTPUT);
  digitalWrite(8, LOW);
  Serial.begin(9600);
  setSyncProvider( requestSync);  //set function to call when sync required
  Serial.println("Waiting for sync message");
  Serial.println("Unix Timestamp");
  Serial.println("Example T1297674000");
  lcd.setCursor(0,0);
  lcd.print("Waiting for PC time sync...");
}

void loop(){  
  if(Serial.available() )
  {
    processSyncMessage();
    digitalWrite(8, HIGH);
  }
  if(timeStatus()!= timeNotSet)
  {
    digitalClockDisplay();
  
    // clear the display if the day changes to clear glitches
    if (day() != yesterday) {
        //lcd.clear();
        yesterday = day();
    }
  }
  delay(20000);  //can be set to 1000, this makes the display more stable
}

void digitalClockDisplay(){

  //turn on backlight only during workday
  if((hour() >= 8) & (hour() < 19)) digitalWrite(8, HIGH);
  else   digitalWrite(8, LOW);

  // digital clock display of the time
  lcd.setCursor(0,0);
  Serial.print(hour());
  lcd.print(hourFormat12());
  printDigits(minute());
  //printDigits(second());
  Serial.print("   ");
  if (isAM()) lcd.print(" AM ");
  if (isPM()) lcd.print(" PM ");
  Serial.print(dayStr(weekday()));
  lcd.print(dayStr(weekday()));
  Serial.print(" ");
  lcd.print(" ");
  lcd.setCursor(0,1);
  Serial.print(day());
  lcd.print(day());
  Serial.print(" ");
    lcd.print(" ");
  Serial.print(monthShortStr(month()));
    lcd.print(monthShortStr(month()));
  Serial.print(" ");
    lcd.print(" ");
  Serial.print(year());
    lcd.print(year());
  Serial.println();
  lcd.setCursor(0,2);
  if (tapeout < now()) {
      weeksleft = (now() - tapeout)/60/60/24/7;
      daysleft = (now() - tapeout)/60/60/24 - weeksleft*7;
      hoursleft = (now() - tapeout)/60/60 - daysleft*24 - weeksleft*7*24;
      minleft =  (now() - tapeout)/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
      lcd.print(   weeksleft   );
      lcd.print("wk ");
      lcd.print(   daysleft   );
      lcd.print("d ");
      lcd.print(   hoursleft   );
      lcd.print("h ");
      lcd.print(   minleft  );
      lcd.print("m ");
      lcd.setCursor(0,3);
      lcd.print("Late! OMG! Ship It!   ");
  } else {
      weeksleft = (tapeout - now())/60/60/24/7;
      daysleft = (tapeout - now())/60/60/24 - weeksleft*7 ;
      hoursleft = (tapeout - now())/60/60 - daysleft*24 - weeksleft*7*24;
      minleft =  (tapeout - now())/60 - hoursleft*60 - daysleft*24*60 - weeksleft*7*24*60;
      lcd.print(   weeksleft   );
      lcd.print("wk ");
      lcd.print(   daysleft   );
      lcd.print("d ");
      lcd.print(   hoursleft   );
      lcd.print("h ");
      lcd.print(   minleft  );
      lcd.print("m  ");
      lcd.setCursor(0,3);
      lcd.print("To Santan Tapeout! ");
  }
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  lcd.print(":");
  if(digits < 10){
    Serial.print('0');
    lcd.print('0');
  }
  Serial.print(digits);
  lcd.print(digits);
}

void processSyncMessage() {
  lcd.clear();
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    char c = Serial.read() ;
    Serial.print(c);
    if( c == TIME_HEADER ) {    
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){
        c = Serial.read();        
        if( c >= '0' && c <= '9'){
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number  
        }
      }
      setTime(pctime);   // Sync Arduino clock to the time received on the serial port
    }
  }
}

time_t requestSync()
{
  Serial.print(TIME_REQUEST,BYTE);
  return 0; // the time will be sent later in response to serial mesg
}