Ikea DIODER custom controller

Like lots of folks on the internet, I saw the DIODER and felt that it could be improved. And what better way than to make it internet-controlled? Given that I had a Nanode lying around looking for a use it seemed like providence.

Finished DIODER controller

So the plan was this:

  • Instead of just cycling between some gaudy colours, lets pick some classier ones
  • Let’s allow the colours to be updated via the web, saving them to EEPROM
  • Using 1D Perlin noise to blend between a pair of colours will allow for pleasing fades and far more interest than just transitioning from A->B (so much interest that it turned out 2 colours is all it needs … for now)
  • Use HSL colour space for super-classy fading
And here’s the code that does all that: rgb.pde.
The hardware side was pretty straightforward – a MOSFET (Stp36nf06l) per channel to buffer the output from the microcontroller (the LEDs run at 12v). I just used the 12v adaptor that came with the DIODER, and ditched the Ikea controller and little junction box thingy. I did add a switch to kick the ethernet chip into a low power mode (because it saves ~350mA and it was easy :))

 

closeup of the controller board
It took a while to figure out the HSL colour space, so here’s what I ended up with:
// based on http://www.dipzo.com/wordpress/?p=50
void hslToRgb( int hue, byte sat, byte light, byte* lpOutRgb )
{
  if( sat == 0 )
  {
    lpOutRgb[0] = lpOutRgb[1] = lpOutRgb[2] = light;
    return;
  }

  float nhue   = (float)hue * (1.0f / 360.0f);
  float nsat   = (float)sat * (1.0f / 255.0f);
  float nlight = (float)light * (1.0f / 255.0f);

  float m2;
  if( light < 128 )
    m2 = nlight * ( 1.0f + nsat );
  else
    m2 = ( nlight + nsat ) - ( nsat * nlight );

  float m1 = ( 2.0f * nlight ) - m2;

  lpOutRgb[0] = hueToChannel( m1, m2, nhue + (1.0f / 3.0f) );
  lpOutRgb[1] = hueToChannel( m1, m2, nhue );
  lpOutRgb[2] = hueToChannel( m1, m2, nhue - (1.0f / 3.0f) );
}

byte hueToChannel( float m1, float m2, float h )
{
  float channel = hueToChannelInternal( m1, m2, h );
  byte  uchan   = (byte)(255.0f * channel);
  return uchan;
}

float hueToChannelInternal( float m1, float m2, float h )
{
   if( h < 0.0f ) h += 1.0f;
   if( h > 1.0f ) h -= 1.0f;

   if( ( 6.0f * h ) < 1.0f )  return ( m1 + ( m2 - m1 ) * 6.0f * h );
   if( ( 2.0f * h ) < 1.0f )  return m2;
   if( ( 3.0f * h ) < 2.0f )  return ( m1 + ( m2 - m1 ) * ((2.0f/3.0f) - h) * 6.0f );
   return m1;
}

I also experimented with adding a gamma curve to the output, but while it definitely improved colour matching, it made fading a lot more jerky, so I didn’t go with it in the end.

Once I had reliable HSL->RGB working, I needed a good HSL interpolate function. That took some effort. I found you can use a straight linear interpolate on the S & L channels, but you need a custom one for the Hue channel as it needs to pick the shortest way to go around the circle. I also wrote it all to treat the interpolation parameter as a value from 0 to 1 in 0.8 fixed point format. This is how it looks:

void lerpHsl( const int* a, const int* b, byte t, int* lpOutHsl )
{
  lpOutHsl[0] = lerpHueFp8( a[0], b[0], t );
  lpOutHsl[1] = lerpFp8( a[1], b[1], t );
  lpOutHsl[2] = lerpFp8( a[2], b[2], t );
}

int lerpFp8( int a, int b, byte t )
{
  long t0 = ( b - a ) * t;
  return ( a + ( t0 >> 8 ) );
}

int lerpHueFp8( int a, int b, byte t )
{  
  // adjust inputs so we take the shortest route around the circle
  int cwdist = b - a;
  if( abs(cwdist) > 180 )
  {
    if( b > a )  a += 360;
    else         b += 360;
  }

  long t0 = ( b - a ) * t;
  int l = a + (t0 >> 8);

  return ( l % 360 );
}

The last colour-related piece was to get a good 1D Perlin noise-like function. After some googling failed to turn up a nice implementation for Arduino, I built this, based on Hugo Elias’ great page here.

#define kPerlinOctaves      3
static const float kaPerlinOctaveAmplitude[kPerlinOctaves] =
{
  0.75f, 0.4f, 0.1f,
};

float perlinNoise1( long x )
{
  x = ( x<<13 ) ^ x;
  return ( 1.0f - ( (x * (x * x * 15731 + 789221L) + 1376312589L) & 0x7fffffff) * (1.0f / 1073741824.0f) );
}

float perlinSmoothedNoise1( long x )
{
  return perlinNoise1(x)*0.5f
       + perlinNoise1(x-1)*0.25f
       + perlinNoise1(x+1)*0.25f;
}

float perlinLerpedNoise1( float x )
{
  long  xInteger  = long(x);
  float xFraction = x - xInteger;

  float v1 = perlinSmoothedNoise1( xInteger );
  float v2 = perlinSmoothedNoise1( xInteger + 1 );

  return lerpFloat( v1, v2, xFraction );
}

float perlinNoise1D( float x )
{
  float total = 0.0f;

  for( int octave = 0; octave < kPerlinOctaves; octave++ )
  {
    int   frequency = 1 << octave;
    float amplitude = kaPerlinOctaveAmplitude[octave];

    total += perlinLerpedNoise1( x * frequency ) * amplitude;
  }

  // map from [-1,1] to [0,1] and constrain
  return constrain( (total + 1.0f) * 0.5f, 0.0f, 1.0f );
}

This generates the following output, which looks pretty sweet when used as the interpolation parameter

With that, all of the RGB LED controlling was done :)

For the web interface, I used the excellent EtherCard library, which made it super-easy.

 

Job done*!

 

*actually, I still need to build a nice jQuery’d webpage to make setting colours easier. Currently I need to go to http://192.168.1.25/hsl?i=0&h=135&s=90&l=50, which isn’t exactly as futuristic as I’d like :)

nanode liiiives!

My FTDI cable arrived today!

The nanode I built says this:

DHCP Client test
0:4:A3:2C:28:AE
Init ENC28J60
Init done
ENC28J60 version 7
Requesting IP Addresse
My IP: 192.168.1.69
Netmask: 255.255.255.0
DNS IP: 192.168.1.254
GW IP: 192.168.1.254

w00t :)

Now I can get on and make … something … with it!

Brighton Mini Maker Faire

Maker Faire came to Brighton!

Spent a very happy hour marvelling at all the amazing things people had made. Awesome :)

Loads more pics and videos here: makerfairebrighton.tumblr.com

more procedural cities

(continued from here)

I’ve been tweaking the secondary road generation (adding things like crossroads), and now I’ve got cities that look like this:

Next up: start looking at tertiary roads and building generation.

I’d love to start having curved roads and rivers in there too, but they’ll have to wait!

was the weather this summer really that lame?

The weather in London this summer seems to have been spectacular in its mediocrity. After an exciting looking start with a really warm May, it turned cold and damp and seems to have stayed that way.

I felt cheated.

But! How bad was this summer in comparison to history? I couldn’t find out anything on the internets to tell me, but I did find tutiempo.net which seemed to have loads of historical weather data. So I cracked out Beautiful Soup and made me a scraper: climatescraper.py

The way I have it set up, it downloads all the weather data for London Heathrow from 1949 to now (excluding the years around the 60s as they all seem to be missing). It then saves the data to a little “database” (alright, it’s just a pickled python dictionary, but that’s because pickling is so easy!)

Now I have all this data, I can render it. For instance, here’s the average daily temperature for each day (this image brought to you by render.py):

As you can see, we haven’t been stiffed. The weather in London is just stunningly mediocre.

If you want to try this for another location, download these scripts and customise the sections at the top for your chosen location. You’ll probably want to tweak which years it downloads as well or you’ll end up with lots of unknown data… You’ll need Beautiful Soup for the scraper and the Python Imaging Library to render the images.

playing with procedural cities

Procedural worlds are awesome. I started playing with Processing and making some!

Unfortunately, Processing is based on Java which doesn’t have operator overloading. Ordinarily I’d be fine with that, but this is gonna get mathsy, so I switched to Cinder, which is C++. After a mercifully swift porting effort, we were back up:

It’s a promising start, but it’s way too rectilinear. I’m going to have to back up and look at generating a road network before anything’s going to look much better. After playing a bit, I found that a random Voronoi diagram seems to give me a nice starting point for the major zoning of a city:

Going beyond a voronoi diagram seems pretty gnarly though :(

I started collecting some reference: byjingo.tumblr.com. Now I have some ideas on what might work, I started playing:

There’s clearly still a lot of work to be done!

To be continued…

digital clock

I saw this cool clock by Jonas Damon in magma:

However, I didn’t like that the digits had wires between them. This is the 21st century etc. So I set out to make my own version where each digit was completely independent.

Cracking out the trusty Arduino, I soon had a single digit…

While I could have carried on and purchased another 3 Arduini, that would have been a bit flash, and these digits needed to be battery powered (or the no wires thing wouldn’t work). After some digging, I plumped for using the ATtiny2313V as they’re nice and low voltage (and crucially cheap). Using the Arduino to flash the firmware onto the new chip, I soon had my first independent digit!

Things got a bit Matrix and it went into replication…

Then I used some super-expensive circuit layout software to plan the schematic (I built it on Tri-Pad board, hence the groups of 3 connected holes). I also ventured into the realms of sticking stuff on the back of the board for the first time – that’s what the bits in red are.

With that, it was all done bar days of soldering and manufacturing.

The 8 rechargeable, Lithium Ion batteries (costing as much as the entire rest of the build) last about 2 months. It’s well worth the hassle of 6 recharges per year :)

The firmware is available here: avr-clock.c and Makefile