General > General Technical Chat

Say a weekend project idea, something nice to build

(1/13) > >>

RoGeorge:
What would that be?

Nominal Animal:
A fire.

No, really.  Fry some sausages or marshmallows, look at the fire, and relax.

MK14:
Connect together a set of suitable LEDs, and your favorite/in-stock microcontroller board, to make a relaxing and pleasant fire simulator, flashing pattern.

For Inspiration:






Zeyneb:
Maybe your car needs an oil change, how about DIY?

EDIT: I think MK14s post would be more suitable for the Southern Hemisphere citizens at this time.

Nominal Animal:
If you have WS2812 or similar programmable RGB leds, and a microcontroller with N×M×2+768 bytes of RAM, you can do some really nice fire and plasma effects.

The idea is that you use a good pseudorandom number generator as a seed in suitable cells.  I recommend using the 32 or 40 high bits of Xorshift64*, e.g.

--- Code: ---#include <stdint.h>

// Any nonzero 64-bit seed will work; randomize it!
uint64_t  prng_state = 1;

// Cache for 8-bit pseudorandom numbers.
uint8_t   prng_cache[4];
uint8_t   prng_cached = 0;

// Obtain a random number between 0 and 255.
uint8_t   prng_u8(void)
{
    if (prng_cached > 0)
        return prng_cache[--prng_cached];

    uint64_t  x = prng_state;
    x ^= x >> 12;
    x ^= x << 25;
    x ^= x >> 27;
    prng_state = x;

    x = (x * UINT64_C(2685821657736338717)) >> 24;

    prng_cache[0] = x;
    prng_cache[1] = x >> 8;
    prng_cache[2] = x >> 16;
    prng_cache[3] = x >> 24;
    prng_cached   = 4;

    return x >> 32;
}

--- End code ---
You declare two buffers and an RGB look-up table:

--- Code: ---#define  N  //rows, vertical
#define  M  //columns, horizontal

typedef struct {
    uint8_t  cell [N][M];
} grid;

grid  g[2];

uint8_t  rgb[256][3];

--- End code ---
For each inner cell, you apply a 3×3 kernel, centered on the cell, with the weights summing to 257 (or less if you want dimming).

--- Code: ---const uint8_t  kernel[3][3] = { ... };

void apply(grid *const dst, grid *const src, const uint8_t flicker, const uint8_t bias)
{
    const uint_fast16_t  cmin =  (uint_fast16_t)flicker * (uint_fast16_t)bias;
    const uint_fast16_t  cmax = (uint16_t)( -(uint_fast16_t)flicker * (uint_fast16_t)(255 - bias) );

    for (uint_fast8_t n = 1; n < N-1; n++) {
        for (uint_fast8_t m = 1; m < M-1; m++) {
            uint16_t c = (uint_fast16_t)(kernel[ 0 ][ 0 ]) * (uint_fast16_t)(src->cell[ n-1 ][ m-1 ])
                       + (uint_fast16_t)(kernel[ 0 ][ 1 ]) * (uint_fast16_t)(src->cell[ n-1 ][ m   ])
                       + (uint_fast16_t)(kernel[ 0 ][ 2 ]) * (uint_fast16_t)(src->cell[ n-1 ][ m+1 ])
                       + (uint_fast16_t)(kernel[ 1 ][ 0 ]) * (uint_fast16_t)(src->cell[ n   ][ m-1 ])
                       + (uint_fast16_t)(kernel[ 1 ][ 1 ]) * (uint_fast16_t)(src->cell[ n   ][ m   ])
                       + (uint_fast16_t)(kernel[ 1 ][ 2 ]) * (uint_fast16_t)(src->cell[ n   ][ m+1 ])
                       + (uint_fast16_t)(kernel[ 2 ][ 0 ]) * (uint_fast16_t)(src->cell[ n+1 ][ m-1 ])
                       + (uint_fast16_t)(kernel[ 2 ][ 1 ]) * (uint_fast16_t)(src->cell[ n+1 ][ m   ])
                       + (uint_fast16_t)(kernel[ 2 ][ 2 ]) * (uint_fast16_t)(src->cell[ n+1 ][ m+1 ])
                       ;
            if (c >= cmin && c <= cmax) {
                c = c - cmin + prng_u8() * uint_fast16_t)flicker;
            }
            dst->cell[n][m] = c >> 8;
        }
    }
}

--- End code ---
You need two grids,
    grid g, gtemp;
Initialize the main one to all zeros, set the seed cell values using the prng_u8() function, and apply the kernel twice,
    apply(gtemp, g, 0, 128);
    apply(g, gtemp, 0, 128);
The flicker term is how much randomness is added to each cell, and bias is whether it tends to increase (<128) or decrease (>128) the cell value.

Now you have the updated state in the main grid, and you can sample specific cells for your RGB LEDs, using the RGB look-up table rgb[g.cell[row][column]][0..2] for red, green, and blue components for that LED, respectively.  You can also do a number of apply() rounds before updating the LEDs.

My favourite is using a regular triangular grid for the LEDs, with relatively large grids.

If you use a RAM-based kernel, you can adjust it in real time, skewing it to a side, creating changing "draft".  Bias it completely towards one side to get drifting plasma/fire.

The possibilities are very nearly limitless, and it is easy to get going and some nice results, while genuine-looking fire takes careful tuning and experimentation.  :-+

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod