BeneluxSpoor.net forum
Vraag en antwoord => Elektronica en analoog => Topic gestart door: Edsko Hekman op 14 mei 2018, 10:59:15
-
Hi,
misschien vervuil ik dit draadje nu wel (te veel?), maar ik leg mijn vraag nu even hier neer. Want ik weet het niet allemaal.
Zie onderstaande foto/. Dit is mijn black box voor Grasland, de linkerkant om precies te zijn.
(https://images.beneluxspoor.net/bnls/20180514-102106-1.jpg) (https://images.beneluxspoor.net/bnls/20180514-102106-1.jpg)
Geel (?) is het "Ben sluisje" in de rail gelegd, rood is als ik het als lichtsluis ga gebruiken. Want dat is wat ik er van begrepen heb, corrigeer me als ik er naast zit. Ik dacht te lezen dat als je de ontvanger (of zender) losknipt en op een andere plek plaatst (en weer verbind natuurlijk) dat je dan ook gebruik kunt maken van dit sluisje. Ik hoef me over camouflage geen zorgen te maken, want het zit achter een schot, dus geen hond die het ziet op een beurs oid. Wellicht wel even een beveiliging voor de componenten er overheen, maar meer ook niet lijkt me.
Is de rode optie iets dat kan werken met het sluisje?
Dank voor de uitleg alvast.
Gr.
Edsko
-
Edsko,
Gezien het feit dat jij het op een beurs wilt gaan gebruiken in een module baan, zal er niet alleen eigen materieel de overweg bedienen. Een reflectie sluis kan werken, maar heeft zijn beperkingen (Zie inhoud draadje). Een straal lichtsluis (je rode stippen) heeft dan de voorkeur. Je hebt de straal keurig schuin over het spoor gericht, hierdoor zal je trein als een geheel worden gezien. Ik vraag me alleen af of de hoek groot genoeg is, gezien de afstand bij bv goederenwagens (twee ketelwagens met bordes). Iets schuiner over het spoor zal denk ik dat probleem oplossen. De afstand tussen de punten mag vrij fors zijn.
Groet,
Gerard van der Sel.
-
Goeie visualisatie, zeg!
straal breking (rode stippen)
Met "Ben's sluisje" werkt diagonaal over de rails betrouwbaar,
dat is transmissief gebruik, de trein onderbreekt de lichtstraal.
Hoe goed het werkt, is afhankelijk van de afstand tussen de wagons,
en de afscherming van zender en ontvanger tegen licht van boven af.
Een simpel petje op zender en ontvanger, meterkastje erom, plankje, verzin het wat,
houdt direct licht van boven weg.
Friedel Weber, in Lichtschranke, plaatste zijn zenders en ontvangers recht tegenover elkaar,
en op exact dezelfde hoogte, en dat maakt zijn oplossing een stuk minder betrouwbaar.
Als zijn straalhoogte niet exact gelijk valt met de treinkoppelingen,
dan krijgt hij een onderbreking na elke passerende wagon:
(https://werthof.home.xs4all.nl/treintjes/dc/fw_recht.jpg).
Diagonaal geplaatst (en ook in hoogte diagonaal) heeft een aantal voordelen
boven recht tegenover elkaar en op dezelfde hoogte.
straal weerkaatsing (gele stippen)
De gele stippen staan voor het reflexief gebruik (weerkaatsing):
op zo'n plek heb je zender+ontvanger op zeer geringe afstand van elkaar
tussen de bielsen, en ze wijzen allebei omhoog.
Dat gaat alleen goed als je er een segment met b.v. een blokje huizen of heuvel boven zet.
Niet zo heel veel anders dan wat er in de TCRT5000 behuizing zit.
Je bent alleen iets vrijer in de afstand tussen zender en ontvanger,
en de richtingen waarheen ze wijzen.
Vanuit de TCRT-behuizing kijken ze recht omhoog.
En volgens mij wijkt Ben daar wat af bij plaatsing van zender en ontvanger.
Maar hij zal er zelf wel mee komen als ik abuis ben.
Pssst.... Ben.... ;D
Dit is ook reflexief gebruik (foto van Ben, eerder uit dit draadje):
(https://imagizer.imageshack.com/v2/1280x1024q90/922/Y069x5.jpg)
En dat zou je bij een 2-baans overweg ook kunnen gebruiken,
om treinen in beide banen met een en het zelfde lichtsluisje te bewaken.
Maar juist bij een overweg heb je dan ook nog een andere kant om te bewaken.
-
Hi guys,
dank voor de uitleg.
@Gerard: de hoek kan best groter, er ligt ongeveer 30cm rails op de BB, dus dat zou ruimte genoeg moeten geven qua hoek.
Goeie visualisatie, zeg!
dank. :)
straal breking (rode stippen)
en de afscherming van zender en ontvanger tegen licht van boven af.
Een simpel petje op zender en ontvanger, meterkastje erom, plankje, verzin het wat,
houdt direct licht van boven weg.
Ik heb over de gehele lengte van de BB (+/- 30 cm) een "tunnel" staan (binnenkant zwart geverfd). Er valt dus geen licht van boven op de zender en ontvanger. Dus dat is alvast geregeld. ;)
Maar ik begrijp dat ik bijvoorbeeld de ontvanger los kan knippen van de print en ander de andere zijde van de rails kan plaatsen, waarbij ik natuurlijk wel "even" de ontvanger weer verbind met de print. Klopt dit? Zo ja, dan maak ik er gewoon een straal onderbreking van. Ik vind het wat te ver gaan om van iedere BNLS baan deelnemer te vragen om zijn materieel van koper- of alu tape te voorzien aan de onderzijde. :-\
Ik heb 20 van die dingen bestelt als het goed is, dus ik kan wat oefenen zal ik maar zeggen. ;)
Gr.
Edsko
-
Hoi,
Ben zijn opstelling in de loods is op +/- 5 - 10 cm van de detectie zone.
Waarom zou een detectie ingebouwd in het baanlichaam dan niet werken?
De detectie (reflexie) is dan maar op 1 cm afstand!
Ik heb ze ook besteld, testen zal uitwijzen welke opstelling ik zal gebruiken.
Dave
-
Hoi
Dacht, reageer toch even want over IR reflectie is al voldoende geschreven, zie deze topic:
https://forum.beneluxspoor.net/index.php?topic=72888.msg32
Echter door ervaring zal deze toch soms om onderling storing te voorkomen ontkoppeld moeten worden, een diode in de plus voeding en daarachter een condensator over de plus en min, komt neer op het eerdere omschreven schema in deze topic. Gebruikte diode bij mij is een 1N4148 en de uitgang kan rechtstreeks op een S88 ingang.
Frans
-
POST!!
(https://images.beneluxspoor.net/bnls/20180514-195034.jpg) (https://images.beneluxspoor.net/bnls/20180514-195034.jpg)
De boel kan beginnen. :)
Wat is nu de zender en wat de ontvanger? En maakt het nog uit welke ik losmaak en op afstand weer verbind? Ik heb zelf het idee dqat het niet uitmaakt, maar hoor dat graag bevestigd door iemand die er meer van weet dan ikke. :)
Ik heb er nu dus 20, dus als er één sneuvelt, och... ;)
Gr.
Edsko
-
Edsko,
Het maakt inderdaad niet uit. Als je het echt wilt weten, maak dan een foto van onder en bovenkant. Kijk ik even of ik het langs deze weg kan vertellen. Vaak is de donkere LED de zender.
Groet,
Gerard van der Sel.
-
@Fransx
over IR reflectie is al voldoende geschreven
Klopt, maar ik begon het draadje over de toepassing van reedrelais, en Ali-lichtsluisjes.
Ali-lichtsluisjes hebben goedkope fotodiodes als ontvanger, geen IS471 dus.
Echter door ervaring zal deze toch soms om onderling storing te voorkomen ontkoppeld moeten worden
Bedoel je daarmee dat de combinatie lichtsluisje(met IS471) + S88 soms ontkoppeld moet worden?
Waarom zou een detectie ingebouwd in het baanlichaam dan niet werken?
De detectie (reflexie) is dan maar op 1 cm afstand!
Ik hoop dat je gelijk hebt. Dat ligt absoluut binnen de optimale marge van b.v. een TCRT5000 en ook binnen de marge van menig andere fotodiode.
Echter, het voorgaande samenvattend: Eerder in dit draadje (https://forum.beneluxspoor.net/index.php?topic=79736.msg3221854208#msg3221854208)
Bij reflexie
Omgevingslicht (ambient light) heeft invloed op de ontvanger:
-Sterke directe straling verblindt de ontvanger.
-Minder sterke maar constante straling maakt ontvanger slecht ziend.
-Variërende straling maakt dat ontvanger spoken ziet.
=>En vandaar een voorkeur voor afscherming boven de baan, bij gebruik van goedkope fotodiodes.
Omgevingslicht heeft invloed op het bestraalde object.
- totaal geen waarneming (met name bij plastics, en met name bij zwarte kleuren),
- sterk verminderde waarneming (met name bij plastics met grijze kleur),
- achtergrond krijgt soms groter contrast dan bestraalde object
=>En vandaar het idee om bij zwart plastic of grijs plastic onderkanten van treintjes
de zichtbaarheid te vergroten, bij gebruik van goedkope fotodiodes.
Er zijn 3 workarounds genoemd (bij reflexief gebruik van goedkope fotodiodes):
- behuizing met omgevingslicht-filter (zoals de TCRT5000)
- mechanische voorzieningen treffen (bij treintjes gaatje boren tussen de bielsen)
- wisselstroom gebruiken
=>Wisselstroom toepassing is een manier om met een goedkope fotodiode te doen wat de IS471 zelf kan (tacten van zender en ontvanger).
Het gebeuren staat uitgelegd in Vishay (application of optical sensors 80107, 2002).
-
Hi,
zie hieronder de foto.
(https://images.beneluxspoor.net/bnls/20180515-091320.jpg) (https://images.beneluxspoor.net/bnls/20180515-091320.jpg)
Gr.
Edsko
-
MH-Sensor Series Flying Fish, wow, wat zien ze er mooi uit. (y)
-
Hopelijk werken ze ook mooi. ;)
-
Op de foto is helaas geen spoor te zien. Ze mogen mooi zijn, als ze maar goed werken.
Mooi werken is voor mensen die creatief werken (behalve ICT-ers). Ik kan een print er mooi uit laten zien, maar dat is bij een stuk code nog nooit gelukt. Het inspringen en korte en lange regels zorgt er voor dat zo'n listing er niet uit ziet.
(Sorry even een stukje persoonlijke frustratie)
Groet,
Gerard van der Sel.
-
Maakt het trouwens nog uit hoe ik de LED's aanbreng? Kan ik ze gewoon rechtop plaatsen of moet ik ze haaks op het houtwerk plaatsen? Ik ben geneigd ze haaks te plaatsen, maar dat is meer een gevoel. Moet ik zo op elkaar richten? Hoe nauwkeurig moet dat? De hoek kom ik wel uit, dat is niet het moeilijkste.
Wat ik wil doen, is op beide black boxen een lichtsluis maken, per spoor één. Als op het voorste spoor een trein van links naar rechts rijdt, dan zou op de linker black box de AKI met geluid aan moeten gaan en op de rechter black box de AKI met geluid weer uit moeten gaan. Is dat mogelijk? Ik gebruik de lichtsluizen dan als aan-/uit schakelaar. Stel dat dit zo geimplementeerd kan worden, zou het dan ook automatisch goed werken als er op het voorste spoor van rechts naar links gereden wordt?
Er is een Arduino in huis die ik hier voor wil/kan gebruiken.
Nieuwe materie voor me, wel geinig. :)
Gr.
Edsko
-
Maakt het trouwens nog uit hoe ik de LED's aanbreng? Kan ik ze gewoon rechtop plaatsen of moet ik ze haaks op het houtwerk plaatsen? Ik ben geneigd ze haaks te plaatsen, maar dat is meer een gevoel. Moet ik zo op elkaar richten? Hoe nauwkeurig moet dat? De hoek kom ik wel uit, dat is niet het moeilijkste.
Richt ze naar elkaar, de stralingshoek van de led is beperkt. Ik gebruik ze ook maar dan reflectief.
Wat ik wil doen, is op beide black boxen een lichtsluis maken, per spoor één. Als op het voorste spoor een trein van links naar rechts rijdt, dan zou op de linker black box de AKI met geluid aan moeten gaan en op de rechter black box de AKI met geluid weer uit moeten gaan. Is dat mogelijk? Ik gebruik de lichtsluizen dan als aan-/uit schakelaar. Stel dat dit zo geimplementeerd kan worden, zou het dan ook automatisch goed werken als er op het voorste spoor van rechts naar links gereden wordt?
Er is een Arduino in huis die ik hier voor wil/kan gebruiken.
Niet automatisch. Als je per spoor links en rechts een aparte lichtsluis hebt, zeg voor het voorste spoor in de linker BB ,noem die detector VL. Voor het voorste spoor rechter BB, noem die VR etc. dan kun je op het afgaan van VL de AKI aan zetten en op het aangaan van VR de AKI uitzetten. Voor het achterste spoor is dan de volgorde AR AKI aan, AL AKI uit. Het probleem is dan als een trein op het verkeerde spoor zit. Dan zul je iets meer met de triggers moeten doen. Bijvoorbeeld, de AKI is standaard uit, zodra nu een van de lichtsluisjes uit een paar (VL en VR of AR en AL) triggered gaat de AKI aan, zodra nu de andere uit het paar triggered gaat de AKI weer uit. Dit werkt alleen goed als de lichtsluis zodanig schuin staat dat er niet tijdens het passeren van een trein de detector uit en aan gaat. Als dat gebeurd zul je met timers moeten werken om korte onderbrekingen uit te filteren. Een ander probleem is, wat gebeurd er als er twee treinen tegelijkertijd (een van links en een van rechts) komen. Dan zul je tellers moeten bijhouden over het aantal treinen dat in je module zit .
Ik hoop dat ik het niet te complex maak.
Groet
Meino
-
Mooi werken is voor mensen die creatief werken (behalve ICT-ers). Ik kan een print er mooi uit laten zien, maar dat is bij een stuk code nog nooit gelukt. Het inspringen en korte en lange regels zorgt er voor dat zo'n listing er niet uit ziet.
(Sorry even een stukje persoonlijke frustratie)
Gerard
als ik dat stukje code, dat ik van je heb, bekijk, dan valt het wel mee. Maar je hoeft natuurlijk commentaar niet op de zelfde instructie regel te zetten, dat kun je ook erg goed voor de instructie te zetten. Dan kun je ook veel meer commentaar kwijt en houd je de regels korter. Overigens ook sommige ICT-ers houden van net werk en ook een programma kan een zekere schoonheid hebben. Maar er is natuurlijk wel een officiele wedstrijd in onbegrijpelijk coderen, nl. de Obfuscated C contest (https://www.ioccc.org/)
Groet
Meino
-
Esso,
Doe zoals het grootbedrijf het doet. Als je de sensoren van de linker BB een teller met 1 laat verhogen en de sensoren van de rechter BB de teller met 1 last verlagen ben je klaar. Zolang de teller 0 is is je Aki uit. Alleen met trein plaatsen in grasland geeft dan nog problemen. Maar even met je hand door de lichtsluis achter de trein en dat is ook opgelost.
Groet,
Gerard van der Sel.
-
Richt ze naar elkaar, de stralingshoek van de led is beperkt. Ik gebruik ze ook maar dan reflectief.
Check! Ga ik doen.
Een ander probleem is, wat gebeurd er als er twee treinen tegelijkertijd (een van links en een van rechts) komen. Dan zul je tellers moeten bijhouden over het aantal treinen dat in je module zit .
Deze had ik idd ook bedacht nadat ik mijn vorige bericht had ingetypt. Maar geen oplossing nog bedacht. Maar het klinkt alsof het op te lossen is. Dat is fijn. Ik krijg steeds meer zin om de zaken eens uit te gaan proberen. Nu nog voeding voor die vliegende vissen. ;)
Ik hoop dat ik het niet te complex maak.
Ben je gek! Fijn dat je meedenkt! (y)
Denk dat ik eerst alles maar eens ga proberen met een lampje dat aan en uit gaat. Moet ik nog technisch gaan doen ook. Wie had dat gedacht...
Gr.
Edsko
-
Esso,
Het is meer dan 30 jaar geleden toen mijn 8 jarige buurjongen mij zo noemde... ;D
Gr.
Edsko ;)
-
Nu nog voeding voor die vliegende vissen. ;)
Dat is makkelijk, VCC op de 5v van de Arduino, gnd op een gnd van de Arduino en de output op een pin van de Arduino die je kunt uitlezen.
Groet Meino
-
Check! (y)
-
<off topic>
Even een domper voor je Edsko (sorry voor de verschrijving net), ga in gedachten is met een trein van circa 80 cm over je module bak. Je zult zien dat het geheel dan niet goed werkt.
</off topic>
Ik denk dat je even voor je overweg een nieuw draadje moet openen, want dit gaat over de Ali lichtsluisjes (Sorry is mijn mening en ik ben geen moderator, dus heb eigenlijk niets te zeggen).
Groet,
Gerard van der Sel.
-
Ik twijfelde ook al of ik dit niet gewoon in Grasland moet bespreken. Laten we dat dan maar doen. Ik meld het bij de mods.
-
Ik zie dat je de link aan de grasland kant (https://forum.beneluxspoor.net/index.php?topic=60837.msg3221857796#msg3221857796) al gelegd hebt.
Als je overwegbesturing (Arduino en lichtsluizen) in een aparte rubriek (Elektronica en analoog of Digitaal) stopt, dan draagt dat bij aan de forumordening, en daarmee de kans op repliek. In beide rubrieken zitten Arduino toepassingen. Duidelijk is met zoekopdracht (overweg arduino) dat zulke draadjes nu nog echt overal te verwachten zijn
Het zal voor de moderators inmiddels wel te veel werk zijn om een aparte rubriek Arduino te maken. Met daaronder apart analoge en digitale toepassingen, of aparte deelgebieden zoals bezetmelding, koppelrails, lokomloop, lokwissel, overwegen, pendelen, seinen, wissels.
-
Bericht gemeld. Nu even wachten op een mod. Komt goed.
-
Friedel Weber, in Lichtschranke, plaatst zijn zenders en ontvangers recht tegenover elkaar,
en op exact dezelfde hoogte, en dat maakt zijn oplossing een stuk minder betrouwbaar.
Als zijn straalhoogte niet exact gelijk valt met de treinkoppelingen,
dan krijgt hij een onderbreking na elke passerende wagon.
(...)
Diagonaal geplaatst (en ook in hoogte diagonaal) heeft een aantal voordelen
boven recht tegenover elkaar en op dezelfde hoogte.(...)
Dat denk je dan, tot deze reactie in het digitale draadje (lichtsluis, waar verkrijgbaar) (https://forum.beneluxspoor.net/index.php?topic=79634.msg3221858783#msg3221858783):
Blausee-Mitholz heeft z'n lichtsluis schuin (niet haaks erop) over het spoor gericht, en de zender staat hoger opgesteld dan de ontvanger. Toch gaat het fout: want de lichtstraal vangt de koppelingen niet.
Mogelijke oorzaak: in een boog met krappe radius (circa 36 mm) zwenken de koppen van rijtuigen te ver uit, en kan de straal er tussen door piepen (indien niet gericht op de koppelingen zelf).
Mogelijke oplossing in termen van Ali-lichtsluisjes: je neemt 2 sluisjes om een bepaalde situatie af te dekken, en de OUT van beide sluisjes sluit je aan op het zelfde relais of op de zelfde s88 melder.
-
Op verzoek afgesplitst. Ik heb het bij "elektronica en analoog" als categorie gehouden en de titel aangepast. De vlag dekt de lading zo, neem ik aan?
Reinout-als-moderator
-
Het feit dat Edsko met een Arduino gaat werken, maakt het leven een stuk gemakkelijker. In de programmering kun je allerlei scenario's opvangen. Het probleem van korte onderbrekingen omdat tussen de wagons de sensors elkaar weer kort zien, is simpel op te lossen met een timer. Ook de situatie van een korte trein kun je makkelijk programmatisch oplossen.
Groet Meino
-
Ook de situatie van een korte trein kun je makkelijk programmatisch oplossen.
Daar had ik nog niet bij stilgestaan. (y)
-
Eigenlijk kun je het probleem reduceren tot een "finite State Machine" (Eindigetoestandautomaat). Dus is het een kwestie van alle mogelijke toestanden (states) van het systeem en de bijbehorende mogelijke overgangen te bepalen. Bijvoorbeeld, toestand 1 is "Er is geen trein in de module", dit zou de begin toestand kunnen zijn.
Toestand 2 zou kunnen zijn "een lichtsluis detecteert het passeren van een trein". Toestand 3 zou kunnen zijn "Er is geen lichtsluis meer over die een trein detecteert". De mogelijke overgangen zouden dan zijn van 1 naar 2, maar van 1 naar 3 kan niet. van 3 naar 1 kan weer wel en van 2 naar 3 ook, maar van 2 naar 1 weer niet.
Het is een beetje puzzelen, want je hebt te maken met 2 sporen en dus meerdere mogelijkheden, maar het staat los van het programmeren, het is gewoon goed nadenken over wat er gebeurd. Maar als je dit eenmaal op papier hebt is het programma zelf voor dit gedeelte makkelijk te schrijven. Je houdt natuurlijk nog genoeg uitdagingen over, zoals het aansturen van de aki's en de generatie van de bellen.
Groet Meino
-
Oke,
Alles even samenvatten:
Eisen/Wensen:
Aansturing van een AKI door een trein. Aan de trein mogen geen aanpassingen gedaan worden. De AKI is dubbelsporig en moet van beide zijde op hetzelfde spoor aangestuurd worden. Gekozen is voor aansturing via "lichtsluizen" en een Arduino.
Eventuele knippenringen door de lichtsluizen worden door een schuine opstelling verminderd, geheel voorkomen kan niet. Dit wordt niet door extra hardware opgelost.
Opstelling:
(https://images.beneluxspoor.net/bnls/Lichtsluizen.jpg) (https://images.beneluxspoor.net/bnls/Lichtsluizen.jpg)
Even in "Grasland" gekeken voor de juiste opstelling. De overweg bevind zich links op de module. Dus er is een ongelijke tijd voor het aanrijden van de AKI. Is in dit geval niet storend, daar de korte aanrijtijd door de BBL (blackbox links) gecamoufleerd wordt. De rode lijnen zijn de 4 sensoren voor de AKI aansturing.
Schema:
(https://images.beneluxspoor.net/bnls/SchemaLichtsluizen.jpg) (https://images.beneluxspoor.net/bnls/SchemaLichtsluizen.jpg)
Voeden uit de Arduino. De sensoren zullen ieder zo'n 30mA trekken, dus dat moet kunnen. Voeden uit de USB poort van de PC is dan niet meer mogelijk. De voeding van de Arduino gebruiken. Waar de 4 sensoren aangesloten worden is niet van belang, zolang pen 0 (RX), 1 (TX) en 13 (LED) maar niet gebruikt worden. Probeer zoveel mogelijk de pennen 2 (INT0) en 3 (INT1) te vermijden. In dit geval is dat niet nodig, daar we deze functionaliteit toch niet nodig hebben.
Software:
// Definitie van de 4 ingangen voor de sensoren
#define SBBLSP1 3 // BlackBox Links, Spoor 1
#define SBBLSP2 4 // BlackBox Links, Spoor 2
#define SBBRSP1 5 // BlackBox Rechts, Spoor 1
#define SBBRSP2 6 // BlackBox REchts, Spoor 2
#define DELAY 500 // Vertraging in milli seconde
// Laatste stand van de melder
bool MBBLSP1;
bool MBBLSP2;
bool MBBRSP1;
bool MBBRSP2;
// Timers om het vrijgeven te vertragen
unsigned long TSBBLSP1;
unsigned long TSBBLSP2;
unsigned long TSBBRSP1;
unsigned long TSBBRSP2;
// Variabelen die richting in de sporen bij houden
// < 0: trein rijdt van rechts naar links
// 0: geen trein
// > 0: trein rijdt van links naar rechts
byte DIRSP1;
byte DIRSP2;
// Functies om de melders te lezen (true = bezet)
bool readBBLSP1() {
// if (digitalRead(SBBLSP1) > 0) {
if (digitalRead(SBBLSP1) == 0) {
TSBBLSP1 = millis() + DELAY;
}
return (TSBBLSP1 > millis());
}
bool readBBLSP2() {
// if (digitalRead(SBBLSP2) > 0) {
if (digitalRead(SBBLSP2) == 0) {
TSBBLSP2 = millis() + DELAY;
}
return (TSBBLSP2 > millis());
}
bool readBBRSP1() {
// if (digitalRead(SBBRSP1) > 0) {
if (digitalRead(SBBRSP1) == 0) {
TSBBRSP1 = millis() + DELAY;
}
return (TSBBRSP1 > millis());
}
bool readBBRSP2() {
// if (digitalRead(SBBRSP2) > 0) {
if (digitalRead(SBBRSP2) == 0) {
TSBBRSP2 = millis() + DELAY;
}
return (TSBBRSP2 > millis());
}
// Initialialatie van de Arduino
void setup() {
// put your setup code here, to run once:
// Maak de inputs met extra pullups
pinMode(SBBLSP1, INPUT_PULLUP);
pinMode(SBBLSP2, INPUT_PULLUP);
pinMode(SBBRSP1, INPUT_PULLUP);
pinMode(SBBRSP2, INPUT_PULLUP);
// Zet de interne LED output
pinMode(LED_BUILTIN, OUTPUT);
// Initialiseer de laatste waarde
MBBLSP1 = readBBLSP1();
MBBLSP2 = readBBLSP2();
MBBRSP1 = readBBRSP1();
MBBRSP2 = readBBRSP2();
// Initialiseer de timers
TSBBLSP1 = millis();
TSBBLSP2 = millis();
TSBBRSP1 = millis();
TSBBRSP2 = millis();
// Meld geen trein (waarde 0)
DIRSP1 = 0;
DIRSP2 = 0;
// LED uit
digitalWrite(LED_BUILTIN, LOW);
}
void loop() {
// put your main code here, to run repeatedly:
// fase: toestand nu en de vorige keer van de melder
// volgorde:
// 0: geen trein
// 1: trein komt binnen
// 2: trein verlaat
// 3: trein aanwezig
byte fase;
// Spoor 1 (links)
fase = (MBBLSP1 ? 2 : 0);
MBBLSP1 = readBBLSP1();
fase += (MBBLSP1 ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (DIRSP1 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
DIRSP1++;
}
}
if (fase == 2) {
// Trein verlaat
if (DIRSP1 < 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
DIRSP1++;
}
}
// Spoor 1 (rechts)
fase = (MBBRSP1 ? 2 : 0);
MBBRSP1 = readBBRSP1();
fase += (MBBRSP1 ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (DIRSP1 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
DIRSP1--;
}
}
if (fase == 2) {
// Trein verlaat
if (DIRSP1 > 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
DIRSP1--;
}
}
// Spoor 2 (links)
fase = (MBBLSP2 ? 2 : 0);
MBBLSP2 = readBBLSP2();
fase += (MBBLSP2 ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (DIRSP2 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
DIRSP2++;
}
}
if (fase == 2) {
// Trein verlaat
if (DIRSP2 < 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
DIRSP2++;
}
}
// Spoor 2 (rechts)
fase = (MBBRSP2 ? 2 : 0);
MBBRSP2 = readBBRSP2();
fase += (MBBRSP2 ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (DIRSP2 == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
DIRSP2--;
}
}
if (fase == 2) {
// Trein verlaat
if (DIRSP2 > 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
DIRSP2--;
}
}
// Aansturen van de AKI / AHOB (overweg)
if ((DIRSP1 == 0) && (DIRSP2 == 0)) {
// Overweg geopend
digitalWrite(LED_BUILTIN, LOW);
} else {
// Overweg gesloten
digitalWrite(LED_BUILTIN, HIGH);
}
}
Uitleg bij de code:
In de eerste regels zijn de ingangen gedefinieerd. Gebruik gewoon de nummers die op het Arduino bordje staan. Doordat de ingangen nu een naam hebben gekregen zijn ze gemakkelijk te gebruiken in de code.
Hierna is de vertraging gedefinieerd, die bij het wegvallen van de detektie opgeteld wordt om in de software korte onderbrekingen op te vangen.
Dan volgen de variabelen zoals die gebruikt worden in het programma. Als eerste 4 booleans om de stand van de melder te onthouden. Daarna 4 timers om bij te houden wanneer voor het laatst een sensor is gezien.
Tenslotte een tweetal variabelen om de toestand van de sporen vast te leggen. Dit is een zogenaamde state variabele (zie uitleg Meino).
Nu volgens de functies waaruit het programma is opgebouwd, naast de verplichte functies setup() en loop().
Dit zijn 4 functies die ieder een sensor behandelen.
De werking van de functie is als volgt:
Eerst wordt het niveau van de ingang vastgesteld. Meld deze dat er een trein aanwezig is, dan wordt de timer van deze ingnag geladen met de huidige stand van de millis teller (interne teller van de Arduino) plus de vertraging.
Tenslotte wordt er boolean gemaakt die aangeeft of de huidge stand van de millis teller kleiner is dan de timer value.
Dit is om te zorgen dat het resultaat van deze functies niet gestoord wordt door verstoringen, doordat de uitgang van de sensor even van stand veranderd.
Dan volgen de verplichte functies setup() en loop(). Setup zal alle in- en uitgangen goed zetten en de variabelen van hun begin waarde voorzien.
Loop() is het uiteindelijke programma. Ook hier wordt weer een finite state pattern gebruikt (het is tenslotte mijn favoriete pattern en ben de "Gang of four" dankbaar voor het definiëren.) Het gaat in dit geval om de variabele fase. Deze kent de waardes 0 t/m 3 en ontstaat uit de waarde van de sensor van de vorige loop() doorloop en de huidige. De waarde van fase doorloopt de 4 waardes op de volgende manier:
De waarde van de melder uit de vorige loop zal de waarde van fase vullen met 0 (geen trein) of 2 (trein). Hierna wordt naar aanleiding van de huidige weaarde er 0 (geen trein) of 1 (trein) bij opgeteld. Als een trein door de sensor (lichtsluis) rijdt, ontstaat nu het volgende patroon:
.......000013333........333320000........
De waardes 0 en 3 komen vaak voor en vertellen dat de situatie constant is gebleven. Echter 1 (voorkant van de trein) en 2 (achterkant van de trein) komen per passage maar een keer voor. Nu moet alleen nog uitgezocht worden hoe de toestand waarin het spoor rond de AKI zich bevind is. Hiervoor zal de volgende finite state variabele gebruikt worden. Dit is dirSPx. Deze variabele kent de waardes 0 (geen trein), 1 (trein rijdt van links naar rechts) en -1 (trein rijdt van rechts naar links). De variabele idrSPx mag alleen onder bepaalde voorwaarde verhoogd / verlaagd worden.
Uiteindelijk zal dirSPx altijd terug komen op 0. Als alle dirSPx variabelen 0 zijn, mag de AKI geopend worden. Indien een disSPx niet 0 is moet de AKI gesloten worden. In dit geval zal bij gesloten AKI de LED op de Arduino oplichten en pen 13 5V voeren, ten teken dat de AKI dicht moet.
(Verderop gaan we de code uitbreiden met het aansturen van de LEDs van de AKI.)
Huiswerk: ;D
@Edsko (en wie nog meer wil):
Schakeling bouwen en testen. We zijn hier nieuwsgierig naar het resultaat. Gezien het weer verwachten we dat je een poosje bezig zult ziijn.
@Allen:
Mochten er vragen opmerkingen of andere dingen zijn, post ze gerust.
@C goeroes:
Het programma roept om optimalisatie. Ik weet dat dit mogelijk is, maar moet te veel research op het internet doen om het in C voor elkaar te krijgen.
Help mij en Edsko door met voorbeelden te komen hoe stukken code geoptimaliseerd kunnen worden. Zie het als een een simpele wedstrijd zoals Meino aangaf.
Zo ik ga met vakantie en zal alleen via mijn mobiel meelezen en reageren. Dus verwacht de komende dagen geen lappen tekst meer.
Groet,
Gerard van der Sel.
-
Oke,
Alles even samenvatten:
Eisen/Wensen:
Aansturing van een AKI door een trein. Aan de trein mogen geen aanpassingen gedaan worden. De AKI is dubbelsporig en moet van beide zijde op hetzelfde spoor aangestuurd worden. Gekozen is voor aansturing via "lichtsluizen" en een Arduino.
Eventuele knippenringen door de lichtsluizen worden door een schuine opstelling verminderd, geheel voorkomen kan niet. Dit wordt niet door extra hardware opgelost.
Je bent snel. Ik vind het ook een mooie uitdaging/puzzle, dus ben ik ook maar aan een stukje code begonnen, alleen mijn code is totaal anders (Object oriented met classes), wel gebruik ik de zelfde toestanden als jij. Als ik klaar ben zal ik mijn versie ook wel even publiceren.
@C goeroes:
Het programma roept om optimalisatie. Ik weet dat dit mogelijk is, maar moet te veel research op het internet doen om het in C voor elkaar te krijgen.
Help mij en Edsko door met voorbeelden te komen hoe stukken code geoptimaliseerd kunnen worden. Zie het als een een simpele wedstrijd zoals Meino aangaf.
Ik ben lang geleden gestopt om de code zelf te optimaliseren, mijn ervaring is dat de GNU compilers dermate goed zijn in het optimaliseren, dat eigen pogingen vaak averechts werken of hooguit geen invloed hebben. Ik vind het veel belangrijker dat de code goed leesbaar is.
Zo ik ga met vakantie en zal alleen via mijn mobiel meelezen en reageren. Dus verwacht de komende dagen geen lappen tekst meer.
Prettige vakantie, ook ik vertrek van de week. Heb wel de laptop bij me, dus zolang er wifi is kan ik kontact houden.
Groet Meino
-
<off topic>
(https://images.beneluxspoor.net/bnls/DelChatoDeltebre.jpg) (https://images.beneluxspoor.net/bnls/DelChatoDeltebre.jpg)
Kom er al 11 jaar. In geen velden of "asfaltwegen" wifi te vinden. De telefoon gaat terug naar 3G. Internet is er traaaaaaaaag (dankzij de EU is er tenminste internet voor buitenlanders). Gaan twee keer per dag koffie drinken om "up to date" te blijven. Verder genieten van het groeien van de rijst in de rijstvelden (ja, ik ben in Europa). Maar eerst vrijdag en zaterdag 1700 km rijden met dit:
(https://images.beneluxspoor.net/bnls/20170609-093540-min.jpg) (https://images.beneluxspoor.net/bnls/20170609-093540-min.jpg)
<on topic>
Groet,
Gerard van der Sel.
-
Met interesse kijk ik mee:
Ik heb een leuke voor jullie.
Zelfde situatie, alleen driesporig.
- knipperleds(oranje)
- stepper controller voor 2 servos voor slaghekwerk.
- fotocellen als lichtsluis.
Verder breadboard en verzameling weerstanden en toebehoren aan draad tot beschikking om te experimenteren.
Ben nu alleen ook niet thuis, maar wel van plan dit te gebruiken met een Arduino Mega 2560.
Zonodig in eigen draadje want het is niet met Ali-lichtsluisjes.
Heb een leuk tutorial (https://www.stummiforum.de/viewtopic.php?f=21&t=127532) (klik) gezien van een Duitser die ook nastuiterende slagboom geprogrammeerd heeft.
Erg interessant, moet ik ff opzoeken
Sketch staat er ook bij.
Start bij terugkomst uit het verre Lettele ::) wel een topic in deze hoek van het forum.
Gr Koen.
-
Hm een forum moderator. Nu even voorzichtig zijn, want voor het weet mag je niet meer op de site.
De code is "per spoor" geschreven. Als je de namen volgt dan zie je dat er SP1 en SP2 gebruikt wordt. Copieer iedere SP2 en maak daar SP3 van dan ben je al halverwege (SBBLSP3, SBBRSP3, MBBLSP3, MBBRSP3, TSBBLSP3, TSBBRSP3 en DIRSP3 ). Van de read functies de laatste twee copieren en de 2 vervangen door een 3 en tenslotte in setup() de nieuwe variabelen toevoegen en initialiseren.
In loop() het stuk gemarkeerd met spoor 2 (links) en spoor 2 (rechts) copieren (eronder). De 2-en vervangen door 3-en. en tenslotte de regel
if ((DIRSP1 == 0) && (DIRSP2 == 0)) {
vervangen door:
if ((DIRSP1 == 0) && (DIRSP2 == 0) && (DIRSP3 == 0)) {
Je hebt de code nu voor 3 sporen.
Het knipperen komt als Edsko er aan toe is, want ook zijn AKI gaat knipperen.
Groet,
Gerard van der Sel.
-
Met interesse kijk ik mee:
Ik heb een leuke voor jullie.
Zelfde situatie, alleen driesporig.
- knipperleds(oranje)
- stepper controller voor 2 servos voor slaghekwerk.
- fotocellen als lichtsluis.
Ik weet nog niet hoe het met Gerards code zit (dat nog niet goed bestudeerd), maar mijn code heeft daar geen probleem mee. Ik hanteer voor ieder spoor een aparte state machine. De stand voor de AKI wordt bepaald door een AND conditie over de staat van alle sporen. Dus het is simpel te imlementeren door de de AND conditie met extra sporen uit te breiden.
Het aansturen van steppers in plaats van leds is een wijziging in de techniek. en niet zo moeilijk.
Groet Meino
-
@Gerard,
Ik maak gewoon dankbaar gebruik van alle technische kennis die er is hier.
Mijn kennis is 0.
Maar het lijkt me niet het allermoeilijkste om dit voorelkaar te krijgen.
Achter de forum schermen al een beetje opweg geholpen door Meino.
Loop wel iets vooruit op mijn eigen planning want ik wou eerst een enkele servo en een enkele led laten werken voor oefening, maar dat geloof ik naar aanleiding van de vele filmpjes op YouTube eerlijk gezegd wel en maakt het interessant voor mij om gelijk maar een stap verder te gaan.
Zoals ik al zei ben ik ook nu niet thuis, maar ik heb al een testplankje klaar liggen met stukje spoor om van start te gaan.
Zal het as weekend starten ;D
-
Gerard was sneller met zijn code. maar ik was ook al begonnen omdat ik ook op Kranenberg wel een werkende AKI wil hebben.
Dit is mijn stukje code. Let wel het is nog niet getest. Voor test doeleinden kun je de define DEBUG op 1 zetten dan genereert de code log output op de seriele monitor van de Arduino IDE.
#define DEBUG 0
enum SpoorState {leeg,
sensor1komend,
sensor2komend,
sensor1gaand,
sensor2gaand
};
//
// Class for a single (white) led which flickers 50 times per
// minute when on
//
class SingleLed
{
private:
int ledPin;
bool ledOn = true;
int interval = 600; // *** 50 keer per minuut
bool lightOn = false;
unsigned long lastTime;
public:
//
// Create a new instance of a (white) led, connect it to the specified
// digital pin and put it in the specified state (true = on, false = off)
//
SingleLed(int aPin, bool state)
{
ledPin = aPin;
ledOn = state;
lightOn = false;
pinMode(ledPin, OUTPUT);
lastTime = millis();
}
//
// Set the state of the led (true = on, false = off)
//
void setOn(bool state)
{
ledOn = state;
}
//
// If the state is on, put power on the pin of the led, using timers
// to make the flicker work.
// If the led is off, remove the power from the pin of the led.
//
void heartBeat()
{
if (ledOn) // Do we need to light the led?
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= interval) // Has the interval time passed?
{
lastTime = currTime; // Start new interval
if (!lightOn) // Was the led lighted?
{
digitalWrite(ledPin, HIGH); // No, so switch it on
lightOn = true;
}
else
{
digitalWrite(ledPin, LOW); // Yes, so switch it off
lightOn = false;
}
}
}
else if (lightOn) // No light, but is the led still on?
{
digitalWrite(ledPin, LOW); // Switch ir off
lightOn = false;
}
}
};
//
// Class for a set of two (red) leds which alternate(flicker) 50 times per
// minute when on
//
class DuoLed
{
private:
int led1Pin;
int led2Pin;
bool ledOn = true;
int interval = 600; // *** 50 keer per minuut
bool lightOn = false;
unsigned long lastTime;
public:
//
// Create a new instance, connect it to the specified
// digital pins and put it in the specified state (true = on, false = off)
//
DuoLed(int aPin1, int aPin2, bool state)
{
led1Pin = aPin1;
led2Pin = aPin2;
ledOn = state;
lightOn = false;
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
lastTime = millis();
}
//
// Set the state of the leds (true = on, false = off)
//
void setOn(bool state)
{
ledOn = state;
}
//
// If the state is on, put power on the pins of the leds, using timers
// to make the alternating flicker work.
// If the led is off, remove the power from the pins of the leds.
//
void heartBeat()
{
if (ledOn) // Are the leds activated
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= interval) // Has the interval passed?
{
lastTime = currTime; // Yes, start new interval
if (!lightOn) // The leds alternate, are we in phase1 (led1 on, led2 off)
{
digitalWrite(led1Pin, HIGH); // Yes, led1 on
digitalWrite(led2Pin, LOW); // led2 off
lightOn = true; // When the interval expires, switch the leds
}
else // We are in phase2 (led1 off, led2 on)
{
digitalWrite(led1Pin, LOW); // Led1 off
digitalWrite(led2Pin, HIGH); // Led2 on
lightOn = false; // When the interval expires, switc the leds
}
}
}
else // The leds are not active, switch of both leds
{
digitalWrite(led1Pin, LOW);
digitalWrite(led2Pin, LOW);
lightOn = false;
}
}
};
enum AkiStaat {aan, uit};
//
// A simple class that represents a complet AKI with all its leds
//
// TBD, the sound of the bells
//
class AKI
{
private:
SingleLed *whiteLight;
DuoLed *redLights;
AkiStaat state = uit;
public:
//
// Create an instance of the AKI, using the specified Led objects
//
AKI(SingleLed *aWhiteLed, DuoLed *aRedLed)
{
whiteLight = aWhiteLed;
redLights = aRedLed;
state = uit;
}
//
// Activate the connected leds. TBD: the sound
//
void heartBeat()
{
redLights->heartBeat();
whiteLight->heartBeat();
}
void set(AkiStaat aState)
{
state = aState;
if (state == uit)
{
#if (DEBUG)
Serial.println("[AKI::set] AKI uit");
#endif
redLights->setOn(false);
whiteLight->setOn(true);
}
else
{
#if (DEBUG)
Serial.println("[AKI::set] AKI aan");
#endif
redLights->setOn(true);
whiteLight->setOn(false);
}
}
};
//
// Some sensors use a digital signal and keep it high when not active and drop the signal
// when the sensor trips, use in that case the laag setting. Others use a digital signal
// and are low when not active and make the signal high when the sensor trips, use in that case
// the hoog setting.
// if the sensor doesn't generate a digital signal, you have to use a pullup resistor (or INPUT_PULLUP)
// and in that case specify hoog.
//
enum SensorTrigger {laag, hoog};
//
// A simple class which represents the state of a single sensor
//
class Sensor
{
private:
int sensorPin;
SensorTrigger type = hoog;
bool state = false; // true = on, false = off
unsigned long lastTime = 0; // Timer to ignore short interrupts
#define JITTER_TIME 1000 // wait a second before the sensor goes off
public:
//
// Create a new instance
//
Sensor(int aPin)
{
sensorPin = aPin;
pinMode(sensorPin, INPUT);
}
//
// Create a new instance
//
Sensor(int aPin, SensorTrigger aType)
{
sensorPin = aPin;
type = aType;
pinMode(sensorPin, INPUT);
}
//
// Return the current logical state of the sensor
//
bool getState()
{
return state;
}
//
// Monitor the physical sensor and update the state accordingly
//
void heartBeat()
{
if (digitalRead(sensorPin) == HIGH)
{
if (type == laag) // For sensors type laag an high signal means they are in the off state
{
if (state != false) // Process this signal only when the current state is ON
{
if (lastTime == 0)
{
lastTime = millis(); // start Interval
}
else
{
unsigned long currTime = millis();
if ((currTime-lastTime) >= JITTER_TIME)
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor goes off");
#endif
state = false; // sensor goes OFF
lastTime = 0; // Reset interval timer
}
}
}
}
else
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor goes on");
#endif
state = true; // Sensor goes ON
lastTime = 0; // Reset interval timer
}
}
else // sensorPin = LOW
{
if (type == laag)
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor goes on");
#endif
state == true; // Sensor goes ON
lastTime = 0; // Reset interval timer;
}
else
{
if (state != false) // Process this signal only when the current state is ON
{
if (lastTime == 0)
{
lastTime = millis(); // start Interval
}
else
{
unsigned long currTime = millis();
if ((currTime-lastTime) >= JITTER_TIME)
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor goes off");
#endif
state = false; // sensor goes OFF
lastTime = 0; // Reset interval timer
}
}
}
}
}
}
};
//
// A finite state machine that guards a occupance of a single track
//
class SpoorControl
{
private:
Sensor *sensor1;
Sensor *sensor2;
SpoorState state = leeg;
//
// Based on the state of sensor 1 and the current state of the FSM, a new state
// is calculated.
//
void handleSensor1(bool trigger)
{
if (trigger) // Sensor 1 is ON
{
if (state == leeg) // If the state is "leeg" it means that a train enters the section
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is sensor1komend");
#endif
state = sensor1komend; // so set it to state komend
}
else if (state == sensor2komend) // if the other sensor tripped first
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is sensor1gaand");
#endif
state = sensor1gaand; // The train is starting to leave the section
}
}
else
{ // Sensor went OFF
if (state == sensor1gaand) // If the train started to leave via sensor 1
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is leeg");
#endif
state = leeg; // the section is "leeg"
}
}
}
//
// Based on the state of sensor 2 and the current state of the FSM, a new state
// is calculated.
//
void handleSensor2(bool trigger)
{
if (trigger) // Sensor 2 is ON
{
if (state == leeg) // Is the section "leeg"?
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is sensor2komend");
#endif
state = sensor2komend; // A Train entered the section via sensor 2
}
else if (state == sensor1komend) // No a train entered the section via the other sensor
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is sensor2gaand");
#endif
state = sensor2gaand; // Start the leaving process
}
}
else
{
if (state == sensor2gaand) // A train is in the process of leaving
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is leeg");
#endif
state = leeg; // Section is empty again
}
}
}
public:
//
// Create an instance with two sensors
//
SpoorControl(Sensor *aSensor1, Sensor *aSensor2)
{
sensor1 = aSensor1;
sensor2 = aSensor2;
}
//
// Get give the sensors a kick and check their state so we can update our own
// state.
//
void heartBeat()
{
sensor1->heartBeat();
sensor2->heartBeat();
handleSensor1(sensor1->getState());
handleSensor2(sensor2->getState());
}
//
// Return the current state of the section
//
SpoorState getState()
{
return state;
}
};
//
// Create 2 FSM controling two track sections
//
SpoorControl spoor1(new Sensor(A0, hoog), new Sensor(A1, hoog));
SpoorControl spoor2(new Sensor(A2, hoog), new Sensor(A3, hoog));
//
// Create an instance of the AKI
//
AKI aki(new SingleLed(A4, true), new DuoLed(A5, A6, false));
void setup()
{
#if (DEBUG)
//Serial.begin(9600);
Serial.begin(115200);
while (!Serial);
Serial.println("Starting");
Serial.flush();
#endif //DEBUG
}
void loop()
{
spoor1.heartBeat(); // These object must monitor their sensors
spoor2.heartBeat(); // so they can update their states
if ((spoor1.getState() == leeg) && (spoor2.getState() == leeg))
{
aki.set(uit); // Stop sound and flashing red lights
}
else
{
aki.set(aan); // Start flashing red lights and sound
}
aki.heartBeat(); // Let the AKI update it's connected bells and leds
}
Zoals jullie kunnen zien kom ik uit een andere IT wereld dan Gerard, dus ik probeer altijd zoveel mogelijk de functionaliteit in aparte classes (objecten) te stoppen.
Groet Meino
-
Ik heb een kleine opmerking over de code van Gerard. Ik zie dat hij de sensor pins initialiseer met INPUT_PULLUP, ik denk dat dat niet goed gaat werken, omdat deze bordjes zelf een goede 5v of een goede gnd maken. Ik initialiseer de pinnen dus met INPUT. Verder als de IR receiver geen IR ziet, dan zet hij het signaal hoog (5v), op het moment dat hij IR ziet, gaat het signaal naar low (0v). Dat betekend dat als de detector gemodificeerd wordt om als lichtsluis te werken, een HIGH signaal betekend dat de IR is onderbroken en een LOW signaal betekend dat IR niet onderbroken is.
Tenminste dat is de situatie met de benadering detectors die ik heb van het merk "Flying fish", die het zelfde zijn als die Edsko heeft aangeschaft.
@Gerard
Leuk stekje waar je naar toe gaat.
Groet Meino
-
Geïnspireerd door de vele berichten op dit forum wat je allemaal met Arduino kan, heb ik me er de laatste weken flink in verdiept en mee geëxperimenteerd. Geweldig hoeveel kennis hier gedeeld wordt!
Ik ben zelf meer een lezer dan een reageerder (sorry), maar wellicht kan ik hier toch even wat zinvols toevoegen als het gaat om stuiterende slagbomen.
Volgende link kwam ik namelijk tijdens mijn zoektochten op internet tegen. Het toont weliswaar een sketch voor locloodsdeuren, het principe van de versnelling en vertraging bij openen, en ook de terugvering, kan met kleine wijzigingen het gedrag van de eerder genoemde Duitse tutorial leuk benaderen.
Zie: http://www.locoduino.org/spip.php?article159
-
Jaren geprogrammeerd in zowel de Gerard als de Meino stijl, in alles waarmee te programmeren viel, maar toch allermeest als glu'er (5 regeltjes code schrijven om 2 programma's die niet voor elkaar gemaakt zijn, te laten samensmelten alsof ze een geheel zijn). Beide codes laten zich lezen als een speer. Mooie codes ook.
Maar ik voel me 't meest aangetrokken door Meino's aanpak (https://forum.beneluxspoor.net/index.php?topic=80179.msg3221861964#msg3221861964) vanwege het bereikte abstractieniveau:
//class SpoorControl
//
// Create 2 FSM controling two track sections
//
SpoorControl spoor1(new Sensor(A0, hoog), new Sensor(A1, hoog));
SpoorControl spoor2(new Sensor(A2, hoog), new Sensor(A3, hoog));
Ik ben alweer jaren geleden gestopt met dat werk als "mastergluer" (=lijmen-jan) ;D
Maar ik nam de code even door, en toen kwam het allemaal weer boven.
Ik zie nu in waarom Gerard en Meino van 4 sluisjes uit gaan op 4 aparte pinnen en niet van 4, 2 aan 2 aangesloten, sluisjes (wat weliswaar 2 arduino pinnen scheelt, maar ook aanzienlijk minder flexibel is).
Toch vraag ik me af of je met twee sluizen over 2 of meer sporen, niet beter af bent dan met 2 sluizen per spoor.
-
Aangespoord door de opmerking van NS264 toch maar de code herzien naar objecten. Ik werk graag met de classes in aparte files dus in mijn geval spat de sketch uiteen in drie files, de sketch en 2 ander files voor een class.
In tegen stelling tot wat Meino in zijn code alvast heeft gedaan, heb ik nog niet de AKI knipper-lichten van aansturing voorzien. Dit komt wel als dit door Edsko wat duidelijker gedefinieerd is.
Hieronder de nieuwe sketch:
// Definitie van de 4 ingangen voor de sensoren (2 per spoor)
#define SBBLSP1 2 // BlackBox Links, Spoor 1
#define SBBRSP1 3 // BlackBox Rechts, Spoor 1
#define SBBLSP2 4 // BlackBox Links, Spoor 2
#define SBBRSP2 5 // BlackBox Rechts, Spoor 2
#define DELAY 500 // Vertraging in milli seconde
#define NUMSPOREN 2 // Aantal sporen
#include "Spoor.h"
Spoor sporen[NUMSPOREN];
// Initialialatie van de Arduino
void setup() {
// put your setup code here, to run once:
// Define sporen
sporen[0] = Spoor(SBBLSP1, SBBRSP1, DELAY); // Spoor 1
sporen[1] = Spoor(SBBLSP2, SBBRSP2, DELAY); // Spoor 2
// LED uit
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
}
void loop() {
// put your main code here, to run repeatedly:
bool bezet = false;
for(int i = 0; i < NUMSPOREN; i++)
{
bezet |= sporen[i].calcBezet();
}
// Aansturen van de AKI / AHOB (overweg)
if (bezet) {
// Overweg gesloten
digitalWrite(LED_BUILTIN, HIGH);
} else {
// Overweg geopend
digitalWrite(LED_BUILTIN, LOW);
}
}
En in dezelfde directory als de sketch komen de twee volgende bestanden:
Filenaam Spoor.h (definitie van de class):
#ifndef Spoor_h
#define Spoor_h
#include "Arduino.h"
class Spoor {
public:
Spoor(); // for array
Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay);
bool calcBezet();
private:
bool readLinks();
bool readRechts();
byte _sensorLinks;
byte _sensorRechts;
bool _memLinks;
bool _memRechts;
unsigned long _timerLinks;
unsigned long _timerRechts;
// < 0: trein rijdt van rechts naar links
// 0: geen trein
// > 0: trein rijdt van links naar rechts
byte _dir;
int _sensorDelay;
};
#endif
Filenaam Spoor.cpp (functionaliteit van de class):
#include "Spoor.h"
Spoor::Spoor() {
// Empty constructor, don't use (for array)
}
Spoor::Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay) {
// Variabelen met externe waardes
_sensorLinks = sensorLinks;
_sensorRechts = sensorRechts;
_sensorDelay = sensorDelay;
// Maak de inputs met extra pullups
pinMode(_sensorLinks, INPUT_PULLUP);
pinMode(_sensorRechts, INPUT_PULLUP);
// Voorzie overige variabelen van een default value
_timerLinks = millis();
_timerRechts = millis();
_memLinks = readLinks();
_memRechts = readRechts();
_dir = 0;
}
bool Spoor::readLinks() {
// if (digitalRead(_sensorLinks) > 0) {
if (digitalRead(_sensorLinks) == 0) {
_timerLinks = millis() + _sensorDelay;
}
return (_timerLinks > millis());
}
bool Spoor::readRechts() {
// if (digitalRead(_sensorRechts) > 0) {
if (digitalRead(_sensorRechts) == 0) {
_timerRechts = millis() + _sensorDelay;
}
return (_timerRechts > millis());
}
// return true als bezet
bool Spoor::calcBezet() {
// fase: toestand nu en de vorige keer van de melder
// volgorde:
// 0: geen trein
// 1: voorkant trein
// 2: achterkant trein
// 3: trein aanwezig
byte fase;
// Links
fase = (_memLinks ? 2 : 0);
_memLinks = readLinks();
fase += (_memLinks ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (_dir == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
_dir++;
}
}
if (fase == 2) {
// Trein verlaat
if (_dir < 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
_dir++;
}
}
// Rechts
fase = (_memRechts ? 2 : 0);
_memRechts = readRechts();
fase += (_memRechts ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (_dir == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
_dir--;
}
}
if (fase == 2) {
// Trein verlaat
if (_dir > 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
_dir--;
}
}
return (_dir != 0);
}
Bij het openen van de sketch zal de Arduino IDE automatisch de beide class files mede openen in extra tabs.
PS. Mocht iemand Hilversum in de jaren 80 na willen bouwen, dan kan nu eenvoudig het aantal sporen uitgebreid worden.
Groet,
Gerard van der Sel.
-
Ik heb een kleine opmerking over de code van Gerard. Ik zie dat hij de sensor pins initialiseer met INPUT_PULLUP, ik denk dat dat niet goed gaat werken, omdat deze bordjes zelf een goede 5v of een goede gnd maken. Ik initialiseer de pinnen dus met INPUT. Verder als de IR receiver geen IR ziet, dan zet hij het signaal hoog (5v), op het moment dat hij IR ziet, gaat het signaal naar low (0v). Dat betekend dat als de detector gemodificeerd wordt om als lichtsluis te werken, een HIGH signaal betekend dat de IR is onderbroken en een LOW signaal betekend dat IR niet onderbroken is.
Tenminste dat is de situatie met de benadering detectors die ik heb van het merk "Flying fish", die het zelfde zijn als die Edsko heeft aangeschaft.
Waarom INPUT_PULLUP in plaats van INPUT. Edsko gaat werken met straal breking. Dit betekend dat de pen van de uitgang altijd laag is, tenzij er een trein de straal onderbreekt. Als extra beveiliging gebruik ik de INPUT_PULLUP, zodat bij draadbreuk tussen sensor en Arduino de Ardiono een bezette sensor ziet. Dit heeft bij reflectie geen zin en kan zelfs tot misvattingen leiden.
@Meino: Er is nog een verschil. Ik heb 30 jaar bij de NS (waaronder Movares) gewerkt. Je krijgt dan tussen je oren gestampt dat een fout in de software mensenlevens kan kosten. Dus veel code en hardware ontwerpen hebben dit nog steeds als achtergrond. Ik ben onbewust altijd opzoek naar passieve beveiligingen.
Groet,
Gerard van der Sel.
-
Jan Willem,
Toch vraag ik me af of je met twee sluizen over 2 of meer sporen, niet beter af bent dan met 2 sluizen per spoor.
Ik zal het proberen te verklaren. Stel je voor twee parallelle sporen met hierover zoals jij aangeeft een sluis op basis van straal onderbreking.
Op beide sporen rijdt een trein, en ze rijden naar elkaar toe (moet kunnen toch ;D).
Een van beide treinen komt aan bij de sluis en doorbreekt de straal. De trein wordt gemeld. Terwijl deze trein door de sluis rijdt komt de andere trein ook bij de sluis. Deze kan zich niet melden, want de eerste trein heeft de straal al onderbroken. Als de eerste trein geheel weg is en de tweede trein bevindt zich nog in de sluis zal deze het onderbreken van de straal voor zijn rekening nemen. Als tenslotte de sluis weer vrij is, zal de sluis een trein gemeld hebben, terwijl er toch twee door gegaan zijn.
Ik hoop dat het voorbeeld helpt om het beveiligen te begrijpen. Je kan met een sluis over meerdere sporen werken, als je zeker weet dat er maar een trein tegelijk door de sluis gaat. Een voorbeeld hiervan is in een schaduw station. Je kunt met een straal de einden van alle sporen bewaken, als je maar zorgt dat de trein die het laatst de straal heeft doorbroken een stukje terug rijdt. Dit kan je bij Koploper zien in een schaduwstation.
Groet,
Gerard van der Sel.
-
Even in "Grasland" gekeken voor de juiste opstelling. De overweg bevind zich links op de module. Dus er is een ongelijke tijd voor het aanrijden van de AKI. Is in dit geval niet storend, daar de korte aanrijtijd door de BBL (blackbox links) gecamoufleerd wordt. De rode lijnen zijn de 4 sensoren voor de AKI aansturing.
Tenzij je in de rechter BB van je linker buurman/vouw een uitschuifbare set lichtsensoren monteert zodat de in/uitrij tijd iets verlengt kan worden...
-
En als Edsko besluit voor een keer mee te doen met de BMB, waar men links rijdt?!? werkt het dan ook nog
zo goed?
-
Richard,
Het geheel is door Edsko "gespecificeerd" op twee richtingen per spoor. Dus IEDER spoor kan zowel van links naar rechts als van rechts naar links bereden worden met een werkende AKI.
Dus mocht Edsko ooit met BMB mee willen doen, dan zal de AKI geen spelbreker zijn.
Ik denk dat het grootste probleem het uitschakelen van de AKI wordt. Aan beide kanten rijdt de trein volledig van de module af voordat de AKI open gaat en de bel stopt.
Groet,
Gerard van der Sel.
-
Tenzij je in de rechter BB van je linker buurman/vouw een uitschuifbare set lichtsensoren monteert zodat de in/uitrij tijd iets verlengt kan worden...
Leuk idee, maar dat ga ik niet doen. Lekker simpel houden. Het ding komt zo veel als mogelijk tegen de BB van de buurman aan.
-
Ik denk dat het grootste probleem het uitschakelen van de AKI wordt.
Oplossing: hamer (niet erg vriendelijk) of stekker eruit (wel vriendelijk)
-
Wat gebeurt er als een (korte) trein helemaal tussen twee lichtsluizen past? Op dat moment melden beide 'laag' en dan zou de aki open gaan, terwijl er een trein overheen rijdt.
-
Waarom INPUT_PULLUP in plaats van INPUT. Edsko gaat werken met straal breking. Dit betekend dat de pen van de uitgang altijd laag is, tenzij er een trein de straal onderbreekt. Als extra beveiliging gebruik ik de INPUT_PULLUP, zodat bij draadbreuk tussen sensor en Arduino de Ardiono een bezette sensor ziet. Dit heeft bij reflectie geen zin en kan zelfs tot misvattingen leiden.
@Meino: Er is nog een verschil. Ik heb 30 jaar bij de NS (waaronder Movares) gewerkt. Je krijgt dan tussen je oren gestampt dat een fout in de software mensenlevens kan kosten. Dus veel code en hardware ontwerpen hebben dit nog steeds als achtergrond. Ik ben onbewust altijd opzoek naar passieve beveiligingen.
Dat wist ik niet Gerard, dat maakt wel een verschil. Overigens ik heb geen electronica achtergrond maar ik weet ondertussen wel waarvoor een pullup weerstand dient. Maar omdat hierdoor er twee bronnen zijn die 5v leveren op de input pin, vertrouwde ik dat niet. Maar dat kan dus zonder problemen, weer wat geleerd.
Voordat ik morgen ook vertrek heb ik nog even mijn code uitgeprobeerd op een test opstelling met twee sensors (mijn snelheids meter voor het ijken van locomotieven), daar kwam nog een klein foutje in de code uit, vandaar nog even een nieuwe versie.
#define DEBUG 0
enum SpoorState {leeg,
sensor1komend,
sensor2komend,
sensor1gaand,
sensor2gaand
};
//
// Class for a single (white) led which flickers 50 times per
// minute when on
//
class SingleLed
{
private:
int ledPin;
bool ledOn = true;
int interval = 600; // *** 50 keer per minuut
bool lightOn = false;
unsigned long lastTime;
public:
//
// Create a new instance of a (white) led, connect it to the specified
// digital pin and put it in the specified state (true = on, false = off)
//
SingleLed(int aPin, bool state)
{
ledPin = aPin;
ledOn = state;
lightOn = false;
pinMode(ledPin, OUTPUT);
lastTime = millis();
}
//
// Set the state of the led (true = on, false = off)
//
void setOn(bool state)
{
#if (DEBUG)
if (ledOn != state)
{
Serial.print("[SingleLed::setOn]");
if (state)
Serial.println(" aan");
else
Serial.println(" uit");
}
#endif
ledOn = state;
}
//
// If the state is on, put power on the pin of the led, using timers
// to make the flicker work.
// If the led is off, remove the power from the pin of the led.
//
void heartBeat()
{
if (ledOn) // Do we need to light the led?
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= interval) // Has the interval time passed?
{
lastTime = currTime; // Start new interval
if (!lightOn) // Was the led lighted?
{
#if (DEBUG)
Serial.println("[SingleLed::heartBeat] led aan");
#endif
digitalWrite(ledPin, HIGH); // No, so switch it on
lightOn = true;
}
else
{
#if (DEBUG)
Serial.println("[SingleLed::heartBeat] led uit");
#endif
digitalWrite(ledPin, LOW); // Yes, so switch it off
lightOn = false;
}
}
}
else if (lightOn) // No light, but is the led still on?
{
#if (DEBUG)
Serial.println("[SingleLed::heartBeat] led uit");
#endif
digitalWrite(ledPin, LOW); // Switch ir off
lightOn = false;
}
}
};
//
// Class for a set of two (red) leds which alternate(flicker) 50 times per
// minute when on
//
class DuoLed
{
private:
int led1Pin;
int led2Pin;
bool ledOn = true;
int interval = 600; // *** 50 keer per minuut
bool lightOn = false;
bool phase = false;
unsigned long lastTime;
public:
//
// Create a new instance, connect it to the specified
// digital pins and put it in the specified state (true = on, false = off)
//
DuoLed(int aPin1, int aPin2, bool state)
{
led1Pin = aPin1;
led2Pin = aPin2;
ledOn = state;
lightOn = false;
phase = false;
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
lastTime = millis();
}
//
// Set the state of the leds (true = on, false = off)
//
void setOn(bool state)
{
#if (DEBUG)
if (ledOn != state)
{
Serial.print("[DuoLed::setOn]");
if (state)
Serial.println(" aan");
else
Serial.println(" uit");
}
#endif
ledOn = state;
}
//
// If the state is on, put power on the pins of the leds, using timers
// to make the alternating flicker work.
// If the led is off, remove the power from the pins of the leds.
//
void heartBeat()
{
if (ledOn) // Are the leds activated
{
lightOn = true;
unsigned long currTime = millis();
if ((currTime - lastTime) >= interval) // Has the interval passed?
{
lastTime = currTime; // Yes, start new interval
if (!phase) // The leds alternate, are we in phase1 (led1 on, led2 off)
{
#if (DEBUG)
Serial.println("[DuoLed::heartBeat] led1 aan, led2 uit");
#endif
digitalWrite(led1Pin, HIGH); // Yes, led1 on
digitalWrite(led2Pin, LOW); // led2 off
phase = true; // When the interval expires, switch the leds
}
else // We are in phase2 (led1 off, led2 on)
{
#if (DEBUG)
Serial.println("[DuoLed::heartBeat] led1 uit, led2 aan");
#endif
digitalWrite(led1Pin, LOW); // Led1 off
digitalWrite(led2Pin, HIGH); // Led2 on
phase = false; // When the interval expires, switc the leds
}
}
}
else // The leds are not active, switch of both leds
{
if (lightOn)
{
#if (DEBUG)
Serial.println("[DuoLed::heartBeat] led1 uit, led2 uit");
#endif
digitalWrite(led1Pin, LOW);
digitalWrite(led2Pin, LOW);
lightOn = false;
}
}
}
};
enum AkiStaat {aan, uit};
//
// A simple class that represents a complet AKI with all its leds
//
// TBD, the sound of the bells
//
class AKI
{
private:
SingleLed *whiteLight;
DuoLed *redLights;
AkiStaat state = uit;
public:
//
// Create an instance of the AKI, using the specified Led objects
//
AKI(SingleLed *aWhiteLed, DuoLed *aRedLed)
{
whiteLight = aWhiteLed;
redLights = aRedLed;
state = uit;
}
//
// Activate the connected leds. TBD: the sound
//
void heartBeat()
{
redLights->heartBeat();
whiteLight->heartBeat();
}
void set(AkiStaat aState)
{
#if (DEBUG)
if (state != aState)
{
Serial.print("[AKI::set]");
if (aState == uit)
Serial.println(" uit");
else
Serial.println(" aan");
}
#endif
state = aState;
if (state == uit)
{
redLights->setOn(false);
whiteLight->setOn(true);
}
else
{
redLights->setOn(true);
whiteLight->setOn(false);
}
}
};
//
// Some sensors use a digital signal and keep it high when not active and drop the signal
// when the sensor trips, use in that case the "laag" setting. Others use a digital signal
// and are low when not active and make the signal high when the sensor trips, use in that case
// the "hoog" setting.
// if the sensor doesn't generate a digital signal, you have to use a pullup resistor (or INPUT_PULLUP)
// and in that case specify hoog.
//
// The Flying Fish proximity detectors, when used in reflective mode, need the "laag" setting,
// when their sensors are removed and positioned opposit each other, they need the "hoog" setting
//
enum SensorTrigger {laag, hoog};
//
// A simple class which represents the state of a single sensor
//
class Sensor
{
private:
int sensorPin;
SensorTrigger type = hoog;
bool state = false; // true = on, false = off
unsigned long lastTime = 0; // Timer to ignore short interrupts
#define JITTER_TIME 1000 // wait a second before the sensor goes off
public:
//
// Create a new instance
//
Sensor(int aPin)
{
sensorPin = aPin;
pinMode(sensorPin, INPUT);
}
//
// Create a new instance
//
Sensor(int aPin, SensorTrigger aType)
{
sensorPin = aPin;
type = aType;
pinMode(sensorPin, INPUT);
}
//
// Return the current logical state of the sensor
//
bool getState()
{
return state;
}
//
// Monitor the physical sensor and update the state accordingly
//
void heartBeat()
{
if (digitalRead(sensorPin) == HIGH)
{
if (type == laag) // For sensors type laag an high signal means they are in the off state
{
if (state != false) // Process this signal only when the current state is ON
{
if (lastTime == 0)
{
lastTime = millis(); // start Interval
}
else
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= JITTER_TIME)
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor(laag) goes off");
#endif
state = false; // sensor goes OFF
lastTime = 0; // Reset interval timer
}
}
}
}
else
{
#if (DEBUG)
if (state != true)
{
Serial.println("[Sensor::heartBeat] sensor(hoog) goes on");
}
#endif
state = true; // Sensor goes ON
lastTime = 0; // Reset interval timer
}
}
else // sensorPin = LOW
{
if (type == laag)
{
#if (DEBUG)
if (state != true)
{
Serial.println("[Sensor::heartBeat] sensor(laag) goes on");
}
#endif
state = true; // Sensor goes ON
lastTime = 0; // Reset interval timer;
}
else
{
if (state != false) // Process this signal only when the current state is ON
{
if (lastTime == 0)
{
lastTime = millis(); // start Interval
}
else
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= JITTER_TIME)
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor(hoog) goes off");
#endif
state = false; // sensor goes OFF
lastTime = 0; // Reset interval timer
}
}
}
}
}
}
};
//
// A finite state machine that guards a occupance of a single track
//
class SpoorControl
{
private:
Sensor *sensor1;
Sensor *sensor2;
SpoorState state = leeg;
//
// Based on the state of sensor 1 and the current state of the FSM, a new state
// is calculated.
//
void handleSensor1(bool trigger)
{
if (trigger) // Sensor 1 is ON
{
if (state == leeg) // If the state is "leeg" it means that a train enters the section
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is sensor1komend");
#endif
state = sensor1komend; // so set it to state komend
}
else if (state == sensor2komend) // if the other sensor tripped first
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is sensor1gaand");
#endif
state = sensor1gaand; // The train is starting to leave the section
}
}
else
{ // Sensor went OFF
if (state == sensor1gaand) // If the train started to leave via sensor 1
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is leeg");
#endif
state = leeg; // the section is "leeg"
}
}
}
//
// Based on the state of sensor 2 and the current state of the FSM, a new state
// is calculated.
//
void handleSensor2(bool trigger)
{
if (trigger) // Sensor 2 is ON
{
if (state == leeg) // Is the section "leeg"?
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is sensor2komend");
#endif
state = sensor2komend; // A Train entered the section via sensor 2
}
else if (state == sensor1komend) // No a train entered the section via the other sensor
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is sensor2gaand");
#endif
state = sensor2gaand; // Start the leaving process
}
}
else
{
if (state == sensor2gaand) // A train is in the process of leaving
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is leeg");
#endif
state = leeg; // Section is empty again
}
}
}
public:
//
// Create an instance with two sensors
//
SpoorControl(Sensor *aSensor1, Sensor *aSensor2)
{
sensor1 = aSensor1;
sensor2 = aSensor2;
}
//
// Get give the sensors a kick and check their state so we can update our own
// state.
//
void heartBeat()
{
sensor1->heartBeat();
sensor2->heartBeat();
handleSensor1(sensor1->getState());
handleSensor2(sensor2->getState());
}
//
// Return the current state of the section
//
SpoorState getState()
{
return state;
}
};
//
// Create 2 FSM controling two track sections
//
SpoorControl spoor1(new Sensor(A0, laag), new Sensor(A1, laag)); // Sensor works reflective
SpoorControl spoor2(new Sensor(A2, laag), new Sensor(A3, laag));
//
// Create an instance of the AKI
//
AKI aki(new SingleLed(A4, true), new DuoLed(A5, A6, false));
void setup()
{
#if (DEBUG)
//Serial.begin(9600);
Serial.begin(115200);
while (!Serial);
Serial.println("Starting");
Serial.flush();
#endif //DEBUG
}
void loop()
{
spoor1.heartBeat(); // These object must monitor their sensors
spoor2.heartBeat(); // so they can update their states
if ((spoor1.getState() == leeg) && (spoor2.getState() == leeg))
{
aki.set(uit); // Stop sound and flashing red lights
}
else
{
aki.set(aan); // Start flashing red lights and sound
}
aki.heartBeat(); // Let the AKI update it's connected bells and leds
}
Uit het testen bleek wel dat deze Flyijng Fish sensors erg gevoelig zijn voor omgevings licht. Ik deed de test even in mijn serre, maar daar werkte het voor geen meter. Totdat ik me realiseerde (aan de hand van de ledjes op de sensor) dat ze altijd aan waren. Pas toen ik weer in de kelder met de treinbaan was, werkte het naar behoren. Dus let op voor omgevings licht.
Groet Meino
-
Wat gebeurt er als een (korte) trein helemaal tussen twee lichtsluizen past? Op dat moment melden beide 'laag' en dan zou de aki open gaan, terwijl er een trein overheen rijdt.
dat is geen probleem, omdat zowel bij mijn code als de code van Gerard het treinvak pas weer vrijgegeven wordt op het moment dat de trein de tweede sensor activeert en vervolgens de tweede sensor in zijn geheel gepasseerd is. Het feit dat de eerste sensor gepasseerd is heeft geen invloed op de status van het treinvak. Het gaat dus niet om de status van een enkele sensor, maar de volgorde van de statussen van de sensors die bepalen of een treinvak bezet of vrij is.
Overigens zijn er wel scenario's dat het niet goed gaat. Bijv. als een trein de module binnen komt, stopt en dan terug rijdt, kan niet correct afgehandeld worden met de informatie die beschikbaar komt van de lichtsluisjes.
Groet Meino
-
@Meino,
Kijk even in mijn code. De situatie die ontstaat is niet correct,maar wel veilig. De AKI blijft gewoon gesloten. Pas een volgende trein uit de richting waar de eerdere trein kwam zal de boel herstellen, naast opnieuw starten.
Groet,
Gerard van der Sel.
PS. Goede reis en tot over een week dan maar.
-
Dag Gerard
ik had je code bekeken en wat ik zag leek voor betreffende de states erg op mijn code (ook 3 states)
Ik hanteer voor een spoor de volgende states, leeg, komend en gaand. Alleen bij status leeg zal de AKI uit zijn. De volgorde van de gebeurtenissen is bij mij:
- een trein arriveert bij sensor 1, state gaat van leeg naar komend. Vanaf nu worden alle events die van sensor 1 komen weggegooid.
- De trein ariveert bij sensor 2, state gaat van komend naar gaand.
- De trein verlaat de BB en sensor 2 gaat weer naar af, state gaat van gaand naar leeg. Om te voorkomen dat dit te snel getriggered wordt (door korte onderbrekingen) zit er een timer op het naar af gaan van een sensor. Hij moet minimaal 1 seconde af zijn voordat het als een gebeurtenis wordt opgepikt.
Als de trein van de andere kant komt, vindt in principe de zelfde volgorde van state wisselingen plaats. Ik heb je code niet al te diep bekeken, maar ik had het idee dat je de zelfde volgorde van soortgelijke state wisseling hebt geimplementeerd.
Bedankt en jij ook nog een goede reis.
Groet Meino
-
Is het niet veel handiger om met een bezetmelder op basis van stroomdetectie te werken - aangenomen dat behalve de loc ook iedere wagon stroom trekt en voor zover dat niet in strijd is met de eis dat er niets aan de trein veranderd mag worden?
Dat betekent dan dat het met een eenvoudige elektronische schakeltrap (zonder processor) kan worden gerealiseer: bezet = dicht, vrij = open (en je hebt ook geen last van omgevingslicht).
-
Hi,
dat zou in principe kunnen. Echter, dan moet ik van alle deelnemers aan de baan gaan vragen of ze al hun rijdend materieel dat op de baan gaat rijden, stroom moeten afnemen op ale wielen. Dat kan ik niet vragen, vandaar de lichtsluis.
-
NS264 (Koen),
Gebruik jij een servo of een stappenmotor voor je overgenomen. Een servo is gemakkelijker.
Ik kan in de linken die jij gegeven hebt niet echt het stuiteren van de boom terugvinden, wel mooie lineaire bewegingen. Is het de bedoeling dat de bomen ook na stuiteren? Beneden en boven neem ik aan.
Groet,
Gerard van der Sel.
-
Hte is hier nog een beetje rustig. Te warm om nu te gaan knutselen en ook mijn tuin vraagt wel wat aandacht momenteel.
Ik heb echter wel goede hoop dat ik er deze week nog ergens aan toe ga komen. :)
-
Ook laatste restje vakantie aan het vieren.
Ik kom er later vandaag op terug.
Een stuiterende boom is leuk maar niet perse noodzakelijk, slechts detail.
De link nr de Duitse forum laat ook vertraging zien met behulp van tandwielen, leuk, maar als je al een mooie beweging hebt met en servo is dat genoeg.
BTW ik heb een steppen controller voor de arduino om of 2 servo te bedienen of een motor.
Ik open een eigen draadje straks omdat het afwijkt van Edsko's plan.
Gr Koen.
Ow, en fotocellen voor detectie.
-
Servo's kun je direct aan de Arduino aansluiten. Daar heb je geen versterker bij nodig. Stuiteren vergt een patroon ipv een lineaire beweging. Die komt uit een formule of een tabel. Is het wel goed dat we een versie van de software maken?
Groet,
Gerard van der Sel.
-
Weet niet of Edsko het er mee eens is maar ik ben hier (https://forum.beneluxspoor.net/index.php?topic=80381.msg3221865206;topicseen#msg3221865206)begonnen.
Gr Koen.
-
Zo. Ik heb eindelijk eens de Arduino IDE geïnstalleerd en de code van Gerard gecompiled. Ik wil uiteindelijk zowel de code van Gerard als van Meino eens proberen om te zien wat de evt verschillen zijn, zo die er al zijn.
Ik ben een complete leek op het gebied van Arduino's, dus heb aub even geduld met mijn onkunde in deze toch wel interessante materie. ;)
Ik heb de code dus gecompiled en zal deze morgen eens proberen te laden in de Arduino UNO die ik heb.
Maar nu het volgende. :) Ik heb hier ook twee ali lichtsluisjes voor me liggen. Ik neem maar even aan dat ik de witte led er ongestraft af kan solderen. Maar dan? Ik heb hier een solderless breadboard voor me liggen en wat draadjes met stekkertjes eraan en zo. Allemaal leuk, maar ik heb (nog) geen idee van hoe en of wat. Dat zal allemaal wel goed komen, maar hoe nu verder?
Ik heb ook nog een zakje met losse ledjes erin en wat weerstandjes. Maar ik weet dus niet hoe ik zo'n breadboard opbouw. :-\ Wie helpt me op weg?
Gr.
Edsko
-
... ik weet dus niet hoe ik zo'n breadboard opbouw.
Je prikt de onderdelen in de gaatjes en verbindt ze volgens het schema met elkaar met die insteekdraadjes. De kolommen met gaatjes zijn al met elkaar verbonden. De twee regels (blauw en rood) langs de boven- en onderrand ook.
https://en.wikipedia.org/wiki/Breadboard (https://en.wikipedia.org/wiki/Breadboard)
-
Heyhoi Edsko hier zijn we ook al wat aan het testen geslagen met lichtsluizen en oplossingen mbt de treinlift, seinen en laad/lossysteem. Kom eens kijken hier als met name Ruud en Paul van de EMV en/of Nico hier ook aanwezig zijn. (y)
Groetjes Jake
-
Edsko,
Als je een Led lossoldeert, dan kun je deze niet in het breadboard prikken. De pootjes zijn te kort, vervuild met resten tin. Probeer er draden aan te solderen en doe die in je breadboard. Dit werkt voor experimenten hardstikke leuk.
Groet,
Gerard van der Sel.
-
Terug van de korte vakantie. Nu volgende aanpakken verbouwen en verhuizen. Wel nieuwe tandwielen met motor (https://images.beneluxspoor.net/bnls/TandwielenMotor.jpg) voor de draaischijf gekocht. Moeten nog op de Arduino aangesloten worden.
Hoe staat het met het testen. Krijg je al wat aan de gang?
Groet,
Gerard van der Sel.
-
Tenminste 30 dagen... Nou, daar ga ik wel heel erg ruim overheen... :-X ::)
Deze ook maar weer eens oppakken. Ik begin weer van voren af aan, want de PC waarop ik de gecompilede code had staan, is vervangen. Natuurlijk heb ik die code weggemikt, zo hoort dat als je je PC gaat vervangen... ::)
Dus, binnenkort hier ook weer verder mee. Zal toch een keer af moeten. ;)
Gr.
Edsko
-
Zeau, ben ik weer....
Heb wat lopen prutsen de afgelopen dagen aan de opstelling.
Onderstaand de eerste poging. En die werkte niet. De IR LED bleek naar de gallemiezen kwam ik later achter....
(https://images.beneluxspoor.net/bnls/IMG-20210322-WA0006-60591dbaa7660.jpg) (https://images.beneluxspoor.net/bnls/IMG-20210322-WA0006-60591dbaa7660.jpg)
Dan maar eens kijken of het ding überhaupt werkt zónder dat ik er aan loop te rotzooien.
(https://images.beneluxspoor.net/bnls/IMG-20210322-WA0004-60591dbab93c6.jpg) (https://images.beneluxspoor.net/bnls/IMG-20210322-WA0004-60591dbab93c6.jpg)
(https://images.beneluxspoor.net/bnls/20210322-132609-60591dbcd272d.jpg) (https://images.beneluxspoor.net/bnls/20210322-132609-60591dbcd272d.jpg)
Jazeker! Werkt! Mooi, door naar de volgende stap, opnieuw de IR-LED verwijderen en met een draadje doorverbinden.
Zou het nu wel werken?
(https://images.beneluxspoor.net/bnls/20210322-165055-60591dbd57cea.jpg) (https://images.beneluxspoor.net/bnls/20210322-165055-60591dbd57cea.jpg)
Ja hoor, doet het. En dus door naar de volgende test.
(https://images.beneluxspoor.net/bnls/20210322-170706-60591dbf33736.jpg) (https://images.beneluxspoor.net/bnls/20210322-170706-60591dbf33736.jpg)
Potvolblommen! :D Het concept werkt. Leuk!
Nu door naar het volgende. En dat is een plankje met rails maken waarop ik het concept in het klein ga testen.
Gr.
Edsko
-
Edsko
die code zwerft ongetwijfeld nog ergens op mijn laptop. Anders heb ik nog wel een stukje code van mijn (werkende) AKU.
Groet Meino
-
Hey MNeino,
zou fijn zijn als dat er nog is. :) Eens kijken wat ik daar mee kan. :)
Gr.
Edsko
-
Ik heb ooit een werkend ahob programma gemaakt. Ik meen dat een iemand er gebruik van heeft gemaakt en hij was tevreden. Programma is zo geschreven zodat hij met 1 of 2 sporen kan werken waarbij het niet uitmaakt naar welke kant de treinen rijden.
Zonder al te veel moeite kan je er ook een aki van maken, je hoeft volgens mij alleen de knipperende witte lamp toe te voegen. Er zit natuurlijk ook code in voor het gebruik van servo motoren voor bomen. Dat kan je weghalen of laten staan.
Denk je dat je het zelf kan aanpassen? Anders kijk ik ff in d'n middagpauze voor je als je wilt.
https://github.com/bask185/ahob (https://github.com/bask185/ahob)
Mvg,
Bas
-
Dank voor het aanbod Bas. Eerst eens mijn testplankje maken. ;)
Ik wil eens kijken of het werkt wat ik wil, zal ongetwijfeld.
Het doel:
- Twee sporen.
- In- en uitrij sluis per spoor.
- Eén spoor met een driehoogte sein uit stelsel '46.
- Werkende AKI (5 lampen per AKI, 2 achterzijde, 3 voorzijde).
- Werkende bel voor de AKI.
Kortom, best een leuke opstelling.
Het drie hoogte sein werkt niet op een bezetmelder, maar mag gewoon op tijd. Is gewoon een leuke gimmick en niets meer.
Dus, plankje maken en gaan.
-
Ik wil eens kijken of het werkt wat ik wil, zal ongetwijfeld.
De software zal geen bottle neck zijn. Als je alles goed aansluit, komt het wel goed.
Die bel is wel een leuke uitdaging. Er zijn ook meerdere manieren voor om dat werkend te krijgen. Meino hier heeft het hele geheugen van een arduino volgeklapt met een audio fragment. Klaas Zondervan had een leuke analoge oplossing die andere ging klinken als een passerende trein teveel stroom trok ;D.
Ik heb zelf een arduino een .WAV af laten spelen van een SD kaart en een enkele transistor als versterker. Een kerel had een library gemaakt en gedeeld op instructables. Het was echt ontzettend simpel en goedkoop om het na te doen. Je kan ook op ali kijken voor mp3 modules die met een arduino kunnen interfacen. Daar zijn er zat van te vinden ;) Ik heb er zelf 2 liggen, maar ik ben er nog niet mee bezig geweest.
Het drie hoogte sein werkt niet op een bezetmelder, maar mag gewoon op tijd. Is gewoon een leuke gimmick en niets meer.
Ik heb mijn seinmodule ook ontworpen dat ze op tijd gaan werken mits ze niet zijn verbonden aan een ander sein. De tijd gaat dan lopen als de bezetmelder de trein niet meer ziet. De tijd kan ik instellen met de potmeter en met schakelaars kan ik het sein vertellen of hij 3 of 2 lampen heeft (y). Dus ze werken dan wel met een bezetmelder, maar dat kan dus ook een korte zijn zoals een lichtsluis ::)
Bas
-
Edsko
De code die ik destijds voor je geschreven had, kan ik ook niet meer terugvinden. Gek genoeg heb ik nog wel de versie van Gerard op mijn computer. Ik denk dat ik met mijn eigen code zelf verder ben gegaan voor de AKI die ik heb ontwikkeld. Ik ga die code voor mijn AKI wel even klaar maken in een versie die zonder de Canbus werkt. Verder heb ik ook nog een schets voor een Arduino Nano voor het belgeluid. Die Nano stuurt een audioversterkertje met een speakertje aan. Die koppel je met een pin aan de Arduino die de AKI bestuurd. Pin hoog, bel gaat klingelen, pin laag geluid stopt. Zie https://forum.beneluxspoor.net/index.php?topic=77057.msg3222115129#msg3222115129 (https://forum.beneluxspoor.net/index.php?topic=77057.msg3222115129#msg3222115129) en
https://forum.beneluxspoor.net/index.php?topic=90291.msg3222116019#msg3222116019 (https://forum.beneluxspoor.net/index.php?topic=90291.msg3222116019#msg3222116019)
Misschien kun je dat gebruiken. Verder wil je ook nog iets met een driehoogtesein '46. Ik zal ook wat code bijvoegen om dat ding aan te sturen.
Misschien moeten we eens wat afspreken.
Groet Meino
-
Gebruik je geen github voor je hobby projecten, Meino ???
-
Bas
Het simpele antwoord is nee. Ik heb in mijn werk net een staartje van Git meegemaakt, toen een aantal lieden besloten dat Git goedkoper was dan Clearcase en dus beter was voor het doen van projecten (wat een ramp!). Verder heb ik geen behoefte om mijn handel uitgebreid te publiceren, die tijd heb ik gehad.
Groet Meino
-
jaja, ruim 30 dagen.... :angel:
Dus.... eindelijk tijd gehad om mijn test plankje af te maken. Ik wil eens kijken of ik dit ding aan de praat kan krijgen en kan laten zien in de stand op Rijswijk. Gewoon omdat het kan. :)
(https://images.beneluxspoor.net/bnls_2022/20220918-233100-1-63278ed268d03.jpg) (https://images.beneluxspoor.net/bnls_2022/20220918-233100-1-63278ed268d03.jpg)
Nu het plankje klaar is (ok, de LED's om de AKI te simuleren missen nog), wordt het ook tijd om de code in de Arduino te plaatsen.
Dus ik heb de laatste code van Gerard erbij gepakt, gekopieerd naar een Notepad file, en er uiteindelijk drie losse files van gemaakt.
Het openen van de sketch gaat prima, de andere twee files openen ook keurig. Geen probleem daarmee.
Wel een probleem, een heleboel eigenlijk, tijdens het compileren van de zaak.
Veel meldingen "Spoor.h:8:1: error: stray '\302' in program Spoor(); // for array"
Het lijkt er op dat ik veel spaties "even" opnieuw mag zetten. Dus dat "klusje" ga ik ook maar doen.
Maar goed, belangrijkste is dat ik hier weer mee bezig ben. De testopstelling werkt tot dusverre. Er gaat een lampje op de "FlyFish" aan en uit als ik mijn hand of een wagentje tussen de sensoren stop. Dus dat is veelbelovend.
Nu nog "even" een imitatie AKI maken mbv wat LED's en ikke is bijna klaar. Nog wel even de code aanpassen naar de AKI begreep ik uit de teksten van Gerard vd Sel. Nu maar hopen dat Gerard nog meeleest na 4 jaar... :-X :-\
Gr.
Edsko
-
Zo, meteen ook maar een update. :)
Zojuist nog even geprobeerd of de boel draaiend te krijgen was, dus alle spaties vervangen. Was een klusje, maar klaar.
Boel compileerde netjes en dus ook maar geüpload naar de Arduino UNO. Ging ook prima.
Als ik de code goed begrijp, zou de code het onboard led aan en uit moeten schakelen. Aan gaat prima, uit niet meer. Ja, 500ms of zoiets, eenmalig, maar dan houdt het op. Maar goed, ik ben wel weer wat verder. (y)
Ik dacht even output te gaan printen, maar dat werkte niet. Nu is het ook te laat om me daar nu nog druk om te gaan maken.
Volgende klusje is het klaarmaken van een imitatie AKI. Wel een van drie lampen. Ook al wordt het op mijn baan 5 ledjes, drie aan de voorzijde, twee aan de achterzijde. Nu eerst een van drie.
Dus de bovenste dan langzaam knipperend, de onderste twee uit. Bij bezet de onderste twee afwisselend knipperend en de bovenste uit. (y)
Nu eerst pitten.
Gr.
Edsko
-
Je kan hier wat code posten of me PB'en als je ergens niet uitkomt. Een veelvoud van 2 ogen zien meer dan een enkelvoud van 2 ogen ::)
Mvg,
Bas
-
Aangespoord door de opmerking van NS264 toch maar de code herzien naar objecten. Ik werk graag met de classes in aparte files dus in mijn geval spat de sketch uiteen in drie files, de sketch en 2 ander files voor een class.
In tegen stelling tot wat Meino in zijn code alvast heeft gedaan, heb ik nog niet de AKI knipper-lichten van aansturing voorzien. Dit komt wel als dit door Edsko wat duidelijker gedefinieerd is.
Hieronder de nieuwe sketch:
// Definitie van de 4 ingangen voor de sensoren (2 per spoor)
#define SBBLSP1 2 // BlackBox Links, Spoor 1
#define SBBRSP1 3 // BlackBox Rechts, Spoor 1
#define SBBLSP2 4 // BlackBox Links, Spoor 2
#define SBBRSP2 5 // BlackBox Rechts, Spoor 2
#define DELAY 500 // Vertraging in milli seconde
#define NUMSPOREN 2 // Aantal sporen
#include "Spoor.h"
Spoor sporen[NUMSPOREN];
// Initialialatie van de Arduino
void setup() {
// put your setup code here, to run once:
// Define sporen
sporen[0] = Spoor(SBBLSP1, SBBRSP1, DELAY); // Spoor 1
sporen[1] = Spoor(SBBLSP2, SBBRSP2, DELAY); // Spoor 2
// LED uit
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
}
void loop() {
// put your main code here, to run repeatedly:
bool bezet = false;
for(int i = 0; i < NUMSPOREN; i++)
{
bezet |= sporen[i].calcBezet();
}
// Aansturen van de AKI / AHOB (overweg)
if (bezet) {
// Overweg gesloten
digitalWrite(LED_BUILTIN, HIGH);
} else {
// Overweg geopend
digitalWrite(LED_BUILTIN, LOW);
}
}
En in dezelfde directory als de sketch komen de twee volgende bestanden:
Filenaam Spoor.h (definitie van de class):
#ifndef Spoor_h
#define Spoor_h
#include "Arduino.h"
class Spoor {
public:
Spoor(); // for array
Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay);
bool calcBezet();
private:
bool readLinks();
bool readRechts();
byte _sensorLinks;
byte _sensorRechts;
bool _memLinks;
bool _memRechts;
unsigned long _timerLinks;
unsigned long _timerRechts;
// < 0: trein rijdt van rechts naar links
// 0: geen trein
// > 0: trein rijdt van links naar rechts
byte _dir;
int _sensorDelay;
};
#endif
Filenaam Spoor.cpp (functionaliteit van de class):
#include "Spoor.h"
Spoor::Spoor() {
// Empty constructor, don't use (for array)
}
Spoor::Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay) {
// Variabelen met externe waardes
_sensorLinks = sensorLinks;
_sensorRechts = sensorRechts;
_sensorDelay = sensorDelay;
// Maak de inputs met extra pullups
pinMode(_sensorLinks, INPUT_PULLUP);
pinMode(_sensorRechts, INPUT_PULLUP);
// Voorzie overige variabelen van een default value
_timerLinks = millis();
_timerRechts = millis();
_memLinks = readLinks();
_memRechts = readRechts();
_dir = 0;
}
bool Spoor::readLinks() {
// if (digitalRead(_sensorLinks) > 0) {
if (digitalRead(_sensorLinks) == 0) {
_timerLinks = millis() + _sensorDelay;
}
return (_timerLinks > millis());
}
bool Spoor::readRechts() {
// if (digitalRead(_sensorRechts) > 0) {
if (digitalRead(_sensorRechts) == 0) {
_timerRechts = millis() + _sensorDelay;
}
return (_timerRechts > millis());
}
// return true als bezet
bool Spoor::calcBezet() {
// fase: toestand nu en de vorige keer van de melder
// volgorde:
// 0: geen trein
// 1: voorkant trein
// 2: achterkant trein
// 3: trein aanwezig
byte fase;
// Links
fase = (_memLinks ? 2 : 0);
_memLinks = readLinks();
fase += (_memLinks ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (_dir == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
_dir++;
}
}
if (fase == 2) {
// Trein verlaat
if (_dir < 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
_dir++;
}
}
// Rechts
fase = (_memRechts ? 2 : 0);
_memRechts = readRechts();
fase += (_memRechts ? 1 : 0);
if (fase == 1) {
// Trein komt binnen
if (_dir == 0) { // Bij het bereiken van de andere kant alleen reageren op het verlaten
_dir--;
}
}
if (fase == 2) {
// Trein verlaat
if (_dir > 0) { // Bij het verlaten van de binnen melder niet een extra puls geven.
_dir--;
}
}
return (_dir != 0);
}
Hi Bas,
dit is de code die ik gebruikt heb. Komt van pagina drie en is, zoals Gerard al zegt, nog niet af. Dat moet dus nog verder uitgewerkt worden. Nu ben ik een no-no wat betreft het programmeren van deze dingen en ligt het programmeren an sich ook al ruim 13 jaar achter me. Dus extra ogen zijn altijd welkom. (y)
Eens kijken if ik deze week iets met LED's kan fabrieken.
Gr.
Edsko
-
Ik heb de code bekeken en ik heb zowaar een waarschijnlijke bug gevonden. Er was een byte genaamd _dir. Maar _dir moest van het programma ook -1 kunnen worden. Alleen een byte variabele die kan dat niet. Ik heb hem opgelost door er een int8_t van te maken :police:.
De sensors werden volgens mij ook verkeerdom ingelezen er stond
if (digitalRead(_sensorLinks) == 1)
En daar heb ik
if (digitalRead(_sensorLinks) == 0)
van gemaakt.
Dit is wel afhankelijk van hoe je de sensor aan hebt gesloten. in 9 van de 10 keer trekt een sensor oid een input pin naar de 0V toe die anders met een pull-up weerstand op 5v wordt gehouden.
Ik heb verder hier en der wat notities geplaatst en dingen wat leesbaarder neergekalt.
Nu ben ik een no-no wat betreft het programmeren van deze dingen
Dat snap ik, en ik snap ook als je in dat geval dan ook nog constructies ziet zoals:
fase = (_memLinks ? 2 : 0);
_memLinks = readLinks();
fase += (_memLinks ? 1 : 0);
return (_dir != 0) ;
Dat dat er niet makkelijker er van wordt...
Ik vond de werking van hoe de bezetstatus wordt afgehandeld een beetje kryptisch. Ik heb die niet helemaal gevolgd en doorlopen of daar ook bugs in zitten.
Ik heb tevens de led knipperend gemaakt voor je. Ik heb voor dat soort dingen ooit een repeat macro bedacht.
Hier staat de aangepast code.
/* NOTE BAS
Onderstaande macro gebruik ik om dingen met een bepaald interval te maken, het gebruik staat in de code
Het is ontzettend simpel om toe te passen.
*/
#define REPEAT_MS(x) { \
static uint32_t previousTime ;\
uint32_t currentTime = millis() ;\
if( currentTime - previousTime >= x ) {\
previousTime = currentTime ;
// code to be repeated goes between these 2 macros
#define END_REPEAT } \
}
// Definitie van de 4 ingangen voor de sensoren (2 per spoor)
#define BB_LINKS_1 2 // BlackBox Links, Spoor 1
#define BB_RECHTS_1 3 // BlackBox Rechts, Spoor 1
#define BB_LINKS_2 4 // BlackBox Links, Spoor 2
#define BB_RECHTS_2 5 // BlackBox Rechts, Spoor 2
/* NOTE BAS:
SBBLSP1 etc aangepast naar BB_LINKS_1 omdat... leesbaarheid
SBBLSP1 is 'mumbo jumbo' die wij mensen niet kunnen lezen, computers wel.
klein detailtje ;)
*/
#define BLINK_TIME 500 // BAS: knipperled toegevoegd
#define SENSOR_DELAY 500 // Vertraging in milli seconde
/* NOTE BAS:
DELAY omgegenoemd naar SENSOR_DELAY
DELAY betekent eigenlijk niks, SENSOR_DELAY verschaft iets van informatie dat het met een sensor te maken heeft
*/
#define NUMSPOREN 2 // Aantal sporen
#include "Spoor.h"
Spoor sporen[NUMSPOREN];
// Initialialatie van de Arduino
void setup()
{
// put your setup code here, to run once:
// Define sporen
sporen[0] = Spoor(BB_LINKS_1, BB_RECHTS_1, SENSOR_DELAY); // Spoor 1
sporen[1] = Spoor(BB_LINKS_2, BB_RECHTS_2, SENSOR_DELAY); // Spoor 2
// LED uit
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin( 9600 ) ;
/* NOTE BAS:
Als je dingen naar de monitor wilt printen, moet je de seriele interface eerst opzetten,
en dat doe je met bovenstaande regel.
Nu kan je overal Serial.print() en Serial.println() gebruiken.
*/
Serial.println("hello world") ;
}
void loop()
{
// put your main code here, to run repeatedly:
bool bezet = false;
for(int i = 0; i < NUMSPOREN; i++)
{
bezet |= sporen[i].calcBezet();
}
// Aansturen van de AKI / AHOB (overweg)
if (bezet)
{
// Overweg gesloten
/* NOTE BAS
Hier gebruik ik mijn repeat macro om de led elke 'BLINK TIME' te laten knipperen
Alle code tussen REPEAT_MS en END_REPEAT wordt hier elke 'BLINK_TIME' uitgevoerd.
*/
REPEAT_MS( BLINK_TIME )
{
digitalWrite( LED_BUILTIN, !digitalRead( LED_BUILTIN ) ;
/* NOTE BAS
ipv HIGH of LOW, lees ik eerst uit wat de led is met digitalRead(), het resultaat inverteer ik met !
en dat wordt de nieuwe stand van de led. Dit laat de led togglen.
*/
}
END_REPEAT
}
else
{
// Overweg geopend
digitalWrite(LED_BUILTIN, LOW); // zet de led uit.
}
}
#ifndef Spoor_h
#define Spoor_h
#include "Arduino.h"
class Spoor {
public:
Spoor(); // for array
Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay);
bool calcBezet();
private:
bool readLinks();
bool readRechts();
byte _sensorLinks;
byte _sensorRechts;
bool _memLinks;
bool _memRechts;
unsigned long _timerLinks;
unsigned long _timerRechts;
// < 0: trein rijdt van rechts naar links
// 0: geen trein
// > 0: trein rijdt van links naar rechts
int8_t _dir; // NOTE BAS: dit was een 'byte' en dat was een bug. _dir kan namelijk negatief worden
// maar een byte is unsigned en het bereik is 0-255. Een byte kan dus niet negatief zijn
// het bereik van een int8_t is -128 tot 127 Een int8_t kan wel negatief zijn
int _sensorDelay;
};
#endif
#include "Spoor.h"
enum train_states // NOTE BAS: deze enumerator toegevoegd om verderop meer leesbaarheid te krijgen.
{
geenTrein = 0, // 0: geen trein
voorkantTrein, // 1: voorkant trein
achterkantTrein, // 2: achterkant trein
treinAanwezig, // 3: trein aanwezig
} ;
Spoor::Spoor()
{
// Empty constructor, don't use (for array)
}
Spoor::Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay)
{
// Variabelen met externe waardes
_sensorLinks = sensorLinks;
_sensorRechts = sensorRechts;
_sensorDelay = sensorDelay;
// Maak de inputs met extra pullups
pinMode(_sensorLinks, INPUT_PULLUP);
pinMode(_sensorRechts, INPUT_PULLUP);
// Voorzie overige variabelen van een default value
_timerLinks = millis();
_timerRechts = millis();
_memLinks = readLinks(); // NOTE BAS: niet aangepast maar 'readLinks' is een *** benaming omdat 'read' Engels is en 'Links' is Nederlands
// de eerste 3x las ik readLinks als 'lees verbindingen', want links is verbindingen in het Engels....
_memRechts = readRechts();
_dir = 0;
}
bool Spoor::readLinks()
{
if (digitalRead(_sensorLinks) == 1 ) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft
{
_timerLinks = millis() + _sensorDelay;
}
return (_timerLinks > millis());
}
bool Spoor::readRechts()
{
if (digitalRead(_sensorRechts) == 0) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft
{
_timerRechts = millis() + _sensorDelay;
}
return (_timerRechts > millis());
}
// return true als bezet
bool Spoor::calcBezet()
{
// fase: toestand nu en de vorige keer van de melder
// volgorde:
// 0: geen trein NOTE BAS: ik heb hiervoor een enum gemaakt hier boven in.
// 1: voorkant trein
// 2: achterkant trein
// 3: trein aanwezig
byte fase;
// Links
/* NOTE BAS: geen regel code met de beruchte '?' of Ternary operator is ooit leesbaar geweest..
fase = (_memLinks ? 2 : 0);
_memLinks = readLinks();
fase += (_memLinks ? 1 : 0);
If Condition is true ? then value X : otherwise value Y
bovenstaande vervangen door:
*/
if( _memLinks > 0 ) { fase = achterkantTrein; }
else { fase = voorkantTrein; }
_memLinks = readLinks();
if( _memLinks > 0 ) { fase ++ ; }
if (fase == voorkantTrein)
{
// Trein komt binnen
if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten
{
_dir++;
}
}
if (fase == achterkantTrein) {
// Trein verlaat
if (_dir < 0) // Bij het verlaten van de binnen melder niet een extra puls geven.
{
_dir++;
}
}
// Rechts
/*
fase = (_memRechts ? 2 : 0);
_memRechts = readRechts();
fase += (_memRechts ? 1 : 0);
*/
if( _memRechts > 0 ) { fase = achterkantTrein; }
else { fase = voorkantTrein; }
_memRechts = readRechts();
if( _memLinks > 0 ) { fase ++ ; }
if (fase == voorkantTrein) {
// Trein komt binnen
if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten
{
_dir--;
}
}
if (fase == achterkantTrein)
{
// Trein verlaat
if (_dir > 0) // Bij het verlaten van de binnen melder niet een extra puls geven.
{
_dir--;
}
}
// NOTE BAS vanwege leesbaarheid heb ik deze regel vervangen door een if else statement en een return van true of false
// return (_dir != 0) ;
if (dir == geenTrein) return false ;
else return true ;
}
Ik hoop dat het iets oplost :-D
Mvg,
Bas
-
Dat is een tijdje geleden dat we (Gerard en ik) voor Koen en jou bezig zijn geweest. Ik had toen ook een schets gemaakt, ik dacht voor Koen, maar dat weet ik niet meer zeker.
Voor het geval dat je Gerards code niet makkelijk aan de praat krijgt. Bij deze ook nog een schets die ik destijds in elkaar geflansd had.
Groet Meino
#define DEBUG 1
enum SpoorState {leeg,
sensor1komend,
sensor2komend,
sensor1gaand,
sensor2gaand
};
//
// Class for a single (white) led which flickers 50 times per
// minute when on
//
class SingleLed
{
private:
int ledPin;
bool ledOn = true;
int interval = 600; // *** 50 keer per minuut
bool lightOn = false;
unsigned long lastTime;
public:
//
// Create a new instance of a (white) led, connect it to the specified
// digital pin and put it in the specified state (true = on, false = off)
//
SingleLed(int aPin, bool state)
{
ledPin = aPin;
ledOn = state;
lightOn = false;
pinMode(ledPin, OUTPUT);
lastTime = millis();
}
//
// Set the state of the led (true = on, false = off)
//
void setOn(bool state)
{
#if (DEBUG)
if (ledOn != state)
{
Serial.print("[SingleLed::setOn]");
if (state)
Serial.println(" aan");
else
Serial.println(" uit");
}
#endif
ledOn = state;
}
//
// If the state is on, put power on the pin of the led, using timers
// to make the flicker work.
// If the led is off, remove the power from the pin of the led.
//
void heartBeat()
{
if (ledOn) // Do we need to light the led?
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= interval) // Has the interval time passed?
{
lastTime = currTime; // Start new interval
if (!lightOn) // Was the led lighted?
{
#if (DEBUG)
Serial.println("[SingleLed::heartBeat] led aan");
#endif
digitalWrite(ledPin, HIGH); // No, so switch it on
lightOn = true;
}
else
{
#if (DEBUG)
Serial.println("[SingleLed::heartBeat] led uit");
#endif
digitalWrite(ledPin, LOW); // Yes, so switch it off
lightOn = false;
}
}
}
else if (lightOn) // No light, but is the led still on?
{
#if (DEBUG)
Serial.println("[SingleLed::heartBeat] led uit");
#endif
digitalWrite(ledPin, LOW); // Switch ir off
lightOn = false;
}
}
};
//
// Class for a set of two (red) leds which alternate(flicker) 50 times per
// minute when on
//
class DuoLed
{
private:
int led1Pin;
int led2Pin;
bool ledOn = true;
int interval = 600; // *** 50 keer per minuut
bool lightOn = false;
bool phase = false;
unsigned long lastTime;
public:
//
// Create a new instance, connect it to the specified
// digital pins and put it in the specified state (true = on, false = off)
//
DuoLed(int aPin1, int aPin2, bool state)
{
led1Pin = aPin1;
led2Pin = aPin2;
ledOn = state;
lightOn = false;
phase = false;
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
lastTime = millis();
}
//
// Set the state of the leds (true = on, false = off)
//
void setOn(bool state)
{
#if (DEBUG)
if (ledOn != state)
{
Serial.print("[DuoLed::setOn]");
if (state)
Serial.println(" aan");
else
Serial.println(" uit");
}
#endif
ledOn = state;
}
//
// If the state is on, put power on the pins of the leds, using timers
// to make the alternating flicker work.
// If the led is off, remove the power from the pins of the leds.
//
void heartBeat()
{
if (ledOn) // Are the leds activated
{
lightOn = true;
unsigned long currTime = millis();
if ((currTime - lastTime) >= interval) // Has the interval passed?
{
lastTime = currTime; // Yes, start new interval
if (!phase) // The leds alternate, are we in phase1 (led1 on, led2 off)
{
#if (DEBUG)
Serial.println("[DuoLed::heartBeat] led1 aan, led2 uit");
#endif
digitalWrite(led1Pin, HIGH); // Yes, led1 on
digitalWrite(led2Pin, LOW); // led2 off
phase = true; // When the interval expires, switch the leds
}
else // We are in phase2 (led1 off, led2 on)
{
#if (DEBUG)
Serial.println("[DuoLed::heartBeat] led1 uit, led2 aan");
#endif
digitalWrite(led1Pin, LOW); // Led1 off
digitalWrite(led2Pin, HIGH); // Led2 on
phase = false; // When the interval expires, switc the leds
}
}
}
else // The leds are not active, switch of both leds
{
if (lightOn)
{
#if (DEBUG)
Serial.println("[DuoLed::heartBeat] led1 uit, led2 uit");
#endif
digitalWrite(led1Pin, LOW);
digitalWrite(led2Pin, LOW);
lightOn = false;
}
}
}
};
enum AkiStaat {aan, uit};
//
// A simple class that represents a complet AKI with all its leds
//
// TBD, the sound of the bells
//
class AKI
{
private:
SingleLed *whiteLight;
DuoLed *redLights;
AkiStaat state = uit;
public:
//
// Create an instance of the AKI, using the specified Led objects
//
AKI(SingleLed *aWhiteLed, DuoLed *aRedLed)
{
whiteLight = aWhiteLed;
redLights = aRedLed;
state = uit;
}
//
// Activate the connected leds. TBD: the sound
//
void heartBeat()
{
redLights->heartBeat();
whiteLight->heartBeat();
}
void set(AkiStaat aState)
{
#if (DEBUG)
if (state != aState)
{
Serial.print("[AKI::set]");
if (aState == uit)
Serial.println(" uit");
else
Serial.println(" aan");
}
#endif
state = aState;
if (state == uit)
{
redLights->setOn(false);
whiteLight->setOn(true);
}
else
{
redLights->setOn(true);
whiteLight->setOn(false);
}
}
};
//
// Some sensors use a digital signal and keep it high when not active and drop the signal
// when the sensor trips, use in that case the "laag" setting. Others use a digital signal
// and are low when not active and make the signal high when the sensor trips, use in that case
// the "hoog" setting.
// if the sensor doesn't generate a digital signal, you have to use a pullup resistor (or INPUT_PULLUP)
// and in that case specify hoog.
//
// The Flying Fish proximity detectors, when used in reflective mode, need the "laag" setting,
// when their sensors are removed and positioned opposit each other, they need the "hoog" setting
//
enum SensorTrigger {laag, hoog};
//
// A simple class which represents the state of a single sensor
//
class Sensor
{
private:
int sensorPin;
SensorTrigger type = hoog;
bool state = false; // true = on, false = off
unsigned long lastTime = 0; // Timer to ignore short interrupts
#define JITTER_TIME 1000 // wait a second before the sensor goes off
public:
//
// Create a new instance
//
Sensor(int aPin)
{
sensorPin = aPin;
pinMode(sensorPin, INPUT_PULLUP);
}
//
// Create a new instance
//
Sensor(int aPin, SensorTrigger aType)
{
sensorPin = aPin;
type = aType;
pinMode(sensorPin, INPUT_PULLUP);
}
//
// Return the current logical state of the sensor
//
bool getState()
{
return state;
}
//
// Monitor the physical sensor and update the state accordingly
//
void heartBeat()
{
if (digitalRead(sensorPin) == HIGH)
{
if (type == laag) // For sensors type laag an high signal means they are in the off state
{
if (state != false) // Process this signal only when the current state is ON
{
if (lastTime == 0)
{
lastTime = millis(); // start Interval
}
else
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= JITTER_TIME)
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor(laag) goes off");
#endif
state = false; // sensor goes OFF
lastTime = 0; // Reset interval timer
}
}
}
}
else
{
#if (DEBUG)
if (state != true)
{
Serial.println("[Sensor::heartBeat] sensor(hoog) goes on");
}
#endif
state = true; // Sensor goes ON
lastTime = 0; // Reset interval timer
}
}
else // sensorPin = LOW
{
if (type == laag)
{
#if (DEBUG)
if (state != true)
{
Serial.println("[Sensor::heartBeat] sensor(laag) goes on");
}
#endif
state = true; // Sensor goes ON
lastTime = 0; // Reset interval timer;
}
else
{
if (state != false) // Process this signal only when the current state is ON
{
if (lastTime == 0)
{
lastTime = millis(); // start Interval
}
else
{
unsigned long currTime = millis();
if ((currTime - lastTime) >= JITTER_TIME)
{
#if (DEBUG)
Serial.println("[Sensor::heartBeat] sensor(hoog) goes off");
#endif
state = false; // sensor goes OFF
lastTime = 0; // Reset interval timer
}
}
}
}
}
}
};
//
// A finite state machine that guards a occupance of a single track
//
class SpoorControl
{
private:
Sensor *sensor1;
Sensor *sensor2;
SpoorState state = leeg;
//
// Based on the state of sensor 1 and the current state of the FSM, a new state
// is calculated.
//
void handleSensor1(bool trigger)
{
if (trigger) // Sensor 1 is ON
{
if (state == leeg) // If the state is "leeg" it means that a train enters the section
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is sensor1komend");
#endif
state = sensor1komend; // so set it to state komend
}
else if (state == sensor2komend) // if the other sensor tripped first
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is sensor1gaand");
#endif
state = sensor1gaand; // The train is starting to leave the section
}
}
else
{ // Sensor went OFF
if (state == sensor1gaand) // If the train started to leave via sensor 1
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor1] state is leeg");
#endif
state = leeg; // the section is "leeg"
}
}
}
//
// Based on the state of sensor 2 and the current state of the FSM, a new state
// is calculated.
//
void handleSensor2(bool trigger)
{
if (trigger) // Sensor 2 is ON
{
if (state == leeg) // Is the section "leeg"?
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is sensor2komend");
#endif
state = sensor2komend; // A Train entered the section via sensor 2
}
else if (state == sensor1komend) // No a train entered the section via the other sensor
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is sensor2gaand");
#endif
state = sensor2gaand; // Start the leaving process
}
}
else
{
if (state == sensor2gaand) // A train is in the process of leaving
{
#if (DEBUG)
Serial.println("[SpoorControl::handleSensor2] state is leeg");
#endif
state = leeg; // Section is empty again
}
}
}
public:
//
// Create an instance with two sensors
//
SpoorControl(Sensor *aSensor1, Sensor *aSensor2)
{
sensor1 = aSensor1;
sensor2 = aSensor2;
}
//
// Get give the sensors a kick and check their state so we can update our own
// state.
//
void heartBeat()
{
sensor1->heartBeat();
sensor2->heartBeat();
handleSensor1(sensor1->getState());
handleSensor2(sensor2->getState());
}
//
// Return the current state of the section
//
SpoorState getState()
{
return state;
}
};
//
// Create 2 FSM controling two track sections
//
SpoorControl spoor1(new Sensor(A0, hoog), new Sensor(A1, hoog)); // Sensor works reflective
SpoorControl spoor2(new Sensor(A2, hoog), new Sensor(A3, hoog));
//
// Create an instance of the AKI
//
AKI aki(new SingleLed(2, true), new DuoLed(3, 4, false));
void setup()
{
#if (DEBUG)
//Serial.begin(9600);
Serial.begin(115200);
while (!Serial);
Serial.println("Starting");
Serial.flush();
#endif //DEBUG
}
void loop()
{
spoor1.heartBeat(); // These object must monitor their sensors
spoor2.heartBeat(); // so they can update their states
if ((spoor1.getState() == leeg) && (spoor2.getState() == leeg))
{
aki.set(uit); // Stop sound and flashing red lights
}
else
{
aki.set(aan); // Start flashing red lights and sound
}
aki.heartBeat(); // Let the AKI update it's connected bells and leds
}
-
Hi,
idd Meino, het is 4 jaar geleden ongeveer. :-X Maar blijmoedig ga ik hier verder mee. :)
Ik ben weer een klein stapje verder. Ik heb een simulatie gemaakt van een AKI en hoop het ding aan de praat te krijgen. Vandaag iig getest met een aangepast blink programma en hij werkt! De drie LEDjes gaan keurig los van elkaar aan en uit. Nu moet het nog in het programma. Denk ik....
(https://images.beneluxspoor.net/bnls_2022/20220921-092523-632b82c22f059.jpg) (https://images.beneluxspoor.net/bnls_2022/20220921-092523-632b82c22f059.jpg)
Zo ziet het plaatje er dus uit. Boven geel en onder twee rode lampen. De gele moet rustig knipperen als de overweg veilig is. De rode twee mogen "woest" om en om aan en uit gaan om de aanstormende trein te introduceren. Dus dat. Maar ja, hoe dat in de code te plaatsen....
De gebruikte weerstand is overigens 1kOhm en dat drie keer.
Geel is aangesloten op pin 8, rood op pin 9 en 10. Lekker simpel.
Ik zal eens gaan prutsen met de code die Bas heeft aangepast. Eens zien of ik daar uit ga komen. :-\ :angel:
Vind het wel heel leuk nu het bijna draait. Kan ik ook mijn BB's gaan uitrusten met deze sluisjes. Moet ik eigenlijk wel even iets beters fabriceren dan de huidige standaards van hout, die zien er eigenlijk niet uit, maar doen wel waar ze voor bedoelt zijn. (y)
Komt vast goed uiteindelijk.
Groet,
Edsko
-
Ik heb de code bekeken en ik heb zowaar een waarschijnlijke bug gevonden. Er was een byte genaamd _dir. Maar _dir moest van het programma ook -1 kunnen worden. Alleen een byte variabele die kan dat niet. Ik heb hem opgelost door er een int8_t van te maken :police:.
De sensors werden volgens mij ook verkeerdom ingelezen er stond
if (digitalRead(_sensorLinks) == 1)
En daar heb ik
if (digitalRead(_sensorLinks) == 0)
van gemaakt.
Dit is wel afhankelijk van hoe je de sensor aan hebt gesloten. in 9 van de 10 keer trekt een sensor oid een input pin naar de 0V toe die anders met een pull-up weerstand op 5v wordt gehouden.
Dank je wel voor het vinden en aanpassen van de bug. (y)
/* NOTE BAS
Onderstaande macro gebruik ik om dingen met een bepaald interval te maken, het gebruik staat in de code
Het is ontzettend simpel om toe te passen.
*/
#define REPEAT_MS(x) { \
static uint32_t previousTime ;\
uint32_t currentTime = millis() ;\
if( currentTime - previousTime >= x ) {\
previousTime = currentTime ;
// code to be repeated goes between these 2 macros
#define END_REPEAT } \
}
// Definitie van de 4 ingangen voor de sensoren (2 per spoor)
#define BB_LINKS_1 2 // BlackBox Links, Spoor 1
#define BB_RECHTS_1 3 // BlackBox Rechts, Spoor 1
#define BB_LINKS_2 4 // BlackBox Links, Spoor 2
#define BB_RECHTS_2 5 // BlackBox Rechts, Spoor 2
/* NOTE BAS:
SBBLSP1 etc aangepast naar BB_LINKS_1 omdat... leesbaarheid
SBBLSP1 is 'mumbo jumbo' die wij mensen niet kunnen lezen, computers wel.
klein detailtje ;)
*/
#define BLINK_TIME 500 // BAS: knipperled toegevoegd
#define SENSOR_DELAY 500 // Vertraging in milli seconde
/* NOTE BAS:
DELAY omgegenoemd naar SENSOR_DELAY
DELAY betekent eigenlijk niks, SENSOR_DELAY verschaft iets van informatie dat het met een sensor te maken heeft
*/
#define NUMSPOREN 2 // Aantal sporen
#include "Spoor.h"
Spoor sporen[NUMSPOREN];
// Initialialatie van de Arduino
void setup()
{
// put your setup code here, to run once:
// Define sporen
sporen[0] = Spoor(BB_LINKS_1, BB_RECHTS_1, SENSOR_DELAY); // Spoor 1
sporen[1] = Spoor(BB_LINKS_2, BB_RECHTS_2, SENSOR_DELAY); // Spoor 2
// LED uit
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
Serial.begin( 9600 ) ;
/* NOTE BAS:
Als je dingen naar de monitor wilt printen, moet je de seriele interface eerst opzetten,
en dat doe je met bovenstaande regel.
Nu kan je overal Serial.print() en Serial.println() gebruiken.
*/
Serial.println("hello world") ;
}
void loop()
{
// put your main code here, to run repeatedly:
bool bezet = false;
for(int i = 0; i < NUMSPOREN; i++)
{
bezet |= sporen[i].calcBezet();
}
// Aansturen van de AKI / AHOB (overweg)
if (bezet)
{
// Overweg gesloten
/* NOTE BAS
Hier gebruik ik mijn repeat macro om de led elke 'BLINK TIME' te laten knipperen
Alle code tussen REPEAT_MS en END_REPEAT wordt hier elke 'BLINK_TIME' uitgevoerd.
*/
REPEAT_MS( BLINK_TIME )
{
digitalWrite( LED_BUILTIN, !digitalRead( LED_BUILTIN ) ;
/* NOTE BAS
ipv HIGH of LOW, lees ik eerst uit wat de led is met digitalRead(), het resultaat inverteer ik met !
en dat wordt de nieuwe stand van de led. Dit laat de led togglen.
*/
}
END_REPEAT
}
else
{
// Overweg geopend
digitalWrite(LED_BUILTIN, LOW); // zet de led uit.
}
}
Dit ga ik eens rustig bekijken of ik hier chocola van kan maken. :)
#ifndef Spoor_h
#define Spoor_h
#include "Arduino.h"
class Spoor {
public:
Spoor(); // for array
Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay);
bool calcBezet();
private:
bool readLinks();
bool readRechts();
byte _sensorLinks;
byte _sensorRechts;
bool _memLinks;
bool _memRechts;
unsigned long _timerLinks;
unsigned long _timerRechts;
// < 0: trein rijdt van rechts naar links
// 0: geen trein
// > 0: trein rijdt van links naar rechts
int8_t _dir; // NOTE BAS: dit was een 'byte' en dat was een bug. _dir kan namelijk negatief worden
// maar een byte is unsigned en het bereik is 0-255. Een byte kan dus niet negatief zijn
// het bereik van een int8_t is -128 tot 127 Een int8_t kan wel negatief zijn
int _sensorDelay;
};
#endif
Ik neem aan dat dit de file Spoor.h is
#include "Spoor.h"
enum train_states // NOTE BAS: deze enumerator toegevoegd om verderop meer leesbaarheid te krijgen.
{
geenTrein = 0, // 0: geen trein
voorkantTrein, // 1: voorkant trein
achterkantTrein, // 2: achterkant trein
treinAanwezig, // 3: trein aanwezig
} ;
Spoor::Spoor()
{
// Empty constructor, don't use (for array)
}
Spoor::Spoor(byte sensorLinks, byte sensorRechts, int sensorDelay)
{
// Variabelen met externe waardes
_sensorLinks = sensorLinks;
_sensorRechts = sensorRechts;
_sensorDelay = sensorDelay;
// Maak de inputs met extra pullups
pinMode(_sensorLinks, INPUT_PULLUP);
pinMode(_sensorRechts, INPUT_PULLUP);
// Voorzie overige variabelen van een default value
_timerLinks = millis();
_timerRechts = millis();
_memLinks = readLinks(); // NOTE BAS: niet aangepast maar 'readLinks' is een *** benaming omdat 'read' Engels is en 'Links' is Nederlands
// de eerste 3x las ik readLinks als 'lees verbindingen', want links is verbindingen in het Engels....
_memRechts = readRechts();
_dir = 0;
}
bool Spoor::readLinks()
{
if (digitalRead(_sensorLinks) == 1 ) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft
{
_timerLinks = millis() + _sensorDelay;
}
return (_timerLinks > millis());
}
bool Spoor::readRechts()
{
if (digitalRead(_sensorRechts) == 0) // NOTE BAS, deze omgekeerd naar een 1, omdat een sensor die geen trein ziet, een hoog signaal geeft
{
_timerRechts = millis() + _sensorDelay;
}
return (_timerRechts > millis());
}
// return true als bezet
bool Spoor::calcBezet()
{
// fase: toestand nu en de vorige keer van de melder
// volgorde:
// 0: geen trein NOTE BAS: ik heb hiervoor een enum gemaakt hier boven in.
// 1: voorkant trein
// 2: achterkant trein
// 3: trein aanwezig
byte fase;
// Links
/* NOTE BAS: geen regel code met de beruchte '?' of Ternary operator is ooit leesbaar geweest..
fase = (_memLinks ? 2 : 0);
_memLinks = readLinks();
fase += (_memLinks ? 1 : 0);
If Condition is true ? then value X : otherwise value Y
bovenstaande vervangen door:
*/
if( _memLinks > 0 ) { fase = achterkantTrein; }
else { fase = voorkantTrein; }
_memLinks = readLinks();
if( _memLinks > 0 ) { fase ++ ; }
if (fase == voorkantTrein)
{
// Trein komt binnen
if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten
{
_dir++;
}
}
if (fase == achterkantTrein) {
// Trein verlaat
if (_dir < 0) // Bij het verlaten van de binnen melder niet een extra puls geven.
{
_dir++;
}
}
// Rechts
/*
fase = (_memRechts ? 2 : 0);
_memRechts = readRechts();
fase += (_memRechts ? 1 : 0);
*/
if( _memRechts > 0 ) { fase = achterkantTrein; }
else { fase = voorkantTrein; }
_memRechts = readRechts();
if( _memLinks > 0 ) { fase ++ ; }
if (fase == voorkantTrein) {
// Trein komt binnen
if (_dir == 0) // Bij het bereiken van de andere kant alleen reageren op het verlaten
{
_dir--;
}
}
if (fase == achterkantTrein)
{
// Trein verlaat
if (_dir > 0) // Bij het verlaten van de binnen melder niet een extra puls geven.
{
_dir--;
}
}
// NOTE BAS vanwege leesbaarheid heb ik deze regel vervangen door een if else statement en een return van true of false
// return (_dir != 0) ;
if (dir == geenTrein) return false ;
else return true ;
}
Ik neem aan dat dit de file Spoor.cpp is.
Kloppen mijn aannames mbt de benaming van de files?
Ik ga hier eens rustig naar kijken. Zal ws wel na het weekend worden ivm drukte. Vrijdag OnTraxs, zaterdag ook al druk met afspraken en zondag ben ik vast moe en lui van vrijdag en zaterdag. :D
Gr.
Edsko
-
Kloppen mijn aannames mbt de benaming van de files?
(y)
en zondag ben ik vast moe en lui van vrijdag en zaterdag
Dan heb je pech, er zijn zondag ook trein gerelateerde activiteiten in Schoonhoven. ;D ;D ;D
https://www.indekrimpenerwaard.nl/agenda/3452053333/modelbouwtentoonstelling-carmeliet-op-stoom (https://www.indekrimpenerwaard.nl/agenda/3452053333/modelbouwtentoonstelling-carmeliet-op-stoom)
Mvg,
Bas
P.S.
Denk na voor jezelf of je nog iets van custom printjes wilt, zoals bijvoorbeeld een driehoekig printje voor een AKI of zo ::) dan kan dat geregeld worden (y)
-
Dank voor het aanbod Bas, maar een driehoekig printplaatje gaat wat lastig worden. Zie foto hieronder voor de te gebruiken AKI's, waarvan ik nog steeds geen idee heb hoe ik daar licht in ga frotten. Het spul is erg fragiel. Maar het moet te doen zijn.
(https://images.beneluxspoor.net/bnls/20200124_122711.jpg) (https://images.beneluxspoor.net/bnls/20200124_122711.jpg)
Vijf Ledjes dus... 1xgeel, 4xrood. Denk ik....Ik laat me graag verbeteren. :)
Gr.
Edsko
-
Volgens mij is de AKI die je daar toont de tweede oerversie met groen, oranje en rood, waarbij de storingslamp (oranje) maar aan 1 kant zichtbaar was en groen en rood aan beide kanten.
Volgens mij werden alle lampen (waaronder wit dus) dubbel uitgevoerd toen het groene licht wit werd en naar boven verhuisde en de storingslamp verviel en een rode lamp werd.
Dus helemaal supertechnisch correct gezien, klopt je AKI niet ;)
-
Dank voor de aanvulling. Maar heel eerlijk wordt het me daarvoor te complex. :D Ik houd het lekker simpel. :)
Gr.
Edsko
-
Kan je er 3mm leds insteken van achter? Ik heb ooit als tip hier gekregen om een ronde led in een boor machine te doen en door er schuurpapier tegen aan te houden, kan je de led iets dunner maken.
Lakdraadjes er aan solderen, alles zwart verven en wegwerken (y)
Mvg,
Bas
-
Ik heb SMD's die ik wil gebruiken, met lakdraad er al aan
-
hallo Edsko
even een andere vraag over de 3 licht seinen , welke ledjes ga je daar in doen voor de seinbeelden,
voor de kleuren groen, wit en geel
of doe je een eenvoudige set kleuren er in
vriendelijke groeten
Gerard
-
Daar heb ik volgens mij twee kleuren smd's voor. En de lakdraden daarvan kan ik door de buis heen halen als het goed is
-
bedankt
-
Ik denk dat je het beste de leds op een rond stukje styreen kan lijmen ???
-
Dat is idd het plan. Ik heb zo'n tang waarmee je gaatjes in riemen etc kunt maken. Die wil ik daarvoor gebruiken. Moet lukken
Waar ik echter nog niet uit kom, die meerkleuren smd ledjes hebben meerdere draden. Hoe weet ik welke waar voor dient? Ik heb geen idee.
Gr.
Edsko
-
Ik geloof niet dat ik de code helemaal begrijp. Ik heb het zwaar omgebouwd van buildin led naar pin 8. ;) Ledje gaat ook keurig aan.
Maar als de wagen eenmaal door de linker sluis is, gaat het ledje weer uit. De wagon door de rechter sluis halen levert geen reactie op.
Wat ik verwacht, is dat als de wagon door de linkersluis gaat, de twee rode ledjes afwisselend gaan knipperen. Gaat de wagon daarna door de rechtersluis, dan verwacht ik dat de twee rode ledjes stoppen met knipperen en dat het gele led weer rustig gaat knipperen. Ik ben wat aan het experimenteren met de code, maar het lukt nog niet.
Gr.
Edsko
-
Grappig. Als ik de linker sluis loskoppel van de Arduino, beginnen de rode leds automatisch te knipperen.
Plaats ik iets in de rechter sluis, dan stoppen de rode leds met knipperen. Rechts geeft dus wel degelijk een signaal door, daar was ik even niet zeker van. Nu wel.
-
Dus geen trein in sluis, signaal is '0'
wel trein in sluis -> signaal is '1'
Altijd handig te weten (y).
Mvg,
Bas
-
Waar ik echter nog niet uit kom, die meerkleuren smd ledjes hebben meerdere draden. Hoe weet ik welke waar voor dient? Ik heb geen idee.
Vaak hebben SMD-LEDs een inkeping bij de positieve kant of een symbool op de onderkant wat die aansluiting markeert. Het leuke is dat als je ogen niet zo goed zijn, je dit amper kunt zien (maar goed, over het algemeen worden ze dan ook machinaal verwerkt en maakt dat niet uit).
Makkelijker is om gewoon met een multimeter op de diodestand of weerstand-instelling combinaties te gaan proberen, net zolang tot je iets op ziet lichten: de meeste multimeters kunnen genoeg stroom leveren om LEDs op te laten lichten, alleen witte lukt niet altijd.
Een van de draden zal een gezamenlijke positieve of negatieve aansluiting zijn, maar er zijn ook SMD-LEDs waar elke LED elke aansluiting afzonderlijk bezit.
-
Dank Menno, dat ga ik eens proberen. (y)
-
Wat ik verwacht, is dat als de wagon door de linkersluis gaat, de twee rode ledjes afwisselend gaan knipperen. Gaat de wagon daarna door de rechtersluis, dan verwacht ik dat de twee rode ledjes stoppen met knipperen en dat het gele led weer rustig gaat knipperen. Ik ben wat aan het experimenteren met de code, maar het lukt nog niet.
Edsko, je zou eens in de schets die ik je heb opgestuurd kunnen kijken. Die bevat een class "SpoorControl" die precies doet wat jij wilt. Trein rijdt blok binnen en passeert sensor. Blok raakt bezet. Bij het verlaten van het blok en als de trein de andere sensor geheel heeft verlaten komt het blok weer vrij.
Die schets is een gestripte versie van de code die op Kranenberg de AKI aanstuurt.
Groet Meino
-
Hi Meino,
Dank voor de tip. Ik ga een kijken en prutsen.
Gr.
Edsko
-
Hi,
Ik heb weer zitten kijken naar de code, zowel van Bas als Meino, maar het gaat m'n pet te boven. Ik kom er gewoon niet uit.
Ik kan het enigszins volgen wat er gebeurd, maar ik mis gewoon kennis. Ik kan wel hulp hierbij gebruiken.
Ik ben nu met de door Bas aangepaste code van Gerard bezig. Die doet niet geheel wat ik wil. Het om en om laten knipperen krijg ik niet voor elkaar.
Ik heb de code van Meino ook botweg geüploaded naar de Arduino Uno, maar ook die doet het niet. Het enige dat daarbij gebeurd, is dat op de rechter "Fly-fish" het lampje knippert ten teken dat de boel onderbroken is. En dat is dus niet het geval. Als ik mijn hand er tussen stop, gebeurd er niks. En aan de linkerkant gebeurd ook niks.
Ik weet ook niet hoe ik in de code van Meino kan aangeven op welke pinnen de LED's zijn aangesloten. :(
De build-in led brandt wel de gehele tijd, ook geen idee of dat goed is.
Kortom, ik zit vast. Uhm, hellup en zo... Brand....
Gr.
Edsko
-
Vanaf regel 509 kan je de inputs en outputs opgeven. Ik moest ook even zoeken hier naar omdat er geen constantes waren gebruikt.
Voor de sporen worden de pinnen A0 t/m A3 gebruikt.
En voor de leds worden pinnen 2, 3 en 4 gebruikt.
SpoorControl spoor1(new Sensor(A0, hoog), new Sensor(A1, hoog)); // Sensor works reflective
SpoorControl spoor2(new Sensor(A2, hoog), new Sensor(A3, hoog));
//
// Create an instance of the AKI
//
AKI aki(new SingleLed(2, true), new DuoLed(3, 4, false));
Je kan ook nog mijn kant en klare code gebruiken. De link staat in post #38 (https://forum.beneluxspoor.net/index.php?topic=80179.msg3222208701#msg3222208701) Ik zal die zo even testen of die nog werkt :P.
Mvg,
Bas
-
Edsko
op welke pinnen heb je de flyfish sensors gezet? en aan welke pinnen heb je de witte en de twee rode leds geplaatst?
Verder, de schets zoals die nu is, werkt voor een dubbelsporige blok. Ik geloof dat jij in je proefopstelling maar een spoor hebt, dus ook een van de twee SpoorControl objecten moet er even uit.
Nog iets anders. Ik weet uit ervaring dat die Flyfish sensors erg gevoelig zijn voor omgevingslicht. Je kunt proberen om met de potmeter op de Flyfish die gevoeligheid aan te passen. Dat aanpassen moet je toch al doen om te zorgen dat ze goed werken in de opostelling die je gekozen hebt.
Groet Meino
-
Ik zal die zo even testen of die nog werkt
Done!. Er zaten nog wat issues in, zou nu weer gelikt moeten zijn (y) https://github.com/bask185/ahob/ (https://github.com/bask185/ahob/)
In mijn code heb ik alle IO gecentraliseerd in een bestandje io.h. Die kan je niet openen via de arduino ide omdat hij in de src sub-folder staat. Gelukkig heeft elke computer kladblok ;D
#define detector1 2
#define detector2 3
#define detector3 4
#define detector4 5
#define servoPin1 6
#define servoPin2 7
#define led1 10
#define blinkLed1 12
#define blinkLed2 13
Geschikt voor 1 tot oneindig veel sporen en werkt in beide richtingen. Omdat deze code voor een AHO was gemaakt, zit er ook code in voor servo's maar als je die gewoon niet aansluit, heb je een prima werkende AKI ;)
#include "src/io.h"
#include "railCrossing.h"
#include "track.h"
const int trackPins[][2] = // pin numbers for the track objects
{
{ detector1, detector2 } , // track 1
{ detector3, detector4 } , // track 2
//{ detector5, detector6 } , // track 3 add as many as you want
} ;
Track track[] = // array of track objects, each track object has 2 sensors
{
Track(),
Track(),
// Track(), // for every track, you need to add a line here
} ;
const uint8_t nTracks = sizeof(track) / sizeof(track[0] ) ; // should correctly get the amount of tracks.
void setup()
{
initIO();
Serial.begin(4800);
Serial.println(F("AHOB STARTED")) ;
for( int i = 0 ; i < nTracks ; i ++ )
{
uint8_t pin1 = trackPins[i][0] ; // get pins from array and pass them to all track objects
uint8_t pin2 = trackPins[i][1] ;
track[i].begin( pin1, pin2 ) ;
}
railCrossingInit(); // initialize state machine for rail crossing
}
void loop()
{
uint8_t occupiedTracks = 0 ;
for( int i = 0 ; i < nTracks ; i ++ )
{
if( track[i].readSensors() != 0 ) occupiedTracks = 1 ; // if atleast one track detects a train, set this to 1
}
railCrossing( occupiedTracks ); // stuur ahob aan
}
}
Probeer wel eerst Meino's code uit :P
Mvg,
Bas
-
Edsko
Soest-Vleuten is niet zo ver, misschien moeten we eens afspreken als je er niet uitkomt met alle drie de schetsjes. Ik kan wel naar jou toekomen, je bent ook welkom bij mij. Dus zie maar.
Groet Meino
-
Ik zou sws naar Meino gaan, kan je Kranenberg bekijken ;D
-
Edsko,
Jij HEBT hetzelfde probleem als ik HAD met die arduino's,
te weinig ervaring, te weinig praktijk, tussen alle haakjes enz het overzicht kwijt en bij mij het feit dat ik altijd ruzie heb met mijn 2 vingerig toetsenbord en het toetsenbord met mij. Die code , eerlijk gezegd ik snap er geen jota van.
Vanmiddag heb ik je probleem eens in mijn programma samengesteld en in 3 uurtjes tijd kwam ik tot de volgende,
(https://images.beneluxspoor.net/bnls_2022/Spporwegovergang-6335d0173fd1b.jpg) (https://images.beneluxspoor.net/bnls_2022/Spporwegovergang-6335d0173fd1b.jpg)
ff getest en het werkt. OK, het is maar voor enkelspoor maar het geeft 'n idee. De code is ook beschikbaar,
#include <SimpleTimer.h>
volatile int Spoor_leeg;
volatile boolean SR_pin_4;
volatile boolean SR_pin_5;
SimpleTimer timer;
void Simple_timer_1() {
if (Spoor_leeg == 0) {
//Knipperen geel 1000mSec
digitalWrite(8,(!digitalRead(8)));
} else {
digitalWrite(8,LOW);
}
}
void Simple_timer_3() {
//Knipperen rood 250mSec
if (Spoor_leeg != 0) {
digitalWrite(9,(!digitalRead(9)));
digitalWrite(10,(!digitalRead(9)));
} else {
digitalWrite(9,LOW);
digitalWrite(10,LOW);
}
}
void setup(){
Spoor_leeg = 0;
SR_pin_4 = LOW;
SR_pin_5 = LOW;
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(12, INPUT);
Serial.begin(9600);
pinMode(8, OUTPUT);
timer.setInterval(1000L, Simple_timer_1);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
timer.setInterval(200L, Simple_timer_3);
}
void loop(){
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
//Inrij signaal
if (!digitalRead(4) && SR_pin_4) {
Spoor_leeg = Spoor_leeg + 1;
SR_pin_4 = LOW;
} else {
if (digitalRead(4)) {
SR_pin_4 = HIGH;
}
}
if (!digitalRead(5) && SR_pin_5) {
Spoor_leeg = Spoor_leeg - 1;
SR_pin_5 = LOW;
} else {
if (digitalRead(5)) {
SR_pin_5 = HIGH;
}
}
//Reset tellerstand bij storing
if (digitalRead(12) == LOW) {
Spoor_leeg = 0;
}
Serial.println(Spoor_leeg);
timer.run();
}
Voor mijzelf een groot gemak en waarom zou ik al het toetsenwerk over en over again opnieuw doen?
Momenteel aktief met ESP32 om een home systeem over WiFi te bouwen, maar dat heeft niets met treintjes te maken ;D
Groet Caspar
-
Ik heb hier al veel gelezen op het forum,maar ik had nog geen account.
nu even een vraag over de overweg.
Ik heb met een vriend een sketch geschreven in wokwi,deze is voor enkelspoor in 2 richtingen en 2 sensoren.
heb het nog niet op de baan n spoor getest.
heb nu wel een vermoeden dat ik met een korte trein rijd de slagbomen te vroeg gaan openen.
misschien beter om met 4 sensoren te werken.
https://wokwi.com/projects/352417544076547073 hierbij de link voor de geintresseerde.
is voor een belgisch spoorweg.
-
Hallo Willy1,
Ik vermoed dat je de weerstanden bent vergeten voor de leds.
Ik kende wokwi nog niet, ziet er leuk uit.
Bedankt voor het vermelden.
mvg spock
-
in wokwi is dit niet echt nodig,Ik heb weerstanden van 220ohm tussen de leds staan.