Doel:€250.00
Donaties:€88.00

Per saldo:€-162.00

Steun ons nu!

Laatst bijgewerkt
op 03-06-2025

Vacature: secretaris bestuur
Algemeen

De stichting

Recente berichten

Thunderbirds door bask185
Vandaag om 19:55:54
Veevervoer ss/ ns door klusser
Vandaag om 19:17:52
Piko 2025 door VAM65
Vandaag om 19:00:38
Toon hier je nieuwe (model-) spooraanwinst(en)... door Gino
Vandaag om 18:59:55
Big Scale Trains - NS SLT in H0 door MOVisser
Vandaag om 18:57:31
TurnControl: aansluiting verwijderen door Hans Gvz
Vandaag om 18:52:49
LS Models/Lemke CityNightLine samenstelling?? door Jelmer
Vandaag om 18:50:14
Spoor op industrieterrein Lage Weide door Jos_1972
Vandaag om 18:33:23
FS grand comfort Bandeira 1e klasse door Quinzeedied
Vandaag om 17:25:00
Ons woonkamer pendelbaantje 480x20cm door Mar-Cas
Vandaag om 17:12:41
Haperende locs door joespoor
Vandaag om 17:03:21
Contactgegevens oud lid door Pauldg
Vandaag om 16:54:07
Rijden met de 3737 op een commodore 64 door Nijboer
Vandaag om 16:27:30
Baanbouw: NL Baan Kleindrecht in H0 door AdLoc
Vandaag om 16:20:38
Pendel module door Bert55
Vandaag om 16:09:16
Am Ende der Strecke, modulebaan op 1 M2 door Frank 123
Vandaag om 16:05:40
NS 3502 van zwart naar groen door Ivo tB
Vandaag om 15:34:51
Portland ID, OR; een 2-turnout Inglenook door Ronald door Ronald Halma
Vandaag om 13:28:07
Een insulfrog polariseren. door bask185
Vandaag om 12:27:20
Tandwielen of wielstellen met tandwiel voor Rocky Rail NS 6400 / 6500 door Roy van Dijk
Vandaag om 11:58:19
Mallnitzer Tauernbahnstrecke ÖBB N Spoor door william_2
Vandaag om 11:57:29
De dingen die je kan maken uit een plaat. door bask185
Vandaag om 11:40:10
De bouw van mijn modelbaan in Thailand door Thai-Bundesbahn
Vandaag om 11:32:20
Knutselen met Holland Rail door mamory
Vandaag om 11:17:05
Roco Z21 en Yamorc YD6016 raar fenomeen door Chiel
Vandaag om 11:08:11
11e Grote Modelspoorexpo Leuven, 27 en 28 september door Wim1969
Vandaag om 11:07:38
Ombouw/Pimpen Bolle neuzen door bollen neus
Vandaag om 10:33:55
Roco 290 digtaliseren door FreekH
Vandaag om 10:30:05
Nederland jaren 50 op basis van mijn roots door defender
Vandaag om 10:14:22
Onlangs gespot - gefotografeerd, de links door Jeroen Water
Vandaag om 10:05:59
  

Auteur Topic: Pendel module  (gelezen 4255 keer)

bask185

  • Offline Offline
  • Berichten: 5055
Re: Pendel module
« Reactie #45 Gepost op: 22 September 2025, 13:36:23 »
Ik heb een LDR gebruikt, daar heb ik een printje voor gemaak met potmeter voor de gevoeligheid, maar die kan je volgens mij ook inkopen. Die LDR kan je ook makkelijk wegwerken. Alleen omgeving licht kan een ding zijn, als de verlichting erg inconsistent is, zou dat een probleem kunnen vormen. Echter.. als je software heb kan je met met 1 LDR en 1 enkel weerstandje dat probleem ook tackelen. Dan kan je mooi gemiddele brekeningen laten doen en varierende drempelwaardes intodruceren enzo.

Anders een reflectie sensor met IR, Die kan je ook onder je baan wegwerken.



Joz heeft een time of flight sensor gebruikt met succes voor een keerlus module. Naar het schijnt deed die al schakelen op de eerste beste koppelhaak die voorbij kwam. Maar daar komt SMD assemblage bij kijken, denk ik. Hij had hem verwerkt tot een biels die je makkelijk kwijt kon. Die kan je echt 99.9% onzichtbaar wegwerken
Train-Science.com
Train-Science github
It ain't rocket science ;-)

Mar-Cas

  • Offline Offline
  • Berichten: 273
  • Samen bouwen a.d. woonkamerbaan is wel zo gezellig
Re: Pendel module
« Reactie #46 Gepost op: 22 September 2025, 14:49:58 »
Ach bij al die kunsten kan mijn systeempje er ook nog wel bij.

4 draadjes benodigd voor het rijdend gedeelte.
Geen sluisjes, lichtsensors, stroomdetectie, magneetjes of anderszins. Dus een schone baan met alleen scenery.
Schakeld bij lokomotief of wagon voorop.



Pendelbaan 3,5 meter lang, voorzien van connector en
hierop kan worden aangesloten, direct of middels adapterbox,

1   Pendelunit PWM gestuurd met,
        2 schakelaars links/rechts gaand
        Schakelaar Handmatig / automatisch pendelen
        3potmeters  (snelheid, optrek & afrem vertraging en random wachtijd)
        Door analoge en digitale lokomotieven bereidbaar

2   ESU  Lokprogrammer voor testen en inregelen parameters van ABC
        breaking en motorsetting enz

3   Z21 Rijden en treintje spelen.(incl ABC breaking)

Greetz Caspar

Henry Stelling

  • Offline Offline
  • Berichten: 37
Re: Pendel module
« Reactie #47 Gepost op: 22 September 2025, 21:22:56 »
Welke simpele degelijke pendel module zou ik het beste kunnen aanschaffen?

ruudns

  • Offline Offline
  • Berichten: 6352
  • ***
Re: Pendel module
« Reactie #48 Gepost op: 22 September 2025, 21:50:32 »
Als het werkt en je tevreden bent met wat je nu hebt, laat je het zo ;).
Ho, NS periode III tot V. Artitec, Roco, Hamo, FM, Piko, Rivarossi en Liliput.
Verwerken van NS H0 modellen in de NSinmodel treinenlijst (https://forum.beneluxspoor.net/index.php?topic=67158.0).

RhB-Mikey

  • Lokifahrer Mikey
  • Online Online
  • Berichten: 714
  • Rhätische Bahn fan
    • Flickr
Re: Pendel module
« Reactie #49 Gepost op: 22 September 2025, 23:57:13 »
Welke simpele degelijke pendel module zou ik het beste kunnen aanschaffen?

Viessmann 5214
Lid van Vereniging Spoorgroep Zwitserland, Regio Zuidwest

klik hier voor mijn filmpjes

Bouwt aan Bahnhof Langwies

Ronald Halma

  • Organisator US Convention Nederland
  • Offline Offline
  • Berichten: 18105
  • Modelrailroading is fun!
    • Team USA Metusa Junction
Re: Pendel module
« Reactie #50 Gepost op: 23 September 2025, 00:02:12 »
Welke simpele degelijke pendel module zou ik het beste kunnen aanschaffen?

Het werkt toch? Jammer geld als je nu wat anders zou kopen.
Greetz, Ronald

Mijn US Convention Aalten

Mijn modules!:

Micromodule

Klaas Zondervan

  • Offline Offline
  • Berichten: 26790
    • Pagina van klaas
Re: Pendel module
« Reactie #51 Gepost op: 23 September 2025, 09:56:43 »
Als je zoekt op pendelzugsteuerung, vind je allerlei mogelijkheden.
De viessmann 5214 lijkt mij een goede keuze. Het aansluiten is supereenvoudig en de instellingen doe je met potmetertjes. Het is wel een module in het duurdere segment.

Tams heeft een module die goedkoper is. Heeft ook de mogelijkheid voor een stop bij een tussenstation.

De keuze is reuze. Maar als de huidige module doet wat je wil, waarom dan nog extra geld uitgeven?
Projecten:
Dubbelom
Halte Assel
Geluk, dat is vooraan staan als de overweg gesloten is.

Bert55

  • Offline Offline
  • Berichten: 950
Re: Pendel module
« Reactie #52 Gepost op: 25 September 2025, 23:51:12 »
Als bezigheid tijdens de vakantie wat nagedacht over de kant en klare oplossingen, prima, wat prijzig en wellicht wat beperkt.

Of ik het zelf ga bouwen, geen idee, maar hier een impressie hoe het kan worden.

het schema:

Het printje:


Zoals het nu getekend is de afmeting 5 * 10cm.
Ik heb er instel potmeters op gezet, dat kunnen net zo goed draai potmeters zijn, helemaal weglaten kan uiteraard ook, de instellingen kun je ook in de sketch aanpassen. (dat zou denk ik ook niet vaak nodig zijn, wel bij het afregelen denk ik.

De 3 leds geven het volgende aan: spanning aangesloten / loc gaat van A naar B, loc gaat van B naar A.
De gedachte is om de laatste 2 leds te laten knipperen tijden optrekken en vertraging, dat zou ook snel knipperen bij optrekken en langzaam bij afremmen kunnen zijn.

2 spare in/outputs zitten erop, bijvoorbeeld voor een tussenstop of zo, meer dan 2 kan ook.

Kosten van zo'n print met alle componenten, denk dan € 10-15

Ik heb het schema en de print vlot getekend, geen fouten controle nog.

Ach, leuk om te doen, of er iemand wat aan heeft ??? ::)
Met vriendelijke groet, Bert
Märklin, DCCnext, ECOS
Witmoosdorf afgebroken, Witmoos 2 wordt opgestart na de verhuizing

bask185

  • Offline Offline
  • Berichten: 5055
Re: Pendel module
« Reactie #53 Gepost op: Vandaag om 08:31:07 »
Ik geloof zelf in een meer modulaire opzet in plaats van '1 ding'. Ik heb ooit een ding gemaakt, wat ik een 'train-catcher' noemde. Het is eigenlijk niks meer dan een veredelde diode fuik met rem en optrek vertraging. Het enige wat die print deed, was een trein 'catchen' geleidelijk afremmen en stoppen. Hij kon detecteren wanneer er werd omgepoold en adhv daarvan kon hij de trein weer langzaam laten optrekken. Je zou je baan dan een constante spanning moeten geven. (dus je fleischmann trafo op een mooie kruissnelheid instellen).

De train catcher stuurt een pulsje uit als hij een trein heeft 'gevangen'. Dat pulsje kon je aansluiten op een timer relais die dan een instelbare tijd later het spoor deed ompolen. Je had dus 2 catchers en 1 timer relais nodig om een volwaardige automaat mee te maken.

Verder zaten er kleine handigheidjes in:
een buffer sectie waardoor je met push-pull treinen kon werken met dezelfde remwegen.
Een stop sectie om versneld af te remmen.
Je had ook een ingang om een trein vast te blijven houden. Als je bijvoorbeeld meerdere kopspoortjes hebt, kan je kiezen welke trein mag pendelen.
Als je de puls uitgang door loop't naar zijn vast hou lijn, last hij simpelweg een pauze in van 30s. Zo kan je een halte maken halverwege de route.
Je kon er zelfs meer passeerstukken mee realiseren.
Elke catcher heeft zijn eigen potmeter om remvertraging in te stellen, zo kan je met kortere en langere sporen overweg.

Ik had zelfs een werkende protope gemaakt. Het leuk is, dat je kan kiezen tussen handmatige bediening en automatische bediening. Vervang de timer relais door een schakelaar en je kan pendelen door zelf een schakelaar om te gooien. De catchers regelen voor jou het optrekken en afremmen.

Maar het heeft nooit de productie bereikt  ::).
Ik heb nog oude documentatie voor als iemand het boeit

Ik wil het idee nog wel een keer oppakken. Wat ik wil toevoegen, is een centrale print die je dan op een x aantal catchers kan aansluiten. De centrale moet kunnen ompolen, snelheid instellen en automatiseren. Automatiseren wil ik oplossen door programma's in te leren door het voor te doen. Dan moet je zelf dus ompolen en bij train catchers op knopjes drukken om treinen heen en weer te sturen. De centrale neemt die handelingen op, en kan dat later tot op een ms nauwkeurig naspelen.

De catchers moeten ook elke een dikke transistor krijgen om wissels te kunnen schakelen dmv een diode matrix. Elke catcher kan dan een volledige wisselstraat schakelen naar/van zijn spoor.

En ik wil optische detectie dmv een LDR toepassen. Dan hoef je geen rail isolaties te maken tussen buffer, brake en stop secties. Als een trein over de sensor rijdt, is hij al in de rem sectie en dan kan de catcher direct beginnen met werken. En als de trein de sensor uit rijdt, kan hij versneld afremmen. (of je moet een aparte stop sensor maken, wat ansich ook prima oplossing is).

Mvg,

Bas
Train-Science.com
Train-Science github
It ain't rocket science ;-)

Bert55

  • Offline Offline
  • Berichten: 950
Re: Pendel module
« Reactie #54 Gepost op: Vandaag om 08:39:28 »
Prima Bas,  jij hebt ook meer ervaring in het ontwikkelen.
Even buiten het feit dat 3 rail meer mijn ding is  ;D
Met vriendelijke groet, Bert
Märklin, DCCnext, ECOS
Witmoosdorf afgebroken, Witmoos 2 wordt opgestart na de verhuizing

bask185

  • Offline Offline
  • Berichten: 5055
Re: Pendel module
« Reactie #55 Gepost op: Vandaag om 08:59:26 »
Alles begint bij een idee, pas als dat goed is, volgen schema's en printplaten. I like to think dat ik goed in ideeën ben, maar wie ben ik. Ik ben ook altijd benieuwd naar andermans ideeën. Soms PB ik iemand wel eens om een idee te pitchen, iemand waarvan ik weet dat hij daar zelf ook ideeën over bedacht heeft.

Ik denk dat hamvraag is wat is 'beter': 1 pendelautomaat vs meerdere blokjes?
'Beter' is omslachtig maar dat kan je kwantificeren
Wat bedient makkelijker? / hoe wil je het bedienen?
Wat bekabelt makkelijer?
Wat is betrouwbaarder?
Wat is goedkoper?
Is het makkelijk genoeg voor mensen om het te begrijpen?

Met deze eisen kan je al aan de slag gaan met ontwerpen. Je kan beginnen met een schema, maar je kan ook dingen gaan neeretten op papier. Ik was gisteren bijvoorbeeld iets van cab control aan het uitwerken. Daar heb ik inmiddels een print concept voor, maar hier begon het mee


Wat 3-rail betreft... Als de detectie al optisch is opgelost. Dan hoef je eigenlijk alleen maar het ompool relais te wisselen voor een 'hoog pulse' relais. Gewoon een relais wat een korte 24V puls op het spoor. Dat kan volgens mij met een setje jumpers. Ik had wel eens een pwm regelaar in elkaar gehackt met een arduino en een boost-converter. Die marklins rijden namelijk prima 2 kanten op gelijkspanning met minder geluid ;D.

Mvg,

Bas
Train-Science.com
Train-Science github
It ain't rocket science ;-)

Bert55

  • Offline Offline
  • Berichten: 950
Re: Pendel module
« Reactie #56 Gepost op: Vandaag om 13:39:59 »
Ah, ompuls relais, zo simpel had ik het nog niet bedacht.
Kan ook nog mooi een oled display toevoegen om de wachttijd en indicatie optrek- en remvertraging weer te geven, kost ook geen drol.
Met vriendelijke groet, Bert
Märklin, DCCnext, ECOS
Witmoosdorf afgebroken, Witmoos 2 wordt opgestart na de verhuizing

bask185

  • Offline Offline
  • Berichten: 5055
Re: Pendel module
« Reactie #57 Gepost op: Vandaag om 15:03:55 »
Idd, die ene euro. Hoef je hem niet aan de computer te hangen. Kan je eerste een programma opnemen en dan later wachttijden ed finetunen.

Wellicht Bert dat een H-brug ook niet zo slecht is ipv een relais. Want dan kan je evt ook DCC in de mix gooien. Als je digitale treinen behandelt alsof ze analoog zijn en dus spanningsloos zet. Dan kan je onder DCC adres 0, het broadcast adres, ook digitale treinen in de mix gooien. De pendel apparatus hoeft alleen maar te weten dat het een digitale trein betreft. Het adres van de trein maakt dan niet.

Als ik die traincatcher daarop aanpas, kan die ook gewoon de spanning uitzetten met zijn transistor wanneer de trein is ontvangen. Met zijn signaal lijn kan hij tevens doorgeven dat de trein moet remmen en ook moet stoppen.

Mvg,

Bas
Train-Science.com
Train-Science github
It ain't rocket science ;-)

Bert55

  • Offline Offline
  • Berichten: 950
Re: Pendel module
« Reactie #58 Gepost op: Vandaag om 16:09:16 »
Dat van DCC snap ik nog niet, maar dat hoeft nu ook nog niet. Je vind het vast niet erg dat we wat parallel bezig zijn, met ideeën spuiten wordt het steed leuker en krijgen we gemak en een functionaliteit die je niet kan kopen. En ook nog eens simpel voor niet techneuten.

Ik heb AI gevraagd naar een aanpassing van de sketch:
1. OLED Display
2. Voor 3rail (ongetwijfeld nog met een brug te kiezen tussen = en ~)
3. Led richting indicatie, A->B en B->A. Knippert langzaam bij optrekken, constant bij op snelheid, snel bij afremmen.
4. 2 extra stopplekken.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// OLED display instellingen
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Constants voor pinnen - Märklin wisselstroom versie
const int lightSensorPin1 = 2;    // Lichtsluis station 1 (digital)
const int lightSensorPin2 = 3;    // Lichtsluis station 2 (digital)
const int lightSensorPin3 = 10;   // Lichtsluis stopplaats 3 (digital)
const int lightSensorPin4 = 11;   // Lichtsluis stopplaats 4 (digital)
const int relayPin = 4;           // Relais voor richting (digital)
const int pwmPin = 9;             // PWM voor snelheid (moet PWM pin zijn)
const int accelPotPin = A0;       // Aanloopvertraging potentiometer
const int decelPotPin = A1;       // Remvertraging potentiometer
const int waitPotPin = A2;        // Wachttijd potentiometer
const int manualControlPin = 6;   // Handbediening schakelaar (digital)
const int ledPin1 = 7;            // LED 1: Station 1 -> Station 2
const int ledPin2 = 8;            // LED 2: Station 2 -> Station 1
const int statusLedPin = 13;      // Status LED (built-in)

// Märklin specifieke instellingen
const int MIN_PWM = 30;           // Minimale PWM voor Märklin (i.v.m. startspanning)
const int MAX_PWM = 255;          // Maximale PWM
const int DIRECTION_DELAY = 500;  // Vertraging bij richtingsverandering (ms)

// LED knipper instellingen
const unsigned long SLOW_BLINK_INTERVAL = 800;   // Langzaam knipperen (800ms)
const unsigned long FAST_BLINK_INTERVAL = 200;   // Snel knipperen (200ms)
const unsigned long VERY_FAST_BLINK_INTERVAL = 100; // Zeer snel knipperen (100ms)

// Stopplaats instellingen
const int STOP_TIME = 3000;       // Wachttijd stopplaatsen (3 seconden)

// Variabelen
int currentSpeed = 0;
int targetSpeed = 0;
int previousSpeed = 0;
bool movingForward = true;
unsigned long lastUpdateTime = 0;
unsigned long waitStartTime = 0;
unsigned long directionChangeTime = 0;
unsigned long lastSensorTime = 0;
unsigned long manualOverrideTime = 0;
unsigned long lastDisplayUpdate = 0;
unsigned long lastLEDUpdate = 0;
bool waiting = false;
bool changingDirection = false;
bool manualControl = false;
bool emergencyStopActive = false;
bool sensorError = false;
bool ledState = false;
int cycleCount = 0;
unsigned long totalRunTime = 0;
unsigned long programStartTime = millis();

// Trein toestanden
enum TrainState {
 MOVING_TO_STATION2,
 WAITING_AT_STATION2,
 MOVING_TO_STATION1,
 WAITING_AT_STATION1,
 STOPPING_AT_POINT3,
 STOPPING_AT_POINT4,
 MANUAL_CONTROL,
 EMERGENCY_STOP
};

TrainState currentState = MOVING_TO_STATION2;
TrainState previousState = MOVING_TO_STATION2;

void setup() {
 // Pin modes instellen
 pinMode(lightSensorPin1, INPUT_PULLUP);
 pinMode(lightSensorPin2, INPUT_PULLUP);
 pinMode(lightSensorPin3, INPUT_PULLUP);
 pinMode(lightSensorPin4, INPUT_PULLUP);
 pinMode(relayPin, OUTPUT);
 pinMode(pwmPin, OUTPUT);
 pinMode(manualControlPin, INPUT_PULLUP);
 pinMode(ledPin1, OUTPUT);
 pinMode(ledPin2, OUTPUT);
 pinMode(statusLedPin, OUTPUT);

 // OLED display initialiseren
 if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
   Serial.println(F("SSD1306 allocation failed"));
   for(;;);
 }
 display.clearDisplay();
 display.setTextColor(SSD1306_WHITE);
 display.setTextSize(1);
 display.setCursor(0,0);
 display.println("Märklin Pendeltrein");
 display.println("4 Stopplaatsen");
 display.display();
 delay(2000);

 // Seriële communicatie voor debugging
 Serial.begin(9600);
 Serial.println("Märklin Pendeltrein met 4 Stopplaatsen Gestart");
 Serial.println("=============================================");

 // Start richting station 2
 digitalWrite(relayPin, HIGH);
 movingForward = true;
 updateLEDs(false);

 // Start met minimale snelheid
 analogWrite(pwmPin, MIN_PWM);
 delay(1000);

 programStartTime = millis();
 displayStartScreen();
}

void loop() {
 unsigned long currentTime = millis();

 // Lees bedieningselementen
 bool manualControlRequest = digitalRead(manualControlPin) == LOW;

 // Handmatige overname detectie
 if (manualControlRequest && !manualControl) {
   enableManualControl();
 } else if (!manualControlRequest && manualControl) {
   disableManualControl();
 }

 if (manualControl) {
   handleManualControl();
   updateDisplay(currentTime);
   updateLEDControl(currentTime);
   return;
 }

 if (emergencyStopActive) {
   handleEmergencyStop();
   updateDisplay(currentTime);
   updateLEDControl(currentTime);
   return;
 }

 // Lees potentiometers
 int acceleration = map(analogRead(accelPotPin), 0, 1023, 20, 200);
 int deceleration = map(analogRead(decelPotPin), 0, 1023, 20, 200);
 int waitTime = map(analogRead(waitPotPin), 0, 1023, 5, 120) * 1000;

 // Lichtsluis detectie met debouncing
 bool atStation1 = readSensorWithDebounce(lightSensorPin1, currentTime);
 bool atStation2 = readSensorWithDebounce(lightSensorPin2, currentTime);
 bool atPoint3 = readSensorWithDebounce(lightSensorPin3, currentTime);
 bool atPoint4 = readSensorWithDebounce(lightSensorPin4, currentTime);

 // Sensor status monitoring
 checkSensorStatus(currentTime);

 // Update totale looptijd
 if (currentState == MOVING_TO_STATION1 || currentState == MOVING_TO_STATION2 ||
     currentState == STOPPING_AT_POINT3 || currentState == STOPPING_AT_POINT4) {
   totalRunTime += (currentTime - lastUpdateTime);
 }

 // Uitgebreide State machine met 4 stopplaatsen
 switch (currentState) {
   case MOVING_TO_STATION2:
     targetSpeed = MAX_PWM;
     digitalWrite(statusLedPin, HIGH);

     if (atPoint3 && movingForward) {
       currentState = STOPPING_AT_POINT3;
       waitStartTime = currentTime;
       waiting = true;
       targetSpeed = 0;
       logEvent("Aangekomen bij stopplaats 3");
     }
     else if (atStation2) {
       previousState = currentState;
       currentState = WAITING_AT_STATION2;
       waitStartTime = currentTime;
       waiting = true;
       targetSpeed = 0;
       cycleCount++;
       updateLEDs(false);
       logEvent("Aangekomen bij station 2");
     }
     break;

   case STOPPING_AT_POINT3:
     targetSpeed = 0;
     digitalWrite(statusLedPin, (millis() % 1000 < 500));

     if (currentTime - waitStartTime >= STOP_TIME && !waiting) {
       currentState = MOVING_TO_STATION2;
       targetSpeed = MAX_PWM;
       logEvent("Vertrokken van stopplaats 3");
     }

     if (waiting && currentTime - waitStartTime >= 1000) {
       waiting = false;
     }
     break;

   case WAITING_AT_STATION2:
     targetSpeed = 0;
     digitalWrite(statusLedPin, (millis() % 1000 < 500));

     if (currentTime - waitStartTime >= waitTime && !waiting && !changingDirection) {
       changingDirection = true;
       directionChangeTime = currentTime;
       digitalWrite(relayPin, LOW);
       movingForward = false;
       logEvent("Richting veranderd naar station 1");
     }

     if (changingDirection && currentTime - directionChangeTime >= DIRECTION_DELAY) {
       changingDirection = false;
       previousState = currentState;
       currentState = MOVING_TO_STATION1;
       targetSpeed = MIN_PWM;
       updateLEDs(true);
       logEvent("Vertrek van station 2");
     }

     if (waiting && currentTime - waitStartTime >= 1000) {
       waiting = false;
     }
     break;

   case MOVING_TO_STATION1:
     targetSpeed = MAX_PWM;
     digitalWrite(statusLedPin, HIGH);

     if (atPoint4 && !movingForward) {
       currentState = STOPPING_AT_POINT4;
       waitStartTime = currentTime;
       waiting = true;
       targetSpeed = 0;
       logEvent("Aangekomen bij stopplaats 4");
     }
     else if (atStation1) {
       previousState = currentState;
       currentState = WAITING_AT_STATION1;
       waitStartTime = currentTime;
       waiting = true;
       targetSpeed = 0;
       cycleCount++;
       updateLEDs(false);
       logEvent("Aangekomen bij station 1");
     }
     break;

   case STOPPING_AT_POINT4:
     targetSpeed = 0;
     digitalWrite(statusLedPin, (millis() % 1000 < 500));

     if (currentTime - waitStartTime >= STOP_TIME && !waiting) {
       currentState = MOVING_TO_STATION1;
       targetSpeed = MAX_PWM;
       logEvent("Vertrokken van stopplaats 4");
     }

     if (waiting && currentTime - waitStartTime >= 1000) {
       waiting = false;
     }
     break;

   case WAITING_AT_STATION1:
     targetSpeed = 0;
     digitalWrite(statusLedPin, (millis() % 1000 < 500));

     if (currentTime - waitStartTime >= waitTime && !waiting && !changingDirection) {
       changingDirection = true;
       directionChangeTime = currentTime;
       digitalWrite(relayPin, HIGH);
       movingForward = true;
       logEvent("Richting veranderd naar station 2");
     }

     if (changingDirection && currentTime - directionChangeTime >= DIRECTION_DELAY) {
       changingDirection = false;
       previousState = currentState;
       currentState = MOVING_TO_STATION2;
       targetSpeed = MIN_PWM;
       updateLEDs(true);
       logEvent("Vertrek van station 1");
     }

     if (waiting && currentTime - waitStartTime >= 1000) {
       waiting = false;
     }
     break;
 }

 // Snelheidsregeling
 if (currentTime - lastUpdateTime >= 50) {
   previousSpeed = currentSpeed;
   updateSpeedControl(acceleration, deceleration, currentTime);
   lastUpdateTime = currentTime;
 }

 // LED aansturing updaten
 updateLEDControl(currentTime);

 // Display updaten (elke 500ms)
 if (currentTime - lastDisplayUpdate >= 500) {
   updateDisplay(currentTime);
   lastDisplayUpdate = currentTime;
 }

 // Status rapportage elk uur
 static unsigned long lastReportTime = 0;
 if (currentTime - lastReportTime >= 3600000) {
   generateStatusReport();
   lastReportTime = currentTime;
 }

 delay(10);
}

// LED aansturing functies (zelfde als voorheen)
void updateLEDControl(unsigned long currentTime) {
 static unsigned long lastBlinkTime = 0;
 unsigned long blinkInterval = 0;
 bool shouldBlink = false;

 if (emergencyStopActive) {
   blinkInterval = VERY_FAST_BLINK_INTERVAL;
   shouldBlink = true;
 }
 else if (currentState == MOVING_TO_STATION1 || currentState == MOVING_TO_STATION2 ||
          currentState == STOPPING_AT_POINT3 || currentState == STOPPING_AT_POINT4) {
   if (currentSpeed > previousSpeed) {
     blinkInterval = SLOW_BLINK_INTERVAL;
     shouldBlink = true;
   }
   else if (currentSpeed < previousSpeed && currentSpeed > MIN_PWM + 10) {
     blinkInterval = FAST_BLINK_INTERVAL;
     shouldBlink = true;
   }
   else {
     shouldBlink = false;
   }
 }
 else if (currentState == WAITING_AT_STATION1 || currentState == WAITING_AT_STATION2) {
   blinkInterval = SLOW_BLINK_INTERVAL;
   shouldBlink = true;
 }

 if (shouldBlink && blinkInterval > 0) {
   if (currentTime - lastBlinkTime >= blinkInterval) {
     ledState = !ledState;
     updateLEDs(ledState);
     lastBlinkTime = currentTime;
   }
 } else {
   updateLEDs(!shouldBlink);
 }
}

void updateLEDs(bool enable) {
 if (emergencyStopActive) {
   digitalWrite(ledPin1, enable);
   digitalWrite(ledPin2, enable);
 }
 else if (manualControl) {
   digitalWrite(ledPin1, LOW);
   digitalWrite(ledPin2, LOW);
 }
 else if (currentState == MOVING_TO_STATION2 || currentState == STOPPING_AT_POINT3) {
   digitalWrite(ledPin1, enable);
   digitalWrite(ledPin2, LOW);
 }
 else if (currentState == MOVING_TO_STATION1 || currentState == STOPPING_AT_POINT4) {
   digitalWrite(ledPin1, LOW);
   digitalWrite(ledPin2, enable);
 }
 else {
   digitalWrite(ledPin1, LOW);
   digitalWrite(ledPin2, LOW);
 }
}

// Display functies met extra stopplaatsen
void displayStartScreen() {
 display.clearDisplay();
 display.setTextSize(2);
 display.setCursor(0,0);
 display.println(" MARKLIN");
 display.println(" 4 STOP");
 display.println(" PLAATSEN");
 display.setTextSize(1);
 display.setCursor(0,50);
 display.println("Route: 1-3-2-4-1");
 display.display();
 delay(3000);
}

void updateDisplay(unsigned long currentTime) {
 display.clearDisplay();

 // Header met status en locatie
 display.setTextSize(1);
 display.setCursor(0,0);
 display.print("Status: ");
 display.println(getStateName(currentState));

 // Huidige locatie
 display.setCursor(70,0);
 display.print("Loc: ");
 display.println(getLocationName(currentState));

 // Horizontale lijn
 display.drawLine(0, 10, 128, 10, SSD1306_WHITE);

 // Potentiometer waarden
 int accelValue = map(analogRead(accelPotPin), 0, 1023, 1, 10);
 int decelValue = map(analogRead(decelPotPin), 0, 1023, 1, 10);
 int waitValue = map(analogRead(waitPotPin), 0, 1023, 5, 120);

 display.setCursor(0,15);
 display.print("Optrek: ");
 display.print(accelValue);
 display.println(" sec");

 display.setCursor(0,25);
 display.print("Afrem:  ");
 display.print(decelValue);
 display.println(" sec");

 display.setCursor(0,35);
 display.print("Wachten: ");
 display.print(waitValue);
 display.println(" sec");

 // Stopplaats wachttijd
 display.setCursor(0,45);
 display.print("Stop:   ");
 display.print(STOP_TIME / 1000);
 display.println(" sec");

 // Snelheidsbalk
 int speedPercent = map(currentSpeed, 0, 255, 0, 100);
 display.setCursor(0,55);
 display.print("Snelh: ");
 display.print(speedPercent);
 display.print("% ");
 display.print(currentSpeed > previousSpeed ? "▲" : (currentSpeed < previousSpeed ? "▼" : "■"));

 // Snelheidsbalk tekenen
 int barWidth = map(currentSpeed, 0, 255, 0, 100);
 display.drawRect(50, 55, 70, 8, SSD1306_WHITE);
 display.fillRect(50, 55, barWidth * 70 / 100, 8, SSD1306_WHITE);

 display.display();
}

String getStateName(TrainState state) {
 switch(state) {
   case MOVING_TO_STATION1: return "Naar Stat 1";
   case MOVING_TO_STATION2: return "Naar Stat 2";
   case WAITING_AT_STATION1: return "Wacht Stat 1";
   case WAITING_AT_STATION2: return "Wacht Stat 2";
   case STOPPING_AT_POINT3: return "Stop Plaats 3";
   case STOPPING_AT_POINT4: return "Stop Plaats 4";
   case MANUAL_CONTROL: return "Handmatig";
   case EMERGENCY_STOP: return "NOODSTOP";
   default: return "Onbekend";
 }
}

String getLocationName(TrainState state) {
 switch(state) {
   case MOVING_TO_STATION1: return "1->2";
   case MOVING_TO_STATION2: return "2->1";
   case WAITING_AT_STATION1: return "Stat 1";
   case WAITING_AT_STATION2: return "Stat 2";
   case STOPPING_AT_POINT3: return "Stop 3";
   case STOPPING_AT_POINT4: return "Stop 4";
   case MANUAL_CONTROL: return "Hand";
   case EMERGENCY_STOP: return "STOP";
   default: return "Onbekend";
 }
}

// Overige functies blijven hetzelfde
bool readSensorWithDebounce(int sensorPin, unsigned long currentTime) {
 static unsigned long lastSensorTime1 = 0, lastSensorTime2 = 0, lastSensorTime3 = 0, lastSensorTime4 = 0;
 static bool lastState1 = HIGH, lastState2 = HIGH, lastState3 = HIGH, lastState4 = HIGH;

 bool currentState = digitalRead(sensorPin) == LOW;
 unsigned long* lastTime;
 bool* lastState;

 switch(sensorPin) {
   case lightSensorPin1: lastTime = &lastSensorTime1; lastState = &lastState1; break;
   case lightSensorPin2: lastTime = &lastSensorTime2; lastState = &lastState2; break;
   case lightSensorPin3: lastTime = &lastSensorTime3; lastState = &lastState3; break;
   case lightSensorPin4: lastTime = &lastSensorTime4; lastState = &lastState4; break;
   default: return false;
 }

 if (currentState != *lastState) {
   *lastTime = currentTime;
   *lastState = currentState;
 }
 return (currentTime - *lastTime > 100) && currentState;
}

void checkSensorStatus(unsigned long currentTime) {
 static unsigned long lastSensorCheck = 0;
 if (currentTime - lastSensorCheck > 5000) {
   // Eenvoudige conflict detectie
   int activeSensors = 0;
   if (digitalRead(lightSensorPin1) == LOW) activeSensors++;
   if (digitalRead(lightSensorPin2) == LOW) activeSensors++;
   if (digitalRead(lightSensorPin3) == LOW) activeSensors++;
   if (digitalRead(lightSensorPin4) == LOW) activeSensors++;

   if (activeSensors > 1) {
     sensorError = true;
     triggerEmergencyStop("Sensor conflict");
   } else {
     sensorError = false;
   }
   lastSensorCheck = currentTime;
 }
}

void updateSpeedControl(int acceleration, int deceleration, unsigned long currentTime) {
 if (!changingDirection && !emergencyStopActive) {
   if (currentSpeed < targetSpeed) {
     int speedIncrease = min(acceleration / 20, targetSpeed - currentSpeed);
     currentSpeed += speedIncrease;
     if (currentSpeed > 0 && currentSpeed < MIN_PWM) currentSpeed = MIN_PWM;
   } else if (currentSpeed > targetSpeed) {
     int speedDecrease = min(deceleration / 20, currentSpeed - targetSpeed);
     currentSpeed -= speedDecrease;
     if (currentSpeed < MIN_PWM && targetSpeed == 0) currentSpeed = 0;
   }
 } else {
   currentSpeed = 0;
 }
 analogWrite(pwmPin, max(currentSpeed, MIN_PWM));
}

void enableManualControl() {
 previousState = currentState;
 currentState = MANUAL_CONTROL;
 manualControl = true;
 manualOverrideTime = millis();
 updateLEDs(false);
 logEvent("Handmatige bediening");
}

void disableManualControl() {
 manualControl = false;
 currentState = previousState;
 updateLEDs(true);
 logEvent("Automatisch hervat");
}

void handleManualControl() {
 digitalWrite(statusLedPin, (millis() % 500 < 250));
 updateLEDs(false);
 if (millis() - manualOverrideTime > 300000) disableManualControl();
}

void triggerEmergencyStop(String reason) {
 emergencyStopActive = true;
 currentState = EMERGENCY_STOP;
 targetSpeed = 0;
 currentSpeed = 0;
 analogWrite(pwmPin, 0);
 logEvent("NOODSTOP: " + reason);
}

void handleEmergencyStop() {
 digitalWrite(statusLedPin, (millis() % 200 < 100));
}

void logEvent(String message) {
 Serial.print("[");
 Serial.print(millis() / 1000);
 Serial.print("s] ");
 Serial.println(message);
}

void generateStatusReport() {
 Serial.println("\n=== STATUS RAPPORT ===");
 Serial.print("Totale bedrijfstijd: ");
 Serial.print((millis() - programStartTime) / 3600000);
 Serial.println(" uur");
 Serial.print("Aantal cycli: ");
 Serial.println(cycleCount);
 Serial.print("Huidige staat: ");
 Serial.println(getStateName(currentState));
 Serial.println("====================\n");
}

void serialEvent() {
 while (Serial.available()) {
   char command = Serial.read();
   switch(command) {
     case 's': triggerEmergencyStop("Serieel commando"); break;
     case 'r': emergencyStopActive = false; currentState = MOVING_TO_STATION2; break;
     case 'm': enableManualControl(); break;
     case 'a': disableManualControl(); break;
     case '?': generateStatusReport(); break;
   }
 }
}

Ga thuis eerst op termijn een (Marklin) loc van richting laten veranderen, dan verder testen, leuk dit.

Edit: inmiddels de delays vervangen door millis, denk niet nodig dat nu hier nog neer te zetten

« Laatst bewerkt op: Vandaag om 16:39:37 door Bert55 »
Met vriendelijke groet, Bert
Märklin, DCCnext, ECOS
Witmoosdorf afgebroken, Witmoos 2 wordt opgestart na de verhuizing