In een voorgaande knutselaerij wordt het het ineen knutselen van een bij fischertechnik te gebruiken controller met een Arduino Pro Mini Atmega328P beschreven.
Zodra de hardware als prototype in elkaar gezet was, kon het experimenteren met het programmeren van de Zauberling beginnen. Een van de uitgangspunten was bijvoorbeeld veel functionaliteit over te nemen van andere fishertechnik modules.
Gaandeweg ontstonden ook ideeën ter uitbreiding en/of verbetering van deze functionaliteit. In dit artikel ga ik daar wat nader op in.
Een succesvol magiër moet een goede goochelstaf, betoverende kleding en wonderlijke tovervoorwerpen hebben. De 'hardware' moet in orde zijn. Maar voor het verrichten van de ware wonderen, is de leergierigheid op het gebied van toverspreuken en bezweringen doorslaggevend. De betovering is compleet met de juiste magische formule, en het is juist de combinatie van toverstaf en toverspreuken waarin de ware magie schuilt. Laten eens te kijken naar het grote experimentele goochelboek: de software van de Zauberling.
Het prettige van de Arduino Pro Mini Atmega328P is dat deze zich, zodra de brug naar de TTL-interface van het kleine printje geslagen is, eenvoudig vanuit de Arduino IDE laat programmeren. Op die manier kan de software in principe altijd in ontwikkeling blijven en eenvoudig worden uitgebreid of aangepast. Nadat ik enkele testprogramma’s had gemaakt voor het controleren van de aansturing van de motor- en servo-uitgangen, startte ik met het nabouwen van de algemene functionaliteit van de E-Tec en Elektronics modules. Doordat de software van de Zauberling zo eenvoudig aan te passen is, paste ik het ‘Basisprogramma’ meteen op enkele punten aan. In deel 3 van dit artikel wordt daarmee een toepassing aangestuurd. In dit deel leest u welke andere trucs de Zauberling op dit moment al onder de knie heeft.
Op het front van de Zauberling is met DIP-schuifschakelaars instelbaar welk ‘programma’ of stuurfunctie moet worden uitgevoerd. Hierdoor is het, net als met de E-Tec module, mogelijk snel te wisselen tussen diverse programma’s. Vooral voor een programmeerbare module als de Zauberling is dat tijdens de ontwikkeling van software erg handig. Terwijl bijvoorbeeld aan een verbeterde versie van bepaalde functionaliteit wordt gewerkt, kan een eerdere stabiele versie van deze functionaliteit ook gewoon nog ‘onder de knop’ worden gehouden.
De Zauberling is nog een eerste prototype en de programmatuur daardoor nog in ontwikkeling. Onderstaande tabel toont wat reeds, in verschillende stadia van perfectie, is gerealiseerd.
Het ‘Basisprogramma’ is bekend van o.a. de E-Tec module en vereist drie schakelaars op de ingangen. Indien schakelaar 1 wordt gedrukt, begint de motor linksom te draaien. Indien schakelaar 2 wordt gedrukt, begint de motor rechtsom te draaien. Bij drukken op schakelaar 3 stopt de motor. Een kleine wijziging die ik maakte, is dat door nogmaals drukken op schakelaar 3 de motor de laatste draairichting na de stop hervat.
Prog | DIP1 | DIP2 | DIP3 | DIP4 | I1 Logica | I2 Logica | I3 Logica | Funktie | Potentiometer |
---|---|---|---|---|---|---|---|---|---|
0 | - | - | - | - | Negatief | Negatief | Negatief | Basisprogramma met gelijkmatig toerentalverloop | Tijd 0~2500ms |
1 | - | - | - | ON | Positief | Positief | Positief | Basisprogramma met gelijkmatig toerentalverloop | Tijd 0~2500ms |
2 | - | - | ON | - | Auto | Auto | Auto | AND/NAND−Poort | Drempelwaarde Sensoren |
3 | - | - | ON | ON | Auto | Auto | Auto | OR/NOR−Poort | Drempelwaarde Sensoren |
4 | - | ON | - | - | Auto | Auto | Auto | XOR/XNOR−Poort | Drempelwaarde Sensoren |
5 | - | ON | - | ON | Auto | Auto | Auto | SR-Flip Flop - SET=IN1, CLK=IN2, RESET=IN3 (R is dominant) | Drempelwaarde Sensoren |
6 | - | ON | ON | - | Auto | Auto | Auto | JK-Flip Flop - J=IN1, CLK=IN2, K=IN3 | Drempelwaarde Sensoren |
7 | - | ON | ON | ON | Auto | Auto | Auto | D-Flip Flop met Reset | Drempelwaarde Sensoren |
8 | ON | - | - | - | Auto | Auto | Auto | Monoflop met Reset (tijd met Potentiometer instelbaar) | Pulstijd 10~2500ms |
9 | ON | - | - | ON | Auto | Auto | Auto | Zwaailicht, snelheid instelbaar | Frequentie |
10 | ON | - | ON | - | Auto | Auto | Auto | Flitslicht, snelheid instelbaar | Frequentie |
11 | ON | - | ON | ON | - | - | - | Toekomstige projecten :-) | - |
12 | ON | ON | - | - | - | - | - | Toekomstige projecten :-) | - |
13 | ON | ON | - | ON | - | - | - | Toekomstige projecten :-) | - |
14 | ON | ON | ON | - | - | - | - | Demo: Motor draairichtingingen | - |
15 | ON | ON | ON | ON | - | - | - | Demo: Servobewegingen | - |
bit3 | bit2 | bit1 | bit0 |
Het is doorgaans belangrijk te weten of een schakelaar of sensor aan de ingang in ruststand open of gesloten is en daarmee hoe het detecterende gedrag moet worden geïnterpreteerd. Voor een programma als het ‘Basisprogramma’ in de E-Tec module is dit bijvoorbeeld zinvol, omdat één van de schakelaars bij het inschakelen van de module al kan zijn ingedrukt en de motor dan dus direct in de juiste richting moet gaan lopen om deze weer vrij te spelen.
Anderzijds is het prettig aan de ingangen zowel spanningsdalingen als spanningsstijging als logische detectieniveaus te kunnen gebruiken. Voorbeelden van sensoren die een spanningsstijging bewerkstelligen als ze moeten melden, zijn bijvoorbeeld de foto-transistoren uit een lichtkast of een schakelaar die in ruststand aan massa is gelegd. Sommige sensoren reageren echter net andersom, zoals bijvoorbeeld het uitgangssignaal van actieve IR-obstacle sensor in rust 5 volt is en dit bij detectie van een obstakel juist naar nul volt daalt. Je zou dit ‘negatieve logica’ kunnen noemen.
Om deze reden had ik mijzelf de uitdaging gesteld de verwerking van de ingangssignalen van de Zauberling zo uniform mogelijk te houden. De module kan flexibeler gebruikt worden als (bijna) alle soorten sensoren en logica aan de ingangen door elkaar kunnen worden gebruikt. Meestal is immers slechts signalering van de afwijkende uitgangsstand voldoende als schakelende impuls.
Het is natuurlijk mogelijk bij het inschakelen (of na een reset) van de Zauberling, de gemeten ingangswaarden op te slaan als referentiewaarden. Met de potentiometer op het front kan een drempelwaarde worden ingesteld. Een ingang wordt ‘actief’ zodra daarna de overeenkomstige referentiewaarde met meer dan de drempelwaarde wordt overschreden. Het maakt hierbij niet uit of de waarde naar boven, of naar onder, van de referentiewaarde afwijkt. De ingestelde drempelwaarde dient bovendien als maat voor de hysterese voor sensoren die na detectie slechts geleidelijk terugkeren op hun uitgangswaarde en hierbij door het gebied rond de drempelwaarde gaan. Hierdoor gaat de ingang niet ‘klapperen’ wanneer de uitganswaarde van de sensor zich in het gebied rond de detectiedrempel beweegt. Het detectiegedrag van een langzaam naar de referentiewaarde terugkerende sensor wordt op deze manier getemperd.
De software zal nog wel even in ontwikkeling zal blijven. Het code-fragment hiernaast toont (sterk vereenvoudigd) de meting van de uitgangswaarden en hoe met de treshold en hysterese wordt omgegaan.
Door deze truc zijn de ingangen van de Zauberling met een grote verscheidenheid aan sensoren te gebruiken. Actieve sensoren zoals de IR-obstacle sensor, de PIR-bewegingssensor of een hall-effect sensor kunnen hierdoor ook worden gebruikt. De enige voorwaarde is dat de referentiewaarde bij aanvang kan worden gemeten met een ‘ongeactiveerde’ sensor. Aangezien de meeste regelingen de sensoren voornamelijk als detector gebruiken, wordt aan deze eis in de praktijk vaak voldaan.
Maar er kunnen natuurlijk specifieke uitzonderingen zijn. Voor sommige regelingen (zoals bijvoorbeeld het ‘Basisprogramma’ is het beter als het type sensor en het gedrag vast kan worden gekozen. De software is zodanig opgezet, dat voor het ‘Basisprogramma’ deze keuze ook expliciet moet worden gemaakt. Er zijn twee varianten opgenomen zodat het zowel met de klassieke sensoren met positive logica (zoals de vertrouwde lichtkast met foto-transistor), als met sensoren met negatieve logica kan worden ingezet.
void setup() {
…
in1Default = analogRead(IN1);
in2Default = analogRead(IN2);
in3Default = analogRead(IN3);
…
…
}
void loop() {
…
…
potValue = analogRead(POTMETER);
sensorTreshold = map(potValue, MINREG, MAXREG, 1, TRESHOLD_MAX);
…
…
// Read inputs ,take hysteresis into account
in1Value = analogRead(IN1);
if (abs(in1Value-in1Default) > sensorTreshold) {
in1ValueTrigger = in1Value;
in1Active = true;
} else {
if (abs(in1Value-in1ValueTrigger) > sensorTreshold/2) { // Hysteresis...
in1Active = false;
in1TriggerUsed = false;
}
}
in2Value = analogRead(IN2);
if (abs(in2Value-in2Default) > sensorTreshold) {
in2ValueTrigger = in2Value;
in2Active = true;
} else {
if (abs(in2Value-in2ValueTrigger) > sensorTreshold/2) { // Hysteresis...
in2Active = false;
in2TriggerUsed = false;
}
}
in3Value = analogRead(IN3);
if (abs(in3Value-in3Default) > sensorTreshold) {
in3ValueTrigger = in3Value;
in3Active = true;
} else {
if (abs(in3Value-in3ValueTrigger) > sensorTreshold/2) { // Hysteresis...
in3Active = false;
in3TriggerUsed = false;
}
}
…
…
}
In het (vereenvoudigde) codefragment hiernaast wordt eerst het aantal stappen bepaald waarin het toerental en/of de draairichting moet verlopen. Dit gebeurt op basis van de waarde die met de potentiometer op het front kan worden ingesteld. Indien deze geheel naar links (naar nul) wordt gedraaid is het gedrag zoals bekend is van de E-Tec module. Naarmate de potentiometer meer naar rechts wordt gedraaid worden de snelheids- en draairichtingveranderingen geleidelijker. De tijd hiervoor is instelbaar van 0 tot 2,5 seconden. In het filmpje dat ik maakte is te zien hoe boterzacht de motor uitdraait en weer op gang komt.
Hoewel dit talent bij een magiër niet zou misstaan, is het helaas nog niet gelukt de Zauberling de toekomst te laten voorspellen. Bedenk dus dat deze motoruitloop ná de sensor-detectie plaatsvindt. De bewegende constructie moet dit vanzelfsprekend faciliteren en niet vastlopen of botsen. In de praktijk is hier echter bij de keuze van de positie van de sensoren eenvoudig rekening mee te houden. Een bijkomstig voordeel zou zelfs kunnen zijn dat deze eigenschap gebruikt worden om, zonder de sensoren te verplaatsen, de maximale uitslag van een bewegende slede af te stellen.
De Zauberling kan nog niet overweg met stappenmotoren, dus de afgelegde weg is nu nog slechts op basis van de ingestelde tijd bepaald. Hierdoor zal deze bij verschillende overbrengingen van de motor variëren. Mocht een volgende incarnatie van de Zauberling meer ingangen krijgen, dan zou het mogelijk zijn die te gebruiken voor de terugkoppeling van een encodermotor. Voor nu vond ik dat allemaal echter nog niet nodig.
void setMotorSpeed(bool rotateDir, int motorSpeed, bool smooth) {
// rotateDir = true means O1/O2 CW rotation
// rotateDir = false is O1/O2 CCW, output O3/O4 is reversed
// motorSpeed is a value between 0 and 512
// smooth = potmeter setting is value of gracefully descend and ascend
int tempSpeed;
int speedStep;
if (rotateDir!=currentMotorDir || motorSpeed!=currentMotorSpeed) {
int smoothDelay = timeDelay/25;
if (currentMotorDir == rotateDir) { // No directional changes...
speedStep = (motorSpeed-currentMotorSpeed)/SPEED_STEPS;
tempSpeed = currentMotorSpeed;
do {
tempSpeed += speedStep;
if (abs(motorSpeed-tempSpeed) <= abs(speedStep)) tempSpeed = motorSpeed; // Last step...
delay(smoothDelay);
if (rotateDir) {
Out1.drive(tempSpeed);
Out2.drive(-tempSpeed);
} else {
Out1.drive(-tempSpeed);
Out2.drive(tempSpeed);
}
} while (abs(motorSpeed-tempSpeed) > abs(speedStep));
} else { // Towards and through zero...
for (tempSpeed=currentMotorSpeed; tempSpeed>0; tempSpeed-=(currentMotorSpeed/SPEED_STEPS)) {
// Slow down to zero...
delay(smoothDelay);
if (currentMotorDir) {
Out1.drive(tempSpeed);
Out2.drive(-tempSpeed);
} else {
Out1.drive(-tempSpeed);
Out2.drive(tempSpeed);
}
}
speedStep = motorSpeed/SPEED_STEPS; // Always positive...
for (tempSpeed=0; tempSpeed<=motorSpeed; tempSpeed += (motorSpeed/SPEED_STEPS)) {
// Build up to motorSpeed again...
if (abs(motorSpeed-tempSpeed) <= speedStep) tempSpeed = motorSpeed; // Last step...
delay(smoothDelay);
if (rotateDir) {
Out1.drive(tempSpeed);
Out2.drive(-tempSpeed);
} else {
Out1.drive(-tempSpeed);
Out2.drive(tempSpeed);
}
}
}
currentMotorDir = rotateDir;
currentMotorSpeed = motorSpeed;
}
}
De software voor de Zauberling zal de komende tijd vast nog verder worden uitgebreid en verfijnd en is te downloaden van GitHub. Schroomt u niet mij te mailen of te benaderen op het forum als u suggesties, opmerkingen, vragen of ideeën voor toekomstige functionaliteit voor de Zauberling heeft. Voor een echte tovenaar is het schijnbaar onmogelijke immers de ultieme uitdaging... 😄