Saturday, June 29, 2013

is it even possible to huff alcohol with dry ice?




My kitchen sports an odd tableau today. Dry ice, bubbles, kitchen scales and vodka. I saw a fear and uncertainty and oh my god wont someone think of the children article today that claimed teenagers were getting dangerously drunk by inhaling alcohol vaporized by putting dry ice into a bottle and breathing the vapors. I was immediately skeptical that the alcohol would vaporize that way in any meaningful amount and since I had to go to the grocery store today anyway I decided to pick up some dry ice and sacrifice a few ounces of vodka to testing this.

I ran 2 tests with dry ice and one control bowl just to see if it vaporized just sitting in an open bowl at room temperature.

I weighed the bowls and added 2 oz of vodka and then a chunk of dry ice. In the first test I used tongs to move around the dry ice piece but when I realized I was removing drops of the sample each time I did this I stopped and only gently sloshed around the bowl in the second to keep the dry ice in contact with the vodka. I didn't agitate or move the control bowl at all between weighing it and weighing it again at the end of the experiment.


I recorded the weight of the empty bowl first as this kitchen scale wont stay on long enough to let the ice completely disappear and so the tear would get lost. This is me measuring in the 2oz of vodka. Then I added in a couple of small pieces of dry ice.

 


And I let them sit there and bubble. If you're going to get enough alcohol into you through any route even inhaling, then a significant physical amount of this liquid must get carried away along with the CO2. It's not homeopathic alcohol after all.

While I did not try to huff any of it during the experiment the fog did smell strongly of vodka and I thought for a while that perhaps that meant that a significant amount was being liberated! I was wrong.

While we waited my son and I performed all the other necessary experiments and delights that having extra dry ice around make possible. And I finally got that forming a bubble over the entire perimeter of a bowl to work making HUGE dry ice bubbles that pop in a cascade of fog that is just so much fun to watch over and over again :)

It took around 10 minutes for the dry ice to bubble away. Experiment 1, the one I messed with and lost a few drops, lost .05oz. Thats 5 hundredths of an ounce. (incidentally, also the smallest granularity of my scale, so it may have been slightly more or less) The 3 drops on the table under my tongs are more than enough to explain that. The second test lost nothing, it weighed exactly the same amount after the ice as it did before the ice. The control bowl lost .05oz as well, just sitting there at room temperature the alcohol was evaporating, but nobody got drunk off that. So it seems that putting the booze in wth the dry ice actually keeps it from evaporating, dropping the temperature so that the vapor pressure of alcohol didn't let hardly any at all escape into the air.

So I'm calling this one busted. There is no way that you can get drunk off inhaling the fog from a bottle of dry ice and booze. What you might get is hypoxic however, which could be very dangerous if you breathed only from the bottle for an extended period of time. But most of us have taken a few hits off helium balloons in our day and there is no oxygen in there either and as long as you kept it to 1 or 2 lungfulls you didn't pass out. Having been a teenager once myself I witnessed and even once in a great while took part in some things that would have qualified as sublimely stupid. Teenagers do this sort of thing. But huffing alcohol in this particular manner just can't do anything to you. There almost certainly are ways of actually vaporizing the alcohol though, if you wanted to heat it and bubble air through it, or do something really painful and stupid like put it into a cold mist humidifier you could probably make a cloud of it that had plenty of alcohol in it. But at least in that last example I challenge anyone to take a second breath after taking the first. You'd be choking and telling your stupid buddy that you were drunk enough and it was his turn and you'd also get it in your eyes. Ouch...

So tell your kids that if they see anybody doing this to leave the party, not because they are doing something really dangerous, but that they are too stupid to trust with other necessities of keeping themselves alive through the rest of the day.

Now.. if you'll excuse me I have 4oz of very well chilled vodka and a martini glass waiting for me to finish this entry.

Sunday, June 16, 2013

Arduino, xBee and PWM lighting with XTension

Back on Halloween Ben and I built him a gigantic lightup inflatable pumpkin costume that was a great deal of fun. In addition to the el wire face on it we also built him an electric t-shirt with LED strips attached to an arduino, some buttons for lighting effects and a little 12v battery pack to power them.

You can see them there under his costume, at night they put on a great show, flickering and fading in and out and flashing brightly when he pushed the button that let them accentuate his awesomeness while trick-or-treating.  We used these cool white LED strips from adafruit.com. After halloween I removed them from the t-shirt and saved them for future projects. A future project revealed itself shortly thereafter in the form of aquarium lighting for his new fish tank. We didn't do any fancy remote control or PWM on them for version 1. We just taped 2 of the 4 little strips to some shelf support material I had and powered them from a generic 12v wall wort.

They worked great for a while, but the constant splashing of water on them and the metal bars soon took it's toll. I think that the power supply may have been a bit high too for they rather quickly started to degrade and individual LED's started to go dim. Even so they lasted several months, but finally died and it was time to rebuild. We had 2 more strips left over from the costume and this time we decided to do it right. PWM to control the levels so it could be dimmed, an xBee radio so that it could be wired into the Home Automation System and some buttons so he could set the level there. I had just finished an arduino interface for XTension and so decided that this should be a demo project on how to bring some of these things together. 

Here you can see how far the old LED strips degraded. The metal shelf support is rusty, the LED strips have gone opaque and you can see where some coper was exposed and turned bright green.


Yuck... This time I would build something with proper heat sinking and proper protection from the elements. I used a  piece of aluminum extrusion U channel as the base for them. It's available at HD and others as a shelf support. It's meant to go over the long edge of a plywood or particle board shelf to keep it from bowing in the middle. It wasn't quite the perfect size for 2 LED strips, they were a tight fit, but I added some extra adhesive behind them as well. 


Also you can see one of the bezel pieces. I printed those on the MakerBot out of translucent PLA. They are actually less translucent that I had though and I might replace them with just cut pieces of plastic soon, but they work for now to protect the lights from the water.

For the Arduino I went with a Fio. I'm not using the lipoly battery charging ability of it, just the fact that it's an arduino with an xBee socket built in. Both running at 3.3v so no other circuitry is required. Or so it seemed... The LED strips need to run at 12v, the Fio is rated at 12v input and initially booted and started up OK, when I had it wired in circuit and applied 12v the regulator on the board burst into bright flame or arcing or something. I removed the power with some alacrity thinking I had cooked the arduino and probably the xBee as well. Testing from USB power though showed them both to be just fine. Now thats impressive, a piece of gear that can actually catch fire and not break down! So instead of relying on the on board regulator I added a beefier external 3.3v regulator. That also released it's magic smoke upon startup. So at this point I took a step back and reviewed the rest of my wiring. Had I wired the mosfet backwards and was putting 12v into one of the input pins or something? Nope, everything looked good. So I broke out an anyvolt micro adjustable regulator and hooked that up instead. Adjusted it's output down to 3.3v and all was well. I guess 3.3v linear regulators just dont like an input as high as 12v. There are many dc/dc converters on the market now, and anyvolt also make a 3.3v version, but the adjustable was what I had on hand. Connecting that to the 3.3v input and bypassing the internal regulator completely brought it all happily back to life.



The mosfet in the picture makes PWM'ing high loads so very easy, no external parts required, not even a resister. This particular model is an N-channel power mosfet and I wired it according to adafruits excellent examples that are linked to from that store entry. Thats actually the same one that powered ben's halloween costume so it's still got some lumps of hot glue attached.  A $1.25 saved is a $1.25 earned ;) You can also see the LED strips powered up and running behind their makerbotted water protection. The plastic strips are just hot glued gently on top of the aluminum channel. I want to be able to replace them when they get a scuzzy from being in the water.


I mounted all three devices into a tiny plastic parts case with a hole drilled through the top/bottom for the xBee antenna. If you were using a lower output one with a chip antenna then even that wouldn't be necessary. 


The buttons in their final install position on the fish tank. Not very pretty, this end of the project will likely get a reworking.

The arduino interface for XTEnsion just provides a simple text based interface for sending values back and forth. basically just address=value with a return at the end. It can be extended of course ;) but for this that wasn't necessary. I opted to make the buttons and the light totally separate in the device itself, requiring the intervention of the computer in order to send back the light level in response to a button push. This means that you can't control the light if the computer if offline, but if the computer is offline I've got bigger problems than the fish tank lights. So in this code the buttons just send an ON when they are pushed (and no off, though I could do that easily enough if it's useful) and then the computer responds by sending a level for the lamp. There is a heartbeat delay between pushing a button and the response coming back, but this way I can set the levels in the computer without having to recompile the arduino code, or without having to write a lot of code to save the levels into the eeprom. So there are other solutions if you like that. You could also build this without any remote computer in the mix at all by just setting the lamp PWM value in the processButtons() handler. But this is an example of how to write arduino code that talks to XTension.


This is how the units are setup in XTension. The buttons receive the commands send from the arduino like:
  Serial.println( "button1=on");

and if you change the aquarium light units level it ends up sending a command like "LAMP=160"

XTension will also convert the address to be all caps, so keep that in mind in your arduino when comparing strings. In the code you'll see some commented out map commands as I was going to map the standard dim level in XTension, 0%=100% onto the range of PWM outputs available on the arduino, 0-255, but decided not to, just let us control it from here. In experimenting with it we discovered that 160 was plenty bright for the fish and the plants and struck a nice comprimise between light and heat output. Any more than that and the light bar started to border on hot rather than just warm. I want to keep these LED's for a long time so we are not going to let them overheat. And a value of just 4 is bright enough on the dim setting for Ben to use as a nightlight. It really does look like moonlight at that level and is quite pretty.

The computer control is important separate from the button control so that the lights can be turned on remotely when we are on vacation, or if he fails to turn them on in the morning. Since feeding the fish and turning on the light is part of his morning ritual he rarely forgets. But now I know when he last turned the lights on, and if it doesn't happen I can turn the lights on automatically and send me an alert so that I can feed the fish if he forgets. He's 8 and is really very good at taking care of them, but it does happen. 

Since the arduino has plenty of inputs and outputs available we have plenty of room available for future expansion. I think a water temperature sensor is in the near future, that will be easy. Perhaps some UV or deep blue LED's to make his fluorescent fish light up at night too. We're also starting to think about an automatic feeder that we would design and print on the makerbot and control from this same arduino.

Setting up xBee radios to work with XTension needs an entry of it's own as well. That will come shortly. Here is the source code free and open use it as you wish. download the arduino project

/*

  Ben's aquarium light 
  
  using an xBee to talk to XTension

  June 10 2013  james@sentman.com
  
  In this example, the 3 buttons send their ON to XTension when they are pushed, and XTension replies
  with the proper change to the light level. They do not directly control the level of the lamp.
  the lamp is only controlled from XTension by way of scripting from the button units.

*/


//input and output pin definitions
const int lampPin = 3;
const int upButton = 8;
const int midButton = 7;
const int downButton = 12;
const int ledPin = 13;

//these globals are used by the serial interface for talking to and getting commands
//from XTension via the Arduino interface. All commands are sent as NAME=value pairs with a 
//carriage return at the end. Set your buffer sizes to be at least as big as the longest command
//you expect to receive. These are oversized as only a single value is sent.

const int commandBufferSize = 19;
const int valueBufferSize = 22;
char commandBuffer[ commandBufferSize + 1];
int commandBufferIndex = 0;
char valueBuffer[ valueBufferSize + 1];
int valueBufferIndex = 0;
boolean gotCommand = false;


//debounce necessities
unsigned long lastButtonMillis = 0;
unsigned long currentMillis = 0;
int currentButtonPushed = -1;




void setup(){
  
 //make sure xBee is set to same serial speed. Could use faster of course 
 Serial.begin( 9600);

 //set the pinmodes for in or out as appropriate
 pinMode( lampPin, OUTPUT);
 pinMode( upButton, INPUT);
 pinMode( midButton, INPUT);
 pinMode( downButton, INPUT);
 pinMode( ledPin, OUTPUT); 
 //turnon the pullup resisters
 //to simplify the wiring I'm using internal pullup resisters for the buttons
 //that way I only have to connect them to ground.
 digitalWrite( upButton, HIGH);
 digitalWrite( midButton, HIGH);
 digitalWrite( downButton, HIGH);
 //make sure we startup off 
 analogWrite( lampPin, 0);
 //could always save the current value of the light to the eeprom 
 //and retrieve it at startup so that a power outage for a few seconds 
 //wouldn't result in the light being off.
 //give the led a flash
 digitalWrite( ledPin, HIGH);
 delay( 500);
 digitalWrite( ledPin, LOW);
 //write to XTension that the system is ready.
 Serial.println( "log=Aquarium Ready");

 //and update it's unit so that it knows that it's not on
 Serial.println( "LAMP=0");
  
  
  
}


void loop(){
  
   //currentMillis is used in the button processing in several places
   //so instead of constantly calling to millis() just do it once and put it
   //in this variable.
   currentMillis = millis();
   //check the serial buffer for any waiting command data and process it
   //if there is any
   processSerialCommands();
  
   //check for any button state changes
   processButtons(); 

  
  
}

/*
  this is part of the Arduino interface to XTension
  it can easily be reused in future projects.
  this just manages the command and value buffers and reading of data
  from the port. Any actual received commands will be passed to the next
  processCommand() method. Add any other incoming value handlers or special
  commands there. This handler shoulnd't need to be changed for most things
*/

void processSerialCommands(){
   int workByte;
  
    //if no data available then just return, nothing to do this cycle through loop
    if (Serial.available() == 0){
     return;
    }
   //read a byte
   workByte = Serial.read();

   //since all data is sent and received as name=value pairs
   //initial data is added to the command buffer. When a 61 or "=" is recieved
   //we finalize the end of the commandBuffer with a nul and start adding future characters
   //to the value buffer.
   if (workByte == 61){
      commandBuffer[ commandBufferIndex] = 0;
      commandBufferIndex = 0;
      gotCommand = true;
      return;
   }
   
   
   //this is looking for the carriage return at the end of the command line
   //if it finds the return then it finalizes the value buffer with a nul and 
   //resets the buffer indexes to get them all ready for the next command
   // and finally passes the most recently received command=value pair to the process command
   if (workByte == 13){
     valueBuffer[ valueBufferIndex]=0;
     valueBufferIndex = 0;
     commandBufferIndex = 0;
     gotCommand = false;
     processCommand();
     return;
   }
   
   
   //if we haven't finalized the command yet (or address as it's now called in XTension)
   //then we add the byte to the commandBuffer and increment the index to wait for the next one
  if (!gotCommand){
    commandBuffer[ commandBufferIndex] = workByte;
    commandBufferIndex++;
    
    //make sure that we dont overrun the buffer though and reset it if we're receiving garbage
    if (commandBufferIndex > commandBufferSize + 1){
      commandBufferIndex = 0;
      return;
    }
    
  } else {
    
    //we've already got the command because gotCommand has been set to true by the
    //check above for a 61 value or "="
    //so now add instead to the value buffer, increment it's counter and continue
    valueBuffer[ valueBufferIndex] = workByte;
    valueBufferIndex++;
    
    //make sure that the value buffer doesn't overflow and if so then
    //reset both the command and value buffer due to garbage on the line.
    if (valueBufferIndex > valueBufferSize + 1){
      commandBufferIndex = 0;
      valueBufferIndex = 0;
      return;
    }
  }
  
}

//XTENSION here is where you will receive incoming commands use the string objects to manage your response
//  add as many addresses as you need.

void processCommand(){
  String theCommand = String( commandBuffer);
  String theValue = String( valueBuffer);
  
  if (theCommand == "LAMP"){
    
    if (theValue == "on"){
      setLampLevel( 100);
    } else if (theValue == "off"){
      setLampLevel( 0);
    } else {
      setLampLevel( theValue.toInt());
    }
    
    return;
  }
  
  //add as many more comparisons for theCommmand as you need to for your application
  //XTension will always send address=value pairs if it's a change to a unit, though
  //any data may be sent with the "send data" verb including commands that have no value
  //though in that case you should still send the = and then immediately the return. like
  //reboot=/13 do not omit the equal sign.
}


void setLampLevel( int newLevel){
 //int adjustedLevel;
 //level from XTension is 0 to 100, map it so that we never go to all on 
 //adjustedLevel = map(newLevel, 0, 100, 0, 210); //keep it from going all on as that burns out the LED's
 //Serial.print( "log=level is ");
 //Serial.println( adjustedLevel);
 analogWrite( lampPin, newLevel);
  
  
}


void processButtons(){
  boolean debounceTimeout;
  
  if ((currentMillis - lastButtonMillis) > 100){
    debounceTimeout = true;
  } else {
    debounceTimeout = false;
  }
  
  
  if (digitalRead( upButton) == LOW){
    //upbutton is pushed
    if ((debounceTimeout) && (currentButtonPushed != upButton)){
      currentButtonPushed = upButton;
      lastButtonMillis = currentMillis;
      Serial.println( "button1=on");
      return;
    }
  } else if (currentButtonPushed == upButton){
      //the button is up but the last button pushed was ours so we can reset it
      if (debounceTimeout){
        lastButtonMillis = currentMillis;
        currentButtonPushed = -1;
      }
  }

    
 if (digitalRead( midButton) == LOW){
    //midButton is pushed
    if ((debounceTimeout) && (currentButtonPushed != midButton)){
      currentButtonPushed = midButton;
      lastButtonMillis = currentMillis;
      Serial.println( "button2=on");
      return;
    }
  } else if (currentButtonPushed == midButton){
      //the button is up but the last button pushed was ours so we can reset it
      if (debounceTimeout){
        lastButtonMillis = currentMillis;
        currentButtonPushed = -1;
      }
    }
    
  if (digitalRead( downButton) == LOW){
    //upbutton is pushed
    if ((debounceTimeout) && (currentButtonPushed != downButton)){
      currentButtonPushed = downButton;
      lastButtonMillis = currentMillis;
      Serial.println( "button3=on");
      return;
    }
  } else if (currentButtonPushed == downButton){
      //the button is up but the last button pushed was ours so we can reset it
      if (debounceTimeout){
        lastButtonMillis = currentMillis;
        currentButtonPushed = -1;
      }
  }
}

Tuesday, June 4, 2013

iPhone restore problems

I replaced the battery in my iPhone 4 the other day. It seemed to work fine till it ran all the down yesterday. Upon plugging the phone back in it got itself stuck in an infinite loop of rebooting.

I placed the phone into restore mode and plugged it into the computer, but it wouldn't get past the extracting and preparing software phase with a "2001" error. Which Apple says is something to do with USB. Much trying with new cables and restarting resulted in nothing.

After switching back to the old battery though I was able to restore the phone (and I wonder if I had though to do that initially if I could have kept the things that hadn't been backed up that day, alas) but I still wasn't able to reload it from the last backup because it refused to show up in iTunes.

Finally i noticed that it was showing up as an empty iPhone in Aperture which was running in the background. After quitting that and restarting iTunes I was able to make it show up and am running the restore now.

A tower of unrelated problems is so much fun to tease out.

So... Bad batteries can cause the phone to refuse to connect properly even when connected to power. And Aperture (and probably iPhoto) running at the same time can keep an iPhone from showing up in iTunes if it's been just recently restored.

Putting that information out there for any others that might find themselves in a similar situation.

Update:
I've heard back from ifixit.com from where I got the original battery, and I'll give them a plug for the best support ever, just shipping me a replacement and no hassle. I've used these guys many times in the past for parts and tools and never had an issue and the one time I did they really came through. I know you can find the batteries a little cheaper if you're willing to order direct from china or go on ebay, but their wonderful takeapart videos and their wonderful support are more than worth the extra few bucks. Support a company that will support you back!
.code { background:#f5f8fa; background-repeat:no-repeat; border: solid #5C7B90; border-width: 1px 1px 1px 20px; color: #000000; font: 13px 'Courier New', Courier, monospace; line-height: 16px; margin: 10px 0 10px 10px; max-height: 200px; min-height: 16px; overflow: auto; padding: 28px 10px 10px; width: 90%; } .code:hover { background-repeat:no-repeat; }