Tuesday, April 29, 2014

Blistex Linear Actuator

Update:  5/19

I ordered a servo rotary driver from Servo City (part # SR500) which is a better way of coupling the leadscrew to the servo hub.  With a bit of modification, I was able to attach the leadscrew in a very permanent manner.  After reassembling and a slight modification to the location of the "in" magnetic sensor, the linear actuator is working great.

In the following video, I manually start the servo moving in or out, but it automatically stops at the limits (you can see the limit sensor values change from 1 to 0).  Near the end, I demonstrate that you can also use S to stop the actuator at locations other than the endpoints.  The code is the same as before.



Original Post

This project has been on my "to-do" list for quite a while.  All credit to the Matt Peick:  http://makezine.com/projects/make-34/the-mighty-lip-balm-linear-actuator/ .   Although it's a pretty simple build, I've had problems getting the lip balm "leadscrew" to attach to the servo shaft.  I've tried several kinds of glue (JB Weld*, Bond 527 cement) and tried to get a screw between the two of them but the leadscrew diameter is too small.  As a result, the linear actuator can push out fine, but the leadscrew pops off the servo as the linear actuator pulls in.  You can see this in the video below where the sound of the servo changes noticeable when the leadscrew comes off and the servo is now free-spinning.



I've ordered a couple items from ServoCity and I'm hoping one of these will allow me to make a better connection.  But for now, my implementation of this idea is not ready for usage.

Custom code for this item is on Github:  it allows in and out motion to be triggered using a serial window and also gives a bit of troubleshooting data (the sensor values and the servo pulse width).  https://github.com/gcronin/GPSLockbox/blob/master/blisterservo/blisterservo.ino

*Note: JB Weld is surprisingly poor at holding together plastics, especially smooth ones!


GPS Lockbox: Code Done, Assembly Begun

Last time I posted about the "guts" of a lockbox which would open when a certain location was reached.  The user would input a destination, start the program, the box would lock, and would not open again until the user were close enough to the destination.

I had worked out the details of reading the GPS, using the keypad through a GPIO I2C board, using a 8x2 LCD, and using some RGB lights as indicators.  Since that point, I have upgraded to a 16x2 LCD, and greatly upgraded the code, which now asks for user input (a destination location), calculates the distance to the location, modifies the RGB lights to have a color proportional to the distance to target (from blue == far away to red == close), and "unlocks" the box when close enough.

Original prototype for a 16x2 breakout board
for a Sparkfun LCD.  This is the one I am using
for the GPS lockbox.
The first modification was to use a 16x2 LCD from Sparkfun.  Data sheet is here.   It is SO much bigger than the 8x2, and it operates in 4bit mode meaning that only four of the eight data lines (DB0 - DB7) are needed to "run" the LCD.  I made a PCB breakout board for this one:  the Eagle data files can be found here. This process also opened up four more pins on the Arduino Micro... Enable, R/W, DB4, DB5, DB6, and DB7 are running to the analog inputs, freeing up four of the digital pins.

For the newer prototypes, the potentiometer
is underneath the LCD to minimize space.

I had previously had some confusion about the differences between different ways to represent GPS data.  I have standardized the code such that it always represents data in the format dd mm.mmmm.  This happens both when data is printed back to the computer over the serial port, and also when data is printed on the LCD.  This format can also be found easily online in many places like GPS Visualizer (see the picture below).  So this should make the process of inputting a destination pretty easy.

Next I added in code which allows the user to put in the target destination.  The most current version of the code is on GitHub.     The flowchart below shows the way that the keypad is read.  This is important, because it takes about a second to read the GPS and we only want this to be happening when the user is not entering data.  Otherwise the delay is impossibly confusing.  In addition, the flowchart always allows us to "start over" at any point by pressing A, so that we can always enter a new destination without having to restart the microprocessor.

The right hand side of the code is very similar to what I had in the first iteration.  The biggest change is that I realized that I needed to look for the $GPGGA ANYWHERE in the GPS string and not just at the beginning of the string.  I had thought my previous code did this, but I was wrong.  The line below looks for $GPGGA and also looks for an astericks after $GPGGA.  Since $GPGGA is at the start of the string and * indicates the checksum, the Parse flag is only set if a full string has been seen.

 if(StringContains(buffer, "$GPGGA")!= -1 && StringContains(buffer, "*") > StringContains(buffer, "$GPGGA")) {
        startPosition = StringContains(buffer, "$GPGGA") +7;
        Parse = true;
      }

The distance function on the right side is one that I just pulled directly from the internet.  I have no idea how it works; has to do with finding the distance along a great circle between the current location and the destination location.

The rest of the code is straightforward although the implementation is pretty course.  The Setup Program drops the Latitude Setup Flag, prints a prompt on the LCD for the operator ("Latitude: ddmmmmmm"), zeros the input buffer, and turns the LEDs red to show that we are waiting for input.

The Latitude Setup Program reads in the latitude as it is typed (slowly shifting the LEDs towards green) and prints the inputs on the LCD so that they replace the ddmmmmmm.  It takes 8 digits, then prompts the user to "Hit D".  Hitting D raises the Latitude Setup Flag, drops the Longitude Setup Flag, prints a prompt on the LCD for the operator ("Longitude: dddmmmmmm"), turns the LEDs red, and zeros the input buffer.  The Longitude Setup Program does the same thing as the Latitude Setup Program, raising the Setup Flag at the end.

The structure of the program allows the user to type A at any time which will lower the Setup Flag (bypassing GPS readings until the flag is set again) and allowing the setup program to run again in its entirety.

The last piece of this puzzle has to do with the RGB LEDs.  Originally I had hoped to have them fade throughout the program with the rate of fading increasing as the user got closer to the target destination.  While I updated the function fadeColor to be asynchronous (so the colors would change as the main loop cycled without a separate loop within the function), I found that the fade rate was limited by the loop cycle time, which was relatively slow because of the time required to read the GPS.  Fades either go impossibly slow OR huge jumps in color must be done each loop, which looks stupid.  So I will only use the fading at the very end as a sort of celebration once the box is opened.  Otherwise, once setup is done, the color of the LEDs is just set on a scale between RED (255, 0, 0) or BLUE (0, 0, 255) using a scale factor (eventually i'll program in the user to enter the approximate distance to the target and that will be the scale factor).  The variable "precision" is a threshold for how close the user needs to be to the target before the box opens.


I am working on putting all the components into a hinged box bought from Staples, product #942401.  Fortunately it laser prints beautifully.  I will have to figure out how the box physically locks.

Sunday, April 13, 2014

GPS Lockbox "Guts"

Often with complex projects which involve a lot of different components which have to talk to each other, I will work on the guts in stages without worrying about what the final product will look like.  Using getting the guts to work together is a huge part of the project and the cosmetic details are a secondary consideration.  If the "insides" don't work, it doesn't matter how pretty the outsides look.

This project is envisioned to be a modification of the lockbox which allows the box to open when a certain location is reached (rather than when a certain code is entered).  The lockbox then is a little like the inverse of going geo-caching.  Rather than knowing the GPS coordinates but not having the item at those coordinates, you have the item but not the coordinates.

The guts of this project are shown in the picture at left.  The GPS modem (MediaTek 3328, labelled GTPA010, datasheet here) returns time, latitude, longitude, and altitude at regular intervals (2-3 seconds or so) using a serial connection.  The LCD is the same one I used for the calculator, although I made a nice PCB board for it to simplify the connection process.  Eagle CAD files for the board are here.  This is necessary because the LCD board requires 8-bit mode and therefore has 16 pins and requires 10 inputs plus +5 and GND.   The board even has a spot for a 10k potentiometer so you can adjust the contrast of the LCD.  The keyboard is the same one used for the lockbox and the calculator, but this time I've routed it through a I2C GPIO board from dfrobotics.   The RGB LEDs will be used to provide the user with visual feedback of some type depending on whether he/she is getting closer or farther away from the destination target.  Think of them as a visual way of playing "hot or cold".  The servo will open the lockbox.  Estimated costs:  $25 for Arduino Micro + $15 for Keypad + $6 for LCD + $13 for I2C GPIO + $12 for servo + $40 for GPS =~ $80 + consumables.

The current setup uses every single pin of the Arduino Micro.  Check out the pins assignments:

I started with getting the GPS modem working.  There was lots of great help online for doing this, and I want to credit these two websites for getting me all set: http://letsmakerobots.com/node/34050 and http://forum.arduino.cc/index.php?topic=7490.0.  The first showed me how to hookup the GPS using a softserial interface.  Apparently for this modem a normal hardware serial interface doesn't always work, but the software serial port seemed to do the trick.  It also took me a while to realize or find out that SoftSerial only works on certain pins... this problem was a recurrent one as I switched around pins or migrated to a different Arduino board.  For my original setup, I was using a 1280 Mega, and found out that the "Not all pins on the Mega and Mega 2560 support change interrupts, so only the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69)" - Arduino SoftSerial Documentation.  Once I used the appropriate pins, and a simple program to setup the SoftSerial connection and then read in the available data, I was seeing a stream of text from the GPS.

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3, false);
void setup()  
{Serial.begin(4800);
  mySerial.begin(4800);}
void loop()
{if (mySerial.available())
    Serial.write(mySerial.read());
} 




The next step was to take the serial input data and parse it into useful information.  The MediaTek datasheet shows that the GPS outputs data in several modes (GGA, GSA, GSV, RMC, VTG) and I was seeing parts of all of those modes.  However, the mode that I was consistently getting a full string from was GGA.  I could tell because I could see the string starting with $GPGGA and ending with *OF or some similar two hexadecimal checksum starting with '*'.  So I decided to parse that string.  My savior was codename GeckoCH from the second site listed above, who posted code to parse a GPGMC type string.  I was able to adapt this code to read in serial data until it found "$GPGGA", then pull the time, latitude, longitude, and altitude.  I have not implemented a checksum check because the datasheet does not show how the checksum is calculated.

The function readline pulls in serial data until a buffer overflow would occur (bad) or a carriage return is seen (good).  According to the GPS datasheet, a carriage return is the end of each sequence.

void readline(void) {
 char c;
  bufferIndex = 0;
  while (1) {
      c=mySerial.read();    // read a byte
      if (c == -1)          // if the byte is -1 don't record and skip to the next byte
        continue;
      //Serial.print(c);
      if (c == '\n')        // if the byte is newline don't record and skip to the next byte
        continue;
      if ((bufferIndex == BUFFERSIZE-1) || (c == '\r')) {    // if buffer overflow OR byte is a carriage return, reset the buffer and quit readline
        buffer[bufferIndex] = 0;
        return;
      }
      buffer[bufferIndex++]= c;  // otherwise store the byte
  }

The only problem with this function is that if the GPS is sending nothing, this function doesn't break out of the infinite loop.  That's a bug to be fixed later.  Next in the main loop we look for the first six characters of the buffer to match the string $GPGGA.
if (strncmp(buffer, "$GPGGA",6) == 0)  // Parse the string when it begins with $GPGGA
   { 
    Serial.println(buffer);

This is somewhat confusing since when we look at the buffer, the first six characters are never $GPGGA; they are other parts of the string from the modem.  But I think somehow the buffer gets shifted to the left each cycle so that at some point the string $GPGGA ends up at the front.   Anyhow, it works.  When that happens (and only when that happens), we parse the string looking for deliminators like decimals and commas, and pull out the appropriate data between those deliminators.  For example, the code below finds the longitude by looking after a comma.  It skips the decimal (because floating point math is notoriously bad) then adds in the numbers after the decimal.

// longitude
    parseptr = strchr(parseptr, ',')+1;
    longitude = parsedecimal(parseptr);
    if (longitude != 0) {
      longitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      longitude += parsedecimal(parseptr);

uint32_t parsedecimal(char *str) {
  uint32_t d = 0;
  while (str[0] != 0) {
   if ((str[0] > '9') || (str[0] < '0'))
     return d;
   d *= 10;
   d += str[0] - '0';
   str++;
  }
  return d;
}   

GPS data comes in at least three formats that I have seen.  The first is a straight decimal.  For example, the location of the school that I work at is latitude: 47.6129121, longitude: -122.3161762 (I found this using this cool website for which you can enter an address and find the GPS coordinates).  Latitude is a degree between -90 and 90, where 0 is the equator, the northern hemisphere is positive numbers up the to north pole (90), and the southern hemisphere is negative numbers down to the south pole (-90).  Longitude is measured relative to the prime meridian and goes from -180 to 180 with negative numbers for longitudes west of the prime meridian and positive numbers east of it.

The second and third formats are Degrees, Minutes, Seconds and Degrees, Minutes.  In the latter format, my school's address is N47° 36.7747', W122° 18.9706' .  For more details on going back and forth between these types, see http://en.wikipedia.org/wiki/Geographic_coordinate_conversion.   According to the Mediatek datasheet, the GPS output is in the format ddmm.mmmm for latitude and dddmm.mmmm for longitude.  This means the first two/three numbers are degrees, and the last 6 are minutes with a decimal.  The raw output at my school is shown below, which we can interpret to mean N47° 36.7557', W122° 18.929' . This is pretty close, although not perfectly aligned with the online coordinates.

It will be useful for me to convert from the GPS output (eg ddmm.mmmm) to a decimal because I will be wanting to calculate the difference between the current location and the destination location.  This conversion can be done (using floating point math for now...may need to change is precision suffers) by using the equation DD = D + M/60.  So, for example, if ddmm.mmmm = 4736.7557, then DD = 47 + 36.7557/60 = 47.6125. More on that in a subsequent post.

The test code I downloaded (from codename GeckoCH) prints out latitude and longitude in Degrees, Minutes, Seconds format using the integer and mod trickery below (note that previously the raw value from the GPS modem was multiplied by 10,000 to eliminate the decimal.

      Serial.print(latitude/1000000, DEC); Serial.print("\260"); Serial.print(' ');
      Serial.print((latitude/10000)%100, DEC); Serial.print('\''); Serial.print(' ');
      Serial.print((latitude%10000)*6/1000, DEC); Serial.print('.');
      Serial.print(((latitude%10000)*6/10)%100, DEC); Serial.println('\"');

The output from the computer's serial monitor looks like this:


I would like the final lockbox to be a stand-along unit which doesn't require a computer.  Therefore, I needed to add a keypad to put in data, and an LCD to display data.  The LCD gave me serious trouble at first; displaying letters only in uppercase or lowercase, and displaying gibberish when I tried to print certain characters (such as a space or !) to the screen.  I had some luck troubleshooting this behavior using test code found from this website:  http://www.microcontroller-project.com/displaying-ascii-characters-on-16x2-lcd-with-ardunio.html which helped me to see that the LCD was displaying only the numbers 0-9, the letters A B C D E, the remainder of the alphabet in lowercase, < > = .  Using the code below, it cycled through this sequence several times before cycling through a set of what looked like chinese characters.

void loop()  {
  int count=33;
  char ascii=0x00+33;
  while(count!=235) {
    lcd.setCursor(0, 0);
    lcd.print("DECIMAL = ");
    lcd.print(count);
    lcd.setCursor(0 , 1);
    lcd.print("ASCII = ");
    lcd.print(ascii);
    count++;
    ascii++;
    delay(1000);
    lcd.clear();  }
}


When I migrated from the Arduino Mega to the Arduino Micro and used a different LCD with my previously mentioned PCB board, the problem disappeared.  I haven't tested the original LCD to see if the problem was with it or the wiring to the Mega.

The keypad is being read from using a GPIO board.  I initially tried the wiring and code displayed on their website: http://www.dfrobot.com/wiki/index.php/Arduino_I2C_to_GPIO_Module_%28SKU:DFR0013%29 which failed to produce output which varied at all.  In fact the sample code just returned 69 (ascii for 'E') regardless of what button was pressed.    In looking at the code, you can get a sense of what it does.  The function below first toggles one of the output pins; the outer for loop does this, setting 0.7 (10000000) high and the other three outputs low, then bit shifting (input = input >> 1) so that 0.6 (01000000) is high, and so on.  While one of the columns is high, it then scans the inputs looking for 1000 (0x8), then 0100, 0010, and 0001.  If it finds a match, it records the values of i and j (which correspond to the column and row of the key pressed) and then calls another function (outputchar) which just returns the key pressed.

unsigned char readdata(void)          //main read function
{
  int input=128;                      //binary 10000000, set pin 0.7 HIGH
  for (int i=0;i<4;i++)               //for loop
  {
    write_io (OUT_P0, input);      
    unsigned int temp=0x8;            //temporary integer, binary 1000, to compare with gpio_read() function  
    for (int j=0;j<4;j++)
      {  
         if (gpio_read(PCA9555)==temp)
         { return outputchar(i,j);}   // output the char
         temp=temp>>1 ;               // shift right
      }
    input=input>>1;                   //shift right, set the next pin HIGH, set previous one LOW
  }
  return 'E';                         // if no button is pressed, return E
}

I tried several troubleshooting techniques.  The first was to use a 5V supply to apply voltage to each of the columns, then press and read the rows using a multimeter.  Sure enough, only when the correct button was pressed did I see 5V.  This told me that the keypad was working fine.   Second, I tried to apply 5V directly to one of the inputs.  I reasoned that this should at least trigger an output other than 'E'.  It did not.    Next I simplified the code, just having it print the value of the 4 input pins (eg print the value of gpio_read(PCA9555)).  I noticed that the output was always 15 (decimal for b1111), which meant that the inputs were pulled high.  This suggested there were pullup resistors on the inputs.

 See http://www.francisshanahan.com/index.php/2009/what-are-pull-up-and-pull-down-resistors/ from which the picture at left is taken.  With pullup resistors, you want to ground the input and look for a low signal.  In the picture at left, when the switch is closed, the input sees GND (digital 0).  With this in mind, I modified the readdata function to look for one of the inputs to be LOW (eg 0111 or 1011 or 1101 or 1110).  One way to code this is to use the code below:

unsigned int temp=0x0F;   //binary 1111
temp ^= (1 << j);  

The ^= symbol is an XOR logic, or exclusive OR.  It compares the two inputs, and if ONLY ONE of the inputs is a 1, it returns a 1.  So if both of the inputs are 1 or both of the inputs are 0, it returns a 0.  In this case, we XOR 1111 with 0001 (when j = 0).  This returns 1110, since the first three bits were a 1 XORed with 0 (giving 1), but the last bit was a 1 XORed with a 1 (giving 0).  Basically, this a tricky way to turn OFF the bit in the "jth" position.   With this code substituted into the inner for loop, I finally saw changes in the output from 15 (1111) to 14 (1110) or 13 (1101) or 11 (1011) or 7 (0111) when buttons were pressed.  However, it didn't matter which row was being pressed.  This suggested that something was still wrong, and that the problem was with how I was setting the outputs.

I guessed that maybe I should be setting only one of the outputs LOW, instead of setting only one of the outputs HIGH, and low and behold, it suddenly all worked.  A wonderful moment.  In retrospect, this is obvious.  Instead of setting one line HIGH and then reading all the outputs for the line looking for one to be HIGH, if the default is already HIGH, we should set one line LOW then read all the outputs looking for one to be LOW.  The updated code which works is shown below:

unsigned char readdata(void)          //main read function
{
  for (int i=0;i<4;i++)               //for loop
  {
    int input=0xF0; 
    input ^= (1 << (i+4));            // toggle output LOW (outputs are 5th - 8th bits)
    write_io (OUT_P0, input);    
    for (int j=0;j<4;j++)
      {  
         unsigned int temp=0x0F;   //binary 1111
         temp ^= (1 << j);  
         if (gpio_read(PCA9555)==temp)
         { return outputchar(i,j);}   // output the char
       }
   }
  return 'E';                         // if no button is pressed, return E
}

The last piece of the hardware puzzle was the RGB LEDs.  I found this very helpful instructable:  http://www.instructables.com/id/RGB-LED-Tutorial-using-an-Arduino-RGBL/ and basically worked off of that.  One test of the analog code (which fades between colors) sold me on the fact that using digital outputs is not very cool.  This is because the digital outputs only turn ON or OFF each of the Red, Green, and Blue LEDs, allowing only certain colors.  If you use a PWM output for each of the colors, you can vary the intensity of each color, allowing basically all the possibly colors.  So much cooler.  Not clear on what I mean?   Watch these two videos and tell me which is cooler :)

https://www.youtube.com/watch?v=TwoXCqJAtLw  (Digital)
https://www.youtube.com/watch?v=SbdazwSjIOU (Analog)

Here's a video of my actual RGB LEDs:

The goal here will be to have the rate of fading depend on how close the user is to the GPS target... speeding up as he/she gets closer.  I've got a little work to do, since the fading code from the instructable is synchronous (eg it uses delay functions to dictate the speed of the code).  I need the LEDs to change colors asynchronously so that the communicates with the GPS can continue to happen.  This shouldn't be too hard by using comparisons with the timers rather than delays.

Current version of the code can be found on GitHub:  https://github.com/gcronin/GPSLockbox/blob/master/GPS_micro/GPS_micro.ino .

Friday, April 11, 2014

PWM 555 Timer Servo and DC Motor Tester

For robotics, my students use servos and Tetrix motors to actuate mechanisms.  Sometimes programming is not their forte or they don't want to take the time to wire up a motor/servo controller to an NXT and 12V battery and write basic code... they just want the servo or motor to run so they can get a quick feel for if a prototype will work.

I put together two testers which allow them to quickly hook up a servo or a motor and test it.  The testers allow full range of servo motion and full range of motor speeds from full forward to full reverse.  Both of the testers use exactly the same circuity; a 555 timer with a variable resistor using a potentiometer to set the pulse width.  For the servo tester, this PWM signal directly controls the position of the servo.  For the motor tester, the PWM signal is sent to a Parallax HB-25 Motor Controller (not cheap, but I had a few lying around already).  The video below shows an oscilloscope capturing a PWM pulse output from an Arduino.  You can see the width of the pulse varying over time.


The schematic for the servo tester is shown at left.  R1 is  ~250k plus the 20k potentiometer from one pin to the sweep (eg 250k - 270k).  R2 is 12k plus the rest of the potentiometer (eg 32k - 12k).  The capacitor is 0.1 uF.  Using the equations for the 555 timer, we have a range of outputs of T1 = 19500us, T2 = 830us up to 2200us.  The T2 time is what we want to pulse to the servo, but in the configuration given, T2 is the time spent LOW.  To reverse the polarity of T1 (making that LOW) and T2 (making it high), the output from the 555 is run through an NPN transistor which acts as a NOT gate.  The results are shown below:



A breadboard prototype worked fine, so I used Eagle CAD to make boards for each of the testers.  The EagleCAD files can be downloaded from https://sites.google.com/site/rampantrobots/servotester .

The boards for the servo and motor tester are almost identical, except that the servo requires a voltage of ~5V, and the motor requires a voltage of 12V.  I wanted both to run off the 12V batteries we use for robotics.  So I used a LM7805 for both boards.  For the servo board, the 5V output also powers the servo, while for the motor board the 12V supply is connected directly to the HB-25 input.  For the servo tester, a series of capacitors of different values is used to smooth the 5V line because the servo pull might otherwise cause it to drop too low for the 555 timer to work correctly.  The bottoms of each board show the similarities and differences.



The boards work great.  Check out the movies below which show them in action.




Sunday, September 15, 2013

Metal Fabrication

When I made the Explorer Bot last summer, I wished at one point that I could have just welded the frame together.  But I didn't know how to weld at the time.  This summer, I enrolled in a metal fabrication class and learned several of the basic techniques used to manipulate steel.  I made several items, pictures of which are shown below.  I've labelled some of the pictures with the techniques that were used.
A spaula






Two hooks were made with blacksmithing techniques.  
A tripod holder for an iPhone.




Hardware makes the iPhone holder adjustable at each leg
of the tripod.  I used 1/4"-20 hardware, sandblasting the nuts
prior to MIG 

A piece of pipe tubing was welded onto the iPhone
holder using a MIG.
This corner was made with an
oxy-acetylene welder to put
together two pieces of 16 gauge
steel meeting at the corner.






















Final pictures taken after patina and clearcoat:




Sunday, August 18, 2013

Bare Conductive Paint and Squishy Circuits

Update: 5/22/14

I redid this project with some students in a materials science class. They were able to make both the conductive and insulating dough fine.  The only variable I could figure out which was different was the type of cream of tartar used; the ones that worked were made with McCormick Gourmet Collection cream of tartar.  The ones that did not were made with a QFC generic brand.

In addition, I made some conductive dough from nshima, which is a corn based grain eaten in Zambia.  Here's a picture.  Insulating dough made only with nshima and distilled water was too conductive to be useful.


Original Post

I have spent a couple weeks this summer working to evaluate  fun and creative methods to teach conductivity and circuits.  I worked with both the Squishy Circuits and also with the Bare Conductive Paint.   This is a story of success and current failure.

Success Story:  The Bare Conductive Paint is an easy to use and very fun tool to lay down electrical wiring.  The prototype shown at right is a X-mas tree where one wire runs from the positive battery terminal, up the left side of the tree, and to the anode of the LED.  The other wire runs down the right side of the tree from the cathode of the LED to the negative terminal of the battery.  The paint is a graphite impregnated concoction (hence the black color), which can be painted on with a brush.  It is much thicker than normal paint.  My X-mas tree was made on sticky-back green felt which was then affixed to a card.  

The inspiration for the X-mas tree was this video from the Bare Conductive Paint website:   How to Cold Solder.



Here are a couple christmas presents made for Xmas 2014 for my niece and nephew.  I was particularly proud of the Despicable Minion since the battery made a cool eye, and the conductive paths were along the outside profile of the character and then under his overalls.






Two blobs of green conductive dough allow a circuit
to be made between
an LED and a 6V battery pack.


Less Successful Story:   I have been playing with making conductive and insulating dough using the Squishy Circuits recipes.  I really like the potential for creative application of very simple circuits, and in theory the technology is simple enough that I could work with this system in remote locations, such as Zambia where I have gone with a school group for three summers.   The doughs are just flour and water mixtures, with salt added for the conductive dough (along with cream of tartar or lemon juice as a stabilizing electrolyte), and sugar added for the insulating dough.  The conductive dough works great, as you can see from the picture at left.


With the brown insulating dough in the middle, the
LED turns off indicating a short between
the two conductive blobs.  Apparently the
insulating dough has lower resistance than the LED.


However, I've had real issues with the non-conductive dough, which seems to short the LED, suggesting that the dough has lower resistance than the LED.  I have tried using distilled water, deionized water, and two types of flour (normal bleached and an organic wheat flour), which no discernible differences in behavior.  The folks at Squishy Circuits have been really supportive, but can't seem to offer much help in terms of suggesting possible reasons for the issues with the insulating dough.  This has been a frustrating project.  I'm taking a break from it and will revisit later, possibly using some students in a chemistry class to help troubleshoot in conjunction with a unit on bonding (which relates to electrical conductivity).  Check out more on Squishy Circuits on their Facebook page.

Friday, August 16, 2013

Frostruder - XY Plotter Derivative

The XY Plotter now has a frosting extruder mounted in the place of the Sharpie as the "tool".  I used the Frostruder kit originally designed for the MakerBot, which uses two solenoids to control pressurized air to a syringe.  The syringe can be filled with frosting and the air pushes it out at a rate that depends upon the air pressure and the syringe tip size.

I connected the two solenoids through a series of relays to the Arduino microprocessor which is running the whole project.    Two pins control when pressure is applied to the syringe, and when pressure is vented to atmosphere.

The video below shows a proof of concept of the Frostruder in action.  The video is sped up 4x times.  There is still a lot of work to be done in terms of balancing variables to optimize the extrusion process; the variables include air pressure, time delay between when pressure is applied and when tool head motion begins, rate of tool head motion, and the nature of the frosting used.  Still I was very excited when this video was made because it represents a functional piece of equipment!


Unlike the original Frostruder, the syringe is separate from the electronics and solenoids which route the pressure.  Those are mounted to the frame of the 3D printer in a wooden box.  Tubing runs from the box to the syringe, which is mounted into a custom designed and 3D printed part.  The syringe can be easily removed with just an allen wrench.



SolidWorks and STL files for the carriage can be downloaded from the links below.  These parts were 3D printed using a Replicator using 20% fill and 3 shells. 


I have made two major improvements on the software side of the project as well.  I improved the Processing interface, and I took a major stab at correcting the slope change problem seen in the previous post.

Processing Interface Improvements:
  1. I calibrated the machine to determine the relationship between screen pixels in Processing, steps of the stepper motors, and XY distance traveled.    I changed the interface so that the grid shows inches now.  Unfortunately, the grid spacing doesn't work out very nicely.
  2. I added a clear button which removes the "lineLayer" PGraphic without having to restart the program.
  3. I added a slider based on the Control P5 library which controls the presence and size of a "cookie" in the center of the stage.  The cookie is to scale, making it easier to visualize.
  4. I added the ability to load an image which can serve as a template for drawing the lines on the Processing screen which correspond to the places where frosting will be laid down.  Making the template image is easy with the help of a screen shot tool.  Then the template file can be opened and edited in any image processing software, saved, and then loaded from within the Processing sketch window.  The video above was done with the help of a image file which had wordArt added using Powerpoint.



New and Improved Stepper Motor XY Interweave:
A previous post showed that my method to allow the X and Y stepper motors to move at the same time had a flaw.  The issue was essentially that slopes are often non-integer numbers when reduced to a reasonably small integer denominator, while stepper motors cannot take fractions of a step.  My previous algorithm was to reduce the decimal slope to the nearest smaller whole number, then calculate the remainder which was the additional number of steps required to go along the longer axis.  Those steps were taken at the beginning, effectively increasing the slope by 1 for as many iterations as it took to make up the extra steps.

For example, suppose that you wanted to take 28 steps in the Y direction and 23 steps in the X direction.  The slope, dY/dX is 1.217 which is not possible to do directly with stepper motors.  So instead, we have the motors run at slope 2 for five iterations, and then for slope 1 for 18 iterations, where each iterations corresponds to one step along the X axis.  The picture at left shows that this results in a tool path which substantially deviates from the ideal path, because all the remainder steps are taken at the beginning.

The solution is not hard; we need to space out when the remainder steps are taken instead of doing them all at the beginning.  One algorithm which is working for me is discussed below.  Note that this algorithm is not the most efficient, but it seems to be "good enough" in terms of actual performance on the device.

  1. Calculate the slope and round down, as before.  Also determine the number of leftover steps as before.
  2. Divide the number of iterations (equal to the lesser of dX or dY) by the number of leftover steps.  For example, in this case 23/5 = 4.6.  My algorithm rounds this number UP, because otherwise you could do too many steps.  This is the number of steps per iteration.
  3. Figure out how many steps are still leftover.  In this case, doing an extra step every 5th iteration means 4 steps will get done, so there is one more step to do.  This step is done at the beginning (in retrospect, it should be done at the end).  If there are more than two extra steps, the code repeats steps 2-3 one more time.
From the images below, we can see that the code works if it is somewhat convoluted.  I also setup an Excel spreadsheet which helped me to test the algorithm before actually writing the code for it.  I used the same spreadsheet to visualize the tool-path by having the Arduino printout the cumulative steps along both axes after each iteration, and then graphing these.
Two Method Comparison for dY = 40, dX = 25.
Two Method Comparison for dY = 41, dX = 21.
Actual results of both methods done by Arduino microprocessor and
plotted for four different dX,dY combinations.


One interesting note is that the second method is not always better than the first method.  The case where dX = 21 and dY = 41 results in 21 iterations with a leftover of 20 steps.  So if the original method is used, all but one iteration can be done with an extra step, resulting in the original method giving a better trace of the ideal path.  The code I wrote allows the program to chose the better method.

The code which implements the algorithm described above is shown below.

This is a simplified version of the actual code posted on GitHub, but is easier to understand.  The best way to understand the algorithm is to compare the color coding done in the pictures above with the comments written into the code.

Current code is available:
Processing Sketch
Arduino Sketch