A few more notes on my implementation of Conway’s Life…

March 23, 2015 | Arduino, My Projects | By: Mark VandeWettering

I received a couple of email and twitter queries about various aspects of the code, so I thought I would add a followup to yesterday’s post.

First of all, I received a query as to whether it was “open source”. Frankly, the code is so minimal and so obvious I didn’t even consider it worthy of protection from any license. Consider it in the public domain. I do appreciate it when people who use this code give a nod back to my website as the origin of the code, but it’s not mandatory.

Seriously. It’s not a big deal.

Next, realize that I wrote the code in just a few minutes (less than thirty). It’s written in just about the most obvious way I could conceive. I really was just looking at a way to test my understanding of the U8glib library, and this seemed like a good way to go. There are a number of ways the code could be improved.

First, this implementation doesn’t use the full resolution of the 128×64 display: it only uses 96×64. The reason is quite simple: the way the code is written, it needs to maintain 2 buffers (the “current” and “next” arrays) each of which hold 128×64 bits. If you multiply out 128x64x2 and divide by 8 to get the number of bits needed, you’ll come up with 2048: coincidently, exactly the same amount of RAM in an ATMega328. But you’ll need some extra memory to hold temporary variables, buffers used by the U8glib, the stack for subroutine calls, etc… Trimming the resolution back to 96×64 provides enough space to actually run. But we could actually use the full resolution by being slightly more clever: instead of having two full size arrays, we could do more of the updates “in place”, and only buffer a couple of extra lines to hold out temporary values before we overwrite them. I have the code in my head, but a few odd details about it aren’t worked out yet, I hope to have nearly as simple an implementation worked out today some time. Stay tuned.

Second, it’s slow. Doing 8 independent bit lookups in the array, the increments, and the compares? It’s a straightforward implementation, but not a fast one. In particular, the shift operations on every pixel lookup are probably really a bad idea on the Atmel AVR: these chips don’t include a barrel shifter, so to shift by 7 takes 7 cycles. We could probably factor out a lot of these calculations with some work. It’s possible to use techniques that can process all the bits inside a given word “in parallel” by implementing bitwise arithmetic, but since the AVR is only an 8 bit processor, the gains are less than they would be on a 32 bit processor, and handling all the edge cases is kind of a nuisance. I remember doing this back in my college days, but I’d have to work out all the details again. You can look at this article from StackOverflow to get some hints and pointers to other implementations. Some of the ideas are good, some not.

Third: the display is really, really tiny. It might be fun to use the builtin scaling of the U8G driver to magnify it by two. Then, of course, we’ll only need to do 64×32, which should run around 4x as fast, and should be easier to see. It will also use a lot less memory, which makes it more useful as a module in (say) another program like a DIY watch.

Lastly, I was told that initializing the random number generator in this way would work, but it seems to generate the same seed each time. I’ll have to figure out a better way to initialize the seed on RESET.

Stay tuned for an improved version.

Tiny Implementation of Conway’s Life…

March 22, 2015 | Arduino, Embedded, My Projects, My Stories | By: Mark VandeWettering

I had a few minutes, so I thought I’d try making a graphics demo that runs on the tiny little 0.96″ OLED display I mentioned last week. One of the first programs I ever wrote was an implementation of Conway’s Game of Life, having learned about it from Martin Gardner’s Mathematical Games column in Scientific American. I remember that on my old Atari 400, it took a couple of seconds at least per generation, at a resolution of just 40×20 or so. Because of the limited memory (and small size of the display) I decided a 96×64 resolution. There is just enough memory to handle two full sized bit buffers. With a bit more work, I could make it work at the full resolution of the OLED display, but you need to do some of the updates in place, which makes it a bit harder.

[sourcecode lang=”cpp”]
//
// a tiny implementation of Conway’s Life
// written by Mark VandeWettering (brainwagon@gmail.com)
// https://brainwagon.org
//

#include "U8glib.h"

#define XSIZE (128-32)
#define XSIZE_UINT8 (XSIZE/8)
#define YSIZE (64)

uint8_t current[YSIZE][XSIZE_UINT8] ;
uint8_t next[YSIZE][XSIZE_UINT8] ;

#define MODX(x) (((x)+XSIZE)%XSIZE)
#define MODY(y) (((y)+YSIZE)%YSIZE)

#define ISSET(a, x, y) \
(a[MODY(y)][MODX(x)/8] & (0x1<<(MODX(x)&7)))

#define SET(a, x, y) \
a[MODY(y)][MODX(x)/8] |= (0x1<<(MODX(x)&7))

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

void
init()
{
int i, j ;
for (j=0; j<YSIZE; j++)
for (i=0; i<XSIZE_UINT8; i++)
current[j][i] = random(256) ;
}

void
setup()
{
randomSeed(analogRead(0));
init() ;
}

void
draw()
{
u8g.setDefaultBackgroundColor() ;
u8g.drawBox(0, 0, 128, 64) ;
u8g.setDefaultForegroundColor() ;
u8g.drawXBM(16, 0, XSIZE, YSIZE, (const uint8_t *) next) ;
}

void
loop()
{
int i, j ;

memset((void *) next, 0, sizeof(next)) ;
for (j=0; j<YSIZE; j++) {
for (i=0; i<XSIZE; i++) {
int sum = 0 ;
if (ISSET(current, i-1, j-1)) sum ++ ;
if (ISSET(current, i , j-1)) sum ++ ;
if (ISSET(current, i+1, j-1)) sum ++ ;
if (ISSET(current, i-1, j )) sum ++ ;
if (ISSET(current, i+1, j )) sum ++ ;
if (ISSET(current, i-1, j+1)) sum ++ ;
if (ISSET(current, i , j+1)) sum ++ ;
if (ISSET(current, i+1, j+1)) sum ++ ;

if (ISSET(current, i, j)) {
if (sum == 2 || sum == 3)
SET(next, i, j) ;
} else {
if (sum == 3)
SET(next, i, j) ;
}
}
}

memcpy((void *) current, (void *) next, sizeof(current)) ;

u8g.firstPage() ;
do {
draw() ;
} while (u8g.nextPage()) ;
}
[/sourcecode]

It works! It initializes the display to random values, and then runs Life. If the display gets boring, just hit the result button….


Discovered a new tool for embedded development: platformio

March 22, 2015 | Embedded, Microcontrollers, My Projects | By: Mark VandeWettering

I’m pretty old school when it comes to development. To me, writing code is something I like to do with vi (the editor that I learned three decades ago) and compile with Makefiles, especially for code that I do myself. In general, I prefer to do my development on either Linux or Mac OS too, so portable tools are my favorite. Increasingly, people have come to rely on complex development environments, many of which include code wizards that generate lots of the boiler plate needed to create applications, complex syntax coloring, and engines to refactor code. These environments are often significantly different from one another, are closed source, or rely on older versions of open source tools (like plugins for eclipse).

This seemed doubly true for this little Freescale development board that has been sitting unused since I purchased it at the last (or was it the one before that) Maker Faire. It is supposedly part of the “mbed” family of dev boards, which is supposed to make development across a variety of similar boards simple. But the reality is a dizzying array of odd products, including a web based IDE that just annoyed and confounded me. So, the board mostly sat unused. I did mention it in my “bucket o’ dev boards” video a couple weeks ago, and I thought “there must be a better way”.

Rather than toil away on my own, I tossed the question to my twitter followers:


Within minutes, @ukscone responded with this suggestion:


I had never heard of platformio, but I quickly read over the quickstart, and was impressed. Basically it’s a fairly simple utility called (appropriately enough) platformio, written in Python, and portable to Windows, Mac OS X and Linux. Compiled within it is knowledge of a large number of supported boards. You can get a list of supported boards by typing “platformio boards”, and you’ll get the output.

Platform: atmelavr
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
flora8                atmega32u4     8Mhz      28Kb    2Kb    Adafruit Flora
trinket3              attiny85       8Mhz      8Kb     512B   Adafruit Trinket 3V/8MHz
trinket5              attiny85       16Mhz     8Kb     512B   Adafruit Trinket 5V/16MHz
btatmega168           atmega168      16Mhz     14Kb    1Kb    Arduino BT ATmega168
btatmega328           atmega328p     16Mhz     28Kb    2Kb    Arduino BT ATmega328
diecimilaatmega168    atmega168      16Mhz     14Kb    1Kb    Arduino Duemilanove or Diecimila ATmega168
diecimilaatmega328    atmega328p     16Mhz     30Kb    2Kb    Arduino Duemilanove or Diecimila ATmega328
esplora               atmega32u4     16Mhz     28Kb    2Kb    Arduino Esplora
ethernet              atmega328p     16Mhz     31Kb    2Kb    Arduino Ethernet
fio                   atmega328p     8Mhz      30Kb    2Kb    Arduino Fio
leonardo              atmega32u4     16Mhz     28Kb    2Kb    Arduino Leonardo
megaADK               atmega2560     16Mhz     248Kb   8Kb    Arduino Mega ADK
megaatmega1280        atmega1280     16Mhz     124Kb   8Kb    Arduino Mega or Mega 2560 ATmega1280
megaatmega2560        atmega2560     16Mhz     248Kb   8Kb    Arduino Mega or Mega 2560 ATmega2560 (Mega 2560)
micro                 atmega32u4     16Mhz     28Kb    2Kb    Arduino Micro
miniatmega168         atmega168      16Mhz     14Kb    1Kb    Arduino Mini ATmega168
miniatmega328         atmega328p     16Mhz     28Kb    2Kb    Arduino Mini ATmega328
atmegangatmega168     atmega168      16Mhz     14Kb    1Kb    Arduino NG or older ATmega168
atmegangatmega8       atmega8        16Mhz     7Kb     1Kb    Arduino NG or older ATmega8
nanoatmega168         atmega168      16Mhz     14Kb    1Kb    Arduino Nano ATmega168
nanoatmega328         atmega328p     16Mhz     30Kb    2Kb    Arduino Nano ATmega328
pro8MHzatmega168      atmega168      8Mhz      14Kb    1Kb    Arduino Pro or Pro Mini ATmega168 (3.3V, 8 MHz)
pro16MHzatmega168     atmega168      16Mhz     14Kb    1Kb    Arduino Pro or Pro Mini ATmega168 (5V, 16 MHz)
pro8MHzatmega328      atmega328p     8Mhz      30Kb    2Kb    Arduino Pro or Pro Mini ATmega328 (3.3V, 8 MHz)
pro16MHzatmega328     atmega328p     16Mhz     30Kb    2Kb    Arduino Pro or Pro Mini ATmega328 (5V, 16 MHz)
robotControl          atmega32u4     16Mhz     28Kb    2Kb    Arduino Robot Control
robotMotor            atmega32u4     16Mhz     28Kb    2Kb    Arduino Robot Motor
uno                   atmega328p     16Mhz     31Kb    2Kb    Arduino Uno
yun                   atmega32u4     16Mhz     28Kb    2Kb    Arduino Yun
digispark-tiny        attiny85       16Mhz     5Kb     512B   Digispark (Default - 16 MHz)
digispark-pro32       attiny167      16Mhz     14Kb    512B   Digispark Pro (16 MHz) (32 byte buffer)
digispark-pro64       attiny167      16Mhz     14Kb    512B   Digispark Pro (16 MHz) (64 byte buffer)
digispark-pro         attiny167      16Mhz     14Kb    512B   Digispark Pro (Default 16 MHz)
engduinov1            atmega32u4     8Mhz      28Kb    2Kb    Engduino 1
engduinov2            atmega32u4     8Mhz      28Kb    2Kb    Engduino 2
engduinov3            atmega32u4     8Mhz      28Kb    2Kb    Engduino 3
lilypadatmega168      atmega168      8Mhz      14Kb    1Kb    LilyPad Arduino ATmega168
lilypadatmega328      atmega328p     8Mhz      30Kb    2Kb    LilyPad Arduino ATmega328
LilyPadUSB            atmega32u4     8Mhz      28Kb    2Kb    LilyPad Arduino USB
168pa16m              atmega168p     16Mhz     15Kb    1Kb    Microduino Core (Atmega168PA@16M,5V)
168pa8m               atmega168p     8Mhz      15Kb    1Kb    Microduino Core (Atmega168PA@8M,3.3V)
328p16m               atmega328p     16Mhz     31Kb    2Kb    Microduino Core (Atmega328P@16M,5V)
328p8m                atmega328p     8Mhz      31Kb    2Kb    Microduino Core (Atmega328P@8M,3.3V)
32u416m               atmega32u4     16Mhz     28Kb    2Kb    Microduino Core USB (ATmega32U4@16M,5V)
1284p16m              atmega1284p    16Mhz     127Kb   16Kb   Microduino Core+ (ATmega1284P@16M,5V)
1284p8m               atmega1284p    8Mhz      127Kb   16Kb   Microduino Core+ (ATmega1284P@8M,3.3V)
644pa16m              atmega644p     16Mhz     63Kb    4Kb    Microduino Core+ (Atmega644PA@16M,5V)
644pa8m               atmega644p     8Mhz      63Kb    4Kb    Microduino Core+ (Atmega644PA@8M,3.3V)
panStampAVR           atmega328p     8Mhz      31Kb    2Kb    PanStamp AVR
protrinket3ftdi       atmega328p     16Mhz     28Kb    2Kb    Pro Trinket 3V/12MHz (FTDI)
protrinket3           atmega328p     12Mhz     28Kb    2Kb    Pro Trinket 3V/12MHz (USB)
protrinket5ftdi       atmega328p     16Mhz     28Kb    2Kb    Pro Trinket 5V/16MHz (USB)
protrinket5           atmega328p     16Mhz     28Kb    2Kb    Pro Trinket 5V/16MHz (USB)
raspduino             atmega328p     16Mhz     30Kb    2Kb    Raspduino

Platform: atmelsam
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
due                   at91sam3x8e    84Mhz     512Kb   32Kb   Arduino Due (Programming Port)
dueUSB                at91sam3x8e    84Mhz     512Kb   32Kb   Arduino Due (USB Native Port)
digix                 at91sam3x8e    84Mhz     512Kb   28Kb   Digistump DigiX
sainSmartDue          at91sam3x8e    84Mhz     512Kb   32Kb   SainSmart Due (Programming Port)
sainSmartDueUSB       at91sam3x8e    84Mhz     512Kb   32Kb   SainSmart Due (USB Native Port)

Platform: freescalekinetis
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
IBMEthernetKit        mk64fn1m0vll12 120Mhz    1024Kb  256Kb  Ethernet IoT Starter Kit
frdm_k20d50m          mk20dx128vlh5  48Mhz     128Kb   16Kb   Freescale Kinetis FRDM-K20D50M
frdm_k22f             mk22fn512vlh12 120Mhz    512Kb   128Kb  Freescale Kinetis FRDM-K22F
frdm_k64f             mk64fn1m0vll12 120Mhz    1024Kb  256Kb  Freescale Kinetis FRDM-K64F
frdm_kl05z            mkl05z32vfm4   48Mhz     32Kb    4Kb    Freescale Kinetis FRDM-KL05Z
frdm_kl25z            mkl25z128vlk4  48Mhz     128Kb   16Kb   Freescale Kinetis FRDM-KL25Z
frdm_kl46z            mkl46z256vll4  48Mhz     256Kb   32Kb   Freescale Kinetis FRDM-KL46Z

Platform: nordicnrf51
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
wallBotBLE            nrf51822       16Mhz     128Kb   16Kb   JKSoft Wallbot BLE
nrf51_dk              nrf51822       32Mhz     256Kb   32Kb   Nordic nRF51-DK
nrf51_dongle          nrf51822       32Mhz     256Kb   32Kb   Nordic nRF51-Dongle
nrf51_mkit            nrf51822       16Mhz     128Kb   16Kb   Nordic nRF51822-mKIT
redBearLabBLENano     nrf51822       16Mhz     256Kb   16Kb   RedBearLab BLE Nano
redBearLab            nrf51822       16Mhz     256Kb   16Kb   RedBearLab nRF51822
seeedTinyBLE          nrf51822       16Mhz     256Kb   16Kb   Seeed Tiny BLE
hrm1017               nrf51822       16Mhz     256Kb   16Kb   Switch Science mbed HRM1017

Platform: nxplpc
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
blueboard_lpc11u24    lpc11u24       48Mhz     32Kb    8Kb    BlueBoard-LPC11U24
dipcortexm0           lpc11u24       50Mhz     32Kb    8Kb    DipCortex M0
lpc11u35              lpc11u35       48Mhz     64Kb    10Kb   EA LPC11U35 QuickStart Board
lpc4088_dm            lpc4088        120Mhz    512Kb   96Kb   EA LPC4088 Display Module
lpc4088               lpc4088        120Mhz    512Kb   96Kb   EA LPC4088 QuickStart Board
lpc1549               lpc1549        72Mhz     256Kb   36Kb   LPCXpresso1549
mbuino                lpc11u24       48Mhz     32Kb    8Kb    Outrageous Circuits mBuino
seeeduinoArchPro      lpc1768        96Mhz     512Kb   32Kb   Seeeduino-Arch-Pro
lpc11u35_501          lpc11u35       48Mhz     64Kb    10Kb   TG-LPC11U35-501
lpc1114fn28           lpc1114fn28    48Mhz     32Kb    4Kb    mbed LPC1114FN28
lpc11u24              lpc11u24       48Mhz     32Kb    8Kb    mbed LPC11U24
lpc1768               lpc1768        96Mhz     512Kb   32Kb   mbed LPC1768
ubloxc027             lpc1768        96Mhz     512Kb   32Kb   u-blox C027

Platform: ststm32
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
disco_f334c8          stm32f334c8t6  72Mhz     64Kb    16Kb   32F3348DISCOVERY
disco_f401vc          stm32f401vct6  84Mhz     256Kb   64Kb   32F401CDISCOVERY
disco_f429zi          stm32f429zit6  180Mhz    2048Kb  256Kb  32F429IDISCOVERY
nucleo_f030r8         stm32f030r8t6  48Mhz     64Kb    8Kb    ST Nucleo F030R8
nucleo_f070rb         stm32f070rbt6  48Mhz     128Kb   16Kb   ST Nucleo F070RB
nucleo_f072rb         stm32f072rbt6  48Mhz     128Kb   16Kb   ST Nucleo F072RB
nucleo_f091rc         stm32f091rct6  48Mhz     256Kb   32Kb   ST Nucleo F091RC
nucleo_f103rb         stm32f103rbt6  72Mhz     128Kb   20Kb   ST Nucleo F103RB
nucleo_f302r8         stm32f302r8t6  72Mhz     64Kb    16Kb   ST Nucleo F302R8
nucleo_f303re         stm32f303ret6  72Mhz     512Kb   64Kb   ST Nucleo F303RE
nucleo_f334r8         stm32f334r8t6  72Mhz     64Kb    16Kb   ST Nucleo F334R8
nucleo_f401re         stm32f401ret6  84Mhz     512Kb   96Kb   ST Nucleo F401RE
nucleo_f411re         stm32f411ret6  100Mhz    512Kb   128Kb  ST Nucleo F411RE
nucleo_l053r8         stm32l053r8t6  48Mhz     64Kb    8Kb    ST Nucleo L053R8
nucleo_l152re         stm32l152ret6  32Mhz     512Kb   80Kb   ST Nucleo L152RE
disco_f051r8          stm32f051r8t6  48Mhz     64Kb    8Kb    STM32F0DISCOVERY
disco_f303vc          stm32f303vct6  72Mhz     256Kb   48Kb   STM32F3DISCOVERY
disco_f407vg          stm32f407vgt6  168Mhz    1024Kb  128Kb  STM32F4DISCOVERY
disco_l152rb          stm32l152rbt6  32Mhz     128Kb   16Kb   STM32LDISCOVERY
disco_f100rb          stm32f100rbt6  24Mhz     128Kb   8Kb    STM32VLDISCOVERY

Platform: teensy
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
teensy20              atmega32u4     16Mhz     31Kb    2Kb    Teensy 2.0
teensy30              mk20dx128      48Mhz     128Kb   16Kb   Teensy 3.0
teensy31              mk20dx256      72Mhz     256Kb   64Kb   Teensy 3.1
teensy20pp            at90usb1286    16Mhz     127Kb   8Kb    Teensy++ 2.0

Platform: timsp430
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
lpmsp430fr5739        msp430fr5739   16Mhz     15Kb    1Kb    FraunchPad w/ msp430fr5739
lpmsp430f5529         msp430f5529    16Mhz     128Kb   1Kb    LaunchPad w/ msp430f5529 (16MHz)
lpmsp430f5529_25      msp430f5529    25Mhz     128Kb   1Kb    LaunchPad w/ msp430f5529 (25MHz)
lpmsp430fr5969        msp430fr5969   8Mhz      64Kb    1Kb    LaunchPad w/ msp430fr5969
lpmsp430g2231         msp430g2231    1Mhz      2Kb     128B   LaunchPad w/ msp430g2231 (1 MHz)
lpmsp430g2452         msp430g2452    16Mhz     8Kb     256B   LaunchPad w/ msp430g2452 (16MHz)
lpmsp430g2553         msp430g2553    16Mhz     16Kb    512B   LaunchPad w/ msp430g2553 (16MHz)
panStampNRG           cc430f5137     12Mhz     31Kb    4Kb    PanStamp NRG 1.1

Platform: titiva
---------------------------------------------------------------------------
Type                  MCU            Frequency  Flash   RAM    Name
---------------------------------------------------------------------------
lplm4f120h5qr         lplm4f120h5qr  80Mhz     256Kb   32Kb   LaunchPad (Stellaris) w/ lm4f120 (80MHz)
lptm4c1230c3pm        lptm4c1230c3pm 80Mhz     256Kb   32Kb   LaunchPad (Tiva C) w/ tm4c123 (80MHz)
lptm4c1294ncpdt       lptm4c1294ncpdt 120Mhz    1024Kb  256Kb  LaunchPad (Tiva C) w/ tm4c129 (120MHz)

That’s a LOT of different boards, including a large number of the ones I have. I was particularly interested in creating applications for the Freedom K64F board, which is supported. I typed “platformio install freescalekinetis”, and the script went out and found what version of tools it needed (gcc) and what support framework/libraries it needed, and installed them automatically (on Mac OSX/Linux, they end up hidden in the .platformio library in your home directory). You don’t need to go hunting around and find the right version, platformio takes care all of that (and can handle upgrades as new versions are created). In this way, platformio acts rather like a package manager such as apt-get on Linux.

To use platformio to build a new project, you create a directory, cd into it, and then run “platformio init –board=frdm_k64f”. This creates a src and lib directory, and a file called platformio.ini which describes which boards the project can support. It’s possible to create a single project which supports multiple boards (say, many different types of arduino) and build them all simultaneously, but in my case, I just used the one board. I then created this simple little program inside the src directory:

#include "mbed.h"

Serial pc(USBTX, USBRX);

Ticker timer;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);

int flip = 0 ;

int r=0, g=1, b=1 ;

void
attime()
{
    int t = led1 ;
    led1 = led2 ;
    led2 = led3 ;
    led3 = t ;
}

int
main()
{
        pc.printf("\nHello world.\n") ;
        led1 = r ;
        led2 = g ;
        led3 = b ;

        timer.attach(&attime, 1);
        
        for (;;) {

        }
        
        return 0 ;
}

This is a simple little program that prints “Hello world” back on the USB port, and then blinks the RGB LED in different colors. I didn’t really know much about the library support for these mbed based chips, but I’m old school. Snooping around in the .platformio directory, I found a bunch of header files that hinted at what is possible. I guessed on how this stuff worked, and coded the program up. You can then compile it with “platformio run”, or compile and upload it with “platformio run -t upload”. (There is a way to set it to automatically upload it if it compiles successfully too).

So, within one hour, I had this:


Awesome!

I’m looking forward to doing more experimentation with platformio, and now have it installed on both my Mac and Linux laptops. In addition to some of the odder platforms I have (like the FreeScale or STM32 boards) it also supports the Arduinos. I like the idea of being able to develop code for the Arduino without having to go through their IDE. I did a bit more experimentation with it last night, and got it to generate some display programs for the little OLED display that I wrote about earlier. Platformio also has a library manager which knows about a lot of the popular Arduino libraries, and can automatically download and update those. As I learn more, I’ll try to post more.

Thanks again to @ukscone! Best new thing I’ve discovered in weeks.

Replacing the LCD Panel in a Samsung 303C Chromebook…

March 20, 2015 | Hardware, My Projects, Stupidity | By: Mark VandeWettering

In what quite possibly might be the most boring video ever produced, I recorded myself changing the LCD panel out of my Chromebook. It’s 17 minutes of riveting youtube goodness. Skip down to the bottom if you want to watch.

But here’s the story if you’d rather just read a paragraph. My wife bought me this little Samsung 303C Chromebook a while ago, and unlike the netbook that I had years before, I actually found this gadget to be pretty useful. For those who may not know about Chromebooks, they run ChromeOS, an operating system designed by Google to mostly run web applications. You can read more about it, but essentially it’s an OS designed to run a browser and web applications. I use it mostly to do web browsing, email, writing (using Google Docs), Netflix, and running ssh to access other machines on my network. For that, it’s great: it has long battery life, is lightweight, and is cheap (list price is $200 or so). I have taken it when traveling instead of a tablet when I may need to get some writing done, and when bringing a full laptop would be more cumbersome.

Sadly, a few days ago I realized that I had somehow managed to crack the LCD screen on it. I tend to be pretty casual with the thing, so I probably kicked it around while it was on the floor or something. I was kind of bummed. But a little quick googling revealed that I could get a replacement screen from Amazon for about $39 with free shipping courtesy of Amazon Prime. I ordered it on Tuesday night, and got it Thursday.

The replacement is very, very simple: I suspect having done it once I could probably do it in less than five minutes. The procedure is basically to turn off the unit, pop off the bezel (just use your fingers), and remove four screws that hold the screen in place. Then, you have to disconnect the ribbon connector, which I found to be a little unobvious, and results in a boring middle part of this video, where I am trying to understand exactly how to release the catch. I was overly cautious, and wanted to make sure I knew what I was doing, so I stopped and rewatched another video, which didn’t help a lot. In the end, I realized what I was staring at: there is a C shaped hasp which goes around the outside of the connector on the board, and had a plastic tab which was hidden under a layer of tape above. Once I figured that out, I used a small screwdriver to lift the edge, and disconnected the ribbon cable. After that, it was entirely easy: just reverse the process, attach the cable, secure the four screws again, pop the bezel on, and voila! Screen works again.

At the very end of the video, you can hear me muttering a little bit about the “black line”. When I reinstalled it, it looks a little like the active area of the screen is a little offset: I see a black gap at the top, and the active lines of the screen at the very bottom are very close (or even hidden a little) by the bezel. I was wondering if perhaps I should have secured the panel with the alternate set of screw holes. Rewatching the video, it appears that I used the same set that the original did, but I might still disassemble it to adjust this and see if it makes the result better.

In any case, it was a quick and easy fix, and I’m glad my trusty little Chromebook is back and running.

Regarding production: I filmed it all with my GoPro Hero 3 (white). I apologize a bit for the audio, I’m picking up a bit of noise, and didn’t have time to fix it. I assembled the two clips using an FFMPEG script that I have used before, with one addition: I realized that I typed my login password on camera, thought that might be a bad idea, so I figured out how to blur out the image at that time. Fun! I might make a new article about that later, when I develop some more interesting examples.

Hope this helps someone in the future!

Need π to 100 or so digits precision?

March 17, 2015 | Math | By: Mark VandeWettering

Use the “bc” arbitrary precision calculator you can probably find (or install easily) on your Linux box.

> bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=50
4*a(1)
3.14159265358979323846264338327950288419716939937508

User input is in bold. the scale command sets the number of digits of precision. If you need 200 digits…

scale=200
4*a(1)
3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
223172535940812848111745028410270193852110555964462294895493038196

Other formulas work pretty well too:

4*(4*a(1/5)-a(1/239))
3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
223172535940812848111745028410270193852110555964462294895493038188

Note: the last few digits are likely to be off, so generate a few more than you need. For fun, try to set the number of digits to a couple of thousand digits, and compare the runtime of each of the formulas.

Addendum: You can use the Gauss-Legendre algorithm to compute the digits of pi using bc as well. If you double the “scale”, you’ll need to add one to the for loop variable.

scale=1000

define sqr(x) {
    return x * x ;
}

a = 1 
b = 1 / sqrt(2)
t = 1 / 4
p = 1

for (i=0; i<9; i++) {
    next_a = (a + b) / 2
    next_b = sqrt(a * b)
    next_t = t - p * sqr(a - next_a)
    next_p = 2 * p

    a = next_a
    b = next_b
    t = next_t
    p = next_p
}

sqr(a + b) / (4 * t)

My first try at an inexpensive 0.96″ OLED display…

March 17, 2015 | Amateur Science, Arduino, Development Boards | By: Mark VandeWettering

As my recent video showed, I have a lot of development boards. I also have a fair number of little boards that are useful to plugin to these development boards to accomplish various tasks. Yesterday, I received a little OLED board that I thought I’d try hooking up and let you know about my experience.

There are lots of boards out there that apparently use the same screen: a 0.96″ OLED display with a resolution of 128×64. I ordered this one from Amazon for only $9 with free shipping. The description is a little bit misleading: you can find versions of these kinds of boards that have 7 or 8 pins and use the SPI bus. This one has (and requires) only four pins, and uses the I2C bus. I’m no expert on the technical differences, but my general impression is that SPI is full duplex and can run at higher speed and at longer range, but requires individual chip select lines for each device, where the I2C bus uses chip addressing, so no additional wires need to be hooked up to select the proper target device. (If any of my genius readers care to correct me on that, feel free to leave a comment).

Here’s a picture of the module I got, as I tweeted it yesterday:

It’s safe to run on either 5v or 3.3v, without any level converters or other nonsense. I hooked it up to one of my Sparkfun RedBoard Arduino clones. I plugged it into a bread board, and then wired up the four connections. VCC goes to the 5V pin on the Redboard, GND goes to one of the Arduino grounds. The remaining two lines need to be hooked up to the SCL (serial clock) and SDA (serial data) lines on the Arduino. This caused me a minor bit of confusion: on an Arduino R3, those two pins are on A4 and A5.

Uno R3 Pinout

On the RedBoard, these pins are split out separately onto separate pins near the AREF pin.

Red Board

I connected them to the SCL/SDA connectors on the RedBoard. I suspect that on the Uno R3, A4/A5 are the connectors you’ll need. Other variants of the Arduino might need different pins.

And, of course you’ll need some software. It’s tempting to go to Adafruit for all things Arduino, but in this case it can be a bit of a mistake I think, or at least it might require a bit of tinkering. Adafruit sells their own OLED boards, but they are a bit more costly and are wired a bit differently, and I thought that might make their software a little trickier to configure.

Instead, I found the U8G graphics library. It’s fairly nice because it supports a wide variety of boards, and is self contained. If you download the Arduino code and unzip it into the Arduino library directory and restart the Arduino environment, you’ll see some examples installed. But if you load one and try to compile it, you’ll encounter an error: the examples aren’t configured for the particular board you need. To do that, you need to uncomment the right definition for the graphics device.

For this specific device, you want to delete the two slashes at the start of this line. This selects the I2C bus, and tells it to use the SSD1306 chip that is on the board. This one worked for me.

//U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE);  // I2C / TWI

So, I downloaded the “Graphics Test” example, made that modification, compiled it and downloaded it to the RedBoard. Voila



A pretty neat little display. I must say that it’s a bit too tiny for my old-guy eyes to read when the print is small (damn you presbyopia!) but It’s very sharp and clear. If you have need of such a device, this one seems inexpensive and easy to use. Check it out.

A New Development Board: the ODROID-C1

March 14, 2015 | Development Boards, Raspberry Pi, Small Linux Computers | By: Mark VandeWettering

My ODROID-C1One of my recent posts highlighted the big pile of development boards that I have lying around. This week, I actually added to that pile in a couple of ways: I found a pair of Beagle Bone Blacks that I had misplaced, a couple of Propeller boards, and most significantly, I ordered an ODROID-C1 from ameriDroid. Stupidly, I didn’t read their website carefully enough, so I ended up making TWO orders from ameriDroid, the second to get the somewhat odd power supply needed (5V, 2A, with 2.5mm barrel) and to which I added the clear case you see, and also a micro HDMI cable (I know I have one some where, but I couldn’t find it). The prices for the additional goodies swell the price a bit, but are quite reasonably priced: $4.95 for the case, $5.95 for the HDMI cable, and $6.95 for the power adapter. Consider carefully before ordering and you’ll save a round of shipping.

ameriDroid did an excellent job of shipping: I had BOTH orders delivered just two days after ordering. They even included this nice hand written thank you, which makes more sense when you realize I had this delivered to my work address.


In the following discussion, when I mention the Raspberry Pi, I am speaking of the older variation model B and the B+. I do not yet have a Raspberry Pi 2, which upgrades to a 900Mhz quad core with 1GB of DRAM.

Given that I have four Raspberry Pis and three Beagle Bone Blacks of various generations, what compelled me to look at the ODROID-C1? You can read the specifications yourself, but here are the things that were most intriguing to me:

  • Quad core 1.5Ghz ARM processor. Compared to the 700Mhz single core ARM in the Raspberry Pi and the 1Ghz CPU in the Beagle Bone Black, one might expect that this little board could handle a lot more stuff.
  • 1GB of Dram, double most of my other boards. Nice!
  • Supports some little eMMC4.5 flash boards, which are supposed to be faster than existing microSD cards (more on this below).
  • 4 USB ports + 1 USB OTG port. Lots of expansion capabilities.
  • Includes an infrared receiver built onto the board. Might be cool for remote/home theater applications.
  • Supports both Ubuntu and Android. I’m mostly a Linux guy, but the possibility of using recent Android builds is interesting too.

Okay, so on to my experience…

I didn’t order any of the memory cards from ameriDroid with the operating systems pre installed. Why? I’m kind of a cheapskate, and I have a couple of spare 16GB microSD cards lying around. I started with a class 10 Lexar card. From my Ubuntu laptop, I downloaded their version of Ubuntu (1.1GB compressed, around 4gb uncompressed) and did the usual dance using the Linux “dd” program to copy it to the flash card. I also got an Edimax Wifi dongle from one of my other Raspberry Pis, and the wireless keyboard dongle. Plugged all this stuff together, plugged the microHDMI cable into my old Samsung TV, and powered it on. And…

Nothing. Screen went black on the TV, and the two LEDs on the board (red and blue) were steady and mixing to purple color. Hmmph.

A little googling revealed that if Linux had booted, it would be flashing the blue led as a heart beat indication. I decided to go ahead and try reburning Linux onto my other flash card (which it turns out is a slower class 6 Lexar card). After all, earlier this week I discovered that one of my unbootable Raspberry Pis was in fact an issue with SD card compatibility.

And, of course… that worked! Up until a point. My TV is rather old, and just supports 720P. When it booted, I ended up with my tv saying “Video Mode Not Supported”. Grrr. It turns out that you can change that by modifying the boot.ini file on the card (easy to edit if you have another Linux box, mount the card, edit the file to select 720p, save, eject, and reboot).

And that worked. Again, up until a point. On my TV, overscan is a bit of an issue: a significant amount of the screen (including all of the all-important task bar) was actually off screen on my TV. Grr… I drug out a monitor which didn’t have the overscan issues. And rebooted.

Into a nice X-windows desktop. It wasn’t the Unity layout that I was familiar with from my desktop, it’s more old school. On the desktop is a README and an icon labelled “ODROID Utility”. You click on it, and it allows you to do some features similar to those performed by the “raspi-config” program on the Raspberry Pi: most notably, to upgrade the kernel/firmware and expand the root partition to take full advantage of the entire microSD card. If you select the “upgrade kernel”, it actually doesn’t do that, it tells you that you can use the normal “sudo apt-get update; sudo apt-get upgrade; sudo apt-get dist-upgrade” commands to update. But I did try to expand the drive, rebooted, setup the wireless network using the desktop utility, and then started the apt-get stuff…

But something along here went wrong. Even after rebooting, it didn’t appear that the card was expanded, but I didn’t notice until the upgrade was underway. There were a couple of other oddities: ssh didn’t appear to be working right, I couldn’t login remotely. And the Edimax Wifi was really, really slow: just a few kb per second. That upgrade was going to take forever. And while that was happening, I noticed the odd “unexpanded” root partition, which appeared to be out of space. Argh!

So, I redid the entire process again: reflashed the OS, and redid everything again. I also decided to ditch the Edimax connector, and instead plugged the board into my wireless router via Ethernet.

And somehow, things worked better. I’m not sure what I did wrong, but when I tried to expand the root FS, it told me to check to make sure that the root device was on /dev/mmcblk0p2. I exited first, and ran df to check, and it told me that it couldn’t access the mount table. “What the heck?” I decided to reboot again, and it showed up properly, not sure why. In any case, I expanded the root fs and rebooted. This time, I saw 11GB free, and decided to proceed with the apt-get upgrades.

Now that I was hooked up via Ethernet, things seemed to work much better. It still took a couple of hours to update all this stuff, but it did, and now it’s running pretty well.

If you “cat /proc/cpuinfo”, you get:

odroid@r2d2:~$ cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 1 (v7l)
processor       : 0
BogoMIPS        : 3.27

processor       : 1
BogoMIPS        : 3.27

processor       : 2
BogoMIPS        : 3.27

processor       : 3
BogoMIPS        : 3.27

Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xc05
CPU revision    : 1

Hardware        : ODROIDC
Revision        : 000a
Serial          : 1b00000000000000

Nice! Quad core. It still doesn’t seem super fast, no doubt because of the slow flash cards. You can ssh in using the login odroid password odroid. You can run sudo or su with the same password.

It was a bit of a hassle, but it appears to work.

Overall, the biggest problem I have with the ODROID thusfar is the Ubuntu distribution is just too bloated. It loads a whole bunch of software that might be reasonable on a desktop, but seems out of place (at least by default) on a small system. The Raspbian distribution of Debian actually walks this line pretty carefully: it feels fleshed out, but by default doesn’t include absolutely everything you might want, because after all, you might not want all this stuff, and resources on these small boards are fairly scarce. I don’t think I need the jdk, cups, kido (I had to look it up too), samba, chrome and firefox (runnable, but not all that pleasant in low memory systems) and god knows what else. This also means that getting your system up to date is slow too, because there is just so much software to update. Bleh.

It’s also pretty clear that the ODROID distribution is just less polished. The Raspberry Pi might annoy me with its (understandable) insistence on setting your keyboard up for UK English, but it’s easy enough to change, and raspi-config handles most of it. Ubuntu on the ODROID seems curiously to come with the default time zone set to Australia/Adelaide, and I had to google for the dpkg-reconfigure magic to fix it. Your expectations and experiences might be different.

One of my twitter followers asked whether I had bought the eMMC card with Ubuntu pre-installed. I did not, and the reason is simple: I’m a cheapshake. I think I paid ~$10 for my last 16gb microSD card, whereas the 16gb eMMC cards sold by ameriDroid cost $40 (more than the entire rest of the computer). Whether they are speedy or not, it didn’t seem like economy to me.

A few last thoughts after my first day as an ODROID-C1:

If you are a relative beginner to Linux, I don’t think I’d allow myself to be seduced by the ODROID’s higher speed. Get yourself a Raspberry Pi 2: definitely setup better for newbies, and has a much larger community to draw from. I found the learning curve for the ODROID to be a bit steeper than I think newbs could handle.

The ODROID-C1 could use a more disciplined Ubuntu distribution. The existing one includes everything and then some. A smaller but more reasoned distribution would be nicer.

I have not figured out what the deal is with the microSD card that wouldn’t boot. I am told that Samsung cards are in general better, but more investigation is clearly needed. I’ve no doubt that the class 6 card I’m using is slow, but the class 10 card I tried didn’t work. More experimentation is clearly (but sadly) still needed.

I should experiment with wireless again. I’ve had good luck with the Edimax dongles on the Pi, not sure what the issue might be.

Buy the AC adapter when you order one. And the HDMI cable if you don’t have one.

A lot of the documentation is obviously kind of bad translations. Even their videos can be a little bit mumbly and hard to understand:



Are any of my other readers using the ODROID-C1? I’d love to hear your comments and experiences.

3/14/15

March 14, 2015 | Amateur Science, Math | By: Mark VandeWettering

Happy Albert Einstein’s birthday! And we are just a few minutes away (in our time zone anyway) from 9:26. Huzzah!

I’m going to celebrate by making Shepard’s Pi(e) for dinner.

A 6M beacon using the NT7S’s Si5351 board…

March 9, 2015 | Amateur Radio, Arduino | By: Mark VandeWettering

This morning, the Tweeti-verse (I can’t believe I just used that word) informed me that Thomas, LA3PNA had constructed a VHF beacon using the Si5351, and I was tagged as somehow helping:

Sure enough, I’m getting lots of mileage out of the very simple Morse generating code that I posted a while back. But the real star of this was Jason Mildrum (NT7S) and his awesome little Si5351 breakout board that he designed and made available via Indiegogo, as well as a nice little Arduino library to control the board. For those of you who don’t follow this stuff, the Si5351 is a nifty little board that is capable of generating three frequencies at once under the control of a microcontroller like the Arduino. Guys like Jason and Pete Juliani, N6QW, have been experimenting using this device as the basis for frequency generation in a variety of experimental radios. I received my kit last week, and hope to get the board up and running this week. Stay tuned!

Increasing pyephem’s accuracy for satellite rise/set calculations…

March 8, 2015 | Amateur Satellite, Amateur Science, Python | By: Mark VandeWettering

A few years ago, I created my own Python implementation of the Plan13 satellite prediction code written by James Miller (G3RUH). The Plan13 algorithm isn’t very complicated: you can easily run it on processors like the Arduino (in fact, I used it for my ANGST satellite tracker) But somehow, I managed to misplace the source code for the Python version, probably on a hard drive for a computer that died, and so when I wanted to do some ISS calculations, I decided that I’d go ahead and use PyEphem, a much more complete package that can do all sorts of astronomical calculations, and which includes an implementation of the fairly standard SGP4 model.

It’s fairly simple to write some code to predict ISS passes from any position on earth. Here’s a quick example, with the TLEs for the ISS hard coded, as well as an observer position:

[sourcecode lang=”python”]
#!/usr/bin/env python

from math import degrees
import ephem

# create an observer
obs = ephem.Observer()
obs.lat = ‘38.0’
obs.lon = ‘-122’
obs.elevation = 100.

# create the iss object…

iss = ephem.readtle("ISS (ZARYA) ",
"1 25544U 98067A 15067.48441091 .00017347 00000-0 26069-3 0 9998",
"2 25544 51.6448 227.0292 0008846 83.1031 17.2346 15.54929647932364")

# figure out the next pass…
# only interested in rt (rise time), tt (transit time) and st (set time)
#

rt, razi, tt, televation, st, sazi = obs.next_pass(iss)

print "Rise Time: ", rt
print "Transit Time:", tt
print "Set Time: ", st
[/sourcecode]

But I was somewhat chagrined that if I ran this little snippet multiple times, I got different answers. Not by a lot, but by several seconds:

pi@blueberrypi ~ $ !.
./iss
Rise Time:    2015/3/8 22:30:12
Transit Time: 2015/3/8 21:00:52
Set Time:     2015/3/8 21:04:09
pi@blueberrypi ~ $ !!
./iss
Rise Time:    2015/3/8 22:30:12
Transit Time: 2015/3/8 21:00:53
Set Time:     2015/3/8 21:04:10
pi@blueberrypi ~ $ !!
./iss
Rise Time:    2015/3/8 22:30:13
Transit Time: 2015/3/8 21:00:53
Set Time:     2015/3/8 21:04:10
pi@blueberrypi ~ $ !!
./iss
Rise Time:    2015/3/8 22:30:03
Transit Time: 2015/3/8 21:00:49
Set Time:     2015/3/8 21:04:11

Digging in the code, it’s not hard to see what’s going on. The code is stepping forward by intervals of about 1 minute, trying to catch the satellite as it peaks over the horizon. When it does, it then uses twenty iterations of the secant method to find the point where the satellite crosses zero altitude. But there is an early out: if the interval drops below ten seconds, it goes ahead and exists. Similarly, it only locates the time of the transit to within 15 seconds. But these can be fixed with some quick, and probably undisciplined changes to the code will make things behave better.

Both edits are in the file riset_cir.c which is part of libastro-3.7.5 (your version might change, but will probably be the same). Near the top you’ll find the declaration for TMACC

[sourcecode lang=”C”]
#define TMACC (10./3600./24.0) /* convergence accuracy, days */
[/sourcecode]

Change this to 0.5 seconds instead.

[sourcecode lang=”C”]
#define TMACC (0.5/3600./24.0) /* convergence accuracy, days */
[/sourcecode]

You might want to increase MAXPASSES in the find_0alt function, but I had no difficulty with leaving it at 20.

Similarly, we need to change the error in find_transit:

[sourcecode lang=”C”]
static int
find_transit (double dt, Now *np, Obj *op)
{
#define MAXLOOPS 10
#define MAXERR (0.25/60.) /* hours */
[/sourcecode]

The number of iterations is pretty low (just 10) and the MAXERR was 15 seconds. I decided to add some iterations to ensure convergence, and to set the MAXERR to be just one second.

[sourcecode lang=”C”]
static int
find_transit (double dt, Now *np, Obj *op)
{
#define MAXLOOPS 20
#define MAXERR (1./3600.) /* hours */
[/sourcecode]

With these changes in place, you get times which are accurate to around one second. Note: I do not mean to imply that these numbers are somehow absolutely better. It is known that the SGP4 model can only locate satellites to errors of around 1km per day at best, so trying to converge them to insane levels of accuracy isn’t meaningful. But for my application, I want to count down to transits, and having the estimate jump around by a few seconds made the count down look funny. Of course, I could have just computed the times once, and used that, but I still think it’s kind of odd that the estimates vary by a human discernable amount depending solely on what time you decide to try to compute from. This additional accuracy makes the program a very tiny bit slower, but is worth it for my application.

Addendum: A few more lines of code make the code a bit more useful. This now outputs the next pass expressed in the localtime rather than UTC, and gives you a bit of a countdown.

[sourcecode lang=”python”]
#!/usr/bin/env python

from math import degrees
import ephem
import datetime

# create an observer
obs = ephem.Observer()
obs.lat = ‘38.0’
obs.lon = ‘-122’
obs.elevation = 100.

# create the iss object…

iss = ephem.readtle("ISS (ZARYA) ",
"1 25544U 98067A 15067.48441091 .00017347 00000-0 26069-3 0 9998",
"2 25544 51.6448 227.0292 0008846 83.1031 17.2346 15.54929647932364")

# figure out the next pass…
# only interested in rt (rise time), tt (transit time) and st (set time)
#

n = ephem.now()

rt, razi, tt, televation, st, sazi = obs.next_pass(iss)

print "%d" % round((rt – n) * 3600 * 24), "seconds until the next pass."

rt = ephem.localtime(rt).strftime("%x %X")
tt = ephem.localtime(tt).strftime("%x %X")
st = ephem.localtime(st).strftime("%x %X")

print "Rise Time: ", rt, "Azimuth: %5.1f" % degrees(razi)
print "Transit Time:", tt, "Elevation: %5.1f" % degrees(televation)
print "Set Time: ", st, "Azimuth: %5.1f" % degrees(sazi)
[/sourcecode]

Addendum2: A few more lines of code fetches a current set of orbital elements from celestrak.com. A future revision of this will probably cache a local copy of these orbital elements so you don’t unnecessarily hammer their server.

[sourcecode lang=”python”]
#!/usr/bin/env python

from math import degrees
import ephem
import datetime
import urllib2

req = urllib2.Request("http://celestrak.com/NORAD/elements/amateur.txt")
response = urllib2.urlopen(req)
data = response.read().splitlines()

objs = []

for idx in range(0, len(data), 3):
objs.append(ephem.readtle(data[idx], data[idx+1], data[idx+2]))

# create an observer
obs = ephem.Observer()
obs.lat = ‘38.0’
obs.lon = ‘-122’
obs.elevation = 100.

# create the iss object…

iss = ephem.readtle("ISS (ZARYA) ",
"1 25544U 98067A 15067.48441091 .00017347 00000-0 26069-3 0 9998",
"2 25544 51.6448 227.0292 0008846 83.1031 17.2346 15.54929647932364")

# figure out the next pass…
# only interested in rt (rise time), tt (transit time) and st (set time)
#

tlist = []

for obj in objs:
r = obs.next_pass(obj)
tlist.append((r[0], obj, r))

tlist.sort()

for t, obj, r in tlist:

n = ephem.now()

rt, razi, tt, televation, st, sazi = r

print obj.name
print "%d" % round((rt-n) * 3600 * 24), "seconds until the next pass."

rt = ephem.localtime(rt).strftime("%x %X")
tt = ephem.localtime(tt).strftime("%x %X")
st = ephem.localtime(st).strftime("%x %X")

print "Rise Time: ", rt, "Azimuth: %5.1f" % degrees(razi)
print "Transit Time:", tt, "Elevation: %5.1f" % degrees(televation)
print "Set Time: ", st, "Azimuth: %5.1f" % degrees(sazi)

print
[/sourcecode]

The output is now a list of all the amateur satellites that it fetched, sorted in order of the passes which are soonest appear first.

BEESAT-2
410 seconds until the next pass.
Rise Time:    03/08/15 18:33:03 Azimuth:   272.2
Transit Time: 03/08/15 18:37:54 Elevation:   8.1
Set Time:     03/08/15 18:42:45 Azimuth:     9.4

CUBESAT XI-V (CO-58)
526 seconds until the next pass.
Rise Time:    03/08/15 18:34:59 Azimuth:    31.0
Transit Time: 03/08/15 18:41:08 Elevation:  16.4
Set Time:     03/08/15 18:47:16 Azimuth:   153.1

XIWANG-1 (HOPE-1)
1228 seconds until the next pass.
Rise Time:    03/08/15 18:46:41 Azimuth:    91.6
Transit Time: 03/08/15 18:53:13 Elevation:   8.5
Set Time:     03/08/15 18:59:45 Azimuth:     6.5

OSCAR 7 (AO-7)
1251 seconds until the next pass.
Rise Time:    03/08/15 18:47:04 Azimuth:   229.2
Transit Time: 03/08/15 18:54:42 Elevation:   8.5
Set Time:     03/08/15 19:02:20 Azimuth:   317.9

AAUSAT3
2080 seconds until the next pass.
Rise Time:    03/08/15 19:00:54 Azimuth:    29.7
Transit Time: 03/08/15 19:07:39 Elevation:  19.3
Set Time:     03/08/15 19:14:25 Azimuth:   157.0

PCSAT (NO-44)
2515 seconds until the next pass.
Rise Time:    03/08/15 19:08:08 Azimuth:   173.2
Transit Time: 03/08/15 19:15:24 Elevation:  24.3
Set Time:     03/08/15 19:22:39 Azimuth:    41.1

CUTE-1.7+APD II (CO-65)
2940 seconds until the next pass.
Rise Time:    03/08/15 19:15:14 Azimuth:    81.8
Transit Time: 03/08/15 19:17:56 Elevation:   1.9
Set Time:     03/08/15 19:20:37 Azimuth:    31.8

JAS-2 (FO-29)
2956 seconds until the next pass.
Rise Time:    03/08/15 19:15:30 Azimuth:   255.5
Transit Time: 03/08/15 19:19:08 Elevation:   2.2
Set Time:     03/08/15 19:22:47 Azimuth:   307.5

M-CUBED & EXP-1 PRIME
3635 seconds until the next pass.
Rise Time:    03/08/15 19:26:49 Azimuth:   354.1
Transit Time: 03/08/15 19:32:20 Elevation:  12.4
Set Time:     03/08/15 19:37:52 Azimuth:   247.0

MOZHAYETS 4 (RS-22)
3940 seconds until the next pass.
Rise Time:    03/08/15 19:31:54 Azimuth:   347.2
Transit Time: 03/08/15 19:37:10 Elevation:   9.9
Set Time:     03/08/15 19:42:26 Azimuth:   248.6

CUBESAT XI-IV (CO-57)
4134 seconds until the next pass.
Rise Time:    03/08/15 19:35:08 Azimuth:   194.6
Transit Time: 03/08/15 19:42:31 Elevation:  27.0
Set Time:     03/08/15 19:49:53 Azimuth:   334.6

HAMSAT (VO-52)
4222 seconds until the next pass.
Rise Time:    03/08/15 19:36:36 Azimuth:   235.6
Transit Time: 03/08/15 19:40:29 Elevation:   4.5
Set Time:     03/08/15 19:44:22 Azimuth:   310.9

PRISM (HITOMI)
4468 seconds until the next pass.
Rise Time:    03/08/15 19:40:41 Azimuth:    13.2
Transit Time: 03/08/15 19:47:14 Elevation:  82.2
Set Time:     03/08/15 19:53:46 Azimuth:   192.3

CUTE-1 (CO-55)
4562 seconds until the next pass.
Rise Time:    03/08/15 19:42:16 Azimuth:   198.2
Transit Time: 03/08/15 19:49:30 Elevation:  23.6
Set Time:     03/08/15 19:56:44 Azimuth:   332.9

STRAND-1
4714 seconds until the next pass.
Rise Time:    03/08/15 19:44:47 Azimuth:    18.5
Transit Time: 03/08/15 19:52:18 Elevation:  49.9
Set Time:     03/08/15 19:59:48 Azimuth:   181.1

BEESAT-3
4722 seconds until the next pass.
Rise Time:    03/08/15 19:44:55 Azimuth:   342.9
Transit Time: 03/08/15 19:44:56 Elevation:  -0.0
Set Time:     03/08/15 19:44:56 Azimuth:   342.9

YUBILEINY (RS-30)
5115 seconds until the next pass.
Rise Time:    03/08/15 19:51:28 Azimuth:   279.5
Transit Time: 03/08/15 19:57:25 Elevation:   3.7
Set Time:     03/08/15 20:03:21 Azimuth:   342.8

TRITON-1
5411 seconds until the next pass.
Rise Time:    03/08/15 19:56:24 Azimuth:    92.7
Transit Time: 03/08/15 20:00:09 Elevation:   3.9
Set Time:     03/08/15 20:03:54 Azimuth:    25.1

UOSAT 2 (UO-11)
6509 seconds until the next pass.
Rise Time:    03/08/15 20:14:43 Azimuth:    95.0
Transit Time: 03/08/15 20:18:33 Elevation:   4.5
Set Time:     03/08/15 20:22:23 Azimuth:    22.8

SEEDS II (CO-66)
6557 seconds until the next pass.
Rise Time:    03/08/15 20:15:30 Azimuth:   127.3
Transit Time: 03/08/15 20:21:07 Elevation:  16.4
Set Time:     03/08/15 20:26:43 Azimuth:     6.7

UWE-3
6694 seconds until the next pass.
Rise Time:    03/08/15 20:17:48 Azimuth:    76.8
Transit Time: 03/08/15 20:20:03 Elevation:   1.3
Set Time:     03/08/15 20:22:18 Azimuth:    35.9

RADIO ROSTO (RS-15)
7326 seconds until the next pass.
Rise Time:    03/08/15 20:28:20 Azimuth:   128.2
Transit Time: 03/08/15 20:36:14 Elevation:   6.0
Set Time:     03/08/15 20:44:09 Azimuth:    56.8

GOMX 1
7721 seconds until the next pass.
Rise Time:    03/08/15 20:34:55 Azimuth:   139.6
Transit Time: 03/08/15 20:41:44 Elevation:  28.3
Set Time:     03/08/15 20:48:33 Azimuth:     0.7

CUBEBUG-2 (LO-74)
9556 seconds until the next pass.
Rise Time:    03/08/15 21:05:29 Azimuth:   126.2
Transit Time: 03/08/15 21:11:12 Elevation:  15.9
Set Time:     03/08/15 21:16:56 Azimuth:     7.5

VELOX-PII
9914 seconds until the next pass.
Rise Time:    03/08/15 21:11:28 Azimuth:   125.2
Transit Time: 03/08/15 21:17:05 Elevation:  15.3
Set Time:     03/08/15 21:22:43 Azimuth:     8.0

FUNCUBE-1 (AO-73)
9936 seconds until the next pass.
Rise Time:    03/08/15 21:11:49 Azimuth:   118.8
Transit Time: 03/08/15 21:17:04 Elevation:  11.9
Set Time:     03/08/15 21:22:20 Azimuth:    11.1

ZACUBE-1 (TSHEPISOSAT)
10153 seconds until the next pass.
Rise Time:    03/08/15 21:15:26 Azimuth:   121.9
Transit Time: 03/08/15 21:20:52 Elevation:  13.4
Set Time:     03/08/15 21:26:17 Azimuth:     9.6

DELFI-C3 (DO-64)
11107 seconds until the next pass.
Rise Time:    03/08/15 21:31:21 Azimuth:   142.9
Transit Time: 03/08/15 21:37:20 Elevation:  29.2
Set Time:     03/08/15 21:43:19 Azimuth:   359.6

HUMSAT-D
12799 seconds until the next pass.
Rise Time:    03/08/15 21:59:32 Azimuth:   133.5
Transit Time: 03/08/15 22:05:21 Elevation:  20.4
Set Time:     03/08/15 22:11:09 Azimuth:     4.0

EAGLE 2
13942 seconds until the next pass.
Rise Time:    03/08/15 22:18:36 Azimuth:   136.2
Transit Time: 03/08/15 22:24:17 Elevation:  22.0
Set Time:     03/08/15 22:29:58 Azimuth:     3.0

CUBEBUG-1 (CAPITAN BETO)
15152 seconds until the next pass.
Rise Time:    03/08/15 22:38:45 Azimuth:   129.1
Transit Time: 03/08/15 22:44:45 Elevation:  18.7
Set Time:     03/08/15 22:50:44 Azimuth:     4.6

SPROUT
15611 seconds until the next pass.
Rise Time:    03/08/15 22:46:24 Azimuth:    92.6
Transit Time: 03/08/15 22:50:05 Elevation:   4.0
Set Time:     03/08/15 22:53:46 Azimuth:    24.0

JUGNU
16144 seconds until the next pass.
Rise Time:    03/08/15 22:55:18 Azimuth:   204.1
Transit Time: 03/08/15 23:00:40 Elevation:   6.1
Set Time:     03/08/15 23:06:02 Azimuth:   124.2

DUCHIFAT-1
16575 seconds until the next pass.
Rise Time:    03/08/15 23:02:29 Azimuth:    35.0
Transit Time: 03/08/15 23:07:53 Elevation:  12.7
Set Time:     03/08/15 23:13:17 Azimuth:   148.7

SRMSAT
17209 seconds until the next pass.
Rise Time:    03/08/15 23:13:03 Azimuth:   176.4
Transit Time: 03/08/15 23:15:40 Elevation:   1.1
Set Time:     03/08/15 23:18:17 Azimuth:   139.8

SWISSCUBE
18892 seconds until the next pass.
Rise Time:    03/08/15 23:41:05 Azimuth:    73.7
Transit Time: 03/08/15 23:43:37 Elevation:   1.4
Set Time:     03/08/15 23:46:09 Azimuth:    31.4

SAUDISAT 1C (SO-50)
19177 seconds until the next pass.
Rise Time:    03/08/15 23:45:51 Azimuth:   170.5
Transit Time: 03/08/15 23:52:00 Elevation:  17.7
Set Time:     03/08/15 23:58:10 Azimuth:    47.9

BEESAT
19303 seconds until the next pass.
Rise Time:    03/08/15 23:47:57 Azimuth:    77.8
Transit Time: 03/08/15 23:50:51 Elevation:   2.0
Set Time:     03/08/15 23:53:45 Azimuth:    28.8

TISAT 1
19890 seconds until the next pass.
Rise Time:    03/08/15 23:57:44 Azimuth:   141.2
Transit Time: 03/09/15 00:03:57 Elevation:  28.7
Set Time:     03/09/15 00:10:10 Azimuth:   359.5

ITUPSAT 1
21056 seconds until the next pass.
Rise Time:    03/09/15 00:17:09 Azimuth:   104.3
Transit Time: 03/09/15 00:22:11 Elevation:   8.1
Set Time:     03/09/15 00:27:12 Azimuth:    14.2

KKS-1 (KISEKI)
24703 seconds until the next pass.
Rise Time:    03/09/15 01:17:56 Azimuth:    96.4
Transit Time: 03/09/15 01:22:04 Elevation:   5.2
Set Time:     03/09/15 01:26:12 Azimuth:    20.4

LUSAT (LO-19)
25871 seconds until the next pass.
Rise Time:    03/09/15 01:37:24 Azimuth:    29.2
Transit Time: 03/09/15 01:44:13 Elevation:  20.0
Set Time:     03/09/15 01:51:01 Azimuth:   157.9

ITAMSAT (IO-26)
26776 seconds until the next pass.
Rise Time:    03/09/15 01:52:30 Azimuth:    42.8
Transit Time: 03/09/15 01:57:50 Elevation:   7.6
Set Time:     03/09/15 02:03:10 Azimuth:   133.0

TECHSAT 1B (GO-32)
27579 seconds until the next pass.
Rise Time:    03/09/15 02:05:52 Azimuth:    41.3
Transit Time: 03/09/15 02:11:26 Elevation:   8.3
Set Time:     03/09/15 02:17:00 Azimuth:   134.4

HORYU 2
31680 seconds until the next pass.
Rise Time:    03/09/15 03:14:13 Azimuth:    41.7
Transit Time: 03/09/15 03:19:13 Elevation:   8.3
Set Time:     03/09/15 03:24:13 Azimuth:   137.6

ISS (ZARYA)
38130 seconds until the next pass.
Rise Time:    03/09/15 05:01:43 Azimuth:   115.2
Transit Time: 03/09/15 04:15:25 Elevation: -74.9
Set Time:     03/09/15 05:01:43 Azimuth:   115.2

Addendum3: Hmm. If you look carefully, the last entry in the test output is bogus: the time of maximum elevation does not fall between the rise and set time, and the elevation is negative. Staring at the code some more, I’m now worried about the logic of the root finder. I’ll have to ponder it some more.

Old Radio Publications available online…

March 4, 2015 | Amateur Radio | By: Mark VandeWettering

I like reading old books and old magazines. Luckily, the Internet is making a lot of that kind of material available online for free. A couple of quick links to some items I’ve found recently on the subject of amateur radio:

  • Radio News was published from 1919 to 1959. PDF scans of every issue are available.
  • 73 Magazine may be more familiar to many more hams. It was published from 1960 until 2003. Its founder Wayne Green, W2NSD often wrote editorials critical of the American Radio Relay League, and therefore provides an interesting contrast to the ARRL’s QST magazine.
  • QST is the publication of the ARRL. Their archives are also available, but only to members of the society (one of the primary reasons that I continue to be a member).

Lots of reading for the radio amateur.

A Big Bin Full O’ Development Boards at BrainWagon Labs…

March 1, 2015 | Arduino, Atmel AVR, Hardware, My Projects, Raspberry Pi | By: Mark VandeWettering

I have an odd obsession with small, relatively cheap hardware development boards. Over the last few years, I’ve acquired a bunch of them, from Arduino to Raspberry Pi to BeagleBone Black. I thought it might be nice to just do a short video showing what I have around. So I did. Here’s a little 25 minute video demoing what I’ve got lying around.

Here’s a bunch of links to some of the boards I mentioned:

  • Arduino, the classic board. Based upon the ATMEGA328, an 8 bit processor, 32K of flash, 20Mhz. Great user community.
  • Beagle Bone Black Very cool Linux based machine.
  • Raspberry Pi Perhaps my favorite board, I don’t have the version 2 board yet, but the version B+ boards are really nice. I particularly like the Pi Camera boards you can use with them.
  • WRTNode A very cool, very cheap Linux box, with WiFi. Runs OpenWRT, a stripped down version of Linux, but still cool.
  • Wild Fire board A very nifty little board by Wicked Devices, who supplied me with a couple. During the video, I mentioned that I thought these boards were a bit expensive, but checking their website, I see them selling for about $49. If you need an Arduino compatible board with some extra punch, it’s a great little board.
  • ESP8266 The tiniest and cheapest board that I had. Often used as simple serial->WiFi chips, they are actually quite powerful and can be reprogrammed. This lua based firmware is a cool example.

Task completed: Evil Mad Science ISP Shield soldered together…

February 24, 2015 | Arduino | By: Mark VandeWettering

Last night, the absent-far-too-often urge to fire up the soldering iron and make something hit me, so I warmed up the Weller and did this:


I bought this kit quite a while ago, and it has been sitting on the shelf mocking me for a long time. It’s available from Evil Mad Science for a reasonable $13 or so, and is a very easy kit to assemble, consisting of a crystal, three caps, and seven resistors, plus some headers. My soldering skills are a bit rusty, but it wasn’t difficult, I had it done in a leisurely 40 minutes or so, including my hunt for some bare ATMEGA328s that I had stashed in a box somewhere.Arduino ISP Shield

If you aren’t really up on this, you might ask “okay, what does it do?”

Long time readers of my blog may remember that I had previously used an Arduino as a programmer, in that case to program some small 8 pin Atmel chips like the ATTINY13 or ATTINY85. These chips are too small to use the regular boot loader that is common on the ATMega328 chips that are used on the Arduino, so you need to use the ISP (or In System Programming) method to get software onto the chip. If you want to program the Arduino bootloader onto a bare ATMega328 chip, or write software directly to such a chip, you also need to use the ISP interface. If you have a breadboard, you can pretty easily set up the programmer, but it’s a little inconvenient: I have to look up all the right jumper wires, double check them, maybe wire up a crystal oscillator, it’s just not fun. Hence, this shield. You plug it into an Arduino (I used one of my oldest Arduino Duielfoovena, whatever that word is) and flash the AVRISP sketch that comees with the Arduino software, and voila, you are ready to program. It has a nice ZIF (zero insertion force) socket, which allows you to insert your 28 pin DIP (either a ATMega328 or ATMega168) and has four LEDs that can serve as status indicators. If you want to burn a bootloader onto a chip, you select the “Arduino as ISP” Programmer type, and then tell it to burn the bootloader. Voila!

The ISP also includes the classic six pin header that you can use to jumper to any Atmel board that provides such a header, and you can program the chip inside the system, including non-DIP versions.

So, why would you want to do this?

Well, you can build your own Arduino compatible boards now, for much less than what you would typically pay (although, perhaps not cheaper than you could pay getting them from China). A bare ATMega328 costs about $3.50, which isn’t super cheap, but it won’t break the bank either. Add in a little 5v or 3.3v regulator, two caps and a crystal, and for less than 5 dollars in parts you can put together a homebrew microcontroller than you can program with the Arduino environment. Pretty useful if, say, you wanted to embed a little microcontroller in a radio project you wanted to try.

Apologies for the long gap between posts. I’ve got more stuff in mind, I’ll try to get back to doing more stuff and blogging more stuff.

Another bit of programmable hardware: the WRTnode

January 2, 2015 | Computer Science, Hardware, Internet of Things, My Projects, Operating Systems, Raspberry Pi | By: Mark VandeWettering

I’ve got a weak spot for cheap, programmable hardware. In my junk drawer I’ve got a collection of Arduinos, Parallax Propellor boards, a couple of STM32 based ARM boards, and several Beagle Bone Blacks and Raspberry Pis. Today, another entry arrived: the WRTnode.

I’ve only had it out of the box for a few hours, and a little bit of tinkering, but here are my initial impressions.

WRTnodeA few basics first: it’s a small, cheap Linux computer. Nominally, the list price is supposed to be $25, but I ordered mine via the Amazon store and paid a bit of a premium: it cost $35, but shipped in two days via Amazon Prime. It comes in a small plastic box the size of an Altoids tin, and includes a little USB cable that allows you to chain an extra USB device to it, as well as provide power. I plugged mine into a little D-Link USB hub I had lying around. Seems to work fine.

In terms of capability, it falls somewhere between the Arduino and a Raspberry Pi. The processor is actually not ARM based, it’s an MTK MT7620N MIPS processor that runs at 580Mhz. It has a 512Mbit DDR2 RAM and 128Mbit of SPI flash ROM. This is quite a bit less than the Raspberry Pi, but it does have one cool added feature: it’s got a 300Mbit wireless networking chip on board which can do 802.11n. It also can handle USB host mode. Basically, you can think of this as the brains to a fairly reasonable wireless router. It’s a very small board, only 45mm x 50mm, and includes 23 GPIO pins, as well as JTAG and SPI.

Because of it’s rather limited memory, it can’t run full Debian. Instead, it runs the OpenWRT distribution, a small distribution which is often used on tiny embedded boxes that serve as routers. It runs BusyBox, has the tiny shell “ash”, as well as the LuCI web based configuration interface, which is based upon the uhttpd webserver.

Setting it up was pretty darned easy: I plugged the supplied USB cable into it, and the other end into my powered hub. A small blue LED comes on, and about 20 seconds later, a new wireless access point was visible called WRTnode9DDB. If you attach to that network, you are asked for a network password, which defaults to 12345678, and then you can telnet to the device, which defaults to IP address 192.168.8.1. You can login as root with no password. If you run passwd you can enter a new password, and then you can use ssh to connect to it.

Screen Shot 2015-01-02 at 9.14.47 PM

Nifty! If you cat /proc/cpuinfo you can get information about the processor:

system type		: Ralink MT7620N ver:2 eco:6
machine			: WRTNODE
processor		: 0
cpu model		: MIPS 24KEc V5.0
BogoMIPS		: 398.13
wait instruction	: yes
microsecond timers	: yes
tlb_entries		: 32
extra interrupt vector	: yes
hardware watchpoint	: yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
isa			: mips1 mips2 mips32r1 mips32r2
ASEs implemented	: mips16 dsp
shadow register sets	: 1
kscratch registers	: 0
core			: 0
VCED exceptions		: not available
VCEI exceptions		: not available

and ditto for cat /proc/meminfo:

MemTotal:          61852 kB
MemFree:           22516 kB
Buffers:            4828 kB
Cached:            17928 kB
SwapCached:            0 kB
Active:            14292 kB
Inactive:          10744 kB
Active(anon):       3772 kB
Inactive(anon):       76 kB
Active(file):      10520 kB
Inactive(file):    10668 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:          2296 kB
Mapped:             1960 kB
Shmem:              1568 kB
Slab:               6028 kB
SReclaimable:       1784 kB
SUnreclaim:         4244 kB
KernelStack:         296 kB
PageTables:          292 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:       30924 kB
Committed_AS:       6948 kB
VmallocTotal:    1048372 kB
VmallocUsed:        2204 kB
VmallocChunk:    1032516 kB

OpenWRT isn’t as full featured as some Linux distributions, but it’s not bad. It includes ssh, Python and Lua. It’s got vi. It runs its own small package manager called opkg, which has a pretty good selection of precompiled packages available for install (although its good to be careful, you don’t have an infinite amount of space). Scanning the list, it’s got installation packages for lighttpd, Asterix, and a bunch of other goodies.

I haven’t had a lot of time to mess with it, but I’m fairly impressed so far. I have a feeling I’m going to miss having a C compiler/make setup on the board, but it looks to be pretty simple to cross compile to it from my main Linux box. I have already rebuilt the distribution, and will probably try flashing it sometime soon.

If you are in the market for a little machine with features like this (esp. with WiFi), it might be worth it.

Ship in a Bottle: Traditional vs. “Modern” method…

December 22, 2014 | Ship In a Bottle | By: Mark VandeWettering

Every since I was a young lad, I’ve been fascinated by miniatures and model building. Like many of my obsessions, I did more reading than actual constructing. In particular, I remember reading several books about building “ships in a bottle”, and for some reason, this particular interest has cycled around and is again at the top of my brain. Since I have some vacation coming up over the holiday, I thought that maybe I’d give it a whirl, and see how well I can do.

But of course, all I’ve done so far is just reading and research.

Oddly enough, there doesn’t seem to be a huge amount of information on the web. Sure, you can find some pictures, and even a video or two, and some instructables, but compared to many other endeavors, the information and instruction seem a bit thin. Part of this is no doubt that this is due to the subject matter itself: many traditional crafts aren’t as well represented on the Internet as other, more modern activities. Still, it carries over into other media as well: the number of books dedicated to building ships in a bottle are quite limited as well. And, while there are several national organizations for ship building, they seem rather cagey about what it is they do.

One is no doubt some carry over from the “secret knowledge” that so-called Impossible Bottles are shrouded in. While it isn’t too hard to get some basic description about how ships in a bottle are made, in general it is considered rude to reveal the secrets of putting stuff in bottles. It just doesn’t seem to be a community that revels in sharing techniques.

But anyway…

The traditional scheme of putting sailing ships in bottles consists of the following elements:

  • the model is constructed outside the bottle, with the masts hinged to fold back along the bottle
  • square sails are generally mounted on the spars, and twisted to lie parallel to the masts so they can fold around the body
  • spankers and jibs are mounted loosely on strings that can be pulled to be drawn into their final position
  • the model is folded flat, and is inserted tailfirst into the bottle
  • once inside the bottle, the various strings are drawn tight to pull up the masts on their hinges, and others draw the spankers and jibs into place.
  • once everything looks nice, small drops of glue are used to fix the threads in place, and the excess can be cut off with tiny bits of razor blade on a long wire

Some visuals will help. Here’s the traditional method demonstrated, which gives some hint as to the complexity.

Seems straightforward enough, if not exactly easy. But I was wondering: are all ships in a bottle done this way? The existance of other “impossible” bottles shows that many things can be disassembled and reassembled in bottles using techniques that are rather different than this scheme. Are other techniques used?

The answer is “yes”. For instance, many ships have hulls which are too large to fit through the bottle’s spout. These are sometimes created in layers, which are inserted one by one into the bottle and glued into place, with a rather thin “deck” which holds all that traditional masting. But, I wondered, couldn’t all the rest be assembled outside in pieces and inserted through the neck? Are these kind of techniques being used?

The answer is “yes”, while the traditional method is far and away the most popular, there are model makers who use other, “modern” methods to build ships in a bottle, but descriptions of the techniques they use are rather sparse. The first I encountered was this page by Ralph W. Preston on the “Modern Method”. He writes:

Towards the end of the Great Depression, a new approach to building ships in bottles appeared. This new approach is one that I call the “modern” method. By this method the ship is disassembled outside, then reassembled within. Long tweezers and similar tools are used. I am a member of the modern school. It would be tempting to say that my method is better, but much traditional work of superb quality is around.

He doesn’t seem to enumerate the principles he uses, but he does have some intriguing information as part of the documentation of various works he created. His Viking ship shows some of his “non-traditional” techniques at work.

Cool stuff, but it didn’t tell me the information that I wanted.

Artem Potem has this webpage, somewhat clumsily translated from Russian to English that talks about other techniques that could be used. For instance, his Method 3 eliminates the need for a mast hinge, which could be interesting.

The only other bit of innovation I found was this Youtube video (sadly, in Portuguese, I think) which shows assembly of a ship using something like what I expect Potem was describing. The ship is actually inserted bow first, and the masts are loose,,, Very nice ship model, and some great photography.


I’m prepping a more lengthy set of links and resources, which should show up in the next week or so.

Addendum:

Here’s another “bowfirst” construction video, this one of the HMS Beagle…