Monday, February 28, 2011

GAGA-1: flight computer testing

Having got the flight computer radio working with my homebrew antenna it was time for a couple of tests: test that the radio could actually transmit over a reasonably long distance and see how long the flight computer would keep running for.

Here's GAGA-1 ready for its trip (I made a little cover for the antenna to protect it on the journey):

The capsule will get lifted to over 30km and I'm using a 10mW radio transmitter. As others have shown this works fine with line-of-sight and a good antenna. To run the test I got a helping hand from my parents who dropped me off at one end of Abberton reservoir with my Yaesu FT-790R and a Yagi antenna while they drove off to Abberton church with GAGA-1 sitting on the backseat transmitting a short RTTY message. The total distance between the two points was almost exactly 5.5km.

Got a few funny looks from birdwatchers and families as I stood there (although one person was kind enough to take my picture, see below).

As they drove away I left the radio receiver on the ground with a little whip antenna on it. This was able to pick them up almost the entire way (at some points the signal fading, and while at the church there was a lot of noise).



Switching to the Yagi made the signal come in loud and clear, so loud and clear in fact that they never bothered to get out of the car. Over 5.5km from inside a car parked inside a copse the transmitter was working fine at the other end of this shot:

Here's an action shot of me with the Yagi pointing vaguely in GAGA-1's direction. The signal was so strong with the Yagi that pointing it in pretty much any direction worked.

The final test for the day was to let the flight computer run and see how it fared. After 8 hours of continuous transmission I pulled the plug on the test. The final transmission was $$GAGA,24.8,Error: 0 which indicated that the internal capsule temperature was 24.8C and that the external sensor was not connected.

Here's a picture of the flight computer left and recovery computer on the right before mounting inside the box.

And here's a view inside the capsule showing the mounted computers with batteries. Doing this I discovered that I'd mounted the battery packs in positions that made inserting the camera really hard and no clearance for the antenna SMA connector. Had to remove and reglue.

Friday, February 25, 2011

GAGA-1: Another little freeze test

Having done freeze tests on the Arduino, the capsule and the camera I decided I needed a test of the Mylar film inside the capsule after a discussion on the UKHAS IRC list.

The film is stuck to the inside of the capsule with a spray glue used to mount photographs (which is safe for use on polystyrene), but I suddenly wondered if it might peel off at low temperatures.

So, into the freezer for two hours. Here's the capsule with the lid off sitting in the freezer.

Two hours later there were no visible ill effects:

So, yet another test completed. This weekend's big test is a long distance (few mile) test of the main radio transmitter.

Saturday, February 19, 2011

GAGA-1: Working flight computer

And so after much preparation and the early success in getting RTTY transmission working I soldered everything onto the custom Arduino shield that forms the flight computer, plugged it in and... it just worked!

Here's the flight computer board connected to the Arduino. The biggest item is the Radiometrix NTX2 module with a small voltage divider below it which is used to set the frequencies for the 0 and 1 values. The antenna is connected to the SMA connector bottom left.

Just above the radio is the DS1821 temperature sensor that will measure internal capsule temperature. It has an associated pull up resistor. The external temperature sensor connects to the three pin header to the right of the radio (it too has a pull up resistor).

Here's a log of transmitted temperature data received via RTTY:
$$GAGA,24.0,Error: 0,
$$GAGA,24.0,Error: 0,
$$GAGA,24.0,Error: 0,
$$GAGA,24.0,Error: 0,
$$GAGA,24.0,Error: 0,
$$GAGA,23.9,Error: 0,
$$GAGA,23.9,Error::C'fwyZ
'/A,23.7,Error: 0,
$$GAGA,23.7,Error: 0,
$$GAGA,23.7,Error: 0x$$GAGA,23.8,23.3,
$$GAGA,23.7,22.9,
$$GAGA,23.7,22.6,
$$GAGA,23.7,22.6,
$$GAGA,23.7,29.8,
$$GAGA,23.7,29.7,
$$GAGA,23.7,27.6,
$$GAGA,23.7,26.1,
$$GAGA,23.7,25.0,
The first few lines of reports show the internal temperature (24.0C---yes, it's warm in the basement) and an error report (Error: 0) for the external temperature. The error was happening because I didn't have the sensor plugged in. I recently enhanced the code that handles the DS1821 sensor to report errors. Error 0 means that the sensor didn't respond.

The garbled output is because I was fiddling around with my radio. I then plugged the sensor in it started reading temperatures. The temperature peaked at 29.8C because I held the sensor in my hand.

Next steps are: a long distance test of transmission to make sure that's working correctly and install the GPS. With the GPS I'll be at the end of the long GAGA-1 road.

PS One final shot of the Arduino shield showing the painful leg bending required to fit in with the Arduino's silly pin spacing.

GAGA-1: The lovely sound of RTTY

For the first time today I tried receiving the RTTY transmitted by GAGA-1 and decoding it using DL-FLDIGI. It worked (first time!).

To illustrate the whole set up here's a little video. The radio I'm using is a Yaesu FT-790R II which I bought second-hand on eBay. This is an old radio, but it's sturdy and can do SSB at 70cm. Although it's a portable, I managed to buy one that had never been outside and it looks like it's been treated with great care. Thanks, eBay!

The flight computer is in a loop transmitting $GAGA-1 Test Transmission using 7-bit ASCII, with two stop bits, no parity at 50 baud.



Apologies for the shaky hand and blurry video. The combination of me + the iPhone's poor camera isn't great. Just listen to that lovely RTTY sound though.

Friday, February 18, 2011

How could I have coded this better?

For work I had to write a small script to scrape Google results to measure relative rank of my company and others that we like to track. We were looking at various search terms and where we appear in the results.

So, I decided to use Python with BeautifulSoup. I love BeautifulSoup, but I don't use Python very often, so... Python experts: criticize my code! How would you have done this better?
# Script to perform Google searches and extract the domain names of
# the returned results.  The order in which the domain names are
# returned is used to determine a ranking between different companies.

# This is the list of domains to look for in Google searches.  To
# search for more or different domains simply alter this list.  The
# order of this list determines the order in which the results are
# saved.

domains = [ 'foo.com', 'bar.com', 'baz.com' ]

from BeautifulSoup import BeautifulSoup
import urllib, urllib2
from urlparse import urlparse

# Performs a Google search and returns a BeautifulSoup object
# containing the parsed, returned page.
def google(q): # Query string (will be URL quoted by this function)

    # This attempts to ask for 100 results from Google.  This does not
    # always seem to work correctly.  Note that the fake User-Agent is
    # required otherwise Google will reject the search

    url = "http://google.com/search?q=%s&num=100&hl=en&start=0" % 
          urllib.quote_plus(q)
    req = urllib2.Request(url, None, {'User-Agent':'Mozilla/5.0 (Macintosh; U; 
             Intel Mac OS X 10_5_8; en-US) AppleWebKit/534.13 (KHTML, like Gecko) 
             Chrome/9.0.597.94 Safari/534.13'} )
    res = urllib2.urlopen(req)
    dat = res.read()
    res.close()

    return BeautifulSoup(dat)

# Small helper function to output a single line of a CSV file.  Note
# that this does not do quoting of arguments so assumes there are not
# " or , present.
def csv(f, l): # First elements to print followed by list of elements
               # to print
    print "%s," % f, ", ".join(l)

# Cartesian product function (similar to itertools.product but joins
# the #elements together as a space separated string rather than
# returning a tuple)
def product(*args): # List to x together
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield " ".join(prod)

# This generates all possible search strings to be used using
# product.  This can be modified to create other search terms by
# altering the lists (add/delete elements, or add/delete lists).  Each
# of these terms will have "whizz bang" appended below

terms = product( [ 'a', 'b', 'c' ],
                 [ 'foo', 'bar', 'baz' ],
                 [ 'one', 'two', 'three', 'four' ] )

csv('term', domains)

for t in terms:

    # All the queries have 'whizz bang' appended to the end of
    # them

    qu = "%s whizz bang" % t

    # This performs a Google query using the helper function and then
    # extracts all the <a> tags that have class "l".  If Google
    # changes the structure of their pages this is where this code
    # will break.  Currently class=l grabs all the appropriate links
    # (displayed in green in the search results).

    so = google(qu)

    # The urlparse(u['href'])[1] works by extracting the href from the
    # <a> tag, parsing it into component parts and extracting the 1th
    # element of the returned tuple which contains the netloc (the
    # domain name)

    a = [ urlparse(u['href'])[1] for u in so.findAll("a", {"class":"l"}) ]

    # The pos array stores the lowest position in which a specific
    # domain has been seen in the results from Google.  Each element
    # corresponds to an element of domains.  Initially, these are set
    # to 0 to indicate 'not found' in the results.

    rank = [ "0" for d in domains ]

    # Here we iterate through the returned domain names in a and match
    # them up with the domain names we are looking for.

    for i in range(len(a)):
        for j in range(len(domains)):

            # Note that the comparison here deals with two cases.  The
            # domain is entirely 'foo.com' (for example), or the
            # domain ends with '.foo.com' (for example).

            if ((domains[j] == a[i]) or a[i].endswith(".%s" % domains[j])):
                rank[j] = "%d" % (i+1) # Count ranks from 1 not 0

    csv(qu, rank)

GAGA-1: Parachute

Yesterday's post contained a nice surprise: the parachute that will bring GAGA-1 safely back to ground level. It's a 36" parachute made to order by Spherachutes.

Spherachutes makes custom parachutes for model rocketry and also for high-altitude ballooning. Using their weight chart and an approximate weight of 1.1kg 2.4lb) for GAGA-1 a good size appeared to be 36". This should give a descent rate between 15 to 20 feet per second (that's rougly between and 16 and 20 kph).

Here's the parachute sitting on the kitchen table:

In the picture above you can see that there are two pieces of rope in the hole at the top of the canopy. That's the 'balloon option' provided by Spherachutes and is where the balloon itself will be attached via a few metres of strong, thin cord.

It's not possible to see the lines coming from the parachutes, but these will be attached to more thin cord which will attach to the capsule. So the parachute is deployed at all times. When going up the balloon pulls on the parachute. On the way down the balloon is gone and the parachute simply opens and slows the descent.

PS The folks at Spherachutes were great to deal with; highly recommended.

Thursday, February 10, 2011

GAGA-1: Temperature measurement

One step closer to launch tonight with the completion of work on the software for the internal and external temperature sensors. I'm using the DS1821 digital temperature sensor that has an operating range of -55C to 125C (that should cover the range I'll be seeing). It's a lovely little transistor-sized device:

The DS1821 uses something called the 1-Wire protocol. Essentially, it's a proprietary networking protocol that uses single byte control packets and its own serial timing. The entire thing is detailed in the datasheet. The family of devices using 1-Wire supporting networking multiple of them on a single wire, but the DS1821 only supports one device per wire.

So, my two DS1821s are connected to two ports on the Arduino flight computer. To interface to the devices some software is needed. There is an Arduino project for this called OneWire but I had trouble getting it going and it was late so I wrote my own code. (Also, this is the sort of thing I love).

First, here's a picture of the device under test. The DS1821 is at the top mounted just above the Radiometrix NTX2 module. On the breadboard there are power connections from the Arduino (using 5V) and a 4K7 pull up resistor need to pull the DS1821 data line high.

All the code is in the GAGA-1 GitHub repository but here are some excerpts.

To write bits to the device you have to follow this timing diagram:

To write a zero you drive the pin low for 60us and then release it allowing the pull-up resistor to do its job. To write a one you drive low for 1us and then drive high for the rest of the 60us slot. There's a 1us interval needed between writes.

The DS1821 actually samples the bus after 15us, so this translates into the following code:
// ds1821_write_bit: write a single bit to the DS1821
void ds1821_write_bit( int b,  // The bit to be written
             int pin ) // Arduino pin the DS1821 is on
{
  ds1821_drive_low( pin );

  // Total write time is 60us.  The DS1821 samples the
  // bus between 15us and 60us.
  
  delayMicroseconds( 15 );

  if ( b ) {
    digitalWrite( pin, HIGH );
    delayMicroseconds( 45 );
  } else {
    delayMicroseconds( 45 );
    digitalWrite( pin, HIGH );
  }
  
  // Recovery time before next operation
  delayMicroseconds( 1 );
}
Reading has a different timing cycle like this:

The Arduino drives the pin low and then releases it. Within 15us it samples the pin to read the high or low value. After 60us the entire cycle is done. That turns into the following in code:
// ds1821_read_bit: read a single bit coming from the DS1821
int ds1821_read_bit( int pin ) // Arduino pin the DS1821 is on
{
  ds1821_drive_low( pin );
  
  // The read slot is 60us.  Start by pushing the bus low and
  // wait 1us, then switch to input mode.  Data is valid for 15us
  // and read the state from the DS1821.  
  
  delayMicroseconds( 1 );
  digitalWrite( pin, HIGH );

  pinMode( pin, INPUT );
  delayMicroseconds( 5 );
  int value = ( digitalRead( pin ) == HIGH );
  
  // Calculated as 60 - 5 - 1 + 1 for recovery time.
  
  delayMicroseconds( 55 );
  return value;
}
And it works. Here's a little shot of temperatures in tenths of degrees C read from the board and output down the Arduino debugging serial link. The measurements start at room temperature and then I placed my finger on the DS1821 to warm it up.

At the end I removed my finger and let it drop back to room temperature. Sampling was done every 5s.

And finally, I managed to connect up the external DS1821 incorrectly and reverse the polarity. It got incredibly hot and I burnt my finger on it. Oddly, this didn't kill it. Connecting it correctly I got a nice stream of temperature data from it. Here's the little guy under test:

Tuesday, February 08, 2011

GAGA-1: Batteries

As I've mentioned before, GAGA-1 is using Energizer Ultimate Lithium AA batteries for the camera, flight and recovery computers. A total of 12 batteries will fly: two for the camera, four for the recovery computer and six for the flight computer.

They are light, give a lot of power and work at extreme temperatures. All are great virtues for this type of activity. Two are inside the camera, but the other 10 need battery holders.

So, I've hotglued in place one six battery holder and one four battery holder. Happily, there's enough space inside the capsule for them. Before doing this I also put batteries in them and shook them as hard as I could to see if the batteries were likely to come loose.

In the picture you can also see the nylon threaded rod used to hold down the computers and camera and the cable in the middle is the coax coming from the quarter wave antenna. The coloured dots on the battery holders are part of my Murphy's Law protection scheme.

The Mylar film inside the box is conductive, so to ensure no short circuits I insulated the exposed metal on the battery holders before installing them.

The other thing I've been working on is the interfacing with the DS1821 temperature sensors. But that's another story for another blog post. Here's a picture of the sensor that will be used to get external temperatures. It fits in a straw that pokes out the top of the capsule.

Saturday, February 05, 2011

GAGA-1: Voiding the warranty (for great justice!)

Having dug out and insulated the hole for the camera that will fly on GAGA-1 there was one last camera-related task to perform: make sure that it didn't move during the flight.

If you've seen any videos of other high-altitude balloon projects you'll know that there's quite a lot of buffeting of the capsule (especially in the jet stream) and so the camera needs to be fixed in place.

I had been planning to use strong Velcro mounts but after shaking the capsule around it was obvious that the camera was going to move around and the pictures would be spoilt. So, Plan B.

Plan B is a M6 nylon threaded rod that pierces the capsule wall and holds the camera in place with nuts. To do that a suitable 6mm hole needs to be drilled in the camera itself.

I dismantled my spare Canon A560 (the one that's partly broken) to see where I could drill. It was pretty obvious that the safest place was right through the view finder from the front. There are no electronics in the way. The view finder is a self-contained unit with plastic lenses. (A note of caution: the flash in the camera stores a lot of voltage in a small capacitor. Touch it and you'll get a big shock. I found that out the hard way.)

So, I first drilled a guide hole through the camera using a 2mm drill straight through the middle of the view finder lens on the front:

Next I used a 6mm drill to complete the hole. There was a load of debris inside the camera (contained within the view finder housing) that I removed using very thin pliers (it was the mangled guts of the view finder).

Then a quick check that the hole was good by threading through the M6 rod:

And then it was just a matter of making an appropriate hole in the capsule wall and pushing through the rod. To make sure it doesn't move there's a nut and the whole thing is hot glued in place.

And here's the finished mounting. The camera is held snugly in place.

A similar arrangement is used to hold the board containing the computers in place:

In other news, I've ordered one of the final bits that I didn't have: the parachute. It's a 36" parachute from Spherachutes with the balloon option (a point on the top where it can be attached to the line going to the balloon). It weighs just 50g but should slow the capsule for a safe landing.

Since Spherachutes makes them to order I've chosen alternating neon green and black panels. Neon green so that it can easily be seen on the ground, and black to find it in the sky.

Friday, February 04, 2011

Hacking the Toshiba T4800CT (a love story)

With St. Valentine's Day on the way, here's a little story about love (and technology).

Back in 1995 I needed a laptop for my girlfriend. She was thousands of miles away in Europe and I was in California and the phone bills (and the shenanigans with messing around inside international phone switches) were getting too much. I knew that we'd be able to communicate cheaply if I paid for a CompuServe account in the US and gave her a machine that had a PCMCIA 14.4Kbps modem in it. She'd be able to dial a local call and send and receive email from me in California.

Only trouble was, I didn't have enough money to buy her a laptop. So I kept searching around for deals and happened upon a Toshiba T4800CT in The Good Guys! in San Jose, CA. It was an older model and being sold off for a reasonable price. And it was a suitable machine.

So, I decided to buy it. But I couldn't because the machine was locked. There was some software that locked down Windows completely and required a password that they'd forgotten. You could play around with the installed software (more on that later) but not access anything else.

No access to File Manager, no way to get a COMMAND.COM prompt, just a bunch of productivity apps and demos. No way to run a program that wasn't in Program Manager already. And AOL, of course.

Everything was locked down.

The salesperson went away to find the password while I messed around with the machine. In doing so, I found a way in that would enable me to delete the SYS file that was used to implement the locking of the machine. I tried it out while no one was looking.

The salesperson came back to tell me that no one knew the password. So, I said: "If I can break into this machine right now, will you give me another $250 off?". He looked amused and said "Sure". With $250 off I could really afford the machine and that $250 would go on my next plane ticket to see my girlfriend.

So, I said "OK. Watch this." And I just stood there. About two minutes later a COMMAND.COM shell popped up on screen from nowhere. I quickly changed to C:\WINDOWS and deleted the offending .SYS file, and removed a reference to it from CONFIG.SYS using Notepad. I rebooted the machine and crossed my fingers.

The machine booted cleanly, didn't ask for any password and Windows started. The salesperson was good enough to honour the $250 offer. He walked with me to the sales desk to tell the story of what he'd just seen.

Of course, now you want to know how I made COMMAND.COM appear by magic.

The machine had a copy of Lotus Organizer on it. Organizer is a 'Filofax' type program that includes a calendar. The calendar allows you to set appointments. The appointments have various options related to what to do when it's time for the appointment (e.g. pop up a message, play a sound).

Image courtesy of BM Software

One of the options buried deep in the program was "Run a program" and it allowed selection of the program using the Open File Common Dialog Box which was not locked down at all.

All I'd done was set an appointment for about five minutes in the future (IIRC the granularity was something like 5 minutes) that ran COMMAND.COM.

PS We married a few years later after many exchanged emails.

Wednesday, February 02, 2011

Over 1,000 messages of support for Plan 28

After yesterday's blog post on the state of Plan 28 I've received over 1,000 emails and messages of support for the project. Thank you so much!

I can't possibly reply to everyone personally, but thank you! It means a great deal.

Here are a sample of the heartwarming messages:
I'm in for the long haul!

Get the charity set up ASAP; I want to throw money 
at this project.

Babbage had the patience and perseverance... so do 
we. Just keep going! The pledge holds!

Building one of these things isn't like slapping a 
few parts together. We knew it would be a long 
process. We're here for the long haul.

I'll happily increase my donation in the hope you 
can still reach the original goal.

Many people say "Why?" I say "Why not?" Go for it!

Still very supportive.  Send details of where to 
deposit pledge at any time.

I'm still in for $100. I'd love to see this done 
and one day come to see it in person!

This is a great project and I'll be supporting 
you all the way. 

I REALLY really appreciate the work, and will 
promote it.

I'm still in. Too cool of a project to give up 
on. Let me know what I can do and keep up the 
good work.

Put me down for a £50 pledge.  Good luck, I hope 
(and am sure) you can pull it off.

I sure want to see that machine :D, so keep on! 

I'll never give up on this project.
If you sent me a personal message with a question I will try to answer in the next week.

Tuesday, February 01, 2011

The State of Plan 28

Yesterday, many readers will have received an email from PledgeBank informing them that the Plan 28 pledge drive had failed. In a narrow technical sense that's correct: I had hoped to get 10,000 people to pledge to donate $10/£10/€10 towards building Babbage's Analytical Engine. In the end 3,996 people from around the world pledged.

Thank you to everyone who expressed this interest in the project. Because of you the project is not going away.

Here's the current state of things:

1. I am in the process of setting up the charitable organization that will manage Plan 28. As I mentioned before I've joined forces with Doron Swade on this and we are actively working to get the project running. Tomorrow I am meeting with specialist lawyers who will handle the charity registration.

2. We are in active talks with the Science Museum about their participation in the project (we hope to build the Analytical Engine at the Science Museum). This has take much longer than anticipated because the Science Museum is a very large organization whose management hierarchy must be navigated. There is great enthusiasm about the project at the Science Museum and they have been very helpful in providing access to Babbage's machines. I hope to announce the final details of our cooperation with the Science Museum in the next couple of weeks.

3. Doron and I are also in active talks with the Computer Conservation Society about their participation in the project. They have done wonderful work on many other historic computer reconstructions (and are just starting on EDSAC). We expect to be able to talk about that in detail in early March.

4. I continue to receive offers in kind of help on the project and I am very grateful for these and we will, undoubtedly, be taking many of them up when the time comes.

5. Another round of publicity will be coming shortly. In this Thursday's Times there's the Eureka science supplement which contains a special feature on the Analytical Engine and Plan 28. And a couple of weeks back I was being photographed for a feature in Wired Magazine. This will be in an issue sometime in the next couple of months.

I know that many people would like to give me money right now. I've been holding off for two reasons: firstly, if I start accepting your money without a proper legal organization I'll find myself in tax hell (the tax people might think the donations are my personal income, and you won't be able to get any tax deduction, and Plan 28 won't be able to apply for Gift Aid).

Secondly, once I can announce that the first part of the project is going to happen (digitization of the entire Babbage archive) the money will actually be needed. I hope to be asking people to donate sometime in the next few weeks.

I realize also that many people are frustrated that project isn't already off and running. Unfortunately, there is a lot of ground work (such as setting up ties with various organizations, finalizing the plan of action, and mundane things like bank accounts) to ensure that Plan 28 has a really solid footing.

Nevertheless, we still hope to have the Analytical Engine complete by 2021. Thank you for your continued support.

PS I have created a mailing list so that people can get email updates on the project. Just send a mail to [email protected] to join.