self-organizing systems with many picAXEs

AlC

Member
Hi all,

I've been reading something over at instructables that triggered my interest: an array of LEDs simulating the self-organizing behaviour of a swarm of blinking fireflies. The LEDs start out by emitting random flashes of light, but with time they synchronize to each other and finally they all blink synchronized (each of the LEDs has a small Atiny12 and a light-dependent resistor) Since I like the idea I want to copy this with several picAXE08 (I don't like atmel chips since I can't write code for them).

But before going out and buying a whole bunch of picaxe08, I thought I'd like to have some opinions on the software I wrote for it - specifically my fears are that the individual "fireflies"/circuits will not differ enough in their initial delay before they start their blink'n sync adventures..

I've tried to fill a word variable with "random" value and then use only 1 byte of that, can anyone have a look at the code please and tell me what they think - will this cause the fireflies initial (still unsynchronized) behaviour to be "individual" enough, or will the more or less all start at the same time?

Will the program work at all?

thanks

heres my code

Code:
; *** FIREFLY.BAS  ************ Version 1.0 beta *******  SELF-SYNCHRONIZING NETWORK OF LED FIREFLIES  ***
; this program is intended for simulation of a swarm of fireflies by many individually controlled LEDs, designed
; to run on a PICaxe08 with a LDR connected to pin 1  and one LED wired to pin 2 (each firefly needs one PICaxe)
; Since they are totally independent besides of sharing the same reset switch, one can easily combine any number of 
; fireflies to form a large array of blinking, self-organizing LEDs...  pressing the "reset" switch will of course disturb 
; the fireflies and their uniform blinking pattern, like walking right into a swarm would disturb real blinking fireflies too, 
; probably, and it takes awhile before they start blinking and syncing again...
; --------------------------------------------------------------------------------------------------------------------------------------------------
; Copyright (c) 15/05/2009 
; Dennis Schulze

; variables
symbol Power = w4               ;determines how urgently the firefly wants to pulse or how hard it "desires" to do so 
symbol Brightness=b2          ;this later contains the reading of the LDR value
symbol Ambient =b3             ;initial ambient light intensity value is stored here for comparison reasons
symbol BlinkCounter =  b4    ;Counter needed for initialisation blinking loop
symbol RndDelay = b1          ;this will be seeded with a random number for individual delay time

; constants
symbol Daylight=195              ; above this light intensity threshold the firefly does not glow at all (i.e. if its not "night")
symbol MaxPower = 80        ; Urgency threshold that triggers an immediate pulse

;counters
let BlinkCounter = 1                ;reset all counters
let Power = 1			;


;randomize a bit to give individuality
random w0                          ;generate "random" 16bit number (hopefully differing enough between individual PICaxe ICs)..
let RndDelay = b1 * 24        ;take the last 8bit of it and multiply by 24 to give several seconds delay at most


; initialisation blinking loop
for BlinkCounter = 1 to 5    ; blink five times
	gosub pulse
	pause 700
	BlinkCounter = BlinkCounter + 1
next BlinkCounter	




 pause 1500                            ; wait long enough to make sure that absolutely NO firefly is blinking at the moment
readadc 1, Ambient             ; then read out ambient light intensity and store value in "Ambient"
pause RndDelay                     ; pause for an "individual" (hopefully) amount of time before doing anything else



main: do        ; main loop


	
	let Power = Power + 1     ; slowly start incrementing the fireflie's desire to blink..

	
	readadc 1, Brightness     ;...while watching the surrounding fireflies too!

	
	if Brightness >= Daylight then      ; unless its daytime (fireflies are sleeping during daytime!)...

		sleep 3

	endif

	
	if Brightness > Ambient then       ;......perceiving pulses from other fireflies will

		Power = Power + 50             ;..strongly increase our fireflys desire to pulse with them!

	endif

	
	if Power > MaxPower then          ; if the desire is strong enough... 

		gosub pulse		; ...the firefly bursts out a light pulse
			
	        let Power = 1         ; what a relief for the firefly! "desire" is reset to initial value 
	        				; (equals satisfaction about just having pulsed) 
	  
	 endif

				
loop       ;  starts building desire for another pulse again (while slowly approximating the other's frequencies)





;subroutine
pulse:

    high 2             ; give a short flash of light
    pause 300
    low 2

return
 

eclectic

Moderator
@Dennis

"Will the program work at all?"

Have you tried it?
If only in Simulation.



e
 
Last edited:

AlC

Member
Not in hardware since I don't have many spare picaxe08 lying around, which is prerequisite for this project.

The program does simulate well though, the "LED" flashes from time to time while slowly incrementing the "desire" by 1 at a time, when I raise the adc value manually this triggers the LED to flash almost immediately which is what it should do.

I'm only concerned about diversity between single chips: will a number generated individually on each chip with "random" differ enough between single picaxe08 to make it possible that they all start at different times when all are switched on at once? They should not be synchronized at the beginning already thats why I ask. The effect is that they need some time to get into sync with each other.. ..looks very interesting when you watch it.

But for this to happen, they need to be off-sync to begin with. This is achieved by having each "firefly" wait an individual amnt of time before it starts blinking and syncing. So a good random value is needed for calculating this individual delay. the Picaxe08 doesn't have any internal clock the random number could be seeded with (like with the picaxe X chips), but I hope their internal oscillators are all slightly different enough. (?)

anyone know code for generating good (diverse between single chips!!) random numbers?
 
Last edited:

Jeremy Leach

Senior Member
Interesting !

I've not studied it in detail but - If you're powering up all picaxes at the same time then I think you'll need to have a different 'seed' for the random part, becuase it's only pseudo random on a picaxe. However I'd personally not get hung up on the random aspect and just have different preset constants for each picaxe.

Also, you might find the LDRs have trouble detecting the light pulses from the LEDs??

So, what stops real fireflies all speeding up I wonder?! Do they have an inbuilt frequency?
 

Andrew Cowan

Senior Member
To get truly different delays, put pause 3 at the top of one 08Ms code, pause 7 at the top of the next's, pause 11 at the top of the next...

A
 

hippy

Technical Support
Staff member
All PICAXE random numbers will initialise to zero and follow the same sequence so all ( without any attempt to synchronise them ) will run in sync until small differences in oscillator frequencies causes them to drift apart. You will need a seed value which is different for each PICAXE programmed.

One way to create a seed is to read the initial value from Eeeprom, update it and write back. This way you get a different sequence at each power-up. Unfortunately all those powered up the same number of times will stay in sync.

You can get a random value from reading the LDR as Boriz suggests, and you could add this to a stored Eeprom value.

Eeprom 0,(0) ' Initial seed - All the same

StartProgram:
Read 0,w0 ' Read initial seed
ReadAdc10 1, brightness
w0 = w0 + brightness
Random w0
Write 0,w0 ' Save a new seed for next time
Do
: ' Rest of code
Loop

There are other ways to do it; you could read the LDR value and repeat 'RANDOM w0' however many times indicated and so forth.

Note that PICAXE-08 only have limited ADC capabilities; only 16 distinct levels. You may be better off with 08M.
 
Last edited:

SilentScreamer

Senior Member
Assuming you have an unused input could you record a few bits from a floating input pin and use this as the seed? I've not got a clue as to how well it would work though.
 

Jeremy Leach

Senior Member
Or perhaps just have the picaxes in two groups each group (flock/swarm?!) fed from a different power switch. Then manually switch each set on with manual delay between switching - I'd think this would ensure each display sequence would be sufficiently different??
 

boriz

Senior Member

lanternfish

Senior Member
In this section of code

; initialisation blinking loop
for BlinkCounter = 1 to 5 ; blink five times
gosub pulse
pause 700
BlinkCounter = BlinkCounter + 1
next BlinkCounter

I think the underlined command will increment BlinkCounter so that the 'firefly' will only produces 3 flashes of light. Not hugely important(?).

Nice code and faithful to the original.

cheers
 

AlC

Member
Wow,

Thanks to all for all these answers!!

@lanternfish, thats right I noticed too that it doesn't blink 5x only 3x - is it the counter being incremented to 2,3,4 only during the for/next loop? should I start with 0 and count to 6 instead? (and no, its not really important but I'd like to have it infact blink five times if I try to write code for five times.. hehe)


Given all the good suggestions about aquiring good random seed, I'm not sure which route to go. I like the idea of boriz, reading out the LDR forr a random seed, since this requires no additional hardware or wiring (a pure software solution so to speak). The thing with the random noize transistor circuit sounds nice too, but would require me to give each firefly this circuit. Or wire them all to one "randomizing" component/circuit which isn't how real fireflies work.

The idea of just loading each "firefly" with differing code (i.e. variations in initial delay implemented by hand) is only acceptable if the LDR idea doesn't work out well I think, alas every firefly isn't made equal in nature as well so I might as well give them different initial delays by hand. (But I would like it more if I could say "look, even thier programming is equal between them, they're all THE SAME kind of firefly")

BTW, the LDR will of course need to have some kind of diffusor covering the LEDs, so that part of the emitted light is reflected and can be "seen" by the LDR...

the Picaxe08 really only has 16 steps resolution for the adc? That wouldn't be sufficient! I thought the 08 had 8bit adc=256 steps in contrast to the 08m with 10bit=1024 steps? (correct me if I'm wrong plz!)

Concerning the question why the fireflies don't blink faster and faster, well neighboring blink pulses don't cause immediate blinking only bump up the "desire" to do so a fair bit, so the fireflie's blinks are closer and closer with each cycle. When they are synced, they all bump up at the same speed thus having a steady blinking frequency. The code ofcourse still needs some fine tuning to accomplish this, but the goal is that the neighbouring fireflies blink closer together each time they do, they are not supposed to be synced right after the first blink but rather after several blink pulses. (hope this was clear enough to understand)

Last thing, I don't understand the thing with writing to eeprom - how is it supposed to give a random seed if I first fill it with zeroes by myself, then read that out and add/multiply/whatever with "random", then write back? Why not just write random to eeprom directly instead? (confusion here)


Once again, thanks for all the replies and great input!
 

QuIcK

Senior Member
The idea is to mix the random number up a bit. its not a real random number, and you cant use a random number to seed a random number, because it will still follow the same pattern.
this means that each picaxe will generate the smae random numbers, and have the same behaviour patterns

what hippy is suggesting, is have a sort of "power up" counter, that will increment by a random amount (dictated by the current light state). this will cause each picaxe to seed their "random number" generator with a different value (unless all the light levels are the same). as its incrementing, even if the light is roughly the same as the last time it powered up, it will still have a different seed. (also it will overflow every now and then, "refreshing" the seed).

you could certainly randomize the initial eeprom write, but thats the same as giving each one a different initial pause...


as for the loop, the "next BlinkCounter" will increment the variable BlinkCounter. so you do not need to do that inside the loop (unless you are trying to skip steps).
Code:
; initialisation blinking loop
for BlinkCounter = 1 to 5 ; blink five times
gosub pulse
pause 700
'BlinkCounter = BlinkCounter + 1 ' delete this line
next BlinkCounter
 
Last edited:

AlC

Member
@QuIcK: Ah I see. so I was counting twice per for/next, d'oh.

Think the idea of using the LDR value and multiply with an "old" random seed from eeprom sounds best.

So the eeprom initially contains the first reading of the LDR (after it is first powered on), then with each subsequential power-on this eeprom value is read and some mathematical fancy done (multiply with new LDR reading perhaps?) and again stored in eeprom, where it is available for next power-on. This value is used each time to calculate the initial delay.(Did I get this right?)

This would make the fireflies be pretty synced at first power-on, but each time the start delays differ more and more between them, - right?

(I think this would be very close to real fireflies behaviour, they are individual not right away from day of birth but through learning differently. So they consider different times as apppropriate for starting to blink when they're finally adult...)

The picaxe08 really has only 4bit/16 steps for adc? If so I'd might consider using the 08m for greater diversity among single fireflies!

The project takes on shape I'd say.
 

hippy

Technical Support
Staff member
Yes, the PICAXE-08 only has 4-bit ADC resolution though that's expanded to give 16, 8-bit values.

Yes, you got the seeding right. No matter what mechanism is actually used anything which gives a bit of divergence early on should lead to more divergence later on.
 

eclectic

Moderator
How about changing the individual "Fly's" processing speed?

Using a random derived seed,
then randomly alter
the CALIBFREQ, by say + / - 3?

e
 

AlC

Member
thinking about it, what about waiting several seconds at the beginning, and use this time interval to read out the LDR periodically several times, then calculate random seed by lets say multiplying these values? (or use just a few bits of each LDR reading to form a random word maybe?)

One could just wave the hand above the fireflies to "randomize" them before they start blinking ..
 

AlC

Member
@eclectic: I fear that wouldn't work well for synchronization since they need to stay in sync once they found the common frequency, meaning they need to increment the "desire" at the same speed when no input (input=LDR reading over a certain threshold=blinking neighbors) occurs. Once they have adjusted to their neighbors, they all at once get a positive LDR reading at the same time, and slowly increment the remainder of the time until they all at once blink again, which triggers another LDR reading in all fireflies at once etc.. This needs to happen at the same speed in all chips to stay in sync and not slowly loose it!

Just the starting time/delay needs to be different to create unorganized behaviour at the start, so the self-organizing effect can be observed.

of course one could also implement a clock frequency adjustment based on timed LDR readings, and have individual blinking speeds synchronize to a common average freq - but this model is just about same fixed frequency for all, and altering the "offset" of the individual frequencies to get things in sync. Its easier..
 
Last edited:

AlC

Member
There's also a similar physics experiment where you place several mechanical metronomes with individually set, differing speeds on a big pendulum, and what happens after some time the metronomes approach the same frequency, while giving off or taking up excess kinetic enrgy via the pendulum they're sitting upon..(added bonus: pendulum reaches steady motion once equilibrium between metronomes is reached)

These fireflies reaching synchronous blinking frequency are somewhat similar, but as said somewhere above they don't differ in blinking frequency but rather just in the "offset" (or starting delay), kinda like a simplified version of the metronome/pendulum thing.

:)
 

boriz

Senior Member
The LDR seed idea will only work with an 08m. You need 10 bit resolution to get the variations in the last few bits. If you have to use the cheaper 08’s, perhaps this idea will work:

At switch on, charge an electrolytic capacitor through a Thermistor (or LDR, Phototransistor, whatever). Tap the capacitor voltage using a digital input and wait for it to read high. While waiting, increment a counter in a loop. Slight variations in manufacturing tolerances in the Picaxe, the Thermistor and the Capacitor should all add up to a fairly unique delay. The counter becomes the seed.
 

lanternfish

Senior Member
One of the Instructable firefly circuits (http://www.instructables.com/id/Synchronizing-Fireflies/) uses ATTiny13v's. All use the same code and this results in an interesting display that eventually syncs after a couple of minutes.

Surely this is what the intention of the system is, to eventually synchronise.

That being the case, the minute timing differences due to component tolerances between the 08M's should be sufficient to provide the necessary randomness at start up.

As a though, slowly waving your hand over the array of 'fireflies' after powering may possibly introduce the randomness you are looking for (?).

Cheers
 

AlC

Member
As a though, slowly waving your hand over the array of 'fireflies' after powering may possibly introduce the randomness you are looking for (?).
Yes thats what I was thinking too, and have a few seconds "learning phase" at the beginning, during which the LDR is periodically read several times (whilst hand is waved over the whole array), then use this values combined with eeprom reading for a good random seed..

Yes I've read the instructable linked above and am aware that the guy says hes using attiny without randomizing anything, but I cannot believe that this (without any special, truly random delay) leads to the real random behaviour seen in the video..

the fireflies start several seconds off sync in the video, I don't buy that this happens due to just "for/next-ing" 500 times in a row and because of Atiny chips having such great tolerances.
As hippy mentioned the picaxe chips will all come to the same "random number" when switched on at once, and will only differ slightly in results with time, due to minor diffrences in int.oscillator frequency.

So IF the fireflies have indeed all indentical coding but individual starting behaviour, then this code needs some true randomness to create a degree of individuality among them I'd say?

(is the aTINY chips from atmel really manufactured with SUCH great tolerances? I don't know but it would surprise me, alas they're supposed to contain the same digital circuitry!!)

EDIT and yes I'll go for the 08M for the sake of having usable 10bit LDR readout. :)

As soon as I'm in posession of more than one 08M chip I'll try how individual they can get with a simple "random" and "debug" (or wire both to one trigger button and see if they increment a variable at the same speed), then based on that knowledge decide on how to best approach the wanted individuality. But I think its good to know all those possible methods for random seed before, and think I'll need them.
 
Last edited:

boriz

Senior Member
Something like this at the start of the program?:

Code:
READ 0,w0
READADC10 1,w1
w0=w0+w1
WRITE 0,w0
This way, small differences accumulate between runs. The seed (w0) is almost guaranteed to be different for different Picaxes and get more different with each run. No need to bother trapping overflow.

But I don’t think it’s necessary.

The motivation to flash starts off very low and increases according to how much light is detected by the sensor. The motivation accumulates through iterations of the main loop. It may as well start off at zero. No two LDRs will be producing exactly the same output. So after the first couple of iterations through the loop, the LDR randomness will have accumulated, and the motivation to flash will be different for different Picaxes, making a unique seed unnecessary.
 

AlC

Member
The seed (w0) is almost guaranteed to be different for different Picaxes
last time I asked in this very thread, the consensus seemed to be that all picAXEs are not individual enough between single chips. (ask hippy!)

So after the first couple of iterations through the loop, the LDR randomness will have accumulated, and the motivation to flash will be different for different Picaxes, making a unique seed unnecessary.
Yes but this only works if you HAVE a random seed to begin with I'd say. All picaxe adding 1F to 00 and writing to eeprom for use next time won't give individuality, not even after 5 million cycles (ok after 5mio cycles maybe they do differ a bit)

So yes, its not needed to always have good random seed, but if you need it at the beginning you can right away leave the randomness in I think and not change the code again. Furthermore the random delay at the beginning make it never boring to watch, opposed to having the same pattern each start.

And no, I will not just read from eeprom and add the LDR reading to that for next time, but instead I'll loop through several readings during a few seconds, multiply THOSE LDR readings with each other and then use that to seed my random number. The handwaving/programming story mentioned above.
 

BeanieBots

Moderator
The voltage read will be quite different on each device.
Not only due to variations in light level but also LDR spec.
Even without any hand waving.

Bottom line, try it.
 

Andrew Cowan

Senior Member
When you make the potential divider for the LDR, don't use 0.0001% precision resistors.

There you go - another source of randomness.

A
 

hippy

Technical Support
Staff member
I agree with Dippy; the only way to find out is to try it. In theory the oscillators should be fairly closely matched and they should start off running in sync but practice may be very different and even a small % error can rapidly turn into a notable one.

I have a 3x3 LED 'ornament' made from 1Hz flashing LED's ( all circuitry built-in, just needs +V/0V ) and was surprised to find how much start-up time differed and how out of sync they turned out to be.

Set two 08M's running with the same code and a LED+R on output 1 ...

Do
Toggle 1
Pause 1000
Loop
 

hippy

Technical Support
Staff member
Fzzt!

I agree with Dippy, who would have posted he agreed with BeanieBots if he had posted. That's if Dippy had posted, not if BeanieBots had posted.

Fizzle
 

boriz

Senior Member
“Yes but this only works if you HAVE a random seed to begin with”

No. I don’t think you understand. Think of it like this:

This is not an example of a firefly routine. It is only to illustrate cumulative randomness.

You read the LDR. You take the last 5 bit’s and add that to a total. Repeat. When the total gets to (say) 10000 you flash and reset the total to zero again. Try it with two Picaxes. They will flash at different times. And no RANDOM command required.

Each iteration, you get closer to the flash threshold. But different Picaxes (with different LDRs) will increment their totals at different rates. Each iteration will cause the totals to get further and further away from each other. And unless you artificially synchronize them, each loop will run at a slightly different speed.

You might also like to use a thermistor as the other leg of the LDR divider. That will add further randomness/noise to the ADC readings.

Random behavior. No RANDOM command required. No seed required.
 

Dippy

Moderator
I totally agree with that.

I'm not sure I agree with BB about where he has put his slide rule though.
 

AlC

Member
a) ok boriz, I see - its no random seed per se, but you cannot deny the real randomness needs to be included somehow, either with or without using the pseudo-random genrator? which leads me directly to

b) :) yes I think bottom line is try it out. experiment is king.

c) I personally am of the opinion that real fireflies are not individual because they can count crazy fast to 50000 before blinking, but rather because they are exosed to different outer influences (like, lets say, the amount of ambient light or perceived duration of sunset etc - just an example *hint*hint*) ;)


BTW I like the idea of using 5% or higher tolerance resistors for the LDR voltage divider! Thats the type of "extra circuitry" that will make no problems in design or price, heh.
 
Top