Categories
Arduino Instructable IoT

Je eigen Internet-of-Things infrastructuur bouwen

Al jaren wordt er over gesproken en gepubliceerd. Ook is veel informatie te vinden in Youtube video’s. Inmiddels is het Internet-of-Things (IoT) realiteit geworden. Met slimme, internet connected producten zoals Google Nest, huishoudelijke apparatenwearables en sensornetwerken komt het Internet-Of-Things langzaam aan tot leven bij het grote publiek.

Ook de open source en ‘makers’-community houden zich steeds meer bezig met het IoT. Met open source MQTT message brokers zoals Mosquitto of met hardware platformen zoals de Arduino Yun in combinatie met IoT software stacks zoals Temboo is het relatief eenvoudig om een eigen IoT omgeving op te zetten. Maar het is natuurlijk veel leuker om het allemaal zelf te bouwen. En zoals uit dit artikel zal blijken, zo moeilijk is dat niet.

De basis voor een zelfbouw IoT systeem is een database waarin meetdata opgeslagen en weer opgevraagd kan worden. Een mySQL database zoals bij veel webhosting services wordt aangeboden voldoet daarvoor prima. Middels PHP scripts kan een website gebouwd worden waarmee zo’n mySQL database beschreven en gelezen kan worden. Bijvoorbeeld met een webpagina die HTML GET en POST commando’s accepteert. Een goed voorbeeld is mijn eigen IoT webserver. Behalve de webpagina die nieuwe meetdata verwerkt zijn er ook webpagina’s waarmee nieuwe meetdata aangeboden kan worden en webpagina’s waarmee de opgeslagen meetdata weer in tabelvorm opgevraagd kan worden.

Het posten van een HTML GET of POST message hoeft natuurlijk niet perse via een PHP webpagina. Het kan natuurlijk ook via een Arduino met een internet interface. Voor mijn proefopstelling gebruik ik een Arduino ethernet die via routers verbonden is met een internet modem. Die proefopstelling meet elke 5 minuten de temperatuur op mijn zolderkamer en verstuurt die middels HTTP GET/POST-request naar de PHP web server. Het maken van een web client waarmee HTTP GET-commando’s verstuurd kunnen worden is te vinden op de Arduino website. Het versturen van een HTTP POST-request gaat op soortgelijke wijze.

Het opvragen van de opgeslagen meetdata kan behalve middels een webpagina natuurlijk ook via een offline web-client applicatie, in dit geval een in C# geschreven MS-Windows applicatie. Daarmee wordt de ruwe meetdata grafisch weergegeven.

Voor wie inhoudelijk wil snappen hoe het werkt of voor wie het zelf wil nabouwen en aanpassen aan zijn eigen omgeving is de broncode van alle software (Arduino, PHP en C#) als ZIP file te downloaden.

Have fun!

Categories
Arduino Instructable

Batterijverbruik van je Arduino project optimaliseren

De meest gebruikte Arduino is waarschijnlijk de Arduino Uno. Met een voedingspanningsbereik van 7-12 [V] (aanbevolen) is de Arduino Uno prima bruikbaar voor batterij gevoedde toepassingen. Veelal kies je daarbij voor een 9 [V] blok-batterij (types 6R61, MN1604) of voor een zestal AA-penlights (types LR 6, MN1500).

Deze laatste hebben significant meer opslagcapaciteit en geven dus meer gebruiksduur. Een eenmalig experiment met alleen de Arduino Uno  en de “blink” sketch, dus zonder extra hardware zoals shields, sensoren, LEDs of motoren, bleek uit te komen op een gebruiksduur van ruim 50 uur. Da’s op zich niet onaardig maar het kan veel beter, in deze blog leg ik uit hoe!

Stap 1: Reduceer de klokfrequentie en de voedingsspanning.

Een standaard Arduino Uno gebruikt een ATmega328p microcontroller van Atmel die draait op een klokfrequentie van 16 [MHz] en een voedingsspanning van 5 [V]. Zoals bijgaand figuur laat zien is het stroomverbruik bij die waardes ca 9.5 [mA]. Prima als je die 16 [MHz] nodig hebt vanwege ‘zware’ berekeningen, of wanneer je de 5 [V] nodig hebt vanwege de aangesloten sensoren, actuatoren of shields. Maar als je zou kunnen volstaan met bijv 8 [MHz] en 3.3 [V] dan kun je daarmee het stroomverbuik met ruim een factor 3 reduceren tot ca 3 [mA].

 

 

Stap 2: Optimaliseer het voedingscircuit en het aantal batterijen

De Arduino Uno gebruikt een standaard 7805 als voedingsspanningsregulator voor de 5 [V]. Voor veel toepassingen een prima oplossing maar met een aantal beperkingen voor batterij gevoedde systemen. Zo is de ruststroom van deze 7805 regulaar relatief hoog. Een Arduino Uno (in Idle mode) verbruikt daardoor al ca 10 [mA]. Verdere heeft de 7805 een redelijk grote drop-out voltage (=Vin-Vout) wat resulteert in onnodige warmteverliezen.

Voor batterij gevoedde toepassingen heeft Sparkfun daarom de Arduino Pro ontwikkeld. Deze Pro versie maakt gebruik van een MIC5205 regulator. Voordelen van deze regulator zijn een aanmerkelijk lagere ruststroom en een aanmerkelijk lagere drop-out voltage. Verder is de Arduino Pro ook in een 8 [MHz], 3.3 [V] versie verkrijgbaar. Een Arduino Pro kan daardoor gevoed worden met slechts 3 AA penlights of met een (oplaadbare) 3.7 [V] Lithium-Polymere batterij (LiPo).

 

 

 

Stap 3: Reduceer het energieverbruik mbv de “Sleep-mode” van de microcontroller

De Atmel microcontroller beschikt over zgn “sleep-mode” functies waarmee ongebruikte delen van de microcontroller (tijdelijk) uitgeschakeld kunnen worden. Het stroomverbruik van de microcontroller wordt hierdoor (tijdelijk) ook lager. Zodra de microcontroller daarna weer in aktie moet komen dan zal deze uiteraard eerst weer ‘wakker gemaakt’ moeten worden, bijvoorbeeld middels een ‘timer’ of ‘UART’-interrupt.

Een typische toepassing voor dit mechanisme is data acquisitie; het vergaren van meetsignalen. Hierbij worden op gezette tijden een of meer sensoren afgetast en vervolgens worden de meetwaardes lokaal opgeslagen of opgestuurd naar een centrale verzamelplaats. In de tussenperiodes heeft de microcontroller eigenlijk niets te doen en wordt er onnodig stroom verbruikt. Je zou de microcontroller op die tussenmomenten beter tijdelijk kunnen uitschakelen en met vaste intervallen weer kunnen inschakelen.

De grootste reductie in stroomverbruik wordt bereikt met “SLEEP_MODE_PWR_DOWN” modus. Hiermee wordt vrijwel de gehele microcontroller in slaapstand gebracht. Alleen een watchdog timer interrupt (of een harde reset) kan de microcontroller nu nog doen ontwaken. Een watchdog timer heeft vele functies. Een daarvan is het generen van een interrupt nadat een vooraf ingesteld interval is verstreken. Ideaal dus voor het eerder genoemde data acquisitie voorbeeld.

Experiment

Om de invloed van de ‘sleep-mode’ op het stroomverbruik te kunnen meten heb ik een eenvoudige Arduino sketch geschreven; een low-power variant op de standaard “blink” sketch. Ook nu wordt LED13 met vaste intervallen uit- en weer aangeschakeld. Maar nu worden om-en-om de standaard “delay()” functie (met een stroomvretende softwareteller), en de “SLEEP_MODE_PWR_DOWN” functie (waarbij de watchdog timer de Arduino na de ingestelde wachttijd weer ontwaakt) gebruikt, zie onderstaand plaatje. Er zijn achtereenvolgens 4 toestanden te onderscheiden:

  1. Arduino SW-delay en LED13 aan (2 [sec]) : 5.6 [mA]
  2. Arduino sleep-mode en LED13 aan (1 [sec]) : 2 [mA]
  3. Arduino SW-delay en LED13 uit (2 [sec]) : 4.4 [mA]
  4. Arduino sleep-mode en LED13 uit (1 [sec]) : 0.6 [mA]

Duidelijk waarneembaar is het verschil in stroomverbruik tussen de ‘delay()’-mode en de “sleep-mode”. Merk op dat voor deze test een Arduino-pro 8 [MHz], 3.3 [V] toegepast is omdat het effect bij een Arduino Pro beter meetbaar is dan bij een Arduino Uno vanwege het eerder besproken voedingscircuit. Tenslotte is de rode power-on LED op de Arduino Pro zeer waarschijnlijk de reden voor de resterende 0.6 [mA] in sleep-mode.

Referenties

[ref 1] Batterijen: https://nl.wikipedia.org/wiki/Batterij_(elektrisch)

[ref 2] ATmega328p: https://www.atmel.com/devices/atmega328.aspx

[ref 3] Arduino Uno: https://arduino.cc/en/Main/ArduinoBoardUno

[ref 4] Arduino Pro: https://arduino.cc/en/Main/ArduinoBoardPro

[ref 5] Regulator with low dropvoltage and low quiescent current: https://www.micrel.com/_PDF/mic5205.pdf

[ref 6] Lithium-Polymeer batterijen: https://learn.adafruit.com/li-ion-and-lipoly-batteries

[ref 7] Arduino sleep modes: https://playground.arduino.cc/Learning/ArduinoSleepCode

[ref 8] Arduino watchdog timer: https://www.youtube.com/watch?v=BDsu8YhYn8g

[ref 9] Experiment sketch: https://www.felixdonkers.nl/downloadables/blinkWithSleepMode.zip

[ref 10] Nog een “sleeping Arduino” voorbeeld: https://donalmorrissey.blogspot.nl/2010/04/sleeping-arduino-part-5-wake-up-via.html

Categories
Arduino Instructable

Bouwen van de 3x3x3 LED kubus

In een eerder artikel beschreven we al de technische werking van de 3x3x3 LED kubus maar aan een (openbare) montagehandleiding ontbrak het tot nu toe. In deze blog volgt die dan (eindelijk). De montage is relatief eenvoudig mits je de hieronder opgegeven montagevolgorde aanhoudt. Hiervan afwijken kan hinder veroorzaken bij het solderen. De schakeling werkt dan waarschijnlijk nog prima maar ziet er mogelijk minder fraai uit.

Tip: bestudeer eerst deze montagehandleiding van voor tot achter en begin daarna pas met de montage.

Om te beginnen, de stuklijst:

  • 1 * LED cube shield
  • 27 * LED 5mm
  • 12 * weerstand 220 ohm (rood-rood-bruin)
  • 1 * header 10p
  • 1 * header 6p
  • 2 * header 8p
  • 3 * transistor BC547 of 2N2222A

 

 

De keuze van de LEDs vraagt nog even wat aandacht. In principe werkt de schakeling met vrijwel elke 5mm LED. Maar voor de look&feel is het beter om een LED te kiezen die vooral aan de zijkant zichtbaar is. Een difuse LED werkt daarom beter dan een transparante LED en kies ook de openingshoek van de LED zo groot mogelijk. Last-but-not-least, kies voor LEDs met een goede lichtopbrengst, bijvoorbeeld >1000mcd @ 10mA.

Daarnaast zijn de volgende gereedschappen aan te raden:

  • Soldeerbout (ca 15 Watt)
  • Soldeertin (met harskern)
  • Litze draad (tbv herstellen van kleine soldeerfoutjes)
  • Wat verzilverd/vernikkeld koperdraad
  • Een LED soldeermal (zie verderop voor details)
  • Een puntbek-tangetje om aansluitdraden te kunnen buigen
  • Een puntknip-tangetje om het teveel aan aansluitdraden te kunnen afknippen
  • Een weerstand buigmal om aansluitdraden op een vaste steek te kunnen buigen

De eerste stap is het monteren van de weerstanden. Daarvoor moeten de aansluitdraden van de weerstanden op de juiste maat omgebogen worden. Dat kan prima met het puntbuigtangetje zoals hierboven afgebeeld, maar het kan nog beter gaat dat met de blauwe buigmal. De buigmal zorgt voor exact de juiste maat en zorgt bovendien voor een perfecte symetrie van de linker- en de rechterkant.

Nadat alle weerstanden op maat zijn gebogen plaatst U ze in aangegeven posities op de shield (tekstzijde = bovenzijde). Alle weerstanden hebben dezelfde waarde dus daar hoeft U niet perse op te letten, maar voor het oog is het wel leuker als alle kleurcodes in dezelfde richting staan. Vervolgens is het handig om de weerstanden nog even aan de bovenzijde met een plakbandje te fixeren zodat ze er niet uitvallen als U ze vanaf de onderkant gaat solderen.

Vervolgens plaatst U de 3 transistoren. Van bovenaf gezien zijn deze halfrond van vorm. Plaats die exact zoals aangegeven op de afbeelding op de print, soldeer ze vast en knip de overlengte van de aansluitdraden af met de kniptang.

De vier headers soldeert U nu nog niet, die zitten anders alleen maar in de weg bij het solderen van de overige onderdelen. De headers toevoegen gaat nog prima nadat ook de 1e laag met LEDs zijn gemonteerd.

De volgende stap is het toevoegen van de onderste laag van 9 LEDs. Daarvoor kunt U het beste een soldeermal maken zoals hieronder is afgebeeld. Zo’n mal helpt om de LEDs per laag op de goede hoogte en onderlinge afstand te kunnen houden.

De gaten hebben een diameter van 5mm (de dikte van de LEDs) en een onderlinge steek van ca 15mm (gebruik evt de soldeergaten op de shield voor de LEDs als referentie voor de maat).

Voordat U de LEDs in de soldeermal plaatst buigt U de aansluitdraden zoals hiernaast is aangegeven. Zorg ervoor dat alle LEDs dezelfde richting op worden geboden. Let hiervoor vooral goed op de juiste positie van de lange aansluitdraad (de ‘+’) van de LEDs! Klik op de foto voor een vergroting. Dit buigen is nodig omdat U de 2e laag LEDs straks gaan solderen op de aansluitdraden van de 1e LED-laag. Daarvoor moeten de aansluitdraden zich niet onder maar juist naast de behuizing van de LEDs bevinden.

 

Zodra alle LEDs voorgebogen en geplaatst zijn, kan de shield over de aansluitdraden geschoven worden. Voorzichtig, want anders buigen ze krom. De shield moet zo geplaatst worden dat het lange printspoor aan de onderzijde van de shield verbonden is met de korte aansluitdraden (de ‘-‘) van de LEDs. Plaats de shield ook zo dat alle LEDs op dezelfde hoogte zitten, dat ziet er fraaier uit.

Soldeer de LEDs vervolgens vast. Nadat dat klaar is hoeven we nauwelijks nog aan de onderzijde te solderen en kunnen nu ook de headers aan de onderzijde geplaatst en aan de bovenzijde gesoldeerd te worden. De shield dient er nu uit te zien als hieronder afgebeeld.

 

 

Nu kunt U het bouwwerk evt alvast aansluiten op een Arduino en met test-software controleren of alles goed functioneert. Eventuele montagefouten kunnen nu nog eenvoudig hersteld worden.

Tijd voor de 2e laag met LEDs. Die 2e laag ziet er een tikkeltje anders uit dan de 1e laag omdat alleen de lange aansluitdraden worden aangesloten op de onderliggende LEDs. De korte aansluitdraden van de 2e laag worden onderling met elkaar doorverbonden. Dus dienen de aansluitdraden van deze 2e serie van 9 LEDs iets anders te worden voorgeboden, zie afbeelding hiernaast. Let er ook hier op dat de aansluitdraden in de juiste richting worden geboden anders komen ze niet exact boven de LEDs van de 1e laag uit.

 

Zodra alle 9 LEDs voorgebogen zijn kunnen de aansluitdraden op maat geknipt worden (hoogte ca 15mm) en kun je de liggende aansluitdraden per 3 LEDs aan elkaar gesolderen. Laat de uiteinden ervan nog even op lengte, daar komt straks nog een draadbrug en een doorverbinding naar de shield.

Nu kunnen de LEDs van de 2e laag op de 1e laag worden gesoldeerd. Bij voorkeur doet U dat per setje van 3 LEDs en begint U met de achterste rij. Daardoor kunt U met je soldeerbout overal nog prima bij en blijft het solderen, met name voor de middelste LED, eenvoudig. Om het Uzelf nog wat makkelijker te maken brengt U eerst alvast een druppeltje tin aan in de ‘knie’ van de onderliggende LED zodat U geen handen tekort komt bij het aan elkaar solderen van beide LEDs.

Nadat alle 9 LEDs zijn gesoldeerd dient U de uitstekende aansluitdraden nog met elkaar door te verbinden en met een draadje aan te sluiten op die shield, zie foto hiernaast. Daarna kunt U met een kleine uitbreiding op de test-software controleren of beide lagen correct werken.

Het monteren van de 3e LED-laag gaat op exact dezelfde manier als bij de 2e LED-laag.

 

 

 

Proficiat! Als het goed is heeft U nu een werkende 3x3x3 LED kubus gebouwd. Gebruik de demo software om de complete LED kubus te testen en om er Uw eigen patronen aan toe te voegen. De technische uitleg uit het vorige artikel van de 3x3x3 LED kubus zal U daarbij zeker van pas komen.

HAVE FUN! (en laat even weten met een foto of video of het gelukt is)

Categories
Arduino Instructable Product review

Het Mondriaan generator experiment

Soms experimenteer je met hardware gewoon omdat het leuk is om er ervaring mee op te doen. En waarschijnlijk komt die kennis in de toekomst vast nog eens van pas. Zo kocht ik onlangs een color LCD shield van Sparkfun. Dit shield ontwerp dateert uit 2009 en bevat een Nokia 6100-like LCD scherm van 128×128 pixels met een pixelresolutie van 12 bits (4R+4G+4B). Via de Sparkfun website zijn de bijbehorende library en voorbeeld software te downloaden. Waarschijnlijk is de hardware in de laatste jaren ietswat gewijzigd want er waren een paar kleine aanpassingen nodig om deze driver met mijn shield werkend te krijgen. Na wat uurtjes gepuzzel had ik de eerste demo werkend, een analoge klok. Dus werd het tijd voor een leuke, zelf verzonnen en geprogrammeerde toepassing.

Geinspireerd door een uitzending van Pauw en Witteman over het project “Elegante Algoritmes“, besloot ook ik een poging te doen om een software algoritme te ontwikkelen dat automatisch een Mondriaan-achtig plaatje genereert. Het “Mondriaan Victory Boogie Woogie” schilderij uit 1944 zit er niet in, daarvoor zijn de afmetingen van het LCD scherm te klein. Maar een wat eenvoudigere variant van een Mondriaan leek me wel een poging waard. Het is mij gebleken dat je met een verbluffend eenvoudig algoritme al hele leuke resultaten kunt bereiken.

Als basis voor het algoritme dient een ‘canvas’-matrix waarop de software het schilderij kan gaan tekenen. Deze canvas-matrix is twee-dimensionaal (rij, kolom) en bestaat uit pixelsegmenten waarbij 1 pixel-segment overeen komt met exact 8×8 beeldpixels. Uitgaande van een LCD beeldscherm van  128×128 beeldpixels bevat de canvas-matrix dus 16×16 pixelsegmenten. “Tekenen op het canvas” betekent dat de software  automatisch ogenschijnlijk willekeurige rechthoeken van verschillende afmetingen op het canvas plaatst, varierend van 1×1 pixelsegment tot 3×4 pixelsegmenten, etc. Net zolang tot het hele canvas volledig met rechthoeken gevuld is. Elke rechthoek is omrand met een zwarte lijn en wordt door de software random voorzien van een fill-color. In lijn met de Mondriaan stijl bestaat het kleurenpalet uit: blauw, geel, rood, zwart of (meestal) wit.

Het algoritme bestaat in feite uit 2 delen:

  • Het eerste deel zoekt naar de eerstvolgende vrije plek op het canvas. Het zoeken naar een lege plek in de matrix loopt van links-boven naar rechts-onder. Het algoritme is klaar zodra alle pixel-elementen in de matrix gevuld zijn.
  • Het tweede deel van het algoritme probeert op de vrije plek een rechthoek met random afmetingen te passen waarbij natuurlijk geen overlap mag ontstaan met eerder geplaatste, naburige rechthoeken. Indien de te plaatsen rechthoek niet blijkt te passen wordt opnieuw een rechthoek, nu met andere afmetingen, gekozen en wordt geprobeerd deze nieuwe rechthoek alsnog te plaatsen. Dit laatste proces wordt net zo lang herhaald tot dat het gelukt is om een rechthoek in te passen.

Natuurlijk kost het nog enige tuning om het Mondriaan gevoel op te wekken. Zo kun je spelen met de maximaal toegestane afmetingen van de rechthoeken en met de mate waarin kleuren in het kleurenpalet afgewisseld worden. Daarom zijn in de voorbeeldcode 3 varianten geimplementeerd, iedere drukschakelaar is gekoppeld aan 1 van die varianten, zie de video op YouTube.

De voorbeeldcode biedt m.i. een aardig schot in de richting, maar smaken verschillen en het staat eenieder vrij om nieuwe puntjes op de ‘i’ te plaatsen. Veel succes met zelf experimenteren en optimaliseren.

 

Categories
Instructable

7 tips voor een effectievere Google Adwords campagne

Regelmatig verzorg ik 1-dags Arduino workshops en natuurlijk streef ik elke keer naar voldoende inschrijvingen. Om dat te bereiken maak ik onder andere gebruik van Google AdWords. Je weet wel, die kleine advertenties die boven, onder of naast je zoekresultaten staan wanneer je “iets” hebt ge-Google-ed.

Google AdWords

Een Google Ad campagne starten is een fluitje van een cent. Eerst een account aanmaken, dan  een advertentie maken en wat bijpassende treftwoorden invullen en tenslotte geld storten. Ter controle nog zelf wat googlen om te testen of je advertentie inderdaad voorbij komt en klaar is Kees. In de dagen erna kun je via het Google Adwords dashboard blijven volgen hoe je advertentie scoort om daarmee je campagne verder te optimaliseren.

Het plaatsen van Google-ad’s is uiteraard niet gratis en dus wil je een zo groot mogelijk rendament; “zoveel mogelijk mensen uit je doelgroep naar je website verleiden tegen zo laag mogelijke kosten”. Maar ja, hoe optimaliseer je een campagne? In eerste instantie kwam ik niet verder dan “welke trefwoorden werken wel, welke werken niet”. Maar gelukkig biedt Google een gratis AdWords-welkomstservice. In minder dan 30 minuten lopen ze samen met je door je campagne en geven ze tips om die te verbeteren. En ja ook ik ben sceptisch maar ik heb het gesprek ervaren als een echte win-win. Hier zijn 7 tips die ik heb toegepast:

1) Bouw een campagne op met meerdere losse advertenties en met meerdere links

De verschillende advertenties worden afwisselend getoond en voor iedere advertentie worden aparte statistieken bijgehouden. Advertenties die na verloop beter blijken te scoren (lees: vaker aangeklikt worden), worden verhoudingsgewijs ook steeds vaker getoond. Zo kun je uitproberen met welke advertentieteksten jij jouw doelgroep het beste bereikt.

Verder kun je aan een advertentie nog een zgn “extensie”-linkje koppelen. Zo kun je vanuit de advertentie niet alleen laten verwijzen naar de subpagina waarvoor de advertentie bedoeld is maar je kunt ook een linkje toevoegen die bijvoorbeeld naar de hoofdpagina van je website verwijst. Daarmee verhoog je de kans dat een consument minimaal op een van beide linkjes klikt. Je vindt dit onder het tabblad ‘advertentie-extenties’.

2) Optimaliseer op de kwaliteitsscore van je zoekwoorden

Ieder zoekwoord wordt door Google beoordeeld op zijn zoekwaarde. Daarbij kijkt Google o.a. naar hoe goed het trefwoord past bij je advertentietekst(en) en naar hoe goed het past bij de website waarnaar de advertentie verwijst (Let op: dit blijkt hoofdlettergevoelig!). Maar mensen zijn gewoontedieren zijn en dus is het goed om ook zo goed mogelijk aan te sluiten bij zoekgewoontes. Dus analiseert Google ook hoe vaak jouw zoekwoord bij eerdere zoekakties al eens gebruikt is. Hoe beter e.e.a. past, hoe hoger de kwaliteits-score van je zoekwoord.

Een kwaliteitsscore vanaf 6/10 is redelijk. Trefwoorden met een lagere score kun je beter vervangen of weg laten. Ze toch laten staan werkt zelfs tegen je. Het levert Google immers een veel positiever merk-imago op (bij zowel adverteerders als bij consumenten) als alle aangeboden advertenties maximaal relevant zijn. Slecht passende advertenties worden daarom zoveel mogelijk gemeden. Hoe hoger jouw gemiddelde kwaliteitsscore is, hoe groter de kans dat jouw advertentie wel getoond wordt in plaats van die van jouw concurrent. Dus beter 10 goeie dan 100 matige zoekwoorden.

P.s. andersom kun je die kwaliteitsscore natuurlijk ook gebruiken om je teksten in je advertentie en op je webpagina te optimaliseren (lees beter op elkaar af te stemmen).

3) Optimaliseer op de CTR waarde van je zoekwoorden

Nadat je campagne een poosje loopt krijg je steeds meer informatie waarop je kunt gaan bijsturen. Zo zie je per zoekwoord het aantal vertoningen en het aantal klikken. De verhouding daartussen resulteert in een zgn CTR score. Hoe hoger de CTR score, hoe succesvoller dat zoekwoord is. Ervaring leert dat een CTR score van 2% of hoger een prima waarde is. Zoekwoorden met een lagere score dan 1% kun je beter laten vervallen (om dezelfde redenen als hierboven beschreven zijn voor de kwaliteits-score). Uiteraard wordt de betrouwbaarheid van de CTR score beter naarmate de campagne langer loopt en de advertentie vaker vertoond is.

4) Segmenteren en campagnes evt splitsen

Google ad’s worden standaard zowel getoond op de Google zoekpagina alsook op zgn ‘partner websites’ (bijv. Google-maps, YouTube, etc). Je kunt dat zo laten of je kunt ervoor kiezen om alleen bij een van beide groepen te adverteren. Wat een verstandige keuze is hangt erg af van je campagne. Op je Google dashboard kun je middels de functie “segmenteren” per categorie zien hoe je doelgroep reageert op je zoekwoorden. Sommige oekwoorden zullen in de ‘Google’ categorie een hoge CTR score geven, terwijl datzelfde zoekwoord in de ‘partners’ categorie juist een lage CTR score geeft, of andersom.

5) Optimaliseer het CPC bod en bod-limiet per zoekwoord

CPC staat voor “Costs-per-Click” en standaard staat die waarde op automatisch ingesteld. Google bepaalt dan mede aan de hand van jouw maximale dagbudget een  streefkostprijs per zoekwoord. Zeker in het begin van je campagne is die automatische stand prima. Zo kun je wat ervaring opbouwen over welke van jouw zoekwoorden het meest gebruikt worden en welke zoekwoorden het vaakst leiden tot een daadwerkelijke klik. Stel nog wel even een maximaal-budget-per-zoekwoord in. Daarmee voorkom je dat je hele dagbudget met 1 klik wordt opgebruikt.

Op het moment dat je voldoende zicht hebt op je meest succesvolle zoekwoorden kun je ervoor kiezen om de CPC voor die zoekwoorden handmatig een hogere waarde te geven. Uiteraard zal je advertentie dan vaker getoond worden, want advertenties met de hoogste CPC waarde krijgen voorrang van Google.

6) Probeer je campagne uit, maar niet als gewone consument

Binnen de Google AdWords omgeving zijn een aantal tools beschikbaar waarmee je kunt inschatten hoe je campagne zich in de werkelijke wereld zal gaan gedragen. Je vindt ze onder het kopje hulpprogramma’s en analyse. Een erg handig tool is de zgn “Google verkeer-schatter”. Daarmee kun je inschatten hoe vaak jouw advertentie zichtbaar zal zijn, per zoekwoord en op basis van jouw budget instellingen.

Een ander voorbeeld is de functie “Advertentievoorbeeld en -diagnose”. Deze functie gedraagt zich nagenoeg hetzelfde als de normale Google zoekmachine, met als belangrijkste uitzondering dat er nu geen rekening gehouden wordt met jouw “niet-klik-gedrag”. In normaal gebruik wordt dit gedrag door Google namelijk geinterpreteerd als “niet geinteresseerd in deze advertentie en opnieuw tonen heeft dus geen zin“. Je voorkomt met deze diagnosefunctie dus dat jouw advertentie op jouw PC niet meer getoond wordt, iets wat je in dit geval juist wel wilt.

7) Bel de Google Adwords service-desk voor uitstekende support

De mensen van Google zijn vriendelijk, goed getrained en erg behulpzaam. Hun belang is ook jouw belang, maar daar gebruik van.

Categories
Instructable

Tutorials

Zo af en toe voeg ik wat wetenswaardige documentjes toe aan mijn verzameling. Hierbij een overzicht:

Video’s:

Categories
Arduino Instructable

5x5x5 RGB LED cube

Op YouTube zijn voldoende voorbeelden van LED-cubes te vinden, heel soms RGB maar meestal monochroom en vaak ook met ‘normale’ 5mm LEDs. Zelf had ik al eens een 3x3x3 LED kubus gebouwd en beschreven in een eerdere blog.

Deze keer wilde ik een LED-cube maken die ook tijdens buitenevenementen als blikvanger kan dienen (en inmiddels ook gedaan heeft). Dus iets met redelijk forse afmetingen zodat ie ook van ver af al opvalt. Om arbitraire redenen koos ik voor een 5x5x5 kubus, dus 125 RGB LEDs, met buitenmaten 50x50x50 [cm], zie foto.

Als ‘basismateriaal’ koos ik de LED-pixelsnoeren waarmee ik in eerdere projecten (o.a. LED-pixel-pong) al de nodige ervaring had opgedaan. Deze hebben een SPI-achtige interface en zijn daarom redelijk eenvoudig met een Arduino aan te sturen. Bovendien kun je meerdere snoeren met elkaar doorverbinden. Elk LED-pixelsnoer heeft 25 RGB LEDs dus met 5 van deze snoeren is de kubus te realiseren. Een kleine bijkomstigheid is het stroomverbruik van de kubus bij volle belasting, dus alle pixels 100% wit. De LEDjes zijn samen goed voor zo’n 3*125*20 [mA] = 7,5 [A]. Een aparte 5[V] voeding is dus geen overbodige luxe.

Het is overigens niet verstandig om alle LED-pixels vanuit 1 centraal aansluitpunt te voeden. De nullijn van het LED-pixelsnoer wordt namelijk zowel gebruikt voor de stroomtoevoer en als SPI-signaal-retourgeleider. En de common-mode stroompieken die ontstaan door het aan/uit schakelen van de LEDs verstoren de SPI commando’s waardoor regelmatig foute LED patronen zichtbaar worden. Dit probleem is eenvoudig op te lossen middels een zgn ‘ster’-voeding, dwz elk LED-pixelsnoer apart aansluiten op de 5[V] voeding.

De SPI interface kan wel gewoon doorgelust worden. Hierdoor behelst het individueel aansturen van de LEDs niet meer dan het in de juiste volgorde versturen van 3*125 bytes via de SPI interface, telkens in de volgorde RoodGroenBlauwRoodGroenBlauwRoodGroenBlauw-etc… Voor het ontwerpen van leuke LED-patronen is het erg handig indien je de LED-pixels aan kunt spreken op basis van hun XYZ-coordinaten. En wanneer je het LED-pixel snoer bovendien op een regelmatige manier door de LED-kubus laat lopen is het ook vrij eenvoudig om een functie te schrijven die deze XYZ coordinaten omrekent het volgnummer [0…124] van die pixel in het LED-pixelsnoer.

Wat rest is de nodige fantasie om allerlei leuke LED-patronen te bedenken en te programmeren, deze voorbeeldcode is hiervoor een goede start. Ervaring leert dat de snelheid van de SPI-interface en de rekenkracht van de Arduino voldoende groot zijn voor een refresh-rate van >25 frames/sec.

Categories
Arduino Instructable

En dan vertoont je sketch plotseling gekke kuren…

Herkenbaar? Het ontwikkelen van Uw Arduino sketch verloopt tot nu toe zonder al te grote problemen. Maar dan, na slechts een kleine wijziging of uitbreiding gedraagt de sketch zich plotseling heel vreemd. LEDjes en schakelaars reageren niet meer zoals bedoeld, de seriele poort geeft geen debug informatie meer door. Of erger nog, de Arduino loopt onverwacht vast. U spit uw broncode nog eens stevig door, probeert nog wat, maar het vreemde gedrag blijft onverklaarbaar.

Het overkwam mij onlangs bij het uitbreiden van de LED kubus sketch. De software had al wekenlang zonder problemen gedraaid maar nadat ik een aantal nieuwe LED patronen had toegevoegd begon deze plotseling gekke kuren te vertonen. Uiteraard op plekken die je niet verwacht en waar je op dat moment ook helemaal geen code aan het wijzigen bent.

Ad-hoc aanpak

“Trial-and-error” aanpak

De eerste stap is natuurlijk om te kijken of je ergens een domme type-fout hebt gemaakt, maar een zorgvuldige code inspectie leverde mij niet direct iets op. Dan maar snel even via de trial-and-error aanpak proberen grip te krijgen op de situatie. Maar trial-and-error is een soort van paniekreactie en paniek is meestal geen goede raad- gever. Niet zelden introduceer je hiermee meer nieuwe bugs dan dat je er bestaande bugs mee oplost. Even achterover leunen en een goede analyse van het probleem uitvoeren werkt beter. En enige praktijkervaring helpt natuurlijk ook enorm…

Uit eerdere projecten heb ik geleerd ik dat dit soort problemen vaak veroorzaakt worden doordat er op een ongecontrolleerde manier in het werkgeheugen (SRAM) geschreven wordt, juist op plekken waar dat op dat moment niet hoort. Programma-variabelen veranderen hierdoor onterecht van waarde en het gedrag van je sketch wordt er compleet onvoorspelbaar door.

Basiskennis

Nog even wat basiskennis opfrissen want hoe zat het ook alweer? De meeste μ-controllers beschikken over twee soorten geheugen: ‘FLASH geheugen’ voor de opslag van programmacode en andersoortige constante informatie en ‘SRAM geheugen’ voor de opslag van allerlei veranderlijke informatie (lees: variabelen).

Een Arduino Uno beschikt over 32kByte aan FLASH geheugen en 2kByte aan SRAM. Niet zo veel als je dat vergelijkt met een PC. Het is dus zaak om er zuinig mee om te springen. Zeker het SRAM geheugen dient zo efficient mogelijk ingezet te worden. Vandaar dat er in de programmeertaal onderscheid gemaakt wordt tussen zgn ‘statische’ en ‘dynamische‘ variabelen.

SRAM gebruik

Statische variabelen zijn bedoeld voor de opslag van informatie waarvan de inhoud (=waarde) voortdurend bewaard moet blijven, dwz zolang het programma aktief is. In de broncode vind je deze variabelen bijvoorbeeld bovenaan de sketch, dus buiten de setup() en de loop(). Statische variabelen worden normaliter opgeslagen in het onderste deel van de SRAM, het zgn ‘heap-geheugen‘.

Tijdens het compileren van de sketch bouwt de compiler een lijst op van alle statische variabelen, incl het type (char, int, long, etc). Met die lijst wordt de benodigde SRAM opslagcapaciteit berekend en bij het starten van het programma wordt die ruimte gereserveerd in het heap-geheugen. Dit heap-geheugen heeft normaliter een vaste grootte.

Dynamische variabelen daarintegen zijn bedoeld voor informatie die slechts tijdelijk beschikbaar hoeft te zijn. Dynamische variabelen worden dus pas in het geheugen opgeslagen zodra en voor zolang ze echt nodig zijn. Voorbeelden zijn functie-parameters en variabelen die binnen de functies gedeclareerd worden. Ze claimen pas geheugen zodra de functie aangeroepen wordt en geven het geheugen weer vrij weer zodra de functie afgerond is. Dynamische variabelen worden opgeslagen in het ‘stack-geheugen‘.

int gemiddelde;                    // gemiddelde = static

void meting(int aantal)            // aantal = dynamic
{
  int i;                           // i = dynamic
  int meetwaarde = 0;              // meetwaarde = dynamic

  for (i=0; i<aantal; i++)
    meetwaarde += analogRead(0);

  gemiddelde = meetwaarde/aantal;
}

void loop()
{
  meting(4);                       // "4" = constant
  serial.println(gemiddelde);
}

Vaak hangt het van externe gebeurtenissen af (schakelaars, sensoren, etc) welke functies aangeroepen zullen worden en in ook welke volgorde. Daarbij komt het ook vaak voor dat functies elkaar aanroepen. Daarom is het tijdens het compileren van je sketch vrijwel onmogelijk om uit te rekenen hoeveel stack-geheugen je sketch maximaal nodig zal hebben. Het stack-geheugen zal gedurende het verloop van je programma dus willen ‘ademen’ (= groeien en weer krimpen). Wees gerust, je hebt er zelf geen omkijken naar, de compiler regelt dit allemaal netjes voor je. Tenminste, zolang er voldoende vrij geheugen is.

Stack overflow

Wanneer het vrije geheugengebied tussen de stack en de heap onvoldoende groot is dan ontstaat het risico dat de ‘stack’ over de ‘heap‘ heen kan groeien. We spreken dan van ‘stack overflow‘ en da’s een gevaarlijke situatie want meerdere variabelen gebruiken op dat moment hetzelfde gebiedje in het SRAM geheugen. Het wijziging van de inhoud van de ene variabele betekent automatisch ook dat de waarde van een andere variabele mee verandert, met onvoorspelbaar gedrag van de sketch tot gevolg.

Stack-overflow‘ kan verschillende oorzaken hebben. Vaak is het een combinatie van teveel aanroepen van functies binnen functies die ieder wellicht ook nog eens veel dynamische variabelen gebruiken. Een typisch voorbeeld is het gebruik van recursief programmeren. Op een PC zelden een probleem, maar op een microcontroller loop je al snel uit het SRAM geheugen. Illustratief hiervoor is het uitrekenen van de faculteit van een getal ( N! ), zoals bijvoorbeeld 6! = 6*5*4*3*2*1 = 720. Een beetje goochelen met cijfers leert dat je 6! ook als volgt zou kunnen uitrekenen: 6! = 6*5!. En 5! op zijn beurt weer als 5! = 5*4!. Wanneer je recursief programmeert riskeer je al vrij snel stack-overflow. Immers, bij elke keer dat de functie zichzelf aanroept worden de zowel de functie-parameter alsook de lokale variable tijdelijk op de stack bewaard. De stack groeit dus met de waarde van N, zie voorbeeld hieronder.

unsigned long faculteit_recursief(int N)
{
  unsigned long uitkomst;

  if (N > 1)
    uitkomst = N * faculteit(N-1);
  else if (N == 1)
    uitkomst = 1; 
  else if (N == 0) 
    uitkomst = 1;  
  else
    uitkomst = 0; // error!!
  return(uitkomst);
}

void loop()
{ 
  unsigned long einduitkomst;

  einduitkomst = faculteit_recursief(10);
  serial.println(einduitkomst);
}

Memory leakage

Free-The-Malloc()s

Een beginnende programmeur zal het niet snel doen maar soms wil of kun je het beheer van het SRAM geheugen niet aan de compiler overlaten. Bijvoorbeeld voor het beheren van een tabel waarvan je tevoren de lengte of de inhoudsvolgorde niet kunt voorspellen, denk aan een telefoonlijst. Aan zo’n tabel wil je flexibel nieuwe contacten kunnen toevoegen of verwijderen. In zo’n geval gebruik je bijvoorkeur een linked-list maar dan moet je daarvoor wel zelf geheugen kunnen reserveren en weer vrijgeven. De Arduino programmeertaal biedt daarvoor net als veel andere programmeertalen de functies ‘malloc()‘ voor het reserveren van stukje SRAM geheugen en ‘free()‘ om stukjes SRAM geheugen weer vrij te geven.

Dynamisch geheugenbeheer vraagt een goede administratie, een strakke discipline en zorgvuldig programmeren. Want wanneer je geheugen per ongeluk niet meer vrij geeft maar wel telkens nieuwe stukjes geheugen reserveert dan ontstaat zgn memory leakage. Het vrije geheugen raakt langzaam maar zeker op, er treedt een stack-overflow op en je programma loopt vast. Op een PC merk je dat waarschijnlijk pas na dagen gebruik (famous blue screens), maar op een Arduino loop je snel uit het beschikbare geheugen. Dus alleen gebruiken als je voldoende programmeerkennis hebt!

Hoeveel SRAM geheugen heb ik eigenlijk nog beschikbaar?

De Arduino beschikt jammer genoeg niet over een standaard functie waarmee je de hoeveelheid vrije SRAM rechtstreeks kunt opvragen. Eigenlijk best jammer, maar niet getreurd. In de Arduino playground omgeving hebben andere programmeurs hiervoor meerdere bruikbare functies beschikbaar gesteld. Ikzelf heb positieve ervaring met de availableMemory() functie van David A. Mellis. Niet de snelste maar wel effectief en kort en ook eenvoudig te doorgronden. Door te experimenteren deze ‘availableMemory()’ functie leerde dat ik dat een Arduino sketch standaard de helft van het beschikbare SRAM (1024 bytes) reserveert voor de heap (en voor interne administratie) en dat de andere helft (ook 1024 bytes) beschikbaar blijft voor de stack.

Het declareren van een handjevol LED-kubuspatronen bleek de hoeveelheid vrije SRAM dan ook niet te beinvloeden, die paar patronen passen kennelijk prima binnen de standaard heap-grootte. Maar wanneer je 1-voor-1 nieuwe LED-kubuspatronen blijft toevoegen dan kom je op een gegeven moment voorbij het punt waarop de standaard heap-grootte niet meer toereikend is. Vanaf dat punt reserveert de compiler extra heap-geheugen en zal de hoeveelheid vrije SRAM evenredig afnemen, tot het op een gegeven moment gewoon op is. En hoewel het toevoegen van LED-kubuspatronen ervoor zorgt dat juist de heap en niet zozeer de stack groeit, neemt het risico op ‘stack-overflow‘ wel toe. Op het punt dat mijn sketch rare kuren begon te vertonen had ik niet meer dan 23 bytes vrij SRAM geheugen meer over. Met mijn analyse zat ik dus op het juiste spoor.

Dat de nieuwe LED-kubuspatronen juist in SRAM terecht kwamen verbaasde mij in eerste instantie. Ik was in de veronderstelling dat ze in FLASH opgeslagen zouden worden en dus geen significante invloed zouden hebben op de beschikbare hoeveelheid SRAM. Achteraf (altijd achteraf) is dat toch wel verklaarbaar; in mijn sketch waren de patronen als een ‘unsigned long’ array gedefinieerd, zie onder, dus een SRAM variabele.

unsigned long LED_pattern[] = {
  0b00000000000000000000000111111111,
  0b00000000000000111101111000010000,
  0b00000111101111000010000000000000,
  0b00000111111111000000000000000000,
  0b00000000010000111101111000000000,
  0b00000000000000000010000111101111,
};

Op zoek naar de oplossing

Mijn eerste ingeving was om er ‘constantes’ van te maken, dus het toevoegen van het keyword ‘const‘ zou het probleem vast oplossen, zie onder.

const unsigned long LED_pattern[] = {
  0b00000000000000000000000111111111,
  0b00000000000000111101111000010000,
  0b00000111101111000010000000000000,
  0b00000111111111000000000000000000,
  0b00000000010000111101111000000000,
  0b00000000000000000010000111101111,
};

Maar helaas, het ‘const’-keyword is een qualifier die welliswaar het gedrag van de variabele verandert, maar het blijft een SRAM variabele. Het toevoegen heeft alleen tot gevolg dat de compiler weet dat de inhoud niet overschreven mag worden en dus een foutmelding geeft als je dat toch probeert.

Het keyword waarmee je kunt forceren dat een constante wel in het FLASH geheugen terecht komt is PROGMEM, een onderdeel van de ‘pgmspace‘-library. Het toevoegen van de library en het keyword is voldoende, de rest van de sketch kan ongewijzigd blijven.

#include <avr/pgmspace.h>

PROGMEM unsigned long LED_pattern[] = {
  0b00000000000000000000000111111111,
  0b00000000000000111101111000010000,
  0b00000111101111000010000000000000,
  0b00000111111111000000000000000000,
  0b00000000010000111101111000000000,
  0b00000000000000000010000111101111,
};

Pfjew… PROBLEM SOLVED! De voorbeeldcode van een eerdere blog over de 3x3x3 LED kubus heb ik inmiddels aangepast. Veel succes en plezier met het zelf aanmaken van nieuwe LED-kubuspatronen.

Categories
Instructable

Digitaal filteren van analoge sensoren

Last van meetruis of van een te grove meetresolutie? Het middelen van meetwaardes kan helpen. Maar dan niet simpelweg optellen en delen van een korte burst aan meetwaardes, want dat heeft zo zijn beperkingen. Een Moving Average Filter werkt beter; een eenvoudig en efficient digitaal filter dat niet zo maf is als de afkorting doet vermoeden. En ruis is eigenlijk ook niet zo slecht als het lijkt, je kunt er namelijk ook je voordeel mee doen. Hoe dat werkt? Deze blog legt het je uit.

Ongefilterd

ruwe meetwaardes, interval=100[ms]

Stel je hebt een TMP36 temperatuursensor aangesloten op een Arduino, een veel voorkomende (deel-)schakeling. Toen ik daarmee voor de eerste keer een meting deed viel me op dat de meetresolutie slechts 0,5[ºC] was, zie figuur. Vreemd eigenlijk want de datasheet van de TMP36 sensor geeft aan dat een nauwkeurigheid van 0,1[ºC] prima haalbaar is. De verklaring is simpel; de temperatuursensor heeft een gevoeligheid van 10[mV/ºC] en de Arduino ADC waarmee de meetwaarde wordt ingelezen gebruikt 10 bits voor een meetbereik van 5[V]. Dit resulteert een resolutie van ongeveer (5,0[V]/1024=) ~5[mV/bit] oftewel 0,5[ºC] per bit. Wat verder opvalt is dat er zo nu en dan ook ‘spikes’ in het signaal voorkomen ter grootte van +/-0,5[ºC], zeer waarschijnlijk een kleine signaalruis waardoor de ADC meetwaarde zo af en toe gewoon 1 bit hoger of lager uitvalt.

Referentie-code:

loop ()
{
  meetwaarde = analogRead(0);
  delay(100);
}

Recht-toe-recht-aan middelen van meetwaardes

middelen van 16 meetwaardes

Een vaak gebruikte manier om de meetresolutie te verbeteren en de ruis te verminderen en is het middelen van enkele samples. De theorie leert immers dat de meetresolutie evenredig is met het aantal meetwaardes waarover je middelt; met elke verdubbeling van het aantal meetwaardes verdubbelt ook de resolutie. Door het middelen van 16 meetwaardes krijg je dus een temperatuurmeetresolutie van 0,03[ºC].

Potentieel, want zoals de figuur hiernaast laat zien heeft de middeling inderdaad enig effect, maar lang niet op alle gewenste plekken, de ‘plateaus’ verraden nog steeds een effectieve meetresolutie van 0,5[ºC]. De verbeterde resolutie is alleen waarneembaar rondom de flanken tussen de plateaus en ook sommige spikes zijn kleiner geworden, maar zeker niet allemaal! Filteren heeft nl alleen een effect als de meetwaardes waarover je middelt van elkaar verschillen. En verschillen treden in dit voorbeeld vooral op bij de flanken tussen de plateaus en rondom spikes en niet halverwege de plateaus.

Het toevoegen van een klein beetje analoge ruis bovenop het echte temperatuursignaal, dus aan de ingang van de ADC, kan helpen om de resolutie te verbeteren. Want, aangenomen dat de extra ruis een gemiddelde waarde van ‘0’ heeft dan zal de gemiddelde analoge meetwaarde dus onveranderd blijven, maar door de extra ruis ontstaat er wel een (kleine) variatie rondom dat gemiddelde. Door die kleine variatie wordt het oorspronkelijke patroon van constante meetwaarden doorbroken en krijgt het middelingsproces alsnog een kans om waarde toe te voegen. In de audio- en videotechniek wordt dit proces ook wel ‘dithering‘ genoemd.

Helaas is het toevoegen van ‘nette’ ruis niet eenvoudig, maar reeds aanwezige ruis onderdrukken met een analoog filter levert dus niet perse een voordeel op.

Referentie-code:

const int N = 16; 
loop ()
{
  meetwaarde = 0;
  for (int i=0; i<N; i++)
    meetwaarde += analogRead(0);
  meetwaarde /= N;
  delay(100);
}

Middelen met slim gekozen intervaltijd

middelen met langere intervaltijden

Om beter te kunnen filteren heb je dus meetwaardes nodig die onderling van waarde verschillen anders heeft het middelen geen effect. Om variatie in meetwaardes te bereiken dien je het interval tussen de meetwaardes slim te kiezen; dwz, een waarde die in goede verhouding staat tot de tijdconstante (τ) van je systeem (τ is de tijd die nodig is om ca 65% van de beoogde verandering teweeg te brengen). Zonder dit verder wetenschappelijk te willen onderbouwen is een filtersnelheid van ~0.1*τ een goede vuistregel. Voorbeeld: veronderstel een systeem met een tijdconstante van τ=15[sec]. Daarbij past prima een filter met een filtersnelheid van 1.6[sec]; dwz een filter waarbij we telkens 16 meetwaardes middelen met een meetinterval van ~100[msec]. In het figuur is te zien dat met een dergelijk filter alle spikes verdwenen zijn en dat de flanken tussen de plateaus mooi geleidelijk verlopen. Uiteraard is een vuistregel slechts een vuistregel en is tunen op de praktijksituatie altijd aan te raden. Een sneller filter zorgt ervoor dat de het filtereffect steeds minder wordt en het gedrag steeds meer gaat lijken op de eerder besproken filterimplementatie. Een trager filter zorgt ervoor dat de gefilterde meetwaarde steeds langzamer reageert op snelle temperatuursveranderingen.

Deze manier van middelen heeft wel een belangrijk nadeel. De tijd dat de Arduino bezig is met de meting is nl behoorlijk lang en zolang de meting loopt is het voor een gemiddelde programmeur best lastig om de Arduino ook nog andere taken te laten uitvoeren. Denk aan het updaten van een display, het aansturen van een servo, etc, etc.

Referentie-code:

const int N = 16; 
loop ()
{
  meetwaarde = 0;
  for (int i=0; i<N; i++) {
    meetwaarde += analogRead(0);
    delay(100);
  }
  meetwaarde /= N;
}

Middelen met een “Moving Average Filter”

Middelen met een Moving Average Filter

Het “Moving Average Filter” biedt een oplossing voor het bovengenoemde probleem. In plaats van telkens opnieuw 16 metingen uit te voeren maken we slim hergebruik van 15 voorgaande metingen en voeren we telkens slechts 1 nieuwe meting uit. Hierdoor kost een meting per keer slechts 100[msec] en niet telkens 1600[msec] zoals in het vorige voorbeeld.

Bovendien vertoont het filter een nog vloeiender verloop van de gefilterde meetwaardes omdat de opeenvolgende meetintervallen ditmaal telkens een (100*15/16 =) 94% overlap hebben.

Referentie-code: 
const int N = 16;
int meetwaardes[N];
int i = 0;

loop ()
{
  meetwaardes[i] = analogRead(0);      // vervang oudste meetwaarde
  i++; i %= N;                         // teller loopt van 0 tot N-1

  // bereken filterwaarde
  int filterwaarde = 0;                
  for (int j=0; j<N; j++)
    filterwaarde += meetwaardes[j];
  filterwaarde /= N;

  delay(100); 
}

Bonus:

Tenslotte kan er algoritmisch nog een kleine optimalisatie uitgevoerd worden waardoor de Arduino minder rekentijd nodig heeft voor het uitrekenen van de gemiddelde waarde. Vanwege het “moving average” karakter van het filter kan de standaardberekening:

gemiddelde_waarde = som(meetwaarde) / N

vervangen worden door:

gemiddelde_waarde = (vorige_somwaarde – oudste_meting + nieuwste_meting) / N

Hierdoor worden in plaats van 16 telkens slechts 2 optelberekeningen uitgevoerd. Marginaal voor zo’n kort MA-filter, maar zeer rekentijd besparend naarmate het filter ‘langer’ gekozen wordt.

Rekentijd geoptimaliseerde referentie-code:

const int N = 16;           // aantal te middelen meetwaardes
int meetwaardes[N];         // opslag van individuele meetwaardes
int filteraccumulator = 0;  // optelsom van alle individuele meetwaardes
int i = 0;                  // meetwaardeteller

loop ()
{
  filteraccumulator -= meetwaardes[i]; // vergeet oudste meetwaarde
  meetwaardes[i] = analogRead(0);      // bewaar nieuwe meetwaarde
  filteraccumulator += meetwaardes[i]; // accumuleer nieuwste meetwaarde
  i++; i %= N;                         // teller loopt van 0 tot N-1

  filterwaarde = filteraccumulator/N;  // bereken de gemmiddelde waarde

  delay(100); 
}
Categories
Arduino Instructable

3x3x3 LED kubus

Niet de meest geavanceerde LED kubus maar wel eentje die relatief eenvoudig te maken en te begrijpen is omdat er nauwelijk extra elektronica nodig is om de kubus aan te sturen met een Arduino. Geen moeilijke (seriele) protocollen dus maar gewoon digitale I/O pennen ‘hoog’ (= “1” = “true”) en ‘laag’ (= “0” = “false”) schakelen. En voor wie hem zelf wil bouwen; het elektrisch schema, de source code en zelfs een Fritzing PCB layout, ze zijn hier allemaal te downloaden.

De hardware

Maar eerst een kort stukje elektronica-theorie. Een LED geeft pas licht als je er in de juiste richting stroom doorheen laat lopen. In het schema rechts is een LED aangesloten op twee digitale I/O pennen van de Arduino; 12 en 2 (= arbitraire keuze). Wanneer we pin 12 ‘hoog’ schakelen en pin 2 ‘laag’ dan loopt de stroom in de juiste richting door de LED waardoor deze licht geeft. Bij elke andere combinatie van ‘hoog’ en ‘laag’ staat de LED uit. De weerstand van 220[Ω] dient ervoor om de LED-stroom te beperken tot ca 10[mA], voor de meeste LEDs een prima waarde.

Voor het aansturen van LEDs heeft een Arduino Uno maximaal 14 digitale I/O pennen maar let op: pennen 0 en 1 zijn al in gebruik voor de USB interface. De uitdaging is nu om met de 12 beschikbare I/O pennen zoveel mogelijk LEDjes te kunnen schakelen, liefst natuurlijk alle 3x3x3=27 van de LED kubus.

En met de nevenstaande schakeling lukt dat prima mits je accepteert dat er in software iets extra’s nodig is om leuke licht-patronen te kunnen maken, maar da’s bij LED aansturingen heel gebruikelijk (meer daarover later bij het bespreken van de software).

In ons ontwerp hebben we de kubus verdeeld in drie horizontale vlakken. Voor het gemak zijn de vlakken met verschillende kleuren in het schema getekend, al zul je in de praktijk natuurlijk allemaal dezelfde kleur LEDs kiezen. De I/O pennen 5 t/m 13 sturen elk een van de negen verticale kolommen van ieder drie LEDs aan. De resterende I/O pennen (2 t/m 4) worden gebruikt voor het aan-/uitschakelen van de drie horizontale vlakken. Dus, om 1 specifieke LED uit de kubus aan te kunnen zetten moet een specifieke kolom ‘hoog’ (=’1′) ingesteld worden en 1 specifiek vlak ‘laag’ (=’0′). En om te voorkomen dat andere LEDs ook gaan branden moeten alle overige kolommen ‘laag’ en alle overige vlakken ‘hoog’ gemaakt worden.

Bewust meerdere LEDjes tegelijkertijd laten branden kan natuurlijk ook. Bijvoorbeeld door meerdere kolommen hoog (=”1″) te maken. Straks zullen we hiervan in onze software bewust gebruik gaan maken. Maar omdat er in het uiterste geval per vlak 9 LEDjes tegelijkertijd aan kunnen staan kan de totale stroom per vlak oplopen tot zo’n 90[mA]. Een Arduino pen kan volgens specificaties max. 40[mA] aan. Vandaar dat er per vlak nog een kleine schakeltransistor (2N2222A of BC546B) nodig is, zie het elektrisch schema. Deze transistor heeft echter een ‘inverterende’ werking. Dwz, een vlak wordt ‘laag’ (=’0′) gemaakt door de betreffende I/O pen juist ‘hoog’ (=’1′) te maken. Dat lijkt even wat verwarrend maar het went snel :-).

Voor de liefhebbers is hier ook nog een PCB layout (let op: ongetest) om LED kubus als Arduino shield te kunnen bouwen. Het eerste LED vlak wordt rechtstreeks op de PCB gemonteerd. Voor het verbinden van de 2e en 3e LED vlakken met de bijbehorende schakeltransistoren zijn enkele soldeerpads voorzien.

Een uitleg over de montage is te vinden in een andere blog.

 

 

 

De software

Optimalisatie in de hardware gaat vaak gepaard met een extra inspanning in de software (en andersom). En omdat we in dit LED kubus ontwerp bezuinigd hebben op het aantal I/O pennen moeten we in de software nu dus iets extra’s doen om alle willekeurige LED patronen te kunnen blijven maken. Met het huidige hardware ontwerp is het bijvoorbeeld niet vanzelfsprekend om het LEDje-link-boven-achter samen met het LEDje-links-voor-onder aan te zetten terwijl alle andere LEDjes uit staan (ik leg dat verder niet uit, lijkt me een leuk zomeravond puzzeltje).

De oplossing (of work-around) heet “tijd-multiplexen”, dwz dat je om-en-om het ene LED-vlak en daarna het andere LED-vlak aan zet. En als je dat heel snel afwisselt lijkt het net alsof de LEDjes van de drie vlakken toch tegelijkertijd aan staan terwijl ze in werkelijkheid 66% van de tijd uit staan. NB: per LEDje  is de effectieve lichtopbrengst dus ook teruggezakt tot slechts 33%!

Net als bij een TV moet de herhaalfrequentie minimaal zo’n 50[Hz] zijn voor een flickervrij beeld. Sneller mag natuurlijk ook maar dan zal de effectieve lichtopbrengst nog wat verder terugzakken omdat alle LEDjes tijdens het omschakelen ook heel even uit staan.

De flowchart hiernaast geeft weer hoe dat er in software uit ziet. In de hoofdlus (links) wordt telkens een LED patroon uit een tabel gelezen. Vervolgens wordt een aparte functie aangeroepen om de LEDs conform het huidige patroon aan en uit te zetten. Dat weergeven gebeurt per vlak apart, maar de herhaalfrequentie is zo hoog dat je niet merkt dat de vlakken om-en-om aan staan. Nadat het huidige patroon voldoende lang getoond is, wordt teruggegaan naar de hoofdlus waar een nieuw patroon uit de tabel opgehaald wordt, etc. En zodra alle patronen uit de tabel aan de beurt geweest zijn wordt weer gewoon vooraan begonnen.

Een LED-patroon is een reeks ‘1’-en en ‘0’-en die samen aangeven welke LEDs er tegelijkertijd aan moeten staan. In ons geval gebruiken we een “unsigned long” waarvan elk bitje 1 LED vertegenwoordigd. De 9 meest rechtse (LSB) bits vertegenwoordigen de LEDjes van vlak 1, de volgende 9 horen bij vlak 2 en de daarop volgende 9 bij vlak 3. Van de 32 beschikbare bitjes worden er om praktische redenen dus maar 27 gebruikt.

In de software (zie code hieronder) wordt per vlak beoordeeld (bitje=1?) welk LEDje moet branden en wordt de betreffende kolom (=’anode’) ‘hoog’ gemaakt. Als alle bitjes uit het vlak zijn beoordeeld wordt vlak 1 aangezet door de bijbehorende I/O pen (=’kathode’) ook ‘hoog’ te maken. Nadat de LEDjes een korte tijd (ca 10[msec]) aan zijn geweest worden ze weer uitgezet door alle kolommen en vlakken laag te maken. Daarna wordt hetzelfde gedaan voor vlak2 en vlak 3.

 

Tenslotte: klik hier om het volledige hard- en software-design te downloaden.

 

 

Wanneer je meer wilt…

Als zelfs een Arduino qua bouwvolume te groot is kun je een Teensy overwegen. In veel opzichten vergelijkbaar met de Arduino UNO maar veel compacter en ook iets goedkoper.

Wanneer het timemultiplexen ongewenst is omdat het de lichtopbrengst van je LED kubus te nadelig beïnvloed of wanneer je een grotere LED kubus wilt dan kun je niet meer volstaan met een Arduino Uno. Als eerste kun je een upgrade overwegen naar de Arduino MEGA. Deze heeft 54 digitale I/O pennen waarop de 27 LEDs rechtstreeks aangesloten kunnen worden. Ook de Teensy++ is het overwegen waard. De Teensy++ is qua functionaliteit vergelijkbaar met de Arduino MEGA maar is net als de gewone Teensy veel compacter.

Maar als je ook daarmee niet vooruit kunt, bijvoorbeeld omdat je een 4x4x4 of een RGB kubus wilt maken, dan ontkom je er niet aan om ook extra elektronica toe te voegen. Er zijn verschillende varianten denkbaar. In deze blog zal ik ze alleen kort beschrijven, wellicht kom ik er in een latere blog nog eens uitvoeriger op terug.

74HC595

Dit is een low-cost serial-to-parallel shift-out register dat middels een seriële (SPI) interface communiceert met de Arduino. Door 2 I/O pennen van de Arduino op te offeren krijg je 8 output pennen terug. En het leuke is dat je deze shift registers kunt cascaderen. Dus zonder verlies van extra I/O pennen op de Arduino krijg je er per chipje dus telkens 8 output pennen bij.

TLC5940

Deze Texas Instruments chip beschikt over 16 PWM kanalen elk 120[mA] kunnen leveren bij Vcc-5[V]. Ideaal voor het aansturen van LEDs. De chip wordt aangestuurd middels een seriele interface en het leuke is dat er ook al een Arduino software library voor beschikbaar is. Dat scheelt dus een boel programmeren. Ook hardwarematig kun je jezelf werk besparen door gebruik te maken van de Sparkfun PWM shield of de TLC5940-breakout. Een kind kan de was doen.