Programming the PixelPusher
version0.5
JasStrong<jasmine@[Link]>
0. Introduction
[Link],anditpushesthemoutto
[Link]/IP
networkstack,andanumberofmodulesthattellithowtotalktodifferentLEDcontrolchips.
[Link]
designedtobeplugandplaytoabstractthecomplexityofthetaskawayfromtheuserto
allowartistsandarchitectstoconcentrateontheinterestingpartofthedesignequation.
Weprovideasoftwarestackthatiscomprisedofthreecomponents:
[Link]
Thefirmwareisapieceofsoftwarethatisloadedintotheflashmemoryofthe
[Link]
realtimeoperatingsystem,anetworkstack,aFATfilesystem,aUSBstack,andasignalling
stacktotalktothestripsorpixelsyouhaveattached.
[Link]
[Link]
asetofclasseswhichcollectivelyfind,makeorderly,andtalktooneormorePixelPusher
controllers.
[Link]
[Link]
[Link]
thelibrary,youcanfindtheminProcessingsExamples...dialogue,underContributed
Libraries.
1. To begin...
1. [Link],sohead
to[Link]
PC,MacandLinux,soyoushouldbeprettywellcovered.
2. [Link]
intoProcessingat[Link]
notethatatthetimeofwriting,PixelPusherisnotyetincludedintheAddlibrary...tool,
[Link]
[Link]
todate.
3. Thirdly,[Link]
firmwareversionshavecomeoutsinceyourproductshipped,aswefollowacontinuous
[Link],andallyouneedisamini
[Link]
document,alsoavailablefromtheHeroicRoboticsforum.
4. Andlastly,youwillneedtowriteaconfigurationfileforeachPixelPusherinyoursystem,
saveeachoneontoaUSBmemorystick,andinsertitintotheappropriatePixelPushers
[Link],tomakethemreadtheirconfiguration,presstheresetbuttonor
[Link],again,explainedinthe
HowToPushPixelsdocument.
YoullneedtoconnectallthePixelPusherstothesamenetworkyourcomputerison,ofcourse.
Onceyouvedonethat,youcanopenoneofthePixelPusherexamplesinProcessing,hitrun
andyoushouldseeitpickupallyourPixelPushersinafewseconds.
2. How does all this work?
PixelPusherisdesignedtoautomaticallyconfigurethearray,anditdoesthisusingtwotypesof
[Link],andtheotherissent
[Link]
howthisworks.
A technical aside:
The Universal Discovery Protocol
ThemessagesthataresentfromthePixelPushertothecontrollingcomputerfollowaformatwecallthe
[Link]
[Link],andarepickedupandstoredin
[Link]:
thePixelPushersIPaddressandMACaddress
twonumberscalledthegroupordinalandcontrollerordinal,assignedbytheuser
howmanystripsareattachedtothisPixelPusher
howmanypixelsareineachstrip
howlongittakesthisPixelPushertoprocesseachpacketofdata
howmanypacketsthePixelPushermissedinthelastsecond
howmanystripscanfitintoasingledatagram(packet).
aflagbyteforeachstrip,describingthepixellayout(RGBorRGBOW,24bitor48bit,
renormalizedorlinear).
thesoftwareversionthePixelPusherisrunning
aflagwordforthePixelPusher,denotingwhetheritrequirespackedstripdatagrams
[Link]
representationispopulatedwithPixelPushersastheyareseen,andkeptuptodateasdiscovery
[Link]
representation,andmodifythepixelsinthemodelthelibraryhandlessendingupdatesoutto
[Link],itusesthesecondformof
traffic.
The Strip Update Message Protocol
[Link]
informationrelatingtospecificstrips,including:
apercardsequencenumberforthecurrentpacket
astripnumberfromzerotoseven
anumberofRGBtripletsappropriatetothenumberofpixelsinastrip
SincethememoryavailabletotheethernetcontrolleronPixelPusherislimited,onlyalimited
numberofpixelscanbesentinasingledatagram.Withourusualmaximumof240pixelsper
strip,[Link],
[Link]
timinginformationandthemissedpacketdatafromthediscoverypacketareusedtothrottlethe
packetsbeingsenttotheavailablesystembandwidth.
3. Groups and Controllers
WeanticipatethatyoumightwanttohavemorethanonesectiontoyourPixelPusherarray.
Maybeyourelightingdifferentareas,oryouwanttohaveabigbillboardsizedvideodisplaythats
[Link].
WhenthelibraryenumeratesaPixelPusheritreadsfromittwonumbers,whicharecalledgroup
[Link],andwithineachgrouptheyareordered
[Link],oryoucanjustselectallofthem
atonce,inwhichcasetheyareorderedfirstbygroupandthenbycontrollerso,forexample,
group2controller1comesbeforegroup2controller2,butgroup1controller37comesbefore
[Link],theethernethardwareaddressisusedasa
[Link]:
4. Nuts and bolts
Asyoullseefromourexamples,thereareafewbitsandpiecesyoullneedinyourProcessing
[Link].
Theimports
[Link]
youllseeablockthatlookslikethis:
[Link].*
[Link]
[Link]
[Link].*
Thisimportstheregistry,whichisthesoftwarecomponentthatlistensforthediscoverypackets,
thePixelPusherabstractionsforPixelsandStrips,andtheJavastandardutilityclasseswhich
areusedforcollections.
Theregistry
ThenextthingwedoistodeclaretheDeviceRegistry.
Theobserver
PixelPushersregistryusesanObservermodeltotellthesketchwhenPixelPushersappearand
[Link].
classTestObserverimplementsObserver{
publicbooleanhasStrips=false
publicvoidupdate(Observableregistry,ObjectupdatedDevice){
println("Registrychanged!")
if(updatedDevice!=null){
println("Devicechange:"+updatedDevice)
}
[Link]=true
}
}
Thenwedeclareone,likethis:
TestObservertestObserver
Asyoucansee,itsnotabigclass,andjustimplementsamemberyoucanusetocheckwhen
[Link]
arraysshapeorbehaviourchangessignificantly.
Setup
Thentherearesomebitsandpiecesweneedtodointhesketchssetup()[Link]
methodthatrunsbeforethesketchstartsinearnest,anditsagoodplacetoinstantiatethebits
[Link]:
registry=newDeviceRegistry()
testObserver=newTestObserver()
[Link](testObserver)
Thisinstantiatestheregistry,[Link]
instantiatestheobserver,andthentellstheregistryaboutit.
Pushingthosepixels
Havingdoneallthissetup,[Link]()
[Link]!Itmighttakea
[Link]
makeanappearance.
if([Link]){
//...thePixelPushercodeiswrappedupinhere
}
Whentheymaketheirappearance,wemakeacalllikethistomaketheregistrystarttalkingto
thePixelPushers:
[Link]()
[Link]
[Link],therearegroupswhichcontaincontrollers
[Link],weprovideawaythatyou
canbypassthisandhavetheregistrydoitforyou.
List<Strip>strips=[Link]()
[Link],ifyouonlywanttotalkto
oneparticulargroup,youcandothis:
List<Strip>strips=[Link](some_group_number)
anditwillreturnalistofallthestripsbelongingtocontrollerswhosegroupnumberisgiven.
Thenallyouneedtodoistoloopthroughthestripsandsetthepixelswithinthemtothe
[Link]!TheStripclass
[Link]()willreturnthenumberof
[Link],[Link](color,
number)wherecolourcaneitherbeaProcessingcolorobjectoraPixelPusherPixelobject.
5. Every day Im scrapin
Inmostofourexamples,wescrapepixelsfromtheProcessingsketchwindowandsendthem
[Link]:
intstripy=0
List<Strip>strips=[Link]()
intyscale=height/([Link]())
for(Stripstrip:strips){
intxscale=width/[Link]()
for(intstripx=0stripx<[Link]()stripx++){
colorc=get(stripx*xscale,stripy*yscale)
[Link](c,stripx)
}
stripy++
}
6. Tweaking the rate
Normally,theregistrykeepstrackofhowmanypacketsarebeinglost(theygetdroppedifthere
isntenoughbandwidthorifyoureusingawirelessnetworkandtheresnoise)andhowlong
eachPixelPusherissayingittakestopushoutacompletepackettothestrips,andadjuststhe
[Link],ifyoureonaveryslownetwork,likea
verylongwirelesslinkoracellularmodem,[Link]
[Link]()methodisfor.
[Link](milliseconds)
[Link]
tozero,[Link]
defaultupdaterate,eachPixelPusherconsumesbetween5and10megabitspersecondof
[Link],aPixelPusherwithtwostripsrunningatmaximumspeed
willconsumeabout52megabitspersecondofbandwidth.
Ifyoureonanetworkwithahigherrorrate,likesomewirelessnetworks,orpoorlyinstalled
ethernet,youmightfindthatyougetpersistentlyhigherrorratesandtheupdatefrequencydrops
[Link],[Link]
[Link](true)willturnautothrottlingon,
[Link](false)willturnitoff.
Asof20130325,thelibrarydefaultstoautothrottlingbeingturnedoff,soyouwillneedtomake
theabovemethodcalltoturniton.
7. Getting the colours right
Ifyoureusingvideosourcematerialandeverythinglookswashedout,youmaywanttoapplythe
[Link],
otherwise.Asofthe20130608versionofthelibrary,thereisacalltotellittocorrectthe
luminancecurve:[Link](true)[Link]
[Link].
8. A note on architecture
ThewayPixelPusherslibraryactuallyworksisthatthereareseveralthreads,allrunning
[Link],sogoodrealtime
[Link],soifyouwanttouseVisualVMtoprofile
whatsusingCPUtime,[Link]:
TheUDPcallback(akaDiscoveryListener)
Theresasmallroutinethatgetscalledeverytimeadiscoverypacketarrives,whichupdatesthe
[Link],andalsonoteshowlongits
[Link]
seconds,[Link](as
indicatedbydiscontinuitiesinthesequencenumbers)thenthisroutineisresponsiblefor
changingtheappropriateratelimitingvariables.
Thepreeningthread
Thisrunseveryfewsecondstocleanthedatastructuresandremoveanysadlydeparted
PixelPushersfromthesystem.
Themarshallingthread(akaSceneThread)
Thisrunscontinuously,andtakescareoftheworkerthreads,makingsurethatthereisone
[Link]
hasdisappeared,andstartingnewoneswhennewPixelPushersappear.
Theworkerthreads(withnameslikeCardThreadfor[Link])
[Link]
checkstheRegistrytoseehowthecardisdoing,andthenitchecksthestripstructures
[Link],itwalksthroughthem,sending
themtothecardattheratethathasbeencalculated,andmarksthemasnotupdated.
Thereareseveraldatastructuresinternaltothelibrarywhichareusedtokeeptrackofwhich
cardsarewhich,whichstripsbelongwhere,[Link]
recommendedthatyousticktousingthesoftwareinterfaceslistedinthisdocument,ratherthan
modifyinganyofthestructuresyourself,sincethesehavechangedinthepastandwilllikely
changeinfuturewhichwouldrequireyoutowritenewcode!
9. Multi-head operations
Becausetheworkerthreadsonlysendpacketstoupdatepixelsthathavechanged,itispossible
tohavemultiplecontrollingPCs(orMacs,Androiddevices,etc.)onasinglePixelPusherarray,
[Link]
recommendedthatyourestrictthissharingtoonecontrollingPCperPixelPusher,since
otherwisetherearelikelytobetimingconflictsandyoumayendupfloodingonepoor
[Link]
architecturethissimple,usetheExtraDelayfeaturedescribedafewpagesagotoreducethe
[Link],sincethesequence
numberswillnotbesynchronizedbetweendifferentcontrollingPCs.